summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS6
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/ABI/testing/sysfs-block37
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci10
-rw-r--r--Documentation/DocBook/kernel-hacking.tmpl4
-rw-r--r--Documentation/DocBook/mtdnand.tmpl2
-rw-r--r--Documentation/DocBook/scsi.tmpl2
-rw-r--r--Documentation/RCU/RTFP.txt77
-rw-r--r--Documentation/RCU/UP.txt34
-rw-r--r--Documentation/RCU/checklist.txt20
-rw-r--r--Documentation/RCU/rcubarrier.txt7
-rw-r--r--Documentation/RCU/torture.txt23
-rw-r--r--Documentation/RCU/whatisRCU.txt14
-rw-r--r--Documentation/arm/memory.txt2
-rw-r--r--Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg588
-rw-r--r--Documentation/blockdev/drbd/DRBD-data-packets.svg459
-rw-r--r--Documentation/blockdev/drbd/README.txt16
-rw-r--r--Documentation/blockdev/drbd/conn-states-8.dot18
-rw-r--r--Documentation/blockdev/drbd/disk-states-8.dot16
-rw-r--r--Documentation/blockdev/drbd/drbd-connection-state-overview.dot85
-rw-r--r--Documentation/blockdev/drbd/node-states-8.dot14
-rw-r--r--Documentation/btmrvl.txt119
-rw-r--r--Documentation/connector/Makefile5
-rw-r--r--Documentation/connector/cn_test.c33
-rw-r--r--Documentation/connector/connector.txt119
-rw-r--r--Documentation/connector/ucon.c62
-rw-r--r--Documentation/cpu-freq/user-guide.txt9
-rw-r--r--Documentation/dontdiff1
-rw-r--r--Documentation/feature-removal-schedule.txt34
-rw-r--r--Documentation/filesystems/nfsroot.txt2
-rw-r--r--Documentation/filesystems/seq_file.txt2
-rw-r--r--Documentation/filesystems/sysfs.txt3
-rw-r--r--Documentation/filesystems/vfat.txt2
-rw-r--r--Documentation/gcov.txt2
-rw-r--r--Documentation/hwlat_detector.txt64
-rw-r--r--Documentation/hwmon/hpfall.c64
-rw-r--r--Documentation/hwmon/pc874272
-rw-r--r--Documentation/hwmon/tmp42136
-rw-r--r--Documentation/kernel-parameters.txt49
-rw-r--r--Documentation/kmemleak.txt12
-rw-r--r--Documentation/kvm/api.txt683
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt127
-rw-r--r--Documentation/lguest/lguest.c721
-rw-r--r--Documentation/networking/00-INDEX2
-rw-r--r--Documentation/networking/ieee802154.txt2
-rw-r--r--Documentation/networking/regulatory.txt2
-rw-r--r--Documentation/power/power_supply_class.txt7
-rw-r--r--Documentation/powerpc/dts-bindings/marvell.txt2
-rw-r--r--Documentation/scsi/ChangeLog.megaraid2
-rw-r--r--Documentation/scsi/scsi_fc_transport.txt2
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt4
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt20
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt64
-rw-r--r--Documentation/sound/alsa/Procfile.txt5
-rw-r--r--Documentation/sysctl/kernel.txt30
-rw-r--r--Documentation/sysrq.txt7
-rw-r--r--Documentation/trace/events.txt9
-rw-r--r--Documentation/trace/ftrace.txt2
-rw-r--r--Documentation/video4linux/CARDLIST.cx238852
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx4
-rw-r--r--Documentation/video4linux/CARDLIST.tuner1
-rw-r--r--Documentation/video4linux/CQcam.txt4
-rw-r--r--Documentation/video4linux/gspca.txt36
-rw-r--r--Documentation/vm/slqbinfo.c1047
-rw-r--r--Documentation/vm/slub.txt10
-rw-r--r--MAINTAINERS2853
-rw-r--r--Makefile4
-rw-r--r--arch/Kconfig12
-rw-r--r--arch/alpha/include/asm/pci.h1
-rw-r--r--arch/alpha/include/asm/percpu.h100
-rw-r--r--arch/alpha/include/asm/smp.h2
-rw-r--r--arch/alpha/include/asm/tlb.h4
-rw-r--r--arch/alpha/include/asm/tlbflush.h1
-rw-r--r--arch/alpha/include/asm/topology.h18
-rw-r--r--arch/alpha/kernel/smp.c14
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S9
-rw-r--r--arch/arm/Kconfig45
-rw-r--r--arch/arm/Kconfig.debug1
-rw-r--r--arch/arm/Makefile14
-rw-r--r--arch/arm/boot/Makefile9
-rw-r--r--arch/arm/boot/compressed/head.S184
-rw-r--r--arch/arm/boot/compressed/misc.c1
-rw-r--r--arch/arm/common/vic.c99
-rw-r--r--arch/arm/configs/cpu9260_defconfig1338
-rw-r--r--arch/arm/configs/cpu9g20_defconfig1328
-rw-r--r--arch/arm/configs/cpuat91_defconfig1316
-rw-r--r--arch/arm/configs/da830_omapl137_defconfig1254
-rw-r--r--arch/arm/configs/da850_omapl138_defconfig1229
-rw-r--r--arch/arm/configs/davinci_all_defconfig173
-rw-r--r--arch/arm/configs/littleton_defconfig783
-rw-r--r--arch/arm/configs/mx27_defconfig270
-rw-r--r--arch/arm/configs/mx3_defconfig151
-rw-r--r--arch/arm/configs/nhk8815_defconfig1316
-rw-r--r--arch/arm/configs/omap3_evm_defconfig2
-rw-r--r--arch/arm/configs/pxa3xx_defconfig1332
-rw-r--r--arch/arm/configs/zylonite_defconfig736
-rw-r--r--arch/arm/include/asm/assembler.h84
-rw-r--r--arch/arm/include/asm/atomic.h2
-rw-r--r--arch/arm/include/asm/cacheflush.h8
-rw-r--r--arch/arm/include/asm/device.h3
-rw-r--r--arch/arm/include/asm/elf.h3
-rw-r--r--arch/arm/include/asm/ftrace.h34
-rw-r--r--arch/arm/include/asm/futex.h1
-rw-r--r--arch/arm/include/asm/mach/mmc.h2
-rw-r--r--arch/arm/include/asm/memory.h6
-rw-r--r--arch/arm/include/asm/mmu_context.h9
-rw-r--r--arch/arm/include/asm/page-nommu.h3
-rw-r--r--arch/arm/include/asm/pci.h2
-rw-r--r--arch/arm/include/asm/pgtable.h20
-rw-r--r--arch/arm/include/asm/ptrace.h8
-rw-r--r--arch/arm/include/asm/smp.h1
-rw-r--r--arch/arm/include/asm/tlb.h4
-rw-r--r--arch/arm/include/asm/tlbflush.h4
-rw-r--r--arch/arm/include/asm/uaccess.h7
-rw-r--r--arch/arm/include/asm/unified.h126
-rw-r--r--arch/arm/kernel/Makefile4
-rw-r--r--arch/arm/kernel/crunch.c13
-rw-r--r--arch/arm/kernel/entry-armv.S169
-rw-r--r--arch/arm/kernel/entry-common.S30
-rw-r--r--arch/arm/kernel/entry-header.S92
-rw-r--r--arch/arm/kernel/head-common.S15
-rw-r--r--arch/arm/kernel/head-nommu.S16
-rw-r--r--arch/arm/kernel/head.S28
-rw-r--r--arch/arm/kernel/module.c53
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/arm/kernel/ptrace.c8
-rw-r--r--arch/arm/kernel/return_address.c71
-rw-r--r--arch/arm/kernel/setup.c28
-rw-r--r--arch/arm/kernel/smp.c10
-rw-r--r--arch/arm/kernel/stacktrace.c4
-rw-r--r--arch/arm/kernel/unwind.c4
-rw-r--r--arch/arm/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm/lib/ashldi3.S4
-rw-r--r--arch/arm/lib/ashrdi3.S4
-rw-r--r--arch/arm/lib/backtrace.S8
-rw-r--r--arch/arm/lib/clear_user.S15
-rw-r--r--arch/arm/lib/copy_from_user.S19
-rw-r--r--arch/arm/lib/copy_template.S24
-rw-r--r--arch/arm/lib/copy_to_user.S19
-rw-r--r--arch/arm/lib/csumpartialcopyuser.S48
-rw-r--r--arch/arm/lib/div64.S4
-rw-r--r--arch/arm/lib/findbit.S34
-rw-r--r--arch/arm/lib/getuser.S5
-rw-r--r--arch/arm/lib/io-writesw-armv4.S5
-rw-r--r--arch/arm/lib/lshrdi3.S4
-rw-r--r--arch/arm/lib/memcpy.S7
-rw-r--r--arch/arm/lib/memmove.S28
-rw-r--r--arch/arm/lib/putuser.S15
-rw-r--r--arch/arm/lib/sha1.S2
-rw-r--r--arch/arm/lib/strncpy_from_user.S2
-rw-r--r--arch/arm/lib/strnlen_user.S2
-rw-r--r--arch/arm/mach-at91/Kconfig70
-rw-r--r--arch/arm/mach-at91/Makefile9
-rw-r--r--arch/arm/mach-at91/Makefile.boot4
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c116
-rw-r--r--arch/arm/mach-at91/at91sam9261.c22
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c360
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c1230
-rw-r--r--arch/arm/mach-at91/board-afeb-9260v1.c14
-rw-r--r--arch/arm/mach-at91/board-cam60.c2
-rw-r--r--arch/arm/mach-at91/board-cpu9krea.c385
-rw-r--r--arch/arm/mach-at91/board-cpuat91.c185
-rw-r--r--arch/arm/mach-at91/board-neocore926.c2
-rw-r--r--arch/arm/mach-at91/board-qil-a9260.c2
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c16
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c3
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c389
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c81
-rw-r--r--arch/arm/mach-at91/board-usb-a9260.c2
-rw-r--r--arch/arm/mach-at91/board-usb-a9263.c2
-rw-r--r--arch/arm/mach-at91/clock.c66
-rw-r--r--arch/arm/mach-at91/generic.h2
-rw-r--r--arch/arm/mach-at91/gpio.c15
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9261.h3
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9g45.h155
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h153
-rw-r--r--arch/arm/mach-at91/include/mach/at_hdmac.h102
-rw-r--r--arch/arm/mach-at91/include/mach/board.h8
-rw-r--r--arch/arm/mach-at91/include/mach/cpu.h23
-rw-r--r--arch/arm/mach-at91/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-at91/include/mach/timex.h10
-rw-r--r--arch/arm/mach-at91/pm.c3
-rw-r--r--arch/arm/mach-davinci/Kconfig49
-rw-r--r--arch/arm/mach-davinci/Makefile14
-rw-r--r--arch/arm/mach-davinci/Makefile.boot10
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c127
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c120
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c82
-rw-r--r--arch/arm/mach-davinci/board-dm355-leopard.c1
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c492
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c76
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c213
-rw-r--r--arch/arm/mach-davinci/board-sffsdr.c1
-rw-r--r--arch/arm/mach-davinci/clock.c5
-rw-r--r--arch/arm/mach-davinci/da830.c1204
-rw-r--r--arch/arm/mach-davinci/da850.c631
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c287
-rw-r--r--arch/arm/mach-davinci/devices.c60
-rw-r--r--arch/arm/mach-davinci/dm355.c168
-rw-r--r--arch/arm/mach-davinci/dm365.c909
-rw-r--r--arch/arm/mach-davinci/dm644x.c141
-rw-r--r--arch/arm/mach-davinci/dm646x.c279
-rw-r--r--arch/arm/mach-davinci/dma.c811
-rw-r--r--arch/arm/mach-davinci/gpio.c105
-rw-r--r--arch/arm/mach-davinci/include/mach/asp.h34
-rw-r--r--arch/arm/mach-davinci/include/mach/common.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/cputype.h24
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h106
-rw-r--r--arch/arm/mach-davinci/include/mach/debug-macro.S8
-rw-r--r--arch/arm/mach-davinci/include/mach/dm355.h7
-rw-r--r--arch/arm/mach-davinci/include/mach/dm365.h29
-rw-r--r--arch/arm/mach-davinci/include/mach/dm644x.h4
-rw-r--r--arch/arm/mach-davinci/include/mach/dm646x.h30
-rw-r--r--arch/arm/mach-davinci/include/mach/edma.h57
-rw-r--r--arch/arm/mach-davinci/include/mach/gpio.h8
-rw-r--r--arch/arm/mach-davinci/include/mach/hardware.h17
-rw-r--r--arch/arm/mach-davinci/include/mach/io.h23
-rw-r--r--arch/arm/mach-davinci/include/mach/irqs.h202
-rw-r--r--arch/arm/mach-davinci/include/mach/memory.h9
-rw-r--r--arch/arm/mach-davinci/include/mach/mux.h602
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h62
-rw-r--r--arch/arm/mach-davinci/include/mach/serial.h6
-rw-r--r--arch/arm/mach-davinci/include/mach/system.h4
-rw-r--r--arch/arm/mach-davinci/include/mach/uncompress.h7
-rw-r--r--arch/arm/mach-davinci/include/mach/vmalloc.h2
-rw-r--r--arch/arm/mach-davinci/mux.c14
-rw-r--r--arch/arm/mach-davinci/sram.c2
-rw-r--r--arch/arm/mach-davinci/time.c16
-rw-r--r--arch/arm/mach-davinci/usb.c13
-rw-r--r--arch/arm/mach-ep93xx/adssphere.c11
-rw-r--r--arch/arm/mach-ep93xx/clock.c131
-rw-r--r--arch/arm/mach-ep93xx/core.c200
-rw-r--r--arch/arm/mach-ep93xx/edb93xx.c10
-rw-r--r--arch/arm/mach-ep93xx/gesbc9312.c11
-rw-r--r--arch/arm/mach-ep93xx/gpio.c65
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h103
-rw-r--r--arch/arm/mach-ep93xx/include/mach/hardware.h17
-rw-r--r--arch/arm/mach-ep93xx/include/mach/io.h17
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h20
-rw-r--r--arch/arm/mach-ep93xx/include/mach/system.h12
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ts72xx.h4
-rw-r--r--arch/arm/mach-ep93xx/micro9.c11
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c33
-rw-r--r--arch/arm/mach-integrator/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c18
-rw-r--r--arch/arm/mach-ks8695/pci.c3
-rw-r--r--arch/arm/mach-nomadik/Kconfig21
-rw-r--r--arch/arm/mach-nomadik/Makefile19
-rw-r--r--arch/arm/mach-nomadik/Makefile.boot4
-rw-r--r--arch/arm/mach-nomadik/board-nhk8815.c111
-rw-r--r--arch/arm/mach-nomadik/clock.c45
-rw-r--r--arch/arm/mach-nomadik/clock.h14
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c139
-rw-r--r--arch/arm/mach-nomadik/gpio.c396
-rw-r--r--arch/arm/mach-nomadik/i2c-8815nhk.c65
-rw-r--r--arch/arm/mach-nomadik/include/mach/clkdev.h7
-rw-r--r--arch/arm/mach-nomadik/include/mach/debug-macro.S22
-rw-r--r--arch/arm/mach-nomadik/include/mach/entry-macro.S43
-rw-r--r--arch/arm/mach-nomadik/include/mach/gpio.h71
-rw-r--r--arch/arm/mach-nomadik/include/mach/hardware.h90
-rw-r--r--arch/arm/mach-nomadik/include/mach/io.h22
-rw-r--r--arch/arm/mach-nomadik/include/mach/irqs.h82
-rw-r--r--arch/arm/mach-nomadik/include/mach/memory.h28
-rw-r--r--arch/arm/mach-nomadik/include/mach/mtu.h45
-rw-r--r--arch/arm/mach-nomadik/include/mach/setup.h22
-rw-r--r--arch/arm/mach-nomadik/include/mach/system.h45
-rw-r--r--arch/arm/mach-nomadik/include/mach/timex.h6
-rw-r--r--arch/arm/mach-nomadik/include/mach/uncompress.h63
-rw-r--r--arch/arm/mach-nomadik/include/mach/vmalloc.h2
-rw-r--r--arch/arm/mach-nomadik/timer.c164
-rw-r--r--arch/arm/mach-omap1/mcbsp.c1
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c5
-rw-r--r--arch/arm/mach-omap2/mcbsp.c1
-rw-r--r--arch/arm/mach-omap2/usb-musb.c21
-rw-r--r--arch/arm/mach-pxa/Kconfig10
-rw-r--r--arch/arm/mach-pxa/Makefile1
-rw-r--r--arch/arm/mach-pxa/cm-x270.c54
-rw-r--r--arch/arm/mach-pxa/cm-x300.c71
-rw-r--r--arch/arm/mach-pxa/colibri-pxa300.c1
-rw-r--r--arch/arm/mach-pxa/colibri-pxa320.c33
-rw-r--r--arch/arm/mach-pxa/colibri-pxa3xx.c52
-rw-r--r--arch/arm/mach-pxa/corgi.c75
-rw-r--r--arch/arm/mach-pxa/csb726.c54
-rw-r--r--arch/arm/mach-pxa/devices.c27
-rw-r--r--arch/arm/mach-pxa/devices.h2
-rw-r--r--arch/arm/mach-pxa/em-x270.c49
-rw-r--r--arch/arm/mach-pxa/gumstix.c5
-rw-r--r--arch/arm/mach-pxa/idp.c5
-rw-r--r--arch/arm/mach-pxa/imote2.c3
-rw-r--r--arch/arm/mach-pxa/include/mach/colibri.h6
-rw-r--r--arch/arm/mach-pxa/include/mach/irqs.h4
-rw-r--r--arch/arm/mach-pxa/include/mach/mmc.h5
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtc.h86
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtx.h5
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa27x_keypad.h3
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa3xx-regs.h4
-rw-r--r--arch/arm/mach-pxa/littleton.c43
-rw-r--r--arch/arm/mach-pxa/lubbock.c13
-rw-r--r--arch/arm/mach-pxa/magician.c49
-rw-r--r--arch/arm/mach-pxa/mainstone.c11
-rw-r--r--arch/arm/mach-pxa/mioa701.c84
-rw-r--r--arch/arm/mach-pxa/palmld.c117
-rw-r--r--arch/arm/mach-pxa/palmt5.c85
-rw-r--r--arch/arm/mach-pxa/palmtc.c455
-rw-r--r--arch/arm/mach-pxa/palmte2.c80
-rw-r--r--arch/arm/mach-pxa/palmtx.c199
-rw-r--r--arch/arm/mach-pxa/palmz72.c88
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c67
-rw-r--r--arch/arm/mach-pxa/poodle.c53
-rw-r--r--arch/arm/mach-pxa/pxa300.c2
-rw-r--r--arch/arm/mach-pxa/pxa320.c2
-rw-r--r--arch/arm/mach-pxa/pxa930.c19
-rw-r--r--arch/arm/mach-pxa/spitz.c62
-rw-r--r--arch/arm/mach-pxa/tosa.c82
-rw-r--r--arch/arm/mach-pxa/treo680.c2
-rw-r--r--arch/arm/mach-pxa/trizeps4.c3
-rw-r--r--arch/arm/mach-pxa/zylonite.c3
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa300.c2
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa320.c2
-rw-r--r--arch/arm/mach-realview/Kconfig2
-rw-r--r--arch/arm/mach-realview/core.c7
-rw-r--r--arch/arm/mach-realview/include/mach/gpio.h6
-rw-r--r--arch/arm/mach-realview/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-realview/platsmp.c18
-rw-r--r--arch/arm/mach-realview/realview_eb.c22
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c22
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c22
-rw-r--r--arch/arm/mach-realview/realview_pba8.c22
-rw-r--r--arch/arm/mach-realview/realview_pbx.c22
-rw-r--r--arch/arm/mach-s3c2410/include/mach/gpio-core.h2
-rw-r--r--arch/arm/mach-u300/mmc.c2
-rw-r--r--arch/arm/mach-versatile/core.c17
-rw-r--r--arch/arm/mach-versatile/include/mach/gpio.h6
-rw-r--r--arch/arm/mach-versatile/include/mach/irqs.h11
-rw-r--r--arch/arm/mach-versatile/versatile_pb.c17
-rw-r--r--arch/arm/mach-w90x900/Makefile2
-rw-r--r--arch/arm/mach-w90x900/clksel.c91
-rw-r--r--arch/arm/mach-w90x900/clock.c18
-rw-r--r--arch/arm/mach-w90x900/clock.h8
-rw-r--r--arch/arm/mach-w90x900/cpu.h1
-rw-r--r--arch/arm/mach-w90x900/include/mach/regs-clock.h22
-rw-r--r--arch/arm/mach-w90x900/include/mach/regs-ebi.h33
-rw-r--r--arch/arm/mach-w90x900/irq.c154
-rw-r--r--arch/arm/mach-w90x900/mach-w90p910evb.c140
-rw-r--r--arch/arm/mach-w90x900/mfp-w90p910.c44
-rw-r--r--arch/arm/mach-w90x900/w90p910.c88
-rw-r--r--arch/arm/mm/Kconfig2
-rw-r--r--arch/arm/mm/alignment.c20
-rw-r--r--arch/arm/mm/cache-v7.S16
-rw-r--r--arch/arm/mm/context.c2
-rw-r--r--arch/arm/mm/dma-mapping.c94
-rw-r--r--arch/arm/mm/fault.c23
-rw-r--r--arch/arm/mm/flush.c10
-rw-r--r--arch/arm/mm/nommu.c1
-rw-r--r--arch/arm/mm/proc-macros.S8
-rw-r--r--arch/arm/mm/proc-v7.S7
-rw-r--r--arch/arm/plat-omap/debug-leds.c11
-rw-r--r--arch/arm/plat-omap/gpio.c14
-rw-r--r--arch/arm/plat-pxa/include/plat/mfp.h68
-rw-r--r--arch/arm/plat-s3c64xx/pm.c2
-rw-r--r--arch/arm/plat-s3c64xx/s3c6400-clock.c4
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c1
-rw-r--r--arch/arm/tools/mach-types73
-rw-r--r--arch/arm/vfp/entry.S2
-rw-r--r--arch/arm/vfp/vfphw.S48
-rw-r--r--arch/avr32/boards/favr-32/setup.c4
-rw-r--r--arch/avr32/include/asm/pgalloc.h2
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S9
-rw-r--r--arch/avr32/lib/memcpy.S16
-rw-r--r--arch/blackfin/include/asm/bfin_rotary.h39
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S5
-rw-r--r--arch/blackfin/mach-bf538/include/mach/defBF539.h2
-rw-r--r--arch/blackfin/mm/sram-alloc.c6
-rw-r--r--arch/cris/include/arch-v10/arch/mmu.h9
-rw-r--r--arch/cris/include/arch-v32/arch/mmu.h10
-rw-r--r--arch/cris/include/asm/mmu_context.h3
-rw-r--r--arch/cris/include/asm/pgalloc.h2
-rw-r--r--arch/cris/include/asm/pgtable.h2
-rw-r--r--arch/cris/kernel/vmlinux.lds.S9
-rw-r--r--arch/cris/mm/fault.c2
-rw-r--r--arch/frv/include/asm/gdb-stub.h1
-rw-r--r--arch/frv/include/asm/pgalloc.h4
-rw-r--r--arch/frv/include/asm/pgtable.h2
-rw-r--r--arch/frv/kernel/vmlinux.lds.S2
-rw-r--r--arch/frv/lib/cache.S2
-rw-r--r--arch/frv/mb93090-mb00/pci-frv.c10
-rw-r--r--arch/h8300/include/asm/pci.h1
-rw-r--r--arch/h8300/kernel/timer/tpu.c1
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S5
-rw-r--r--arch/ia64/Kconfig3
-rw-r--r--arch/ia64/hp/common/sba_iommu.c7
-rw-r--r--arch/ia64/hp/sim/simeth.c2
-rw-r--r--arch/ia64/ia32/sys_ia32.c2
-rw-r--r--arch/ia64/include/asm/device.h3
-rw-r--r--arch/ia64/include/asm/kvm_host.h4
-rw-r--r--arch/ia64/include/asm/pci.h14
-rw-r--r--arch/ia64/include/asm/pgalloc.h6
-rw-r--r--arch/ia64/include/asm/smp.h1
-rw-r--r--arch/ia64/include/asm/tlb.h12
-rw-r--r--arch/ia64/include/asm/topology.h3
-rw-r--r--arch/ia64/kernel/setup.c6
-rw-r--r--arch/ia64/kernel/smp.c5
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S16
-rw-r--r--arch/ia64/kvm/Kconfig11
-rw-r--r--arch/ia64/kvm/kvm-ia64.c85
-rw-r--r--arch/ia64/kvm/mmio.c6
-rw-r--r--arch/ia64/kvm/vcpu.c10
-rw-r--r--arch/ia64/kvm/vcpu.h13
-rw-r--r--arch/ia64/sn/kernel/setup.c2
-rw-r--r--arch/m32r/include/asm/mmu_context.h4
-rw-r--r--arch/m32r/include/asm/pgalloc.h4
-rw-r--r--arch/m32r/include/asm/smp.h2
-rw-r--r--arch/m32r/kernel/smp.c30
-rw-r--r--arch/m32r/kernel/smpboot.c2
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S10
-rw-r--r--arch/m68k/include/asm/checksum.h173
-rw-r--r--arch/m68k/include/asm/checksum_mm.h148
-rw-r--r--arch/m68k/include/asm/checksum_no.h132
-rw-r--r--arch/m68k/include/asm/dma.h492
-rw-r--r--arch/m68k/include/asm/dma_mm.h16
-rw-r--r--arch/m68k/include/asm/dma_no.h494
-rw-r--r--arch/m68k/include/asm/elia.h41
-rw-r--r--arch/m68k/include/asm/gpio.h238
-rw-r--r--arch/m68k/include/asm/hardirq.h13
-rw-r--r--arch/m68k/include/asm/hardirq_mm.h16
-rw-r--r--arch/m68k/include/asm/hardirq_no.h27
-rw-r--r--arch/m68k/include/asm/irq.h135
-rw-r--r--arch/m68k/include/asm/irq_mm.h126
-rw-r--r--arch/m68k/include/asm/irq_no.h26
-rw-r--r--arch/m68k/include/asm/m5206sim.h33
-rw-r--r--arch/m68k/include/asm/m520xsim.h77
-rw-r--r--arch/m68k/include/asm/m523xsim.h77
-rw-r--r--arch/m68k/include/asm/m5249sim.h54
-rw-r--r--arch/m68k/include/asm/m5272sim.h62
-rw-r--r--arch/m68k/include/asm/m527xsim.h169
-rw-r--r--arch/m68k/include/asm/m528xsim.h151
-rw-r--r--arch/m68k/include/asm/m5307sim.h32
-rw-r--r--arch/m68k/include/asm/m532xsim.h198
-rw-r--r--arch/m68k/include/asm/m5407sim.h28
-rw-r--r--arch/m68k/include/asm/mcfgpio.h40
-rw-r--r--arch/m68k/include/asm/mcfintc.h89
-rw-r--r--arch/m68k/include/asm/mcfsim.h93
-rw-r--r--arch/m68k/include/asm/mcfsmc.h6
-rw-r--r--arch/m68k/include/asm/motorola_pgalloc.h6
-rw-r--r--arch/m68k/include/asm/nettel.h4
-rw-r--r--arch/m68k/include/asm/pinmux.h30
-rw-r--r--arch/m68k/include/asm/processor.h171
-rw-r--r--arch/m68k/include/asm/processor_mm.h130
-rw-r--r--arch/m68k/include/asm/processor_no.h143
-rw-r--r--arch/m68k/include/asm/sun3_pgalloc.h4
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds10
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds9
-rw-r--r--arch/m68knommu/Kconfig6
-rw-r--r--arch/m68knommu/kernel/irq.c26
-rw-r--r--arch/m68knommu/kernel/time.c2
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S7
-rw-r--r--arch/m68knommu/lib/checksum.c11
-rw-r--r--arch/m68knommu/platform/5206/Makefile2
-rw-r--r--arch/m68knommu/platform/5206/config.c56
-rw-r--r--arch/m68knommu/platform/5206/gpio.c49
-rw-r--r--arch/m68knommu/platform/5206e/Makefile2
-rw-r--r--arch/m68knommu/platform/5206e/config.c58
-rw-r--r--arch/m68knommu/platform/5206e/gpio.c49
-rw-r--r--arch/m68knommu/platform/520x/Makefile2
-rw-r--r--arch/m68knommu/platform/520x/config.c30
-rw-r--r--arch/m68knommu/platform/520x/gpio.c211
-rw-r--r--arch/m68knommu/platform/523x/Makefile2
-rw-r--r--arch/m68knommu/platform/523x/config.c63
-rw-r--r--arch/m68knommu/platform/523x/gpio.c283
-rw-r--r--arch/m68knommu/platform/5249/Makefile2
-rw-r--r--arch/m68knommu/platform/5249/config.c49
-rw-r--r--arch/m68knommu/platform/5249/gpio.c65
-rw-r--r--arch/m68knommu/platform/5249/intc2.c59
-rw-r--r--arch/m68knommu/platform/5272/Makefile2
-rw-r--r--arch/m68knommu/platform/5272/config.c78
-rw-r--r--arch/m68knommu/platform/5272/gpio.c81
-rw-r--r--arch/m68knommu/platform/5272/intc.c138
-rw-r--r--arch/m68knommu/platform/527x/Makefile2
-rw-r--r--arch/m68knommu/platform/527x/config.c49
-rw-r--r--arch/m68knommu/platform/527x/gpio.c607
-rw-r--r--arch/m68knommu/platform/528x/Makefile2
-rw-r--r--arch/m68knommu/platform/528x/config.c51
-rw-r--r--arch/m68knommu/platform/528x/gpio.c438
-rw-r--r--arch/m68knommu/platform/5307/Makefile2
-rw-r--r--arch/m68knommu/platform/5307/config.c65
-rw-r--r--arch/m68knommu/platform/5307/gpio.c49
-rw-r--r--arch/m68knommu/platform/532x/Makefile2
-rw-r--r--arch/m68knommu/platform/532x/config.c53
-rw-r--r--arch/m68knommu/platform/532x/gpio.c337
-rw-r--r--arch/m68knommu/platform/5407/Makefile2
-rw-r--r--arch/m68knommu/platform/5407/config.c68
-rw-r--r--arch/m68knommu/platform/5407/gpio.c49
-rw-r--r--arch/m68knommu/platform/68328/ints.c72
-rw-r--r--arch/m68knommu/platform/68360/ints.c44
-rw-r--r--arch/m68knommu/platform/coldfire/Makefile21
-rw-r--r--arch/m68knommu/platform/coldfire/gpio.c127
-rw-r--r--arch/m68knommu/platform/coldfire/intc-2.c93
-rw-r--r--arch/m68knommu/platform/coldfire/intc-simr.c78
-rw-r--r--arch/m68knommu/platform/coldfire/intc.c153
-rw-r--r--arch/m68knommu/platform/coldfire/pinmux.c28
-rw-r--r--arch/m68knommu/platform/coldfire/pit.c8
-rw-r--r--arch/m68knommu/platform/coldfire/timers.c18
-rw-r--r--arch/m68knommu/platform/coldfire/vectors.c20
-rw-r--r--arch/microblaze/Makefile35
-rw-r--r--arch/microblaze/include/asm/device.h3
-rw-r--r--arch/microblaze/include/asm/io.h1
-rw-r--r--arch/microblaze/include/asm/pgalloc.h4
-rw-r--r--arch/microblaze/include/asm/pgtable.h6
-rw-r--r--arch/microblaze/include/asm/prom.h23
-rw-r--r--arch/microblaze/include/asm/tlb.h2
-rw-r--r--arch/microblaze/include/asm/uaccess.h2
-rw-r--r--arch/microblaze/kernel/Makefile2
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c2
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-static.c2
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c2
-rw-r--r--arch/microblaze/kernel/head.S17
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S109
-rw-r--r--arch/microblaze/kernel/module.c19
-rw-r--r--arch/microblaze/kernel/setup.c8
-rw-r--r--arch/microblaze/kernel/sys_microblaze.c99
-rw-r--r--arch/microblaze/kernel/syscall_table.S2
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S6
-rw-r--r--arch/microblaze/mm/fault.c15
-rw-r--r--arch/mips/alchemy/common/time.c2
-rw-r--r--arch/mips/cavium-octeon/Makefile4
-rw-r--r--arch/mips/cavium-octeon/msi.c288
-rw-r--r--arch/mips/cavium-octeon/pci-common.c137
-rw-r--r--arch/mips/cavium-octeon/pci-common.h39
-rw-r--r--arch/mips/cavium-octeon/pci.c568
-rw-r--r--arch/mips/cavium-octeon/pcie.c1370
-rw-r--r--arch/mips/include/asm/mach-ip27/topology.h2
-rw-r--r--arch/mips/include/asm/mmu_context.h10
-rw-r--r--arch/mips/include/asm/pci.h2
-rw-r--r--arch/mips/include/asm/pgalloc.h15
-rw-r--r--arch/mips/include/asm/smp-ops.h2
-rw-r--r--arch/mips/include/asm/smp.h2
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S4
-rw-r--r--arch/mips/kernel/smp-cmp.c6
-rw-r--r--arch/mips/kernel/smp-mt.c6
-rw-r--r--arch/mips/kernel/smp-up.c3
-rw-r--r--arch/mips/kernel/smp.c8
-rw-r--r--arch/mips/kernel/smtc.c6
-rw-r--r--arch/mips/kernel/vmlinux.lds.S21
-rw-r--r--arch/mips/mipssim/sim_smtc.c5
-rw-r--r--arch/mips/mm/c-octeon.c2
-rw-r--r--arch/mips/mti-malta/malta-smtc.c4
-rw-r--r--arch/mips/pmc-sierra/yosemite/smp.c4
-rw-r--r--arch/mips/sgi-ip27/ip27-memory.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-smp.c4
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c5
-rw-r--r--arch/mips/sibyte/sb1250/smp.c5
-rw-r--r--arch/mn10300/include/asm/cacheflush.h4
-rw-r--r--arch/mn10300/include/asm/gdb-stub.h1
-rw-r--r--arch/mn10300/include/asm/mmu_context.h12
-rw-r--r--arch/mn10300/include/asm/pci.h13
-rw-r--r--arch/mn10300/include/asm/pgalloc.h2
-rw-r--r--arch/mn10300/kernel/vmlinux.lds.S8
-rw-r--r--arch/parisc/include/asm/pci.h1
-rw-r--r--arch/parisc/include/asm/smp.h1
-rw-r--r--arch/parisc/include/asm/tlb.h4
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S8
-rw-r--r--arch/powerpc/Kconfig25
-rw-r--r--arch/powerpc/Makefile2
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts49
-rw-r--r--arch/powerpc/boot/dts/kilauea.dts44
-rw-r--r--arch/powerpc/boot/dts/mpc8377_rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/mpc8378_rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/mpc8379_rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/mpc8569mds.dts4
-rwxr-xr-xarch/powerpc/boot/wrapper3
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig298
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig350
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig106
-rw-r--r--arch/powerpc/configs/83xx/kmeter1_defconfig176
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig168
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig168
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_mds_defconfig111
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_rdb_defconfig120
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itx_defconfig114
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig114
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_mds_defconfig104
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_mds_defconfig111
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_rdk_defconfig104
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_mds_defconfig110
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_rdb_defconfig162
-rw-r--r--arch/powerpc/configs/83xx/sbc834x_defconfig103
-rw-r--r--arch/powerpc/configs/85xx/ksi8560_defconfig93
-rw-r--r--arch/powerpc/configs/85xx/mpc8540_ads_defconfig91
-rw-r--r--arch/powerpc/configs/85xx/mpc8560_ads_defconfig99
-rw-r--r--arch/powerpc/configs/85xx/mpc85xx_cds_defconfig99
-rw-r--r--arch/powerpc/configs/85xx/sbc8548_defconfig96
-rw-r--r--arch/powerpc/configs/85xx/sbc8560_defconfig91
-rw-r--r--arch/powerpc/configs/85xx/socrates_defconfig165
-rw-r--r--arch/powerpc/configs/85xx/stx_gp3_defconfig119
-rw-r--r--arch/powerpc/configs/85xx/tqm8540_defconfig100
-rw-r--r--arch/powerpc/configs/85xx/tqm8541_defconfig101
-rw-r--r--arch/powerpc/configs/85xx/tqm8548_defconfig100
-rw-r--r--arch/powerpc/configs/85xx/tqm8555_defconfig101
-rw-r--r--arch/powerpc/configs/85xx/tqm8560_defconfig101
-rw-r--r--arch/powerpc/configs/85xx/xes_mpc85xx_defconfig118
-rw-r--r--arch/powerpc/configs/86xx/gef_ppc9a_defconfig521
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc310_defconfig216
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig130
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig118
-rw-r--r--arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig186
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig112
-rw-r--r--arch/powerpc/configs/adder875_defconfig97
-rw-r--r--arch/powerpc/configs/c2k_defconfig121
-rw-r--r--arch/powerpc/configs/ep8248e_defconfig97
-rw-r--r--arch/powerpc/configs/ep88xc_defconfig91
-rw-r--r--arch/powerpc/configs/linkstation_defconfig116
-rw-r--r--arch/powerpc/configs/mgcoge_defconfig97
-rw-r--r--arch/powerpc/configs/mgsuvd_defconfig89
-rw-r--r--arch/powerpc/configs/mpc7448_hpc2_defconfig103
-rw-r--r--arch/powerpc/configs/mpc8272_ads_defconfig104
-rw-r--r--arch/powerpc/configs/mpc83xx_defconfig162
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig193
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig193
-rw-r--r--arch/powerpc/configs/mpc866_ads_defconfig92
-rw-r--r--arch/powerpc/configs/mpc86xx_defconfig186
-rw-r--r--arch/powerpc/configs/mpc885_ads_defconfig91
-rw-r--r--arch/powerpc/configs/pq2fads_defconfig110
-rw-r--r--arch/powerpc/configs/prpmc2800_defconfig158
-rw-r--r--arch/powerpc/configs/storcenter_defconfig108
-rw-r--r--arch/powerpc/include/asm/bitops.h196
-rw-r--r--arch/powerpc/include/asm/cputhreads.h16
-rw-r--r--arch/powerpc/include/asm/device.h3
-rw-r--r--arch/powerpc/include/asm/exception-64e.h201
-rw-r--r--arch/powerpc/include/asm/exception-64s.h (renamed from arch/powerpc/include/asm/exception.h)25
-rw-r--r--arch/powerpc/include/asm/hw_irq.h5
-rw-r--r--arch/powerpc/include/asm/kvm_host.h4
-rw-r--r--arch/powerpc/include/asm/mmu-40x.h3
-rw-r--r--arch/powerpc/include/asm/mmu-44x.h6
-rw-r--r--arch/powerpc/include/asm/mmu-8xx.h3
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h196
-rw-r--r--arch/powerpc/include/asm/mmu-hash32.h6
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h20
-rw-r--r--arch/powerpc/include/asm/mmu.h37
-rw-r--r--arch/powerpc/include/asm/mmu_context.h15
-rw-r--r--arch/powerpc/include/asm/paca.h23
-rw-r--r--arch/powerpc/include/asm/page.h4
-rw-r--r--arch/powerpc/include/asm/page_64.h10
-rw-r--r--arch/powerpc/include/asm/pci.h1
-rw-r--r--arch/powerpc/include/asm/pgalloc-32.h2
-rw-r--r--arch/powerpc/include/asm/pgalloc-64.h4
-rw-r--r--arch/powerpc/include/asm/pgalloc.h39
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64-64k.h4
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h64
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h6
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h14
-rw-r--r--arch/powerpc/include/asm/pte-book3e.h70
-rw-r--r--arch/powerpc/include/asm/pte-common.h3
-rw-r--r--arch/powerpc/include/asm/reg.h141
-rw-r--r--arch/powerpc/include/asm/reg_booke.h42
-rw-r--r--arch/powerpc/include/asm/smp.h12
-rw-r--r--arch/powerpc/include/asm/systbl.h4
-rw-r--r--arch/powerpc/include/asm/tlb.h38
-rw-r--r--arch/powerpc/include/asm/tlbflush.h11
-rw-r--r--arch/powerpc/include/asm/topology.h12
-rw-r--r--arch/powerpc/include/asm/vdso.h3
-rw-r--r--arch/powerpc/kernel/Makefile10
-rw-r--r--arch/powerpc/kernel/asm-offsets.c19
-rw-r--r--arch/powerpc/kernel/cpu_setup_6xx.S2
-rw-r--r--arch/powerpc/kernel/cputable.c57
-rw-r--r--arch/powerpc/kernel/entry_32.S20
-rw-r--r--arch/powerpc/kernel/entry_64.S102
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S784
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S78
-rw-r--r--arch/powerpc/kernel/fpu.S2
-rw-r--r--arch/powerpc/kernel/head_32.S40
-rw-r--r--arch/powerpc/kernel/head_40x.S124
-rw-r--r--arch/powerpc/kernel/head_44x.S56
-rw-r--r--arch/powerpc/kernel/head_64.S83
-rw-r--r--arch/powerpc/kernel/head_8xx.S13
-rw-r--r--arch/powerpc/kernel/head_booke.h50
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S60
-rw-r--r--arch/powerpc/kernel/paca.c3
-rw-r--r--arch/powerpc/kernel/process.c2
-rw-r--r--arch/powerpc/kernel/prom_init.c4
-rw-r--r--arch/powerpc/kernel/setup-common.c6
-rw-r--r--arch/powerpc/kernel/setup_64.c34
-rw-r--r--arch/powerpc/kernel/smp.c12
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c12
-rw-r--r--arch/powerpc/kernel/udbg_16550.c2
-rw-r--r--arch/powerpc/kernel/vdso.c7
-rw-r--r--arch/powerpc/kernel/vector.S2
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S9
-rw-r--r--arch/powerpc/kvm/44x.c4
-rw-r--r--arch/powerpc/kvm/44x_tlb.c11
-rw-r--r--arch/powerpc/kvm/Kconfig14
-rw-r--r--arch/powerpc/kvm/Makefile4
-rw-r--r--arch/powerpc/kvm/booke.c2
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S18
-rw-r--r--arch/powerpc/kvm/e500.c7
-rw-r--r--arch/powerpc/kvm/e500_emulate.c3
-rw-r--r--arch/powerpc/kvm/e500_tlb.c26
-rw-r--r--arch/powerpc/kvm/e500_tlb.h6
-rw-r--r--arch/powerpc/kvm/emulate.c7
-rw-r--r--arch/powerpc/kvm/powerpc.c32
-rw-r--r--arch/powerpc/kvm/trace.h104
-rw-r--r--arch/powerpc/mm/Makefile1
-rw-r--r--arch/powerpc/mm/hash_low_32.S4
-rw-r--r--arch/powerpc/mm/hugetlbpage.c12
-rw-r--r--arch/powerpc/mm/init_32.c2
-rw-r--r--arch/powerpc/mm/init_64.c55
-rw-r--r--arch/powerpc/mm/mmu_context_nohash.c94
-rw-r--r--arch/powerpc/mm/mmu_decl.h37
-rw-r--r--arch/powerpc/mm/pgtable.c12
-rw-r--r--arch/powerpc/mm/pgtable_64.c59
-rw-r--r--arch/powerpc/mm/slb.c30
-rw-r--r--arch/powerpc/mm/stab.c2
-rw-r--r--arch/powerpc/mm/tlb_hash32.c3
-rw-r--r--arch/powerpc/mm/tlb_hash64.c20
-rw-r--r--arch/powerpc/mm/tlb_low_64e.S734
-rw-r--r--arch/powerpc/mm/tlb_nohash.c268
-rw-r--r--arch/powerpc/mm/tlb_nohash_low.S85
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c13
-rw-r--r--arch/powerpc/platforms/85xx/smp.c1
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c1
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype38
-rw-r--r--arch/powerpc/platforms/amigaone/setup.c6
-rw-r--r--arch/powerpc/platforms/cell/celleb_setup.c3
-rw-r--r--arch/powerpc/platforms/cell/smp.c2
-rw-r--r--arch/powerpc/platforms/iseries/exception.S59
-rw-r--r--arch/powerpc/platforms/iseries/exception.h6
-rw-r--r--arch/powerpc/platforms/powermac/smp.c8
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c2
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c6
-rw-r--r--arch/powerpc/platforms/pseries/smp.c2
-rw-r--r--arch/powerpc/sysdev/mpic.c13
-rw-r--r--arch/powerpc/xmon/xmon.c2
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/Makefile3
-rw-r--r--arch/s390/crypto/des_s390.c11
-rw-r--r--arch/s390/crypto/sha1_s390.c26
-rw-r--r--arch/s390/crypto/sha256_s390.c26
-rw-r--r--arch/s390/crypto/sha512_s390.c36
-rw-r--r--arch/s390/include/asm/atomic.h205
-rw-r--r--arch/s390/include/asm/checksum.h25
-rw-r--r--arch/s390/include/asm/chsc.h28
-rw-r--r--arch/s390/include/asm/cio.h223
-rw-r--r--arch/s390/include/asm/ipl.h5
-rw-r--r--arch/s390/include/asm/kvm.h9
-rw-r--r--arch/s390/include/asm/kvm_host.h15
-rw-r--r--arch/s390/include/asm/percpu.h32
-rw-r--r--arch/s390/include/asm/scsw.h (renamed from drivers/s390/cio/scsw.c)345
-rw-r--r--arch/s390/include/asm/setup.h2
-rw-r--r--arch/s390/include/asm/smp.h2
-rw-r--r--arch/s390/include/asm/timex.h16
-rw-r--r--arch/s390/include/asm/tlb.h9
-rw-r--r--arch/s390/include/asm/topology.h1
-rw-r--r--arch/s390/kernel/Makefile4
-rw-r--r--arch/s390/kernel/early.c41
-rw-r--r--arch/s390/kernel/head.S2
-rw-r--r--arch/s390/kernel/ipl.c166
-rw-r--r--arch/s390/kernel/mcount.S147
-rw-r--r--arch/s390/kernel/mcount64.S78
-rw-r--r--arch/s390/kernel/smp.c11
-rw-r--r--arch/s390/kernel/suspend.c73
-rw-r--r--arch/s390/kernel/swsusp_asm64.S (renamed from arch/s390/power/swsusp_asm64.S)37
-rw-r--r--arch/s390/kernel/time.c9
-rw-r--r--arch/s390/kernel/vdso64/clock_gettime.S11
-rw-r--r--arch/s390/kernel/vmlinux.lds.S9
-rw-r--r--arch/s390/kvm/Kconfig9
-rw-r--r--arch/s390/kvm/gaccess.h23
-rw-r--r--arch/s390/kvm/intercept.c18
-rw-r--r--arch/s390/kvm/interrupt.c10
-rw-r--r--arch/s390/kvm/kvm-s390.c78
-rw-r--r--arch/s390/kvm/kvm-s390.h32
-rw-r--r--arch/s390/kvm/sigp.c60
-rw-r--r--arch/s390/power/Makefile8
-rw-r--r--arch/s390/power/suspend.c40
-rw-r--r--arch/s390/power/swsusp.c30
-rw-r--r--arch/s390/power/swsusp_64.c17
-rw-r--r--arch/sh/Kconfig7
-rw-r--r--arch/sh/Kconfig.debug13
-rw-r--r--arch/sh/Makefile21
-rw-r--r--arch/sh/boards/Kconfig7
-rw-r--r--arch/sh/boards/mach-highlander/setup.c7
-rw-r--r--arch/sh/boards/mach-kfr2r09/Makefile1
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c153
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c1
-rw-r--r--arch/sh/boards/mach-x3proto/setup.c7
-rw-r--r--arch/sh/boot/.gitignore5
-rw-r--r--arch/sh/boot/Makefile48
-rw-r--r--arch/sh/boot/compressed/.gitignore1
-rw-r--r--arch/sh/boot/compressed/Makefile21
-rw-r--r--arch/sh/boot/compressed/misc.c149
-rw-r--r--arch/sh/boot/compressed/misc_32.c206
-rw-r--r--arch/sh/boot/compressed/misc_64.c210
-rw-r--r--arch/sh/boot/compressed/piggy.S8
-rw-r--r--arch/sh/boot/compressed/vmlinux.scr10
-rw-r--r--arch/sh/boot/romimage/Makefile19
-rw-r--r--arch/sh/boot/romimage/head.S10
-rw-r--r--arch/sh/boot/romimage/vmlinux.scr6
-rw-r--r--arch/sh/configs/kfr2r09_defconfig877
-rw-r--r--arch/sh/include/asm/entry-macros.S72
-rw-r--r--arch/sh/include/asm/ftrace.h7
-rw-r--r--arch/sh/include/asm/hwblk.h70
-rw-r--r--arch/sh/include/asm/lmb.h6
-rw-r--r--arch/sh/include/asm/pci.h1
-rw-r--r--arch/sh/include/asm/pgalloc.h10
-rw-r--r--arch/sh/include/asm/pgtable_32.h14
-rw-r--r--arch/sh/include/asm/smp.h1
-rw-r--r--arch/sh/include/asm/suspend.h9
-rw-r--r--arch/sh/include/asm/syscall_32.h1
-rw-r--r--arch/sh/include/asm/thread_info.h11
-rw-r--r--arch/sh/include/asm/tlb.h6
-rw-r--r--arch/sh/include/asm/topology.h1
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7722.h14
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7723.h17
-rw-r--r--arch/sh/include/mach-common/romimage.h1
-rw-r--r--arch/sh/include/mach-kfr2r09/partner-jet-setup.txt134
-rw-r--r--arch/sh/include/mach-kfr2r09/romimage.h75
-rw-r--r--arch/sh/kernel/Makefile_322
-rw-r--r--arch/sh/kernel/asm-offsets.c1
-rw-r--r--arch/sh/kernel/cpu/Makefile2
-rw-r--r--arch/sh/kernel/cpu/hwblk.c155
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-mxg.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7201.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7203.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c2
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c2
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh770x.c2
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c2
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7720.c2
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c2
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c2
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c60
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7723.c110
-rw-r--r--arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c106
-rw-r--r--arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c117
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7343.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7366.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c10
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7723.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7763.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7770.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7786.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c2
-rw-r--r--arch/sh/kernel/cpu/sh5/setup-sh5.c2
-rw-r--r--arch/sh/kernel/cpu/shmobile/Makefile1
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c102
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c26
-rw-r--r--arch/sh/kernel/entry-common.S81
-rw-r--r--arch/sh/kernel/ftrace.c190
-rw-r--r--arch/sh/kernel/io_trapped.c7
-rw-r--r--arch/sh/kernel/irq.c17
-rw-r--r--arch/sh/kernel/process_32.c5
-rw-r--r--arch/sh/kernel/ptrace_32.c8
-rw-r--r--arch/sh/kernel/setup.c71
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c4
-rw-r--r--arch/sh/kernel/time.c29
-rw-r--r--arch/sh/kernel/vmlinux.lds.S94
-rw-r--r--arch/sh/lib/Makefile2
-rw-r--r--arch/sh/lib/mcount.S228
-rw-r--r--arch/sh/mm/fault_32.c164
-rw-r--r--arch/sh/mm/numa.c36
-rw-r--r--arch/sh/tools/mach-types1
-rw-r--r--arch/sparc/Kconfig3
-rw-r--r--arch/sparc/include/asm/device.h3
-rw-r--r--arch/sparc/include/asm/pci_32.h1
-rw-r--r--arch/sparc/include/asm/pci_64.h1
-rw-r--r--arch/sparc/include/asm/pgalloc_32.h8
-rw-r--r--arch/sparc/include/asm/smp_64.h1
-rw-r--r--arch/sparc/include/asm/tlb_64.h6
-rw-r--r--arch/sparc/include/asm/topology_64.h16
-rw-r--r--arch/sparc/kernel/smp_64.c42
-rw-r--r--arch/sparc/kernel/sys32.S2
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S8
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/include/asm/common.lds.S5
-rw-r--r--arch/um/include/asm/mmu_context.h4
-rw-r--r--arch/um/include/asm/pci.h1
-rw-r--r--arch/um/include/asm/pgalloc.h4
-rw-r--r--arch/um/include/asm/tlb.h6
-rw-r--r--arch/um/include/shared/ptrace_user.h2
-rw-r--r--arch/um/kernel/dyn.lds.S2
-rw-r--r--arch/um/kernel/smp.c2
-rw-r--r--arch/um/kernel/uml.lds.S2
-rw-r--r--arch/x86/Kconfig8
-rw-r--r--arch/x86/boot/video-vesa.c7
-rw-r--r--arch/x86/boot/video-vga.c10
-rw-r--r--arch/x86/boot/video.c5
-rw-r--r--arch/x86/boot/video.h20
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c2
-rw-r--r--arch/x86/include/asm/apicdef.h2
-rw-r--r--arch/x86/include/asm/cpufeature.h1
-rw-r--r--arch/x86/include/asm/device.h3
-rw-r--r--arch/x86/include/asm/i387.h1
-rw-r--r--arch/x86/include/asm/ioctls.h95
-rw-r--r--arch/x86/include/asm/ipcbuf.h29
-rw-r--r--arch/x86/include/asm/kvm.h10
-rw-r--r--arch/x86/include/asm/kvm_host.h51
-rw-r--r--arch/x86/include/asm/lguest.h3
-rw-r--r--arch/x86/include/asm/lguest_hcall.h18
-rw-r--r--arch/x86/include/asm/mce.h2
-rw-r--r--arch/x86/include/asm/mman.h14
-rw-r--r--arch/x86/include/asm/mmu_context.h6
-rw-r--r--arch/x86/include/asm/module.h13
-rw-r--r--arch/x86/include/asm/msgbuf.h40
-rw-r--r--arch/x86/include/asm/msr-index.h1
-rw-r--r--arch/x86/include/asm/msr.h4
-rw-r--r--arch/x86/include/asm/param.h23
-rw-r--r--arch/x86/include/asm/paravirt.h711
-rw-r--r--arch/x86/include/asm/paravirt_types.h720
-rw-r--r--arch/x86/include/asm/pci.h1
-rw-r--r--arch/x86/include/asm/percpu.h9
-rw-r--r--arch/x86/include/asm/pgalloc.h25
-rw-r--r--arch/x86/include/asm/pgtable.h16
-rw-r--r--arch/x86/include/asm/processor.h2
-rw-r--r--arch/x86/include/asm/scatterlist.h27
-rw-r--r--arch/x86/include/asm/shmbuf.h52
-rw-r--r--arch/x86/include/asm/smp.h7
-rw-r--r--arch/x86/include/asm/socket.h61
-rw-r--r--arch/x86/include/asm/sockios.h14
-rw-r--r--arch/x86/include/asm/termbits.h199
-rw-r--r--arch/x86/include/asm/termios.h115
-rw-r--r--arch/x86/include/asm/thread_info.h7
-rw-r--r--arch/x86/include/asm/topology.h2
-rw-r--r--arch/x86/include/asm/types.h12
-rw-r--r--arch/x86/include/asm/uaccess.h4
-rw-r--r--arch/x86/include/asm/uaccess_64.h10
-rw-r--r--arch/x86/include/asm/ucontext.h8
-rw-r--r--arch/x86/include/asm/vmx.h8
-rw-r--r--arch/x86/kernel/acpi/cstate.c36
-rw-r--r--arch/x86/kernel/apic/io_apic.c7
-rw-r--r--arch/x86/kernel/cpu/amd.c63
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/cpu_debug.c4
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c20
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c30
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c8
-rw-r--r--arch/x86/kernel/cpu/mtrr/amd.c97
-rw-r--r--arch/x86/kernel/cpu/mtrr/centaur.c168
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c350
-rw-r--r--arch/x86/kernel/cpu/mtrr/cyrix.c94
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c304
-rw-r--r--arch/x86/kernel/cpu/mtrr/if.c135
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c455
-rw-r--r--arch/x86/kernel/cpu/mtrr/mtrr.h19
-rw-r--r--arch/x86/kernel/cpu/mtrr/state.c68
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c14
-rw-r--r--arch/x86/kernel/cpu/proc.c3
-rw-r--r--arch/x86/kernel/ds.c6
-rw-r--r--arch/x86/kernel/head_32.S6
-rw-r--r--arch/x86/kernel/irqinit.c2
-rw-r--r--arch/x86/kernel/kgdb.c9
-rw-r--r--arch/x86/kernel/ldt.c4
-rw-r--r--arch/x86/kernel/mfgpt_32.c2
-rw-r--r--arch/x86/kernel/process.c8
-rw-r--r--arch/x86/kernel/process_32.c27
-rw-r--r--arch/x86/kernel/process_64.c33
-rw-r--r--arch/x86/kernel/reboot.c8
-rw-r--r--arch/x86/kernel/setup.c14
-rw-r--r--arch/x86/kernel/setup_percpu.c297
-rw-r--r--arch/x86/kernel/smpboot.c29
-rw-r--r--arch/x86/kernel/traps.c33
-rw-r--r--arch/x86/kernel/vmlinux.lds.S18
-rw-r--r--arch/x86/kvm/Kconfig21
-rw-r--r--arch/x86/kvm/Makefile35
-rw-r--r--arch/x86/kvm/i8254.c161
-rw-r--r--arch/x86/kvm/i8254.h5
-rw-r--r--arch/x86/kvm/i8259.c58
-rw-r--r--arch/x86/kvm/kvm_cache_regs.h9
-rw-r--r--arch/x86/kvm/kvm_svm.h51
-rw-r--r--arch/x86/kvm/kvm_timer.h2
-rw-r--r--arch/x86/kvm/lapic.c322
-rw-r--r--arch/x86/kvm/lapic.h4
-rw-r--r--arch/x86/kvm/mmu.c381
-rw-r--r--arch/x86/kvm/mmu.h4
-rw-r--r--arch/x86/kvm/mmutrace.h220
-rw-r--r--arch/x86/kvm/paging_tmpl.h54
-rw-r--r--arch/x86/kvm/svm.c271
-rw-r--r--arch/x86/kvm/timer.c16
-rw-r--r--arch/x86/kvm/trace.h355
-rw-r--r--arch/x86/kvm/vmx.c441
-rw-r--r--arch/x86/kvm/x86.c784
-rw-r--r--arch/x86/kvm/x86.h4
-rw-r--r--arch/x86/kvm/x86_emulate.c257
-rw-r--r--arch/x86/lguest/boot.c517
-rw-r--r--arch/x86/lguest/i386_head.S112
-rw-r--r--arch/x86/lib/msr.c60
-rw-r--r--arch/x86/mm/fault.c51
-rw-r--r--arch/x86/mm/highmem_32.c3
-rw-r--r--arch/x86/mm/pageattr.c1
-rw-r--r--arch/x86/mm/pgtable.c6
-rw-r--r--arch/x86/mm/srat_64.c6
-rw-r--r--arch/x86/mm/tlb.c15
-rw-r--r--arch/x86/oprofile/nmi_int.c404
-rw-r--r--arch/x86/oprofile/op_counter.h2
-rw-r--r--arch/x86/oprofile/op_model_amd.c373
-rw-r--r--arch/x86/oprofile/op_model_p4.c72
-rw-r--r--arch/x86/oprofile/op_model_ppro.c101
-rw-r--r--arch/x86/oprofile/op_x86_model.h59
-rw-r--r--arch/x86/pci/amd_bus.c64
-rw-r--r--arch/x86/pci/common.c69
-rw-r--r--arch/x86/xen/mmu.c4
-rw-r--r--arch/xtensa/include/asm/tlb.h2
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S13
-rw-r--r--arch/xtensa/platforms/iss/network.c2
-rw-r--r--block/as-iosched.c10
-rw-r--r--block/blk-core.c165
-rw-r--r--block/blk-integrity.c1
-rw-r--r--block/blk-merge.c49
-rw-r--r--block/blk-settings.c102
-rw-r--r--block/blk.h1
-rw-r--r--block/cfq-iosched.c73
-rw-r--r--block/elevator.c16
-rw-r--r--block/genhd.c18
-rw-r--r--crypto/Kconfig2
-rw-r--r--crypto/Makefile3
-rw-r--r--crypto/ablkcipher.c23
-rw-r--r--crypto/aes_generic.c9
-rw-r--r--crypto/ahash.c336
-rw-r--r--crypto/algapi.c103
-rw-r--r--crypto/algboss.c5
-rw-r--r--crypto/ansi_cprng.c34
-rw-r--r--crypto/api.c54
-rw-r--r--crypto/async_tx/async_xor.c2
-rw-r--r--crypto/authenc.c6
-rw-r--r--crypto/cryptd.c286
-rw-r--r--crypto/hmac.c302
-rw-r--r--crypto/internal.h28
-rw-r--r--crypto/pcompress.c6
-rw-r--r--crypto/sha1_generic.c41
-rw-r--r--crypto/sha256_generic.c100
-rw-r--r--crypto/sha512_generic.c48
-rw-r--r--crypto/shash.c270
-rw-r--r--crypto/tcrypt.c18
-rw-r--r--crypto/testmgr.c21
-rw-r--r--crypto/xcbc.c368
-rw-r--r--drivers/acpi/Kconfig17
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/acpi_memhotplug.c85
-rw-r--r--drivers/acpi/acpi_pad.c514
-rw-r--r--drivers/acpi/acpica/Makefile2
-rw-r--r--drivers/acpi/acpica/acconfig.h10
-rw-r--r--drivers/acpi/acpica/acdebug.h4
-rw-r--r--drivers/acpi/acpica/acglobal.h36
-rw-r--r--drivers/acpi/acpica/achware.h8
-rw-r--r--drivers/acpi/acpica/acinterp.h4
-rw-r--r--drivers/acpi/acpica/aclocal.h13
-rw-r--r--drivers/acpi/acpica/acmacros.h2
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acobject.h1
-rw-r--r--drivers/acpi/acpica/acutils.h30
-rw-r--r--drivers/acpi/acpica/amlcode.h1
-rw-r--r--drivers/acpi/acpica/dsopcode.c24
-rw-r--r--drivers/acpi/acpica/evevent.c13
-rw-r--r--drivers/acpi/acpica/evgpe.c8
-rw-r--r--drivers/acpi/acpica/evgpeblk.c4
-rw-r--r--drivers/acpi/acpica/evrgnini.c45
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/exfield.c82
-rw-r--r--drivers/acpi/acpica/exfldio.c13
-rw-r--r--drivers/acpi/acpica/exutils.c53
-rw-r--r--drivers/acpi/acpica/hwgpe.c34
-rw-r--r--drivers/acpi/acpica/hwregs.c206
-rw-r--r--drivers/acpi/acpica/hwsleep.c24
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c166
-rw-r--r--drivers/acpi/acpica/nsalloc.c88
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c7
-rw-r--r--drivers/acpi/acpica/nsload.c3
-rw-r--r--drivers/acpi/acpica/nspredef.c396
-rw-r--r--drivers/acpi/acpica/nsutils.c5
-rw-r--r--drivers/acpi/acpica/nsxfeval.c23
-rw-r--r--drivers/acpi/acpica/nsxfname.c237
-rw-r--r--drivers/acpi/acpica/tbutils.c82
-rw-r--r--drivers/acpi/acpica/uteval.c375
-rw-r--r--drivers/acpi/acpica/utglobal.c11
-rw-r--r--drivers/acpi/acpica/utids.c382
-rw-r--r--drivers/acpi/acpica/utmisc.c85
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/container.c11
-rw-r--r--drivers/acpi/dock.c8
-rw-r--r--drivers/acpi/ec.c118
-rw-r--r--drivers/acpi/glue.c8
-rw-r--r--drivers/acpi/osl.c25
-rw-r--r--drivers/acpi/pci_root.c17
-rw-r--r--drivers/acpi/processor_core.c244
-rw-r--r--drivers/acpi/processor_idle.c10
-rw-r--r--drivers/acpi/processor_perflib.c3
-rw-r--r--drivers/acpi/processor_thermal.c3
-rw-r--r--drivers/acpi/processor_throttling.c100
-rw-r--r--drivers/acpi/scan.c160
-rw-r--r--drivers/acpi/sleep.c22
-rw-r--r--drivers/acpi/system.c2
-rw-r--r--drivers/amba/bus.c26
-rw-r--r--drivers/ata/Kconfig21
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c6
-rw-r--r--drivers/ata/ata_piix.c3
-rw-r--r--drivers/ata/libata-acpi.c7
-rw-r--r--drivers/ata/libata-core.c66
-rw-r--r--drivers/ata/libata-eh.c148
-rw-r--r--drivers/ata/libata-scsi.c55
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/pata_at91.c67
-rw-r--r--drivers/ata/pata_octeon_cf.c5
-rw-r--r--drivers/ata/pata_pcmcia.c1
-rw-r--r--drivers/ata/pata_rdc.c400
-rw-r--r--drivers/ata/sata_inic162x.c2
-rw-r--r--drivers/ata/sata_mv.c2
-rw-r--r--drivers/ata/sata_sil.c15
-rw-r--r--drivers/atm/solos-pci.c2
-rw-r--r--drivers/base/firmware_class.c1
-rw-r--r--drivers/base/platform.c38
-rw-r--r--drivers/base/power/main.c8
-rw-r--r--drivers/base/sys.c2
-rw-r--r--drivers/base/topology.c10
-rw-r--r--drivers/block/DAC960.c4
-rw-r--r--drivers/block/Kconfig2
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/aoe/aoeblk.c1
-rw-r--r--drivers/block/drbd/Kconfig82
-rw-r--r--drivers/block/drbd/Makefile8
-rw-r--r--drivers/block/drbd/drbd_actlog.c1485
-rw-r--r--drivers/block/drbd/drbd_bitmap.c1321
-rw-r--r--drivers/block/drbd/drbd_int.h2243
-rw-r--r--drivers/block/drbd/drbd_main.c3754
-rw-r--r--drivers/block/drbd/drbd_nl.c2355
-rw-r--r--drivers/block/drbd/drbd_proc.c266
-rw-r--r--drivers/block/drbd/drbd_receiver.c4366
-rw-r--r--drivers/block/drbd/drbd_req.c1130
-rw-r--r--drivers/block/drbd/drbd_req.h299
-rw-r--r--drivers/block/drbd/drbd_strings.c113
-rw-r--r--drivers/block/drbd/drbd_tracing.c752
-rw-r--r--drivers/block/drbd/drbd_tracing.h87
-rw-r--r--drivers/block/drbd/drbd_vli.h351
-rw-r--r--drivers/block/drbd/drbd_worker.c1527
-rw-r--r--drivers/block/drbd/drbd_wrappers.h91
-rw-r--r--drivers/block/floppy.c9
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/mg_disk.c101
-rw-r--r--drivers/block/osdblk.c2
-rw-r--r--drivers/bluetooth/Kconfig25
-rw-r--r--drivers/bluetooth/Makefile6
-rw-r--r--drivers/bluetooth/btmrvl_debugfs.c432
-rw-r--r--drivers/bluetooth/btmrvl_drv.h139
-rw-r--r--drivers/bluetooth/btmrvl_main.c624
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c1002
-rw-r--r--drivers/bluetooth/btmrvl_sdio.h108
-rw-r--r--drivers/bluetooth/btusb.c4
-rw-r--r--drivers/char/agp/hp-agp.c9
-rw-r--r--drivers/char/agp/uninorth-agp.c2
-rw-r--r--drivers/char/hvc_iucv.c2
-rw-r--r--drivers/char/hw_random/amd-rng.c4
-rw-r--r--drivers/char/hw_random/geode-rng.c3
-rw-r--r--drivers/char/mem.c1
-rw-r--r--drivers/char/n_tty.c1
-rw-r--r--drivers/char/random.c14
-rw-r--r--drivers/char/sysrq.c8
-rw-r--r--drivers/char/tty_buffer.c13
-rw-r--r--drivers/char/vr41xx_giu.c0
-rw-r--r--drivers/connector/cn_proc.c3
-rw-r--r--drivers/connector/cn_queue.c7
-rw-r--r--drivers/connector/connector.c6
-rw-r--r--drivers/cpufreq/cpufreq.c286
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c18
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c15
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/amcc/crypto4xx_alg.c3
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c73
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.h25
-rw-r--r--drivers/crypto/padlock-sha.c329
-rw-r--r--drivers/dma/Kconfig12
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/at_hdmac.c1213
-rw-r--r--drivers/dma/at_hdmac_regs.h353
-rw-r--r--drivers/dma/dmatest.c21
-rw-r--r--drivers/dma/dw_dmac.c15
-rw-r--r--drivers/dma/fsldma.c17
-rw-r--r--drivers/dma/fsldma.h1
-rw-r--r--drivers/dma/mv_xor.c2
-rw-r--r--drivers/dma/txx9dmac.c15
-rw-r--r--drivers/edac/Makefile6
-rw-r--r--drivers/edac/amd64_edac.c451
-rw-r--r--drivers/edac/amd64_edac.h71
-rw-r--r--drivers/edac/amd64_edac_dbg.c2
-rw-r--r--drivers/edac/amd64_edac_err_types.c161
-rw-r--r--drivers/edac/edac_core.h2
-rw-r--r--drivers/edac/edac_mce_amd.c422
-rw-r--r--drivers/edac/edac_mce_amd.h69
-rw-r--r--drivers/edac/x38_edac.c2
-rw-r--r--drivers/firmware/dcdbas.c49
-rw-r--r--drivers/gpu/drm/drm_edid.c70
-rw-r--r--drivers/gpu/drm/drm_modes.c416
-rw-r--r--drivers/gpu/drm/mga/mga_state.c4
-rw-r--r--drivers/gpu/drm/radeon/Makefile3
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c293
-rw-r--r--drivers/gpu/drm/radeon/r100.c770
-rw-r--r--drivers/gpu/drm/radeon/r300.c78
-rw-r--r--drivers/gpu/drm/radeon/r300_reg.h4
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/r520.c22
-rw-r--r--drivers/gpu/drm/radeon/r600.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon.h87
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h32
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c59
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c74
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c359
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c70
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c45
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c687
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c188
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h51
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c158
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_share.h39
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c209
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c24
-rw-r--r--drivers/gpu/drm/radeon/rs400.c30
-rw-r--r--drivers/gpu/drm/radeon/rs600.c7
-rw-r--r--drivers/gpu/drm/radeon/rs690.c479
-rw-r--r--drivers/gpu/drm/radeon/rs690r.h99
-rw-r--r--drivers/gpu/drm/radeon/rv515.c798
-rw-r--r--drivers/gpu/drm/radeon/rv515r.h170
-rw-r--r--drivers/gpu/drm/radeon/rv770.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c63
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c69
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c25
-rw-r--r--drivers/hid/Kconfig29
-rw-r--r--drivers/hid/Makefile6
-rw-r--r--drivers/hid/hid-a4tech.c4
-rw-r--r--drivers/hid/hid-apple.c4
-rw-r--r--drivers/hid/hid-belkin.c4
-rw-r--r--drivers/hid/hid-cherry.c4
-rw-r--r--drivers/hid/hid-chicony.c4
-rw-r--r--drivers/hid/hid-core.c59
-rw-r--r--drivers/hid/hid-cypress.c4
-rw-r--r--drivers/hid/hid-debug.c438
-rw-r--r--drivers/hid/hid-ezkey.c4
-rw-r--r--drivers/hid/hid-gyration.c4
-rw-r--r--drivers/hid/hid-ids.h4
-rw-r--r--drivers/hid/hid-input.c13
-rw-r--r--drivers/hid/hid-kensington.c4
-rw-r--r--drivers/hid/hid-kye.c4
-rw-r--r--drivers/hid/hid-lg.c6
-rw-r--r--drivers/hid/hid-lgff.c6
-rw-r--r--drivers/hid/hid-microsoft.c4
-rw-r--r--drivers/hid/hid-monterey.c4
-rw-r--r--drivers/hid/hid-ntrig.c37
-rw-r--r--drivers/hid/hid-petalynx.c4
-rw-r--r--drivers/hid/hid-pl.c4
-rw-r--r--drivers/hid/hid-samsung.c43
-rw-r--r--drivers/hid/hid-sjoy.c4
-rw-r--r--drivers/hid/hid-sony.c4
-rw-r--r--drivers/hid/hid-sunplus.c4
-rw-r--r--drivers/hid/hid-tmff.c10
-rw-r--r--drivers/hid/hid-topseed.c4
-rw-r--r--drivers/hid/hid-twinhan.c147
-rw-r--r--drivers/hid/hid-wacom.c4
-rw-r--r--drivers/hid/hid-zpff.c4
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/asus_atk0110.c6
-rw-r--r--drivers/hwmon/hwmon-vid.c10
-rw-r--r--drivers/hwmon/pc87427.c6
-rw-r--r--drivers/hwmon/smsc47m1.c11
-rw-r--r--drivers/hwmon/tmp421.c347
-rw-r--r--drivers/hwmon/vt1211.c6
-rw-r--r--drivers/i2c/busses/i2c-omap.c42
-rw-r--r--drivers/i2c/busses/i2c-pxa.c25
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c30
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c2
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c45
-rw-r--r--drivers/i2c/chips/tsl2550.c57
-rw-r--r--drivers/ide/ide-acpi.c5
-rw-r--r--drivers/ieee1394/raw1394.c4
-rw-r--r--drivers/ieee802154/fakehard.c132
-rw-r--r--drivers/infiniband/core/mad.c6
-rw-r--r--drivers/infiniband/core/sa_query.c7
-rw-r--r--drivers/infiniband/core/uverbs_main.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_config_reg.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_reset.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c7
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/bf54x-keys.c26
-rw-r--r--drivers/input/keyboard/gpio_keys.c19
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c62
-rw-r--r--drivers/input/keyboard/sh_keysc.c22
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/bfin_rotary.c283
-rw-r--r--drivers/input/misc/cobalt_btns.c2
-rw-r--r--drivers/input/misc/dm355evm_keys.c42
-rw-r--r--drivers/input/serio/at32psif.c2
-rw-r--r--drivers/input/serio/i8042.c44
-rw-r--r--drivers/input/serio/serio.c23
-rw-r--r--drivers/input/touchscreen/Kconfig16
-rw-r--r--drivers/input/touchscreen/atmel_tsadcc.c8
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c53
-rw-r--r--drivers/input/touchscreen/tsc2007.c112
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c5
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c81
-rw-r--r--drivers/input/touchscreen/w90p910_ts.c34
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c6
-rw-r--r--drivers/isdn/Kconfig6
-rw-r--r--drivers/isdn/act2000/capi.c3
-rw-r--r--drivers/isdn/act2000/module.c31
-rw-r--r--drivers/isdn/hardware/eicon/message.c4
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c3
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig51
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile8
-rw-r--r--drivers/isdn/hardware/mISDN/avmfritz.c1152
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c23
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c16
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c16
-rw-r--r--drivers/isdn/hardware/mISDN/iohelper.h109
-rw-r--r--drivers/isdn/hardware/mISDN/ipac.h405
-rw-r--r--drivers/isdn/hardware/mISDN/isar.h269
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c1178
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c1655
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c1726
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c1156
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.h58
-rw-r--r--drivers/isdn/hardware/mISDN/speedfax.c526
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c1440
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.h190
-rw-r--r--drivers/isdn/hisax/Kconfig6
-rw-r--r--drivers/isdn/hisax/Makefile4
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c2
-rw-r--r--drivers/isdn/hisax/callc.c4
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/icc.c2
-rw-r--r--drivers/isdn/hisax/isac.c2
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h70
-rw-r--r--drivers/isdn/hisax/isdnl1.c12
-rw-r--r--drivers/isdn/hisax/isdnl2.c4
-rw-r--r--drivers/isdn/hisax/isdnl3.c4
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c20
-rw-r--r--drivers/isdn/hisax/l3dss1.c26
-rw-r--r--drivers/isdn/hisax/l3ni1.c26
-rw-r--r--drivers/isdn/hisax/q931.c24
-rw-r--r--drivers/isdn/hisax/st5481.h2
-rw-r--r--drivers/isdn/hisax/st5481_b.c5
-rw-r--r--drivers/isdn/hisax/st5481_d.c2
-rw-r--r--drivers/isdn/hisax/st5481_usb.c11
-rw-r--r--drivers/isdn/hisax/tei.c4
-rw-r--r--drivers/isdn/hisax/w6692.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c2
-rw-r--r--drivers/isdn/i4l/Kconfig11
-rw-r--r--drivers/isdn/i4l/Makefile1
-rw-r--r--drivers/isdn/i4l/isdn_common.c4
-rw-r--r--drivers/isdn/i4l/isdn_net.c16
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c6
-rw-r--r--drivers/isdn/i4l/isdnhdlc.c (renamed from drivers/isdn/hisax/isdnhdlc.c)429
-rw-r--r--drivers/isdn/mISDN/hwchannel.c15
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c6
-rw-r--r--drivers/isdn/mISDN/layer2.c2
-rw-r--r--drivers/lguest/core.c119
-rw-r--r--drivers/lguest/hypercalls.c145
-rw-r--r--drivers/lguest/interrupts_and_traps.c288
-rw-r--r--drivers/lguest/lg.h32
-rw-r--r--drivers/lguest/lguest_device.c160
-rw-r--r--drivers/lguest/lguest_user.c232
-rw-r--r--drivers/lguest/page_tables.c528
-rw-r--r--drivers/lguest/segments.c106
-rw-r--r--drivers/lguest/x86/core.c374
-rw-r--r--drivers/lguest/x86/switcher_32.S22
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-delay.c4
-rw-r--r--drivers/md/dm-linear.c2
-rw-r--r--drivers/md/dm-mpath.c2
-rw-r--r--drivers/md/dm-raid1.c5
-rw-r--r--drivers/md/dm-stripe.c9
-rw-r--r--drivers/md/dm-table.c15
-rw-r--r--drivers/md/dm.c22
-rw-r--r--drivers/md/dm.h1
-rw-r--r--drivers/md/linear.c4
-rw-r--r--drivers/md/md.c144
-rw-r--r--drivers/md/md.h4
-rw-r--r--drivers/md/multipath.c9
-rw-r--r--drivers/md/raid0.c3
-rw-r--r--drivers/md/raid1.c21
-rw-r--r--drivers/md/raid10.c10
-rw-r--r--drivers/md/raid5.c53
-rw-r--r--drivers/media/common/tuners/qt1010.c12
-rw-r--r--drivers/media/common/tuners/tuner-types.c25
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c277
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c148
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c231
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.h9
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c8
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c14
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c2
-rw-r--r--drivers/media/dvb/frontends/af9013.c25
-rw-r--r--drivers/media/dvb/frontends/cx24123.c2
-rw-r--r--drivers/media/dvb/frontends/dib0070.c2
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c75
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h4
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c484
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.h11
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx_priv.h12
-rw-r--r--drivers/media/dvb/frontends/mt312.c7
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c8
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c2
-rw-r--r--drivers/media/dvb/frontends/stv6110.c48
-rw-r--r--drivers/media/dvb/frontends/stv6110.h2
-rw-r--r--drivers/media/dvb/frontends/zl10036.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c12
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h4
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/radio/radio-cadet.c6
-rw-r--r--drivers/media/radio/radio-mr800.c2
-rw-r--r--drivers/media/radio/radio-si470x.c390
-rw-r--r--drivers/media/video/Kconfig71
-rw-r--r--drivers/media/video/Makefile4
-rw-r--r--drivers/media/video/adv7343.c1
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c2
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c92
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c15
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c2
-rw-r--r--drivers/media/video/bt8xx/bttv.h1
-rw-r--r--drivers/media/video/cafe_ccic.c1
-rw-r--r--drivers/media/video/cx18/cx18-cards.c8
-rw-r--r--drivers/media/video/cx18/cx18-cards.h18
-rw-r--r--drivers/media/video/cx18/cx18-controls.c3
-rw-r--r--drivers/media/video/cx18/cx18-driver.c41
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c58
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-i2c.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c4
-rw-r--r--drivers/media/video/cx23885/cimax2.c1
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c63
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c77
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c30
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c54
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c1
-rw-r--r--drivers/media/video/cx23885/cx23885.h14
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c15
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c13
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c4
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c4
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c8
-rw-r--r--drivers/media/video/cx88/cx88-video.c4
-rw-r--r--drivers/media/video/davinci/Makefile15
-rw-r--r--drivers/media/video/davinci/ccdc_hw_device.h110
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c978
-rw-r--r--drivers/media/video/davinci/dm355_ccdc_regs.h310
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c878
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc_regs.h145
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2124
-rw-r--r--drivers/media/video/davinci/vpif.c234
-rw-r--r--drivers/media/video/davinci/vpif.h632
-rw-r--r--drivers/media/video/davinci/vpif_display.c1679
-rw-r--r--drivers/media/video/davinci/vpif_display.h175
-rw-r--r--drivers/media/video/davinci/vpss.c301
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c149
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c22
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c62
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c157
-rw-r--r--drivers/media/video/em28xx/em28xx.h31
-rw-r--r--drivers/media/video/gspca/Kconfig16
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/conex.c2
-rw-r--r--drivers/media/video/gspca/gspca.c132
-rw-r--r--drivers/media/video/gspca/gspca.h14
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c6
-rw-r--r--drivers/media/video/gspca/mars.c2
-rw-r--r--drivers/media/video/gspca/pac7311.c1
-rw-r--r--drivers/media/video/gspca/sn9c20x.c2436
-rw-r--r--drivers/media/video/gspca/sonixj.c25
-rw-r--r--drivers/media/video/gspca/spca500.c2
-rw-r--r--drivers/media/video/gspca/spca508.c59
-rw-r--r--drivers/media/video/gspca/stk014.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c16
-rw-r--r--drivers/media/video/gspca/sunplus.c12
-rw-r--r--drivers/media/video/gspca/t613.c210
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c873
-rw-r--r--drivers/media/video/gspca/zc3xx.c2
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c12
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c1
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/video/ir-kbd-i2c.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c70
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c13
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c2
-rw-r--r--drivers/media/video/meye.c3
-rw-r--r--drivers/media/video/mt9v011.c83
-rw-r--r--drivers/media/video/mt9v011.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c1
-rw-r--r--drivers/media/video/pwc/pwc.h6
-rw-r--r--drivers/media/video/pxa_camera.c2
-rw-r--r--drivers/media/video/saa6588.c60
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c5
-rw-r--r--drivers/media/video/saa7134/saa7134.h1
-rw-r--r--drivers/media/video/stv680.c9
-rw-r--r--drivers/media/video/tvp514x.c1030
-rw-r--r--drivers/media/video/tvp514x_regs.h10
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c205
-rw-r--r--drivers/media/video/uvc/uvc_driver.c164
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c14
-rw-r--r--drivers/media/video/uvc/uvc_video.c33
-rw-r--r--drivers/media/video/uvc/uvcvideo.h161
-rw-r--r--drivers/media/video/v4l2-ioctl.c23
-rw-r--r--drivers/media/video/vino.c1
-rw-r--r--drivers/media/video/w9968cf.c1
-rw-r--r--drivers/media/video/zoran/zoran_card.c1
-rw-r--r--drivers/media/video/zr364xx.c1226
-rw-r--r--drivers/message/fusion/mptbase.c4
-rw-r--r--drivers/message/fusion/mptlan.c2
-rw-r--r--drivers/mfd/ab3100-core.c8
-rw-r--r--drivers/mfd/ezx-pcap.c103
-rw-r--r--drivers/mfd/twl4030-irq.c2
-rw-r--r--drivers/misc/Kconfig42
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/cb710/sgbuf2.c4
-rw-r--r--drivers/misc/eeprom/at25.c4
-rw-r--r--drivers/misc/ep93xx_pwm.c384
-rw-r--r--drivers/misc/hwlat_detector.c1208
-rw-r--r--drivers/misc/sgi-xp/xpnet.c4
-rw-r--r--drivers/mmc/host/cb710-mmc.c6
-rw-r--r--drivers/mmc/host/imxmmc.c2
-rw-r--r--drivers/mmc/host/mmci.c71
-rw-r--r--drivers/mmc/host/mmci.h2
-rw-r--r--drivers/mmc/host/mxcmmc.c2
-rw-r--r--drivers/mmc/host/pxamci.c104
-rw-r--r--drivers/mmc/host/sdhci-of.c8
-rw-r--r--drivers/mmc/host/sdhci.c15
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mtd/devices/m25p80.c4
-rw-r--r--drivers/mtd/devices/slram.c2
-rw-r--r--drivers/mtd/ftl.c2
-rw-r--r--drivers/mtd/maps/ixp2000.c2
-rw-r--r--drivers/mtd/nand/cafe_nand.c4
-rw-r--r--drivers/mtd/nand/cmx270_nand.c4
-rw-r--r--drivers/mtd/nand/ts7250.c5
-rw-r--r--drivers/mtd/ubi/eba.c3
-rw-r--r--drivers/mtd/ubi/io.c8
-rw-r--r--drivers/mtd/ubi/scan.c35
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi.h5
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c515.c8
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c527.c4
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c4
-rw-r--r--drivers/net/82596.c4
-rw-r--r--drivers/net/Kconfig3
-rw-r--r--drivers/net/a2065.c4
-rw-r--r--drivers/net/amd8111e.c2
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/appletalk/ipddp.c4
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/am79c961a.c2
-rw-r--r--drivers/net/arm/at91_ether.c5
-rw-r--r--drivers/net/arm/ether1.c2
-rw-r--r--drivers/net/arm/ether3.c4
-rw-r--r--drivers/net/at1700.c4
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atl1c/atl1c_main.c3
-rw-r--r--drivers/net/atl1e/atl1e_main.c3
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/au1000_eth.c2
-rw-r--r--drivers/net/b44.c8
-rw-r--r--drivers/net/benet/Kconfig1
-rw-r--r--drivers/net/benet/be.h60
-rw-r--r--drivers/net/benet/be_cmds.c370
-rw-r--r--drivers/net/benet/be_cmds.h55
-rw-r--r--drivers/net/benet/be_ethtool.c21
-rw-r--r--drivers/net/benet/be_hw.h3
-rw-r--r--drivers/net/benet/be_main.c360
-rw-r--r--drivers/net/bfin_mac.c2
-rw-r--r--drivers/net/bmac.c2
-rw-r--r--drivers/net/bnx2.c24
-rw-r--r--drivers/net/bnx2x.h3
-rw-r--r--drivers/net/bnx2x_hsi.h40
-rw-r--r--drivers/net/bnx2x_link.c1100
-rw-r--r--drivers/net/bnx2x_link.h14
-rw-r--r--drivers/net/bnx2x_main.c270
-rw-r--r--drivers/net/bnx2x_reg.h35
-rw-r--r--drivers/net/bonding/bond_3ad.c7
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/Kconfig7
-rw-r--r--drivers/net/can/sja1000/ems_pci.c152
-rw-r--r--drivers/net/can/sja1000/sja1000.c2
-rw-r--r--drivers/net/cassini.c4
-rw-r--r--drivers/net/cnic.c23
-rw-r--r--drivers/net/cris/eth_v10.c2
-rw-r--r--drivers/net/cs89x0.c4
-rw-r--r--drivers/net/cxgb3/adapter.h10
-rw-r--r--drivers/net/cxgb3/ael1002.c1193
-rw-r--r--drivers/net/cxgb3/aq100x.c7
-rw-r--r--drivers/net/cxgb3/common.h10
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c99
-rw-r--r--drivers/net/cxgb3/t3_hw.c15
-rw-r--r--drivers/net/cxgb3/xgmac.c11
-rw-r--r--drivers/net/de600.c2
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c4
-rw-r--r--drivers/net/defxx.c6
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dm9000.c127
-rw-r--r--drivers/net/dm9000.h18
-rw-r--r--drivers/net/dnet.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000.h7
-rw-r--r--drivers/net/e1000/e1000_ethtool.c51
-rw-r--r--drivers/net/e1000/e1000_hw.c4
-rw-r--r--drivers/net/e1000/e1000_hw.h3
-rw-r--r--drivers/net/e1000/e1000_main.c483
-rw-r--r--drivers/net/eepro.c6
-rw-r--r--drivers/net/eexpress.c10
-rw-r--r--drivers/net/enc28j60.c2
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/eql.c2
-rw-r--r--drivers/net/eth16i.c4
-rw-r--r--drivers/net/ethoc.c2
-rw-r--r--drivers/net/ewrk3.c2
-rw-r--r--drivers/net/fealnx.c5
-rw-r--r--drivers/net/fec.c20
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c20
-rw-r--r--drivers/net/fs_enet/mii-fec.c37
-rw-r--r--drivers/net/gianfar.c25
-rw-r--r--drivers/net/gianfar_ethtool.c10
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/6pack.c2
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c4
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c6
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hp100.c6
-rw-r--r--drivers/net/ibm_newemac/core.c2
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ifb.c2
-rw-r--r--drivers/net/igb/e1000_82575.c193
-rw-r--r--drivers/net/igb/e1000_82575.h6
-rw-r--r--drivers/net/igb/e1000_defines.h8
-rw-r--r--drivers/net/igb/e1000_hw.h18
-rw-r--r--drivers/net/igb/e1000_mac.c175
-rw-r--r--drivers/net/igb/e1000_mac.h3
-rw-r--r--drivers/net/igb/e1000_phy.c4
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb_ethtool.c65
-rw-r--r--drivers/net/igb/igb_main.c121
-rw-r--r--drivers/net/igbvf/netdev.c8
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/irda/ali-ircc.c12
-rw-r--r--drivers/net/irda/au1k_ir.c4
-rw-r--r--drivers/net/irda/donauboe.c8
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c10
-rw-r--r--drivers/net/irda/pxaficp_ir.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c4
-rw-r--r--drivers/net/irda/sir_dev.c6
-rw-r--r--drivers/net/irda/smsc-ircc2.c16
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/via-ircc.c12
-rw-r--r--drivers/net/irda/vlsi_ir.c6
-rw-r--r--drivers/net/irda/w83977af_ir.c4
-rw-r--r--drivers/net/isa-skeleton.c2
-rw-r--r--drivers/net/iseries_veth.c4
-rw-r--r--drivers/net/ixgb/ixgb_main.c7
-rw-r--r--drivers/net/ixgbe/ixgbe.h7
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c1
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c24
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c44
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c89
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h32
-rw-r--r--drivers/net/ixp2000/ixpdev.c4
-rw-r--r--drivers/net/jazzsonic.c4
-rw-r--r--drivers/net/jme.c189
-rw-r--r--drivers/net/jme.h21
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lib82596.c4
-rw-r--r--drivers/net/lib8390.c2
-rw-r--r--drivers/net/ll_temac_main.c2
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/macb.c4
-rw-r--r--drivers/net/mace.c2
-rw-r--r--drivers/net/meth.c4
-rw-r--r--drivers/net/mipsnet.c2
-rw-r--r--drivers/net/mlx4/cq.c1
-rw-r--r--drivers/net/mlx4/en_tx.c2
-rw-r--r--drivers/net/mlx4/eq.c1
-rw-r--r--drivers/net/mlx4/icm.c1
-rw-r--r--drivers/net/mlx4/main.c26
-rw-r--r--drivers/net/mlx4/mcg.c1
-rw-r--r--drivers/net/mlx4/mr.c1
-rw-r--r--drivers/net/mlx4/pd.c1
-rw-r--r--drivers/net/mlx4/profile.c2
-rw-r--r--drivers/net/mlx4/qp.c2
-rw-r--r--drivers/net/mlx4/reset.c1
-rw-r--r--drivers/net/mlx4/srq.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/netxen/netxen_nic.h177
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c6
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c81
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h2
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c28
-rw-r--r--drivers/net/netxen/netxen_nic_init.c137
-rw-r--r--drivers/net/netxen/netxen_nic_main.c625
-rw-r--r--drivers/net/ni5010.c2
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/pci-skeleton.c2
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c4
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c4
-rw-r--r--drivers/net/pcnet32.c32
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/bcm63xx.c132
-rw-r--r--drivers/net/phy/mdio-gpio.c77
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp_generic.c38
-rw-r--r--drivers/net/pppoe.c1
-rw-r--r--drivers/net/pppol2tp.c1
-rw-r--r--drivers/net/qlge/qlge_main.c5
-rw-r--r--drivers/net/r6040.c4
-rw-r--r--drivers/net/r8169.c13
-rw-r--r--drivers/net/rionet.c9
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c13
-rw-r--r--drivers/net/s6gmac.c2
-rw-r--r--drivers/net/sb1000.c2
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/seeq8005.c4
-rw-r--r--drivers/net/sfc/efx.c3
-rw-r--r--drivers/net/sgiseeq.c6
-rw-r--r--drivers/net/sh_eth.c2
-rw-r--r--drivers/net/sis900.c2
-rw-r--r--drivers/net/skfp/skfddi.c4
-rw-r--r--drivers/net/skge.c4
-rw-r--r--drivers/net/sky2.c2
-rw-r--r--drivers/net/slip.c6
-rw-r--r--drivers/net/smc911x.c6
-rw-r--r--drivers/net/smc9194.c8
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/net/smc91x.h3
-rw-r--r--drivers/net/sonic.c4
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/sun3_82586.c4
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c2
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tlan.c6
-rw-r--r--drivers/net/tokenring/3c359.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c4
-rw-r--r--drivers/net/tokenring/lanstreamer.c2
-rw-r--r--drivers/net/tokenring/olympic.c2
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c2
-rw-r--r--drivers/net/tulip/de2104x.c2
-rw-r--r--drivers/net/tulip/de4x5.c6
-rw-r--r--drivers/net/tulip/dmfe.c4
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/tulip/uli526x.c4
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c2
-rw-r--r--drivers/net/tun.c18
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/ucc_geth.c65
-rw-r--r--drivers/net/ucc_geth.h2
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/hso.c2
-rw-r--r--drivers/net/usb/kaweth.c4
-rw-r--r--drivers/net/usb/pegasus.c2
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/usbnet.c14
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/via-velocity.c3431
-rw-r--r--drivers/net/via-velocity.h6
-rw-r--r--drivers/net/virtio_net.c3
-rw-r--r--drivers/net/vxge/vxge-config.c10
-rw-r--r--drivers/net/vxge/vxge-config.h10
-rw-r--r--drivers/net/vxge/vxge-main.c103
-rw-r--r--drivers/net/vxge/vxge-main.h4
-rw-r--r--drivers/net/vxge/vxge-reg.h9
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
-rw-r--r--drivers/net/vxge/vxge-version.h2
-rw-r--r--drivers/net/wan/cycx_x25.c2
-rw-r--r--drivers/net/wan/dlci.c4
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wan/farsync.c27
-rw-r--r--drivers/net/wan/hdlc_fr.c6
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wan/x25_asy.c10
-rw-r--r--drivers/net/wimax/i2400m/sdio.c12
-rw-r--r--drivers/net/wireless/Kconfig6
-rw-r--r--drivers/net/wireless/adm8211.c20
-rw-r--r--drivers/net/wireless/airo.c27
-rw-r--r--drivers/net/wireless/arlan-main.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h52
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c617
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h21
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c133
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h10
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h14
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig4
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h61
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c95
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h54
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c1229
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h163
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c183
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h23
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h1563
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c132
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c609
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c92
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h93
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c186
-rw-r--r--drivers/net/wireless/ath/regd.c19
-rw-r--r--drivers/net/wireless/ath/regd_common.h2
-rw-r--r--drivers/net/wireless/atmel.c8
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c3
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c3
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c42
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c13
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c79
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c76
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c73
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c134
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c101
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c266
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c522
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c162
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h158
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c63
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c526
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h93
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c67
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c137
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c201
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Makefile2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c373
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c148
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c21
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h39
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c45
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c36
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c132
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c723
-rw-r--r--drivers/net/wireless/libertas/assoc.c34
-rw-r--r--drivers/net/wireless/libertas/cmd.c8
-rw-r--r--drivers/net/wireless/libertas/defs.h2
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/libertas/if_spi.c8
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/scan.c3
-rw-r--r--drivers/net/wireless/libertas/wext.c2
-rw-r--r--drivers/net/wireless/libertas_tf/main.c3
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c97
-rw-r--r--drivers/net/wireless/mwl8k.c9
-rw-r--r--drivers/net/wireless/netwave_cs.c2
-rw-r--r--drivers/net/wireless/orinoco/Kconfig1
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/airport.c98
-rw-r--r--drivers/net/wireless/orinoco/cfg.c162
-rw-r--r--drivers/net/wireless/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/orinoco/fw.c41
-rw-r--r--drivers/net/wireless/orinoco/hermes.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c50
-rw-r--r--drivers/net/wireless/orinoco/hw.c668
-rw-r--r--drivers/net/wireless/orinoco/hw.h11
-rw-r--r--drivers/net/wireless/orinoco/main.c1132
-rw-r--r--drivers/net/wireless/orinoco/main.h3
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h49
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h57
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c291
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/wext.c878
-rw-r--r--drivers/net/wireless/p54/Makefile3
-rw-r--r--drivers/net/wireless/p54/eeprom.c753
-rw-r--r--drivers/net/wireless/p54/eeprom.h226
-rw-r--r--drivers/net/wireless/p54/fwio.c715
-rw-r--r--drivers/net/wireless/p54/led.c163
-rw-r--r--drivers/net/wireless/p54/lmac.h558
-rw-r--r--drivers/net/wireless/p54/main.c637
-rw-r--r--drivers/net/wireless/p54/p54.h151
-rw-r--r--drivers/net/wireless/p54/p54common.c2688
-rw-r--r--drivers/net/wireless/p54/p54common.h644
-rw-r--r--drivers/net/wireless/p54/p54pci.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c52
-rw-r--r--drivers/net/wireless/p54/p54usb.c42
-rw-r--r--drivers/net/wireless/p54/txrx.c860
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/ray_cs.c9
-rw-r--r--drivers/net/wireless/rndis_wlan.c298
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig8
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c16
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h23
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c28
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c3
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c3
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.c4
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig17
-rw-r--r--drivers/net/wireless/wl12xx/Makefile9
-rw-r--r--drivers/net/wireless/wl12xx/acx.c689
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c353
-rw-r--r--drivers/net/wireless/wl12xx/reg.h1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h479
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c840
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)199
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c (renamed from drivers/net/wireless/wl12xx/boot.c)114
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c428
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)194
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)60
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)16
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)54
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c (renamed from drivers/net/wireless/wl12xx/init.c)78
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h (renamed from drivers/net/wireless/wl12xx/init.h)27
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)659
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.c (renamed from drivers/net/wireless/wl12xx/wl1251.c)299
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.h165
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)64
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)18
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)90
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)24
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)179
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)62
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c (renamed from drivers/net/wireless/wl12xx/tx.c)124
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h (renamed from drivers/net/wireless/wl12xx/tx.h)21
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h409
-rw-r--r--drivers/net/wireless/wl3501_cs.c3
-rw-r--r--drivers/net/wireless/zd1201.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c74
-rw-r--r--drivers/net/xen-netfront.c4
-rw-r--r--drivers/net/xtsonic.c2
-rw-r--r--drivers/net/yellowfin.c4
-rw-r--r--drivers/net/znet.c4
-rw-r--r--drivers/of/of_mdio.c42
-rw-r--r--drivers/oprofile/buffer_sync.c3
-rw-r--r--drivers/oprofile/cpu_buffer.c16
-rw-r--r--drivers/oprofile/oprof.c71
-rw-r--r--drivers/oprofile/oprof.h3
-rw-r--r--drivers/oprofile/oprofile_files.c46
-rw-r--r--drivers/oprofile/oprofile_stats.c5
-rw-r--r--drivers/oprofile/oprofile_stats.h1
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c28
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c12
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c7
-rw-r--r--drivers/pci/intel-iommu.c44
-rw-r--r--drivers/pci/iova.c16
-rw-r--r--drivers/pci/legacy.c34
-rw-r--r--drivers/pci/pci-driver.c16
-rw-r--r--drivers/pci/pci-sysfs.c37
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pci/pci.h1
-rw-r--r--drivers/pci/probe.c3
-rw-r--r--drivers/pci/quirks.c3
-rw-r--r--drivers/pci/search.c31
-rw-r--r--drivers/pci/setup-res.c5
-rw-r--r--drivers/pcmcia/pxa2xx_base.c18
-rw-r--r--drivers/pcmcia/yenta_socket.c16
-rw-r--r--drivers/platform/x86/Kconfig25
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/eeepc-laptop.c9
-rw-r--r--drivers/platform/x86/hp-wmi.c27
-rw-r--r--drivers/platform/x86/sony-laptop.c7
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c390
-rw-r--r--drivers/pnp/pnpacpi/core.c6
-rw-r--r--drivers/power/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/ds2760_battery.c141
-rw-r--r--drivers/power/ds2782_battery.c330
-rw-r--r--drivers/power/olpc_battery.c76
-rw-r--r--drivers/power/power_supply_core.c44
-rw-r--r--drivers/power/power_supply_sysfs.c12
-rw-r--r--drivers/power/wm8350_power.c22
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/core.c214
-rw-r--r--drivers/regulator/da903x.c75
-rw-r--r--drivers/regulator/pcap-regulator.c318
-rw-r--r--drivers/regulator/pcf50633-regulator.c2
-rw-r--r--drivers/regulator/virtual.c56
-rw-r--r--drivers/regulator/wm8350-regulator.c2
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-cmos.c23
-rw-r--r--drivers/rtc/rtc-msm6242.c268
-rw-r--r--drivers/rtc/rtc-pxa.c27
-rw-r--r--drivers/rtc/rtc-rp5c01.c222
-rw-r--r--drivers/rtc/rtc-sa1100.c23
-rw-r--r--drivers/s390/block/dasd.c26
-rw-r--r--drivers/s390/block/dasd_3990_erp.c2
-rw-r--r--drivers/s390/block/dasd_alias.c5
-rw-r--r--drivers/s390/block/dasd_diag.c5
-rw-r--r--drivers/s390/block/dasd_eckd.c47
-rw-r--r--drivers/s390/block/dasd_eer.c4
-rw-r--r--drivers/s390/block/dasd_erp.c4
-rw-r--r--drivers/s390/block/dasd_fba.c9
-rw-r--r--drivers/s390/block/dasd_int.h11
-rw-r--r--drivers/s390/block/dasd_ioctl.c24
-rw-r--r--drivers/s390/char/monreader.c2
-rw-r--r--drivers/s390/char/tape_std.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c4
-rw-r--r--drivers/s390/cio/Makefile2
-rw-r--r--drivers/s390/cio/chp.c3
-rw-r--r--drivers/s390/cio/chsc.h24
-rw-r--r--drivers/s390/cio/css.c26
-rw-r--r--drivers/s390/cio/device.c10
-rw-r--r--drivers/s390/cio/device_fsm.c13
-rw-r--r--drivers/s390/cio/qdio.h4
-rw-r--r--drivers/s390/cio/qdio_debug.c55
-rw-r--r--drivers/s390/cio/qdio_main.c4
-rw-r--r--drivers/s390/crypto/ap_bus.c11
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_main.c10
-rw-r--r--drivers/s390/net/lcs.c8
-rw-r--r--drivers/s390/net/netiucv.c10
-rw-r--r--drivers/s390/net/qeth_l2_main.c1
-rw-r--r--drivers/s390/net/qeth_l3_main.c1
-rw-r--r--drivers/s390/net/smsgiucv.c6
-rw-r--r--drivers/s390/scsi/zfcp_aux.c12
-rw-r--r--drivers/s390/scsi/zfcp_erp.c68
-rw-r--r--drivers/s390/scsi/zfcp_fc.c8
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c56
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c25
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c7
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c100
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c7
-rw-r--r--drivers/scsi/constants.c95
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c23
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c2
-rw-r--r--drivers/scsi/fcoe/libfcoe.c6
-rw-r--r--drivers/scsi/libfc/fc_exch.c23
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/libsas/sas_expander.c147
-rw-r--r--drivers/scsi/libsas/sas_port.c19
-rw-r--r--drivers/scsi/lpfc/Makefile2
-rw-r--r--drivers/scsi/lpfc/lpfc.h19
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c904
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c259
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h74
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c93
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c41
-rw-r--r--drivers/scsi/lpfc/lpfc_nl.h20
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c263
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c53
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c15
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h9
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c133
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c145
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c10
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c44
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi_lib.c7
-rw-r--r--drivers/scsi/scsi_transport_fc.c4
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/scsi_transport_sas.c4
-rw-r--r--drivers/scsi/sd.c20
-rw-r--r--drivers/serial/amba-pl011.c26
-rw-r--r--drivers/serial/atmel_serial.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/serial/pxa.c20
-rw-r--r--drivers/serial/sh-sci.c5
-rw-r--r--drivers/spi/amba-pl022.c2
-rw-r--r--drivers/spi/omap2_mcspi.c32
-rw-r--r--drivers/spi/pxa2xx_spi.c30
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/agnx/xmit.c3
-rw-r--r--drivers/staging/android/lowmemorykiller.c8
-rw-r--r--drivers/staging/at76_usb/at76_usb.c8
-rw-r--r--drivers/staging/dst/dcore.c8
-rw-r--r--drivers/staging/epl/VirtualEthernetLinux.c2
-rw-r--r--drivers/staging/otus/usbdrv.c8
-rw-r--r--drivers/staging/otus/wrap_pkt.c3
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c6
-rw-r--r--drivers/staging/rt2860/rtmp.h2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c4
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c4
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c20
-rw-r--r--drivers/staging/slicoss/slicoss.c2
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.c3
-rw-r--r--drivers/staging/uc2322/Kconfig10
-rw-r--r--drivers/staging/uc2322/Makefile1
-rw-r--r--drivers/staging/uc2322/TODO7
-rw-r--r--drivers/staging/uc2322/aten2011.c2430
-rw-r--r--drivers/staging/udlfb/udlfb.c1
-rw-r--r--drivers/staging/winbond/wb35rx.c3
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c2
-rw-r--r--drivers/usb/core/config.c48
-rw-r--r--drivers/usb/core/devio.c10
-rw-r--r--drivers/usb/gadget/Kconfig10
-rw-r--r--drivers/usb/gadget/f_phonet.c2
-rw-r--r--drivers/usb/gadget/m66592-udc.c284
-rw-r--r--drivers/usb/gadget/m66592-udc.h90
-rw-r--r--drivers/usb/gadget/u_ether.c6
-rw-r--r--drivers/usb/host/Kconfig7
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/ehci-q.c15
-rw-r--r--drivers/usb/host/ehci-sched.c1
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/ohci-omap.c1
-rw-r--r--drivers/usb/host/ohci-pxa27x.c26
-rw-r--r--drivers/usb/host/ohci-q.c2
-rw-r--r--drivers/usb/host/r8a66597-hcd.c210
-rw-r--r--drivers/usb/host/r8a66597.h440
-rw-r--r--drivers/usb/host/xhci-dbg.c199
-rw-r--r--drivers/usb/host/xhci-hcd.c290
-rw-r--r--drivers/usb/host/xhci-mem.c300
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c305
-rw-r--r--drivers/usb/host/xhci.h150
-rw-r--r--drivers/usb/misc/Kconfig2
-rw-r--r--drivers/usb/musb/Kconfig1
-rw-r--r--drivers/usb/musb/musb_core.c21
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c2
-rw-r--r--drivers/usb/musb/musb_regs.h1
-rw-r--r--drivers/usb/serial/cp210x.c3
-rw-r--r--drivers/usb/serial/cypress_m8.h2
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.h7
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/serial/mos7840.c9
-rw-r--r--drivers/usb/serial/option.c133
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/usb/serial/usb-serial.c36
-rw-r--r--drivers/usb/storage/transport.c2
-rw-r--r--drivers/usb/wusbcore/wa-hc.h2
-rw-r--r--drivers/video/Kconfig6
-rw-r--r--drivers/video/atmel_lcdfb.c6
-rw-r--r--drivers/video/backlight/Kconfig2
-rw-r--r--drivers/video/backlight/da903x_bl.c20
-rw-r--r--drivers/video/backlight/jornada720_bl.c2
-rw-r--r--drivers/video/omap/lcd_h3.c4
-rw-r--r--drivers/video/omap/lcd_h4.c4
-rw-r--r--drivers/video/omap/lcd_inn1510.c4
-rw-r--r--drivers/video/omap/lcd_inn1610.c4
-rw-r--r--drivers/video/omap/lcd_osk.c4
-rw-r--r--drivers/video/omap/lcd_palmte.c4
-rw-r--r--drivers/video/omap/lcd_palmtt.c4
-rw-r--r--drivers/video/omap/lcd_palmz71.c4
-rw-r--r--drivers/video/pxafb.c29
-rw-r--r--drivers/video/s3c-fb.c4
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c16
-rw-r--r--drivers/video/uvesafb.c3
-rw-r--r--drivers/virtio/virtio_pci.c248
-rw-r--r--drivers/w1/w1_netlink.c3
-rw-r--r--drivers/watchdog/coh901327_wdt.c11
-rw-r--r--drivers/xen/events.c13
-rw-r--r--firmware/Makefile5
-rw-r--r--firmware/WHENCE17
-rw-r--r--firmware/cxgb3/ael2005_opt_edc.bin.ihex69
-rw-r--r--firmware/cxgb3/ael2005_twx_edc.bin.ihex93
-rw-r--r--firmware/cxgb3/ael2020_twx_edc.bin.ihex100
-rw-r--r--fs/9p/vfs_inode.c126
-rw-r--r--fs/9p/vfs_super.c20
-rw-r--r--fs/block_dev.c10
-rw-r--r--fs/btrfs/async-thread.c4
-rw-r--r--fs/btrfs/ctree.c121
-rw-r--r--fs/btrfs/ctree.h27
-rw-r--r--fs/btrfs/disk-io.c16
-rw-r--r--fs/btrfs/extent-tree.c517
-rw-r--r--fs/btrfs/free-space-cache.c1003
-rw-r--r--fs/btrfs/free-space-cache.h8
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/print-tree.c6
-rw-r--r--fs/btrfs/relocation.c3
-rw-r--r--fs/btrfs/transaction.c56
-rw-r--r--fs/btrfs/transaction.h1
-rw-r--r--fs/btrfs/tree-log.c2
-rw-r--r--fs/btrfs/volumes.c50
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/char_dev.c1
-rw-r--r--fs/cifs/CHANGES6
-rw-r--r--fs/cifs/cifs_dfs_ref.c12
-rw-r--r--fs/cifs/connect.c63
-rw-r--r--fs/cifs/inode.c9
-rw-r--r--fs/configfs/inode.c1
-rw-r--r--fs/dlm/netlink.c2
-rw-r--r--fs/ecryptfs/crypto.c10
-rw-r--r--fs/ecryptfs/keystore.c24
-rw-r--r--fs/ecryptfs/super.c2
-rw-r--r--fs/ext3/dir.c3
-rw-r--r--fs/ext3/inode.c32
-rw-r--r--fs/ext4/inode.c2
-rw-r--r--fs/ext4/mballoc.c10
-rw-r--r--fs/fat/inode.c4
-rw-r--r--fs/fat/namei_vfat.c15
-rw-r--r--fs/fs-writeback.c775
-rw-r--r--fs/fuse/dev.c10
-rw-r--r--fs/fuse/fuse_i.h12
-rw-r--r--fs/fuse/inode.c15
-rw-r--r--fs/gfs2/aops.c39
-rw-r--r--fs/gfs2/glock.c138
-rw-r--r--fs/gfs2/glock.h3
-rw-r--r--fs/gfs2/glops.c21
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/inode.c2
-rw-r--r--fs/gfs2/ops_fstype.c13
-rw-r--r--fs/gfs2/rgrp.c61
-rw-r--r--fs/gfs2/rgrp.h2
-rw-r--r--fs/gfs2/super.c41
-rw-r--r--fs/gfs2/super.h8
-rw-r--r--fs/gfs2/sys.c13
-rw-r--r--fs/hugetlbfs/inode.c1
-rw-r--r--fs/jbd/journal.c26
-rw-r--r--fs/jbd/transaction.c68
-rw-r--r--fs/jfs/acl.c4
-rw-r--r--fs/locks.c2
-rw-r--r--fs/nfs/client.c1
-rw-r--r--fs/nfsd/nfs4proc.c82
-rw-r--r--fs/nfsd/nfs4state.c164
-rw-r--r--fs/nfsd/nfs4xdr.c3
-rw-r--r--fs/nfsd/nfsctl.c5
-rw-r--r--fs/nfsd/nfssvc.c23
-rw-r--r--fs/nilfs2/mdt.c4
-rw-r--r--fs/nilfs2/segment.c23
-rw-r--r--fs/nilfs2/super.c86
-rw-r--r--fs/nilfs2/the_nilfs.h14
-rw-r--r--fs/nls/nls_base.c8
-rw-r--r--fs/notify/Kconfig12
-rw-r--r--fs/notify/dnotify/Kconfig2
-rw-r--r--fs/notify/dnotify/dnotify.c2
-rw-r--r--fs/notify/fsnotify.c4
-rw-r--r--fs/notify/inode_mark.c18
-rw-r--r--fs/notify/inotify/Kconfig2
-rw-r--r--fs/notify/inotify/inotify_user.c109
-rw-r--r--fs/notify/notification.c19
-rw-r--r--fs/ntfs/layout.h2
-rw-r--r--fs/ocfs2/alloc.c47
-rw-r--r--fs/ocfs2/aops.c3
-rw-r--r--fs/ocfs2/dcache.c35
-rw-r--r--fs/ocfs2/dcache.h3
-rw-r--r--fs/ocfs2/dlm/dlmast.c1
-rw-r--r--fs/ocfs2/dlm/dlmfs.c1
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c2
-rw-r--r--fs/ocfs2/file.c5
-rw-r--r--fs/ocfs2/journal.c8
-rw-r--r--fs/ocfs2/journal.h14
-rw-r--r--fs/ocfs2/ocfs2.h22
-rw-r--r--fs/ocfs2/quota.h1
-rw-r--r--fs/ocfs2/quota_global.c33
-rw-r--r--fs/ocfs2/quota_local.c110
-rw-r--r--fs/ocfs2/super.c30
-rw-r--r--fs/ocfs2/xattr.c3
-rw-r--r--fs/proc/base.c23
-rw-r--r--fs/proc/uptime.c7
-rw-r--r--fs/quota/dquot.c7
-rw-r--r--fs/ramfs/file-nommu.c1
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/reiserfs/Makefile2
-rw-r--r--fs/reiserfs/bitmap.c4
-rw-r--r--fs/reiserfs/dir.c101
-rw-r--r--fs/reiserfs/do_balan.c17
-rw-r--r--fs/reiserfs/fix_node.c19
-rw-r--r--fs/reiserfs/inode.c73
-rw-r--r--fs/reiserfs/ioctl.c6
-rw-r--r--fs/reiserfs/journal.c109
-rw-r--r--fs/reiserfs/lock.c89
-rw-r--r--fs/reiserfs/namei.c13
-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.c4
-rw-r--r--fs/super.c3
-rw-r--r--fs/sync.c2
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/sysfs/inode.c1
-rw-r--r--fs/ubifs/commit.c2
-rw-r--r--fs/ubifs/key.h36
-rw-r--r--fs/ubifs/super.c38
-rw-r--r--fs/udf/directory.c86
-rw-r--r--fs/udf/inode.c19
-rw-r--r--fs/udf/lowlevel.c4
-rw-r--r--fs/udf/namei.c1
-rw-r--r--fs/udf/super.c12
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c8
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c15
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.h1
-rw-r--r--fs/xfs/xfs_bmap.c2
-rw-r--r--fs/xfs/xfs_bmap.h11
-rw-r--r--fs/xfs/xfs_bmap_btree.c20
-rw-r--r--fs/xfs/xfs_bmap_btree.h1
-rw-r--r--fs/xfs/xfs_btree.c42
-rw-r--r--fs/xfs/xfs_btree.h15
-rw-r--r--fs/xfs/xfs_fs.h2
-rw-r--r--fs/xfs/xfs_inode.c8
-rw-r--r--fs/xfs/xfs_inode.h5
-rw-r--r--fs/xfs/xfs_inum.h1
-rw-r--r--fs/xfs/xfs_itable.c2
-rw-r--r--fs/xfs/xfs_itable.h5
-rw-r--r--fs/xfs/xfs_log_priv.h2
-rw-r--r--fs/xfs/xfs_log_recover.c2
-rw-r--r--fs/xfs/xfs_mount.c2
-rw-r--r--fs/xfs/xfs_mount.h3
-rw-r--r--fs/xfs/xfs_mru_cache.c29
-rw-r--r--fs/xfs/xfs_mru_cache.h1
-rw-r--r--fs/xfs/xfs_rw.h6
-rw-r--r--fs/xfs/xfs_trans_buf.c4
-rw-r--r--fs/xfs/xfs_vnodeops.c2
-rw-r--r--include/acpi/acpi_bus.h30
-rw-r--r--include/acpi/acpiosxf.h4
-rw-r--r--include/acpi/acpixf.h10
-rw-r--r--include/acpi/actbl.h19
-rw-r--r--include/acpi/actbl1.h8
-rw-r--r--include/acpi/actypes.h94
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/asm-generic/4level-fixup.h4
-rw-r--r--include/asm-generic/device.h3
-rw-r--r--include/asm-generic/pci.h13
-rw-r--r--include/asm-generic/pgtable-nopmd.h2
-rw-r--r--include/asm-generic/pgtable-nopud.h2
-rw-r--r--include/asm-generic/tlb.h12
-rw-r--r--include/asm-generic/topology.h17
-rw-r--r--include/asm-generic/vmlinux.lds.h24
-rw-r--r--include/crypto/algapi.h37
-rw-r--r--include/crypto/hash.h147
-rw-r--r--include/crypto/internal/hash.h147
-rw-r--r--include/crypto/sha.h20
-rw-r--r--include/drm/drm_crtc.h6
-rw-r--r--include/drm/radeon_drm.h23
-rw-r--r--include/drm/ttm/ttm_bo_driver.h20
-rw-r--r--include/drm/ttm/ttm_module.h2
-rw-r--r--include/linux/ata.h36
-rw-r--r--include/linux/backing-dev.h71
-rw-r--r--include/linux/bio.h69
-rw-r--r--include/linux/blkdev.h31
-rw-r--r--include/linux/capability.h2
-rw-r--r--include/linux/cb710.h29
-rw-r--r--include/linux/cgroup.h28
-rw-r--r--include/linux/clocksource.h14
-rw-r--r--include/linux/connector.h6
-rw-r--r--include/linux/cpumask.h709
-rw-r--r--include/linux/crypto.h43
-rw-r--r--include/linux/device-mapper.h4
-rw-r--r--include/linux/device.h9
-rw-r--r--include/linux/drbd.h349
-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/dvb/dmx.h2
-rw-r--r--include/linux/ethtool.h1
-rw-r--r--include/linux/ext3_fs.h2
-rw-r--r--include/linux/fips.h10
-rw-r--r--include/linux/flex_array.h47
-rw-r--r--include/linux/fs.h12
-rw-r--r--include/linux/fsnotify_backend.h12
-rw-r--r--include/linux/fuse.h29
-rw-r--r--include/linux/hid-debug.h48
-rw-r--r--include/linux/hid.h22
-rw-r--r--include/linux/i2c-id.h11
-rw-r--r--include/linux/i2c.h2
-rw-r--r--include/linux/ieee80211.h29
-rw-r--r--include/linux/if_ether.h4
-rw-r--r--include/linux/if_tun.h1
-rw-r--r--include/linux/inetdevice.h2
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/iocontext.h2
-rw-r--r--include/linux/iova.h1
-rw-r--r--include/linux/irq.h7
-rw-r--r--include/linux/isdn/hdlc.h82
-rw-r--r--include/linux/kgdb.h48
-rw-r--r--include/linux/kmemleak.h18
-rw-r--r--include/linux/kvm.h127
-rw-r--r--include/linux/kvm_host.h119
-rw-r--r--include/linux/lguest.h39
-rw-r--r--include/linux/lguest_launcher.h18
-rw-r--r--include/linux/libata.h4
-rw-r--r--include/linux/lru_cache.h294
-rw-r--r--include/linux/lsm_audit.h10
-rw-r--r--include/linux/mISDNhw.h1
-rw-r--r--include/linux/mISDNif.h18
-rw-r--r--include/linux/mfd/da903x.h4
-rw-r--r--include/linux/mfd/ezx-pcap.h3
-rw-r--r--include/linux/mmc/sdio_ids.h6
-rw-r--r--include/linux/namei.h2
-rw-r--r--include/linux/net_dropmon.h1
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/nfs4.h2
-rw-r--r--include/linux/nfsd/nfsd.h3
-rw-r--r--include/linux/nfsd/state.h22
-rw-r--r--include/linux/nfsd/xdr4.h12
-rw-r--r--include/linux/nl80211.h157
-rw-r--r--include/linux/of_mdio.h3
-rw-r--r--include/linux/oprofile.h5
-rw-r--r--include/linux/pci.h5
-rw-r--r--include/linux/percpu-defs.h66
-rw-r--r--include/linux/percpu.h85
-rw-r--r--include/linux/platform_device.h5
-rw-r--r--include/linux/poison.h16
-rw-r--r--include/linux/power_supply.h21
-rw-r--r--include/linux/pps.h2
-rw-r--r--include/linux/rcu_types.h18
-rw-r--r--include/linux/rcuclassic.h178
-rw-r--r--include/linux/rcupdate.h38
-rw-r--r--include/linux/rcupreempt.h10
-rw-r--r--include/linux/rcutree.h12
-rw-r--r--include/linux/regulator/consumer.h4
-rw-r--r--include/linux/regulator/driver.h4
-rw-r--r--include/linux/regulator/machine.h20
-rw-r--r--include/linux/reiserfs_fs.h68
-rw-r--r--include/linux/reiserfs_fs_sb.h20
-rw-r--r--include/linux/rfkill.h16
-rw-r--r--include/linux/scatterlist.h2
-rw-r--r--include/linux/sched.h12
-rw-r--r--include/linux/security.h14
-rw-r--r--include/linux/serio.h2
-rw-r--r--include/linux/skbuff.h6
-rw-r--r--include/linux/slab.h10
-rw-r--r--include/linux/slqb_def.h301
-rw-r--r--include/linux/smp.h11
-rw-r--r--include/linux/sunrpc/svc.h2
-rw-r--r--include/linux/tipc.h2
-rw-r--r--include/linux/topology.h12
-rw-r--r--include/linux/tty.h1
-rw-r--r--include/linux/uio.h17
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/linux/usb/m66592.h44
-rw-r--r--include/linux/usb/r8a66597.h375
-rw-r--r--include/linux/usb/usbnet.h3
-rw-r--r--include/linux/usb/video.h164
-rw-r--r--include/linux/videodev2.h65
-rw-r--r--include/linux/virtio_blk.h6
-rw-r--r--include/linux/virtio_config.h3
-rw-r--r--include/linux/virtio_net.h6
-rw-r--r--include/linux/virtio_ring.h12
-rw-r--r--include/linux/wireless.h8
-rw-r--r--include/linux/wm97xx.h7
-rw-r--r--include/linux/workqueue.h2
-rw-r--r--include/linux/writeback.h15
-rw-r--r--include/media/davinci/ccdc_types.h43
-rw-r--r--include/media/davinci/dm355_ccdc.h321
-rw-r--r--include/media/davinci/dm644x_ccdc.h184
-rw-r--r--include/media/davinci/vpfe_capture.h198
-rw-r--r--include/media/davinci/vpfe_types.h51
-rw-r--r--include/media/davinci/vpss.h69
-rw-r--r--include/media/ir-kbd-i2c.h17
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/media/tvp514x.h4
-rw-r--r--include/media/v4l2-chip-ident.h12
-rw-r--r--include/media/v4l2-subdev.h3
-rw-r--r--include/net/af_ieee802154.h (renamed from include/net/ieee802154/af_ieee802154.h)0
-rw-r--r--include/net/bluetooth/l2cap.h8
-rw-r--r--include/net/cfg80211.h530
-rw-r--r--include/net/genetlink.h66
-rw-r--r--include/net/ieee802154.h (renamed from include/net/ieee802154/mac_def.h)4
-rw-r--r--include/net/ieee802154/nl802154.h41
-rw-r--r--include/net/ieee802154_netdev.h (renamed from include/net/ieee802154/netdevice.h)0
-rw-r--r--include/net/ip6_fib.h6
-rw-r--r--include/net/ip_vs.h119
-rw-r--r--include/net/ipv6.h12
-rw-r--r--include/net/iw_handler.h2
-rw-r--r--include/net/mac80211.h75
-rw-r--r--include/net/net_namespace.h26
-rw-r--r--include/net/netns/x_tables.h3
-rw-r--r--include/net/nl802154.h117
-rw-r--r--include/net/phonet/pn_dev.h2
-rw-r--r--include/net/rose.h2
-rw-r--r--include/net/scm.h2
-rw-r--r--include/net/udp.h3
-rw-r--r--include/net/xfrm.h2
-rw-r--r--include/rdma/ib_cm.h2
-rw-r--r--include/scsi/scsi_device.h2
-rw-r--r--include/sound/ac97_codec.h6
-rw-r--r--include/sound/memalloc.h6
-rw-r--r--include/sound/pcm.h23
-rw-r--r--include/sound/soc-dai.h27
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/sound/soc.h35
-rw-r--r--include/sound/tlv.h14
-rw-r--r--include/sound/uda1380.h22
-rw-r--r--include/sound/wm8993.h44
-rw-r--r--include/trace/events/kvm.h151
-rw-r--r--init/Kconfig50
-rw-r--r--init/main.c29
-rw-r--r--kernel/Makefile6
-rw-r--r--kernel/audit.c1
-rw-r--r--kernel/audit.h26
-rw-r--r--kernel/audit_tree.c223
-rw-r--r--kernel/audit_watch.c293
-rw-r--r--kernel/auditfilter.c39
-rw-r--r--kernel/auditsc.c9
-rw-r--r--kernel/cgroup.c152
-rw-r--r--kernel/fork.c8
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/irq/pm.c8
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kgdb.c30
-rw-r--r--kernel/kprobes.c32
-rw-r--r--kernel/kthread.c10
-rw-r--r--kernel/module.c9
-rw-r--r--kernel/panic.c2
-rw-r--r--kernel/perf_counter.c6
-rw-r--r--kernel/power/hibernate.c21
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/snapshot.c412
-rw-r--r--kernel/printk.c146
-rw-r--r--kernel/profile.c5
-rw-r--r--kernel/ptrace.c2
-rw-r--r--kernel/rcuclassic.c807
-rw-r--r--kernel/rcupdate.c25
-rw-r--r--kernel/rcutorture.c202
-rw-r--r--kernel/sched.c192
-rw-r--r--kernel/signal.c25
-rw-r--r--kernel/smp.c7
-rw-r--r--kernel/softlockup.c16
-rw-r--r--kernel/taskstats.c10
-rw-r--r--kernel/trace/ftrace.c15
-rw-r--r--kernel/trace/kmemtrace.c120
-rw-r--r--kernel/trace/trace.c11
-rw-r--r--kernel/trace/trace.h3
-rw-r--r--kernel/trace/trace_events.c43
-rw-r--r--kernel/trace/trace_stack.c7
-rw-r--r--kernel/trace/trace_stat.c34
-rw-r--r--kernel/tracepoint.c2
-rw-r--r--lib/Kconfig3
-rw-r--r--lib/Kconfig.debug35
-rw-r--r--lib/Makefile4
-rw-r--r--lib/atomic64.c11
-rw-r--r--lib/dynamic_debug.c2
-rw-r--r--lib/flex_array.c269
-rw-r--r--lib/is_single_threaded.c61
-rw-r--r--lib/lru_cache.c560
-rw-r--r--lib/scatterlist.c16
-rw-r--r--lib/zlib_deflate/deflate.c4
-rw-r--r--mm/Makefile5
-rw-r--r--mm/allocpercpu.c28
-rw-r--r--mm/backing-dev.c533
-rw-r--r--mm/bootmem.c6
-rw-r--r--mm/hugetlb.c3
-rw-r--r--mm/kmemleak-test.c6
-rw-r--r--mm/kmemleak.c199
-rw-r--r--mm/memcontrol.c23
-rw-r--r--mm/memory.c11
-rw-r--r--mm/page-writeback.c162
-rw-r--r--mm/page_alloc.c21
-rw-r--r--mm/pdflush.c269
-rw-r--r--mm/percpu.c1316
-rw-r--r--mm/quicklist.c5
-rw-r--r--mm/slqb.c3765
-rw-r--r--mm/slub.c48
-rw-r--r--mm/swap_state.c1
-rw-r--r--mm/swapfile.c4
-rw-r--r--mm/vmscan.c2
-rw-r--r--net/8021q/vlan.c19
-rw-r--r--net/9p/client.c14
-rw-r--r--net/9p/trans_fd.c8
-rw-r--r--net/9p/trans_rdma.c9
-rw-r--r--net/9p/trans_virtio.c11
-rw-r--r--net/Kconfig20
-rw-r--r--net/Makefile1
-rw-r--r--net/atm/br2684.c4
-rw-r--r--net/atm/clip.c12
-rw-r--r--net/atm/lec.c8
-rw-r--r--net/atm/mpc.c2
-rw-r--r--net/bluetooth/bnep/netdev.c6
-rw-r--r--net/bluetooth/hidp/core.c1
-rw-r--r--net/bluetooth/l2cap.c72
-rw-r--r--net/bluetooth/sco.c49
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_netfilter.c96
-rw-r--r--net/compat.c17
-rw-r--r--net/core/dev.c34
-rw-r--r--net/core/ethtool.c16
-rw-r--r--net/core/neighbour.c6
-rw-r--r--net/core/net_namespace.c37
-rw-r--r--net/core/netpoll.c6
-rw-r--r--net/core/rtnetlink.c21
-rw-r--r--net/core/skbuff.c3
-rw-r--r--net/dccp/proto.c4
-rw-r--r--net/decnet/dn_route.c2
-rw-r--r--net/econet/af_econet.c4
-rw-r--r--net/ieee802154/af_ieee802154.c4
-rw-r--r--net/ieee802154/dgram.c6
-rw-r--r--net/ieee802154/netlink.c6
-rw-r--r--net/ieee802154/raw.c2
-rw-r--r--net/ipv4/af_inet.c12
-rw-r--r--net/ipv4/arp.c4
-rw-r--r--net/ipv4/fib_trie.c50
-rw-r--r--net/ipv4/ip_gre.c6
-rw-r--r--net/ipv4/ipip.c6
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv4/route.c2
-rw-r--r--net/ipv4/syncookies.c5
-rw-r--r--net/ipv4/tcp_output.c58
-rw-r--r--net/ipv4/udp.c144
-rw-r--r--net/ipv4/xfrm4_policy.c31
-rw-r--r--net/ipv6/af_inet6.c20
-rw-r--r--net/ipv6/ip6_fib.c16
-rw-r--r--net/ipv6/ip6_input.c6
-rw-r--r--net/ipv6/ip6_output.c26
-rw-r--r--net/ipv6/ip6_tunnel.c4
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/mcast.c1
-rw-r--r--net/ipv6/sit.c6
-rw-r--r--net/ipv6/syncookies.c5
-rw-r--r--net/ipv6/udp.c141
-rw-r--r--net/ipv6/xfrm6_policy.c33
-rw-r--r--net/irda/irlan/irlan_eth.c4
-rw-r--r--net/irda/irnetlink.c2
-rw-r--r--net/irda/irttp.c1
-rw-r--r--net/lapb/lapb_iface.c2
-rw-r--r--net/mac80211/Kconfig30
-rw-r--r--net/mac80211/Makefile4
-rw-r--r--net/mac80211/agg-tx.c3
-rw-r--r--net/mac80211/cfg.c230
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/debugfs_netdev.c46
-rw-r--r--net/mac80211/debugfs_sta.c98
-rw-r--r--net/mac80211/driver-ops.h85
-rw-r--r--net/mac80211/driver-trace.c6
-rw-r--r--net/mac80211/driver-trace.h648
-rw-r--r--net/mac80211/event.c23
-rw-r--r--net/mac80211/ibss.c17
-rw-r--r--net/mac80211/ieee80211_i.h222
-rw-r--r--net/mac80211/iface.c103
-rw-r--r--net/mac80211/key.c28
-rw-r--r--net/mac80211/main.c128
-rw-r--r--net/mac80211/mesh.c13
-rw-r--r--net/mac80211/mesh.h3
-rw-r--r--net/mac80211/mesh_hwmp.c9
-rw-r--r--net/mac80211/mesh_pathtbl.c37
-rw-r--r--net/mac80211/mlme.c1926
-rw-r--r--net/mac80211/pm.c24
-rw-r--r--net/mac80211/rate.c31
-rw-r--r--net/mac80211/rc80211_minstrel.c23
-rw-r--r--net/mac80211/rc80211_pid_algo.c12
-rw-r--r--net/mac80211/rx.c191
-rw-r--r--net/mac80211/scan.c350
-rw-r--r--net/mac80211/sta_info.h30
-rw-r--r--net/mac80211/tx.c426
-rw-r--r--net/mac80211/util.c81
-rw-r--r--net/mac80211/wep.c52
-rw-r--r--net/mac80211/wep.h7
-rw-r--r--net/mac80211/wext.c633
-rw-r--r--net/mac80211/wme.c6
-rw-r--r--net/mac80211/wme.h3
-rw-r--r--net/mac80211/wpa.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_est.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_lc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_nq.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_ah_esp.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_rr.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sched.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sed.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_wlc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_wrr.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c3
-rw-r--r--net/netlabel/netlabel_kapi.c8
-rw-r--r--net/netlink/af_netlink.c72
-rw-r--r--net/netlink/genetlink.c186
-rw-r--r--net/netrom/nr_dev.c4
-rw-r--r--net/packet/af_packet.c246
-rw-r--r--net/phonet/datagram.c5
-rw-r--r--net/phonet/pep-gprs.c4
-rw-r--r--net/phonet/pep.c7
-rw-r--r--net/phonet/pn_dev.c10
-rw-r--r--net/phonet/socket.c96
-rw-r--r--net/rds/connection.c49
-rw-r--r--net/rds/ib.c6
-rw-r--r--net/rds/ib.h18
-rw-r--r--net/rds/ib_cm.c62
-rw-r--r--net/rds/ib_rdma.c12
-rw-r--r--net/rds/ib_recv.c53
-rw-r--r--net/rds/ib_stats.c2
-rw-r--r--net/rds/ib_sysctl.c12
-rw-r--r--net/rds/iw.c15
-rw-r--r--net/rds/iw.h1
-rw-r--r--net/rds/iw_rdma.c28
-rw-r--r--net/rds/iw_send.c2
-rw-r--r--net/rds/iw_stats.c2
-rw-r--r--net/rds/page.c2
-rw-r--r--net/rds/rdma_transport.c8
-rw-r--r--net/rds/recv.c24
-rw-r--r--net/rfkill/core.c41
-rw-r--r--net/rose/af_rose.c18
-rw-r--r--net/rose/rose_dev.c2
-rw-r--r--net/rose/rose_route.c23
-rw-r--r--net/rxrpc/ar-call.c2
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sched/sch_teql.c6
-rw-r--r--net/sunrpc/svcsock.c84
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c4
-rw-r--r--net/tipc/netlink.c2
-rw-r--r--net/tipc/socket.c6
-rw-r--r--net/wireless/Kconfig43
-rw-r--r--net/wireless/Makefile4
-rw-r--r--net/wireless/core.c454
-rw-r--r--net/wireless/core.h214
-rw-r--r--net/wireless/debugfs.c14
-rw-r--r--net/wireless/debugfs.h8
-rw-r--r--net/wireless/ibss.c247
-rw-r--r--net/wireless/mlme.c597
-rw-r--r--net/wireless/nl80211.c1645
-rw-r--r--net/wireless/nl80211.h71
-rw-r--r--net/wireless/reg.c73
-rw-r--r--net/wireless/scan.c85
-rw-r--r--net/wireless/sme.c839
-rw-r--r--net/wireless/util.c66
-rw-r--r--net/wireless/wext-compat.c842
-rw-r--r--net/wireless/wext-compat.h50
-rw-r--r--net/wireless/wext-sme.c383
-rw-r--r--net/wireless/wext.c256
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/basic/fixdep.c3
-rw-r--r--scripts/binoffset.c163
-rwxr-xr-xscripts/extract-ikconfig113
-rwxr-xr-xscripts/get_maintainer.pl42
-rw-r--r--scripts/kconfig/conf.c22
-rw-r--r--scripts/kconfig/expr.c2
-rw-r--r--scripts/kconfig/gconf.c21
-rw-r--r--scripts/kconfig/lkc_proto.h2
-rw-r--r--scripts/kconfig/mconf.c78
-rw-r--r--scripts/kconfig/menu.c79
-rw-r--r--scripts/kconfig/qconf.cc10
-rw-r--r--scripts/markup_oops.pl5
-rw-r--r--scripts/mod/sumversion.c2
-rw-r--r--scripts/module-common.lds8
-rw-r--r--security/capability.c2
-rw-r--r--security/commoncap.c4
-rw-r--r--security/keys/proc.c4
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--security/security.c4
-rw-r--r--security/selinux/avc.c8
-rw-r--r--security/selinux/hooks.c26
-rw-r--r--security/selinux/include/avc.h6
-rw-r--r--security/selinux/ss/services.c142
-rw-r--r--security/smack/smack.h2
-rw-r--r--security/smack/smack_access.c11
-rw-r--r--security/smack/smack_lsm.c8
-rw-r--r--security/tomoyo/common.c30
-rw-r--r--security/tomoyo/common.h2
-rw-r--r--security/tomoyo/domain.c42
-rw-r--r--security/tomoyo/tomoyo.c10
-rw-r--r--security/tomoyo/tomoyo.h3
-rw-r--r--sound/aoa/core/gpio-pmf.c4
-rw-r--r--sound/arm/pxa2xx-ac97.c20
-rw-r--r--sound/core/Kconfig4
-rw-r--r--sound/core/Makefile2
-rw-r--r--sound/core/info.c4
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/pcm_lib.c36
-rw-r--r--sound/core/pcm_memory.c2
-rw-r--r--sound/core/rawmidi.c2
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c14
-rw-r--r--sound/core/seq/seq_midi.c7
-rw-r--r--sound/core/vmaster.c8
-rw-r--r--sound/isa/cmi8330.c86
-rw-r--r--sound/oss/aedsp16.c9
-rw-r--r--sound/oss/mpu401.c2
-rw-r--r--sound/oss/swarm_cs4297a.c3
-rw-r--r--sound/pci/Kconfig4
-rw-r--r--sound/pci/azt3328.c1116
-rw-r--r--sound/pci/azt3328.h103
-rw-r--r--sound/pci/ctxfi/ct20k2reg.h9
-rw-r--r--sound/pci/ctxfi/ctamixer.c34
-rw-r--r--sound/pci/ctxfi/ctatc.c77
-rw-r--r--sound/pci/ctxfi/ctdaio.c30
-rw-r--r--sound/pci/ctxfi/cthw20k1.c22
-rw-r--r--sound/pci/ctxfi/cthw20k2.c73
-rw-r--r--sound/pci/ctxfi/ctmixer.c8
-rw-r--r--sound/pci/ctxfi/ctpcm.c6
-rw-r--r--sound/pci/ctxfi/ctresource.c4
-rw-r--r--sound/pci/ctxfi/ctsrc.c17
-rw-r--r--sound/pci/ctxfi/ctvmem.c6
-rw-r--r--sound/pci/hda/Kconfig27
-rw-r--r--sound/pci/hda/Makefile4
-rw-r--r--sound/pci/hda/hda_beep.c4
-rw-r--r--sound/pci/hda/hda_codec.c66
-rw-r--r--sound/pci/hda/hda_codec.h10
-rw-r--r--sound/pci/hda/hda_eld.c4
-rw-r--r--sound/pci/hda/hda_generic.c18
-rw-r--r--sound/pci/hda/hda_hwdep.c236
-rw-r--r--sound/pci/hda/hda_intel.c48
-rw-r--r--sound/pci/hda/hda_local.h4
-rw-r--r--sound/pci/hda/hda_proc.c3
-rw-r--r--sound/pci/hda/patch_analog.c5
-rw-r--r--sound/pci/hda/patch_ca0110.c3
-rw-r--r--sound/pci/hda/patch_cirrus.c1194
-rw-r--r--sound/pci/hda/patch_cmedia.c3
-rw-r--r--sound/pci/hda/patch_conexant.c479
-rw-r--r--sound/pci/hda/patch_intelhdmi.c2
-rw-r--r--sound/pci/hda/patch_realtek.c2430
-rw-r--r--sound/pci/hda/patch_sigmatel.c752
-rw-r--r--sound/pci/hda/patch_via.c3
-rw-r--r--sound/pci/ice1712/ice1712.h9
-rw-r--r--sound/pci/ice1712/ice1724.c112
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c46
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c174
-rw-r--r--sound/soc/blackfin/Kconfig23
-rw-r--r--sound/soc/blackfin/Makefile6
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c10
-rw-r--r--sound/soc/blackfin/bf5xx-ad1938.c142
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c16
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c8
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c16
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c330
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.h21
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c343
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h14
-rw-r--r--sound/soc/codecs/Kconfig24
-rw-r--r--sound/soc/codecs/Makefile16
-rw-r--r--sound/soc/codecs/ad1938.c652
-rw-r--r--sound/soc/codecs/ad1938.h100
-rw-r--r--sound/soc/codecs/ak4535.c16
-rw-r--r--sound/soc/codecs/cx20442.c398
-rw-r--r--sound/soc/codecs/cx20442.h19
-rw-r--r--sound/soc/codecs/max9877.c308
-rw-r--r--sound/soc/codecs/max9877.h37
-rw-r--r--sound/soc/codecs/spdif_transciever.c3
-rw-r--r--sound/soc/codecs/stac9766.c4
-rw-r--r--sound/soc/codecs/tlv320aic3x.c11
-rw-r--r--sound/soc/codecs/twl4030.c105
-rw-r--r--sound/soc/codecs/twl4030.h2
-rw-r--r--sound/soc/codecs/uda1380.c313
-rw-r--r--sound/soc/codecs/uda1380.h8
-rw-r--r--sound/soc/codecs/wm8350.c40
-rw-r--r--sound/soc/codecs/wm8400.c26
-rw-r--r--sound/soc/codecs/wm8510.c1
-rw-r--r--sound/soc/codecs/wm8523.c755
-rw-r--r--sound/soc/codecs/wm8523.h160
-rw-r--r--sound/soc/codecs/wm8580.c55
-rw-r--r--sound/soc/codecs/wm8731.c74
-rw-r--r--sound/soc/codecs/wm8753.c35
-rw-r--r--sound/soc/codecs/wm8900.c30
-rw-r--r--sound/soc/codecs/wm8903.c27
-rw-r--r--sound/soc/codecs/wm8940.c17
-rw-r--r--sound/soc/codecs/wm8960.c33
-rw-r--r--sound/soc/codecs/wm8961.c1326
-rw-r--r--sound/soc/codecs/wm8961.h866
-rw-r--r--sound/soc/codecs/wm8988.c42
-rw-r--r--sound/soc/codecs/wm8993.c2206
-rw-r--r--sound/soc/codecs/wm8993.h2132
-rw-r--r--sound/soc/codecs/wm9081.c25
-rw-r--r--sound/soc/davinci/Kconfig13
-rw-r--r--sound/soc/davinci/Makefile3
-rw-r--r--sound/soc/davinci/davinci-evm.c102
-rw-r--r--sound/soc/davinci/davinci-i2s.c337
-rw-r--r--sound/soc/davinci/davinci-mcasp.c874
-rw-r--r--sound/soc/davinci/davinci-mcasp.h55
-rw-r--r--sound/soc/davinci/davinci-pcm.c7
-rw-r--r--sound/soc/davinci/davinci-pcm.h18
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c3
-rw-r--r--sound/soc/omap/Kconfig7
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/omap-pcm.c2
-rw-r--r--sound/soc/omap/sdp3430.c11
-rw-r--r--sound/soc/omap/zoom2.c314
-rw-r--r--sound/soc/pxa/magician.c54
-rw-r--r--sound/soc/pxa/palm27x.c204
-rw-r--r--sound/soc/pxa/pxa-ssp.c50
-rw-r--r--sound/soc/soc-core.c128
-rw-r--r--sound/soc/soc-dapm.c355
-rw-r--r--sound/soc/soc-jack.c20
-rw-r--r--sound/soc/txx9/txx9aclc.c10
-rw-r--r--sound/usb/Kconfig1
-rw-r--r--sound/usb/caiaq/audio.c1
-rw-r--r--sound/usb/caiaq/device.c8
-rw-r--r--sound/usb/caiaq/device.h1
-rw-r--r--sound/usb/usbmidi.c290
-rw-r--r--sound/usb/usbmixer.c98
-rw-r--r--usr/Makefile2
-rw-r--r--virt/kvm/Kconfig14
-rw-r--r--virt/kvm/coalesced_mmio.c74
-rw-r--r--virt/kvm/coalesced_mmio.h1
-rw-r--r--virt/kvm/eventfd.c578
-rw-r--r--virt/kvm/ioapic.c84
-rw-r--r--virt/kvm/iodev.h55
-rw-r--r--virt/kvm/irq_comm.c51
-rw-r--r--virt/kvm/kvm_main.c295
-rw-r--r--virt/kvm/kvm_trace.c285
3042 files changed, 196975 insertions, 65212 deletions
diff --git a/CREDITS b/CREDITS
index e76d300e9fe4..1a41bf4addd0 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2006,6 +2006,9 @@ E: paul@laufernet.com
D: Soundblaster driver fixes, ISAPnP quirk
S: California, USA
+N: Jonathan Layes
+D: ARPD support
+
N: Tom Lees
E: tom@lpsg.demon.co.uk
W: http://www.lpsg.demon.co.uk/
@@ -3802,6 +3805,9 @@ S: van Bronckhorststraat 12
S: 2612 XV Delft
S: The Netherlands
+N: Thomas Woller
+D: CS461x Cirrus Logic sound driver
+
N: David Woodhouse
E: dwmw2@infradead.org
D: JFFS2 file system, Memory Technology Device subsystem,
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index d05737aaa84b..06b982affe76 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -82,6 +82,8 @@ block/
- info on the Block I/O (BIO) layer.
blockdev/
- info on block devices & drivers
+btmrvl.txt
+ - info on Marvell Bluetooth driver usage.
cachetlb.txt
- describes the cache/TLB flushing interfaces Linux uses.
cdrom/
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
index cbbd3e069945..5f3bedaf8e35 100644
--- a/Documentation/ABI/testing/sysfs-block
+++ b/Documentation/ABI/testing/sysfs-block
@@ -94,28 +94,37 @@ What: /sys/block/<disk>/queue/physical_block_size
Date: May 2009
Contact: Martin K. Petersen <martin.petersen@oracle.com>
Description:
- This is the smallest unit the storage device can write
- without resorting to read-modify-write operation. It is
- usually the same as the logical block size but may be
- bigger. One example is SATA drives with 4KB sectors
- that expose a 512-byte logical block size to the
- operating system.
+ This is the smallest unit a physical storage device can
+ write atomically. It is usually the same as the logical
+ block size but may be bigger. One example is SATA
+ drives with 4KB sectors that expose a 512-byte logical
+ block size to the operating system. For stacked block
+ devices the physical_block_size variable contains the
+ maximum physical_block_size of the component devices.
What: /sys/block/<disk>/queue/minimum_io_size
Date: April 2009
Contact: Martin K. Petersen <martin.petersen@oracle.com>
Description:
- Storage devices may report a preferred minimum I/O size,
- which is the smallest request the device can perform
- without incurring a read-modify-write penalty. For disk
- drives this is often the physical block size. For RAID
- arrays it is often the stripe chunk size.
+ Storage devices may report a granularity or preferred
+ minimum I/O size which is the smallest request the
+ device can perform without incurring a performance
+ penalty. For disk drives this is often the physical
+ block size. For RAID arrays it is often the stripe
+ chunk size. A properly aligned multiple of
+ minimum_io_size is the preferred request size for
+ workloads where a high number of I/O operations is
+ desired.
What: /sys/block/<disk>/queue/optimal_io_size
Date: April 2009
Contact: Martin K. Petersen <martin.petersen@oracle.com>
Description:
Storage devices may report an optimal I/O size, which is
- the device's preferred unit of receiving I/O. This is
- rarely reported for disk drives. For RAID devices it is
- usually the stripe width or the internal block size.
+ the device's preferred unit for sustained I/O. This is
+ rarely reported for disk drives. For RAID arrays it is
+ usually the stripe width or the internal track size. A
+ properly aligned multiple of optimal_io_size is the
+ preferred request size for workloads where sustained
+ throughput is desired. If no optimal I/O size is
+ reported this file contains 0.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 6bf68053e4b8..25be3250f7d6 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -84,6 +84,16 @@ Description:
from this part of the device tree.
Depends on CONFIG_HOTPLUG.
+What: /sys/bus/pci/devices/.../reset
+Date: July 2009
+Contact: Michael S. Tsirkin <mst@redhat.com>
+Description:
+ Some devices allow an individual function to be reset
+ without affecting other functions in the same device.
+ For devices that have this support, a file named reset
+ will be present in sysfs. Writing 1 to this file
+ will perform reset.
+
What: /sys/bus/pci/devices/.../vpd
Date: February 2008
Contact: Ben Hutchings <bhutchings@solarflare.com>
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index a50d6cd58573..992e67e6be7f 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -449,8 +449,8 @@ printk(KERN_INFO "i = %u\n", i);
</para>
<programlisting>
-__u32 ipaddress;
-printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
+__be32 ipaddress;
+printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
</programlisting>
<para>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index 8e145857fc9d..df0d089d0fb9 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -568,7 +568,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)
<para>
The blocks in which the tables are stored are procteted against
accidental access by marking them bad in the memory bad block
- table. The bad block table managment functions are allowed
+ table. The bad block table management functions are allowed
to circumvernt this protection.
</para>
<para>
diff --git a/Documentation/DocBook/scsi.tmpl b/Documentation/DocBook/scsi.tmpl
index 10a150ae2a7e..d87f4569e768 100644
--- a/Documentation/DocBook/scsi.tmpl
+++ b/Documentation/DocBook/scsi.tmpl
@@ -317,7 +317,7 @@
<para>
The SAS transport class contains common code to deal with SAS HBAs,
an aproximated representation of SAS topologies in the driver model,
- and various sysfs attributes to expose these topologies and managment
+ and various sysfs attributes to expose these topologies and management
interfaces to userspace.
</para>
<para>
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index 9f711d2df91b..d2b85237c76e 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -743,3 +743,80 @@ Revised:
RCU, realtime RCU, sleepable RCU, performance.
"
}
+
+@article{PaulEMcKenney2008RCUOSR
+,author="Paul E. McKenney and Jonathan Walpole"
+,title="Introducing technology into the {Linux} kernel: a case study"
+,Year="2008"
+,journal="SIGOPS Oper. Syst. Rev."
+,volume="42"
+,number="5"
+,pages="4--17"
+,issn="0163-5980"
+,doi={http://doi.acm.org/10.1145/1400097.1400099}
+,publisher="ACM"
+,address="New York, NY, USA"
+,annotation={
+ Linux changed RCU to a far greater degree than RCU has changed Linux.
+}
+}
+
+@unpublished{PaulEMcKenney2008HierarchicalRCU
+,Author="Paul E. McKenney"
+,Title="Hierarchical {RCU}"
+,month="November"
+,day="3"
+,year="2008"
+,note="Available:
+\url{http://lwn.net/Articles/305782/}
+[Viewed November 6, 2008]"
+,annotation="
+ RCU with combining-tree-based grace-period detection,
+ permitting it to handle thousands of CPUs.
+"
+}
+
+@conference{PaulEMcKenney2009MaliciousURCU
+,Author="Paul E. McKenney"
+,Title="Using a Malicious User-Level {RCU} to Torture {RCU}-Based Algorithms"
+,Booktitle="linux.conf.au 2009"
+,month="January"
+,year="2009"
+,address="Hobart, Australia"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/urcutorture.2009.01.22a.pdf}
+[Viewed February 2, 2009]"
+,annotation="
+ Realtime RCU and torture-testing RCU uses.
+"
+}
+
+@unpublished{MathieuDesnoyers2009URCU
+,Author="Mathieu Desnoyers"
+,Title="[{RFC} git tree] Userspace {RCU} (urcu) for {Linux}"
+,month="February"
+,day="5"
+,year="2009"
+,note="Available:
+\url{http://lkml.org/lkml/2009/2/5/572}
+\url{git://lttng.org/userspace-rcu.git}
+[Viewed February 20, 2009]"
+,annotation="
+ Mathieu Desnoyers's user-space RCU implementation.
+ git://lttng.org/userspace-rcu.git
+"
+}
+
+@unpublished{PaulEMcKenney2009BloatWatchRCU
+,Author="Paul E. McKenney"
+,Title="{RCU}: The {Bloatwatch} Edition"
+,month="March"
+,day="17"
+,year="2009"
+,note="Available:
+\url{http://lwn.net/Articles/323929/}
+[Viewed March 20, 2009]"
+,annotation="
+ Uniprocessor assumptions allow simplified RCU implementation.
+"
+}
diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt
index aab4a9ec3931..90ec5341ee98 100644
--- a/Documentation/RCU/UP.txt
+++ b/Documentation/RCU/UP.txt
@@ -2,14 +2,13 @@ RCU on Uniprocessor Systems
A common misconception is that, on UP systems, the call_rcu() primitive
-may immediately invoke its function, and that the synchronize_rcu()
-primitive may return immediately. The basis of this misconception
+may immediately invoke its function. The basis of this misconception
is that since there is only one CPU, it should not be necessary to
wait for anything else to get done, since there are no other CPUs for
anything else to be happening on. Although this approach will -sort- -of-
work a surprising amount of the time, it is a very bad idea in general.
-This document presents three examples that demonstrate exactly how bad an
-idea this is.
+This document presents three examples that demonstrate exactly how bad
+an idea this is.
Example 1: softirq Suicide
@@ -82,11 +81,18 @@ Quick Quiz #2: What locking restriction must RCU callbacks respect?
Summary
-Permitting call_rcu() to immediately invoke its arguments or permitting
-synchronize_rcu() to immediately return breaks RCU, even on a UP system.
-So do not do it! Even on a UP system, the RCU infrastructure -must-
-respect grace periods, and -must- invoke callbacks from a known environment
-in which no locks are held.
+Permitting call_rcu() to immediately invoke its arguments breaks RCU,
+even on a UP system. So do not do it! Even on a UP system, the RCU
+infrastructure -must- respect grace periods, and -must- invoke callbacks
+from a known environment in which no locks are held.
+
+It -is- safe for synchronize_sched() and synchronize_rcu_bh() to return
+immediately on an UP system. It is also safe for synchronize_rcu()
+to return immediately on UP systems, except when running preemptable
+RCU.
+
+Quick Quiz #3: Why can't synchronize_rcu() return immediately on
+ UP systems running preemptable RCU?
Answer to Quick Quiz #1:
@@ -117,3 +123,13 @@ Answer to Quick Quiz #2:
callbacks acquire locks directly. However, a great many RCU
callbacks do acquire locks -indirectly-, for example, via
the kfree() primitive.
+
+Answer to Quick Quiz #3:
+ Why can't synchronize_rcu() return immediately on UP systems
+ running preemptable RCU?
+
+ Because some other task might have been preempted in the middle
+ of an RCU read-side critical section. If synchronize_rcu()
+ simply immediately returned, it would prematurely signal the
+ end of the grace period, which would come as a nasty shock to
+ that other thread when it started running again.
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index accfe2f5247d..51525a30e8b4 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -11,7 +11,10 @@ over a rather long period of time, but improvements are always welcome!
structure is updated more than about 10% of the time, then
you should strongly consider some other approach, unless
detailed performance measurements show that RCU is nonetheless
- the right tool for the job.
+ the right tool for the job. Yes, you might think of RCU
+ as simply cutting overhead off of the readers and imposing it
+ on the writers. That is exactly why normal uses of RCU will
+ do much more reading than updating.
Another exception is where performance is not an issue, and RCU
provides a simpler implementation. An example of this situation
@@ -240,10 +243,11 @@ over a rather long period of time, but improvements are always welcome!
instead need to use synchronize_irq() or synchronize_sched().
12. Any lock acquired by an RCU callback must be acquired elsewhere
- with irq disabled, e.g., via spin_lock_irqsave(). Failing to
- disable irq on a given acquisition of that lock will result in
- deadlock as soon as the RCU callback happens to interrupt that
- acquisition's critical section.
+ with softirq disabled, e.g., via spin_lock_irqsave(),
+ spin_lock_bh(), etc. Failing to disable irq on a given
+ acquisition of that lock will result in deadlock as soon as the
+ RCU callback happens to interrupt that acquisition's critical
+ section.
13. RCU callbacks can be and are executed in parallel. In many cases,
the callback code simply wrappers around kfree(), so that this
@@ -310,3 +314,9 @@ over a rather long period of time, but improvements are always welcome!
Because these primitives only wait for pre-existing readers,
it is the caller's responsibility to guarantee safety to
any subsequent readers.
+
+16. The various RCU read-side primitives do -not- contain memory
+ barriers. The CPU (and in some cases, the compiler) is free
+ to reorder code into and out of RCU read-side critical sections.
+ It is the responsibility of the RCU update-side primitives to
+ deal with this.
diff --git a/Documentation/RCU/rcubarrier.txt b/Documentation/RCU/rcubarrier.txt
index 909602d409bb..e439a0edee22 100644
--- a/Documentation/RCU/rcubarrier.txt
+++ b/Documentation/RCU/rcubarrier.txt
@@ -170,6 +170,13 @@ module invokes call_rcu() from timers, you will need to first cancel all
the timers, and only then invoke rcu_barrier() to wait for any remaining
RCU callbacks to complete.
+Of course, if you module uses call_rcu_bh(), you will need to invoke
+rcu_barrier_bh() before unloading. Similarly, if your module uses
+call_rcu_sched(), you will need to invoke rcu_barrier_sched() before
+unloading. If your module uses call_rcu(), call_rcu_bh(), -and-
+call_rcu_sched(), then you will need to invoke each of rcu_barrier(),
+rcu_barrier_bh(), and rcu_barrier_sched().
+
Implementing rcu_barrier()
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index a342b6e1cc10..9dba3bb90e60 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -76,8 +76,10 @@ torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API,
"rcu_sync" for rcu_read_lock() with synchronous reclamation,
"rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for
rcu_read_lock_bh() with synchronous reclamation, "srcu" for
- the "srcu_read_lock()" API, and "sched" for the use of
- preempt_disable() together with synchronize_sched().
+ the "srcu_read_lock()" API, "sched" for the use of
+ preempt_disable() together with synchronize_sched(),
+ and "sched_expedited" for the use of preempt_disable()
+ with synchronize_sched_expedited().
verbose Enable debug printk()s. Default is disabled.
@@ -162,6 +164,23 @@ of the "old" and "current" counters for the corresponding CPU. The
"idx" value maps the "old" and "current" values to the underlying array,
and is useful for debugging.
+Similarly, sched_expedited RCU provides the following:
+
+ sched_expedited-torture: rtc: d0000000016c1880 ver: 1090796 tfle: 0 rta: 1090796 rtaf: 0 rtf: 1090787 rtmbe: 0 nt: 27713319
+ sched_expedited-torture: Reader Pipe: 12660320201 95875 0 0 0 0 0 0 0 0 0
+ sched_expedited-torture: Reader Batch: 12660424885 0 0 0 0 0 0 0 0 0 0
+ sched_expedited-torture: Free-Block Circulation: 1090795 1090795 1090794 1090793 1090792 1090791 1090790 1090789 1090788 1090787 0
+ state: -1 / 0:0 3:0 4:0
+
+As before, the first four lines are similar to those for RCU.
+The last line shows the task-migration state. The first number is
+-1 if synchronize_sched_expedited() is idle, -2 if in the process of
+posting wakeups to the migration kthreads, and N when waiting on CPU N.
+Each of the colon-separated fields following the "/" is a CPU:state pair.
+Valid states are "0" for idle, "1" for waiting for quiescent state,
+"2" for passed through quiescent state, and "3" when a race with a
+CPU-hotplug event forces use of the synchronize_sched() primitive.
+
USAGE
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 96170824a717..97ded2432c59 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -785,6 +785,7 @@ RCU pointer/list traversal:
rcu_dereference
list_for_each_entry_rcu
hlist_for_each_entry_rcu
+ hlist_nulls_for_each_entry_rcu
list_for_each_continue_rcu (to be deprecated in favor of new
list_for_each_entry_continue_rcu)
@@ -807,19 +808,23 @@ RCU: Critical sections Grace period Barrier
rcu_read_lock synchronize_net rcu_barrier
rcu_read_unlock synchronize_rcu
+ synchronize_rcu_expedited
call_rcu
bh: Critical sections Grace period Barrier
rcu_read_lock_bh call_rcu_bh rcu_barrier_bh
- rcu_read_unlock_bh
+ rcu_read_unlock_bh synchronize_rcu_bh
+ synchronize_rcu_bh_expedited
sched: Critical sections Grace period Barrier
- [preempt_disable] synchronize_sched rcu_barrier_sched
- [and friends] call_rcu_sched
+ rcu_read_lock_sched synchronize_sched rcu_barrier_sched
+ rcu_read_unlock_sched call_rcu_sched
+ [preempt_disable] synchronize_sched_expedited
+ [and friends]
SRCU: Critical sections Grace period Barrier
@@ -827,6 +832,9 @@ SRCU: Critical sections Grace period Barrier
srcu_read_lock synchronize_srcu N/A
srcu_read_unlock
+SRCU: Initialization/cleanup
+ init_srcu_struct
+ cleanup_srcu_struct
See the comment headers in the source code (or the docbook generated
from them) for more information.
diff --git a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
index 43cb1004d35f..9d58c7c5eddd 100644
--- a/Documentation/arm/memory.txt
+++ b/Documentation/arm/memory.txt
@@ -21,6 +21,8 @@ ffff8000 ffffffff copy_user_page / clear_user_page use.
For SA11xx and Xscale, this is used to
setup a minicache mapping.
+ffff4000 ffffffff cache aliasing on ARMv6 and later CPUs.
+
ffff1000 ffff7fff Reserved.
Platforms must not use this address range.
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/btmrvl.txt b/Documentation/btmrvl.txt
new file mode 100644
index 000000000000..34916a46c099
--- /dev/null
+++ b/Documentation/btmrvl.txt
@@ -0,0 +1,119 @@
+=======================================================================
+ README for btmrvl driver
+=======================================================================
+
+
+All commands are used via debugfs interface.
+
+=====================
+Set/get driver configurations:
+
+Path: /debug/btmrvl/config/
+
+gpiogap=[n]
+hscfgcmd
+ These commands are used to configure the host sleep parameters.
+ bit 8:0 -- Gap
+ bit 16:8 -- GPIO
+
+ where GPIO is the pin number of GPIO used to wake up the host.
+ It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface
+ wakeup will be used instead).
+
+ where Gap is the gap in milli seconds between wakeup signal and
+ wakeup event, or 0xff for special host sleep setting.
+
+ Usage:
+ # Use SDIO interface to wake up the host and set GAP to 0x80:
+ echo 0xff80 > /debug/btmrvl/config/gpiogap
+ echo 1 > /debug/btmrvl/config/hscfgcmd
+
+ # Use GPIO pin #3 to wake up the host and set GAP to 0xff:
+ echo 0x03ff > /debug/btmrvl/config/gpiogap
+ echo 1 > /debug/btmrvl/config/hscfgcmd
+
+psmode=[n]
+pscmd
+ These commands are used to enable/disable auto sleep mode
+
+ where the option is:
+ 1 -- Enable auto sleep mode
+ 0 -- Disable auto sleep mode
+
+ Usage:
+ # Enable auto sleep mode
+ echo 1 > /debug/btmrvl/config/psmode
+ echo 1 > /debug/btmrvl/config/pscmd
+
+ # Disable auto sleep mode
+ echo 0 > /debug/btmrvl/config/psmode
+ echo 1 > /debug/btmrvl/config/pscmd
+
+
+hsmode=[n]
+hscmd
+ These commands are used to enable host sleep or wake up firmware
+
+ where the option is:
+ 1 -- Enable host sleep
+ 0 -- Wake up firmware
+
+ Usage:
+ # Enable host sleep
+ echo 1 > /debug/btmrvl/config/hsmode
+ echo 1 > /debug/btmrvl/config/hscmd
+
+ # Wake up firmware
+ echo 0 > /debug/btmrvl/config/hsmode
+ echo 1 > /debug/btmrvl/config/hscmd
+
+
+======================
+Get driver status:
+
+Path: /debug/btmrvl/status/
+
+Usage:
+ cat /debug/btmrvl/status/<args>
+
+where the args are:
+
+curpsmode
+ This command displays current auto sleep status.
+
+psstate
+ This command display the power save state.
+
+hsstate
+ This command display the host sleep state.
+
+txdnldrdy
+ This command displays the value of Tx download ready flag.
+
+
+=====================
+
+Use hcitool to issue raw hci command, refer to hcitool manual
+
+ Usage: Hcitool cmd <ogf> <ocf> [Parameters]
+
+ Interface Control Command
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface
+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface
+
+=======================================================================
+
+
+SD8688 firmware:
+
+/lib/firmware/sd8688_helper.bin
+/lib/firmware/sd8688.bin
+
+
+The images can be downloaded from:
+
+git.infradead.org/users/dwmw2/linux-firmware.git/libertas/
diff --git a/Documentation/connector/Makefile b/Documentation/connector/Makefile
index 8df1a7285a06..d98e4df98e24 100644
--- a/Documentation/connector/Makefile
+++ b/Documentation/connector/Makefile
@@ -9,3 +9,8 @@ hostprogs-y := ucon
always := $(hostprogs-y)
HOSTCFLAGS_ucon.o += -I$(objtree)/usr/include
+
+all: modules
+
+modules clean:
+ $(MAKE) -C ../.. SUBDIRS=$(PWD) $@
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index 6a5be5d5c8e4..1711adc33373 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "cn_test: " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -27,18 +29,17 @@
#include <linux/connector.h>
-static struct cb_id cn_test_id = { 0x123, 0x456 };
+static struct cb_id cn_test_id = { CN_NETLINK_USERS + 3, 0x456 };
static char cn_test_name[] = "cn_test";
static struct sock *nls;
static struct timer_list cn_test_timer;
-void cn_test_callback(void *data)
+static void cn_test_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = (struct cn_msg *)data;
-
- printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
- __func__, jiffies, msg->id.idx, msg->id.val,
- msg->seq, msg->ack, msg->len, (char *)msg->data);
+ pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+ __func__, jiffies, msg->id.idx, msg->id.val,
+ msg->seq, msg->ack, msg->len,
+ msg->len ? (char *)msg->data : "");
}
/*
@@ -63,9 +64,7 @@ static int cn_test_want_notify(void)
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb) {
- printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",
- size);
-
+ pr_err("failed to allocate new skb with size=%u\n", size);
return -ENOMEM;
}
@@ -114,12 +113,12 @@ static int cn_test_want_notify(void)
//netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
netlink_unicast(nls, skb, 0, 0);
- printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
+ pr_info("request was sent: group=0x%x\n", ctl->group);
return 0;
nlmsg_failure:
- printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+ pr_err("failed to send %u.%u\n", msg->seq, msg->ack);
kfree_skb(skb);
return -EINVAL;
}
@@ -131,6 +130,8 @@ static void cn_test_timer_func(unsigned long __data)
struct cn_msg *m;
char data[32];
+ pr_debug("%s: timer fired with data %lu\n", __func__, __data);
+
m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
if (m) {
@@ -150,7 +151,7 @@ static void cn_test_timer_func(unsigned long __data)
cn_test_timer_counter++;
- mod_timer(&cn_test_timer, jiffies + HZ);
+ mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000));
}
static int cn_test_init(void)
@@ -168,8 +169,10 @@ static int cn_test_init(void)
}
setup_timer(&cn_test_timer, cn_test_timer_func, 0);
- cn_test_timer.expires = jiffies + HZ;
- add_timer(&cn_test_timer);
+ mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000));
+
+ pr_info("initialized with id={%u.%u}\n",
+ cn_test_id.idx, cn_test_id.val);
return 0;
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
index ad6e0ba7b38c..81e6bf6ead57 100644
--- a/Documentation/connector/connector.txt
+++ b/Documentation/connector/connector.txt
@@ -5,10 +5,10 @@ Kernel Connector.
Kernel connector - new netlink based userspace <-> kernel space easy
to use communication module.
-Connector driver adds possibility to connect various agents using
-netlink based network. One must register callback and
-identifier. When driver receives special netlink message with
-appropriate identifier, appropriate callback will be called.
+The Connector driver makes it easy to connect various agents using a
+netlink based network. One must register a callback and an identifier.
+When the driver receives a special netlink message with the appropriate
+identifier, the appropriate callback will be called.
From the userspace point of view it's quite straightforward:
@@ -17,10 +17,10 @@ From the userspace point of view it's quite straightforward:
send();
recv();
-But if kernelspace want to use full power of such connections, driver
-writer must create special sockets, must know about struct sk_buff
-handling... Connector allows any kernelspace agents to use netlink
-based networking for inter-process communication in a significantly
+But if kernelspace wants to use the full power of such connections, the
+driver writer must create special sockets, must know about struct sk_buff
+handling, etc... The Connector driver allows any kernelspace agents to use
+netlink based networking for inter-process communication in a significantly
easier way:
int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
@@ -32,15 +32,15 @@ struct cb_id
__u32 val;
};
-idx and val are unique identifiers which must be registered in
-connector.h for in-kernel usage. void (*callback) (void *) - is a
-callback function which will be called when message with above idx.val
-will be received by connector core. Argument for that function must
+idx and val are unique identifiers which must be registered in the
+connector.h header for in-kernel usage. void (*callback) (void *) is a
+callback function which will be called when a message with above idx.val
+is received by the connector core. The argument for that function must
be dereferenced to struct cn_msg *.
struct cn_msg
{
- struct cb_id id;
+ struct cb_id id;
__u32 seq;
__u32 ack;
@@ -55,92 +55,95 @@ Connector interfaces.
int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
-Registers new callback with connector core.
+ Registers new callback with connector core.
-struct cb_id *id - unique connector's user identifier.
- It must be registered in connector.h for legal in-kernel users.
-char *name - connector's callback symbolic name.
-void (*callback) (void *) - connector's callback.
+ struct cb_id *id - unique connector's user identifier.
+ It must be registered in connector.h for legal in-kernel users.
+ char *name - connector's callback symbolic name.
+ void (*callback) (void *) - connector's callback.
Argument must be dereferenced to struct cn_msg *.
+
void cn_del_callback(struct cb_id *id);
-Unregisters new callback with connector core.
+ Unregisters new callback with connector core.
+
+ struct cb_id *id - unique connector's user identifier.
-struct cb_id *id - unique connector's user identifier.
int cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
-Sends message to the specified groups. It can be safely called from
-softirq context, but may silently fail under strong memory pressure.
-If there are no listeners for given group -ESRCH can be returned.
+ Sends message to the specified groups. It can be safely called from
+ softirq context, but may silently fail under strong memory pressure.
+ If there are no listeners for given group -ESRCH can be returned.
-struct cn_msg * - message header(with attached data).
-u32 __group - destination group.
+ struct cn_msg * - message header(with attached data).
+ u32 __group - destination group.
If __group is zero, then appropriate group will
be searched through all registered connector users,
and message will be delivered to the group which was
created for user with the same ID as in msg.
If __group is not zero, then message will be delivered
to the specified group.
-int gfp_mask - GFP mask.
+ int gfp_mask - GFP mask.
-Note: When registering new callback user, connector core assigns
-netlink group to the user which is equal to it's id.idx.
+ Note: When registering new callback user, connector core assigns
+ netlink group to the user which is equal to it's id.idx.
/*****************************************/
Protocol description.
/*****************************************/
-Current offers transport layer with fixed header. Recommended
-protocol which uses such header is following:
+The current framework offers a transport layer with fixed headers. The
+recommended protocol which uses such a header is as following:
msg->seq and msg->ack are used to determine message genealogy. When
-someone sends message it puts there locally unique sequence and random
-acknowledge numbers. Sequence number may be copied into
+someone sends a message, they use a locally unique sequence and random
+acknowledge number. The sequence number may be copied into
nlmsghdr->nlmsg_seq too.
-Sequence number is incremented with each message to be sent.
+The sequence number is incremented with each message sent.
-If we expect reply to our message, then sequence number in received
-message MUST be the same as in original message, and acknowledge
-number MUST be the same + 1.
+If you expect a reply to the message, then the sequence number in the
+received message MUST be the same as in the original message, and the
+acknowledge number MUST be the same + 1.
-If we receive message and it's sequence number is not equal to one we
-are expecting, then it is new message. If we receive message and it's
-sequence number is the same as one we are expecting, but it's
-acknowledge is not equal acknowledge number in original message + 1,
-then it is new message.
+If we receive a message and its sequence number is not equal to one we
+are expecting, then it is a new message. If we receive a message and
+its sequence number is the same as one we are expecting, but its
+acknowledge is not equal to the acknowledge number in the original
+message + 1, then it is a new message.
-Obviously, protocol header contains above id.
+Obviously, the protocol header contains the above id.
-connector allows event notification in the following form: kernel
+The connector allows event notification in the following form: kernel
driver or userspace process can ask connector to notify it when
-selected id's will be turned on or off(registered or unregistered it's
-callback). It is done by sending special command to connector
-driver(it also registers itself with id={-1, -1}).
+selected ids will be turned on or off (registered or unregistered its
+callback). It is done by sending a special command to the connector
+driver (it also registers itself with id={-1, -1}).
-As example of usage Documentation/connector now contains cn_test.c -
-testing module which uses connector to request notification and to
-send messages.
+As example of this usage can be found in the cn_test.c module which
+uses the connector to request notification and to send messages.
/*****************************************/
Reliability.
/*****************************************/
-Netlink itself is not reliable protocol, that means that messages can
+Netlink itself is not a reliable protocol. That means that messages can
be lost due to memory pressure or process' receiving queue overflowed,
-so caller is warned must be prepared. That is why struct cn_msg [main
-connector's message header] contains u32 seq and u32 ack fields.
+so caller is warned that it must be prepared. That is why the struct
+cn_msg [main connector's message header] contains u32 seq and u32 ack
+fields.
/*****************************************/
Userspace usage.
/*****************************************/
+
2.6.14 has a new netlink socket implementation, which by default does not
-allow to send data to netlink groups other than 1.
-So, if to use netlink socket (for example using connector)
-with different group number userspace application must subscribe to
-that group. It can be achieved by following pseudocode:
+allow people to send data to netlink groups other than 1.
+So, if you wish to use a netlink socket (for example using connector)
+with a different group number, the userspace application must subscribe to
+that group first. It can be achieved by the following pseudocode:
s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
@@ -160,8 +163,8 @@ if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
}
Where 270 above is SOL_NETLINK, and 1 is a NETLINK_ADD_MEMBERSHIP socket
-option. To drop multicast subscription one should call above socket option
-with NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
+option. To drop a multicast subscription, one should call the above socket
+option with the NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
2.6.14 netlink code only allows to select a group which is less or equal to
the maximum group number, which is used at netlink_kernel_create() time.
diff --git a/Documentation/connector/ucon.c b/Documentation/connector/ucon.c
index c5092ad0ce4b..4848db8c71ff 100644
--- a/Documentation/connector/ucon.c
+++ b/Documentation/connector/ucon.c
@@ -30,18 +30,24 @@
#include <arpa/inet.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
+#include <getopt.h>
#include <linux/connector.h>
#define DEBUG
#define NETLINK_CONNECTOR 11
+/* Hopefully your userspace connector.h matches this kernel */
+#define CN_TEST_IDX CN_NETLINK_USERS + 3
+#define CN_TEST_VAL 0x456
+
#ifdef DEBUG
#define ulog(f, a...) fprintf(stdout, f, ##a)
#else
@@ -83,6 +89,25 @@ static int netlink_send(int s, struct cn_msg *msg)
return err;
}
+static void usage(void)
+{
+ printf(
+ "Usage: ucon [options] [output file]\n"
+ "\n"
+ "\t-h\tthis help screen\n"
+ "\t-s\tsend buffers to the test module\n"
+ "\n"
+ "The default behavior of ucon is to subscribe to the test module\n"
+ "and wait for state messages. Any ones received are dumped to the\n"
+ "specified output file (or stdout). The test module is assumed to\n"
+ "have an id of {%u.%u}\n"
+ "\n"
+ "If you get no output, then verify the cn_test module id matches\n"
+ "the expected id above.\n"
+ , CN_TEST_IDX, CN_TEST_VAL
+ );
+}
+
int main(int argc, char *argv[])
{
int s;
@@ -94,17 +119,34 @@ int main(int argc, char *argv[])
FILE *out;
time_t tm;
struct pollfd pfd;
+ bool send_msgs = false;
- if (argc < 2)
- out = stdout;
- else {
- out = fopen(argv[1], "a+");
+ while ((s = getopt(argc, argv, "hs")) != -1) {
+ switch (s) {
+ case 's':
+ send_msgs = true;
+ break;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ /* getopt() outputs an error for us */
+ usage();
+ return 1;
+ }
+ }
+
+ if (argc != optind) {
+ out = fopen(argv[optind], "a+");
if (!out) {
ulog("Unable to open %s for writing: %s\n",
argv[1], strerror(errno));
out = stdout;
}
- }
+ } else
+ out = stdout;
memset(buf, 0, sizeof(buf));
@@ -115,9 +157,11 @@ int main(int argc, char *argv[])
}
l_local.nl_family = AF_NETLINK;
- l_local.nl_groups = 0x123; /* bitmask of requested groups */
+ l_local.nl_groups = -1; /* bitmask of requested groups */
l_local.nl_pid = 0;
+ ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
+
if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
perror("bind");
close(s);
@@ -130,15 +174,15 @@ int main(int argc, char *argv[])
setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
}
#endif
- if (0) {
+ if (send_msgs) {
int i, j;
memset(buf, 0, sizeof(buf));
data = (struct cn_msg *)buf;
- data->id.idx = 0x123;
- data->id.val = 0x456;
+ data->id.idx = CN_TEST_IDX;
+ data->id.val = CN_TEST_VAL;
data->seq = seq++;
data->ack = 0;
data->len = 0;
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 5d5f5fadd1c2..2a5b850847c0 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -176,7 +176,9 @@ scaling_governor, and by "echoing" the name of another
work on some specific architectures or
processors.
-cpuinfo_cur_freq : Current speed of the CPU, in KHz.
+cpuinfo_cur_freq : Current frequency of the CPU as obtained from
+ the hardware, in KHz. This is the frequency
+ the CPU actually runs at.
scaling_available_frequencies : List of available frequencies, in KHz.
@@ -196,7 +198,10 @@ related_cpus : List of CPUs that need some sort of frequency
scaling_driver : Hardware driver for cpufreq.
-scaling_cur_freq : Current frequency of the CPU, in KHz.
+scaling_cur_freq : Current frequency of the CPU as determined by
+ the governor and cpufreq core, in KHz. This is
+ the frequency the kernel thinks the CPU runs
+ at.
If you have selected the "userspace" governor which allows you to
set the CPU operating frequency to a specific value, you can read out
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 88519daab6e9..6fef118371e3 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 09e031c55887..8dde1fd34b30 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -206,24 +206,6 @@ Who: Len Brown <len.brown@intel.com>
---------------------------
-What: libata spindown skipping and warning
-When: Dec 2008
-Why: Some halt(8) implementations synchronize caches for and spin
- down libata disks because libata didn't use to spin down disk on
- system halt (only synchronized caches).
- Spin down on system halt is now implemented. sysfs node
- /sys/class/scsi_disk/h:c:i:l/manage_start_stop is present if
- spin down support is available.
- Because issuing spin down command to an already spun down disk
- makes some disks spin up just to spin down again, libata tracks
- device spindown status to skip the extra spindown command and
- warn about it.
- This is to give userspace tools the time to get updated and will
- be removed after userspace is reasonably updated.
-Who: Tejun Heo <htejun@gmail.com>
-
----------------------------
-
What: i386/x86_64 bzImage symlinks
When: April 2010
@@ -394,15 +376,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
-----------------------------
-What: obsolete generic irq defines and typedefs
-When: 2.6.30
-Why: The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t)
- have been kept around for migration reasons. After more than two years
- it's time to remove them finally
-Who: Thomas Gleixner <tglx@linutronix.de>
-
----------------------------
-
What: fakephp and associated sysfs files in /sys/bus/pci/slots/
When: 2011
Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
@@ -449,6 +422,13 @@ When: 2.6.33
Why: Should be implemented in userspace, policy daemon.
Who: Johannes Berg <johannes@sipsolutions.net>
+---------------------------
+
+What: CONFIG_INOTIFY
+When: 2.6.33
+Why: No known users, fsnotify more generic and more easily maintained.
+Who: Eric Paris <eparis@redhat.com>
+
----------------------------
What: CONFIG_X86_OLD_MCE
diff --git a/Documentation/filesystems/nfsroot.txt b/Documentation/filesystems/nfsroot.txt
index 68baddf3c3e0..3ba0b945aaf8 100644
--- a/Documentation/filesystems/nfsroot.txt
+++ b/Documentation/filesystems/nfsroot.txt
@@ -105,7 +105,7 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
the client address and this parameter is NOT empty only
replies from the specified server are accepted.
- Only required for for NFS root. That is autoconfiguration
+ Only required for NFS root. That is autoconfiguration
will not be triggered if it is missing and NFS root is not
in operation.
diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt
index b843743aa0b5..0d15ebccf5b0 100644
--- a/Documentation/filesystems/seq_file.txt
+++ b/Documentation/filesystems/seq_file.txt
@@ -46,7 +46,7 @@ better to do. The file is seekable, in that one can do something like the
following:
dd if=/proc/sequence of=out1 count=1
- dd if=/proc/sequence skip=1 out=out2 count=1
+ dd if=/proc/sequence skip=1 of=out2 count=1
Then concatenate the output files out1 and out2 and get the right
result. Yes, it is a thoroughly useless module, but the point is to show
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
index 7e81e37c0b1e..b245d524d568 100644
--- a/Documentation/filesystems/sysfs.txt
+++ b/Documentation/filesystems/sysfs.txt
@@ -23,7 +23,8 @@ interface.
Using sysfs
~~~~~~~~~~~
-sysfs is always compiled in. You can access it by doing:
+sysfs is always compiled in if CONFIG_SYSFS is defined. You can access
+it by doing:
mount -t sysfs sysfs /sys
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index b58b84b50fa2..eed520fd0c8e 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -102,7 +102,7 @@ shortname=lower|win95|winnt|mixed
winnt: emulate the Windows NT rule for display/create.
mixed: emulate the Windows NT rule for display,
emulate the Windows 95 rule for create.
- Default setting is `lower'.
+ Default setting is `mixed'.
tz=UTC -- Interpret timestamps as UTC rather than local time.
This option disables the conversion of timestamps
diff --git a/Documentation/gcov.txt b/Documentation/gcov.txt
index 40ec63352760..e7ca6478cd93 100644
--- a/Documentation/gcov.txt
+++ b/Documentation/gcov.txt
@@ -47,7 +47,7 @@ Possible uses:
Configure the kernel with:
- CONFIG_DEBUGFS=y
+ CONFIG_DEBUG_FS=y
CONFIG_GCOV_KERNEL=y
and to get coverage data for the entire kernel:
diff --git a/Documentation/hwlat_detector.txt b/Documentation/hwlat_detector.txt
new file mode 100644
index 000000000000..cb61516483d3
--- /dev/null
+++ b/Documentation/hwlat_detector.txt
@@ -0,0 +1,64 @@
+Introduction:
+-------------
+
+The module hwlat_detector is a special purpose kernel module that is used to
+detect large system latencies induced by the behavior of certain underlying
+hardware or firmware, independent of Linux itself. The code was developed
+originally to detect SMIs (System Management Interrupts) on x86 systems,
+however there is nothing x86 specific about this patchset. It was
+originally written for use by the "RT" patch since the Real Time
+kernel is highly latency sensitive.
+
+SMIs are usually not serviced by the Linux kernel, which typically does not
+even know that they are occuring. SMIs are instead are set up by BIOS code
+and are serviced by BIOS code, usually for "critical" events such as
+management of thermal sensors and fans. Sometimes though, SMIs are used for
+other tasks and those tasks can spend an inordinate amount of time in the
+handler (sometimes measured in milliseconds). Obviously this is a problem if
+you are trying to keep event service latencies down in the microsecond range.
+
+The hardware latency detector works by hogging all of the cpus for configurable
+amounts of time (by calling stop_machine()), polling the CPU Time Stamp Counter
+for some period, then looking for gaps in the TSC data. Any gap indicates a
+time when the polling was interrupted and since the machine is stopped and
+interrupts turned off the only thing that could do that would be an SMI.
+
+Note that the SMI detector should *NEVER* be used in a production environment.
+It is intended to be run manually to determine if the hardware platform has a
+problem with long system firmware service routines.
+
+Usage:
+------
+
+Loading the module hwlat_detector passing the parameter "enabled=1" (or by
+setting the "enable" entry in "hwlat_detector" debugfs toggled on) is the only
+step required to start the hwlat_detector. It is possible to redefine the
+threshold in microseconds (us) above which latency spikes will be taken
+into account (parameter "threshold=").
+
+Example:
+
+ # modprobe hwlat_detector enabled=1 threshold=100
+
+After the module is loaded, it creates a directory named "hwlat_detector" under
+the debugfs mountpoint, "/debug/hwlat_detector" for this text. It is necessary
+to have debugfs mounted, which might be on /sys/debug on your system.
+
+The /debug/hwlat_detector interface contains the following files:
+
+count - number of latency spikes observed since last reset
+enable - a global enable/disable toggle (0/1), resets count
+max - maximum hardware latency actually observed (usecs)
+sample - a pipe from which to read current raw sample data
+ in the format <timestamp> <latency observed usecs>
+ (can be opened O_NONBLOCK for a single sample)
+threshold - minimum latency value to be considered (usecs)
+width - time period to sample with CPUs held (usecs)
+ must be less than the total window size (enforced)
+window - total period of sampling, width being inside (usecs)
+
+By default we will set width to 500,000 and window to 1,000,000, meaning that
+we will sample every 1,000,000 usecs (1s) for 500,000 usecs (0.5s). If we
+observe any latencies that exceed the threshold (initially 100 usecs),
+then we write to a global sample ring buffer of 8K samples, which is
+consumed by reading from the "sample" (pipe) debugfs file interface.
diff --git a/Documentation/hwmon/hpfall.c b/Documentation/hwmon/hpfall.c
index bbea1ccfd46a..d2f6711b468b 100644
--- a/Documentation/hwmon/hpfall.c
+++ b/Documentation/hwmon/hpfall.c
@@ -57,45 +57,43 @@ void ignore_me(void)
{
protect(0);
set_led(0);
-
}
-int main(int argc, char* argv[])
+int main(int argc, char *argv[])
{
- int fd, ret;
+ int fd, ret;
- fd = open("/dev/freefall", O_RDONLY);
- if (fd < 0) {
- perror("open");
- return EXIT_FAILURE;
- }
+ fd = open("/dev/freefall", O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return EXIT_FAILURE;
+ }
signal(SIGALRM, ignore_me);
- for (;;) {
- unsigned char count;
-
- ret = read(fd, &count, sizeof(count));
- alarm(0);
- if ((ret == -1) && (errno == EINTR)) {
- /* Alarm expired, time to unpark the heads */
- continue;
- }
-
- if (ret != sizeof(count)) {
- perror("read");
- break;
- }
-
- protect(21);
- set_led(1);
- if (1 || on_ac() || lid_open()) {
- alarm(2);
- } else {
- alarm(20);
- }
- }
+ for (;;) {
+ unsigned char count;
+
+ ret = read(fd, &count, sizeof(count));
+ alarm(0);
+ if ((ret == -1) && (errno == EINTR)) {
+ /* Alarm expired, time to unpark the heads */
+ continue;
+ }
+
+ if (ret != sizeof(count)) {
+ perror("read");
+ break;
+ }
+
+ protect(21);
+ set_led(1);
+ if (1 || on_ac() || lid_open())
+ alarm(2);
+ else
+ alarm(20);
+ }
- close(fd);
- return EXIT_SUCCESS;
+ close(fd);
+ return EXIT_SUCCESS;
}
diff --git a/Documentation/hwmon/pc87427 b/Documentation/hwmon/pc87427
index d1ebbe510f35..db5cc1227a83 100644
--- a/Documentation/hwmon/pc87427
+++ b/Documentation/hwmon/pc87427
@@ -34,5 +34,5 @@ Fan rotation speeds are reported as 14-bit values from a gated clock
signal. Speeds down to 83 RPM can be measured.
An alarm is triggered if the rotation speed drops below a programmable
-limit. Another alarm is triggered if the speed is too low to to be measured
+limit. Another alarm is triggered if the speed is too low to be measured
(including stalled or missing fan).
diff --git a/Documentation/hwmon/tmp421 b/Documentation/hwmon/tmp421
new file mode 100644
index 000000000000..0cf07f824741
--- /dev/null
+++ b/Documentation/hwmon/tmp421
@@ -0,0 +1,36 @@
+Kernel driver tmp421
+====================
+
+Supported chips:
+ * Texas Instruments TMP421
+ Prefix: 'tmp421'
+ Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
+ * Texas Instruments TMP422
+ Prefix: 'tmp422'
+ Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
+ * Texas Instruments TMP423
+ Prefix: 'tmp423'
+ Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
+
+Authors:
+ Andre Prendel <andre.prendel@gmx.de>
+
+Description
+-----------
+
+This driver implements support for Texas Instruments TMP421, TMP422
+and TMP423 temperature sensor chips. These chips implement one local
+and up to one (TMP421), up to two (TMP422) or up to three (TMP423)
+remote sensors. Temperature is measured in degrees Celsius. The chips
+are wired over I2C/SMBus and specified over a temperature range of -40
+to +125 degrees Celsius. Resolution for both the local and remote
+channels is 0.0625 degree C.
+
+The chips support only temperature measurement. The driver exports
+the temperature values via the following sysfs files:
+
+temp[1-4]_input
+temp[2-4]_fault
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 694e165a6f1c..ace9b32095b2 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -57,6 +57,7 @@ parameter is applicable:
ISAPNP ISA PnP code is enabled.
ISDN Appropriate ISDN support is enabled.
JOY Appropriate joystick support is enabled.
+ KVM Kernel Virtual Machine support is enabled.
LIBATA Libata driver is enabled
LP Printer support is enabled.
LOOP Loopback device support is enabled.
@@ -1099,6 +1100,44 @@ and is between 256 and 4096 characters. It is defined in the file
kstack=N [X86] Print N words from the kernel stack
in oops dumps.
+ kvm.ignore_msrs=[KVM] Ignore guest accesses to unhandled MSRs.
+ Default is 0 (don't ignore, but inject #GP)
+
+ kvm.oos_shadow= [KVM] Disable out-of-sync shadow paging.
+ Default is 1 (enabled)
+
+ kvm-amd.nested= [KVM,AMD] Allow nested virtualization in KVM/SVM.
+ Default is 0 (off)
+
+ kvm-amd.npt= [KVM,AMD] Disable nested paging (virtualized MMU)
+ for all guests.
+ Default is 1 (enabled) if in 64bit or 32bit-PAE mode
+
+ kvm-intel.bypass_guest_pf=
+ [KVM,Intel] Disables bypassing of guest page faults
+ on Intel chips. Default is 1 (enabled)
+
+ kvm-intel.ept= [KVM,Intel] Disable extended page tables
+ (virtualized MMU) support on capable Intel chips.
+ Default is 1 (enabled)
+
+ kvm-intel.emulate_invalid_guest_state=
+ [KVM,Intel] Enable emulation of invalid guest states
+ Default is 0 (disabled)
+
+ kvm-intel.flexpriority=
+ [KVM,Intel] Disable FlexPriority feature (TPR shadow).
+ Default is 1 (enabled)
+
+ kvm-intel.unrestricted_guest=
+ [KVM,Intel] Disable unrestricted guest feature
+ (virtualized real and unpaged mode) on capable
+ Intel chips. Default is 1 (enabled)
+
+ kvm-intel.vpid= [KVM,Intel] Disable Virtual Processor Identification
+ feature (tagged TLBs) on capable Intel chips.
+ Default is 1 (enabled)
+
l2cr= [PPC]
l3cr= [PPC]
@@ -1532,6 +1571,11 @@ and is between 256 and 4096 characters. It is defined in the file
symbolic names: lapic and ioapic
Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic
+ netpoll.carrier_timeout=
+ [NET] Specifies amount of time (in seconds) that
+ netpoll should wait for a carrier. By default netpoll
+ waits 4 seconds.
+
no387 [BUGS=X86-32] Tells the kernel to use the 387 maths
emulation library even if a 387 maths coprocessor
is present.
@@ -2481,6 +2525,11 @@ and is between 256 and 4096 characters. It is defined in the file
trace_buf_size=nn[KMG]
[FTRACE] will set tracing buffer size.
+ trace_event=[event-list]
+ [FTRACE] Set and start specified trace events in order
+ to facilitate early boot debugging.
+ See also Documentation/trace/events.txt
+
trix= [HW,OSS] MediaTrix AudioTrix Pro
Format:
<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt
index 89068030b01b..fa932490b3dc 100644
--- a/Documentation/kmemleak.txt
+++ b/Documentation/kmemleak.txt
@@ -35,13 +35,12 @@ Memory scanning parameters can be modified at run-time by writing to the
/sys/kernel/debug/kmemleak file. The following parameters are supported:
off - disable kmemleak (irreversible)
- stack=on - enable the task stacks scanning (default)
- stack=off - disable the tasks stacks scanning
scan=on - start the automatic memory scanning thread (default)
scan=off - stop the automatic memory scanning thread
scan=<secs> - set the automatic memory scanning period in seconds
(default 600, 0 to stop the automatic scanning)
scan - trigger a memory scan
+ dump=<addr> - dump information about the object found at <addr>
Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
the kernel command line.
@@ -110,7 +109,8 @@ reported by kmemleak because values found during the memory scanning
point to such objects. To reduce the number of false negatives, kmemleak
provides the kmemleak_ignore, kmemleak_scan_area, kmemleak_no_scan and
kmemleak_erase functions (see above). The task stacks also increase the
-amount of false negatives and their scanning is not enabled by default.
+amount of false negatives (enabling CONFIG_DEBUG_STACK_USAGE would help
+by zeroing newly allocated stacks).
The false positives are objects wrongly reported as being memory leaks
(orphan). For objects known not to be leaks, kmemleak provides the
@@ -119,9 +119,9 @@ the memory block is known not to contain other pointers and it will no
longer be scanned.
Some of the reported leaks are only transient, especially on SMP
-systems, because of pointers temporarily stored in CPU registers or
-stacks. Kmemleak defines MSECS_MIN_AGE (defaulting to 1000) representing
-the minimum age of an object to be reported as a memory leak.
+systems, because of pointers temporarily stored in CPU registers.
+Kmemleak defines MSECS_MIN_AGE (defaulting to 5000) representing the
+minimum age of an object to be reported as a memory leak.
Limitations and Drawbacks
-------------------------
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
new file mode 100644
index 000000000000..1b1c22da211b
--- /dev/null
+++ b/Documentation/kvm/api.txt
@@ -0,0 +1,683 @@
+The Definitive KVM (Kernel-based Virtual Machine) API Documentation
+===================================================================
+
+1. General description
+
+The kvm API is a set of ioctls that are issued to control various aspects
+of a virtual machine. The ioctls belong to three classes
+
+ - System ioctls: These query and set global attributes which affect the
+ whole kvm subsystem. In addition a system ioctl is used to create
+ virtual machines
+
+ - VM ioctls: These query and set attributes that affect an entire virtual
+ machine, for example memory layout. In addition a VM ioctl is used to
+ create virtual cpus (vcpus).
+
+ Only run VM ioctls from the same process (address space) that was used
+ to create the VM.
+
+ - vcpu ioctls: These query and set attributes that control the operation
+ of a single virtual cpu.
+
+ Only run vcpu ioctls from the same thread that was used to create the
+ vcpu.
+
+2. File descritpors
+
+The kvm API is centered around file descriptors. An initial
+open("/dev/kvm") obtains a handle to the kvm subsystem; this handle
+can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this
+handle will create a VM file descripror which can be used to issue VM
+ioctls. A KVM_CREATE_VCPU ioctl on a VM fd will create a virtual cpu
+and return a file descriptor pointing to it. Finally, ioctls on a vcpu
+fd can be used to control the vcpu, including the important task of
+actually running guest code.
+
+In general file descriptors can be migrated among processes by means
+of fork() and the SCM_RIGHTS facility of unix domain socket. These
+kinds of tricks are explicitly not supported by kvm. While they will
+not cause harm to the host, their actual behavior is not guaranteed by
+the API. The only supported use is one virtual machine per process,
+and one vcpu per thread.
+
+3. Extensions
+
+As of Linux 2.6.22, the KVM ABI has been stabilized: no backward
+incompatible change are allowed. However, there is an extension
+facility that allows backward-compatible extensions to the API to be
+queried and used.
+
+The extension mechanism is not based on on the Linux version number.
+Instead, kvm defines extension identifiers and a facility to query
+whether a particular extension identifier is available. If it is, a
+set of ioctls is available for application use.
+
+4. API description
+
+This section describes ioctls that can be used to control kvm guests.
+For each ioctl, the following information is provided along with a
+description:
+
+ Capability: which KVM extension provides this ioctl. Can be 'basic',
+ which means that is will be provided by any kernel that supports
+ API version 12 (see section 4.1), or a KVM_CAP_xyz constant, which
+ means availability needs to be checked with KVM_CHECK_EXTENSION
+ (see section 4.4).
+
+ Architectures: which instruction set architectures provide this ioctl.
+ x86 includes both i386 and x86_64.
+
+ Type: system, vm, or vcpu.
+
+ Parameters: what parameters are accepted by the ioctl.
+
+ Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL)
+ are not detailed, but errors with specific meanings are.
+
+4.1 KVM_GET_API_VERSION
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: none
+Returns: the constant KVM_API_VERSION (=12)
+
+This identifies the API version as the stable kvm API. It is not
+expected that this number will change. However, Linux 2.6.20 and
+2.6.21 report earlier versions; these are not documented and not
+supported. Applications should refuse to run if KVM_GET_API_VERSION
+returns a value other than 12. If this check passes, all ioctls
+described as 'basic' will be available.
+
+4.2 KVM_CREATE_VM
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: none
+Returns: a VM fd that can be used to control the new virtual machine.
+
+The new VM has no virtual cpus and no memory. An mmap() of a VM fd
+will access the virtual machine's physical address space; offset zero
+corresponds to guest physical address zero. Use of mmap() on a VM fd
+is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is
+available.
+
+4.3 KVM_GET_MSR_INDEX_LIST
+
+Capability: basic
+Architectures: x86
+Type: system
+Parameters: struct kvm_msr_list (in/out)
+Returns: 0 on success; -1 on error
+Errors:
+ E2BIG: the msr index list is to be to fit in the array specified by
+ the user.
+
+struct kvm_msr_list {
+ __u32 nmsrs; /* number of msrs in entries */
+ __u32 indices[0];
+};
+
+This ioctl returns the guest msrs that are supported. The list varies
+by kvm version and host processor, but does not change otherwise. The
+user fills in the size of the indices array in nmsrs, and in return
+kvm adjusts nmsrs to reflect the actual number of msrs and fills in
+the indices array with their numbers.
+
+4.4 KVM_CHECK_EXTENSION
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: extension identifier (KVM_CAP_*)
+Returns: 0 if unsupported; 1 (or some other positive integer) if supported
+
+The API allows the application to query about extensions to the core
+kvm API. Userspace passes an extension identifier (an integer) and
+receives an integer that describes the extension availability.
+Generally 0 means no and 1 means yes, but some extensions may report
+additional information in the integer return value.
+
+4.5 KVM_GET_VCPU_MMAP_SIZE
+
+Capability: basic
+Architectures: all
+Type: system ioctl
+Parameters: none
+Returns: size of vcpu mmap area, in bytes
+
+The KVM_RUN ioctl (cf.) communicates with userspace via a shared
+memory region. This ioctl returns the size of that region. See the
+KVM_RUN documentation for details.
+
+4.6 KVM_SET_MEMORY_REGION
+
+Capability: basic
+Architectures: all
+Type: vm ioctl
+Parameters: struct kvm_memory_region (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_memory_region {
+ __u32 slot;
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size; /* bytes */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES 1UL
+
+This ioctl allows the user to create or modify a guest physical memory
+slot. When changing an existing slot, it may be moved in the guest
+physical memory space, or its flags may be modified. It may not be
+resized. Slots may not overlap.
+
+The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which
+instructs kvm to keep track of writes to memory within the slot. See
+the KVM_GET_DIRTY_LOG ioctl.
+
+It is recommended to use the KVM_SET_USER_MEMORY_REGION ioctl instead
+of this API, if available. This newer API allows placing guest memory
+at specified locations in the host address space, yielding better
+control and easy access.
+
+4.6 KVM_CREATE_VCPU
+
+Capability: basic
+Architectures: all
+Type: vm ioctl
+Parameters: vcpu id (apic id on x86)
+Returns: vcpu fd on success, -1 on error
+
+This API adds a vcpu to a virtual machine. The vcpu id is a small integer
+in the range [0, max_vcpus).
+
+4.7 KVM_GET_DIRTY_LOG (vm ioctl)
+
+Capability: basic
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_dirty_log (in/out)
+Returns: 0 on success, -1 on error
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+ __u32 slot;
+ __u32 padding;
+ union {
+ void __user *dirty_bitmap; /* one bit per page */
+ __u64 padding;
+ };
+};
+
+Given a memory slot, return a bitmap containing any pages dirtied
+since the last call to this ioctl. Bit 0 is the first page in the
+memory slot. Ensure the entire structure is cleared to avoid padding
+issues.
+
+4.8 KVM_SET_MEMORY_ALIAS
+
+Capability: basic
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_memory_alias (in)
+Returns: 0 (success), -1 (error)
+
+struct kvm_memory_alias {
+ __u32 slot; /* this has a different namespace than memory slots */
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size;
+ __u64 target_phys_addr;
+};
+
+Defines a guest physical address space region as an alias to another
+region. Useful for aliased address, for example the VGA low memory
+window. Should not be used with userspace memory.
+
+4.9 KVM_RUN
+
+Capability: basic
+Architectures: all
+Type: vcpu ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+Errors:
+ EINTR: an unmasked signal is pending
+
+This ioctl is used to run a guest virtual cpu. While there are no
+explicit parameters, there is an implicit parameter block that can be
+obtained by mmap()ing the vcpu fd at offset 0, with the size given by
+KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct
+kvm_run' (see below).
+
+4.10 KVM_GET_REGS
+
+Capability: basic
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_regs (out)
+Returns: 0 on success, -1 on error
+
+Reads the general purpose registers from the vcpu.
+
+/* x86 */
+struct kvm_regs {
+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+ __u64 rax, rbx, rcx, rdx;
+ __u64 rsi, rdi, rsp, rbp;
+ __u64 r8, r9, r10, r11;
+ __u64 r12, r13, r14, r15;
+ __u64 rip, rflags;
+};
+
+4.11 KVM_SET_REGS
+
+Capability: basic
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_regs (in)
+Returns: 0 on success, -1 on error
+
+Writes the general purpose registers into the vcpu.
+
+See KVM_GET_REGS for the data structure.
+
+4.12 KVM_GET_SREGS
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_sregs (out)
+Returns: 0 on success, -1 on error
+
+Reads special registers from the vcpu.
+
+/* x86 */
+struct kvm_sregs {
+ struct kvm_segment cs, ds, es, fs, gs, ss;
+ struct kvm_segment tr, ldt;
+ struct kvm_dtable gdt, idt;
+ __u64 cr0, cr2, cr3, cr4, cr8;
+ __u64 efer;
+ __u64 apic_base;
+ __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
+};
+
+interrupt_bitmap is a bitmap of pending external interrupts. At most
+one bit may be set. This interrupt has been acknowledged by the APIC
+but not yet injected into the cpu core.
+
+4.13 KVM_SET_SREGS
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_sregs (in)
+Returns: 0 on success, -1 on error
+
+Writes special registers into the vcpu. See KVM_GET_SREGS for the
+data structures.
+
+4.14 KVM_TRANSLATE
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_translation (in/out)
+Returns: 0 on success, -1 on error
+
+Translates a virtual address according to the vcpu's current address
+translation mode.
+
+struct kvm_translation {
+ /* in */
+ __u64 linear_address;
+
+ /* out */
+ __u64 physical_address;
+ __u8 valid;
+ __u8 writeable;
+ __u8 usermode;
+ __u8 pad[5];
+};
+
+4.15 KVM_INTERRUPT
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_interrupt (in)
+Returns: 0 on success, -1 on error
+
+Queues a hardware interrupt vector to be injected. This is only
+useful if in-kernel local APIC is not used.
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+ /* in */
+ __u32 irq;
+};
+
+Note 'irq' is an interrupt vector, not an interrupt pin or line.
+
+4.16 KVM_DEBUG_GUEST
+
+Capability: basic
+Architectures: none
+Type: vcpu ioctl
+Parameters: none)
+Returns: -1 on error
+
+Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
+
+4.17 KVM_GET_MSRS
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_msrs (in/out)
+Returns: 0 on success, -1 on error
+
+Reads model-specific registers from the vcpu. Supported msr indices can
+be obtained using KVM_GET_MSR_INDEX_LIST.
+
+struct kvm_msrs {
+ __u32 nmsrs; /* number of msrs in entries */
+ __u32 pad;
+
+ struct kvm_msr_entry entries[0];
+};
+
+struct kvm_msr_entry {
+ __u32 index;
+ __u32 reserved;
+ __u64 data;
+};
+
+Application code should set the 'nmsrs' member (which indicates the
+size of the entries array) and the 'index' member of each array entry.
+kvm will fill in the 'data' member.
+
+4.18 KVM_SET_MSRS
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_msrs (in)
+Returns: 0 on success, -1 on error
+
+Writes model-specific registers to the vcpu. See KVM_GET_MSRS for the
+data structures.
+
+Application code should set the 'nmsrs' member (which indicates the
+size of the entries array), and the 'index' and 'data' members of each
+array entry.
+
+4.19 KVM_SET_CPUID
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_cpuid (in)
+Returns: 0 on success, -1 on error
+
+Defines the vcpu responses to the cpuid instruction. Applications
+should use the KVM_SET_CPUID2 ioctl if available.
+
+
+struct kvm_cpuid_entry {
+ __u32 function;
+ __u32 eax;
+ __u32 ebx;
+ __u32 ecx;
+ __u32 edx;
+ __u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+ __u32 nent;
+ __u32 padding;
+ struct kvm_cpuid_entry entries[0];
+};
+
+4.20 KVM_SET_SIGNAL_MASK
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_signal_mask (in)
+Returns: 0 on success, -1 on error
+
+Defines which signals are blocked during execution of KVM_RUN. This
+signal mask temporarily overrides the threads signal mask. Any
+unblocked signal received (except SIGKILL and SIGSTOP, which retain
+their traditional behaviour) will cause KVM_RUN to return with -EINTR.
+
+Note the signal will only be delivered if not blocked by the original
+signal mask.
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+ __u32 len;
+ __u8 sigset[0];
+};
+
+4.21 KVM_GET_FPU
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_fpu (out)
+Returns: 0 on success, -1 on error
+
+Reads the floating point state from the vcpu.
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+ __u8 fpr[8][16];
+ __u16 fcw;
+ __u16 fsw;
+ __u8 ftwx; /* in fxsave format */
+ __u8 pad1;
+ __u16 last_opcode;
+ __u64 last_ip;
+ __u64 last_dp;
+ __u8 xmm[16][16];
+ __u32 mxcsr;
+ __u32 pad2;
+};
+
+4.22 KVM_SET_FPU
+
+Capability: basic
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_fpu (in)
+Returns: 0 on success, -1 on error
+
+Writes the floating point state to the vcpu.
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+ __u8 fpr[8][16];
+ __u16 fcw;
+ __u16 fsw;
+ __u8 ftwx; /* in fxsave format */
+ __u8 pad1;
+ __u16 last_opcode;
+ __u64 last_ip;
+ __u64 last_dp;
+ __u8 xmm[16][16];
+ __u32 mxcsr;
+ __u32 pad2;
+};
+
+5. The kvm_run structure
+
+Application code obtains a pointer to the kvm_run structure by
+mmap()ing a vcpu fd. From that point, application code can control
+execution by changing fields in kvm_run prior to calling the KVM_RUN
+ioctl, and obtain information about the reason KVM_RUN returned by
+looking up structure members.
+
+struct kvm_run {
+ /* in */
+ __u8 request_interrupt_window;
+
+Request that KVM_RUN return when it becomes possible to inject external
+interrupts into the guest. Useful in conjunction with KVM_INTERRUPT.
+
+ __u8 padding1[7];
+
+ /* out */
+ __u32 exit_reason;
+
+When KVM_RUN has returned successfully (return value 0), this informs
+application code why KVM_RUN has returned. Allowable values for this
+field are detailed below.
+
+ __u8 ready_for_interrupt_injection;
+
+If request_interrupt_window has been specified, this field indicates
+an interrupt can be injected now with KVM_INTERRUPT.
+
+ __u8 if_flag;
+
+The value of the current interrupt flag. Only valid if in-kernel
+local APIC is not used.
+
+ __u8 padding2[2];
+
+ /* in (pre_kvm_run), out (post_kvm_run) */
+ __u64 cr8;
+
+The value of the cr8 register. Only valid if in-kernel local APIC is
+not used. Both input and output.
+
+ __u64 apic_base;
+
+The value of the APIC BASE msr. Only valid if in-kernel local
+APIC is not used. Both input and output.
+
+ union {
+ /* KVM_EXIT_UNKNOWN */
+ struct {
+ __u64 hardware_exit_reason;
+ } hw;
+
+If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown
+reasons. Further architecture-specific information is available in
+hardware_exit_reason.
+
+ /* KVM_EXIT_FAIL_ENTRY */
+ struct {
+ __u64 hardware_entry_failure_reason;
+ } fail_entry;
+
+If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due
+to unknown reasons. Further architecture-specific information is
+available in hardware_entry_failure_reason.
+
+ /* KVM_EXIT_EXCEPTION */
+ struct {
+ __u32 exception;
+ __u32 error_code;
+ } ex;
+
+Unused.
+
+ /* KVM_EXIT_IO */
+ struct {
+#define KVM_EXIT_IO_IN 0
+#define KVM_EXIT_IO_OUT 1
+ __u8 direction;
+ __u8 size; /* bytes */
+ __u16 port;
+ __u32 count;
+ __u64 data_offset; /* relative to kvm_run start */
+ } io;
+
+If exit_reason is KVM_EXIT_IO_IN or KVM_EXIT_IO_OUT, then the vcpu has
+executed a port I/O instruction which could not be satisfied by kvm.
+data_offset describes where the data is located (KVM_EXIT_IO_OUT) or
+where kvm expects application code to place the data for the next
+KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a patcked array.
+
+ struct {
+ struct kvm_debug_exit_arch arch;
+ } debug;
+
+Unused.
+
+ /* KVM_EXIT_MMIO */
+ struct {
+ __u64 phys_addr;
+ __u8 data[8];
+ __u32 len;
+ __u8 is_write;
+ } mmio;
+
+If exit_reason is KVM_EXIT_MMIO or KVM_EXIT_IO_OUT, then the vcpu has
+executed a memory-mapped I/O instruction which could not be satisfied
+by kvm. The 'data' member contains the written data if 'is_write' is
+true, and should be filled by application code otherwise.
+
+ /* KVM_EXIT_HYPERCALL */
+ struct {
+ __u64 nr;
+ __u64 args[6];
+ __u64 ret;
+ __u32 longmode;
+ __u32 pad;
+ } hypercall;
+
+Unused.
+
+ /* KVM_EXIT_TPR_ACCESS */
+ struct {
+ __u64 rip;
+ __u32 is_write;
+ __u32 pad;
+ } tpr_access;
+
+To be documented (KVM_TPR_ACCESS_REPORTING).
+
+ /* KVM_EXIT_S390_SIEIC */
+ struct {
+ __u8 icptcode;
+ __u64 mask; /* psw upper half */
+ __u64 addr; /* psw lower half */
+ __u16 ipa;
+ __u32 ipb;
+ } s390_sieic;
+
+s390 specific.
+
+ /* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR 1
+#define KVM_S390_RESET_CLEAR 2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT 8
+#define KVM_S390_RESET_IPL 16
+ __u64 s390_reset_flags;
+
+s390 specific.
+
+ /* KVM_EXIT_DCR */
+ struct {
+ __u32 dcrn;
+ __u32 data;
+ __u8 is_write;
+ } dcr;
+
+powerpc specific.
+
+ /* Fix the size of the union. */
+ char padding[256];
+ };
+};
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index f2296ecedb89..e2ddcdeb61b6 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -36,8 +36,6 @@ detailed description):
- Bluetooth enable and disable
- video output switching, expansion control
- ThinkLight on and off
- - limited docking and undocking
- - UltraBay eject
- CMOS/UCMS control
- LED control
- ACPI sounds
@@ -729,131 +727,6 @@ cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
It is impossible to know if the status returned through sysfs is valid.
-Docking / undocking -- /proc/acpi/ibm/dock
-------------------------------------------
-
-Docking and undocking (e.g. with the X4 UltraBase) requires some
-actions to be taken by the operating system to safely make or break
-the electrical connections with the dock.
-
-The docking feature of this driver generates the following ACPI events:
-
- ibm/dock GDCK 00000003 00000001 -- eject request
- ibm/dock GDCK 00000003 00000002 -- undocked
- ibm/dock GDCK 00000000 00000003 -- docked
-
-NOTE: These events will only be generated if the laptop was docked
-when originally booted. This is due to the current lack of support for
-hot plugging of devices in the Linux ACPI framework. If the laptop was
-booted while not in the dock, the following message is shown in the
-logs:
-
- Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present
-
-In this case, no dock-related events are generated but the dock and
-undock commands described below still work. They can be executed
-manually or triggered by Fn key combinations (see the example acpid
-configuration files included in the driver tarball package available
-on the web site).
-
-When the eject request button on the dock is pressed, the first event
-above is generated. The handler for this event should issue the
-following command:
-
- echo undock > /proc/acpi/ibm/dock
-
-After the LED on the dock goes off, it is safe to eject the laptop.
-Note: if you pressed this key by mistake, go ahead and eject the
-laptop, then dock it back in. Otherwise, the dock may not function as
-expected.
-
-When the laptop is docked, the third event above is generated. The
-handler for this event should issue the following command to fully
-enable the dock:
-
- echo dock > /proc/acpi/ibm/dock
-
-The contents of the /proc/acpi/ibm/dock file shows the current status
-of the dock, as provided by the ACPI framework.
-
-The docking support in this driver does not take care of enabling or
-disabling any other devices you may have attached to the dock. For
-example, a CD drive plugged into the UltraBase needs to be disabled or
-enabled separately. See the provided example acpid configuration files
-for how this can be accomplished.
-
-There is no support yet for PCI devices that may be attached to a
-docking station, e.g. in the ThinkPad Dock II. The driver currently
-does not recognize, enable or disable such devices. This means that
-the only docking stations currently supported are the X-series
-UltraBase docks and "dumb" port replicators like the Mini Dock (the
-latter don't need any ACPI support, actually).
-
-
-UltraBay eject -- /proc/acpi/ibm/bay
-------------------------------------
-
-Inserting or ejecting an UltraBay device requires some actions to be
-taken by the operating system to safely make or break the electrical
-connections with the device.
-
-This feature generates the following ACPI events:
-
- ibm/bay MSTR 00000003 00000000 -- eject request
- ibm/bay MSTR 00000001 00000000 -- eject lever inserted
-
-NOTE: These events will only be generated if the UltraBay was present
-when the laptop was originally booted (on the X series, the UltraBay
-is in the dock, so it may not be present if the laptop was undocked).
-This is due to the current lack of support for hot plugging of devices
-in the Linux ACPI framework. If the laptop was booted without the
-UltraBay, the following message is shown in the logs:
-
- Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present
-
-In this case, no bay-related events are generated but the eject
-command described below still works. It can be executed manually or
-triggered by a hot key combination.
-
-Sliding the eject lever generates the first event shown above. The
-handler for this event should take whatever actions are necessary to
-shut down the device in the UltraBay (e.g. call idectl), then issue
-the following command:
-
- echo eject > /proc/acpi/ibm/bay
-
-After the LED on the UltraBay goes off, it is safe to pull out the
-device.
-
-When the eject lever is inserted, the second event above is
-generated. The handler for this event should take whatever actions are
-necessary to enable the UltraBay device (e.g. call idectl).
-
-The contents of the /proc/acpi/ibm/bay file shows the current status
-of the UltraBay, as provided by the ACPI framework.
-
-EXPERIMENTAL warm eject support on the 600e/x, A22p and A3x (To use
-this feature, you need to supply the experimental=1 parameter when
-loading the module):
-
-These models do not have a button near the UltraBay device to request
-a hot eject but rather require the laptop to be put to sleep
-(suspend-to-ram) before the bay device is ejected or inserted).
-The sequence of steps to eject the device is as follows:
-
- echo eject > /proc/acpi/ibm/bay
- put the ThinkPad to sleep
- remove the drive
- resume from sleep
- cat /proc/acpi/ibm/bay should show that the drive was removed
-
-On the A3x, both the UltraBay 2000 and UltraBay Plus devices are
-supported. Use "eject2" instead of "eject" for the second bay.
-
-Note: the UltraBay eject support on the 600e/x, A22p and A3x is
-EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
-
-
CMOS/UCMS control
-----------------
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 9ebcd6ef361b..950cde6d6e58 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -1,7 +1,9 @@
-/*P:100 This is the Launcher code, a simple program which lays out the
- * "physical" memory for the new Guest by mapping the kernel image and
- * the virtual devices, then opens /dev/lguest to tell the kernel
- * about the Guest and control it. :*/
+/*P:100
+ * This is the Launcher code, a simple program which lays out the "physical"
+ * memory for the new Guest by mapping the kernel image and the virtual
+ * devices, then opens /dev/lguest to tell the kernel about the Guest and
+ * control it.
+:*/
#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
@@ -46,13 +48,15 @@
#include "linux/virtio_rng.h"
#include "linux/virtio_ring.h"
#include "asm/bootparam.h"
-/*L:110 We can ignore the 39 include files we need for this program, but I do
- * want to draw attention to the use of kernel-style types.
+/*L:110
+ * We can ignore the 42 include files we need for this program, but I do want
+ * to draw attention to the use of kernel-style types.
*
* As Linus said, "C is a Spartan language, and so should your naming be." I
* like these abbreviations, so we define them here. Note that u64 is always
* unsigned long long, which works on all Linux systems: this means that we can
- * use %llu in printf for any u64. */
+ * use %llu in printf for any u64.
+ */
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint16_t u16;
@@ -69,8 +73,10 @@ typedef uint8_t u8;
/* This will occupy 3 pages: it must be a power of 2. */
#define VIRTQUEUE_NUM 256
-/*L:120 verbose is both a global flag and a macro. The C preprocessor allows
- * this, and although I wouldn't recommend it, it works quite nicely here. */
+/*L:120
+ * verbose is both a global flag and a macro. The C preprocessor allows
+ * this, and although I wouldn't recommend it, it works quite nicely here.
+ */
static bool verbose;
#define verbose(args...) \
do { if (verbose) printf(args); } while(0)
@@ -87,8 +93,7 @@ static int lguest_fd;
static unsigned int __thread cpu_id;
/* This is our list of devices. */
-struct device_list
-{
+struct device_list {
/* Counter to assign interrupt numbers. */
unsigned int next_irq;
@@ -100,8 +105,7 @@ struct device_list
/* A single linked list of devices. */
struct device *dev;
- /* And a pointer to the last device for easy append and also for
- * configuration appending. */
+ /* And a pointer to the last device for easy append. */
struct device *lastdev;
};
@@ -109,8 +113,7 @@ struct device_list
static struct device_list devices;
/* The device structure describes a single device. */
-struct device
-{
+struct device {
/* The linked-list pointer. */
struct device *next;
@@ -135,8 +138,7 @@ struct device
};
/* The virtqueue structure describes a queue attached to a device. */
-struct virtqueue
-{
+struct virtqueue {
struct virtqueue *next;
/* Which device owns me. */
@@ -168,20 +170,24 @@ static char **main_args;
/* The original tty settings to restore on exit. */
static struct termios orig_term;
-/* We have to be careful with barriers: our devices are all run in separate
+/*
+ * We have to be careful with barriers: our devices are all run in separate
* threads and so we need to make sure that changes visible to the Guest happen
- * in precise order. */
+ * in precise order.
+ */
#define wmb() __asm__ __volatile__("" : : : "memory")
#define mb() __asm__ __volatile__("" : : : "memory")
-/* Convert an iovec element to the given type.
+/*
+ * Convert an iovec element to the given type.
*
* This is a fairly ugly trick: we need to know the size of the type and
* alignment requirement to check the pointer is kosher. It's also nice to
* have the name of the type in case we report failure.
*
* Typing those three things all the time is cumbersome and error prone, so we
- * have a macro which sets them all up and passes to the real function. */
+ * have a macro which sets them all up and passes to the real function.
+ */
#define convert(iov, type) \
((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
@@ -198,8 +204,10 @@ static void *_convert(struct iovec *iov, size_t size, size_t align,
/* Wrapper for the last available index. Makes it easier to change. */
#define lg_last_avail(vq) ((vq)->last_avail_idx)
-/* The virtio configuration space is defined to be little-endian. x86 is
- * little-endian too, but it's nice to be explicit so we have these helpers. */
+/*
+ * The virtio configuration space is defined to be little-endian. x86 is
+ * little-endian too, but it's nice to be explicit so we have these helpers.
+ */
#define cpu_to_le16(v16) (v16)
#define cpu_to_le32(v32) (v32)
#define cpu_to_le64(v64) (v64)
@@ -241,11 +249,12 @@ static u8 *get_feature_bits(struct device *dev)
+ dev->num_vq * sizeof(struct lguest_vqconfig);
}
-/*L:100 The Launcher code itself takes us out into userspace, that scary place
- * where pointers run wild and free! Unfortunately, like most userspace
- * programs, it's quite boring (which is why everyone likes to hack on the
- * kernel!). Perhaps if you make up an Lguest Drinking Game at this point, it
- * will get you through this section. Or, maybe not.
+/*L:100
+ * The Launcher code itself takes us out into userspace, that scary place where
+ * pointers run wild and free! Unfortunately, like most userspace programs,
+ * it's quite boring (which is why everyone likes to hack on the kernel!).
+ * Perhaps if you make up an Lguest Drinking Game at this point, it will get
+ * you through this section. Or, maybe not.
*
* The Launcher sets up a big chunk of memory to be the Guest's "physical"
* memory and stores it in "guest_base". In other words, Guest physical ==
@@ -253,7 +262,8 @@ static u8 *get_feature_bits(struct device *dev)
*
* This can be tough to get your head around, but usually it just means that we
* use these trivial conversion functions when the Guest gives us it's
- * "physical" addresses: */
+ * "physical" addresses:
+ */
static void *from_guest_phys(unsigned long addr)
{
return guest_base + addr;
@@ -268,7 +278,8 @@ static unsigned long to_guest_phys(const void *addr)
* Loading the Kernel.
*
* We start with couple of simple helper routines. open_or_die() avoids
- * error-checking code cluttering the callers: */
+ * error-checking code cluttering the callers:
+ */
static int open_or_die(const char *name, int flags)
{
int fd = open(name, flags);
@@ -283,12 +294,19 @@ static void *map_zeroed_pages(unsigned int num)
int fd = open_or_die("/dev/zero", O_RDONLY);
void *addr;
- /* We use a private mapping (ie. if we write to the page, it will be
- * copied). */
+ /*
+ * We use a private mapping (ie. if we write to the page, it will be
+ * copied).
+ */
addr = mmap(NULL, getpagesize() * num,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED)
err(1, "Mmaping %u pages of /dev/zero", num);
+
+ /*
+ * One neat mmap feature is that you can close the fd, and it
+ * stays mapped.
+ */
close(fd);
return addr;
@@ -305,20 +323,24 @@ static void *get_pages(unsigned int num)
return addr;
}
-/* This routine is used to load the kernel or initrd. It tries mmap, but if
+/*
+ * This routine is used to load the kernel or initrd. It tries mmap, but if
* that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
- * it falls back to reading the memory in. */
+ * it falls back to reading the memory in.
+ */
static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
{
ssize_t r;
- /* We map writable even though for some segments are marked read-only.
+ /*
+ * We map writable even though for some segments are marked read-only.
* The kernel really wants to be writable: it patches its own
* instructions.
*
* MAP_PRIVATE means that the page won't be copied until a write is
* done to it. This allows us to share untouched memory between
- * Guests. */
+ * Guests.
+ */
if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
return;
@@ -329,7 +351,8 @@ static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
}
-/* This routine takes an open vmlinux image, which is in ELF, and maps it into
+/*
+ * This routine takes an open vmlinux image, which is in ELF, and maps it into
* the Guest memory. ELF = Embedded Linking Format, which is the format used
* by all modern binaries on Linux including the kernel.
*
@@ -337,23 +360,28 @@ static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
* address. We use the physical address; the Guest will map itself to the
* virtual address.
*
- * We return the starting address. */
+ * We return the starting address.
+ */
static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
{
Elf32_Phdr phdr[ehdr->e_phnum];
unsigned int i;
- /* Sanity checks on the main ELF header: an x86 executable with a
- * reasonable number of correctly-sized program headers. */
+ /*
+ * Sanity checks on the main ELF header: an x86 executable with a
+ * reasonable number of correctly-sized program headers.
+ */
if (ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_386
|| ehdr->e_phentsize != sizeof(Elf32_Phdr)
|| ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
errx(1, "Malformed elf header");
- /* An ELF executable contains an ELF header and a number of "program"
+ /*
+ * An ELF executable contains an ELF header and a number of "program"
* headers which indicate which parts ("segments") of the program to
- * load where. */
+ * load where.
+ */
/* We read in all the program headers at once: */
if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
@@ -361,8 +389,10 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
err(1, "Reading program headers");
- /* Try all the headers: there are usually only three. A read-only one,
- * a read-write one, and a "note" section which we don't load. */
+ /*
+ * Try all the headers: there are usually only three. A read-only one,
+ * a read-write one, and a "note" section which we don't load.
+ */
for (i = 0; i < ehdr->e_phnum; i++) {
/* If this isn't a loadable segment, we ignore it */
if (phdr[i].p_type != PT_LOAD)
@@ -380,13 +410,15 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
return ehdr->e_entry;
}
-/*L:150 A bzImage, unlike an ELF file, is not meant to be loaded. You're
- * supposed to jump into it and it will unpack itself. We used to have to
- * perform some hairy magic because the unpacking code scared me.
+/*L:150
+ * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed
+ * to jump into it and it will unpack itself. We used to have to perform some
+ * hairy magic because the unpacking code scared me.
*
* Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
* a small patch to jump over the tricky bits in the Guest, so now we just read
- * the funky header so we know where in the file to load, and away we go! */
+ * the funky header so we know where in the file to load, and away we go!
+ */
static unsigned long load_bzimage(int fd)
{
struct boot_params boot;
@@ -394,8 +426,10 @@ static unsigned long load_bzimage(int fd)
/* Modern bzImages get loaded at 1M. */
void *p = from_guest_phys(0x100000);
- /* Go back to the start of the file and read the header. It should be
- * a Linux boot header (see Documentation/x86/i386/boot.txt) */
+ /*
+ * Go back to the start of the file and read the header. It should be
+ * a Linux boot header (see Documentation/x86/i386/boot.txt)
+ */
lseek(fd, 0, SEEK_SET);
read(fd, &boot, sizeof(boot));
@@ -414,9 +448,11 @@ static unsigned long load_bzimage(int fd)
return boot.hdr.code32_start;
}
-/*L:140 Loading the kernel is easy when it's a "vmlinux", but most kernels
+/*L:140
+ * Loading the kernel is easy when it's a "vmlinux", but most kernels
* come wrapped up in the self-decompressing "bzImage" format. With a little
- * work, we can load those, too. */
+ * work, we can load those, too.
+ */
static unsigned long load_kernel(int fd)
{
Elf32_Ehdr hdr;
@@ -433,24 +469,28 @@ static unsigned long load_kernel(int fd)
return load_bzimage(fd);
}
-/* This is a trivial little helper to align pages. Andi Kleen hated it because
+/*
+ * This is a trivial little helper to align pages. Andi Kleen hated it because
* it calls getpagesize() twice: "it's dumb code."
*
* Kernel guys get really het up about optimization, even when it's not
- * necessary. I leave this code as a reaction against that. */
+ * necessary. I leave this code as a reaction against that.
+ */
static inline unsigned long page_align(unsigned long addr)
{
/* Add upwards and truncate downwards. */
return ((addr + getpagesize()-1) & ~(getpagesize()-1));
}
-/*L:180 An "initial ram disk" is a disk image loaded into memory along with
- * the kernel which the kernel can use to boot from without needing any
- * drivers. Most distributions now use this as standard: the initrd contains
- * the code to load the appropriate driver modules for the current machine.
+/*L:180
+ * An "initial ram disk" is a disk image loaded into memory along with the
+ * kernel which the kernel can use to boot from without needing any drivers.
+ * Most distributions now use this as standard: the initrd contains the code to
+ * load the appropriate driver modules for the current machine.
*
* Importantly, James Morris works for RedHat, and Fedora uses initrds for its
- * kernels. He sent me this (and tells me when I break it). */
+ * kernels. He sent me this (and tells me when I break it).
+ */
static unsigned long load_initrd(const char *name, unsigned long mem)
{
int ifd;
@@ -462,12 +502,16 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
if (fstat(ifd, &st) < 0)
err(1, "fstat() on initrd '%s'", name);
- /* We map the initrd at the top of memory, but mmap wants it to be
- * page-aligned, so we round the size up for that. */
+ /*
+ * We map the initrd at the top of memory, but mmap wants it to be
+ * page-aligned, so we round the size up for that.
+ */
len = page_align(st.st_size);
map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
- /* Once a file is mapped, you can close the file descriptor. It's a
- * little odd, but quite useful. */
+ /*
+ * Once a file is mapped, you can close the file descriptor. It's a
+ * little odd, but quite useful.
+ */
close(ifd);
verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len);
@@ -476,8 +520,10 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
}
/*:*/
-/* Simple routine to roll all the commandline arguments together with spaces
- * between them. */
+/*
+ * Simple routine to roll all the commandline arguments together with spaces
+ * between them.
+ */
static void concat(char *dst, char *args[])
{
unsigned int i, len = 0;
@@ -494,10 +540,12 @@ static void concat(char *dst, char *args[])
dst[len] = '\0';
}
-/*L:185 This is where we actually tell the kernel to initialize the Guest. We
+/*L:185
+ * This is where we actually tell the kernel to initialize the Guest. We
* saw the arguments it expects when we looked at initialize() in lguest_user.c:
* the base of Guest "physical" memory, the top physical page to allow and the
- * entry point for the Guest. */
+ * entry point for the Guest.
+ */
static void tell_kernel(unsigned long start)
{
unsigned long args[] = { LHREQ_INITIALIZE,
@@ -511,7 +559,7 @@ static void tell_kernel(unsigned long start)
}
/*:*/
-/*
+/*L:200
* Device Handling.
*
* When the Guest gives us a buffer, it sends an array of addresses and sizes.
@@ -522,20 +570,26 @@ static void tell_kernel(unsigned long start)
static void *_check_pointer(unsigned long addr, unsigned int size,
unsigned int line)
{
- /* We have to separately check addr and addr+size, because size could
- * be huge and addr + size might wrap around. */
+ /*
+ * We have to separately check addr and addr+size, because size could
+ * be huge and addr + size might wrap around.
+ */
if (addr >= guest_limit || addr + size >= guest_limit)
errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
- /* We return a pointer for the caller's convenience, now we know it's
- * safe to use. */
+ /*
+ * We return a pointer for the caller's convenience, now we know it's
+ * safe to use.
+ */
return from_guest_phys(addr);
}
/* A macro which transparently hands the line number to the real function. */
#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
-/* Each buffer in the virtqueues is actually a chain of descriptors. This
+/*
+ * Each buffer in the virtqueues is actually a chain of descriptors. This
* function returns the next descriptor in the chain, or vq->vring.num if we're
- * at the end. */
+ * at the end.
+ */
static unsigned next_desc(struct vring_desc *desc,
unsigned int i, unsigned int max)
{
@@ -556,7 +610,10 @@ static unsigned next_desc(struct vring_desc *desc,
return next;
}
-/* This actually sends the interrupt for this virtqueue */
+/*
+ * This actually sends the interrupt for this virtqueue, if we've used a
+ * buffer.
+ */
static void trigger_irq(struct virtqueue *vq)
{
unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
@@ -576,12 +633,14 @@ static void trigger_irq(struct virtqueue *vq)
err(1, "Triggering irq %i", vq->config.irq);
}
-/* This looks in the virtqueue and for the first available buffer, and converts
+/*
+ * This looks in the virtqueue for the first available buffer, and converts
* it to an iovec for convenient access. Since descriptors consist of some
* number of output then some number of input descriptors, it's actually two
* iovecs, but we pack them into one and note how many of each there were.
*
- * This function returns the descriptor number found. */
+ * This function waits if necessary, and returns the descriptor number found.
+ */
static unsigned wait_for_vq_desc(struct virtqueue *vq,
struct iovec iov[],
unsigned int *out_num, unsigned int *in_num)
@@ -590,17 +649,23 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
struct vring_desc *desc;
u16 last_avail = lg_last_avail(vq);
+ /* There's nothing available? */
while (last_avail == vq->vring.avail->idx) {
u64 event;
- /* OK, tell Guest about progress up to now. */
+ /*
+ * Since we're about to sleep, now is a good time to tell the
+ * Guest about what we've used up to now.
+ */
trigger_irq(vq);
/* OK, now we need to know about added descriptors. */
vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
- /* They could have slipped one in as we were doing that: make
- * sure it's written, then check again. */
+ /*
+ * They could have slipped one in as we were doing that: make
+ * sure it's written, then check again.
+ */
mb();
if (last_avail != vq->vring.avail->idx) {
vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
@@ -620,8 +685,10 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
errx(1, "Guest moved used index from %u to %u",
last_avail, vq->vring.avail->idx);
- /* Grab the next descriptor number they're advertising, and increment
- * the index we've seen. */
+ /*
+ * Grab the next descriptor number they're advertising, and increment
+ * the index we've seen.
+ */
head = vq->vring.avail->ring[last_avail % vq->vring.num];
lg_last_avail(vq)++;
@@ -636,8 +703,10 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
desc = vq->vring.desc;
i = head;
- /* If this is an indirect entry, then this buffer contains a descriptor
- * table which we handle as if it's any normal descriptor chain. */
+ /*
+ * If this is an indirect entry, then this buffer contains a descriptor
+ * table which we handle as if it's any normal descriptor chain.
+ */
if (desc[i].flags & VRING_DESC_F_INDIRECT) {
if (desc[i].len % sizeof(struct vring_desc))
errx(1, "Invalid size for indirect buffer table");
@@ -656,8 +725,10 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
if (desc[i].flags & VRING_DESC_F_WRITE)
(*in_num)++;
else {
- /* If it's an output descriptor, they're all supposed
- * to come before any input descriptors. */
+ /*
+ * If it's an output descriptor, they're all supposed
+ * to come before any input descriptors.
+ */
if (*in_num)
errx(1, "Descriptor has out after in");
(*out_num)++;
@@ -671,14 +742,19 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
return head;
}
-/* After we've used one of their buffers, we tell them about it. We'll then
- * want to send them an interrupt, using trigger_irq(). */
+/*
+ * After we've used one of their buffers, we tell the Guest about it. Sometime
+ * later we'll want to send them an interrupt using trigger_irq(); note that
+ * wait_for_vq_desc() does that for us if it has to wait.
+ */
static void add_used(struct virtqueue *vq, unsigned int head, int len)
{
struct vring_used_elem *used;
- /* The virtqueue contains a ring of used buffers. Get a pointer to the
- * next entry in that used ring. */
+ /*
+ * The virtqueue contains a ring of used buffers. Get a pointer to the
+ * next entry in that used ring.
+ */
used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
used->id = head;
used->len = len;
@@ -698,9 +774,9 @@ static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
/*
* The Console
*
- * We associate some data with the console for our exit hack. */
-struct console_abort
-{
+ * We associate some data with the console for our exit hack.
+ */
+struct console_abort {
/* How many times have they hit ^C? */
int count;
/* When did they start? */
@@ -715,30 +791,35 @@ static void console_input(struct virtqueue *vq)
struct console_abort *abort = vq->dev->priv;
struct iovec iov[vq->vring.num];
- /* Make sure there's a descriptor waiting. */
+ /* Make sure there's a descriptor available. */
head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
if (out_num)
errx(1, "Output buffers in console in queue?");
- /* Read it in. */
+ /* Read into it. This is where we usually wait. */
len = readv(STDIN_FILENO, iov, in_num);
if (len <= 0) {
/* Ran out of input? */
warnx("Failed to get console input, ignoring console.");
- /* For simplicity, dying threads kill the whole Launcher. So
- * just nap here. */
+ /*
+ * For simplicity, dying threads kill the whole Launcher. So
+ * just nap here.
+ */
for (;;)
pause();
}
+ /* Tell the Guest we used a buffer. */
add_used_and_trigger(vq, head, len);
- /* Three ^C within one second? Exit.
+ /*
+ * Three ^C within one second? Exit.
*
* This is such a hack, but works surprisingly well. Each ^C has to
* be in a buffer by itself, so they can't be too fast. But we check
* that we get three within about a second, so they can't be too
- * slow. */
+ * slow.
+ */
if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
abort->count = 0;
return;
@@ -763,15 +844,23 @@ static void console_output(struct virtqueue *vq)
unsigned int head, out, in;
struct iovec iov[vq->vring.num];
+ /* We usually wait in here, for the Guest to give us something. */
head = wait_for_vq_desc(vq, iov, &out, &in);
if (in)
errx(1, "Input buffers in console output queue?");
+
+ /* writev can return a partial write, so we loop here. */
while (!iov_empty(iov, out)) {
int len = writev(STDOUT_FILENO, iov, out);
if (len <= 0)
err(1, "Write to stdout gave %i", len);
iov_consume(iov, out, len);
}
+
+ /*
+ * We're finished with that buffer: if we're going to sleep,
+ * wait_for_vq_desc() will prod the Guest with an interrupt.
+ */
add_used(vq, head, 0);
}
@@ -791,15 +880,30 @@ static void net_output(struct virtqueue *vq)
unsigned int head, out, in;
struct iovec iov[vq->vring.num];
+ /* We usually wait in here for the Guest to give us a packet. */
head = wait_for_vq_desc(vq, iov, &out, &in);
if (in)
errx(1, "Input buffers in net output queue?");
+ /*
+ * Send the whole thing through to /dev/net/tun. It expects the exact
+ * same format: what a coincidence!
+ */
if (writev(net_info->tunfd, iov, out) < 0)
errx(1, "Write to tun failed?");
+
+ /*
+ * Done with that one; wait_for_vq_desc() will send the interrupt if
+ * all packets are processed.
+ */
add_used(vq, head, 0);
}
-/* Will reading from this file descriptor block? */
+/*
+ * Handling network input is a bit trickier, because I've tried to optimize it.
+ *
+ * First we have a helper routine which tells is if from this file descriptor
+ * (ie. the /dev/net/tun device) will block:
+ */
static bool will_block(int fd)
{
fd_set fdset;
@@ -809,8 +913,11 @@ static bool will_block(int fd)
return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
}
-/* This is where we handle packets coming in from the tun device to our
- * Guest. */
+/*
+ * This handles packets coming in from the tun device to our Guest. Like all
+ * service routines, it gets called again as soon as it returns, so you don't
+ * see a while(1) loop here.
+ */
static void net_input(struct virtqueue *vq)
{
int len;
@@ -818,21 +925,38 @@ static void net_input(struct virtqueue *vq)
struct iovec iov[vq->vring.num];
struct net_info *net_info = vq->dev->priv;
+ /*
+ * Get a descriptor to write an incoming packet into. This will also
+ * send an interrupt if they're out of descriptors.
+ */
head = wait_for_vq_desc(vq, iov, &out, &in);
if (out)
errx(1, "Output buffers in net input queue?");
- /* Deliver interrupt now, since we're about to sleep. */
+ /*
+ * If it looks like we'll block reading from the tun device, send them
+ * an interrupt.
+ */
if (vq->pending_used && will_block(net_info->tunfd))
trigger_irq(vq);
+ /*
+ * Read in the packet. This is where we normally wait (when there's no
+ * incoming network traffic).
+ */
len = readv(net_info->tunfd, iov, in);
if (len <= 0)
err(1, "Failed to read from tun.");
+
+ /*
+ * Mark that packet buffer as used, but don't interrupt here. We want
+ * to wait until we've done as much work as we can.
+ */
add_used(vq, head, len);
}
+/*:*/
-/* This is the helper to create threads. */
+/* This is the helper to create threads: run the service routine in a loop. */
static int do_thread(void *_vq)
{
struct virtqueue *vq = _vq;
@@ -842,8 +966,10 @@ static int do_thread(void *_vq)
return 0;
}
-/* When a child dies, we kill our entire process group with SIGTERM. This
- * also has the side effect that the shell restores the console for us! */
+/*
+ * When a child dies, we kill our entire process group with SIGTERM. This
+ * also has the side effect that the shell restores the console for us!
+ */
static void kill_launcher(int signal)
{
kill(0, SIGTERM);
@@ -878,11 +1004,15 @@ static void reset_device(struct device *dev)
signal(SIGCHLD, (void *)kill_launcher);
}
+/*L:216
+ * This actually creates the thread which services the virtqueue for a device.
+ */
static void create_thread(struct virtqueue *vq)
{
- /* Create stack for thread and run it. Since stack grows
- * upwards, we point the stack pointer to the end of this
- * region. */
+ /*
+ * Create stack for thread. Since the stack grows upwards, we point
+ * the stack pointer to the end of this region.
+ */
char *stack = malloc(32768);
unsigned long args[] = { LHREQ_EVENTFD,
vq->config.pfn*getpagesize(), 0 };
@@ -893,17 +1023,22 @@ static void create_thread(struct virtqueue *vq)
err(1, "Creating eventfd");
args[2] = vq->eventfd;
- /* Attach an eventfd to this virtqueue: it will go off
- * when the Guest does an LHCALL_NOTIFY for this vq. */
+ /*
+ * Attach an eventfd to this virtqueue: it will go off when the Guest
+ * does an LHCALL_NOTIFY for this vq.
+ */
if (write(lguest_fd, &args, sizeof(args)) != 0)
err(1, "Attaching eventfd");
- /* CLONE_VM: because it has to access the Guest memory, and
- * SIGCHLD so we get a signal if it dies. */
+ /*
+ * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so
+ * we get a signal if it dies.
+ */
vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
if (vq->thread == (pid_t)-1)
err(1, "Creating clone");
- /* We close our local copy, now the child has it. */
+
+ /* We close our local copy now the child has it. */
close(vq->eventfd);
}
@@ -955,7 +1090,10 @@ static void update_device_status(struct device *dev)
}
}
-/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
+/*L:215
+ * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In
+ * particular, it's used to notify us of device status changes during boot.
+ */
static void handle_output(unsigned long addr)
{
struct device *i;
@@ -964,25 +1102,42 @@ static void handle_output(unsigned long addr)
for (i = devices.dev; i; i = i->next) {
struct virtqueue *vq;
- /* Notifications to device descriptors update device status. */
+ /*
+ * Notifications to device descriptors mean they updated the
+ * device status.
+ */
if (from_guest_phys(addr) == i->desc) {
update_device_status(i);
return;
}
- /* Devices *can* be used before status is set to DRIVER_OK. */
+ /*
+ * Devices *can* be used before status is set to DRIVER_OK.
+ * The original plan was that they would never do this: they
+ * would always finish setting up their status bits before
+ * actually touching the virtqueues. In practice, we allowed
+ * them to, and they do (eg. the disk probes for partition
+ * tables as part of initialization).
+ *
+ * If we see this, we start the device: once it's running, we
+ * expect the device to catch all the notifications.
+ */
for (vq = i->vq; vq; vq = vq->next) {
if (addr != vq->config.pfn*getpagesize())
continue;
if (i->running)
errx(1, "Notification on running %s", i->name);
+ /* This just calls create_thread() for each virtqueue */
start_device(i);
return;
}
}
- /* Early console write is done using notify on a nul-terminated string
- * in Guest memory. */
+ /*
+ * Early console write is done using notify on a nul-terminated string
+ * in Guest memory. It's also great for hacking debugging messages
+ * into a Guest.
+ */
if (addr >= guest_limit)
errx(1, "Bad NOTIFY %#lx", addr);
@@ -998,10 +1153,12 @@ static void handle_output(unsigned long addr)
* routines to allocate and manage them.
*/
-/* The layout of the device page is a "struct lguest_device_desc" followed by a
+/*
+ * The layout of the device page is a "struct lguest_device_desc" followed by a
* number of virtqueue descriptors, then two sets of feature bits, then an
* array of configuration bytes. This routine returns the configuration
- * pointer. */
+ * pointer.
+ */
static u8 *device_config(const struct device *dev)
{
return (void *)(dev->desc + 1)
@@ -1009,9 +1166,11 @@ static u8 *device_config(const struct device *dev)
+ dev->feature_len * 2;
}
-/* This routine allocates a new "struct lguest_device_desc" from descriptor
+/*
+ * This routine allocates a new "struct lguest_device_desc" from descriptor
* table page just above the Guest's normal memory. It returns a pointer to
- * that descriptor. */
+ * that descriptor.
+ */
static struct lguest_device_desc *new_dev_desc(u16 type)
{
struct lguest_device_desc d = { .type = type };
@@ -1032,8 +1191,10 @@ static struct lguest_device_desc *new_dev_desc(u16 type)
return memcpy(p, &d, sizeof(d));
}
-/* Each device descriptor is followed by the description of its virtqueues. We
- * specify how many descriptors the virtqueue is to have. */
+/*
+ * Each device descriptor is followed by the description of its virtqueues. We
+ * specify how many descriptors the virtqueue is to have.
+ */
static void add_virtqueue(struct device *dev, unsigned int num_descs,
void (*service)(struct virtqueue *))
{
@@ -1050,6 +1211,11 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
vq->next = NULL;
vq->last_avail_idx = 0;
vq->dev = dev;
+
+ /*
+ * This is the routine the service thread will run, and its Process ID
+ * once it's running.
+ */
vq->service = service;
vq->thread = (pid_t)-1;
@@ -1061,10 +1227,12 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
/* Initialize the vring. */
vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);
- /* Append virtqueue to this device's descriptor. We use
+ /*
+ * Append virtqueue to this device's descriptor. We use
* device_config() to get the end of the device's current virtqueues;
* we check that we haven't added any config or feature information
- * yet, otherwise we'd be overwriting them. */
+ * yet, otherwise we'd be overwriting them.
+ */
assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
memcpy(device_config(dev), &vq->config, sizeof(vq->config));
dev->num_vq++;
@@ -1072,14 +1240,18 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
verbose("Virtqueue page %#lx\n", to_guest_phys(p));
- /* Add to tail of list, so dev->vq is first vq, dev->vq->next is
- * second. */
+ /*
+ * Add to tail of list, so dev->vq is first vq, dev->vq->next is
+ * second.
+ */
for (i = &dev->vq; *i; i = &(*i)->next);
*i = vq;
}
-/* The first half of the feature bitmask is for us to advertise features. The
- * second half is for the Guest to accept features. */
+/*
+ * The first half of the feature bitmask is for us to advertise features. The
+ * second half is for the Guest to accept features.
+ */
static void add_feature(struct device *dev, unsigned bit)
{
u8 *features = get_feature_bits(dev);
@@ -1093,9 +1265,11 @@ static void add_feature(struct device *dev, unsigned bit)
features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
}
-/* This routine sets the configuration fields for an existing device's
+/*
+ * This routine sets the configuration fields for an existing device's
* descriptor. It only works for the last device, but that's OK because that's
- * how we use it. */
+ * how we use it.
+ */
static void set_config(struct device *dev, unsigned len, const void *conf)
{
/* Check we haven't overflowed our single page. */
@@ -1105,12 +1279,18 @@ static void set_config(struct device *dev, unsigned len, const void *conf)
/* Copy in the config information, and store the length. */
memcpy(device_config(dev), conf, len);
dev->desc->config_len = len;
+
+ /* Size must fit in config_len field (8 bits)! */
+ assert(dev->desc->config_len == len);
}
-/* This routine does all the creation and setup of a new device, including
- * calling new_dev_desc() to allocate the descriptor and device memory.
+/*
+ * This routine does all the creation and setup of a new device, including
+ * calling new_dev_desc() to allocate the descriptor and device memory. We
+ * don't actually start the service threads until later.
*
- * See what I mean about userspace being boring? */
+ * See what I mean about userspace being boring?
+ */
static struct device *new_device(const char *name, u16 type)
{
struct device *dev = malloc(sizeof(*dev));
@@ -1123,10 +1303,12 @@ static struct device *new_device(const char *name, u16 type)
dev->num_vq = 0;
dev->running = false;
- /* Append to device list. Prepending to a single-linked list is
+ /*
+ * Append to device list. Prepending to a single-linked list is
* easier, but the user expects the devices to be arranged on the bus
* in command-line order. The first network device on the command line
- * is eth0, the first block device /dev/vda, etc. */
+ * is eth0, the first block device /dev/vda, etc.
+ */
if (devices.lastdev)
devices.lastdev->next = dev;
else
@@ -1136,8 +1318,10 @@ static struct device *new_device(const char *name, u16 type)
return dev;
}
-/* Our first setup routine is the console. It's a fairly simple device, but
- * UNIX tty handling makes it uglier than it could be. */
+/*
+ * Our first setup routine is the console. It's a fairly simple device, but
+ * UNIX tty handling makes it uglier than it could be.
+ */
static void setup_console(void)
{
struct device *dev;
@@ -1145,8 +1329,10 @@ static void setup_console(void)
/* If we can save the initial standard input settings... */
if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
struct termios term = orig_term;
- /* Then we turn off echo, line buffering and ^C etc. We want a
- * raw input stream to the Guest. */
+ /*
+ * Then we turn off echo, line buffering and ^C etc: We want a
+ * raw input stream to the Guest.
+ */
term.c_lflag &= ~(ISIG|ICANON|ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
@@ -1157,10 +1343,12 @@ static void setup_console(void)
dev->priv = malloc(sizeof(struct console_abort));
((struct console_abort *)dev->priv)->count = 0;
- /* The console needs two virtqueues: the input then the output. When
+ /*
+ * The console needs two virtqueues: the input then the output. When
* they put something the input queue, we make sure we're listening to
* stdin. When they put something in the output queue, we write it to
- * stdout. */
+ * stdout.
+ */
add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
@@ -1168,7 +1356,8 @@ static void setup_console(void)
}
/*:*/
-/*M:010 Inter-guest networking is an interesting area. Simplest is to have a
+/*M:010
+ * Inter-guest networking is an interesting area. Simplest is to have a
* --sharenet=<name> option which opens or creates a named pipe. This can be
* used to send packets to another guest in a 1:1 manner.
*
@@ -1182,7 +1371,8 @@ static void setup_console(void)
* multiple inter-guest channels behind one interface, although it would
* require some manner of hotplugging new virtio channels.
*
- * Finally, we could implement a virtio network switch in the kernel. :*/
+ * Finally, we could implement a virtio network switch in the kernel.
+:*/
static u32 str2ip(const char *ipaddr)
{
@@ -1207,11 +1397,13 @@ static void str2mac(const char *macaddr, unsigned char mac[6])
mac[5] = m[5];
}
-/* This code is "adapted" from libbridge: it attaches the Host end of the
+/*
+ * This code is "adapted" from libbridge: it attaches the Host end of the
* network device to the bridge device specified by the command line.
*
* This is yet another James Morris contribution (I'm an IP-level guy, so I
- * dislike bridging), and I just try not to break it. */
+ * dislike bridging), and I just try not to break it.
+ */
static void add_to_bridge(int fd, const char *if_name, const char *br_name)
{
int ifidx;
@@ -1231,9 +1423,11 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name)
err(1, "can't add %s to bridge %s", if_name, br_name);
}
-/* This sets up the Host end of the network device with an IP address, brings
+/*
+ * This sets up the Host end of the network device with an IP address, brings
* it up so packets will flow, the copies the MAC address into the hwaddr
- * pointer. */
+ * pointer.
+ */
static void configure_device(int fd, const char *tapif, u32 ipaddr)
{
struct ifreq ifr;
@@ -1260,10 +1454,12 @@ static int get_tun_device(char tapif[IFNAMSIZ])
/* Start with this zeroed. Messy but sure. */
memset(&ifr, 0, sizeof(ifr));
- /* We open the /dev/net/tun device and tell it we want a tap device. A
+ /*
+ * We open the /dev/net/tun device and tell it we want a tap device. A
* tap device is like a tun device, only somehow different. To tell
* the truth, I completely blundered my way through this code, but it
- * works now! */
+ * works now!
+ */
netfd = open_or_die("/dev/net/tun", O_RDWR);
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
strcpy(ifr.ifr_name, "tap%d");
@@ -1274,18 +1470,22 @@ static int get_tun_device(char tapif[IFNAMSIZ])
TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0)
err(1, "Could not set features for tun device");
- /* We don't need checksums calculated for packets coming in this
- * device: trust us! */
+ /*
+ * We don't need checksums calculated for packets coming in this
+ * device: trust us!
+ */
ioctl(netfd, TUNSETNOCSUM, 1);
memcpy(tapif, ifr.ifr_name, IFNAMSIZ);
return netfd;
}
-/*L:195 Our network is a Host<->Guest network. This can either use bridging or
+/*L:195
+ * Our network is a Host<->Guest network. This can either use bridging or
* routing, but the principle is the same: it uses the "tun" device to inject
* packets into the Host as if they came in from a normal network card. We
- * just shunt packets between the Guest and the tun device. */
+ * just shunt packets between the Guest and the tun device.
+ */
static void setup_tun_net(char *arg)
{
struct device *dev;
@@ -1302,13 +1502,14 @@ static void setup_tun_net(char *arg)
dev = new_device("net", VIRTIO_ID_NET);
dev->priv = net_info;
- /* Network devices need a receive and a send queue, just like
- * console. */
+ /* Network devices need a recv and a send queue, just like console. */
add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
- /* We need a socket to perform the magic network ioctls to bring up the
- * tap interface, connect to the bridge etc. Any socket will do! */
+ /*
+ * We need a socket to perform the magic network ioctls to bring up the
+ * tap interface, connect to the bridge etc. Any socket will do!
+ */
ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (ipfd < 0)
err(1, "opening IP socket");
@@ -1362,39 +1563,31 @@ static void setup_tun_net(char *arg)
verbose("device %u: tun %s: %s\n",
devices.device_num, tapif, arg);
}
-
-/* Our block (disk) device should be really simple: the Guest asks for a block
- * number and we read or write that position in the file. Unfortunately, that
- * was amazingly slow: the Guest waits until the read is finished before
- * running anything else, even if it could have been doing useful work.
- *
- * We could use async I/O, except it's reputed to suck so hard that characters
- * actually go missing from your code when you try to use it.
- *
- * So we farm the I/O out to thread, and communicate with it via a pipe. */
+/*:*/
/* This hangs off device->priv. */
-struct vblk_info
-{
+struct vblk_info {
/* The size of the file. */
off64_t len;
/* The file descriptor for the file. */
int fd;
- /* IO thread listens on this file descriptor [0]. */
- int workpipe[2];
-
- /* IO thread writes to this file descriptor to mark it done, then
- * Launcher triggers interrupt to Guest. */
- int done_fd;
};
/*L:210
* The Disk
*
- * Remember that the block device is handled by a separate I/O thread. We head
- * straight into the core of that thread here:
+ * The disk only has one virtqueue, so it only has one thread. It is really
+ * simple: the Guest asks for a block number and we read or write that position
+ * in the file.
+ *
+ * Before we serviced each virtqueue in a separate thread, that was unacceptably
+ * slow: the Guest waits until the read is finished before running anything
+ * else, even if it could have been doing useful work.
+ *
+ * We could have used async I/O, except it's reputed to suck so hard that
+ * characters actually go missing from your code when you try to use it.
*/
static void blk_request(struct virtqueue *vq)
{
@@ -1406,47 +1599,64 @@ static void blk_request(struct virtqueue *vq)
struct iovec iov[vq->vring.num];
off64_t off;
- /* Get the next request. */
+ /*
+ * Get the next request, where we normally wait. It triggers the
+ * interrupt to acknowledge previously serviced requests (if any).
+ */
head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
- /* Every block request should contain at least one output buffer
+ /*
+ * Every block request should contain at least one output buffer
* (detailing the location on disk and the type of request) and one
- * input buffer (to hold the result). */
+ * input buffer (to hold the result).
+ */
if (out_num == 0 || in_num == 0)
errx(1, "Bad virtblk cmd %u out=%u in=%u",
head, out_num, in_num);
out = convert(&iov[0], struct virtio_blk_outhdr);
in = convert(&iov[out_num+in_num-1], u8);
+ /*
+ * For historical reasons, block operations are expressed in 512 byte
+ * "sectors".
+ */
off = out->sector * 512;
- /* The block device implements "barriers", where the Guest indicates
+ /*
+ * The block device implements "barriers", where the Guest indicates
* that it wants all previous writes to occur before this write. We
* don't have a way of asking our kernel to do a barrier, so we just
- * synchronize all the data in the file. Pretty poor, no? */
+ * synchronize all the data in the file. Pretty poor, no?
+ */
if (out->type & VIRTIO_BLK_T_BARRIER)
fdatasync(vblk->fd);
- /* In general the virtio block driver is allowed to try SCSI commands.
- * It'd be nice if we supported eject, for example, but we don't. */
+ /*
+ * In general the virtio block driver is allowed to try SCSI commands.
+ * It'd be nice if we supported eject, for example, but we don't.
+ */
if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
fprintf(stderr, "Scsi commands unsupported\n");
*in = VIRTIO_BLK_S_UNSUPP;
wlen = sizeof(*in);
} else if (out->type & VIRTIO_BLK_T_OUT) {
- /* Write */
-
- /* Move to the right location in the block file. This can fail
- * if they try to write past end. */
+ /*
+ * Write
+ *
+ * Move to the right location in the block file. This can fail
+ * if they try to write past end.
+ */
if (lseek64(vblk->fd, off, SEEK_SET) != off)
err(1, "Bad seek to sector %llu", out->sector);
ret = writev(vblk->fd, iov+1, out_num-1);
verbose("WRITE to sector %llu: %i\n", out->sector, ret);
- /* Grr... Now we know how long the descriptor they sent was, we
+ /*
+ * Grr... Now we know how long the descriptor they sent was, we
* make sure they didn't try to write over the end of the block
- * file (possibly extending it). */
+ * file (possibly extending it).
+ */
if (ret > 0 && off + ret > vblk->len) {
/* Trim it back to the correct length */
ftruncate64(vblk->fd, vblk->len);
@@ -1456,10 +1666,12 @@ static void blk_request(struct virtqueue *vq)
wlen = sizeof(*in);
*in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
} else {
- /* Read */
-
- /* Move to the right location in the block file. This can fail
- * if they try to read past end. */
+ /*
+ * Read
+ *
+ * Move to the right location in the block file. This can fail
+ * if they try to read past end.
+ */
if (lseek64(vblk->fd, off, SEEK_SET) != off)
err(1, "Bad seek to sector %llu", out->sector);
@@ -1474,13 +1686,16 @@ static void blk_request(struct virtqueue *vq)
}
}
- /* OK, so we noted that it was pretty poor to use an fdatasync as a
+ /*
+ * OK, so we noted that it was pretty poor to use an fdatasync as a
* barrier. But Christoph Hellwig points out that we need a sync
* *afterwards* as well: "Barriers specify no reordering to the front
- * or the back." And Jens Axboe confirmed it, so here we are: */
+ * or the back." And Jens Axboe confirmed it, so here we are:
+ */
if (out->type & VIRTIO_BLK_T_BARRIER)
fdatasync(vblk->fd);
+ /* Finished that request. */
add_used(vq, head, wlen);
}
@@ -1491,7 +1706,7 @@ static void setup_block_file(const char *filename)
struct vblk_info *vblk;
struct virtio_blk_config conf;
- /* The device responds to return from I/O thread. */
+ /* Creat the device. */
dev = new_device("block", VIRTIO_ID_BLOCK);
/* The device has one virtqueue, where the Guest places requests. */
@@ -1510,27 +1725,32 @@ static void setup_block_file(const char *filename)
/* Tell Guest how many sectors this device has. */
conf.capacity = cpu_to_le64(vblk->len / 512);
- /* Tell Guest not to put in too many descriptors at once: two are used
- * for the in and out elements. */
+ /*
+ * Tell Guest not to put in too many descriptors at once: two are used
+ * for the in and out elements.
+ */
add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
- set_config(dev, sizeof(conf), &conf);
+ /* Don't try to put whole struct: we have 8 bit limit. */
+ set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf);
verbose("device %u: virtblock %llu sectors\n",
++devices.device_num, le64_to_cpu(conf.capacity));
}
-struct rng_info {
- int rfd;
-};
-
-/* Our random number generator device reads from /dev/random into the Guest's
+/*L:211
+ * Our random number generator device reads from /dev/random into the Guest's
* input buffers. The usual case is that the Guest doesn't want random numbers
* and so has no buffers although /dev/random is still readable, whereas
* console is the reverse.
*
- * The same logic applies, however. */
+ * The same logic applies, however.
+ */
+struct rng_info {
+ int rfd;
+};
+
static void rng_input(struct virtqueue *vq)
{
int len;
@@ -1543,9 +1763,10 @@ static void rng_input(struct virtqueue *vq)
if (out_num)
errx(1, "Output buffers in rng?");
- /* This is why we convert to iovecs: the readv() call uses them, and so
- * it reads straight into the Guest's buffer. We loop to make sure we
- * fill it. */
+ /*
+ * Just like the console write, we loop to cover the whole iovec.
+ * In this case, short reads actually happen quite a bit.
+ */
while (!iov_empty(iov, in_num)) {
len = readv(rng_info->rfd, iov, in_num);
if (len <= 0)
@@ -1558,15 +1779,18 @@ static void rng_input(struct virtqueue *vq)
add_used(vq, head, totlen);
}
-/* And this creates a "hardware" random number device for the Guest. */
+/*L:199
+ * This creates a "hardware" random number device for the Guest.
+ */
static void setup_rng(void)
{
struct device *dev;
struct rng_info *rng_info = malloc(sizeof(*rng_info));
+ /* Our device's privat info simply contains the /dev/random fd. */
rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
- /* The device responds to return from I/O thread. */
+ /* Create the new device. */
dev = new_device("rng", VIRTIO_ID_RNG);
dev->priv = rng_info;
@@ -1582,8 +1806,10 @@ static void __attribute__((noreturn)) restart_guest(void)
{
unsigned int i;
- /* Since we don't track all open fds, we simply close everything beyond
- * stderr. */
+ /*
+ * Since we don't track all open fds, we simply close everything beyond
+ * stderr.
+ */
for (i = 3; i < FD_SETSIZE; i++)
close(i);
@@ -1594,8 +1820,10 @@ static void __attribute__((noreturn)) restart_guest(void)
err(1, "Could not exec %s", main_args[0]);
}
-/*L:220 Finally we reach the core of the Launcher which runs the Guest, serves
- * its input and output, and finally, lays it to rest. */
+/*L:220
+ * Finally we reach the core of the Launcher which runs the Guest, serves
+ * its input and output, and finally, lays it to rest.
+ */
static void __attribute__((noreturn)) run_guest(void)
{
for (;;) {
@@ -1630,7 +1858,7 @@ static void __attribute__((noreturn)) run_guest(void)
*
* Are you ready? Take a deep breath and join me in the core of the Host, in
* "make Host".
- :*/
+:*/
static struct option opts[] = {
{ "verbose", 0, NULL, 'v' },
@@ -1651,8 +1879,7 @@ static void usage(void)
/*L:105 The main routine is where the real work begins: */
int main(int argc, char *argv[])
{
- /* Memory, top-level pagetable, code startpoint and size of the
- * (optional) initrd. */
+ /* Memory, code startpoint and size of the (optional) initrd. */
unsigned long mem = 0, start, initrd_size = 0;
/* Two temporaries. */
int i, c;
@@ -1664,24 +1891,32 @@ int main(int argc, char *argv[])
/* Save the args: we "reboot" by execing ourselves again. */
main_args = argv;
- /* First we initialize the device list. We keep a pointer to the last
+ /*
+ * First we initialize the device list. We keep a pointer to the last
* device, and the next interrupt number to use for devices (1:
- * remember that 0 is used by the timer). */
+ * remember that 0 is used by the timer).
+ */
devices.lastdev = NULL;
devices.next_irq = 1;
+ /* We're CPU 0. In fact, that's the only CPU possible right now. */
cpu_id = 0;
- /* We need to know how much memory so we can set up the device
+
+ /*
+ * We need to know how much memory so we can set up the device
* descriptor and memory pages for the devices as we parse the command
* line. So we quickly look through the arguments to find the amount
- * of memory now. */
+ * of memory now.
+ */
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
mem = atoi(argv[i]) * 1024 * 1024;
- /* We start by mapping anonymous pages over all of
+ /*
+ * We start by mapping anonymous pages over all of
* guest-physical memory range. This fills it with 0,
* and ensures that the Guest won't be killed when it
- * tries to access it. */
+ * tries to access it.
+ */
guest_base = map_zeroed_pages(mem / getpagesize()
+ DEVICE_PAGES);
guest_limit = mem;
@@ -1714,8 +1949,10 @@ int main(int argc, char *argv[])
usage();
}
}
- /* After the other arguments we expect memory and kernel image name,
- * followed by command line arguments for the kernel. */
+ /*
+ * After the other arguments we expect memory and kernel image name,
+ * followed by command line arguments for the kernel.
+ */
if (optind + 2 > argc)
usage();
@@ -1733,20 +1970,26 @@ int main(int argc, char *argv[])
/* Map the initrd image if requested (at top of physical memory) */
if (initrd_name) {
initrd_size = load_initrd(initrd_name, mem);
- /* These are the location in the Linux boot header where the
- * start and size of the initrd are expected to be found. */
+ /*
+ * These are the location in the Linux boot header where the
+ * start and size of the initrd are expected to be found.
+ */
boot->hdr.ramdisk_image = mem - initrd_size;
boot->hdr.ramdisk_size = initrd_size;
/* The bootloader type 0xFF means "unknown"; that's OK. */
boot->hdr.type_of_loader = 0xFF;
}
- /* The Linux boot header contains an "E820" memory map: ours is a
- * simple, single region. */
+ /*
+ * The Linux boot header contains an "E820" memory map: ours is a
+ * simple, single region.
+ */
boot->e820_entries = 1;
boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
- /* The boot header contains a command line pointer: we put the command
- * line after the boot header. */
+ /*
+ * The boot header contains a command line pointer: we put the command
+ * line after the boot header.
+ */
boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
/* We use a simple helper to copy the arguments separated by spaces. */
concat((char *)(boot + 1), argv+optind+2);
@@ -1760,11 +2003,13 @@ int main(int argc, char *argv[])
/* Tell the entry path not to try to reload segment registers. */
boot->hdr.loadflags |= KEEP_SEGMENTS;
- /* We tell the kernel to initialize the Guest: this returns the open
- * /dev/lguest file descriptor. */
+ /*
+ * We tell the kernel to initialize the Guest: this returns the open
+ * /dev/lguest file descriptor.
+ */
tell_kernel(start);
- /* Ensure that we terminate if a child dies. */
+ /* Ensure that we terminate if a device-servicing child dies. */
signal(SIGCHLD, kill_launcher);
/* If we exit via err(), this kills all the threads, restores tty. */
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 1634c6dcecae..50189bf07d53 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -60,6 +60,8 @@ framerelay.txt
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
generic_netlink.txt
- info on Generic Netlink
+ieee802154.txt
+ - Linux IEEE 802.15.4 implementation, API and drivers
ip-sysctl.txt
- /proc/sys/net/ipv4/* variables
ip_dynaddr.txt
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt
index a0280ad2edc9..1d4ed66b1b1c 100644
--- a/Documentation/networking/ieee802154.txt
+++ b/Documentation/networking/ieee802154.txt
@@ -69,7 +69,7 @@ We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c
SoftMAC
=======
-We are going to provide intermediate layer impelementing IEEE 802.15.4 MAC
+We are going to provide intermediate layer implementing IEEE 802.15.4 MAC
in software. This is currently WIP.
See header include/net/ieee802154/mac802154.h and several drivers in
diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
index eaa1a25946c1..ee31369e9e5b 100644
--- a/Documentation/networking/regulatory.txt
+++ b/Documentation/networking/regulatory.txt
@@ -96,7 +96,7 @@ Example code - drivers hinting an alpha2:
This example comes from the zd1211rw device driver. You can start
by having a mapping of your device's EEPROM country/regulatory
-domain value to to a specific alpha2 as follows:
+domain value to a specific alpha2 as follows:
static struct zd_reg_alpha2_map reg_alpha2_map[] = {
{ ZD_REGDOMAIN_FCC, "US" },
diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index c6cd4956047c..9f16c5178b66 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -76,6 +76,11 @@ STATUS - this attribute represents operating status (charging, full,
discharging (i.e. powering a load), etc.). This corresponds to
BATTERY_STATUS_* values, as defined in battery.h.
+CHARGE_TYPE - batteries can typically charge at different rates.
+This defines trickle and fast charges. For batteries that
+are already charged or discharging, 'n/a' can be displayed (or
+'unknown', if the status is not known).
+
HEALTH - represents health of the battery, values corresponds to
POWER_SUPPLY_HEALTH_*, defined in battery.h.
@@ -108,6 +113,8 @@ relative, time-based measurements.
ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
CAPACITY - capacity in percents.
+CAPACITY_LEVEL - capacity level. This corresponds to
+POWER_SUPPLY_CAPACITY_LEVEL_*.
TEMP - temperature of the power supply.
TEMP_AMBIENT - ambient temperature.
diff --git a/Documentation/powerpc/dts-bindings/marvell.txt b/Documentation/powerpc/dts-bindings/marvell.txt
index 3708a2fd4747..f1533d91953a 100644
--- a/Documentation/powerpc/dts-bindings/marvell.txt
+++ b/Documentation/powerpc/dts-bindings/marvell.txt
@@ -32,7 +32,7 @@ prefixed with the string "marvell,", for Marvell Technology Group Ltd.
devices. This field represents the number of cells needed to
represent the address of the memory-mapped registers of devices
within the system controller chip.
- - #size-cells : Size representation for for the memory-mapped
+ - #size-cells : Size representation for the memory-mapped
registers within the system controller chip.
- #interrupt-cells : Defines the width of cells used to represent
interrupts.
diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid
index eaa4801f2ce6..38e9e7cadc90 100644
--- a/Documentation/scsi/ChangeLog.megaraid
+++ b/Documentation/scsi/ChangeLog.megaraid
@@ -514,7 +514,7 @@ iv. Remove yield() while mailbox handshake in synchronous commands
v. Remove redundant __megaraid_busywait_mbox routine
-vi. Fix bug in the managment module, which causes a system lockup when the
+vi. Fix bug in the management module, which causes a system lockup when the
IO module is loaded and then unloaded, followed by executing any
management utility. The current version of management module does not
handle the adapter unregister properly.
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
index d7f181701dc2..aec6549ab097 100644
--- a/Documentation/scsi/scsi_fc_transport.txt
+++ b/Documentation/scsi/scsi_fc_transport.txt
@@ -378,7 +378,7 @@ Vport Disable/Enable:
int vport_disable(struct fc_vport *vport, bool disable)
where:
- vport: Is vport to to be enabled or disabled
+ vport: Is vport to be enabled or disabled
disable: If "true", the vport is to be disabled.
If "false", the vport is to be enabled.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 4252697a95d6..f9d11140af91 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -768,6 +768,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
Passing -1 will make the driver to choose the appropriate
value based on the controller chip.
+ patch - Specifies the early "patch" files to modify the HD-audio
+ setup before initializing the codecs. This option is
+ available only when CONFIG_SND_HDA_PATCH_LOADER=y is set.
+ See HD-Audio.txt for details.
[Single (global) options]
single_cmd - Use single immediate commands to communicate with
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 939a3dd58148..0fe1cd95eb45 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -114,8 +114,8 @@ ALC662/663/272
samsung-nc10 Samsung NC10 mini notebook
auto auto-config reading BIOS (default)
-ALC882/885
-==========
+ALC882/883/885/888/889
+======================
3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1
@@ -127,12 +127,8 @@ ALC882/885
mbp3 Macbook Pro rev3
imac24 iMac 24'' with jack detection
w2jc ASUS W2JC
- auto auto-config reading BIOS (default)
-
-ALC883/888
-==========
- 3stack-dig 3-jack with SPDIF I/O
- 6stack-dig 6-jack digital with SPDIF I/O
+ 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883)
+ alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883)
3stack-6ch 3-jack 6-channel
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board
@@ -159,6 +155,8 @@ ALC883/888
fujitsu-pi2515 Fujitsu AMILO Pi2515
fujitsu-xa3530 Fujitsu AMILO XA3530
3stack-6ch-intel Intel DG33* boards
+ intel-alc889a Intel IbexPeak with ALC889A
+ intel-x58 Intel DX58 with ALC889
asus-p5q ASUS P5Q-EM boards
mb31 MacBook 3,1
sony-vaio-tt Sony VAIO TT
@@ -377,7 +375,7 @@ STAC92HD73*
STAC92HD83*
===========
ref Reference board
- mic-ref Reference board with power managment for ports
+ mic-ref Reference board with power management for ports
dell-s14 Dell laptop
auto BIOS setup (default)
@@ -385,3 +383,7 @@ STAC9872
========
vaio VAIO laptop without SPDIF
auto BIOS setup (default)
+
+Cirrus Logic CS4206/4207
+========================
+ mbp55 MacBook Pro 5,5
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 71ac995b1915..7b8a5f947d1d 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -139,6 +139,10 @@ The driver checks PCI SSID and looks through the static configuration
table until any matching entry is found. If you have a new machine,
you may see a message like below:
------------------------------------------------------------------------
+ hda_codec: ALC880: BIOS auto-probing.
+------------------------------------------------------------------------
+Meanwhile, in the earlier versions, you would see a message like:
+------------------------------------------------------------------------
hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
------------------------------------------------------------------------
Even if you see such a message, DON'T PANIC. Take a deep breath and
@@ -403,6 +407,66 @@ re-configure based on that state, run like below:
------------------------------------------------------------------------
+Early Patching
+~~~~~~~~~~~~~~
+When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
+firmware file for modifying the HD-audio setup before initializing the
+codec. This can work basically like the reconfiguration via sysfs in
+the above, but it does it before the first codec configuration.
+
+A patch file is a plain text file which looks like below:
+
+------------------------------------------------------------------------
+ [codec]
+ 0x12345678 0xabcd1234 2
+
+ [model]
+ auto
+
+ [pincfg]
+ 0x12 0x411111f0
+
+ [verb]
+ 0x20 0x500 0x03
+ 0x20 0x400 0xff
+
+ [hint]
+ hp_detect = yes
+------------------------------------------------------------------------
+
+The file needs to have a line `[codec]`. The next line should contain
+three numbers indicating the codec vendor-id (0x12345678 in the
+example), the codec subsystem-id (0xabcd1234) and the address (2) of
+the codec. The rest patch entries are applied to this specified codec
+until another codec entry is given.
+
+The `[model]` line allows to change the model name of the each codec.
+In the example above, it will be changed to model=auto.
+Note that this overrides the module option.
+
+After the `[pincfg]` line, the contents are parsed as the initial
+default pin-configurations just like `user_pin_configs` sysfs above.
+The values can be shown in user_pin_configs sysfs file, too.
+
+Similarly, the lines after `[verb]` are parsed as `init_verbs`
+sysfs entries, and the lines after `[hint]` are parsed as `hints`
+sysfs entries, respectively.
+
+The hd-audio driver reads the file via request_firmware(). Thus,
+a patch file has to be located on the appropriate firmware path,
+typically, /lib/firmware. For example, when you pass the option
+`patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be
+present.
+
+The patch module option is specific to each card instance, and you
+need to give one file name for each instance, separated by commas.
+For example, if you have two cards, one for an on-board analog and one
+for an HDMI video board, you may pass patch option like below:
+------------------------------------------------------------------------
+ options snd-hda-intel patch=on-board-patch,hdmi-patch
+------------------------------------------------------------------------
+
+
Power-Saving
~~~~~~~~~~~~
The power-saving is a kind of auto-suspend of the device. When the
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index 381908d8ca42..719a819f8cc2 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -101,6 +101,8 @@ card*/pcm*/xrun_debug
bit 0 = Enable XRUN/jiffies debug messages
bit 1 = Show stack trace at XRUN / jiffies check
bit 2 = Enable additional jiffies check
+ bit 3 = Log hwptr update at each period interrupt
+ bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
When the bit 0 is set, the driver will show the messages to
kernel log when an xrun is detected. The debug message is
@@ -117,6 +119,9 @@ card*/pcm*/xrun_debug
buggy) hardware that doesn't give smooth pointer updates.
This feature is enabled via the bit 2.
+ Bits 3 and 4 are for logging the hwptr records. Note that
+ these will give flood of kernel messages.
+
card*/pcm*/sub*/info
The general information of this PCM sub-stream.
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 322a00bb99d9..dd8322f40fd0 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -303,25 +303,29 @@ This option can be used to select the type of process address
space randomization that is used in the system, for architectures
that support this feature.
-0 - Turn the process address space randomization off by default.
+0 - Turn the process address space randomization off. This is the
+ default for architectures that do not support this feature anyways,
+ and kernels that are booted with the "norandmaps" parameter.
1 - Make the addresses of mmap base, stack and VDSO page randomized.
This, among other things, implies that shared libraries will be
- loaded to random addresses. Also for PIE-linked binaries, the location
- of code start is randomized.
+ loaded to random addresses. Also for PIE-linked binaries, the
+ location of code start is randomized. This is the default if the
+ CONFIG_COMPAT_BRK option is enabled.
- With heap randomization, the situation is a little bit more
- complicated.
- There a few legacy applications out there (such as some ancient
+2 - Additionally enable heap randomization. This is the default if
+ CONFIG_COMPAT_BRK is disabled.
+
+ There are a few legacy applications out there (such as some ancient
versions of libc.so.5 from 1996) that assume that brk area starts
- just after the end of the code+bss. These applications break when
- start of the brk area is randomized. There are however no known
+ just after the end of the code+bss. These applications break when
+ start of the brk area is randomized. There are however no known
non-legacy applications that would be broken this way, so for most
- systems it is safe to choose full randomization. However there is
- a CONFIG_COMPAT_BRK option for systems with ancient and/or broken
- binaries, that makes heap non-randomized, but keeps all other
- parts of process address space randomized if randomize_va_space
- sysctl is turned on.
+ systems it is safe to choose full randomization.
+
+ Systems with ancient and/or broken binaries should be configured
+ with CONFIG_COMPAT_BRK enabled, which excludes the heap from process
+ address space randomization.
==============================================================
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index cf42b820ff9d..d56a01775423 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -66,7 +66,8 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
'b' - Will immediately reboot the system without syncing or unmounting
your disks.
-'c' - Will perform a kexec reboot in order to take a crashdump.
+'c' - Will perform a system crash by a NULL pointer dereference.
+ A crashdump will be taken if configured.
'd' - Shows all locks that are held.
@@ -141,8 +142,8 @@ useful when you want to exit a program that will not let you switch consoles.
re'B'oot is good when you're unable to shut down. But you should also 'S'ync
and 'U'mount first.
-'C'rashdump can be used to manually trigger a crashdump when the system is hung.
-The kernel needs to have been built with CONFIG_KEXEC enabled.
+'C'rash can be used to manually trigger a crashdump when the system is hung.
+Note that this just triggers a crash if there is no dump mechanism available.
'S'ync is great when your system is locked up, it allows you to sync your
disks and will certainly lessen the chance of data loss and fscking. Note
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
index f157d7594ea7..2bcc8d4dea29 100644
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -83,6 +83,15 @@ When reading one of these enable files, there are four results:
X - there is a mixture of events enabled and disabled
? - this file does not affect any event
+2.3 Boot option
+---------------
+
+In order to facilitate early boot debugging, use boot option:
+
+ trace_event=[event-list]
+
+The format of this boot option is the same as described in section 2.1.
+
3. Defining an event-enabled tracepoint
=======================================
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index a39b3c749de5..325a22d0c029 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -134,7 +134,7 @@ of ftrace. Here is a list of some of the key files:
than requested, the rest of the page will be used,
making the actual allocation bigger than requested.
( Note, the size may not be a multiple of the page size
- due to buffer managment overhead. )
+ due to buffer management overhead. )
This can only be updated when the current_tracer
is set to "nop".
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 450b8f8c389b..525edb37c758 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -21,3 +21,5 @@
20 -> Hauppauge WinTV-HVR1255 [0070:2251]
21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295]
22 -> Mygica X8506 DMB-TH [14f1:8651]
+ 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657]
+ 24 -> Hauppauge WinTV-HVR1850 [0070:8541]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 014d255231fc..084a7b62451e 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -20,7 +20,7 @@
19 -> EM2860/SAA711X Reference Design (em2860)
20 -> AMD ATI TV Wonder HD 600 (em2880) [0438:b002]
21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800) [eb1a:2801]
- 22 -> Unknown EM2750/EM2751 webcam grabber (em2750) [eb1a:2750,eb1a:2751]
+ 22 -> EM2710/EM2750/EM2751 webcam grabber (em2750) [eb1a:2750,eb1a:2751]
23 -> Huaqi DLCW-130 (em2750)
24 -> D-Link DUB-T210 TV Tuner (em2820/em2840) [2001:f112]
25 -> Gadmei UTV310 (em2820/em2840)
@@ -33,7 +33,7 @@
34 -> Terratec Cinergy A Hybrid XS (em2860) [0ccd:004f]
35 -> Typhoon DVD Maker (em2860)
36 -> NetGMBH Cam (em2860)
- 37 -> Gadmei UTV330 (em2860)
+ 37 -> Gadmei UTV330 (em2860) [eb1a:50a6]
38 -> Yakumo MovieMixer (em2861)
39 -> KWorld PVRTV 300U (em2861) [eb1a:e300]
40 -> Plextor ConvertX PX-TV100U (em2861) [093b:a005]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index be67844074dd..ba9fa679e2d3 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -78,3 +78,4 @@ tuner=77 - TCL tuner MF02GIP-5N-E
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
+tuner=81 - Partsnic (Daewoo) PTI-5NF05
diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt
index 04986efb731c..d230878e473e 100644
--- a/Documentation/video4linux/CQcam.txt
+++ b/Documentation/video4linux/CQcam.txt
@@ -18,8 +18,8 @@ Table of Contents
1.0 Introduction
- The file ../drivers/char/c-qcam.c is a device driver for the
-Logitech (nee Connectix) parallel port interface color CCD camera.
+ The file ../../drivers/media/video/c-qcam.c is a device driver for
+the Logitech (nee Connectix) parallel port interface color CCD camera.
This is a fairly inexpensive device for capturing images. Logitech
does not currently provide information for developers, but many people
have engineered several solutions for non-Microsoft use of the Color
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 2bcf78896e22..b43702470130 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -44,7 +44,9 @@ zc3xx 0458:7007 Genius VideoCam V2
zc3xx 0458:700c Genius VideoCam V3
zc3xx 0458:700f Genius VideoCam Web V2
sonixj 0458:7025 Genius Eye 311Q
+sn9c20x 0458:7029 Genius Look 320s
sonixj 0458:702e Genius Slim 310 NB
+sn9c20x 045e:00f4 LifeCam VX-6000 (SN9C20x + OV9650)
sonixj 045e:00f5 MicroSoft VX3000
sonixj 045e:00f7 MicroSoft VX1000
ov519 045e:028c Micro$oft xbox cam
@@ -138,6 +140,7 @@ spca500 04fc:7333 PalmPixDC85
sunplus 04fc:ffff Pure DigitalDakota
spca501 0506:00df 3Com HomeConnect Lite
sunplus 052b:1513 Megapix V4
+sunplus 052b:1803 MegaImage VI
tv8532 0545:808b Veo Stingray
tv8532 0545:8333 Veo Stingray
sunplus 0546:3155 Polaroid PDC3070
@@ -233,6 +236,7 @@ pac7311 093a:2621 PAC731x
pac7311 093a:2622 Genius Eye 312
pac7311 093a:2624 PAC7302
pac7311 093a:2626 Labtec 2200
+pac7311 093a:2629 Genious iSlim 300
pac7311 093a:262a Webcam 300k
pac7311 093a:262c Philips SPC 230 NC
zc3xx 0ac8:0302 Z-star Vimicro zc0302
@@ -245,6 +249,7 @@ zc3xx 0ac8:305b Z-star Vimicro zc0305b
zc3xx 0ac8:307b Ldlc VC302+Ov7620
vc032x 0ac8:c001 Sony embedded vimicro
vc032x 0ac8:c002 Sony embedded vimicro
+vc032x 0ac8:c301 Samsung Q1 Ultra Premium
spca508 0af9:0010 Hama USB Sightcam 100
spca508 0af9:0011 Hama USB Sightcam 100
sonixb 0c45:6001 Genius VideoCAM NB
@@ -282,6 +287,29 @@ sonixj 0c45:613a Microdia Sonix PC Camera
sonixj 0c45:613b Surfer SN-206
sonixj 0c45:613c Sonix Pccam168
sonixj 0c45:6143 Sonix Pccam168
+sonixj 0c45:6148 Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
+sn9c20x 0c45:6240 PC Camera (SN9C201 + MT9M001)
+sn9c20x 0c45:6242 PC Camera (SN9C201 + MT9M111)
+sn9c20x 0c45:6248 PC Camera (SN9C201 + OV9655)
+sn9c20x 0c45:624e PC Camera (SN9C201 + SOI968)
+sn9c20x 0c45:624f PC Camera (SN9C201 + OV9650)
+sn9c20x 0c45:6251 PC Camera (SN9C201 + OV9650)
+sn9c20x 0c45:6253 PC Camera (SN9C201 + OV9650)
+sn9c20x 0c45:6260 PC Camera (SN9C201 + OV7670)
+sn9c20x 0c45:6270 PC Camera (SN9C201 + MT9V011/MT9V111/MT9V112)
+sn9c20x 0c45:627b PC Camera (SN9C201 + OV7660)
+sn9c20x 0c45:627c PC Camera (SN9C201 + HV7131R)
+sn9c20x 0c45:627f PC Camera (SN9C201 + OV9650)
+sn9c20x 0c45:6280 PC Camera (SN9C202 + MT9M001)
+sn9c20x 0c45:6282 PC Camera (SN9C202 + MT9M111)
+sn9c20x 0c45:6288 PC Camera (SN9C202 + OV9655)
+sn9c20x 0c45:628e PC Camera (SN9C202 + SOI968)
+sn9c20x 0c45:628f PC Camera (SN9C202 + OV9650)
+sn9c20x 0c45:62a0 PC Camera (SN9C202 + OV7670)
+sn9c20x 0c45:62b0 PC Camera (SN9C202 + MT9V011/MT9V111/MT9V112)
+sn9c20x 0c45:62b3 PC Camera (SN9C202 + OV9655)
+sn9c20x 0c45:62bb PC Camera (SN9C202 + OV7660)
+sn9c20x 0c45:62bc PC Camera (SN9C202 + HV7131R)
sunplus 0d64:0303 Sunplus FashionCam DXG
etoms 102c:6151 Qcam Sangha CIF
etoms 102c:6251 Qcam xxxxxx VGA
@@ -290,6 +318,7 @@ spca561 10fd:7e50 FlyCam Usb 100
zc3xx 10fd:8050 Typhoon Webshot II USB 300k
ov534 1415:2000 Sony HD Eye for PS3 (SLEH 00201)
pac207 145f:013a Trust WB-1300N
+sn9c20x 145f:013d Trust WB-3600R
vc032x 15b8:6001 HP 2.0 Megapixel
vc032x 15b8:6002 HP 2.0 Megapixel rz406aa
spca501 1776:501c Arowana 300K CMOS Camera
@@ -300,4 +329,11 @@ spca500 2899:012c Toptro Industrial
spca508 8086:0110 Intel Easy PC Camera
spca500 8086:0630 Intel Pocket PC Camera
spca506 99fa:8988 Grandtec V.cap
+sn9c20x a168:0610 Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x a168:0611 Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x a168:0613 Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x a168:0618 Dino-Lite Digital Microscope (SN9C201 + HV7131R)
+sn9c20x a168:0614 Dino-Lite Digital Microscope (SN9C201 + MT9M111)
+sn9c20x a168:0615 Dino-Lite Digital Microscope (SN9C201 + MT9M111)
+sn9c20x a168:0617 Dino-Lite Digital Microscope (SN9C201 + MT9M111)
spca561 abcd:cdee Petcam
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/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index bb1f5c6e28b3..510917ff59ed 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -41,6 +41,8 @@ Possible debug options are
P Poisoning (object and padding)
U User tracking (free and alloc)
T Trace (please only use on single slabs)
+ O Switch debugging off for caches that would have
+ caused higher minimum slab orders
- Switch all debugging off (useful if the kernel is
configured with CONFIG_SLUB_DEBUG_ON)
@@ -59,6 +61,14 @@ to the dentry cache with
slub_debug=F,dentry
+Debugging options may require the minimum possible slab order to increase as
+a result of storing the metadata (for example, caches with PAGE_SIZE object
+sizes). This has a higher liklihood of resulting in slab allocation errors
+in low memory situations or if there's high fragmentation of memory. To
+switch off debugging for such caches by default, use
+
+ slub_debug=O
+
In case you forgot to enable debugging on the kernel command line: It is
possible to enable debugging manually when the kernel is up. Look at the
contents of:
diff --git a/MAINTAINERS b/MAINTAINERS
index 7051d42c8142..8967b242a704 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -73,8 +73,8 @@ Note: For the hard of thinking, this list is meant to remain in alphabetical
order. If you could add yourselves to it in alphabetical order that would be
so much easier [Ed]
-P: Person
-M: Mail patches to
+P: Person (obsolete)
+M: Mail patches to: FullName <address@domain>
L: Mailing list that is relevant to this area
W: Web-page with status/info
T: SCM tree type and location. Type is one of: git, hg, quilt, stgit.
@@ -104,88 +104,74 @@ X: Files and directories that are NOT maintained, same rules as F:
matches all files in and below net excluding net/ipv6/
3C505 NETWORK DRIVER
-P: Philip Blundell
-M: philb@gnu.org
+M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/3c505*
3C59X NETWORK DRIVER
-P: Steffen Klassert
-M: klassert@mathematik.tu-chemnitz.de
+M: Steffen Klassert <klassert@mathematik.tu-chemnitz.de>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/vortex.txt
F: drivers/net/3c59x.c
3CR990 NETWORK DRIVER
-P: David Dillow
-M: dave@thedillows.org
+M: David Dillow <dave@thedillows.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/typhoon*
3W-9XXX SATA-RAID CONTROLLER DRIVER
-P: Adam Radford
-M: linuxraid@amcc.com
+M: Adam Radford <linuxraid@amcc.com>
L: linux-scsi@vger.kernel.org
W: http://www.amcc.com
S: Supported
F: drivers/scsi/3w-9xxx*
3W-XXXX ATA-RAID CONTROLLER DRIVER
-P: Adam Radford
-M: linuxraid@amcc.com
+M: Adam Radford <linuxraid@amcc.com>
L: linux-scsi@vger.kernel.org
W: http://www.amcc.com
S: Supported
F: drivers/scsi/3w-xxxx*
53C700 AND 53C700-66 SCSI DRIVER
-P: James E.J. Bottomley
-M: James.Bottomley@HansenPartnership.com
+M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/53c700*
6PACK NETWORK DRIVER FOR AX.25
-P: Andreas Koensgen
-M: ajk@comnets.uni-bremen.de
+M: Andreas Koensgen <ajk@comnets.uni-bremen.de>
L: linux-hams@vger.kernel.org
S: Maintained
F: drivers/net/hamradio/6pack.c
8169 10/100/1000 GIGABIT ETHERNET DRIVER
-P: Francois Romieu
-M: romieu@fr.zoreil.com
+M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/r8169.c
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
-P: Alan Cox
-M: alan@lxorguk.ukuu.org.uk
L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net
-S: Odd Fixes
+S: Orphan
F: drivers/serial/8250*
F: include/linux/serial_8250.h
8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
-P: Paul Gortmaker
-M: p_gortmaker@yahoo.com
+M: Paul Gortmaker <p_gortmaker@yahoo.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/*8390*
F: drivers/net/ax88796.c
9P FILE SYSTEM
-P: Eric Van Hensbergen
-M: ericvh@gmail.com
-P: Ron Minnich
-M: rminnich@sandia.gov
-P: Latchesar Ionkov
-M: lucho@ionkov.net
+M: Eric Van Hensbergen <ericvh@gmail.com>
+M: Ron Minnich <rminnich@sandia.gov>
+M: Latchesar Ionkov <lucho@ionkov.net>
L: v9fs-developer@lists.sourceforge.net
W: http://swik.net/v9fs
T: git git://git.kernel.org/pub/scm/linux/kernel/ericvh/v9fs.git
@@ -194,15 +180,13 @@ F: Documentation/filesystems/9p.txt
F: fs/9p/
A2232 SERIAL BOARD DRIVER
-P: Enver Haase
-M: A2232@gmx.net
+M: Enver Haase <A2232@gmx.net>
L: linux-m68k@lists.linux-m68k.org
S: Maintained
F: drivers/char/ser_a2232*
AACRAID SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
+M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
L: linux-scsi@vger.kernel.org
W: http://www.adaptec.com/
S: Supported
@@ -210,44 +194,38 @@ F: Documentation/scsi/aacraid.txt
F: drivers/scsi/aacraid/
ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
-P: Hans de Goede
-M: j.w.r.degoede@hhs.nl
+M: Hans de Goede <j.w.r.degoede@hhs.nl>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/abituguru.c
ABIT UGURU 3 HARDWARE MONITOR DRIVER
-P: Alistair John Strachan
-M: alistair@devzero.co.uk
+M: Alistair John Strachan <alistair@devzero.co.uk>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/abituguru3.c
ACENIC DRIVER
-P: Jes Sorensen
-M: jes@trained-monkey.org
+M: Jes Sorensen <jes@trained-monkey.org>
L: linux-acenic@sunsite.dk
S: Maintained
F: drivers/net/acenic*
ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
-P: Peter Feuerer
-M: peter@piie.net
-W: http://piie.net/?section=acerhdf
-S: Maintained
-F: drivers/platform/x86/acerhdf.c
+M: Peter Feuerer <peter@piie.net>
+W: http://piie.net/?section=acerhdf
+S: Maintained
+F: drivers/platform/x86/acerhdf.c
ACER WMI LAPTOP EXTRAS
-P: Carlos Corbacho
-M: carlos@strangeworlds.co.uk
+M: Carlos Corbacho <carlos@strangeworlds.co.uk>
L: aceracpi@googlegroups.com (subscribers-only)
W: http://code.google.com/p/aceracpi
S: Maintained
F: drivers/platform/x86/acer-wmi.c
ACPI
-P: Len Brown
-M: lenb@kernel.org
+M: Len Brown <lenb@kernel.org>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
@@ -257,8 +235,7 @@ F: drivers/pnp/pnpacpi/
F: include/linux/acpi.h
ACPI BATTERY DRIVERS
-P: Alexey Starikovskiy
-M: astarikovskiy@suse.de
+M: Alexey Starikovskiy <astarikovskiy@suse.de>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
@@ -266,80 +243,77 @@ F: drivers/acpi/battery.c
F: drivers/acpi/*sbs*
ACPI EC DRIVER
-P: Alexey Starikovskiy
-M: astarikovskiy@suse.de
+M: Alexey Starikovskiy <astarikovskiy@suse.de>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
F: drivers/acpi/ec.c
ACPI FAN DRIVER
-P: Zhang Rui
-M: rui.zhang@intel.com
+M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
F: drivers/acpi/fan.c
ACPI PCI HOTPLUG DRIVER
-P: Kristen Carlson Accardi
-M: kristen.c.accardi@intel.com
+M: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
L: linux-pci@vger.kernel.org
S: Supported
F: drivers/pci/hotplug/acpi*
+ACPI PROCESSOR AGGREGATOR DRIVER
+P: Shaohua Li
+M: shaohua.li@intel.com
+L: linux-acpi@vger.kernel.org
+W: http://www.lesswatts.org/projects/acpi/
+S: Supported
+F: drivers/acpi/acpi_pad.c
+
ACPI THERMAL DRIVER
-P: Zhang Rui
-M: rui.zhang@intel.com
+M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
F: drivers/acpi/*thermal*
ACPI VIDEO DRIVER
-P: Zhang Rui
-M: rui.zhang@intel.com
+M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
F: drivers/acpi/video.c
ACPI WMI DRIVER
-P: Carlos Corbacho
-M: carlos@strangeworlds.co.uk
+M: Carlos Corbacho <carlos@strangeworlds.co.uk>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Maintained
F: drivers/platform/x86/wmi.c
AD1889 ALSA SOUND DRIVER
-P: Kyle McMartin
-M: kyle@mcmartin.ca
-P: Thibaut Varene
-M: T-Bone@parisc-linux.org
+M: Kyle McMartin <kyle@mcmartin.ca>
+M: Thibaut Varene <T-Bone@parisc-linux.org>
W: http://wiki.parisc-linux.org/AD1889
L: linux-parisc@vger.kernel.org
S: Maintained
F: sound/pci/ad1889.*
ADM1025 HARDWARE MONITOR DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
+M: Jean Delvare <khali@linux-fr.org>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/adm1025
F: drivers/hwmon/adm1025.c
ADM1029 HARDWARE MONITOR DRIVER
-P: Corentin Labbe
-M: corentin.labbe@geomatys.fr
+M: Corentin Labbe <corentin.labbe@geomatys.fr>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/adm1029.c
ADM8211 WIRELESS DRIVER
-P: Michael Wu
-M: flamingice@sourmilk.net
+M: Michael Wu <flamingice@sourmilk.net>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
@@ -347,35 +321,30 @@ S: Maintained
F: drivers/net/wireless/adm8211.*
ADT746X FAN DRIVER
-P: Colin Leroy
-M: colin@colino.net
+M: Colin Leroy <colin@colino.net>
S: Maintained
F: drivers/macintosh/therm_adt746x.c
ADVANSYS SCSI DRIVER
-P: Matthew Wilcox
-M: matthew@wil.cx
+M: Matthew Wilcox <matthew@wil.cx>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/advansys.txt
F: drivers/scsi/advansys.c
AEDSP16 DRIVER
-P: Riccardo Facchetti
-M: fizban@tin.it
+M: Riccardo Facchetti <fizban@tin.it>
S: Maintained
F: sound/oss/aedsp16.c
AFFS FILE SYSTEM
-P: Roman Zippel
-M: zippel@linux-m68k.org
+M: Roman Zippel <zippel@linux-m68k.org>
S: Maintained
F: Documentation/filesystems/affs.txt
F: fs/affs/
AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
-P: David Howells
-M: dhowells@redhat.com
+M: David Howells <dhowells@redhat.com>
L: linux-afs@lists.infradead.org
S: Supported
F: fs/afs/
@@ -383,40 +352,35 @@ F: include/net/af_rxrpc.h
F: net/rxrpc/af_rxrpc.c
AGPGART DRIVER
-P: David Airlie
-M: airlied@linux.ie
+M: David Airlie <airlied@linux.ie>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
S: Maintained
F: drivers/char/agp/
F: include/linux/agp*
AHA152X SCSI DRIVER
-P: Juergen E. Fischer
-M: fischer@norbit.de
+M: "Juergen E. Fischer" <fischer@norbit.de>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/aha152x*
F: drivers/scsi/pcmcia/aha152x*
AIC7XXX / AIC79XX SCSI DRIVER
-P: Hannes Reinecke
-M: hare@suse.de
+M: Hannes Reinecke <hare@suse.de>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/aic7xxx/
F: drivers/scsi/aic7xxx_old/
AIO
-P: Benjamin LaHaise
-M: bcrl@kvack.org
+M: Benjamin LaHaise <bcrl@kvack.org>
L: linux-aio@kvack.org
S: Supported
F: fs/aio.c
F: include/linux/*aio*.h
ALCATEL SPEEDTOUCH USB DRIVER
-P: Duncan Sands
-M: duncan.sands@free.fr
+M: Duncan Sands <duncan.sands@free.fr>
L: linux-usb@vger.kernel.org
W: http://www.linux-usb.org/SpeedTouch/
S: Maintained
@@ -424,32 +388,27 @@ F: drivers/usb/atm/speedtch.c
F: drivers/usb/atm/usbatm.c
ALCHEMY AU1XX0 MMC DRIVER
-P: Manuel Lauss
-M: manuel.lauss@gmail.com
+M: Manuel Lauss <manuel.lauss@gmail.com>
S: Maintained
F: drivers/mmc/host/au1xmmc.c
ALI1563 I2C DRIVER
-P: Rudolf Marek
-M: r.marek@assembler.cz
+M: Rudolf Marek <r.marek@assembler.cz>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/busses/i2c-ali1563
F: drivers/i2c/busses/i2c-ali1563.c
ALPHA PORT
-P: Richard Henderson
-M: rth@twiddle.net
+M: Richard Henderson <rth@twiddle.net>
S: Odd Fixes for 2.4; Maintained for 2.6.
-P: Ivan Kokshaysky
-M: ink@jurassic.park.msu.ru
+M: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
S: Maintained for 2.4; PCI support for 2.6.
L: linux-alpha@vger.kernel.org
F: arch/alpha/
AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
-P: Thomas Dahlmann
-M: dahlmann.thomas@arcor.de
+M: Thomas Dahlmann <dahlmann.thomas@arcor.de>
L: linux-geode@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: drivers/usb/gadget/amd5536udc.*
@@ -466,8 +425,7 @@ F: drivers/video/geode/
F: arch/x86/include/asm/geode.h
AMD IOMMU (AMD-VI)
-P: Joerg Roedel
-M: joerg.roedel@amd.com
+M: Joerg Roedel <joerg.roedel@amd.com>
L: iommu@lists.linux-foundation.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
S: Supported
@@ -475,40 +433,33 @@ F: arch/x86/kernel/amd_iommu*.c
F: arch/x86/include/asm/amd_iommu*.h
AMD MICROCODE UPDATE SUPPORT
-P: Andreas Herrmann
-M: andreas.herrmann3@amd.com
+M: Andreas Herrmann <andreas.herrmann3@amd.com>
L: amd64-microcode@amd64.org
S: Supported
F: arch/x86/kernel/microcode_amd.c
AMS (Apple Motion Sensor) DRIVER
-P: Stelian Pop
-M: stelian@popies.net
-P: Michael Hanselmann
-M: linux-kernel@hansmi.ch
+M: Stelian Pop <stelian@popies.net>
+M: Michael Hanselmann <linux-kernel@hansmi.ch>
S: Supported
F: drivers/hwmon/ams/
AMSO1100 RNIC DRIVER
-P: Tom Tucker
-M: tom@opengridcomputing.com
-P: Steve Wise
-M: swise@opengridcomputing.com
+M: Tom Tucker <tom@opengridcomputing.com>
+M: Steve Wise <swise@opengridcomputing.com>
L: general@lists.openfabrics.org
S: Maintained
F: drivers/infiniband/hw/amso1100/
AOA (Apple Onboard Audio) ALSA DRIVER
-P: Johannes Berg
-M: johannes@sipsolutions.net
+M: Johannes Berg <johannes@sipsolutions.net>
L: linuxppc-dev@ozlabs.org
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/aoa/
APM DRIVER
-P: Stephen Rothwell
-M: sfr@canb.auug.org.au
+M: Stephen Rothwell <sfr@canb.auug.org.au>
L: linux-laptop@vger.kernel.org
W: http://www.canb.auug.org.au/~sfr/
S: Supported
@@ -516,51 +467,44 @@ F: arch/x86/kernel/apm_32.c
F: include/linux/apm_bios.h
APPLE BCM5974 MULTITOUCH DRIVER
-P: Henrik Rydberg
-M: rydberg@euromail.se
+M: Henrik Rydberg <rydberg@euromail.se>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/mouse/bcm5974.c
APPLE SMC DRIVER
-P: Nicolas Boichat
-M: nicolas@boichat.ch
+M: Nicolas Boichat <nicolas@boichat.ch>
L: mactel-linux-devel@lists.sourceforge.net
S: Maintained
F: drivers/hwmon/applesmc.c
APPLETALK NETWORK LAYER
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
S: Maintained
F: drivers/net/appletalk/
F: net/appletalk/
APPLETOUCH TOUCHPAD DRIVER
-P: Johannes Berg
-M: johannes@sipsolutions.net
+M: Johannes Berg <johannes@sipsolutions.net>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/input/appletouch.txt
F: drivers/input/mouse/appletouch.c
ARC FRAMEBUFFER DRIVER
-P: Jaya Kumar
-M: jayalk@intworks.biz
+M: Jaya Kumar <jayalk@intworks.biz>
S: Maintained
F: drivers/video/arcfb.c
F: drivers/video/fb_defio.c
ARM MFM AND FLOPPY DRIVERS
-P: Ian Molton
-M: spyro@f2s.com
+M: Ian Molton <spyro@f2s.com>
S: Maintained
F: arch/arm/lib/floppydma.S
F: arch/arm/include/asm/floppy.h
ARM PORT
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
@@ -571,79 +515,70 @@ S: Orphan
F: drivers/mmc/host/mmci.*
ARM/ADI ROADRUNNER MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
F: arch/arm/mach-ixp23xx/
F: arch/arm/mach-ixp23xx/include/mach/
ARM/ADS SPHERE MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/AFEB9260 MACHINE SUPPORT
-P: Sergey Lapin
-M: slapin@ossfans.org
+M: Sergey Lapin <slapin@ossfans.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/AJECO 1ARM MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/ATMEL AT91RM9200 ARM ARCHITECTURE
-P: Andrew Victor
-M: linux@maxim.org.za
+M: Andrew Victor <linux@maxim.org.za>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://maxim.org.za/at91_26.html
S: Maintained
ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Hartley Sweeten <hsweeten@visionengravers.com>
+M: Ryan Mallon <ryan@bluewatersys.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
+F: arch/arm/mach-ep93xx/
+F: arch/arm/mach-ep93xx/include/mach/
ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/CLKDEV SUPPORT
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
F: arch/arm/common/clkdev.c
F: arch/arm/include/asm/clkdev.h
ARM/COMPULAB CM-X270/EM-X270 and CM-X300 MACHINE SUPPORT
-P: Mike Rapoport
-M: mike@compulab.co.il
+M: Mike Rapoport <mike@compulab.co.il>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/CORGI MACHINE SUPPORT
-P: Richard Purdie
-M: rpurdie@rpsys.net
+M: Richard Purdie <rpurdie@rpsys.net>
S: Maintained
ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
-P: Paulius Zaleckas
-M: paulius.zaleckas@teltonika.lt
+M: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
T: git git://gitorious.org/linux-gemini/mainline.git
S: Maintained
F: arch/arm/mach-gemini/
ARM/EBSA110 MACHINE SUPPORT
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
@@ -651,12 +586,9 @@ F: arch/arm/mach-ebsa110/
F: drivers/net/arm/am79c961a.*
ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
-P: Daniel Ribeiro
-M: drwyrm@gmail.com
-P: Stefan Schmidt
-M: stefan@openezx.org
-P: Harald Welte
-M: laforge@openezx.org
+M: Daniel Ribeiro <drwyrm@gmail.com>
+M: Stefan Schmidt <stefan@openezx.org>
+M: Harald Welte <laforge@openezx.org>
L: openezx-devel@lists.openezx.org (subscribers-only)
W: http://www.openezx.org/
S: Maintained
@@ -664,15 +596,13 @@ T: topgit git://git.openezx.org/openezx.git
F: arch/arm/mach-pxa/ezx.c
ARM/FARADAY FA526 PORT
-P: Paulius Zaleckas
-M: paulius.zaleckas@teltonika.lt
+M: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
F: arch/arm/mm/*-fa*
ARM/FOOTBRIDGE ARCHITECTURE
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
@@ -680,175 +610,146 @@ F: arch/arm/include/asm/hardware/dec21285.h
F: arch/arm/mach-footbridge/
ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-P: Sascha Hauer
-M: kernel@pengutronix.de
+M: Sascha Hauer <kernel@pengutronix.de>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/GUMSTIX MACHINE SUPPORT
-P: Steve Sakoman
-M: sakoman@gmail.com
+M: Steve Sakoman <sakoman@gmail.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
-P: Philipp Zabel
-M: philipp.zabel@gmail.com
+M: Philipp Zabel <philipp.zabel@gmail.com>
S: Maintained
F: arch/arm/mach-pxa/hx4700.c
F: arch/arm/mach-pxa/include/mach/hx4700.h
ARM/HP JORNADA 7XX MACHINE SUPPORT
-P: Kristoffer Ericson
-M: kristoffer.ericson@gmail.com
+M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
W: www.jlime.com
S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
+F: arch/arm/mach-sa1100/jornada720.c
+F: arch/arm/mach-sa1100/include/mach/jornada720.h
ARM/INTEL IOP32X ARM ARCHITECTURE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Lennert Buytenhek <kernel@wantstofly.org>
+M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
ARM/INTEL IOP33X ARM ARCHITECTURE
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
ARM/INTEL IOP13XX ARM ARCHITECTURE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Lennert Buytenhek <kernel@wantstofly.org>
+M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
ARM/INTEL IQ81342EX MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Lennert Buytenhek <kernel@wantstofly.org>
+M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
ARM/INTEL IXP2000 ARM ARCHITECTURE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/INTEL IXDP2850 MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/INTEL IXP23XX ARM ARCHITECTURE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/INTEL XSC3 (MANZANO) ARM CORE
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Lennert Buytenhek <kernel@wantstofly.org>
+M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
ARM/IP FABRICS DOUBLE ESPRESSO MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/LOGICPD PXA270 MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/MAGICIAN MACHINE SUPPORT
-P: Philipp Zabel
-M: philipp.zabel@gmail.com
+M: Philipp Zabel <philipp.zabel@gmail.com>
S: Maintained
ARM/MIOA701 MACHINE SUPPORT
-P: Robert Jarzmik
-M: robert.jarzmik@free.fr
+M: Robert Jarzmik <robert.jarzmik@free.fr>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
F: arch/arm/mach-pxa/mioa701.c
S: Maintained
ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
-P: Michael Petchkovsky
-M: mkpetch@internode.on.net
+M: Michael Petchkovsky <mkpetch@internode.on.net>
S: Maintained
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
-P: Nelson Castillo
-M: arhuaco@freaks-unidos.net
+M: Nelson Castillo <arhuaco@freaks-unidos.net>
L: openmoko-kernel@lists.openmoko.org (subscribers-only)
W: http://wiki.openmoko.org/wiki/Neo_FreeRunner
S: Supported
ARM/TOSA MACHINE SUPPORT
-P: Dmitry Eremin-Solenikov
-M: dbaryshkov@gmail.com
-P: Dirk Opfer
-M: dirk@opfer-online.de
+M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+M: Dirk Opfer <dirk@opfer-online.de>
S: Maintained
-ARM/PALMTX,PALMT5,PALMLD,PALMTE2 SUPPORT
-P: Marek Vasut
-M: marek.vasut@gmail.com
+ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
+M: Marek Vasut <marek.vasut@gmail.com>
W: http://hackndev.com
S: Maintained
ARM/PALM TREO 680 SUPPORT
-P: Tomas Cech
-M: sleep_walker@suse.cz
+M: Tomas Cech <sleep_walker@suse.cz>
W: http://hackndev.com
S: Maintained
ARM/PALMZ72 SUPPORT
-P: Sergey Lapin
-M: slapin@ossfans.org
+M: Sergey Lapin <slapin@ossfans.org>
W: http://hackndev.com
S: Maintained
ARM/PLEB SUPPORT
-P: Peter Chubb
-M: pleb@gelato.unsw.edu.au
+M: Peter Chubb <pleb@gelato.unsw.edu.au>
W: http://www.disy.cse.unsw.edu.au/Hardware/PLEB
S: Maintained
ARM/PT DIGITAL BOARD PORT
-P: Stefan Eletzhofer
-M: stefan.eletzhofer@eletztrick.de
+M: Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
ARM/RADISYS ENP2611 MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/RISCPC ARCHITECTURE
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
@@ -862,14 +763,12 @@ F: drivers/net/arm/ether*
F: drivers/scsi/arm/
ARM/SHARK MACHINE SUPPORT
-P: Alexander Schulz
-M: alex@shark-linux.de
+M: Alexander Schulz <alex@shark-linux.de>
W: http://www.shark-linux.de/shark.html
S: Maintained
ARM/SAMSUNG ARM ARCHITECTURES
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
@@ -877,91 +776,73 @@ F: arch/arm/plat-s3c/
F: arch/arm/plat-s3c24xx/
ARM/S3C2410 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2410/
ARM/S3C2440 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2440/
ARM/S3C2442 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2442/
ARM/S3C2443 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2443/
ARM/S3C6400 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c6400/
ARM/S3C6410 ARM ARCHITECTURE
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c6410/
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/THECUS N2100 MACHINE SUPPORT
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/NUVOTON W90X900 ARM ARCHITECTURE
-P: Wan ZongShun
-M: mcuos.com@gmail.com
+M: Wan ZongShun <mcuos.com@gmail.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.mcuos.com
S: Maintained
ARM/VFP SUPPORT
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
F: arch/arm/vfp/
-ARPD SUPPORT
-P: Jonathan Layes
-L: netdev@vger.kernel.org
-S: Maintained
-F: net/ipv4/arp.c
-
ASUS ACPI EXTRAS DRIVER
-P: Corentin Chary
-M: corentincj@iksaif.net
-P: Karol Kozimor
-M: sziwan@users.sourceforge.net
+M: Corentin Chary <corentincj@iksaif.net>
+M: Karol Kozimor <sziwan@users.sourceforge.net>
L: acpi4asus-user@lists.sourceforge.net
W: http://acpi4asus.sf.net
S: Maintained
@@ -969,25 +850,21 @@ F: arch/x86/kernel/acpi/boot.c
F: drivers/platform/x86/asus_acpi.c
ASUS ASB100 HARDWARE MONITOR DRIVER
-P: Mark M. Hoffman
-M: mhoffman@lightlink.com
+M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/asb100.c
ASUS LAPTOP EXTRAS DRIVER
-P: Corentin Chary
-M: corentincj@iksaif.net
+M: Corentin Chary <corentincj@iksaif.net>
L: acpi4asus-user@lists.sourceforge.net
W: http://acpi4asus.sf.net
S: Maintained
F: drivers/platform/x86/asus-laptop.c
ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
-P: Dan Williams
-M: dan.j.williams@intel.com
-P: Maciej Sosnowski
-M: maciej.sosnowski@intel.com
+M: Dan Williams <dan.j.williams@intel.com>
+M: Maciej Sosnowski <maciej.sosnowski@intel.com>
W: http://sourceforge.net/projects/xscaleiop
S: Supported
F: Documentation/crypto/async-tx-api.txt
@@ -997,64 +874,49 @@ F: include/linux/dmaengine.h
F: include/linux/async_tx.h
ATA OVER ETHERNET (AOE) DRIVER
-P: Ed L. Cashin
-M: ecashin@coraid.com
+M: "Ed L. Cashin" <ecashin@coraid.com>
W: http://www.coraid.com/support/linux
S: Supported
F: Documentation/aoe/
F: drivers/block/aoe/
ATHEROS ATH5K WIRELESS DRIVER
-P: Jiri Slaby
-M: jirislaby@gmail.com
-P: Nick Kossifidis
-M: mickflemm@gmail.com
-P: Luis R. Rodriguez
-M: lrodriguez@atheros.com
-P: Bob Copeland
-M: me@bobcopeland.com
+M: Jiri Slaby <jirislaby@gmail.com>
+M: Nick Kossifidis <mickflemm@gmail.com>
+M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
+M: Bob Copeland <me@bobcopeland.com>
L: linux-wireless@vger.kernel.org
L: ath5k-devel@lists.ath5k.org
S: Maintained
F: drivers/net/wireless/ath/ath5k/
ATHEROS ATH9K WIRELESS DRIVER
-P: Luis R. Rodriguez
-M: lrodriguez@atheros.com
-P: Jouni Malinen
-M: jmalinen@atheros.com
-P: Sujith Manoharan
-M: Sujith.Manoharan@atheros.com
-P: Vasanthakumar Thiagarajan
-M: vasanth@atheros.com
-P: Senthil Balasubramanian
-M: senthilkumar@atheros.com
+M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
+M: Jouni Malinen <jmalinen@atheros.com>
+M: Sujith Manoharan <Sujith.Manoharan@atheros.com>
+M: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+M: Senthil Balasubramanian <senthilkumar@atheros.com>
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
S: Supported
F: drivers/net/wireless/ath/ath9k/
ATHEROS AR9170 WIRELESS DRIVER
-P: Christian Lamparter
-M: chunkeey@web.de
+M: Christian Lamparter <chunkeey@web.de>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/ar9170
S: Maintained
F: drivers/net/wireless/ath/ar9170/
ATI_REMOTE2 DRIVER
-P: Ville Syrjala
-M: syrjala@sci.fi
+M: Ville Syrjala <syrjala@sci.fi>
S: Maintained
F: drivers/input/misc/ati_remote2.c
ATLX ETHERNET DRIVERS
-P: Jay Cliburn
-M: jcliburn@gmail.com
-P: Chris Snook
-M: csnook@redhat.com
-P: Jie Yang
-M: jie.yang@atheros.com
+M: Jay Cliburn <jcliburn@gmail.com>
+M: Chris Snook <csnook@redhat.com>
+M: Jie Yang <jie.yang@atheros.com>
L: atl1-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/atl1
W: http://atl1.sourceforge.net
@@ -1062,8 +924,7 @@ S: Maintained
F: drivers/net/atlx/
ATM
-P: Chas Williams
-M: chas@cmf.nrl.navy.mil
+M: Chas Williams <chas@cmf.nrl.navy.mil>
L: linux-atm-general@lists.sourceforge.net (subscribers-only)
L: netdev@vger.kernel.org
W: http://linux-atm.sourceforge.net
@@ -1072,8 +933,7 @@ F: drivers/atm/
F: include/linux/atm*
ATMEL AT91 MCI DRIVER
-P: Nicolas Ferre
-M: nicolas.ferre@atmel.com
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.atmel.com/products/AT91/
W: http://www.at91.com/
@@ -1081,49 +941,42 @@ S: Maintained
F: drivers/mmc/host/at91_mci.c
ATMEL AT91 / AT32 MCI DRIVER
-P: Nicolas Ferre
-M: nicolas.ferre@atmel.com
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Maintained
F: drivers/mmc/host/atmel-mci.c
F: drivers/mmc/host/atmel-mci-regs.h
ATMEL AT91 / AT32 SERIAL DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
S: Supported
F: drivers/serial/atmel_serial.c
ATMEL LCDFB DRIVER
-P: Nicolas Ferre
-M: nicolas.ferre@atmel.com
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/atmel_lcdfb.c
F: include/video/atmel_lcdc.h
ATMEL MACB ETHERNET DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
S: Supported
F: drivers/net/macb.*
ATMEL SPI DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
S: Supported
F: drivers/spi/atmel_spi.*
ATMEL USBA UDC DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
L: kernel@avr32linux.org
W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
S: Supported
F: drivers/usb/gadget/atmel_usba_udc.*
ATMEL WIRELESS DRIVER
-P: Simon Kelley
-M: simon@thekelleys.org.uk
+M: Simon Kelley <simon@thekelleys.org.uk>
L: linux-wireless@vger.kernel.org
W: http://www.thekelleys.org.uk/atmel
W: http://atmelwlandriver.sourceforge.net/
@@ -1131,10 +984,8 @@ S: Maintained
F: drivers/net/wireless/atmel*
AUDIT SUBSYSTEM
-P: Al Viro
-M: viro@zeniv.linux.org.uk
-P: Eric Paris
-M: eparis@redhat.com
+M: Al Viro <viro@zeniv.linux.org.uk>
+M: Eric Paris <eparis@redhat.com>
L: linux-audit@redhat.com (subscribers-only)
W: http://people.redhat.com/sgrubb/audit/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current.git
@@ -1143,8 +994,7 @@ F: include/linux/audit.h
F: kernel/audit*
AUXILIARY DISPLAY DRIVERS
-P: Miguel Ojeda Sandonis
-M: miguel.ojeda.sandonis@gmail.com
+M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
W: http://miguelojeda.es/auxdisplay.htm
W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
S: Maintained
@@ -1152,8 +1002,7 @@ F: drivers/auxdisplay/
F: include/linux/cfag12864b.h
AVR32 ARCHITECTURE
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
W: http://www.atmel.com/products/AVR32/
W: http://avr32linux.org/
W: http://avrfreaks.net/
@@ -1161,14 +1010,12 @@ S: Supported
F: arch/avr32/
AVR32/AT32AP MACHINE SUPPORT
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
S: Supported
F: arch/avr32/mach-at32ap/
AX.25 NETWORK LAYER
-P: Ralf Baechle
-M: ralf@linux-mips.org
+M: Ralf Baechle <ralf@linux-mips.org>
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
@@ -1177,128 +1024,110 @@ F: include/net/ax25.h
F: net/ax25/
B43 WIRELESS DRIVER
-P: Michael Buesch
-M: mb@bu3sch.de
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
+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
S: Maintained
F: drivers/net/wireless/b43/
B43LEGACY WIRELESS DRIVER
-P: Larry Finger
-M: Larry.Finger@lwfinger.net
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
+M: Larry Finger <Larry.Finger@lwfinger.net>
+M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/users/Drivers/b43
S: Maintained
F: drivers/net/wireless/b43legacy/
BACKLIGHT CLASS/SUBSYSTEM
-P: Richard Purdie
-M: rpurdie@rpsys.net
+M: Richard Purdie <rpurdie@rpsys.net>
S: Maintained
F: drivers/video/backlight/
F: include/linux/backlight.h
BAYCOM/HDLCDRV DRIVERS FOR AX.25
-P: Thomas Sailer
-M: t.sailer@alumni.ethz.ch
+M: Thomas Sailer <t.sailer@alumni.ethz.ch>
L: linux-hams@vger.kernel.org
W: http://www.baycom.org/~tom/ham/ham.html
S: Maintained
F: drivers/net/hamradio/baycom*
BEFS FILE SYSTEM
-P: Sergey S. Kostyliov
-M: rathamahata@php4.ru
+M: "Sergey S. Kostyliov" <rathamahata@php4.ru>
S: Maintained
F: Documentation/filesystems/befs.txt
F: fs/befs/
BFS FILE SYSTEM
-P: Tigran A. Aivazian
-M: tigran@aivazian.fsnet.co.uk
+M: "Tigran A. Aivazian" <tigran@aivazian.fsnet.co.uk>
S: Maintained
F: Documentation/filesystems/bfs.txt
F: fs/bfs/
F: include/linux/bfs_fs.h
BLACKFIN ARCHITECTURE
-P: Mike Frysinger
-M: vapier@gentoo.org
+M: Mike Frysinger <vapier@gentoo.org>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
F: arch/blackfin/
BLACKFIN EMAC DRIVER
-P: Michael Hennerich
-M: michael.hennerich@analog.com
+M: Michael Hennerich <michael.hennerich@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
F: drivers/net/bfin_mac.*
BLACKFIN RTC DRIVER
-P: Mike Frysinger
-M: vapier.adi@gmail.com
+M: Mike Frysinger <vapier.adi@gmail.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
F: drivers/rtc/rtc-bfin.c
BLACKFIN SERIAL DRIVER
-P: Sonic Zhang
-M: sonic.zhang@analog.com
+M: Sonic Zhang <sonic.zhang@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
F: drivers/serial/bfin_5xx.c
BLACKFIN WATCHDOG DRIVER
-P: Mike Frysinger
-M: vapier.adi@gmail.com
+M: Mike Frysinger <vapier.adi@gmail.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
F: drivers/watchdog/bfin_wdt.c
BLACKFIN I2C TWI DRIVER
-P: Sonic Zhang
-M: sonic.zhang@analog.com
+M: Sonic Zhang <sonic.zhang@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org/
S: Supported
F: drivers/i2c/busses/i2c-bfin-twi.c
BLOCK LAYER
-P: Jens Axboe
-M: axboe@kernel.dk
+M: Jens Axboe <axboe@kernel.dk>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
S: Maintained
F: block/
BLOCK2MTD DRIVER
-P: Joern Engel
-M: joern@lazybastard.org
+M: Joern Engel <joern@lazybastard.org>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/devices/block2mtd.c
BLUETOOTH DRIVERS
-P: Marcel Holtmann
-M: marcel@holtmann.org
+M: Marcel Holtmann <marcel@holtmann.org>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
S: Maintained
F: drivers/bluetooth/
BLUETOOTH SUBSYSTEM
-P: Marcel Holtmann
-M: marcel@holtmann.org
+M: Marcel Holtmann <marcel@holtmann.org>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git
@@ -1307,8 +1136,7 @@ F: net/bluetooth/
F: include/net/bluetooth/
BONDING DRIVER
-P: Jay Vosburgh
-M: fubar@us.ibm.com
+M: Jay Vosburgh <fubar@us.ibm.com>
L: bonding-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/bonding/
S: Supported
@@ -1316,54 +1144,46 @@ F: drivers/net/bonding/
F: include/linux/if_bonding.h
BROADCOM B44 10/100 ETHERNET DRIVER
-P: Gary Zambrano
-M: zambrano@broadcom.com
+M: Gary Zambrano <zambrano@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/b44.*
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
-P: Michael Chan
-M: mchan@broadcom.com
+M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/bnx2.*
F: drivers/net/bnx2_*
BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
-P: Eilon Greenstein
-M: eilong@broadcom.com
+M: Eilon Greenstein <eilong@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/bnx2x*
BROADCOM TG3 GIGABIT ETHERNET DRIVER
-P: Matt Carlson
-M: mcarlson@broadcom.com
-P: Michael Chan
-M: mchan@broadcom.com
+M: Matt Carlson <mcarlson@broadcom.com>
+M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/tg3.*
BSG (block layer generic sg v4 driver)
-P: FUJITA Tomonori
-M: fujita.tomonori@lab.ntt.co.jp
+M: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
L: linux-scsi@vger.kernel.org
S: Supported
F: block/bsg.c
F: include/linux/bsg.h
BT8XXGPIO DRIVER
-P: Michael Buesch
-M: mb@bu3sch.de
+M: Michael Buesch <mb@bu3sch.de>
W: http://bu3sch.de/btgpio.php
S: Maintained
F: drivers/gpio/bt8xxgpio.c
BTRFS FILE SYSTEM
-P: Chris Mason
-M: chris.mason@oracle.com
+M: Chris Mason <chris.mason@oracle.com>
L: linux-btrfs@vger.kernel.org
W: http://btrfs.wiki.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable.git
@@ -1372,8 +1192,7 @@ F: Documentation/filesystems/btrfs.txt
F: fs/btrfs/
BTTV VIDEO4LINUX DRIVER
-P: Mauro Carvalho Chehab
-M: mchehab@infradead.org
+M: Mauro Carvalho Chehab <mchehab@infradead.org>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -1382,16 +1201,14 @@ F: Documentation/video4linux/bttv/
F: drivers/media/video/bt8xx/bttv*
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
-P: David Howells
-M: dhowells@redhat.com
+M: David Howells <dhowells@redhat.com>
L: linux-cachefs@redhat.com
S: Supported
F: Documentation/filesystems/caching/cachefiles.txt
F: fs/cachefiles/
CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
-P: Jonathan Corbet
-M: corbet@lwn.net
+M: Jonathan Corbet <corbet@lwn.net>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
@@ -1399,10 +1216,8 @@ F: Documentation/video4linux/cafe_ccic
F: drivers/media/video/cafe_ccic*
CALGARY x86-64 IOMMU
-P: Muli Ben-Yehuda
-M: muli@il.ibm.com
-P: Jon D. Mason
-M: jdmason@kudzu.us
+M: Muli Ben-Yehuda <muli@il.ibm.com>
+M: "Jon D. Mason" <jdmason@kudzu.us>
L: discuss@x86-64.org
S: Maintained
F: arch/x86/kernel/pci-calgary_64.c
@@ -1411,10 +1226,8 @@ F: arch/x86/include/asm/calgary.h
F: arch/x86/include/asm/tce.h
CAN NETWORK LAYER
-P: Urs Thuermann
-M: urs.thuermann@volkswagen.de
-P: Oliver Hartkopp
-M: oliver.hartkopp@volkswagen.de
+M: Urs Thuermann <urs.thuermann@volkswagen.de>
+M: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
L: socketcan-core@lists.berlios.de (subscribers-only)
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@@ -1423,15 +1236,13 @@ F: include/linux/can/
F: include/linux/can.h
CAN NETWORK DRIVERS
-P: Wolfgang Grandegger
-M: wg@grandegger.com
+M: Wolfgang Grandegger <wg@grandegger.com>
L: socketcan-core@lists.berlios.de (subscribers-only)
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
CELL BROADBAND ENGINE ARCHITECTURE
-P: Arnd Bergmann
-M: arnd@arndb.de
+M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@ozlabs.org
L: cbe-oss-dev@ozlabs.org
W: http://www.ibm.com/developerworks/power/cell/
@@ -1442,8 +1253,7 @@ F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
-P: David Vrabel
-M: david.vrabel@csr.com
+M: David Vrabel <david.vrabel@csr.com>
L: linux-usb@vger.kernel.org
S: Supported
F: Documentation/usb/WUSB-Design-overview.txt
@@ -1452,8 +1262,7 @@ F: drivers/usb/wusbcore/
F: include/linux/usb/wusb*
CFAG12864B LCD DRIVER
-P: Miguel Ojeda Sandonis
-M: miguel.ojeda.sandonis@gmail.com
+M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
W: http://miguelojeda.es/auxdisplay.htm
W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
S: Maintained
@@ -1461,8 +1270,7 @@ F: drivers/auxdisplay/cfag12864b.c
F: include/linux/cfag12864b.h
CFAG12864BFB LCD FRAMEBUFFER DRIVER
-P: Miguel Ojeda Sandonis
-M: miguel.ojeda.sandonis@gmail.com
+M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
W: http://miguelojeda.es/auxdisplay.htm
W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
S: Maintained
@@ -1470,8 +1278,7 @@ F: drivers/auxdisplay/cfag12864bfb.c
F: include/linux/cfag12864b.h
CFG80211 and NL80211
-P: Johannes Berg
-M: johannes@sipsolutions.net
+M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
S: Maintained
F: include/linux/nl80211.h
@@ -1480,66 +1287,47 @@ F: net/wireless/*
X: net/wireless/wext*
CHECKPATCH
-P: Andy Whitcroft
-M: apw@canonical.com
+M: Andy Whitcroft <apw@canonical.com>
S: Supported
F: scripts/checkpatch.pl
CISCO 10G ETHERNET DRIVER
-P: Scott Feldman
-M: scofeldm@cisco.com
-P: Joe Eykholt
-M: jeykholt@cisco.com
+M: Scott Feldman <scofeldm@cisco.com>
+M: Joe Eykholt <jeykholt@cisco.com>
S: Supported
F: drivers/net/enic/
CIRRUS LOGIC EP93XX ETHERNET DRIVER
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/arm/ep93xx_eth.c
CIRRUS LOGIC EP93XX OHCI USB HOST DRIVER
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/host/ohci-ep93xx.c
CIRRUS LOGIC CS4270 SOUND DRIVER
-P: Timur Tabi
-M: timur@freescale.com
+M: Timur Tabi <timur@freescale.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/codecs/cs4270*
-CIRRUS LOGIC CS4280/CS461x SOUNDDRIVER
-P: Cirrus Logic Corporation (kernel 2.2 driver)
-M: Cirrus Logic Corporation, Thomas Woller <twoller@crystal.cirrus.com>
-P: Nils Faerber (port to kernel 2.4)
-M: Nils Faerber <nils@kernelconcepts.de>
-S: Maintained
-F: Documentation/input/cs461x.txt
-F: sound/pci/cs46xx/
-
CLK API
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
F: include/linux/clk.h
CISCO FCOE HBA DRIVER
-P: Abhijeet Joglekar
-M: abjoglek@cisco.com
-P: Joe Eykholt
-M: jeykholt@cisco.com
+M: Abhijeet Joglekar <abjoglek@cisco.com>
+M: Joe Eykholt <jeykholt@cisco.com>
L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/fnic/
CODA FILE SYSTEM
-P: Jan Harkes
-M: jaharkes@cs.cmu.edu
+M: Jan Harkes <jaharkes@cs.cmu.edu>
M: coda@cs.cmu.edu
L: codalist@coda.cs.cmu.edu
W: http://www.coda.cs.cmu.edu/
@@ -1549,8 +1337,7 @@ F: fs/coda/
F: include/linux/coda*.h
COMMON INTERNET FILE SYSTEM (CIFS)
-P: Steve French
-M: sfrench@samba.org
+M: Steve French <sfrench@samba.org>
L: linux-cifs-client@lists.samba.org
L: samba-technical@lists.samba.org
W: http://linux-cifs.samba.org/
@@ -1560,70 +1347,57 @@ F: Documentation/filesystems/cifs.txt
F: fs/cifs/
COMPACTPCI HOTPLUG CORE
-P: Scott Murray
-M: scottm@somanetworks.com
-M: scott@spiteful.org
+M: Scott Murray <scott@spiteful.org>
L: linux-pci@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/pci/hotplug/cpci_hotplug*
COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
-P: Scott Murray
-M: scottm@somanetworks.com
-M: scott@spiteful.org
+M: Scott Murray <scott@spiteful.org>
L: linux-pci@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/pci/hotplug/cpcihp_zt5550.*
COMPACTPCI HOTPLUG GENERIC DRIVER
-P: Scott Murray
-M: scottm@somanetworks.com
-M: scott@spiteful.org
+M: Scott Murray <scott@spiteful.org>
L: linux-pci@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/pci/hotplug/cpcihp_generic.c
COMPAL LAPTOP SUPPORT
-P: Cezary Jackiewicz
-M: cezary.jackiewicz@gmail.com
+M: Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
S: Maintained
F: drivers/platform/x86/compal-laptop.c
COMPUTONE INTELLIPORT MULTIPORT CARD
-P: Michael H. Warfield
-M: mhw@wittsend.com
+M: "Michael H. Warfield" <mhw@wittsend.com>
W: http://www.wittsend.com/computone.html
S: Maintained
F: Documentation/serial/computone.txt
F: drivers/char/ip2/
CONEXANT ACCESSRUNNER USB DRIVER
-P: Simon Arlott
-M: cxacru@fire.lp0.eu
+M: Simon Arlott <cxacru@fire.lp0.eu>
L: accessrunner-general@lists.sourceforge.net
W: http://accessrunner.sourceforge.net/
S: Maintained
F: drivers/usb/atm/cxacru.c
CONFIGFS
-P: Joel Becker
-M: joel.becker@oracle.com
+M: Joel Becker <joel.becker@oracle.com>
S: Supported
F: fs/configfs/
F: include/linux/configfs.h
CONNECTOR
-P: Evgeniy Polyakov
-M: zbr@ioremap.net
+M: Evgeniy Polyakov <zbr@ioremap.net>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/connector/
CONTROL GROUPS (CGROUPS)
-P: Paul Menage
-M: menage@google.com
-P: Li Zefan
-M: lizf@cn.fujitsu.com
+M: Paul Menage <menage@google.com>
+M: Li Zefan <lizf@cn.fujitsu.com>
L: containers@lists.linux-foundation.org
S: Maintained
F: include/linux/cgroup*
@@ -1631,30 +1405,26 @@ F: kernel/cgroup*
F: mm/*cgroup*
CORETEMP HARDWARE MONITORING DRIVER
-P: Rudolf Marek
-M: r.marek@assembler.cz
+M: Rudolf Marek <r.marek@assembler.cz>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/coretemp
F: drivers/hwmon/coretemp.c
COSA/SRP SYNC SERIAL DRIVER
-P: Jan "Yenya" Kasprzak
-M: kas@fi.muni.cz
+M: Jan "Yenya" Kasprzak <kas@fi.muni.cz>
W: http://www.fi.muni.cz/~kas/cosa/
S: Maintained
F: drivers/net/wan/cosa*
CPMAC ETHERNET DRIVER
-P: Florian Fainelli
-M: florian@openwrt.org
+M: Florian Fainelli <florian@openwrt.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/cpmac.c
CPU FREQUENCY DRIVERS
-P: Dave Jones
-M: davej@redhat.com
+M: Dave Jones <davej@redhat.com>
L: cpufreq@vger.kernel.org
W: http://www.codemonkey.org.uk/projects/cpufreq/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq.git
@@ -1664,15 +1434,13 @@ F: drivers/cpufreq/
F: include/linux/cpufreq.h
CPUID/MSR DRIVER
-P: H. Peter Anvin
-M: hpa@zytor.com
+M: "H. Peter Anvin" <hpa@zytor.com>
S: Maintained
F: arch/x86/kernel/cpuid.c
F: arch/x86/kernel/msr.c
CPUSETS
-P: Paul Menage
-M: menage@google.com
+M: Paul Menage <menage@google.com>
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
S: Supported
@@ -1687,20 +1455,16 @@ F: Documentation/filesystems/cramfs.txt
F: fs/cramfs/
CRIS PORT
-P: Mikael Starvik
-M: starvik@axis.com
-P: Jesper Nilsson
-M: jesper.nilsson@axis.com
+M: Mikael Starvik <starvik@axis.com>
+M: Jesper Nilsson <jesper.nilsson@axis.com>
L: linux-cris-kernel@axis.com
W: http://developer.axis.com
S: Maintained
F: arch/cris/
CRYPTO API
-P: Herbert Xu
-M: herbert@gondor.apana.org.au
-P: David S. Miller
-M: davem@davemloft.net
+M: Herbert Xu <herbert@gondor.apana.org.au>
+M: "David S. Miller" <davem@davemloft.net>
L: linux-crypto@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git
S: Maintained
@@ -1711,58 +1475,50 @@ F: drivers/crypto/
F: include/crypto/
CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
-P: Neil Horman
-M: nhorman@tuxdriver.com
+M: Neil Horman <nhorman@tuxdriver.com>
L: linux-crypto@vger.kernel.org
S: Maintained
CS5535 Audio ALSA driver
-P: Jaya Kumar
-M: jayakumar.alsa@gmail.com
+M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained
F: sound/pci/cs5535audio/
CX18 VIDEO4LINUX DRIVER
-P: Hans Verkuil
-M: hverkuil@xs4all.nl
-P: Andy Walls
-M: awalls@radix.net
+M: Hans Verkuil <hverkuil@xs4all.nl>
+M: Andy Walls <awalls@radix.net>
L: ivtv-devel@ivtvdriver.org
-L: ivtv-users@ivtvdriver.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
W: http://linuxtv.org
+W: http://www.ivtvdriver.org/index.php/Cx18
S: Maintained
F: Documentation/video4linux/cx18.txt
F: drivers/media/video/cx18/
CXGB3 ETHERNET DRIVER (CXGB3)
-P: Divy Le Ray
-M: divy@chelsio.com
+M: Divy Le Ray <divy@chelsio.com>
L: netdev@vger.kernel.org
W: http://www.chelsio.com
S: Supported
F: drivers/net/cxgb3/
CXGB3 IWARP RNIC DRIVER (IW_CXGB3)
-P: Steve Wise
-M: swise@chelsio.com
+M: Steve Wise <swise@chelsio.com>
L: general@lists.openfabrics.org
W: http://www.openfabrics.org
S: Supported
F: drivers/infiniband/hw/cxgb3/
CYBERPRO FB DRIVER
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
F: drivers/video/cyber2000fb.*
CYCLADES 2X SYNC CARD DRIVER
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
W: http://oops.ghostprotocols.net:81/blog
S: Maintained
F: drivers/net/wan/cycx*
@@ -1779,8 +1535,7 @@ S: Orphan
F: drivers/net/wan/pc300*
DAMA SLAVE for AX.25
-P: Joerg Reuter
-M: jreuter@yaina.de
+M: Joerg Reuter <jreuter@yaina.de>
W: http://yaina.de/jreuter/
W: http://www.qsl.net/dl1bke/
L: linux-hams@vger.kernel.org
@@ -1794,29 +1549,23 @@ F: net/ax25/ax25_timer.c
F: net/ax25/sysctl_net_ax25.c
DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-P: Tobias Ringstrom
-M: tori@unhappy.mine.nu
+M: Tobias Ringstrom <tori@unhappy.mine.nu>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/dmfe.txt
F: drivers/net/tulip/dmfe.c
DC390/AM53C974 SCSI driver
-P: Kurt Garloff
-M: garloff@suse.de
+M: Kurt Garloff <garloff@suse.de>
W: http://www.garloff.de/kurt/linux/dc390/
-P: Guennadi Liakhovetski
-M: g.liakhovetski@gmx.de
+M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
S: Maintained
F: drivers/scsi/tmscsim.*
DC395x SCSI driver
-P: Oliver Neukum
-M: oliver@neukum.name
-P: Ali Akcaagac
-M: aliakc@web.de
-P: Jamie Lenehan
-M: lenehan@twibble.org
+M: Oliver Neukum <oliver@neukum.name>
+M: Ali Akcaagac <aliakc@web.de>
+M: Jamie Lenehan <lenehan@twibble.org>
W: http://twibble.org/dist/dc395x/
L: dc395x@twibble.org
L: http://lists.twibble.org/mailman/listinfo/dc395x/
@@ -1825,8 +1574,7 @@ F: Documentation/scsi/dc395x.txt
F: drivers/scsi/dc395x.*
DCCP PROTOCOL
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: dccp@vger.kernel.org
W: http://linux-net.osdl.org/index.php/DCCP
S: Maintained
@@ -1835,8 +1583,7 @@ F: include/linux/tfrc.h
F: net/dccp/
DECnet NETWORK LAYER
-P: Christine Caulfield
-M: christine.caulfield@googlemail.com
+M: Christine Caulfield <christine.caulfield@googlemail.com>
W: http://linux-decnet.sourceforge.net
L: linux-decnet-user@lists.sourceforge.net
S: Maintained
@@ -1844,40 +1591,34 @@ F: Documentation/networking/decnet.txt
F: net/decnet/
DEFXX FDDI NETWORK DRIVER
-P: Maciej W. Rozycki
-M: macro@linux-mips.org
+M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/net/defxx.*
DELL LAPTOP DRIVER
-P: Matthew Garrett
-M: mjg59@srcf.ucam.org
+M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained
F: drivers/platform/x86/dell-laptop.c
DELL LAPTOP SMM DRIVER
-P: Massimo Dal Zotto
-M: dz@debian.org
+M: Massimo Dal Zotto <dz@debian.org>
W: http://www.debian.org/~dz/i8k/
S: Maintained
F: drivers/char/i8k.c
F: include/linux/i8k.h
DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
-P: Doug Warzecha
-M: Douglas_Warzecha@dell.com
+M: Doug Warzecha <Douglas_Warzecha@dell.com>
S: Maintained
F: Documentation/dcdbas.txt
F: drivers/firmware/dcdbas.*
DELL WMI EXTRAS DRIVER
-P: Matthew Garrett
-M: mjg59@srcf.ucam.org
+M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained
DEVICE NUMBER REGISTRY
-P: Torben Mathiasen
-M: device@lanana.org
+M: Torben Mathiasen <device@lanana.org>
W: http://lanana.org/docs/device-list/index.html
S: Maintained
@@ -1892,8 +1633,7 @@ F: include/linux/device-mapper.h
F: include/linux/dm-*.h
DIGI INTL. EPCA DRIVER
-P: Digi International, Inc
-M: Eng.Linux@digi.com
+M: "Digi International, Inc" <Eng.Linux@digi.com>
L: Eng.Linux@digi.com
W: http://www.digi.com
S: Orphan
@@ -1902,34 +1642,29 @@ F: drivers/char/epca*
F: drivers/char/digi*
DIRECTORY NOTIFICATION (DNOTIFY)
-P: Eric Paris
-M: eparis@parisplace.org
+M: Eric Paris <eparis@parisplace.org>
S: Maintained
F: Documentation/filesystems/dnotify.txt
F: fs/notify/dnotify/
F: include/linux/dnotify.h
DISK GEOMETRY AND PARTITION HANDLING
-P: Andries Brouwer
-M: aeb@cwi.nl
+M: Andries Brouwer <aeb@cwi.nl>
W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html
W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
S: Maintained
DISKQUOTA
-P: Jan Kara
-M: jack@suse.cz
+M: Jan Kara <jack@suse.cz>
S: Maintained
F: Documentation/filesystems/quota.txt
F: fs/quota/
F: include/linux/quota*.h
DISTRIBUTED LOCK MANAGER (DLM)
-P: Christine Caulfield
-M: ccaulfie@redhat.com
-P: David Teigland
-M: teigland@redhat.com
+M: Christine Caulfield <ccaulfie@redhat.com>
+M: David Teigland <teigland@redhat.com>
L: cluster-devel@redhat.com
W: http://sources.redhat.com/cluster/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm.git
@@ -1937,61 +1672,65 @@ S: Supported
F: fs/dlm/
DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
-P: Maciej Sosnowski
-M: maciej.sosnowski@intel.com
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Maciej Sosnowski <maciej.sosnowski@intel.com>
+M: Dan Williams <dan.j.williams@intel.com>
S: Supported
F: drivers/dma/
F: include/linux/dma*
DME1737 HARDWARE MONITOR DRIVER
-P: Juerg Haefliger
-M: juergh@gmail.com
+M: Juerg Haefliger <juergh@gmail.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/dme1737
F: drivers/hwmon/dme1737.c
DOCBOOK FOR DOCUMENTATION
-P: Randy Dunlap
-M: rdunlap@xenotime.net
+M: Randy Dunlap <rdunlap@xenotime.net>
S: Maintained
DOCKING STATION DRIVER
-P: Shaohua Li
-M: shaohua.li@intel.com
+M: Shaohua Li <shaohua.li@intel.com>
L: linux-acpi@vger.kernel.org
S: Supported
F: drivers/acpi/dock.c
DOCUMENTATION
-P: Randy Dunlap
-M: rdunlap@xenotime.net
+M: Randy Dunlap <rdunlap@xenotime.net>
L: linux-doc@vger.kernel.org
S: Maintained
F: Documentation/
DOUBLETALK DRIVER
-P: James R. Van Zandt
-M: jrv@vanzandt.mv.com
+M: "James R. Van Zandt" <jrv@vanzandt.mv.com>
L: blinux-list@redhat.com
S: Maintained
F: drivers/char/dtlk.c
F: include/linux/dtlk.h
DPT_I2O SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
+M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
L: linux-scsi@vger.kernel.org
W: http://www.adaptec.com/
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
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+M: Greg Kroah-Hartman <gregkh@suse.de>
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
S: Supported
F: Documentation/kobject.txt
@@ -2001,52 +1740,45 @@ F: include/linux/kobj*
F: lib/kobj*
DRM DRIVERS
-P: David Airlie
-M: airlied@linux.ie
+M: David Airlie <airlied@linux.ie>
L: dri-devel@lists.sourceforge.net
T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
S: Maintained
F: drivers/gpu/drm/
DSCC4 DRIVER
-P: Francois Romieu
-M: romieu@fr.zoreil.com
+M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/wan/dscc4.c
DZ DECSTATION DZ11 SERIAL DRIVER
-P: Maciej W. Rozycki
-M: macro@linux-mips.org
+M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/serial/dz.*
EATA-DMA SCSI DRIVER
-P: Michael Neuffer
-M: mike@i-Connect.Net
+M: Michael Neuffer <mike@i-Connect.Net>
L: linux-eata@i-connect.net
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/eata*
EATA ISA/EISA/PCI SCSI DRIVER
-P: Dario Ballabio
-M: ballabio_dario@emc.com
+M: Dario Ballabio <ballabio_dario@emc.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/eata.c
EATA-PIO SCSI DRIVER
-P: Michael Neuffer
-M: mike@i-Connect.Net
+M: Michael Neuffer <mike@i-Connect.Net>
L: linux-eata@i-connect.net
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/eata_pio.*
EBTABLES
-P: Bart De Schuymer
-M: bart.de.schuymer@pandora.be
+M: Bart De Schuymer <bart.de.schuymer@pandora.be>
L: ebtables-user@lists.sourceforge.net
L: ebtables-devel@lists.sourceforge.net
W: http://ebtables.sourceforge.net/
@@ -2055,10 +1787,8 @@ F: include/linux/netfilter_bridge/ebt_*.h
F: net/bridge/netfilter/ebt*.c
ECRYPT FILE SYSTEM
-P: Tyler Hicks
-M: tyhicks@linux.vnet.ibm.com
-P: Dustin Kirkland
-M: kirkland@canonical.com
+M: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
+M: Dustin Kirkland <kirkland@canonical.com>
L: ecryptfs-devel@lists.launchpad.net
W: https://launchpad.net/ecryptfs
S: Supported
@@ -2066,8 +1796,7 @@ F: Documentation/filesystems/ecryptfs.txt
F: fs/ecryptfs/
EDAC-CORE
-P: Doug Thompson
-M: dougthompson@xmission.com
+M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Supported
@@ -2076,94 +1805,80 @@ F: drivers/edac/edac_*
F: include/linux/edac.h
EDAC-AMD64
-P: Doug Thompson
-M: dougthompson@xmission.com
-P: Borislav Petkov
-M: borislav.petkov@amd.com
+M: Doug Thompson <dougthompson@xmission.com>
+M: Borislav Petkov <borislav.petkov@amd.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Supported
F: drivers/edac/amd64_edac*
EDAC-E752X
-P: Mark Gross
-M: mark.gross@intel.com
-P: Doug Thompson
-M: dougthompson@xmission.com
+M: Mark Gross <mark.gross@intel.com>
+M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e752x_edac.c
EDAC-E7XXX
-P: Doug Thompson
-M: dougthompson@xmission.com
+M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e7xxx_edac.c
EDAC-I82443BXGX
-P: Tim Small
-M: tim@buttersideup.com
+M: Tim Small <tim@buttersideup.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82443bxgx_edac.c
EDAC-I3000
-P: Jason Uhlenkott
-M: juhlenko@akamai.com
+M: Jason Uhlenkott <juhlenko@akamai.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i3000_edac.c
EDAC-I5000
-P: Doug Thompson
-M: dougthompson@xmission.com
+M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
-P: Mauro Carvalho Chehab
-M: mchehab@redhat.com
+M: Mauro Carvalho Chehab <mchehab@redhat.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I82975X
-P: Ranganathan Desikan
-M: ravi@jetztechnologies.com
-P: Arvind R.
-M: arvind@jetztechnologies.com
+M: Ranganathan Desikan <ravi@jetztechnologies.com>
+M: "Arvind R." <arvind@jetztechnologies.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82975x_edac.c
EDAC-PASEMI
-P: Egor Martovetsky
-M: egor@pasemi.com
+M: Egor Martovetsky <egor@pasemi.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/pasemi_edac.c
EDAC-R82600
-P: Tim Small
-M: tim@buttersideup.com
+M: Tim Small <tim@buttersideup.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/r82600_edac.c
EEEPC LAPTOP EXTRAS DRIVER
-P: Corentin Chary
-M: corentincj@iksaif.net
+M: Corentin Chary <corentincj@iksaif.net>
L: acpi4asus-user@lists.sourceforge.net
W: http://acpi4asus.sf.net
S: Maintained
@@ -2175,66 +1890,54 @@ S: Orphan
F: fs/efs/
EHCA (IBM GX bus InfiniBand adapter) DRIVER
-P: Hoang-Nam Nguyen
-M: hnguyen@de.ibm.com
-P: Christoph Raisch
-M: raisch@de.ibm.com
+M: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+M: Christoph Raisch <raisch@de.ibm.com>
L: general@lists.openfabrics.org
S: Supported
F: drivers/infiniband/hw/ehca/
EMBEDDED LINUX
-P: Paul Gortmaker
-M: paul.gortmaker@windriver.com
-P: Matt Mackall
-M: mpm@selenic.com
-P: David Woodhouse
-M: dwmw2@infradead.org
+M: Paul Gortmaker <paul.gortmaker@windriver.com>
+M: Matt Mackall <mpm@selenic.com>
+M: David Woodhouse <dwmw2@infradead.org>
L: linux-embedded@vger.kernel.org
S: Maintained
EMULEX LPFC FC SCSI DRIVER
-P: James Smart
-M: james.smart@emulex.com
+M: James Smart <james.smart@emulex.com>
L: linux-scsi@vger.kernel.org
W: http://sourceforge.net/projects/lpfcxxxx
S: Supported
F: drivers/scsi/lpfc/
ENE CB710 FLASH CARD READER DRIVER
-P: Michał Mirosław
-M: mirq-linux@rere.qmqm.pl
-L: linux-kernel@vger.kernel.org
+M: Michał Mirosław <mirq-linux@rere.qmqm.pl>
S: Maintained
F: drivers/misc/cb710/
F: drivers/mmc/host/cb710-mmc.*
F: include/linux/cb710.h
EPSON 1355 FRAMEBUFFER DRIVER
-P: Christopher Hoover
-M: ch@murgatroid.com
-P: Christopher Hoover
-M: ch@hpl.hp.com
+M: Christopher Hoover <ch@murgatroid.com>
+M: Christopher Hoover <ch@hpl.hp.com>
S: Maintained
F: drivers/video/epson1355fb.c
EPSON S1D13XXX FRAMEBUFFER DRIVER
-P: Kristoffer Ericson
-M: kristoffer.ericson@gmail.com
+M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
F: drivers/video/s1d13xxxfb.c
F: include/video/s1d13xxxfb.h
ETHEREXPRESS-16 NETWORK DRIVER
-P: Philip Blundell
-M: philb@gnu.org
+M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/eexpress.*
ETHERNET BRIDGE
-P: Stephen Hemminger
-M: shemminger@linux-foundation.org
+M: Stephen Hemminger <shemminger@linux-foundation.org>
L: bridge@lists.linux-foundation.org
W: http://www.linux-foundation.org/en/Net:Bridge
S: Maintained
@@ -2242,8 +1945,7 @@ F: include/linux/netfilter_bridge/
F: net/bridge/
ETHERTEAM 16I DRIVER
-P: Mika Kuoppala
-M: miku@iki.fi
+M: Mika Kuoppala <miku@iki.fi>
S: Maintained
F: drivers/net/eth16i.c
@@ -2255,12 +1957,9 @@ F: fs/ext2/
F: include/linux/ext2*
EXT3 FILE SYSTEM
-P: Stephen Tweedie
-M: sct@redhat.com
-P: Andrew Morton
-M: akpm@linux-foundation.org
-P: Andreas Dilger
-M: adilger@sun.com
+M: Stephen Tweedie <sct@redhat.com>
+M: Andrew Morton <akpm@linux-foundation.org>
+M: Andreas Dilger <adilger@sun.com>
L: linux-ext4@vger.kernel.org
S: Maintained
F: Documentation/filesystems/ext3.txt
@@ -2268,10 +1967,8 @@ F: fs/ext3/
F: include/linux/ext3*
EXT4 FILE SYSTEM
-P: Theodore Ts'o
-M: tytso@mit.edu
-P: Andreas Dilger
-M: adilger@sun.com
+M: "Theodore Ts'o" <tytso@mit.edu>
+M: Andreas Dilger <adilger@sun.com>
L: linux-ext4@vger.kernel.org
W: http://ext4.wiki.kernel.org
S: Maintained
@@ -2279,30 +1976,26 @@ F: Documentation/filesystems/ext4.txt
F: fs/ext4/
F71805F HARDWARE MONITORING DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
+M: Jean Delvare <khali@linux-fr.org>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/f71805f
F: drivers/hwmon/f71805f.c
FARSYNC SYNCHRONOUS DRIVER
-P: Kevin Curtis
-M: kevin.curtis@farsite.co.uk
+M: Kevin Curtis <kevin.curtis@farsite.co.uk>
W: http://www.farsite.co.uk/
S: Supported
F: drivers/net/wan/farsync.*
FAULT INJECTION SUPPORT
-P: Akinobu Mita
-M: akinobu.mita@gmail.com
+M: Akinobu Mita <akinobu.mita@gmail.com>
S: Supported
F: Documentation/fault-injection/
F: lib/fault-inject.c
FILE LOCKING (flock() and fcntl()/lockf())
-P: Matthew Wilcox
-M: matthew@wil.cx
+M: Matthew Wilcox <matthew@wil.cx>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: include/linux/fcntl.h
@@ -2311,25 +2004,21 @@ F: fs/fcntl.c
F: fs/locks.c
FILESYSTEMS (VFS and infrastructure)
-P: Alexander Viro
-M: viro@zeniv.linux.org.uk
+M: Alexander Viro <viro@zeniv.linux.org.uk>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: fs/*
FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
-P: Riku Voipio
-M: riku.vipio@iki.fi
+M: Riku Voipio <riku.vipio@iki.fi>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/f75375s.c
F: include/linux/f75375s.h
FIREWIRE SUBSYSTEM
-P: Kristian Hoegsberg
-M: krh@redhat.com
-P: Stefan Richter
-M: stefanr@s5r6.in-berlin.de
+M: Kristian Hoegsberg <krh@redhat.com>
+M: Stefan Richter <stefanr@s5r6.in-berlin.de>
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
@@ -2344,15 +2033,13 @@ F: drivers/base/firmware*.c
F: include/linux/firmware.h
FPU EMULATOR
-P: Bill Metzenthen
-M: billm@melbpc.org.au
+M: Bill Metzenthen <billm@melbpc.org.au>
W: http://floatingpoint.sourceforge.net/emulator/index.html
S: Maintained
F: arch/x86/math-emu/
FRAME RELAY DLCI/FRAD (Sangoma drivers too)
-P: Mike McLagan
-M: mike.mclagan@linux.org
+M: Mike McLagan <mike.mclagan@linux.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/wan/dlci.c
@@ -2367,25 +2054,21 @@ F: drivers/video/fb*
F: include/linux/fb.h
FREESCALE DMA DRIVER
-P: Li Yang
-M: leoli@freescale.com
-P: Zhang Wei
-M: zw@zh-kernel.org
+M: Li Yang <leoli@freescale.com>
+M: Zhang Wei <zw@zh-kernel.org>
L: linuxppc-dev@ozlabs.org
S: Maintained
F: drivers/dma/fsldma.*
FREESCALE I2C CPM DRIVER
-P: Jochen Friedrich
-M: jochen@scram.de
+M: Jochen Friedrich <jochen@scram.de>
L: linuxppc-dev@ozlabs.org
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-cpm.c
FREESCALE IMX / MXC FRAMEBUFFER DRIVER
-P: Sascha Hauer
-M: kernel@pengutronix.de
+M: Sascha Hauer <kernel@pengutronix.de>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
@@ -2393,10 +2076,8 @@ F: arch/arm/plat-mxc/include/mach/imxfb.h
F: drivers/video/imxfb.c
FREESCALE SOC FS_ENET DRIVER
-P: Pantelis Antoniou
-M: pantelis.antoniou@gmail.com
-P: Vitaly Bordug
-M: vbordug@ru.mvista.com
+M: Pantelis Antoniou <pantelis.antoniou@gmail.com>
+M: Vitaly Bordug <vbordug@ru.mvista.com>
L: linuxppc-dev@ozlabs.org
L: netdev@vger.kernel.org
S: Maintained
@@ -2404,39 +2085,34 @@ F: drivers/net/fs_enet/
F: include/linux/fs_enet_pd.h
FREESCALE QUICC ENGINE LIBRARY
-P: Timur Tabi
-M: timur@freescale.com
+M: Timur Tabi <timur@freescale.com>
L: linuxppc-dev@ozlabs.org
S: Supported
F: arch/powerpc/sysdev/qe_lib/
F: arch/powerpc/include/asm/*qe.h
FREESCALE HIGHSPEED USB DEVICE DRIVER
-P: Li Yang
-M: leoli@freescale.com
+M: Li Yang <leoli@freescale.com>
L: linux-usb@vger.kernel.org
L: linuxppc-dev@ozlabs.org
S: Maintained
F: drivers/usb/gadget/fsl_usb2_udc.c
FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
-P: Li Yang
-M: leoli@freescale.com
+M: Li Yang <leoli@freescale.com>
L: netdev@vger.kernel.org
L: linuxppc-dev@ozlabs.org
S: Maintained
F: drivers/net/ucc_geth*
FREESCALE QUICC ENGINE UCC UART DRIVER
-P: Timur Tabi
-M: timur@freescale.com
+M: Timur Tabi <timur@freescale.com>
L: linuxppc-dev@ozlabs.org
S: Supported
F: drivers/serial/ucc_uart.c
FREESCALE SOC SOUND DRIVERS
-P: Timur Tabi
-M: timur@freescale.com
+M: Timur Tabi <timur@freescale.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linuxppc-dev@ozlabs.org
S: Supported
@@ -2444,17 +2120,14 @@ F: sound/soc/fsl/fsl*
F: sound/soc/fsl/mpc8610_hpcd.c
FREEVXFS FILESYSTEM
-P: Christoph Hellwig
-M: hch@infradead.org
+M: Christoph Hellwig <hch@infradead.org>
W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
S: Maintained
F: fs/freevxfs/
FREEZER
-P: Pavel Machek
-M: pavel@ucw.cz
-P: Rafael J. Wysocki
-M: rjw@sisk.pl
+M: Pavel Machek <pavel@ucw.cz>
+M: "Rafael J. Wysocki" <rjw@sisk.pl>
L: linux-pm@lists.linux-foundation.org
S: Supported
F: Documentation/power/freezing-of-tasks.txt
@@ -2462,8 +2135,7 @@ F: include/linux/freezer.h
F: kernel/freezer.c
FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS
-P: David Howells
-M: dhowells@redhat.com
+M: David Howells <dhowells@redhat.com>
L: linux-cachefs@redhat.com
S: Supported
F: Documentation/filesystems/caching/
@@ -2471,8 +2143,7 @@ F: fs/fscache/
F: include/linux/fscache*.h
FTRACE
-P: Steven Rostedt
-M: rostedt@goodmis.org
+M: Steven Rostedt <rostedt@goodmis.org>
S: Maintained
F: Documentation/trace/ftrace.txt
F: arch/*/*/*/ftrace.h
@@ -2481,21 +2152,18 @@ F: include/*/ftrace.h
F: kernel/trace/
FUJITSU FR-V (FRV) PORT
-P: David Howells
-M: dhowells@redhat.com
+M: David Howells <dhowells@redhat.com>
S: Maintained
F: arch/frv/
FUJITSU LAPTOP EXTRAS
-P: Jonathan Woithe
-M: jwoithe@physics.adelaide.edu.au
+M: Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
L: linux-acpi@vger.kernel.org
S: Maintained
F: drivers/platform/x86/fujitsu-laptop.c
FUSE: FILESYSTEM IN USERSPACE
-P: Miklos Szeredi
-M: miklos@szeredi.hu
+M: Miklos Szeredi <miklos@szeredi.hu>
L: fuse-devel@lists.sourceforge.net
W: http://fuse.sourceforge.net/
S: Maintained
@@ -2503,30 +2171,26 @@ F: fs/fuse/
F: include/linux/fuse.h
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
-P: Rik Faith
-M: faith@cs.unc.edu
+M: Rik Faith <faith@cs.unc.edu>
L: linux-scsi@vger.kernel.org
S: Odd Fixes (e.g., new signatures)
F: drivers/scsi/fdomain.*
GDT SCSI DISK ARRAY CONTROLLER DRIVER
-P: Achim Leubner
-M: achim_leubner@adaptec.com
+M: Achim Leubner <achim_leubner@adaptec.com>
L: linux-scsi@vger.kernel.org
W: http://www.icp-vortex.com/
S: Supported
F: drivers/scsi/gdt*
GENERIC GPIO I2C DRIVER
-P: Haavard Skinnemoen
-M: hskinnemoen@atmel.com
+M: Haavard Skinnemoen <hskinnemoen@atmel.com>
S: Supported
F: drivers/i2c/busses/i2c-gpio.c
F: include/linux/i2c-gpio.h
GENERIC HDLC (WAN) DRIVERS
-P: Krzysztof Halasa
-M: khc@pm.waw.pl
+M: Krzysztof Halasa <khc@pm.waw.pl>
W: http://www.kernel.org/pub/linux/utils/net/hdlc/
S: Maintained
F: drivers/net/wan/c101.c
@@ -2538,16 +2202,14 @@ F: drivers/net/wan/pci200syn.c
F: drivers/net/wan/wanxl*
GENERIC INCLUDE/ASM HEADER FILES
-P: Arnd Bergmann
-M: arnd@arndb.de
+M: Arnd Bergmann <arnd@arndb.de>
L: linux-arch@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
S: Maintained
F: include/asm-generic
GFS2 FILE SYSTEM
-P: Steven Whitehouse
-M: swhiteho@redhat.com
+M: Steven Whitehouse <swhiteho@redhat.com>
L: cluster-devel@redhat.com
W: http://sources.redhat.com/cluster/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
@@ -2558,10 +2220,8 @@ F: fs/gfs2/
F: include/linux/gfs2_ondisk.h
GIGASET ISDN DRIVERS
-P: Hansjoerg Lipp
-M: hjlipp@web.de
-P: Tilman Schmidt
-M: tilman@imap.cc
+M: Hansjoerg Lipp <hjlipp@web.de>
+M: Tilman Schmidt <tilman@imap.cc>
L: gigaset307x-common@lists.sourceforge.net
W: http://gigaset307x.sourceforge.net/
S: Maintained
@@ -2570,53 +2230,64 @@ F: drivers/isdn/gigaset/
F: include/linux/gigaset_dev.h
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-P: Frank Seidel
-M: frank@f-seidel.de
+M: Frank Seidel <frank@f-seidel.de>
L: lm-sensors@lm-sensors.org
W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
S: Maintained
F: drivers/hwmon/hdaps.c
+HARDWARE LATENCY DETECTOR
+P: Jon Masters
+M: jcm@jonmasters.org
+W: http://www.kernel.org/pub/linux/kernel/people/jcm/hwlat_detector/
+S: Supported
+L: linux-kernel@vger.kernel.org
+F: Documentation/hwlat_detector.txt
+F: drivers/misc/hwlat_detector.c
+
HYPERVISOR VIRTUAL CONSOLE DRIVER
L: linuxppc-dev@ozlabs.org
S: Odd Fixes
F: drivers/char/hvc_*
GSPCA FINEPIX SUBDRIVER
-P: Frank Zago
-M: frank@zago.net
+M: Frank Zago <frank@zago.net>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
F: drivers/media/video/gspca/finepix.c
GSPCA M5602 SUBDRIVER
-P: Erik Andren
-M: erik.andren@gmail.com
+M: Erik Andren <erik.andren@gmail.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
F: drivers/media/video/gspca/m5602/
GSPCA PAC207 SONIXB SUBDRIVER
-P: Hans de Goede
-M: hdegoede@redhat.com
+M: Hans de Goede <hdegoede@redhat.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
F: drivers/media/video/gspca/pac207.c
+GSPCA SN9C20X SUBDRIVER
+P: Brian Johnson
+M: brijohn@gmail.com
+L: linux-media@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+S: Maintained
+F: drivers/media/video/gspca/sn9c20x.c
+
GSPCA T613 SUBDRIVER
-P: Leandro Costantino
-M: lcostantino@gmail.com
+M: Leandro Costantino <lcostantino@gmail.com>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
F: drivers/media/video/gspca/t613.c
GSPCA USB WEBCAM DRIVER
-P: Jean-Francois Moine
-M: moinejf@free.fr
+M: Jean-Francois Moine <moinejf@free.fr>
W: http://moinejf.free.fr
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -2636,31 +2307,27 @@ F: drivers/char/hw_random/
F: include/linux/hw_random.h
HARMONY SOUND DRIVER
-P: Kyle McMartin
-M: kyle@mcmartin.ca
+M: Kyle McMartin <kyle@mcmartin.ca>
L: linux-parisc@vger.kernel.org
S: Maintained
F: sound/parisc/harmony.*
HAYES ESP SERIAL DRIVER
-P: Andrew J. Robinson
-M: arobinso@nyx.net
+M: "Andrew J. Robinson" <arobinso@nyx.net>
W: http://www.nyx.net/~arobinso
S: Maintained
F: Documentation/serial/hayes-esp.txt
F: drivers/char/esp.c
HEWLETT-PACKARD SMART2 RAID DRIVER
-P: Chirag Kantharia
-M: chirag.kantharia@hp.com
+M: Chirag Kantharia <chirag.kantharia@hp.com>
L: iss_storagedev@hp.com
S: Maintained
F: Documentation/blockdev/cpqarray.txt
F: drivers/block/cpqarray.*
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-P: Mike Miller
-M: mike.miller@hp.com
+M: Mike Miller <mike.miller@hp.com>
L: iss_storagedev@hp.com
S: Supported
F: Documentation/blockdev/cciss.txt
@@ -2668,25 +2335,21 @@ F: drivers/block/cciss*
F: include/linux/cciss_ioctl.h
HFS FILESYSTEM
-P: Roman Zippel
-M: zippel@linux-m68k.org
+M: Roman Zippel <zippel@linux-m68k.org>
S: Maintained
F: Documentation/filesystems/hfs.txt
F: fs/hfs/
HGA FRAMEBUFFER DRIVER
-P: Ferenc Bakonyi
-M: fero@drama.obuda.kando.hu
+M: Ferenc Bakonyi <fero@drama.obuda.kando.hu>
L: linux-nvidia@lists.surfsouth.com
W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
S: Maintained
F: drivers/video/hgafb.c
HIBERNATION (aka Software Suspend, aka swsusp)
-P: Pavel Machek
-M: pavel@ucw.cz
-P: Rafael J. Wysocki
-M: rjw@sisk.pl
+M: Pavel Machek <pavel@ucw.cz>
+M: "Rafael J. Wysocki" <rjw@sisk.pl>
L: linux-pm@lists.linux-foundation.org
S: Supported
F: arch/x86/power/
@@ -2698,8 +2361,7 @@ F: include/linux/pm.h
F: arch/*/include/asm/suspend*.h
HID CORE LAYER
-P: Jiri Kosina
-M: jkosina@suse.cz
+M: Jiri Kosina <jkosina@suse.cz>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
@@ -2707,16 +2369,14 @@ F: drivers/hid/
F: include/linux/hid*
HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
-P: Thomas Gleixner
-M: tglx@linutronix.de
+M: Thomas Gleixner <tglx@linutronix.de>
S: Maintained
F: Documentation/timers/
F: kernel/hrtimer.c
F: include/linux/hrtimer.h
HIGH-SPEED SCC DRIVER FOR AX.25
-P: Klaus Kudielka
-M: klaus.kudielka@ieee.org
+M: Klaus Kudielka <klaus.kudielka@ieee.org>
L: linux-hams@vger.kernel.org
W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/
S: Maintained
@@ -2724,16 +2384,14 @@ F: drivers/net/hamradio/dmascc.c
F: drivers/net/hamradio/scc.c
HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
-P: HighPoint Linux Team
-M: linux@highpoint-tech.com
+M: HighPoint Linux Team <linux@highpoint-tech.com>
W: http://www.highpoint-tech.com
S: Supported
F: Documentation/scsi/hptiop.txt
F: drivers/scsi/hptiop.c
HIPPI
-P: Jes Sorensen
-M: jes@trained-monkey.org
+M: Jes Sorensen <jes@trained-monkey.org>
L: linux-hippi@sunsite.dk
S: Maintained
F: include/linux/hippidevice.h
@@ -2741,8 +2399,7 @@ F: include/linux/if_hippi.h
F: net/802/hippi.c
HOST AP DRIVER
-P: Jouni Malinen
-M: j@w1.fi
+M: Jouni Malinen <j@w1.fi>
L: hostap@shmoo.com (subscribers-only)
L: linux-wireless@vger.kernel.org
W: http://hostap.epitest.fi/
@@ -2750,82 +2407,69 @@ S: Maintained
F: drivers/net/wireless/hostap/
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
-P: Carlos Corbacho
-M: carlos@strangeworlds.co.uk
+M: Carlos Corbacho <carlos@strangeworlds.co.uk>
S: Odd Fixes
F: drivers/platform/x86/tc1100-wmi.c
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
-P: Jaroslav Kysela
-M: perex@perex.cz
+M: Jaroslav Kysela <perex@perex.cz>
S: Maintained
F: drivers/net/hp100.*
HPET: High Precision Event Timers driver
-P: Clemens Ladisch
-M: clemens@ladisch.de
+M: Clemens Ladisch <clemens@ladisch.de>
S: Maintained
F: Documentation/timers/hpet.txt
F: drivers/char/hpet.c
F: include/linux/hpet.h
HPET: i386
-P: Venkatesh Pallipadi (Venki)
-M: venkatesh.pallipadi@intel.com
+M: "Venkatesh Pallipadi (Venki)" <venkatesh.pallipadi@intel.com>
S: Maintained
F: arch/x86/kernel/hpet.c
F: arch/x86/include/asm/hpet.h
HPET: x86_64
-P: Vojtech Pavlik
-M: vojtech@suse.cz
+M: Vojtech Pavlik <vojtech@suse.cz>
S: Maintained
HPET: ACPI
-P: Bob Picco
-M: bob.picco@hp.com
+M: Bob Picco <bob.picco@hp.com>
S: Maintained
F: drivers/char/hpet.c
HPFS FILESYSTEM
-P: Mikulas Patocka
-M: mikulas@artax.karlin.mff.cuni.cz
+M: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
S: Maintained
F: fs/hpfs/
HSO 3G MODEM DRIVER
-P: Jan Dumon
-M: j.dumon@option.com
+M: Jan Dumon <j.dumon@option.com>
W: http://www.pharscape.org
S: Maintained
F: drivers/net/usb/hso.c
HTCPEN TOUCHSCREEN DRIVER
-P: Pau Oliva Fora
-M: pof@eslack.org
+M: Pau Oliva Fora <pof@eslack.org>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/htcpen.c
HUGETLB FILESYSTEM
-P: William Irwin
-M: wli@holomorphy.com
+M: William Irwin <wli@holomorphy.com>
S: Maintained
F: fs/hugetlbfs/
I2C/SMBUS STUB DRIVER
-P: Mark M. Hoffman
-M: mhoffman@lightlink.com
+M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-stub.c
I2C SUBSYSTEM
-P: Jean Delvare (PC drivers, core)
-M: khali@linux-fr.org
-P: Ben Dooks (embedded platforms)
-M: ben-linux@fluff.org
+M: "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>
+M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
@@ -2837,30 +2481,25 @@ F: include/linux/i2c-dev.h
F: include/linux/i2c-id.h
I2C-TINY-USB DRIVER
-P: Till Harbaum
-M: till@harbaum.org
+M: Till Harbaum <till@harbaum.org>
L: linux-i2c@vger.kernel.org
W: http://www.harbaum.org/till/i2c_tiny_usb
S: Maintained
F: drivers/i2c/busses/i2c-tiny-usb.c
i386 BOOT CODE
-P: H. Peter Anvin
-M: hpa@zytor.com
+M: "H. Peter Anvin" <hpa@zytor.com>
S: Maintained
F: arch/x86/boot/
i386 SETUP CODE / CPU ERRATA WORKAROUNDS
-P: H. Peter Anvin
-M: hpa@zytor.com
+M: "H. Peter Anvin" <hpa@zytor.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git
S: Maintained
IA64 (Itanium) PLATFORM
-P: Tony Luck
-P: Fenghua Yu
-M: tony.luck@intel.com
-M: fenghua.yu@intel.com
+M: Tony Luck <tony.luck@intel.com>
+M: Fenghua Yu <fenghua.yu@intel.com>
L: linux-ia64@vger.kernel.org
W: http://www.ia64-linux.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
@@ -2868,29 +2507,25 @@ S: Maintained
F: arch/ia64/
IBM MCA SCSI SUBSYSTEM DRIVER
-P: Michael Lang
-M: langa2@kph.uni-mainz.de
+M: Michael Lang <langa2@kph.uni-mainz.de>
W: http://www.uni-mainz.de/~langm000/linux.html
S: Maintained
F: drivers/scsi/ibmmca.c
IBM Power Linux RAID adapter
-P: Brian King
-M: brking@us.ibm.com
+M: Brian King <brking@us.ibm.com>
S: Supported
F: drivers/scsi/ipr.*
IBM ServeRAID RAID DRIVER
P: Jack Hammer
-P: Dave Jeffery
-M: ipslinux@adaptec.com
+M: Dave Jeffery <ipslinux@adaptec.com>
W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html
S: Supported
F: drivers/scsi/ips.*
IDE SUBSYSTEM
-P: David S. Miller
-M: davem@davemloft.net
+M: "David S. Miller" <davem@davemloft.net>
L: linux-ide@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide-2.6.git
S: Maintained
@@ -2899,25 +2534,21 @@ F: drivers/ide/
F: include/linux/ide.h
IDE/ATAPI DRIVERS
-P: Borislav Petkov
-M: petkovbb@gmail.com
+M: Borislav Petkov <petkovbb@gmail.com>
L: linux-ide@vger.kernel.org
S: Maintained
F: Documentation/cdrom/ide-cd
F: drivers/ide/ide-cd*
IDLE-I7300
-P: Andy Henroid
-M: andrew.d.henroid@intel.com
+M: Andy Henroid <andrew.d.henroid@intel.com>
L: linux-pm@lists.linux-foundation.org
S: Supported
F: drivers/idle/i7300_idle.c
IEEE 1394 SUBSYSTEM
-P: Ben Collins
-M: ben.collins@ubuntu.com
-P: Stefan Richter
-M: stefanr@s5r6.in-berlin.de
+M: Ben Collins <ben.collins@ubuntu.com>
+M: Stefan Richter <stefanr@s5r6.in-berlin.de>
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
@@ -2925,19 +2556,15 @@ S: Maintained
F: drivers/ieee1394/
IEEE 1394 RAW I/O DRIVER
-P: Dan Dennedy
-M: dan@dennedy.org
-P: Stefan Richter
-M: stefanr@s5r6.in-berlin.de
+M: Dan Dennedy <dan@dennedy.org>
+M: Stefan Richter <stefanr@s5r6.in-berlin.de>
L: linux1394-devel@lists.sourceforge.net
S: Maintained
F: drivers/ieee1394/raw1394*
IEEE 802.15.4 SUBSYSTEM
-P: Dmitry Eremin-Solenikov
-M: dbaryshkov@gmail.com
-P: Sergey Lapin
-M: slapin@ossfans.org
+M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+M: Sergey Lapin <slapin@ossfans.org>
L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
W: http://apps.sourceforge.net/trac/linux-zigbee
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
@@ -2946,8 +2573,7 @@ F: net/ieee802154/
F: drivers/ieee802154/
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
-P: Mimi Zohar
-M: zohar@us.ibm.com
+M: Mimi Zohar <zohar@us.ibm.com>
S: Supported
F: security/integrity/ima/
@@ -2957,12 +2583,9 @@ S: Orphan
F: drivers/video/imsttfb.c
INFINIBAND SUBSYSTEM
-P: Roland Dreier
-M: rolandd@cisco.com
-P: Sean Hefty
-M: sean.hefty@intel.com
-P: Hal Rosenstock
-M: hal.rosenstock@gmail.com
+M: Roland Dreier <rolandd@cisco.com>
+M: Sean Hefty <sean.hefty@intel.com>
+M: Hal Rosenstock <hal.rosenstock@gmail.com>
L: general@lists.openfabrics.org (moderated for non-subscribers)
W: http://www.openib.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
@@ -2972,65 +2595,55 @@ F: drivers/infiniband/
F: include/linux/if_infiniband.h
INOTIFY
-P: John McCutchan
-M: john@johnmccutchan.com
-P: Robert Love
-M: rlove@rlove.org
-P: Eric Paris
-M: eparis@parisplace.org
+M: John McCutchan <john@johnmccutchan.com>
+M: Robert Love <rlove@rlove.org>
+M: Eric Paris <eparis@parisplace.org>
S: Maintained
F: Documentation/filesystems/inotify.txt
F: fs/notify/inotify/
F: include/linux/inotify.h
INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
-P: Dmitry Torokhov
-M: dmitry.torokhov@gmail.com
-M: dtor@mail.ru
+M: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+M: Dmitry Torokhov <dtor@mail.ru>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
S: Maintained
F: drivers/input/
INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
-P: Sylvain Meyer
-M: sylvain.meyer@worldonline.fr
+M: Sylvain Meyer <sylvain.meyer@worldonline.fr>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: Documentation/fb/intelfb.txt
F: drivers/video/intelfb/
INTEL 810/815 FRAMEBUFFER DRIVER
-P: Antonino Daplas
-M: adaplas@gmail.com
+M: Antonino Daplas <adaplas@gmail.com>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/i810/
INTEL MENLOW THERMAL DRIVER
-P: Sujith Thomas
-M: sujith.thomas@intel.com
+M: Sujith Thomas <sujith.thomas@intel.com>
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
F: drivers/platform/x86/intel_menlow.c
INTEL IA32 MICROCODE UPDATE SUPPORT
-P: Tigran Aivazian
-M: tigran@aivazian.fsnet.co.uk
+M: Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
S: Maintained
F: arch/x86/kernel/microcode_core.c
F: arch/x86/kernel/microcode_intel.c
INTEL I/OAT DMA DRIVER
-P: Maciej Sosnowski
-M: maciej.sosnowski@intel.com
+M: Maciej Sosnowski <maciej.sosnowski@intel.com>
S: Supported
F: drivers/dma/ioat*
INTEL IOMMU (VT-d)
-P: David Woodhouse
-M: dwmw2@infradead.org
+M: David Woodhouse <dwmw2@infradead.org>
L: iommu@lists.linux-foundation.org
T: git git://git.infradead.org/iommu-2.6.git
S: Supported
@@ -3038,14 +2651,12 @@ F: drivers/pci/intel-iommu.c
F: include/linux/intel-iommu.h
INTEL IOP-ADMA DMA DRIVER
-P: Dan Williams
-M: dan.j.williams@intel.com
+M: Dan Williams <dan.j.williams@intel.com>
S: Supported
F: drivers/dma/iop-adma.c
INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
-P: Krzysztof Halasa
-M: khc@pm.waw.pl
+M: Krzysztof Halasa <khc@pm.waw.pl>
S: Maintained
F: arch/arm/mach-ixp4xx/include/mach/qmgr.h
F: arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -3055,29 +2666,22 @@ F: drivers/net/arm/ixp4xx_eth.c
F: drivers/net/wan/ixp4xx_hss.c
INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
-P: Deepak Saxena
-M: dsaxena@plexity.net
+M: Deepak Saxena <dsaxena@plexity.net>
S: Maintained
F: drivers/char/hw_random/ixp4xx-rng.c
INTEL IXP2000 ETHERNET DRIVER
-P: Lennert Buytenhek
-M: kernel@wantstofly.org
+M: Lennert Buytenhek <kernel@wantstofly.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ixp2000/
INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/ixgb/ixgbe)
-P: Jeff Kirsher
-M: jeffrey.t.kirsher@intel.com
-P: Jesse Brandeburg
-M: jesse.brandeburg@intel.com
-P: Bruce Allan
-M: bruce.w.allan@intel.com
-P: PJ Waskiewicz
-M: peter.p.waskiewicz.jr@intel.com
-P: John Ronciak
-M: john.ronciak@intel.com
+M: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+M: Jesse Brandeburg <jesse.brandeburg@intel.com>
+M: Bruce Allan <bruce.w.allan@intel.com>
+M: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
+M: John Ronciak <john.ronciak@intel.com>
L: e1000-devel@lists.sourceforge.net
W: http://e1000.sourceforge.net/
S: Supported
@@ -3089,12 +2693,9 @@ F: drivers/net/ixgb/
F: drivers/net/ixgbe/
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
-P: Zhu Yi
-M: yi.zhu@intel.com
-P: James Ketrenos
-M: jketreno@linux.intel.com
-P: Reinette Chatre
-M: reinette.chatre@intel.com
+M: Zhu Yi <yi.zhu@intel.com>
+M: James Ketrenos <jketreno@linux.intel.com>
+M: Reinette Chatre <reinette.chatre@intel.com>
L: linux-wireless@vger.kernel.org
L: ipw2100-devel@lists.sourceforge.net
W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
@@ -3104,12 +2705,9 @@ F: Documentation/networking/README.ipw2100
F: drivers/net/wireless/ipw2x00/ipw2100.*
INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
-P: Zhu Yi
-M: yi.zhu@intel.com
-P: James Ketrenos
-M: jketreno@linux.intel.com
-P: Reinette Chatre
-M: reinette.chatre@intel.com
+M: Zhu Yi <yi.zhu@intel.com>
+M: James Ketrenos <jketreno@linux.intel.com>
+M: Reinette Chatre <reinette.chatre@intel.com>
L: linux-wireless@vger.kernel.org
L: ipw2100-devel@lists.sourceforge.net
W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
@@ -3119,8 +2717,7 @@ F: Documentation/networking/README.ipw2200
F: drivers/net/wireless/ipw2x00/ipw2200.*
INTEL WIRELESS WIMAX CONNECTION 2400
-P: Inaky Perez-Gonzalez
-M: inaky.perez-gonzalez@intel.com
+M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
M: linux-wimax@intel.com
L: wimax@linuxwimax.org
S: Supported
@@ -3130,10 +2727,8 @@ F: drivers/net/wimax/i2400m/
F: include/linux/wimax/i2400m.h
INTEL WIRELESS WIFI LINK (iwlwifi)
-P: Zhu Yi
-M: yi.zhu@intel.com
-P: Reinette Chatre
-M: reinette.chatre@intel.com
+M: Zhu Yi <yi.zhu@intel.com>
+M: Reinette Chatre <reinette.chatre@intel.com>
L: linux-wireless@vger.kernel.org
L: ipw3945-devel@lists.sourceforge.net
W: http://intellinuxwireless.org
@@ -3142,47 +2737,39 @@ S: Supported
F: drivers/net/wireless/iwlwifi/
IOC3 ETHERNET DRIVER
-P: Ralf Baechle
-M: ralf@linux-mips.org
+M: Ralf Baechle <ralf@linux-mips.org>
L: linux-mips@linux-mips.org
S: Maintained
F: drivers/net/ioc3-eth.c
IOC3 SERIAL DRIVER
-P: Pat Gefre
-M: pfg@sgi.com
+M: Pat Gefre <pfg@sgi.com>
L: linux-mips@linux-mips.org
S: Maintained
F: drivers/serial/ioc3_serial.c
IP MASQUERADING
-P: Juanjo Ciarlante
-M: jjciarla@raiz.uncu.edu.ar
+M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
S: Maintained
F: net/ipv4/netfilter/ipt_MASQUERADE.c
IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
-P: Francois Romieu
-M: romieu@fr.zoreil.com
-P: Sorbica Shieh
-M: sorbica@icplus.com.tw
-P: Jesse Huang
-M: jesse@icplus.com.tw
+M: Francois Romieu <romieu@fr.zoreil.com>
+M: Sorbica Shieh <sorbica@icplus.com.tw>
+M: Jesse Huang <jesse@icplus.com.tw>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ipg.c
IPATH DRIVER
-P: Ralph Campbell
-M: infinipath@qlogic.com
+M: Ralph Campbell <infinipath@qlogic.com>
L: general@lists.openfabrics.org
T: git git://git.qlogic.com/ipath-linux-2.6
S: Supported
F: drivers/infiniband/hw/ipath/
IPMI SUBSYSTEM
-P: Corey Minyard
-M: minyard@acm.org
+M: Corey Minyard <minyard@acm.org>
L: openipmi-developer@lists.sourceforge.net
W: http://openipmi.sourceforge.net/
S: Supported
@@ -3191,20 +2778,16 @@ F: drivers/char/ipmi/
F: include/linux/ipmi*
IPS SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
+M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
L: linux-scsi@vger.kernel.org
W: http://www.adaptec.com/
S: Maintained
F: drivers/scsi/ips*
IPVS
-P: Wensong Zhang
-M: wensong@linux-vs.org
-P: Simon Horman
-M: horms@verge.net.au
-P: Julian Anastasov
-M: ja@ssi.bg
+M: Wensong Zhang <wensong@linux-vs.org>
+M: Simon Horman <horms@verge.net.au>
+M: Julian Anastasov <ja@ssi.bg>
L: netdev@vger.kernel.org
L: lvs-devel@vger.kernel.org
S: Maintained
@@ -3212,17 +2795,14 @@ F: Documentation/networking/ipvs-sysctl.txt
F: net/netfilter/ipvs/
IPWIRELESS DRIVER
-P: Jiri Kosina
-M: jkosina@suse.cz
-P: David Sterba
-M: dsterba@suse.cz
+M: Jiri Kosina <jkosina@suse.cz>
+M: David Sterba <dsterba@suse.cz>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
F: drivers/char/pcmcia/ipwireless/
IPX NETWORK LAYER
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: netdev@vger.kernel.org
S: Maintained
F: include/linux/ipx.h
@@ -3230,8 +2810,7 @@ F: include/net/ipx.h
F: net/ipx/
IRDA SUBSYSTEM
-P: Samuel Ortiz
-M: samuel@sortiz.org
+M: Samuel Ortiz <samuel@sortiz.org>
L: irda-users@lists.sourceforge.net (subscribers-only)
W: http://irda.sourceforge.net/
S: Maintained
@@ -3242,16 +2821,14 @@ F: include/net/irda/
F: net/irda/
ISAPNP
-P: Jaroslav Kysela
-M: perex@perex.cz
+M: Jaroslav Kysela <perex@perex.cz>
S: Maintained
F: Documentation/isapnp.txt
F: drivers/pnp/isapnp/
F: include/linux/isapnp.h
ISCSI
-P: Mike Christie
-M: michaelc@cs.wisc.edu
+M: Mike Christie <michaelc@cs.wisc.edu>
L: open-iscsi@googlegroups.com
W: www.open-iscsi.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mnc/linux-2.6-iscsi.git
@@ -3260,8 +2837,7 @@ F: drivers/scsi/*iscsi*
F: include/scsi/*iscsi*
ISDN SUBSYSTEM
-P: Karsten Keil
-M: isdn@linux-pingi.de
+M: Karsten Keil <isdn@linux-pingi.de>
L: isdn4linux@listserv.isdn4linux.de (subscribers-only)
W: http://www.isdn4linux.de
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/isdn-2.6.git
@@ -3272,18 +2848,15 @@ F: include/linux/isdn.h
F: include/linux/isdn/
ISDN SUBSYSTEM (Eicon active card driver)
-P: Armin Schindler
-M: mac@melware.de
+M: Armin Schindler <mac@melware.de>
L: isdn4linux@listserv.isdn4linux.de (subscribers-only)
W: http://www.melware.de
S: Maintained
F: drivers/isdn/hardware/eicon/
IVTV VIDEO4LINUX DRIVER
-P: Hans Verkuil
-M: hverkuil@xs4all.nl
+M: Hans Verkuil <hverkuil@xs4all.nl>
L: ivtv-devel@ivtvdriver.org
-L: ivtv-users@ivtvdriver.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
W: http://www.ivtvdriver.org
@@ -3293,8 +2866,7 @@ F: drivers/media/video/ivtv/
F: include/linux/ivtv*
JFS FILESYSTEM
-P: Dave Kleikamp
-M: shaggy@linux.vnet.ibm.com
+M: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
L: jfs-discussion@lists.sourceforge.net
W: http://jfs.sourceforge.net/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
@@ -3303,15 +2875,13 @@ F: Documentation/filesystems/jfs.txt
F: fs/jfs/
JME NETWORK DRIVER
-P: Guo-Fu Tseng
-M: cooldavid@cooldavid.org
+M: Guo-Fu Tseng <cooldavid@cooldavid.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/jme.*
JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
-P: David Woodhouse
-M: dwmw2@infradead.org
+M: David Woodhouse <dwmw2@infradead.org>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/doc/jffs2.html
S: Maintained
@@ -3319,10 +2889,8 @@ F: fs/jffs2/
F: include/linux/jffs2.h
JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
-P: Stephen Tweedie
-M: sct@redhat.com
-P: Andrew Morton
-M: akpm@linux-foundation.org
+M: Stephen Tweedie <sct@redhat.com>
+M: Andrew Morton <akpm@linux-foundation.org>
L: linux-ext4@vger.kernel.org
S: Maintained
F: fs/jbd*/
@@ -3330,48 +2898,41 @@ F: include/linux/ext*jbd*.h
F: include/linux/jbd*.h
K8TEMP HARDWARE MONITORING DRIVER
-P: Rudolf Marek
-M: r.marek@assembler.cz
+M: Rudolf Marek <r.marek@assembler.cz>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/k8temp
F: drivers/hwmon/k8temp.c
KCONFIG
-P: Roman Zippel
-M: zippel@linux-m68k.org
+M: Roman Zippel <zippel@linux-m68k.org>
L: linux-kbuild@vger.kernel.org
S: Maintained
F: Documentation/kbuild/kconfig-language.txt
F: scripts/kconfig/
KDUMP
-P: Vivek Goyal
-M: vgoyal@redhat.com
-P: Haren Myneni
-M: hbabu@us.ibm.com
+M: Vivek Goyal <vgoyal@redhat.com>
+M: Haren Myneni <hbabu@us.ibm.com>
L: kexec@lists.infradead.org
W: http://lse.sourceforge.net/kdump/
S: Maintained
F: Documentation/kdump/
KERNEL AUTOMOUNTER (AUTOFS)
-P: H. Peter Anvin
-M: hpa@zytor.com
+M: "H. Peter Anvin" <hpa@zytor.com>
L: autofs@linux.kernel.org
S: Odd Fixes
F: fs/autofs/
KERNEL AUTOMOUNTER v4 (AUTOFS4)
-P: Ian Kent
-M: raven@themaw.net
+M: Ian Kent <raven@themaw.net>
L: autofs@linux.kernel.org
S: Maintained
F: fs/autofs4/
KERNEL BUILD
-P: Sam Ravnborg
-M: sam@ravnborg.org
+M: Sam Ravnborg <sam@ravnborg.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-next.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-fixes.git
L: linux-kbuild@vger.kernel.org
@@ -3381,16 +2942,13 @@ F: Makefile
F: scripts/Makefile.*
KERNEL JANITORS
-P: Several
L: kernel-janitors@vger.kernel.org
-W: http://www.kerneljanitors.org/
-S: Maintained
+W: http://janitor.kernelnewbies.org/
+S: Odd fixes
KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
-P: J. Bruce Fields
-M: bfields@fieldses.org
-P: Neil Brown
-M: neilb@suse.de
+M: "J. Bruce Fields" <bfields@fieldses.org>
+M: Neil Brown <neilb@suse.de>
L: linux-nfs@vger.kernel.org
W: http://nfs.sourceforge.net/
S: Supported
@@ -3403,8 +2961,7 @@ F: include/linux/lockd/
F: include/linux/sunrpc/
KERNEL VIRTUAL MACHINE (KVM)
-P: Avi Kivity
-M: avi@redhat.com
+M: Avi Kivity <avi@redhat.com>
L: kvm@vger.kernel.org
W: http://kvm.qumranet.com
S: Supported
@@ -3415,8 +2972,7 @@ F: include/linux/kvm*
F: virt/kvm/
KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V
-P: Joerg Roedel
-M: joerg.roedel@amd.com
+M: Joerg Roedel <joerg.roedel@amd.com>
L: kvm@vger.kernel.org
W: http://kvm.qumranet.com
S: Supported
@@ -3425,8 +2981,7 @@ F: arch/x86/kvm/kvm_svm.h
F: arch/x86/kvm/svm.c
KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
-P: Hollis Blanchard
-M: hollisb@us.ibm.com
+M: Hollis Blanchard <hollisb@us.ibm.com>
L: kvm-ppc@vger.kernel.org
W: http://kvm.qumranet.com
S: Supported
@@ -3434,8 +2989,7 @@ F: arch/powerpc/include/asm/kvm*
F: arch/powerpc/kvm/
KERNEL VIRTUAL MACHINE For Itanium (KVM/IA64)
-P: Xiantao Zhang
-M: xiantao.zhang@intel.com
+M: Xiantao Zhang <xiantao.zhang@intel.com>
L: kvm-ia64@vger.kernel.org
W: http://kvm.qumranet.com
S: Supported
@@ -3444,10 +2998,8 @@ F: arch/ia64/include/asm/kvm*
F: arch/ia64/kvm/
KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
-P: Carsten Otte
-M: cotte@de.ibm.com
-P: Christian Borntraeger
-M: borntraeger@de.ibm.com
+M: Carsten Otte <cotte@de.ibm.com>
+M: Christian Borntraeger <borntraeger@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -3457,8 +3009,7 @@ F: arch/s390/include/asm/kvm*
F: arch/s390/kvm/
KEXEC
-P: Eric Biederman
-M: ebiederm@xmission.com
+M: Eric Biederman <ebiederm@xmission.com>
W: http://ftp.kernel.org/pub/linux/kernel/people/horms/kexec-tools/
L: kexec@lists.infradead.org
S: Maintained
@@ -3466,8 +3017,7 @@ F: include/linux/kexec.h
F: kernel/kexec.c
KGDB
-P: Jason Wessel
-M: jason.wessel@windriver.com
+M: Jason Wessel <jason.wessel@windriver.com>
L: kgdb-bugreport@lists.sourceforge.net
S: Maintained
F: Documentation/DocBook/kgdb.tmpl
@@ -3477,17 +3027,13 @@ F: include/linux/kgdb.h
F: kernel/kgdb.c
KMEMCHECK
-P: Vegard Nossum
-M: vegardno@ifi.uio.no
+M: Vegard Nossum <vegardno@ifi.uio.no>
P Pekka Enberg
M: penberg@cs.helsinki.fi
-L: linux-kernel@vger.kernel.org
S: Maintained
KMEMLEAK
-P: Catalin Marinas
-M: catalin.marinas@arm.com
-L: linux-kernel@vger.kernel.org
+M: Catalin Marinas <catalin.marinas@arm.com>
S: Maintained
F: Documentation/kmemleak.txt
F: include/linux/kmemleak.h
@@ -3495,30 +3041,24 @@ F: mm/kmemleak.c
F: mm/kmemleak-test.c
KMEMTRACE
-P: Eduard - Gabriel Munteanu
-M: eduard.munteanu@linux360.ro
+M: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
S: Maintained
F: Documentation/trace/kmemtrace.txt
F: include/linux/kmemtrace.h
F: kernel/trace/kmemtrace.c
KPROBES
-P: Ananth N Mavinakayanahalli
-M: ananth@in.ibm.com
-P: Anil S Keshavamurthy
-M: anil.s.keshavamurthy@intel.com
-P: David S. Miller
-M: davem@davemloft.net
-P: Masami Hiramatsu
-M: mhiramat@redhat.com
+M: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
+M: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+M: "David S. Miller" <davem@davemloft.net>
+M: Masami Hiramatsu <mhiramat@redhat.com>
S: Maintained
F: Documentation/kprobes.txt
F: include/linux/kprobes.h
F: kernel/kprobes.c
KS0108 LCD CONTROLLER DRIVER
-P: Miguel Ojeda Sandonis
-M: miguel.ojeda.sandonis@gmail.com
+M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
W: http://miguelojeda.es/auxdisplay.htm
W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
S: Maintained
@@ -3534,31 +3074,27 @@ F: include/*/lapb.h
F: net/lapb/
LASI 53c700 driver for PARISC
-P: James E.J. Bottomley
-M: James.Bottomley@HansenPartnership.com
+M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/53c700.txt
F: drivers/scsi/53c700*
LED SUBSYSTEM
-P: Richard Purdie
-M: rpurdie@rpsys.net
+M: Richard Purdie <rpurdie@rpsys.net>
S: Maintained
F: drivers/leds/
F: include/linux/leds.h
LEGO USB Tower driver
-P: Juergen Stuber
-M: starblue@users.sourceforge.net
+M: Juergen Stuber <starblue@users.sourceforge.net>
L: legousb-devel@lists.sourceforge.net
W: http://legousb.sourceforge.net/
S: Maintained
F: drivers/usb/misc/legousbtower.c
LGUEST
-P: Rusty Russell
-M: rusty@rustcorp.com.au
+M: Rusty Russell <rusty@rustcorp.com.au>
L: lguest@ozlabs.org
W: http://lguest.ozlabs.org/
S: Maintained
@@ -3569,119 +3105,100 @@ F: include/linux/lguest*.h
F: arch/x86/include/asm/lguest*.h
LINUX FOR IBM pSERIES (RS/6000)
-P: Paul Mackerras
-M: paulus@au.ibm.com
+M: Paul Mackerras <paulus@au.ibm.com>
W: http://www.ibm.com/linux/ltc/projects/ppc
S: Supported
LINUX FOR POWERPC (32-BIT AND 64-BIT)
-P: Benjamin Herrenschmidt
-M: benh@kernel.crashing.org
-P: Paul Mackerras
-M: paulus@samba.org
+M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+M: Paul Mackerras <paulus@samba.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git
S: Supported
LINUX FOR POWER MACINTOSH
-P: Benjamin Herrenschmidt
-M: benh@kernel.crashing.org
+M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
LINUX FOR POWERPC EMBEDDED MPC5XXX
-P: Grant Likely
-M: grant.likely@secretlab.ca
+M: Grant Likely <grant.likely@secretlab.ca>
L: linuxppc-dev@ozlabs.org
T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
LINUX FOR POWERPC EMBEDDED PPC4XX
-P: Josh Boyer
-M: jwboyer@linux.vnet.ibm.com
-P: Matt Porter
-M: mporter@kernel.crashing.org
+M: Josh Boyer <jwboyer@linux.vnet.ibm.com>
+M: Matt Porter <mporter@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
-P: Grant Likely
-M: grant.likely@secretlab.ca
+M: Grant Likely <grant.likely@secretlab.ca>
W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex
L: linuxppc-dev@ozlabs.org
T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
LINUX FOR POWERPC EMBEDDED PPC8XX
-P: Vitaly Bordug
-M: vitb@kernel.crashing.org
-P: Marcelo Tosatti
-M: marcelo@kvack.org
+M: Vitaly Bordug <vitb@kernel.crashing.org>
+M: Marcelo Tosatti <marcelo@kvack.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
-P: Kumar Gala
-M: galak@kernel.crashing.org
+M: Kumar Gala <galak@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
LINUX FOR POWERPC PA SEMI PWRFICIENT
-P: Olof Johansson
-M: olof@lixom.net
+M: Olof Johansson <olof@lixom.net>
W: http://www.pasemi.com/
L: linuxppc-dev@ozlabs.org
S: Supported
LINUX SECURITY MODULE (LSM) FRAMEWORK
-P: Chris Wright
-M: chrisw@sous-sol.org
+M: Chris Wright <chrisw@sous-sol.org>
L: linux-security-module@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
S: Supported
LLC (802.2)
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
S: Maintained
F: include/linux/llc.h
F: include/net/llc*
F: net/llc/
LIS3LV02D ACCELEROMETER DRIVER
-P: Eric Piel
-M: eric.piel@tremplin-utc.net
+M: Eric Piel <eric.piel@tremplin-utc.net>
S: Maintained
F: Documentation/hwmon/lis3lv02d
F: drivers/hwmon/lis3lv02d.*
LM83 HARDWARE MONITOR DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
+M: Jean Delvare <khali@linux-fr.org>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/lm83
F: drivers/hwmon/lm83.c
LM90 HARDWARE MONITOR DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
+M: Jean Delvare <khali@linux-fr.org>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/lm90
F: drivers/hwmon/lm90.c
LOCKDEP AND LOCKSTAT
-P: Peter Zijlstra
-M: peterz@infradead.org
-P: Ingo Molnar
-M: mingo@redhat.com
+M: Peter Zijlstra <peterz@infradead.org>
+M: Ingo Molnar <mingo@redhat.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git
S: Maintained
F: Documentation/lockdep*.txt
@@ -3690,8 +3207,7 @@ F: include/linux/lockdep.h
F: kernel/lockdep*
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
-P: Richard Russon (FlatCap)
-M: ldm@flatcap.org
+M: "Richard Russon (FlatCap)" <ldm@flatcap.org>
L: linux-ntfs-dev@lists.sourceforge.net
W: http://www.linux-ntfs.org/content/view/19/37/
S: Maintained
@@ -3699,8 +3215,7 @@ F: Documentation/ldm.txt
F: fs/partitions/ldm.*
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
-P: Eric Moore
-M: Eric.Moore@lsi.com
+M: Eric Moore <Eric.Moore@lsi.com>
M: support@lsi.com
L: DL-MPTFusionLinux@lsi.com
L: linux-scsi@vger.kernel.org
@@ -3709,25 +3224,21 @@ S: Supported
F: drivers/message/fusion/
LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers
-P: Matthew Wilcox
-M: matthew@wil.cx
+M: Matthew Wilcox <matthew@wil.cx>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/sym53c8xx_2/
LTP (Linux Test Project)
-P: Subrata Modak
-M: subrata@linux.vnet.ibm.com
-P: Mike Frysinger
-M: vapier@gentoo.org
+M: Subrata Modak <subrata@linux.vnet.ibm.com>
+M: Mike Frysinger <vapier@gentoo.org>
L: ltp-list@lists.sourceforge.net (subscribers-only)
W: http://ltp.sourceforge.net/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/ltp.git
S: Maintained
M32R ARCHITECTURE
-P: Hirokazu Takata
-M: takata@linux-m32r.org
+M: Hirokazu Takata <takata@linux-m32r.org>
L: linux-m32r@ml.linux-m32r.org
L: linux-m32r-ja@ml.linux-m32r.org (in Japanese)
W: http://www.linux-m32r.org/
@@ -3735,10 +3246,8 @@ S: Maintained
F: arch/m32r/
M68K ARCHITECTURE
-P: Geert Uytterhoeven
-M: geert@linux-m68k.org
-P: Roman Zippel
-M: zippel@linux-m68k.org
+M: Geert Uytterhoeven <geert@linux-m68k.org>
+M: Roman Zippel <zippel@linux-m68k.org>
L: linux-m68k@lists.linux-m68k.org
W: http://www.linux-m68k.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
@@ -3747,23 +3256,20 @@ F: arch/m68k/
F: drivers/zorro/
M68K ON APPLE MACINTOSH
-P: Joshua Thompson
-M: funaho@jurai.org
+M: Joshua Thompson <funaho@jurai.org>
W: http://www.mac.linux-m68k.org/
L: linux-m68k@lists.linux-m68k.org
S: Maintained
F: arch/m68k/mac/
M68K ON HP9000/300
-P: Philip Blundell
-M: philb@gnu.org
+M: Philip Blundell <philb@gnu.org>
W: http://www.tazenda.demon.co.uk/phil/linux-hp
S: Maintained
F: arch/m68k/hp300/
MAC80211
-P: Johannes Berg
-M: johannes@sipsolutions.net
+M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
@@ -3773,10 +3279,8 @@ F: include/net/mac80211.h
F: net/mac80211/
MAC80211 PID RATE CONTROL
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
-P: Mattias Nissler
-M: mattias.nissler@gmx.de
+M: Stefano Brivio <stefano.brivio@polimi.it>
+M: Mattias Nissler <mattias.nissler@gmx.de>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
@@ -3784,67 +3288,57 @@ S: Maintained
F: net/mac80211/rc80211_pid*
MACVLAN DRIVER
-P: Patrick McHardy
-M: kaber@trash.net
+M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/macvlan.c
F: include/linux/if_macvlan.h
MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
-P: Michael Kerrisk
-M: mtk.manpages@gmail.com
+M: Michael Kerrisk <mtk.manpages@gmail.com>
W: http://www.kernel.org/doc/man-pages
L: linux-man@vger.kernel.org
S: Maintained
MARVELL LIBERTAS WIRELESS DRIVER
-P: Dan Williams
-M: dcbw@redhat.com
+M: Dan Williams <dcbw@redhat.com>
L: libertas-dev@lists.infradead.org
S: Maintained
F: drivers/net/wireless/libertas/
MARVELL MV643XX ETHERNET DRIVER
-P: Lennert Buytenhek
-M: buytenh@marvell.com
+M: Lennert Buytenhek <buytenh@marvell.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/mv643xx_eth.*
F: include/linux/mv643xx.h
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
-P: Nicolas Pitre
-M: nico@cam.org
+M: Nicolas Pitre <nico@cam.org>
S: Maintained
MARVELL YUKON / SYSKONNECT DRIVER
-P: Mirko Lindner
-M: mlindner@syskonnect.de
-P: Ralph Roesler
-M: rroesler@syskonnect.de
+M: Mirko Lindner <mlindner@syskonnect.de>
+M: Ralph Roesler <rroesler@syskonnect.de>
W: http://www.syskonnect.com
S: Supported
MATROX FRAMEBUFFER DRIVER
-P: Petr Vandrovec
-M: vandrove@vc.cvut.cz
+M: Petr Vandrovec <vandrove@vc.cvut.cz>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/matrox/matroxfb_*
F: include/linux/matroxfb.h
MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
-P: Hans J. Koch
-M: hjk@linutronix.de
+M: "Hans J. Koch" <hjk@linutronix.de>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/max6650
F: drivers/hwmon/max6650.c
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
-P: Mauro Carvalho Chehab
-M: mchehab@infradead.org
+M: Mauro Carvalho Chehab <mchehab@infradead.org>
P: LinuxTV.org Project
L: linux-media@vger.kernel.org
W: http://linuxtv.org
@@ -3858,8 +3352,7 @@ F: include/linux/dvb/
F: include/linux/videodev*.h
MEGARAID SCSI DRIVERS
-P: Neela Syam Kolli
-M: megaraidlinux@lsi.com
+M: Neela Syam Kolli <megaraidlinux@lsi.com>
L: linux-scsi@vger.kernel.org
W: http://megaraid.lsilogic.com
S: Maintained
@@ -3875,19 +3368,15 @@ F: include/linux/mm.h
F: mm/
MEMORY RESOURCE CONTROLLER
-P: Balbir Singh
-M: balbir@linux.vnet.ibm.com
-P: Pavel Emelyanov
-M: xemul@openvz.org
-P: KAMEZAWA Hiroyuki
-M: kamezawa.hiroyu@jp.fujitsu.com
+M: Balbir Singh <balbir@linux.vnet.ibm.com>
+M: Pavel Emelyanov <xemul@openvz.org>
+M: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
L: linux-mm@kvack.org
S: Maintained
F: mm/memcontrol.c
MEMORY TECHNOLOGY DEVICES (MTD)
-P: David Woodhouse
-M: dwmw2@infradead.org
+M: David Woodhouse <dwmw2@infradead.org>
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/mtd-2.6.git
@@ -3897,8 +3386,7 @@ F: include/linux/mtd/
F: include/mtd/
MICROBLAZE ARCHITECTURE
-P: Michal Simek
-M: monstr@monstr.eu
+M: Michal Simek <monstr@monstr.eu>
L: microblaze-uclinux@itee.uq.edu.au
W: http://www.monstr.eu/fdt/
T: git git://git.monstr.eu/linux-2.6-microblaze.git
@@ -3906,14 +3394,12 @@ S: Supported
F: arch/microblaze/
MICROTEK X6 SCANNER
-P: Oliver Neukum
-M: oliver@neukum.name
+M: Oliver Neukum <oliver@neukum.name>
S: Maintained
F: drivers/usb/image/microtek.*
MIPS
-P: Ralf Baechle
-M: ralf@linux-mips.org
+M: Ralf Baechle <ralf@linux-mips.org>
W: http://www.linux-mips.org/
L: linux-mips@linux-mips.org
T: git git://git.linux-mips.org/pub/scm/linux.git
@@ -3922,8 +3408,7 @@ F: Documentation/mips/
F: arch/mips/
MISCELLANEOUS MCA-SUPPORT
-P: James Bottomley
-M: James.Bottomley@HansenPartnership.com
+M: James Bottomley <James.Bottomley@HansenPartnership.com>
S: Maintained
F: Documentation/ia64/mca.txt
F: Documentation/mca.txt
@@ -3931,15 +3416,13 @@ F: drivers/mca/
F: include/linux/mca*
MODULE SUPPORT
-P: Rusty Russell
-M: rusty@rustcorp.com.au
+M: Rusty Russell <rusty@rustcorp.com.au>
S: Maintained
F: include/linux/module.h
F: kernel/module.c
MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
-P: Stelian Pop
-M: stelian@popies.net
+M: Stelian Pop <stelian@popies.net>
W: http://popies.net/meye/
S: Maintained
F: Documentation/video4linux/meye.txt
@@ -3947,135 +3430,111 @@ F: drivers/media/video/meye.*
F: include/linux/meye.h
MOTOROLA IMX MMC/SD HOST CONTROLLER INTERFACE DRIVER
-P: Pavel Pisa
-M: ppisa@pikron.com
+M: Pavel Pisa <ppisa@pikron.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
F: drivers/mmc/host/imxmmc.*
MOUSE AND MISC DEVICES [GENERAL]
-P: Alessandro Rubini
-M: rubini@ipvvis.unipv.it
+M: Alessandro Rubini <rubini@ipvvis.unipv.it>
S: Maintained
F: drivers/input/mouse/
F: include/linux/gpio_mouse.h
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
-P: Jiri Slaby
-M: jirislaby@gmail.com
+M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
F: Documentation/serial/moxa-smartio
F: drivers/char/mxser.*
MSI LAPTOP SUPPORT
-P: Lennart Poettering
-M: mzxreary@0pointer.de
+M: Lennart Poettering <mzxreary@0pointer.de>
W: https://tango.0pointer.de/mailman/listinfo/s270-linux
W: http://0pointer.de/lennart/tchibo.html
S: Maintained
F: drivers/platform/x86/msi-laptop.c
MULTIFUNCTION DEVICES (MFD)
-P: Samuel Ortiz
-M: sameo@linux.intel.com
+M: Samuel Ortiz <sameo@linux.intel.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
S: Supported
F: drivers/mfd/
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
-P: Pierre Ossman
-M: pierre@ossman.eu
-S: Maintained
+S: Orphan
F: drivers/mmc/
F: include/linux/mmc/
MULTIMEDIA CARD (MMC) ETC. OVER SPI
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
S: Odd Fixes
F: drivers/mmc/host/mmc_spi.c
F: include/linux/spi/mmc_spi.h
MULTISOUND SOUND DRIVER
-P: Andrew Veliath
-M: andrewtv@usa.net
+M: Andrew Veliath <andrewtv@usa.net>
S: Maintained
F: Documentation/sound/oss/MultiSound
F: sound/oss/msnd*
MULTITECH MULTIPORT CARD (ISICOM)
-P: Jiri Slaby
-M: jirislaby@gmail.com
+M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
F: drivers/char/isicom.c
F: include/linux/isicom.h
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
-P: Felipe Balbi
-M: felipe.balbi@nokia.com
+M: Felipe Balbi <felipe.balbi@nokia.com>
L: linux-usb@vger.kernel.org
T: git git://gitorious.org/musb/mainline.git
S: Maintained
F: drivers/usb/musb/
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
-P: Andrew Gallatin
-M: gallatin@myri.com
-P: Brice Goglin
-M: brice@myri.com
+M: Andrew Gallatin <gallatin@myri.com>
+M: Brice Goglin <brice@myri.com>
L: netdev@vger.kernel.org
W: http://www.myri.com/scs/download-Myri10GE.html
S: Supported
F: drivers/net/myri10ge/
NATSEMI ETHERNET DRIVER (DP8381x)
-P: Tim Hockin
-M: thockin@hockin.org
+M: Tim Hockin <thockin@hockin.org>
S: Maintained
F: drivers/net/natsemi.c
NCP FILESYSTEM
-P: Petr Vandrovec
-M: vandrove@vc.cvut.cz
+M: Petr Vandrovec <vandrove@vc.cvut.cz>
L: linware@sh.cvut.cz
S: Maintained
F: fs/ncpfs/
NCR DUAL 700 SCSI DRIVER (MICROCHANNEL)
-P: James E.J. Bottomley
-M: James.Bottomley@HansenPartnership.com
+M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/NCR_D700.*
NETEFFECT IWARP RNIC DRIVER (IW_NES)
-P: Faisal Latif
-M: faisal.latif@intel.com
-P: Chien Tung
-M: chien.tin.tung@intel.com
+M: Faisal Latif <faisal.latif@intel.com>
+M: Chien Tung <chien.tin.tung@intel.com>
L: general@lists.openfabrics.org
W: http://www.neteffect.com
S: Supported
F: drivers/infiniband/hw/nes/
NETEM NETWORK EMULATOR
-P: Stephen Hemminger
-M: shemminger@linux-foundation.org
+M: Stephen Hemminger <shemminger@linux-foundation.org>
L: netem@lists.linux-foundation.org
S: Maintained
F: net/sched/sch_netem.c
NETERION (S2IO) 10GbE DRIVER (xframe/vxge)
-P: Ramkrishna Vepa
-M: ram.vepa@neterion.com
-P: Rastapur Santosh
-M: santosh.rastapur@neterion.com
-P: Sivakumar Subramani
-M: sivakumar.subramani@neterion.com
-P: Sreenivasa Honnur
-M: sreenivasa.honnur@neterion.com
-P: Anil Murthy
-M: anil.murthy@neterion.com
+M: Ramkrishna Vepa <ram.vepa@neterion.com>
+M: Rastapur Santosh <santosh.rastapur@neterion.com>
+M: Sivakumar Subramani <sivakumar.subramani@neterion.com>
+M: Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
+M: Anil Murthy <anil.murthy@neterion.com>
L: netdev@vger.kernel.org
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
@@ -4089,8 +3548,7 @@ P: Marc Boucher
P: James Morris
P: Harald Welte
P: Jozsef Kadlecsik
-P: Patrick McHardy
-M: kaber@trash.net
+M: Patrick McHardy <kaber@trash.net>
L: netfilter-devel@vger.kernel.org
L: netfilter@vger.kernel.org
L: coreteam@netfilter.org
@@ -4106,8 +3564,7 @@ F: net/*/netfilter/
F: net/netfilter/
NETLABEL
-P: Paul Moore
-M: paul.moore@hp.com
+M: Paul Moore <paul.moore@hp.com>
W: http://netlabel.sf.net
L: netdev@vger.kernel.org
S: Supported
@@ -4116,8 +3573,7 @@ F: include/net/netlabel.h
F: net/netlabel/
NETROM NETWORK LAYER
-P: Ralf Baechle
-M: ralf@linux-mips.org
+M: Ralf Baechle <ralf@linux-mips.org>
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
@@ -4126,16 +3582,14 @@ F: include/net/netrom.h
F: net/netrom/
NETWORK BLOCK DEVICE (NBD)
-P: Paul Clements
-M: Paul.Clements@steeleye.com
+M: Paul Clements <Paul.Clements@steeleye.com>
S: Maintained
F: Documentation/blockdev/nbd.txt
F: drivers/block/nbd.c
F: include/linux/nbd.h
NETWORKING [GENERAL]
-P: David S. Miller
-M: davem@davemloft.net
+M: "David S. Miller" <davem@davemloft.net>
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
@@ -4144,18 +3598,12 @@ F: net/
F: include/net/
NETWORKING [IPv4/IPv6]
-P: David S. Miller
-M: davem@davemloft.net
-P: Alexey Kuznetsov
-M: kuznet@ms2.inr.ac.ru
-P: Pekka Savola (ipv6)
-M: pekkas@netcore.fi
-P: James Morris
-M: jmorris@namei.org
-P: Hideaki YOSHIFUJI
-M: yoshfuji@linux-ipv6.org
-P: Patrick McHardy
-M: kaber@trash.net
+M: "David S. Miller" <davem@davemloft.net>
+M: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+M: "Pekka Savola (ipv6)" <pekkas@netcore.fi>
+M: James Morris <jmorris@namei.org>
+M: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
+M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
S: Maintained
@@ -4164,14 +3612,12 @@ F: net/ipv6/
F: include/net/ip*
NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
-P: Paul Moore
-M: paul.moore@hp.com
+M: Paul Moore <paul.moore@hp.com>
L: netdev@vger.kernel.org
S: Maintained
NETWORKING [WIRELESS]
-P: John W. Linville
-M: linville@tuxdriver.com
+M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
S: Maintained
@@ -4187,16 +3633,14 @@ S: Odd Fixes
F: drivers/net/
NETXEN (1/10) GbE SUPPORT
-P: Dhananjay Phadke
-M: dhananjay@netxen.com
+M: Dhananjay Phadke <dhananjay@netxen.com>
L: netdev@vger.kernel.org
W: http://www.netxen.com
S: Supported
F: drivers/net/netxen/
NFS, SUNRPC, AND LOCKD CLIENTS
-P: Trond Myklebust
-M: Trond.Myklebust@netapp.com
+M: Trond Myklebust <Trond.Myklebust@netapp.com>
L: linux-nfs@vger.kernel.org
W: http://client.linux-nfs.org
T: git git://git.linux-nfs.org/pub/linux/nfs-2.6.git
@@ -4210,17 +3654,14 @@ F: include/linux/nfs*
F: include/linux/sunrpc/
NI5010 NETWORK DRIVER
-P: Jan-Pascal van Best
-M: janpascal@vanbest.org
-P: Andreas Mohr
-M: andi@lisas.de
+M: Jan-Pascal van Best <janpascal@vanbest.org>
+M: Andreas Mohr <andi@lisas.de>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ni5010.*
NILFS2 FILESYSTEM
-P: KONISHI Ryusuke
-M: konishi.ryusuke@lab.ntt.co.jp
+M: KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
L: users@nilfs.org
W: http://www.nilfs.org/en/
S: Supported
@@ -4229,26 +3670,22 @@ F: fs/nilfs2/
F: include/linux/nilfs2_fs.h
NINJA SCSI-3 / NINJA SCSI-32Bi (16bit/CardBus) PCMCIA SCSI HOST ADAPTER DRIVER
-P: YOKOTA Hiroshi
-M: yokota@netlab.is.tsukuba.ac.jp
+M: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
S: Maintained
F: Documentation/scsi/NinjaSCSI.txt
F: drivers/scsi/pcmcia/nsp_*
NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
-P: GOTO Masanori
-M: gotom@debian.or.jp
-P: YOKOTA Hiroshi
-M: yokota@netlab.is.tsukuba.ac.jp
+M: GOTO Masanori <gotom@debian.or.jp>
+M: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
S: Maintained
F: Documentation/scsi/NinjaSCSI.txt
F: drivers/scsi/nsp32*
NTFS FILESYSTEM
-P: Anton Altaparmakov
-M: aia21@cantab.net
+M: Anton Altaparmakov <aia21@cantab.net>
L: linux-ntfs-dev@lists.sourceforge.net
W: http://www.linux-ntfs.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git
@@ -4257,16 +3694,14 @@ F: Documentation/filesystems/ntfs.txt
F: fs/ntfs/
NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
-P: Antonino Daplas
-M: adaplas@gmail.com
+M: Antonino Daplas <adaplas@gmail.com>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/riva/
F: drivers/video/nvidia/
OMAP SUPPORT
-P: Tony Lindgren <tony@atomide.com>
-M: tony@atomide.com
+M: "Tony Lindgren <tony@atomide.com>" <tony@atomide.com>
L: linux-omap@vger.kernel.org
W: http://www.muru.com/linux/omap/
W: http://linux.omap.com/
@@ -4275,98 +3710,83 @@ S: Maintained
F: arch/arm/*omap*
OMAP CLOCK FRAMEWORK SUPPORT
-P: Paul Walmsley
-M: paul@pwsan.com
+M: Paul Walmsley <paul@pwsan.com>
L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/*omap*/*clock*
OMAP POWER MANAGEMENT SUPPORT
-P: Kevin Hilman
-M: khilman@deeprootsystems.com
+M: Kevin Hilman <khilman@deeprootsystems.com>
L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/*omap*/*pm*
OMAP AUDIO SUPPORT
-P: Jarkko Nikula
-M: jhnikula@gmail.com
+M: Jarkko Nikula <jhnikula@gmail.com>
L: alsa-devel@alsa-project.org (subscribers-only)
L: linux-omap@vger.kernel.org
S: Maintained
F: sound/soc/omap/
OMAP FRAMEBUFFER SUPPORT
-P: Imre Deak
-M: imre.deak@nokia.com
+M: Imre Deak <imre.deak@nokia.com>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
L: linux-omap@vger.kernel.org
S: Maintained
F: drivers/video/omap/
OMAP MMC SUPPORT
-P: Jarkko Lavinen
-M: jarkko.lavinen@nokia.com
-L: linux-kernel@vger.kernel.org
+M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
L: linux-omap@vger.kernel.org
S: Maintained
F: drivers/mmc/host/*omap*
OMAP RANDOM NUMBER GENERATOR SUPPORT
-P: Deepak Saxena
-M: dsaxena@plexity.net
+M: Deepak Saxena <dsaxena@plexity.net>
S: Maintained
F: drivers/char/hw_random/omap-rng.c
OMAP USB SUPPORT
-P: Felipe Balbi
-M: felipe.balbi@nokia.com
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: Felipe Balbi <felipe.balbi@nokia.com>
+M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
L: linux-omap@vger.kernel.org
S: Maintained
OMFS FILESYSTEM
-P: Bob Copeland
-M: me@bobcopeland.com
+M: Bob Copeland <me@bobcopeland.com>
L: linux-karma-devel@lists.sourceforge.net
S: Maintained
F: Documentation/filesystems/omfs.txt
F: fs/omfs/
OMNIKEY CARDMAN 4000 DRIVER
-P: Harald Welte
-M: laforge@gnumonks.org
+M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/char/pcmcia/cm4000_cs.c
F: include/linux/cm4000_cs.h
OMNIKEY CARDMAN 4040 DRIVER
-P: Harald Welte
-M: laforge@gnumonks.org
+M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/char/pcmcia/cm4040_cs.*
OMNIVISION OV7670 SENSOR DRIVER
-P: Jonathan Corbet
-M: corbet@lwn.net
+M: Jonathan Corbet <corbet@lwn.net>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
F: drivers/media/video/ov7670.c
ONENAND FLASH DRIVER
-P: Kyungmin Park
-M: kyungmin.park@samsung.com
+M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/onenand/
F: include/linux/mtd/onenand*.h
ONSTREAM SCSI TAPE DRIVER
-P: Willem Riede
-M: osst@riede.org
+M: Willem Riede <osst@riede.org>
L: osst-users@lists.sourceforge.net
L: linux-scsi@vger.kernel.org
S: Maintained
@@ -4374,16 +3794,14 @@ F: drivers/scsi/osst*
F: drivers/scsi/st*
OPENCORES I2C BUS DRIVER
-P: Peter Korsgaard
-M: jacmet@sunsite.dk
+M: Peter Korsgaard <jacmet@sunsite.dk>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/busses/i2c-ocores
F: drivers/i2c/busses/i2c-ocores.c
OPROFILE
-P: Robert Richter
-M: robert.richter@amd.com
+M: Robert Richter <robert.richter@amd.com>
L: oprofile-list@lists.sf.net
S: Maintained
F: arch/*/oprofile/
@@ -4391,10 +3809,8 @@ F: drivers/oprofile/
F: include/linux/oprofile.h
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
-P: Mark Fasheh
-M: mfasheh@suse.com
-P: Joel Becker
-M: joel.becker@oracle.com
+M: Mark Fasheh <mfasheh@suse.com>
+M: Joel Becker <joel.becker@oracle.com>
L: ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
W: http://oss.oracle.com/projects/ocfs2/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2.git
@@ -4404,10 +3820,8 @@ F: Documentation/filesystems/dlmfs.txt
F: fs/ocfs2/
ORINOCO DRIVER
-P: Pavel Roskin
-M: proski@gnu.org
-P: David Gibson
-M: hermes@gibson.dropbear.id.au
+M: Pavel Roskin <proski@gnu.org>
+M: David Gibson <hermes@gibson.dropbear.id.au>
L: linux-wireless@vger.kernel.org
L: orinoco-users@lists.sourceforge.net
L: orinoco-devel@lists.sourceforge.net
@@ -4416,10 +3830,8 @@ S: Maintained
F: drivers/net/wireless/orinoco/
OSD LIBRARY and FILESYSTEM
-P: Boaz Harrosh
-M: bharrosh@panasas.com
-P: Benny Halevy
-M: bhalevy@panasas.com
+M: Boaz Harrosh <bharrosh@panasas.com>
+M: Benny Halevy <bhalevy@panasas.com>
L: osd-dev@open-osd.org
W: http://open-osd.org
T: git git://git.open-osd.org/open-osd.git
@@ -4429,8 +3841,7 @@ F: drivers/include/scsi/osd_*
F: fs/exofs/
P54 WIRELESS DRIVER
-P: Michael Wu
-M: flamingice@sourmilk.net
+M: Michael Wu <flamingice@sourmilk.net>
L: linux-wireless@vger.kernel.org
W: http://prism54.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
@@ -4438,30 +3849,25 @@ S: Maintained
F: drivers/net/wireless/p54/
PA SEMI ETHERNET DRIVER
-P: Olof Johansson
-M: olof@lixom.net
+M: Olof Johansson <olof@lixom.net>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pasemi_mac.*
PA SEMI SMBUS DRIVER
-P: Olof Johansson
-M: olof@lixom.net
+M: Olof Johansson <olof@lixom.net>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-pasemi.c
PANASONIC LAPTOP ACPI EXTRAS DRIVER
-P: Harald Welte
-M: laforge@gnumonks.org
+M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
PANASONIC MN10300/AM33 PORT
-P: David Howells
-M: dhowells@redhat.com
-P: Koichi Yasutake
-M: yasutake.koichi@jp.panasonic.com
+M: David Howells <dhowells@redhat.com>
+M: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
L: linux-am33-list@redhat.com (moderated for non-subscribers)
W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
S: Maintained
@@ -4477,14 +3883,10 @@ F: drivers/char/ppdev.c
F: include/linux/ppdev.h
PARAVIRT_OPS INTERFACE
-P: Jeremy Fitzhardinge
-M: jeremy@xensource.com
-P: Chris Wright
-M: chrisw@sous-sol.org
-P: Alok Kataria
-M: akataria@vmware.com
-P: Rusty Russell
-M: rusty@rustcorp.com.au
+M: Jeremy Fitzhardinge <jeremy@xensource.com>
+M: Chris Wright <chrisw@sous-sol.org>
+M: Alok Kataria <akataria@vmware.com>
+M: Rusty Russell <rusty@rustcorp.com.au>
L: virtualization@lists.osdl.org
S: Supported
F: Documentation/ia64/paravirt_ops.txt
@@ -4492,8 +3894,7 @@ F: arch/*/kernel/paravirt*
F: arch/*/include/asm/paravirt.h
PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
-P: Tim Waugh
-M: tim@cyberelk.net
+M: Tim Waugh <tim@cyberelk.net>
L: linux-parport@lists.infradead.org (subscribers-only)
W: http://www.torque.net/linux-pp.html
S: Maintained
@@ -4501,10 +3902,8 @@ F: Documentation/blockdev/paride.txt
F: drivers/block/paride/
PARISC ARCHITECTURE
-P: Kyle McMartin
-M: kyle@mcmartin.ca
-P: Helge Deller
-M: deller@gmx.de
+M: Kyle McMartin <kyle@mcmartin.ca>
+M: Helge Deller <deller@gmx.de>
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
@@ -4513,37 +3912,32 @@ F: arch/parisc/
F: drivers/parisc/
PC87360 HARDWARE MONITORING DRIVER
-P: Jim Cromie
-M: jim.cromie@gmail.com
+M: Jim Cromie <jim.cromie@gmail.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/pc87360
F: drivers/hwmon/pc87360.c
PC8736x GPIO DRIVER
-P: Jim Cromie
-M: jim.cromie@gmail.com
+M: Jim Cromie <jim.cromie@gmail.com>
S: Maintained
F: drivers/char/pc8736x_gpio.c
PCA9532 LED DRIVER
-P: Riku Voipio
-M: riku.voipio@iki.fi
+M: Riku Voipio <riku.voipio@iki.fi>
S: Maintained
F: drivers/leds/leds-pca9532.c
F: include/linux/leds-pca9532.h
PCI ERROR RECOVERY
-P: Linas Vepstas
-M: linas@austin.ibm.com
+M: Linas Vepstas <linas@austin.ibm.com>
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/PCI/pci-error-recovery.txt
F: Documentation/powerpc/eeh-pci-error-recovery.txt
PCI SUBSYSTEM
-P: Jesse Barnes
-M: jbarnes@virtuousgeek.org
+M: Jesse Barnes <jbarnes@virtuousgeek.org>
L: linux-pci@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
S: Supported
@@ -4552,8 +3946,7 @@ F: drivers/pci/
F: include/linux/pci*
PCIE HOTPLUG DRIVER
-P: Kristen Carlson Accardi
-M: kristen.c.accardi@intel.com
+M: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
L: linux-pci@vger.kernel.org
S: Supported
F: drivers/pci/pcie/
@@ -4569,121 +3962,103 @@ F: drivers/pcmcia/
F: include/pcmcia/
PCNET32 NETWORK DRIVER
-P: Don Fry
-M: pcnet32@verizon.net
+M: Don Fry <pcnet32@verizon.net>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcnet32.c
PER-TASK DELAY ACCOUNTING
-P: Balbir Singh
-M: balbir@linux.vnet.ibm.com
+M: Balbir Singh <balbir@linux.vnet.ibm.com>
S: Maintained
F: include/linux/delayacct.h
F: kernel/delayacct.c
PERFORMANCE COUNTER SUBSYSTEM
-P: Peter Zijlstra
-M: a.p.zijlstra@chello.nl
-P: Paul Mackerras
-M: paulus@samba.org
-P: Ingo Molnar
-M: mingo@elte.hu
-L: linux-kernel@vger.kernel.org
+M: Peter Zijlstra <a.p.zijlstra@chello.nl>
+M: Paul Mackerras <paulus@samba.org>
+M: Ingo Molnar <mingo@elte.hu>
S: Supported
PERSONALITY HANDLING
-P: Christoph Hellwig
-M: hch@infradead.org
+M: Christoph Hellwig <hch@infradead.org>
L: linux-abi-devel@lists.sourceforge.net
S: Maintained
F: include/linux/personality.h
PHRAM MTD DRIVER
-P: Joern Engel
-M: joern@lazybastard.org
+M: Joern Engel <joern@lazybastard.org>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/devices/phram.c
PKTCDVD DRIVER
-P: Peter Osterlund
-M: petero2@telia.com
+M: Peter Osterlund <petero2@telia.com>
S: Maintained
F: drivers/block/pktcdvd.c
F: include/linux/pktcdvd.h
POSIX CLOCKS and TIMERS
-P: Thomas Gleixner
-M: tglx@linutronix.de
+M: Thomas Gleixner <tglx@linutronix.de>
S: Supported
F: fs/timerfd.c
F: include/linux/timer*
F: kernel/*timer*
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
-P: Anton Vorontsov
-M: cbou@mail.ru
-P: David Woodhouse
-M: dwmw2@infradead.org
+M: Anton Vorontsov <cbou@mail.ru>
+M: David Woodhouse <dwmw2@infradead.org>
T: git git://git.infradead.org/battery-2.6.git
S: Maintained
F: include/linux/power_supply.h
F: drivers/power/power_supply*
PNP SUPPORT
-P: Adam Belay
-M: abelay@mit.edu
-P: Bjorn Helgaas
-M: bjorn.helgaas@hp.com
+M: Adam Belay <abelay@mit.edu>
+M: Bjorn Helgaas <bjorn.helgaas@hp.com>
S: Maintained
F: drivers/pnp/
PNXxxxx I2C DRIVER
-P: Vitaly Wool
-M: vitalywool@gmail.com
+M: Vitaly Wool <vitalywool@gmail.com>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-pnx.c
PPP PROTOCOL DRIVERS AND COMPRESSORS
-P: Paul Mackerras
-M: paulus@samba.org
+M: Paul Mackerras <paulus@samba.org>
L: linux-ppp@vger.kernel.org
S: Maintained
F: drivers/net/ppp_*
PPP OVER ATM (RFC 2364)
-P: Mitchell Blank Jr
-M: mitch@sfgoth.com
+M: Mitchell Blank Jr <mitch@sfgoth.com>
S: Maintained
F: net/atm/pppoatm.c
F: include/linux/atmppp.h
PPP OVER ETHERNET
-P: Michal Ostrowski
-M: mostrows@earthlink.net
+M: Michal Ostrowski <mostrows@earthlink.net>
S: Maintained
F: drivers/net/pppoe.c
F: drivers/net/pppox.c
PPP OVER L2TP
-P: James Chapman
-M: jchapman@katalix.com
+M: James Chapman <jchapman@katalix.com>
S: Maintained
F: drivers/net/pppol2tp.c
F: include/linux/if_pppol2tp.h
PPS SUPPORT
-P: Rodolfo Giometti
-M: giometti@enneenne.com
+M: Rodolfo Giometti <giometti@enneenne.com>
W: http://wiki.enneenne.com/index.php/LinuxPPS_support
L: linuxpps@ml.enneenne.com (subscribers-only)
S: Maintained
+F: Documentation/pps/
+F: drivers/pps/
+F: include/linux/pps*.h
PREEMPTIBLE KERNEL
-P: Robert Love
-M: rml@tech9.net
+M: Robert Love <rml@tech9.net>
L: kpreempt-tech@lists.sourceforge.net
W: ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
S: Supported
@@ -4691,37 +4066,32 @@ F: Documentation/preempt-locking.txt
F: include/linux/preempt.h
PRISM54 WIRELESS DRIVER
-P: Luis R. Rodriguez
-M: mcgrof@gmail.com
+M: "Luis R. Rodriguez" <mcgrof@gmail.com>
L: linux-wireless@vger.kernel.org
W: http://prism54.org
S: Maintained
F: drivers/net/wireless/prism54/
PROMISE DC4030 CACHING DISK CONTROLLER DRIVER
-P: Peter Denison
-M: promise@pnd-pc.demon.co.uk
+M: Peter Denison <promise@pnd-pc.demon.co.uk>
W: http://www.pnd-pc.demon.co.uk/promise/
S: Maintained
PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
-P: Mikael Pettersson
-M: mikpe@it.uu.se
+M: Mikael Pettersson <mikpe@it.uu.se>
L: linux-ide@vger.kernel.org
S: Maintained
F: drivers/ata/sata_promise.*
PS3 NETWORK SUPPORT
-P: Geoff Levand
-M: geoffrey.levand@am.sony.com
+M: Geoff Levand <geoffrey.levand@am.sony.com>
L: netdev@vger.kernel.org
L: cbe-oss-dev@ozlabs.org
S: Supported
F: drivers/net/ps3_gelic_net.*
PS3 PLATFORM SUPPORT
-P: Geoff Levand
-M: geoffrey.levand@am.sony.com
+M: Geoff Levand <geoffrey.levand@am.sony.com>
L: linuxppc-dev@ozlabs.org
L: cbe-oss-dev@ozlabs.org
S: Supported
@@ -4736,16 +4106,13 @@ F: drivers/usb/host/*ps3.c
F: sound/ppc/snd_ps3*
PS3VRAM DRIVER
-P: Jim Paris
-M: jim@jtan.com
+M: Jim Paris <jim@jtan.com>
L: cbe-oss-dev@ozlabs.org
S: Maintained
PTRACE SUPPORT
-P: Roland McGrath
-M: roland@redhat.com
-P: Oleg Nesterov
-M: oleg@redhat.com
+M: Roland McGrath <roland@redhat.com>
+M: Oleg Nesterov <oleg@redhat.com>
S: Maintained
F: include/asm-generic/syscall.h
F: include/linux/ptrace.h
@@ -4754,8 +4121,7 @@ F: include/linux/tracehook.h
F: kernel/ptrace.c
PVRUSB2 VIDEO4LINUX DRIVER
-P: Mike Isely
-M: isely@pobox.com
+M: Mike Isely <isely@pobox.com>
L: pvrusb2@isely.net (subscribers-only)
L: linux-media@vger.kernel.org
W: http://www.isely.net/pvrusb2/
@@ -4765,10 +4131,8 @@ F: Documentation/video4linux/README.pvrusb2
F: drivers/media/video/pvrusb2/
PXA2xx/PXA3xx SUPPORT
-P: Eric Miao
-M: eric.y.miao@gmail.com
-P: Russell King
-M: linux@arm.linux.org.uk
+M: Eric Miao <eric.y.miao@gmail.com>
+M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
F: arch/arm/mach-pxa/
@@ -4780,17 +4144,14 @@ F: sound/arm/pxa*
F: sound/soc/pxa
PXA168 SUPPORT
-P: Eric Miao
-M: eric.y.miao@gmail.com
-P: Jason Chagas
-M: jason.chagas@marvell.com
+M: Eric Miao <eric.y.miao@gmail.com>
+M: Jason Chagas <jason.chagas@marvell.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
S: Maintained
PXA910 SUPPORT
-P: Eric Miao
-M: eric.y.miao@gmail.com
+M: Eric Miao <eric.y.miao@gmail.com>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
S: Maintained
@@ -4799,13 +4160,12 @@ PXA MMCI DRIVER
S: Orphan
PXA RTC DRIVER
-P: Robert Jarzmik
-M: robert.jarzmik@free.fr
+M: Robert Jarzmik <robert.jarzmik@free.fr>
L: rtc-linux@googlegroups.com
S: Maintained
QLOGIC QLA2XXX FC-SCSI DRIVER
-P: Andrew Vasquez
+M: Andrew Vasquez <andrew.vasquez@qlogic.com>
M: linux-driver@qlogic.com
L: linux-scsi@vger.kernel.org
S: Supported
@@ -4813,7 +4173,7 @@ F: Documentation/scsi/LICENSE.qla2xxx
F: drivers/scsi/qla2xxx/
QLOGIC QLA3XXX NETWORK DRIVER
-P: Ron Mercer
+M: Ron Mercer <ron.mercer@qlogic.com>
M: linux-driver@qlogic.com
L: netdev@vger.kernel.org
S: Supported
@@ -4821,16 +4181,14 @@ F: Documentation/networking/LICENSE.qla3xxx
F: drivers/net/qla3xxx.*
QLOGIC QLGE 10Gb ETHERNET DRIVER
-P: Ron Mercer
+M: Ron Mercer <ron.mercer@qlogic.com>
M: linux-driver@qlogic.com
-M: ron.mercer@qlogic.com
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/qlge/
QNX4 FILESYSTEM
-P: Anders Larsen
-M: al@alarsen.net
+M: Anders Larsen <al@alarsen.net>
W: http://www.alarsen.net/linux/qnx4fs/
S: Maintained
F: fs/qnx4/
@@ -4838,16 +4196,14 @@ F: include/linux/qnx4_fs.h
F: include/linux/qnxtypes.h
RADEON FRAMEBUFFER DISPLAY DRIVER
-P: Benjamin Herrenschmidt
-M: benh@kernel.crashing.org
+M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/aty/radeon*
F: include/linux/radeonfb.h
RAGE128 FRAMEBUFFER DISPLAY DRIVER
-P: Paul Mackerras
-M: paulus@samba.org
+M: Paul Mackerras <paulus@samba.org>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/aty/aty128fb.c
@@ -4862,64 +4218,53 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git
F: drivers/net/wireless/rt2x00/
RAMDISK RAM BLOCK DEVICE DRIVER
-P: Nick Piggin
-M: npiggin@suse.de
+M: Nick Piggin <npiggin@suse.de>
S: Maintained
F: Documentation/blockdev/ramdisk.txt
F: drivers/block/brd.c
RANDOM NUMBER DRIVER
-P: Matt Mackall
-M: mpm@selenic.com
+M: Matt Mackall <mpm@selenic.com>
S: Maintained
F: drivers/char/random.c
RAPIDIO SUBSYSTEM
-P: Matt Porter
-M: mporter@kernel.crashing.org
+M: Matt Porter <mporter@kernel.crashing.org>
S: Maintained
F: drivers/rapidio/
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-P: Corey Thomas
-M: coreythomas@charter.net
+M: Corey Thomas <coreythomas@charter.net>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/ray*
RCUTORTURE MODULE
-P: Josh Triplett
-M: josh@freedesktop.org
-P: Paul E. McKenney
-M: paulmck@linux.vnet.ibm.com
+M: Josh Triplett <josh@freedesktop.org>
+M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
S: Maintained
F: Documentation/RCU/torture.txt
F: kernel/rcutorture.c
RDC R-321X SoC
-P: Florian Fainelli
-M: florian@openwrt.org
+M: Florian Fainelli <florian@openwrt.org>
S: Maintained
RDC R6040 FAST ETHERNET DRIVER
-P: Florian Fainelli
-M: florian@openwrt.org
+M: Florian Fainelli <florian@openwrt.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/r6040.c
RDS - RELIABLE DATAGRAM SOCKETS
-P: Andy Grover
-M: andy.grover@oracle.com
+M: Andy Grover <andy.grover@oracle.com>
L: rds-devel@oss.oracle.com (moderated for non-subscribers)
S: Supported
F: net/rds/
READ-COPY UPDATE (RCU)
-P: Dipankar Sarma
-M: dipankar@in.ibm.com
-P: Paul E. McKenney
-M: paulmck@linux.vnet.ibm.com
+M: Dipankar Sarma <dipankar@in.ibm.com>
+M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
W: http://www.rdrop.com/users/paulmck/rclock/
S: Supported
F: Documentation/RCU/rcu.txt
@@ -4929,16 +4274,14 @@ F: include/linux/srcu.h
F: kernel/rcupdate.c
REAL TIME CLOCK DRIVER
-P: Paul Gortmaker
-M: p_gortmaker@yahoo.com
+M: Paul Gortmaker <p_gortmaker@yahoo.com>
S: Maintained
F: Documentation/rtc.txt
F: drivers/rtc/
F: include/linux/rtc.h
REAL TIME CLOCK (RTC) SUBSYSTEM
-P: Alessandro Zummo
-M: a.zummo@towertech.it
+M: Alessandro Zummo <a.zummo@towertech.it>
L: rtc-linux@googlegroups.com
S: Maintained
F: Documentation/rtc.txt
@@ -4951,8 +4294,7 @@ S: Supported
F: fs/reiserfs/
RFKILL
-P: Johannes Berg
-M: johannes@sipsolutions.net
+M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
S: Maintained
F Documentation/rfkill.txt
@@ -4971,8 +4313,7 @@ F: Documentation/serial/rocket.txt
F: drivers/char/rocket*
ROSE NETWORK LAYER
-P: Ralf Baechle
-M: ralf@linux-mips.org
+M: Ralf Baechle <ralf@linux-mips.org>
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
@@ -4981,21 +4322,17 @@ F: include/net/rose.h
F: net/rose/
RTL8180 WIRELESS DRIVER
-P: John W. Linville
-M: linville@tuxdriver.com
+M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
-F: drivers/net/wireless/rtl818*
+F: drivers/net/wireless/rtl818x/rtl8180*
RTL8187 WIRELESS DRIVER
-P: Herton Ronaldo Krzesinski
-M: herton@mandriva.com.br
-P: Hin-Tak Leung
-M: htl10@users.sourceforge.net
-P: Larry Finger
-M: Larry.Finger@lwfinger.net
+M: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+M: Hin-Tak Leung <htl10@users.sourceforge.net>
+M: Larry Finger <Larry.Finger@lwfinger.net>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
@@ -5003,17 +4340,14 @@ S: Maintained
F: drivers/net/wireless/rtl818x/rtl8187*
S3 SAVAGE FRAMEBUFFER DRIVER
-P: Antonino Daplas
-M: adaplas@gmail.com
+M: Antonino Daplas <adaplas@gmail.com>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/savage/
S390
-P: Martin Schwidefsky
-M: schwidefsky@de.ibm.com
-P: Heiko Carstens
-M: heiko.carstens@de.ibm.com
+M: Martin Schwidefsky <schwidefsky@de.ibm.com>
+M: Heiko Carstens <heiko.carstens@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5021,10 +4355,8 @@ S: Supported
F: arch/s390/
S390 NETWORK DRIVERS
-P: Ursula Braun
-M: ursula.braun@de.ibm.com
-P: Frank Blaschka
-M: blaschka@linux.vnet.ibm.com
+M: Ursula Braun <ursula.braun@de.ibm.com>
+M: Frank Blaschka <blaschka@linux.vnet.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5032,20 +4364,16 @@ S: Supported
F: drivers/s390/net/
S390 ZCRYPT DRIVER
-P: Felix Beck
-M: felix.beck@de.ibm.com
-P: Ralph Wuerthner
-M: ralph.wuerthner@de.ibm.com
+M: Felix Beck <felix.beck@de.ibm.com>
+M: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
S: Supported
F: drivers/s390/crypto/
S390 ZFCP DRIVER
-P: Christof Schmitt
-M: christof.schmitt@de.ibm.com
-P: Martin Peschke
-M: mp3@de.ibm.com
+M: Christof Schmitt <christof.schmitt@de.ibm.com>
+M: Martin Peschke <mp3@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5054,8 +4382,7 @@ F: Documentation/s390/zfcpdump.txt
F: drivers/s390/scsi/zfcp_*
S390 IUCV NETWORK LAYER
-P: Ursula Braun
-M: ursula.braun@de.ibm.com
+M: Ursula Braun <ursula.braun@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5065,15 +4392,13 @@ F: include/net/iucv/
F: net/iucv/
S3C24XX SD/MMC Driver
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Supported
F: drivers/mmc/host/s3cmci.*
SAA7146 VIDEO4LINUX-2 DRIVER
-P: Michael Hunold
-M: michael@mihu.de
+M: Michael Hunold <michael@mihu.de>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
W: http://www.mihu.de/linux/saa7146
@@ -5083,31 +4408,26 @@ F: drivers/media/video/*7146*
F: include/media/*7146*
SC1200 WDT DRIVER
-P: Zwane Mwaikambo
-M: zwane@arm.linux.org.uk
+M: Zwane Mwaikambo <zwane@arm.linux.org.uk>
S: Maintained
F: drivers/watchdog/sc1200wdt.c
SCHEDULER
-P: Ingo Molnar
-M: mingo@elte.hu
-P: Peter Zijlstra
-M: peterz@infradead.org
+M: Ingo Molnar <mingo@elte.hu>
+M: Peter Zijlstra <peterz@infradead.org>
S: Maintained
F: kernel/sched*
F: include/linux/sched.h
SCSI CDROM DRIVER
-P: Jens Axboe
-M: axboe@kernel.dk
+M: Jens Axboe <axboe@kernel.dk>
L: linux-scsi@vger.kernel.org
W: http://www.kernel.dk
S: Maintained
F: drivers/scsi/sr*
SCSI SG DRIVER
-P: Doug Gilbert
-M: dgilbert@interlog.com
+M: Doug Gilbert <dgilbert@interlog.com>
L: linux-scsi@vger.kernel.org
W: http://www.torque.net/sg
S: Maintained
@@ -5115,8 +4435,7 @@ F: drivers/scsi/sg.c
F: include/scsi/sg.h
SCSI SUBSYSTEM
-P: James E.J. Bottomley
-M: James.Bottomley@HansenPartnership.com
+M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
L: linux-scsi@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6.git
@@ -5126,18 +4445,15 @@ F: drivers/scsi/
F: include/scsi/
SCSI TAPE DRIVER
-P: Kai Mäkisara
-M: Kai.Makisara@kolumbus.fi
+M: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/st.txt
F: drivers/scsi/st*
SCTP PROTOCOL
-P: Vlad Yasevich
-M: vladislav.yasevich@hp.com
-P: Sridhar Samudrala
-M: sri@us.ibm.com
+M: Vlad Yasevich <vladislav.yasevich@hp.com>
+M: Sridhar Samudrala <sri@us.ibm.com>
L: linux-sctp@vger.kernel.org
W: http://lksctp.sourceforge.net
S: Supported
@@ -5147,8 +4463,7 @@ F: include/net/sctp/
F: net/sctp/
SCx200 CPU SUPPORT
-P: Jim Cromie
-M: jim.cromie@gmail.com
+M: Jim Cromie <jim.cromie@gmail.com>
S: Odd Fixes
F: Documentation/i2c/busses/scx200_acb
F: arch/x86/kernel/scx200_32.c
@@ -5158,49 +4473,42 @@ F: drivers/mtd/maps/scx200_docflash.c
F: include/linux/scx200.h
SCx200 GPIO DRIVER
-P: Jim Cromie
-M: jim.cromie@gmail.com
+M: Jim Cromie <jim.cromie@gmail.com>
S: Maintained
F: drivers/char/scx200_gpio.c
F: include/linux/scx200_gpio.h
SCx200 HRT CLOCKSOURCE DRIVER
-P: Jim Cromie
-M: jim.cromie@gmail.com
+M: Jim Cromie <jim.cromie@gmail.com>
S: Maintained
F: drivers/clocksource/scx200_hrt.c
SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER
-P: Sascha Sommer
-M: saschasommer@freenet.de
+M: Sascha Sommer <saschasommer@freenet.de>
L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
F: drivers/mmc/host/sdricoh_cs.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
-P: Pierre Ossman
-M: pierre@ossman.eu
+M: Pierre Ossman <pierre@ossman.eu>
L: sdhci-devel@lists.ossman.eu
S: Maintained
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
-P: Anton Vorontsov
-M: avorontsov@ru.mvista.com
+M: Anton Vorontsov <avorontsov@ru.mvista.com>
L: linuxppc-dev@ozlabs.org
L: sdhci-devel@lists.ossman.eu
S: Maintained
F: drivers/mmc/host/sdhci.*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
-P: Ben Dooks
-M: ben-linux@fluff.org
+M: Ben Dooks <ben-linux@fluff.org>
L: sdhci-devel@lists.ossman.eu
S: Maintained
F: drivers/mmc/host/sdhci-s3c.c
SECURITY SUBSYSTEM
-P: James Morris
-M: jmorris@namei.org
+M: James Morris <jmorris@namei.org>
L: linux-security-module@vger.kernel.org (suggested Cc:)
T: git git://www.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
W: http://security.wiki.kernel.org/
@@ -5208,17 +4516,13 @@ S: Supported
F: security/
SECURITY CONTACT
-P: Security Officers
-M: security@kernel.org
+M: Security Officers <security@kernel.org>
S: Supported
SELINUX SECURITY MODULE
-P: Stephen Smalley
-M: sds@tycho.nsa.gov
-P: James Morris
-M: jmorris@namei.org
-P: Eric Paris
-M: eparis@parisplace.org
+M: Stephen Smalley <sds@tycho.nsa.gov>
+M: James Morris <jmorris@namei.org>
+M: Eric Paris <eparis@parisplace.org>
L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
W: http://selinuxproject.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
@@ -5227,15 +4531,13 @@ F: include/linux/selinux*
F: security/selinux/
SENSABLE PHANTOM
-P: Jiri Slaby
-M: jirislaby@gmail.com
+M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
F: drivers/misc/phantom.c
F: include/linux/phantom.h
SERIAL ATA (SATA) SUBSYSTEM
-P: Jeff Garzik
-M: jgarzik@pobox.com
+M: Jeff Garzik <jgarzik@pobox.com>
L: linux-ide@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
S: Supported
@@ -5244,10 +4546,8 @@ F: include/linux/ata.h
F: include/linux/libata.h
SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
-P: Sathya Perla
-M: sathyap@serverengines.com
-P: Subbu Seetharaman
-M: subbus@serverengines.com
+M: Sathya Perla <sathyap@serverengines.com>
+M: Subbu Seetharaman <subbus@serverengines.com>
L: netdev@vger.kernel.org
W: http://www.serverengines.com
S: Supported
@@ -5256,20 +4556,17 @@ F: drivers/net/benet/
SFC NETWORK DRIVER
P: Steve Hodgson
P: Ben Hutchings
-P: Robert Stonehouse
-M: linux-net-drivers@solarflare.com
+M: Robert Stonehouse <linux-net-drivers@solarflare.com>
S: Supported
F: drivers/net/sfc/
SGI GRU DRIVER
-P: Jack Steiner
-M: steiner@sgi.com
+M: Jack Steiner <steiner@sgi.com>
S: Maintained
F: drivers/misc/sgi-gru/
SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
-P: Pat Gefre
-M: pfg@sgi.com
+M: Pat Gefre <pfg@sgi.com>
L: linux-ia64@vger.kernel.org
S: Supported
F: Documentation/ia64/serial.txt
@@ -5277,22 +4574,19 @@ F: drivers/serial/ioc?_serial.c
F: include/linux/ioc?.h
SGI VISUAL WORKSTATION 320 AND 540
-P: Andrey Panin
-M: pazke@donpac.ru
+M: Andrey Panin <pazke@donpac.ru>
L: linux-visws-devel@lists.sf.net
W: http://linux-visws.sf.net
S: Maintained for 2.6.
F: Documentation/sgi-visws.txt
SGI XP/XPC/XPNET DRIVER
-P: Robin Holt
-M: holt@sgi.com
+M: Robin Holt <holt@sgi.com>
S: Maintained
F: drivers/misc/sgi-xp/
SHARP LH SUPPORT (LH7952X & LH7A40X)
-P: Marc Singer
-M: elf@buici.com
+M: Marc Singer <elf@buici.com>
W: http://projects.buici.com/arm
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
@@ -5303,8 +4597,7 @@ F: drivers/usb/gadget/lh7a40*
F: drivers/usb/host/ohci-lh7a40*
SHPC HOTPLUG DRIVER
-P: Kristen Carlson Accardi
-M: kristen.c.accardi@intel.com
+M: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
L: linux-pci@vger.kernel.org
S: Supported
F: drivers/pci/hotplug/shpchp*
@@ -5323,47 +4616,47 @@ F: include/linux/sfi*.h
SIMTEC EB110ATX (Chalice CATS)
P: Ben Dooks
-P: Vincent Sanders
-M: support@simtec.co.uk
+M: Vincent Sanders <support@simtec.co.uk>
W: http://www.simtec.co.uk/products/EB110ATX/
S: Supported
SIMTEC EB2410ITX (BAST)
P: Ben Dooks
-P: Vincent Sanders
-M: support@simtec.co.uk
+M: Vincent Sanders <support@simtec.co.uk>
W: http://www.simtec.co.uk/products/EB2410ITX/
S: Supported
F: arch/arm/mach-s3c2410/
F: drivers/*/*s3c2410*
F: drivers/*/*/*s3c2410*
+TI DAVINCI MACHINE SUPPORT
+P: Kevin Hilman
+M: davinci-linux-open-source@linux.davincidsp.com
+S: Supported
+F: arch/arm/mach-davinci
+
SIS 190 ETHERNET DRIVER
-P: Francois Romieu
-M: romieu@fr.zoreil.com
+M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/sis190.c
SIS 900/7016 FAST ETHERNET DRIVER
-P: Daniele Venzano
-M: venza@brownhat.org
+M: Daniele Venzano <venza@brownhat.org>
W: http://www.brownhat.org/sis900.html
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/sis900.*
SIS 96X I2C/SMBUS DRIVER
-P: Mark M. Hoffman
-M: mhoffman@lightlink.com
+M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/busses/i2c-sis96x
F: drivers/i2c/busses/i2c-sis96x.c
SIS FRAMEBUFFER DRIVER
-P: Thomas Winischhofer
-M: thomas@winischhofer.net
+M: Thomas Winischhofer <thomas@winischhofer.net>
W: http://www.winischhofer.net/linuxsisvga.shtml
S: Maintained
F: Documentation/fb/sisfb.txt
@@ -5371,70 +4664,59 @@ F: drivers/video/sis/
F: include/video/sisfb.h
SIS USB2VGA DRIVER
-P: Thomas Winischhofer
-M: thomas@winischhofer.net
+M: Thomas Winischhofer <thomas@winischhofer.net>
W: http://www.winischhofer.at/linuxsisusbvga.shtml
S: Maintained
F: drivers/usb/misc/sisusbvga/
SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-P: Stephen Hemminger
-M: shemminger@linux-foundation.org
+M: Stephen Hemminger <shemminger@linux-foundation.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/skge.*
F: drivers/net/sky2.*
SLAB ALLOCATOR
-P: Christoph Lameter
-M: cl@linux-foundation.org
-P: Pekka Enberg
-M: penberg@cs.helsinki.fi
-P: Matt Mackall
-M: mpm@selenic.com
+M: Christoph Lameter <cl@linux-foundation.org>
+M: Pekka Enberg <penberg@cs.helsinki.fi>
+M: Matt Mackall <mpm@selenic.com>
L: linux-mm@kvack.org
S: Maintained
F: include/linux/sl?b*.h
F: mm/sl?b.c
SMC91x ETHERNET DRIVER
-P: Nicolas Pitre
-M: nico@cam.org
+M: Nicolas Pitre <nico@cam.org>
S: Maintained
F: drivers/net/smc91x.*
SMSC47B397 HARDWARE MONITOR DRIVER
-P: Mark M. Hoffman
-M: mhoffman@lightlink.com
+M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/smsc47b397
F: drivers/hwmon/smsc47b397.c
SMSC911x ETHERNET DRIVER
-P: Steve Glendinning
-M: steve.glendinning@smsc.com
+M: Steve Glendinning <steve.glendinning@smsc.com>
L: netdev@vger.kernel.org
S: Supported
F: include/linux/smsc911x.h
F: drivers/net/smsc911x.*
SMSC9420 PCI ETHERNET DRIVER
-P: Steve Glendinning
-M: steve.glendinning@smsc.com
+M: Steve Glendinning <steve.glendinning@smsc.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/smsc9420.*
SMX UIO Interface
-P: Ben Nizette
-M: bn@niasdigital.com
+M: Ben Nizette <bn@niasdigital.com>
S: Maintained
F: drivers/uio/uio_smx.c
SN-IA64 (Itanium) SUB-PLATFORM
-P: Jes Sorensen
-M: jes@sgi.com
+M: Jes Sorensen <jes@sgi.com>
L: linux-altix@sgi.com
L: linux-ia64@vger.kernel.org
W: http://www.sgi.com/altix
@@ -5442,8 +4724,7 @@ S: Maintained
F: arch/ia64/sn/
SOC-CAMERA V4L2 SUBSYSTEM
-P: Guennadi Liakhovetski
-M: g.liakhovetski@gmx.de
+M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
@@ -5451,37 +4732,32 @@ F: include/media/v4l2*
F: drivers/media/video/v4l2*
SOEKRIS NET48XX LED SUPPORT
-P: Chris Boot
-M: bootc@bootc.net
+M: Chris Boot <bootc@bootc.net>
S: Maintained
F: drivers/leds/leds-net48xx.c
SOFTWARE RAID (Multiple Disks) SUPPORT
-P: Neil Brown
-M: neilb@suse.de
+M: Neil Brown <neilb@suse.de>
L: linux-raid@vger.kernel.org
S: Supported
F: drivers/md/
F: include/linux/raid/
SONIC NETWORK DRIVER
-P: Thomas Bogendoerfer
-M: tsbogend@alpha.franken.de
+M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/sonic.*
SONICS SILICON BACKPLANE DRIVER (SSB)
-P: Michael Buesch
-M: mb@bu3sch.de
+M: Michael Buesch <mb@bu3sch.de>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/ssb/
F: include/linux/ssb/
SONY VAIO CONTROL DEVICE DRIVER
-P: Mattia Dongili
-M: malattia@linux.it
+M: Mattia Dongili <malattia@linux.it>
L: linux-acpi@vger.kernel.org
W: http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
S: Maintained
@@ -5491,17 +4767,14 @@ F: drivers/platform/x86/sony-laptop.c
F: include/linux/sony-laptop.h
SONY MEMORYSTICK CARD SUPPORT
-P: Alex Dubov
-M: oakad@yahoo.com
+M: Alex Dubov <oakad@yahoo.com>
W: http://tifmxx.berlios.de/
S: Maintained
F: drivers/memstick/host/tifm_ms.c
SOUND
-P: Jaroslav Kysela
-M: perex@perex.cz
-P: Takashi Iwai
-M: tiwai@suse.de
+M: Jaroslav Kysela <perex@perex.cz>
+M: Takashi Iwai <tiwai@suse.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://www.alsa-project.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
@@ -5512,10 +4785,8 @@ F: include/sound/
F: sound/
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-P: Liam Girdwood
-M: lrg@slimlogic.co.uk
-P: Mark Brown
-M: broonie@opensource.wolfsonmicro.com
+M: Liam Girdwood <lrg@slimlogic.co.uk>
+M: Mark Brown <broonie@opensource.wolfsonmicro.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://alsa-project.org/main/index.php/ASoC
@@ -5524,8 +4795,7 @@ F: sound/soc/
F: include/sound/soc*
SPARC + UltraSPARC (sparc/sparc64)
-P: David S. Miller
-M: davem@davemloft.net
+M: "David S. Miller" <davem@davemloft.net>
L: sparclinux@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
@@ -5533,15 +4803,13 @@ S: Maintained
F: arch/sparc/
SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
-P: Roger Wolff
-M: R.E.Wolff@BitWizard.nl
+M: Roger Wolff <R.E.Wolff@BitWizard.nl>
S: Supported
F: Documentation/serial/specialix.txt
F: drivers/char/specialix*
SPI SUBSYSTEM
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
L: spi-devel-general@lists.sourceforge.net
S: Maintained
F: Documentation/spi/
@@ -5549,18 +4817,15 @@ F: drivers/spi/
F: include/linux/spi/
SPIDERNET NETWORK DRIVER for CELL
-P: Ishizaki Kou
-M: kou.ishizaki@toshiba.co.jp
-P: Jens Osterkamp
-M: jens@de.ibm.com
+M: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
+M: Jens Osterkamp <jens@de.ibm.com>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/networking/spider_net.txt
F: drivers/net/spider_net*
SPU FILE SYSTEM
-P: Jeremy Kerr
-M: jk@ozlabs.org
+M: Jeremy Kerr <jk@ozlabs.org>
L: linuxppc-dev@ozlabs.org
L: cbe-oss-dev@ozlabs.org
W: http://www.ibm.com/developerworks/power/cell/
@@ -5569,8 +4834,7 @@ F: Documentation/filesystems/spufs.txt
F: arch/powerpc/platforms/cell/spufs/
SQUASHFS FILE SYSTEM
-P: Phillip Lougher
-M: phillip@lougher.demon.co.uk
+M: Phillip Lougher <phillip@lougher.demon.co.uk>
L: squashfs-devel@lists.sourceforge.net (subscribers-only)
W: http://squashfs.org.uk
S: Maintained
@@ -5578,30 +4842,25 @@ F: Documentation/filesystems/squashfs.txt
F: fs/squashfs/
SRM (Alpha) environment access
-P: Jan-Benedict Glaw
-M: jbglaw@lug-owl.de
+M: Jan-Benedict Glaw <jbglaw@lug-owl.de>
S: Maintained
F: arch/alpha/kernel/srm_env.c
STABLE BRANCH
-P: Greg Kroah-Hartman
-M: greg@kroah.com
-P: Chris Wright
-M: chrisw@sous-sol.org
+M: Greg Kroah-Hartman <greg@kroah.com>
+M: Chris Wright <chrisw@sous-sol.org>
L: stable@kernel.org
S: Maintained
STAGING SUBSYSTEM
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+M: Greg Kroah-Hartman <gregkh@suse.de>
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
L: devel@driverdev.osuosl.org
S: Maintained
F: drivers/staging/
STARFIRE/DURALAN NETWORK DRIVER
-P: Ion Badulescu
-M: ionut@badula.org
+M: Ion Badulescu <ionut@badula.org>
S: Odd Fixes
F: drivers/net/starfire*
@@ -5611,15 +4870,13 @@ F: drivers/net/wireless/strip.c
F: include/linux/if_strip.h
STRADIS MPEG-2 DECODER DRIVER
-P: Nathan Laredo
-M: laredo@gnu.org
+M: Nathan Laredo <laredo@gnu.org>
W: http://www.stradis.com/
S: Maintained
F: drivers/media/video/stradis.c
SUN3/3X
-P: Sam Creasey
-M: sammy@sammy.net
+M: Sam Creasey <sammy@sammy.net>
W: http://sammy.net/sun3/
S: Maintained
F: arch/m68k/kernel/*sun3*
@@ -5627,8 +4884,7 @@ F: arch/m68k/sun3*/
F: arch/m68k/include/asm/sun3*
SUPERH
-P: Paul Mundt
-M: lethal@linux-sh.org
+M: Paul Mundt <lethal@linux-sh.org>
L: linux-sh@vger.kernel.org
W: http://www.linux-sh.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git
@@ -5638,12 +4894,9 @@ F: arch/sh/
F: drivers/sh/
SUSPEND TO RAM
-P: Len Brown
-M: len.brown@intel.com
-P: Pavel Machek
-M: pavel@ucw.cz
-P: Rafael J. Wysocki
-M: rjw@sisk.pl
+M: Len Brown <len.brown@intel.com>
+M: Pavel Machek <pavel@ucw.cz>
+M: "Rafael J. Wysocki" <rjw@sisk.pl>
L: linux-pm@lists.linux-foundation.org
S: Supported
F: Documentation/power/
@@ -5655,32 +4908,28 @@ F: include/linux/freezer.h
F: include/linux/pm.h
SVGA HANDLING
-P: Martin Mares
-M: mj@ucw.cz
+M: Martin Mares <mj@ucw.cz>
L: linux-video@atrey.karlin.mff.cuni.cz
S: Maintained
F: Documentation/svga.txt
F: arch/x86/boot/video*
SYSV FILESYSTEM
-P: Christoph Hellwig
-M: hch@infradead.org
+M: Christoph Hellwig <hch@infradead.org>
S: Maintained
F: Documentation/filesystems/sysv-fs.txt
F: fs/sysv/
F: include/linux/sysv_fs.h
TASKSTATS STATISTICS INTERFACE
-P: Balbir Singh
-M: balbir@linux.vnet.ibm.com
+M: Balbir Singh <balbir@linux.vnet.ibm.com>
S: Maintained
F: Documentation/accounting/taskstats*
F: include/linux/taskstats*
F: kernel/taskstats.c
TC CLASSIFIER
-P: Jamal Hadi Salim
-M: hadi@cyberus.ca
+M: Jamal Hadi Salim <hadi@cyberus.ca>
L: netdev@vger.kernel.org
S: Maintained
F: include/linux/pkt_cls.h
@@ -5688,38 +4937,31 @@ F: include/net/pkt_cls.h
F: net/sched/
TCP LOW PRIORITY MODULE
-P: Wong Hoi Sing, Edison
-M: hswong3i@gmail.com
-P: Hung Hing Lun, Mike
-M: hlhung3i@gmail.com
+M: "Wong Hoi Sing, Edison" <hswong3i@gmail.com>
+M: "Hung Hing Lun, Mike" <hlhung3i@gmail.com>
W: http://tcp-lp-mod.sourceforge.net/
S: Maintained
F: net/ipv4/tcp_lp.c
TEHUTI ETHERNET DRIVER
-P: Alexander Indenbaum
-M: baum@tehutinetworks.net
-P: Andy Gospodarek
-M: andy@greyhouse.net
+M: Alexander Indenbaum <baum@tehutinetworks.net>
+M: Andy Gospodarek <andy@greyhouse.net>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/tehuti*
Telecom Clock Driver for MCPL0010
-P: Mark Gross
-M: mark.gross@intel.com
+M: Mark Gross <mark.gross@intel.com>
S: Supported
F: drivers/char/tlclk.c
TENSILICA XTENSA PORT (xtensa)
-P: Chris Zankel
-M: chris@zankel.net
+M: Chris Zankel <chris@zankel.net>
S: Maintained
F: arch/xtensa/
THINKPAD ACPI EXTRAS DRIVER
-P: Henrique de Moraes Holschuh
-M: ibm-acpi@hmh.eng.br
+M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
L: ibm-acpi-devel@lists.sourceforge.net
W: http://ibm-acpi.sourceforge.net
W: http://thinkwiki.org/wiki/Ibm-acpi
@@ -5728,27 +4970,22 @@ S: Maintained
F: drivers/platform/x86/thinkpad_acpi.c
TI FLASH MEDIA INTERFACE DRIVER
-P: Alex Dubov
-M: oakad@yahoo.com
+M: Alex Dubov <oakad@yahoo.com>
S: Maintained
F: drivers/misc/tifm*
F: drivers/mmc/host/tifm_sd.c
F: include/linux/tifm.h
TI TWL4030 SERIES SOC CODEC DRIVER
-P: Peter Ujfalusi
-M: peter.ujfalusi@nokia.com
+M: Peter Ujfalusi <peter.ujfalusi@nokia.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/codecs/twl4030*
TIPC NETWORK LAYER
-P: Per Liden
-M: per.liden@ericsson.com
-P: Jon Maloy
-M: jon.maloy@ericsson.com
-P: Allan Stephens
-M: allan.stephens@windriver.com
+M: Per Liden <per.liden@ericsson.com>
+M: Jon Maloy <jon.maloy@ericsson.com>
+M: Allan Stephens <allan.stephens@windriver.com>
L: tipc-discussion@lists.sourceforge.net
W: http://tipc.sourceforge.net/
W: http://tipc.cslab.ericsson.net/
@@ -5759,8 +4996,7 @@ F: include/net/tipc/
F: net/tipc/
TLAN NETWORK DRIVER
-P: Samuel Chessman
-M: chessman@tux.org
+M: Samuel Chessman <chessman@tux.org>
L: tlan-devel@lists.sourceforge.net (subscribers-only)
W: http://sourceforge.net/projects/tlan/
S: Maintained
@@ -5768,10 +5004,8 @@ F: Documentation/networking/tlan.txt
F: drivers/net/tlan.*
TOMOYO SECURITY MODULE
-P: Kentaro Takeda
-M: takedakn@nttdata.co.jp
-P: Tetsuo Handa
-M: penguin-kernel@I-love.SAKURA.ne.jp
+M: Kentaro Takeda <takedakn@nttdata.co.jp>
+M: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
@@ -5785,8 +5019,7 @@ S: Orphan
F: drivers/platform/x86/toshiba_acpi.c
TOSHIBA SMM DRIVER
-P: Jonathan Buzzard
-M: jonathan@buzzard.org.uk
+M: Jonathan Buzzard <jonathan@buzzard.org.uk>
L: tlinux-users@tce.toshiba-dme.co.jp
W: http://www.buzzard.org.uk/toshiba/
S: Maintained
@@ -5794,43 +5027,36 @@ F: drivers/char/toshiba.c
F: include/linux/toshiba.h
TMIO MMC DRIVER
-P: Ian Molton
-M: ian@mnementh.co.uk
+M: Ian Molton <ian@mnementh.co.uk>
S: Maintained
F: drivers/mmc/host/tmio_mmc.*
TMPFS (SHMEM FILESYSTEM)
-P: Hugh Dickins
-M: hugh.dickins@tiscali.co.uk
+M: Hugh Dickins <hugh.dickins@tiscali.co.uk>
L: linux-mm@kvack.org
S: Maintained
F: include/linux/shmem_fs.h
F: mm/shmem.c
TPM DEVICE DRIVER
-P: Debora Velarde
-M: debora@linux.vnet.ibm.com
-P: Rajiv Andrade
-M: srajiv@linux.vnet.ibm.com
+M: Debora Velarde <debora@linux.vnet.ibm.com>
+M: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
W: http://tpmdd.sourceforge.net
-P: Marcel Selhorst
-M: m.selhorst@sirrix.com
+M: Marcel Selhorst <m.selhorst@sirrix.com>
W: http://www.sirrix.com
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/char/tpm/
TRIVIAL PATCHES
-P: Jiri Kosina
-M: trivial@kernel.org
+M: Jiri Kosina <trivial@kernel.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
S: Maintained
TTY LAYER
-P: Alan Cox
-M: alan@lxorguk.ukuu.org.uk
+M: Greg Kroah-Hartman <gregkh@suse.de>
S: Maintained
-T: stgit http://zeniv.linux.org.uk/~alan/ttydev/
+T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
F: drivers/char/tty_*
F: drivers/serial/serial_core.c
F: include/linux/serial_core.h
@@ -5838,17 +5064,14 @@ F: include/linux/serial.h
F: include/linux/tty.h
TULIP NETWORK DRIVERS
-P: Grant Grundler
-M: grundler@parisc-linux.org
-P: Kyle McMartin
-M: kyle@mcmartin.ca
+M: Grant Grundler <grundler@parisc-linux.org>
+M: Kyle McMartin <kyle@mcmartin.ca>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/tulip/
TUN/TAP driver
-P: Maxim Krasnyansky
-M: maxk@qualcomm.com
+M: Maxim Krasnyansky <maxk@qualcomm.com>
L: vtun@office.satix.net
W: http://vtun.sourceforge.net/tun
S: Maintained
@@ -5856,24 +5079,20 @@ F: Documentation/networking/tuntap.txt
F: arch/um/os-Linux/drivers/
TURBOCHANNEL SUBSYSTEM
-P: Maciej W. Rozycki
-M: macro@linux-mips.org
+M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/tc/
F: include/linux/tc.h
U14-34F SCSI DRIVER
-P: Dario Ballabio
-M: ballabio_dario@emc.com
+M: Dario Ballabio <ballabio_dario@emc.com>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/u14-34f.c
UBI FILE SYSTEM (UBIFS)
-P: Artem Bityutskiy
-M: dedekind@infradead.org
-P: Adrian Hunter
-M: adrian.hunter@nokia.com
+M: Artem Bityutskiy <dedekind@infradead.org>
+M: Adrian Hunter <adrian.hunter@nokia.com>
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git
W: http://www.linux-mtd.infradead.org/doc/ubifs.html
@@ -5882,37 +5101,32 @@ F: Documentation/filesystems/ubifs.txt
F: fs/ubifs/
UCLINUX (AND M68KNOMMU)
-P: Greg Ungerer
-M: gerg@uclinux.org
+M: Greg Ungerer <gerg@uclinux.org>
W: http://www.uclinux.org/
L: uclinux-dev@uclinux.org (subscribers-only)
S: Maintained
F: arch/m68knommu/
UCLINUX FOR RENESAS H8/300 (H8300)
-P: Yoshinori Sato
-M: ysato@users.sourceforge.jp
+M: Yoshinori Sato <ysato@users.sourceforge.jp>
W: http://uclinux-h8.sourceforge.jp/
S: Supported
UDF FILESYSTEM
-P: Jan Kara
-M: jack@suse.cz
+M: Jan Kara <jack@suse.cz>
W: http://linux-udf.sourceforge.net
S: Maintained
F: Documentation/filesystems/udf.txt
F: fs/udf/
UFS FILESYSTEM
-P: Evgeniy Dushistov
-M: dushistov@mail.ru
+M: Evgeniy Dushistov <dushistov@mail.ru>
S: Maintained
F: Documentation/filesystems/ufs.txt
F: fs/ufs/
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
-P: David Vrabel
-M: david.vrabel@csr.com
+M: David Vrabel <david.vrabel@csr.com>
L: linux-usb@vger.kernel.org
S: Supported
F: drivers/uwb/*
@@ -5920,8 +5134,7 @@ F: include/linux/uwb.h
F: include/linux/uwb/
UNIFORM CDROM DRIVER
-P: Jens Axboe
-M: axboe@kernel.dk
+M: Jens Axboe <axboe@kernel.dk>
W: http://www.kernel.dk
S: Maintained
F: Documentation/cdrom/
@@ -5929,8 +5142,7 @@ F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
UNSORTED BLOCK IMAGES (UBI)
-P: Artem Bityutskiy
-M: dedekind@infradead.org
+M: Artem Bityutskiy <dedekind@infradead.org>
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubi-2.6.git
@@ -5940,23 +5152,20 @@ F: include/linux/mtd/ubi.h
F: include/mtd/ubi-user.h
USB ACM DRIVER
-P: Oliver Neukum
-M: oliver@neukum.name
+M: Oliver Neukum <oliver@neukum.name>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/acm.txt
F: drivers/usb/class/cdc-acm.*
USB BLOCK DRIVER (UB ub)
-P: Pete Zaitcev
-M: zaitcev@redhat.com
+M: Pete Zaitcev <zaitcev@redhat.com>
L: linux-usb@vger.kernel.org
S: Supported
F: drivers/block/ub.c
USB CDC ETHERNET DRIVER
-P: Greg Kroah-Hartman
-M: greg@kroah.com
+M: Greg Kroah-Hartman <greg@kroah.com>
L: linux-usb@vger.kernel.org
S: Maintained
W: http://www.kroah.com/linux-usb/
@@ -5964,39 +5173,34 @@ F: drivers/net/usb/cdc_*.c
F: include/linux/usb/cdc.h
USB CYPRESS C67X00 DRIVER
-P: Peter Korsgaard
-M: jacmet@sunsite.dk
+M: Peter Korsgaard <jacmet@sunsite.dk>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/c67x00/
USB DAVICOM DM9601 DRIVER
-P: Peter Korsgaard
-M: jacmet@sunsite.dk
+M: Peter Korsgaard <jacmet@sunsite.dk>
L: netdev@vger.kernel.org
W: http://www.linux-usb.org/usbnet
S: Maintained
F: drivers/net/usb/dm9601.c
USB DIAMOND RIO500 DRIVER
-P: Cesar Miquel
-M: miquel@df.uba.ar
+M: Cesar Miquel <miquel@df.uba.ar>
L: rio500-users@lists.sourceforge.net
W: http://rio500.sourceforge.net
S: Maintained
F: drivers/usb/misc/rio500*
USB EHCI DRIVER
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
S: Odd Fixes
F: Documentation/usb/ehci.txt
F: drivers/usb/host/ehci*
USB ET61X[12]51 DRIVER
-P: Luca Risolia
-M: luca.risolia@studio.unibo.it
+M: Luca Risolia <luca.risolia@studio.unibo.it>
L: linux-usb@vger.kernel.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6005,8 +5209,7 @@ S: Maintained
F: drivers/media/video/et61x251/
USB GADGET/PERIPHERAL SUBSYSTEM
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
W: http://www.linux-usb.org/gadget
S: Maintained
@@ -6014,8 +5217,7 @@ F: drivers/usb/gadget/
F: include/linux/usb/gadget*
USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
-P: Jiri Kosina
-M: jkosina@suse.cz
+M: Jiri Kosina <jkosina@suse.cz>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
@@ -6023,23 +5225,20 @@ F: Documentation/usb/hiddev.txt
F: drivers/hid/usbhid/
USB ISP116X DRIVER
-P: Olav Kongas
-M: ok@artecdesign.ee
+M: Olav Kongas <ok@artecdesign.ee>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/host/isp116x*
F: include/linux/usb/isp116x.h
USB KAWASAKI LSI DRIVER
-P: Oliver Neukum
-M: oliver@neukum.name
+M: Oliver Neukum <oliver@neukum.name>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/kl5kusb105.*
USB MASS STORAGE DRIVER
-P: Matthew Dharm
-M: mdharm-usb@one-eyed-alien.net
+M: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
L: linux-usb@vger.kernel.org
L: usb-storage@lists.one-eyed-alien.net
S: Maintained
@@ -6047,31 +5246,27 @@ W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
F: drivers/usb/storage/
USB OHCI DRIVER
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
S: Odd Fixes
F: Documentation/usb/ohci.txt
F: drivers/usb/host/ohci*
USB OPTION-CARD DRIVER
-P: Matthias Urlichs
-M: smurf@smurf.noris.de
+M: Matthias Urlichs <smurf@smurf.noris.de>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/option.c
USB OV511 DRIVER
-P: Mark McClelland
-M: mmcclell@bigfoot.com
+M: Mark McClelland <mmcclell@bigfoot.com>
L: linux-usb@vger.kernel.org
W: http://alpha.dyndns.org/ov511/
S: Maintained
F: drivers/media/video/ov511.*
USB PEGASUS DRIVER
-P: Petko Manolov
-M: petkan@users.sourceforge.net
+M: Petko Manolov <petkan@users.sourceforge.net>
L: linux-usb@vger.kernel.org
L: netdev@vger.kernel.org
W: http://pegasus2.sourceforge.net/
@@ -6079,15 +5274,13 @@ S: Maintained
F: drivers/net/usb/pegasus.*
USB PRINTER DRIVER (usblp)
-P: Pete Zaitcev
-M: zaitcev@redhat.com
+M: Pete Zaitcev <zaitcev@redhat.com>
L: linux-usb@vger.kernel.org
S: Supported
F: drivers/usb/class/usblp.c
USB RTL8150 DRIVER
-P: Petko Manolov
-M: petkan@users.sourceforge.net
+M: Petko Manolov <petkan@users.sourceforge.net>
L: linux-usb@vger.kernel.org
L: netdev@vger.kernel.org
W: http://pegasus2.sourceforge.net/
@@ -6095,8 +5288,7 @@ S: Maintained
F: drivers/net/usb/rtl8150.c
USB SE401 DRIVER
-P: Jeroen Vreeken
-M: pe1rxq@amsat.org
+M: Jeroen Vreeken <pe1rxq@amsat.org>
L: linux-usb@vger.kernel.org
W: http://www.chello.nl/~j.vreeken/se401/
S: Maintained
@@ -6104,15 +5296,13 @@ F: Documentation/video4linux/se401.txt
F: drivers/media/video/se401.*
USB SERIAL BELKIN F5U103 DRIVER
-P: William Greathouse
-M: wgreathouse@smva.com
+M: William Greathouse <wgreathouse@smva.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/belkin_sa.*
USB SERIAL CYPRESS M8 DRIVER
-P: Lonnie Mendez
-M: dignome@gmail.com
+M: Lonnie Mendez <dignome@gmail.com>
L: linux-usb@vger.kernel.org
S: Maintained
W: http://geocities.com/i0xox0i
@@ -6120,23 +5310,20 @@ W: http://firstlight.net/cvs
F: drivers/usb/serial/cypress_m8.*
USB SERIAL CYBERJACK DRIVER
-P: Matthias Bruestle and Harald Welte
-M: support@reiner-sct.com
+M: Matthias Bruestle and Harald Welte <support@reiner-sct.com>
W: http://www.reiner-sct.de/support/treiber_cyberjack.php
S: Maintained
F: drivers/usb/serial/cyberjack.c
USB SERIAL DIGI ACCELEPORT DRIVER
-P: Peter Berger and Al Borchers
-M: pberger@brimson.com
-M: alborchers@steinerpoint.com
+M: Peter Berger <pberger@brimson.com>
+M: Al Borchers <alborchers@steinerpoint.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/digi_acceleport.c
USB SERIAL DRIVER
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+M: Greg Kroah-Hartman <gregkh@suse.de>
L: linux-usb@vger.kernel.org
S: Supported
F: Documentation/usb/usb-serial.txt
@@ -6145,38 +5332,33 @@ F: drivers/usb/serial/usb-serial.c
F: include/linux/usb/serial.h
USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
-P: Gary Brubaker
-M: xavyer@ix.netcom.com
+M: Gary Brubaker <xavyer@ix.netcom.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/empeg.c
USB SERIAL KEYSPAN DRIVER
-P: Greg Kroah-Hartman
-M: greg@kroah.com
+M: Greg Kroah-Hartman <greg@kroah.com>
L: linux-usb@vger.kernel.org
W: http://www.kroah.com/linux/
S: Maintained
F: drivers/usb/serial/*keyspan*
USB SERIAL WHITEHEAT DRIVER
-P: Support Department
-M: support@connecttech.com
+M: Support Department <support@connecttech.com>
L: linux-usb@vger.kernel.org
W: http://www.connecttech.com
S: Supported
F: drivers/usb/serial/whiteheat*
USB SMSC95XX ETHERNET DRIVER
-P: Steve Glendinning
-M: steve.glendinning@smsc.com
+M: Steve Glendinning <steve.glendinning@smsc.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/usb/smsc95xx.*
USB SN9C1xx DRIVER
-P: Luca Risolia
-M: luca.risolia@studio.unibo.it
+M: Luca Risolia <luca.risolia@studio.unibo.it>
L: linux-usb@vger.kernel.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6186,8 +5368,7 @@ F: Documentation/video4linux/sn9c102.txt
F: drivers/media/video/sn9c102/
USB SUBSYSTEM
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+M: Greg Kroah-Hartman <gregkh@suse.de>
L: linux-usb@vger.kernel.org
W: http://www.linux-usb.org
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
@@ -6199,15 +5380,13 @@ F: include/linux/usb.h
F: include/linux/usb/
USB UHCI DRIVER
-P: Alan Stern
-M: stern@rowland.harvard.edu
+M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/host/uhci*
USB "USBNET" DRIVER FRAMEWORK
-P: David Brownell
-M: dbrownell@users.sourceforge.net
+M: David Brownell <dbrownell@users.sourceforge.net>
L: netdev@vger.kernel.org
W: http://www.linux-usb.org/usbnet
S: Maintained
@@ -6215,8 +5394,7 @@ F: drivers/net/usb/usbnet.c
F: include/linux/usb/usbnet.h
USB VIDEO CLASS
-P: Laurent Pinchart
-M: laurent.pinchart@skynet.be
+M: Laurent Pinchart <laurent.pinchart@skynet.be>
L: linux-uvc-devel@lists.berlios.de (subscribers-only)
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6225,8 +5403,7 @@ S: Maintained
F: drivers/media/video/uvc/
USB W996[87]CF DRIVER
-P: Luca Risolia
-M: luca.risolia@studio.unibo.it
+M: Luca Risolia <luca.risolia@studio.unibo.it>
L: linux-usb@vger.kernel.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6236,21 +5413,18 @@ F: Documentation/video4linux/w9968cf.txt
F: drivers/media/video/w996*
USB WIRELESS RNDIS DRIVER (rndis_wlan)
-P: Jussi Kivilinna
-M: jussi.kivilinna@mbnet.fi
+M: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/rndis_wlan.c
USB XHCI DRIVER
-P: Sarah Sharp
-M: sarah.a.sharp@intel.com
+M: Sarah Sharp <sarah.a.sharp@intel.com>
L: linux-usb@vger.kernel.org
S: Supported
USB ZC0301 DRIVER
-P: Luca Risolia
-M: luca.risolia@studio.unibo.it
+M: Luca Risolia <luca.risolia@studio.unibo.it>
L: linux-usb@vger.kernel.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6260,16 +5434,14 @@ F: Documentation/video4linux/zc0301.txt
F: drivers/media/video/zc0301/
USB ZD1201 DRIVER
-P: Jeroen Vreeken
-M: pe1rxq@amsat.org
+M: Jeroen Vreeken <pe1rxq@amsat.org>
L: linux-usb@vger.kernel.org
W: http://linux-lc100020.sourceforge.net
S: Maintained
F: drivers/net/wireless/zd1201.*
USB ZR364XX DRIVER
-P: Antoine Jacquet
-M: royale@zerezo.com
+M: Antoine Jacquet <royale@zerezo.com>
L: linux-usb@vger.kernel.org
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -6279,8 +5451,7 @@ F: Documentation/video4linux/zr364xx.txt
F: drivers/media/video/zr364xx.c
USER-MODE LINUX (UML)
-P: Jeff Dike
-M: jdike@addtoit.com
+M: Jeff Dike <jdike@addtoit.com>
L: user-mode-linux-devel@lists.sourceforge.net
L: user-mode-linux-user@lists.sourceforge.net
W: http://user-mode-linux.sourceforge.net
@@ -6291,26 +5462,22 @@ F: fs/hostfs/
F: fs/hppfs/
USERSPACE I/O (UIO)
-P: Hans J. Koch
-M: hjk@linutronix.de
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+M: "Hans J. Koch" <hjk@linutronix.de>
+M: Greg Kroah-Hartman <gregkh@suse.de>
S: Maintained
F: Documentation/DocBook/uio-howto.tmpl
F: drivers/uio/
F: include/linux/uio*.h
UTIL-LINUX-NG PACKAGE
-P: Karel Zak
-M: kzak@redhat.com
+M: Karel Zak <kzak@redhat.com>
L: util-linux-ng@vger.kernel.org
W: http://kernel.org/~kzak/util-linux-ng/
T: git git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
S: Maintained
UVESAFB DRIVER
-P: Michal Januszewski
-M: spock@gentoo.org
+M: Michal Januszewski <spock@gentoo.org>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
W: http://dev.gentoo.org/~spock/projects/uvesafb/
S: Maintained
@@ -6318,53 +5485,44 @@ F: Documentation/fb/uvesafb.txt
F: drivers/video/uvesafb.*
VFAT/FAT/MSDOS FILESYSTEM
-P: OGAWA Hirofumi
-M: hirofumi@mail.parknet.co.jp
+M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
S: Maintained
F: Documentation/filesystems/vfat.txt
F: fs/fat/
VIA RHINE NETWORK DRIVER
-P: Roger Luethi
-M: rl@hellgate.ch
+M: Roger Luethi <rl@hellgate.ch>
S: Maintained
F: drivers/net/via-rhine.c
VIAPRO SMBUS DRIVER
-P: Jean Delvare
-M: khali@linux-fr.org
+M: Jean Delvare <khali@linux-fr.org>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/busses/i2c-viapro
F: drivers/i2c/busses/i2c-viapro.c
VIA SD/MMC CARD CONTROLLER DRIVER
-P: Joseph Chan
-M: JosephChan@via.com.tw
-P: Harald Welte
-M: HaraldWelte@viatech.com
+M: Joseph Chan <JosephChan@via.com.tw>
+M: Harald Welte <HaraldWelte@viatech.com>
S: Maintained
F: drivers/mmc/host/via-sdmmc.c
VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
-P: Joseph Chan
-M: JosephChan@via.com.tw
-P: Scott Fang
-M: ScottFang@viatech.com.cn
+M: Joseph Chan <JosephChan@via.com.tw>
+M: Scott Fang <ScottFang@viatech.com.cn>
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/video/via/
VIA VELOCITY NETWORK DRIVER
-P: Francois Romieu
-M: romieu@fr.zoreil.com
+M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/via-velocity.*
VLAN (802.1Q)
-P: Patrick McHardy
-M: kaber@trash.net
+M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/macvlan.c
@@ -6372,18 +5530,15 @@ F: include/linux/if_*vlan.h
F: net/8021q/
VLYNQ BUS
-P: Florian Fainelli
-M: florian@openwrt.org
+M: Florian Fainelli <florian@openwrt.org>
L: openwrt-devel@lists.openwrt.org
S: Maintained
F: drivers/vlynq/vlynq.c
F: include/linux/vlynq.h
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-P: Liam Girdwood
-M: lrg@slimlogic.co.uk
-P: Mark Brown
-M: broonie@opensource.wolfsonmicro.com
+M: Liam Girdwood <lrg@slimlogic.co.uk>
+M: Mark Brown <broonie@opensource.wolfsonmicro.com>
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?p=48
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
@@ -6392,52 +5547,45 @@ F: drivers/regulator/
F: include/linux/regulator/
VT1211 HARDWARE MONITOR DRIVER
-P: Juerg Haefliger
-M: juergh@gmail.com
+M: Juerg Haefliger <juergh@gmail.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/vt1211
F: drivers/hwmon/vt1211.c
VT8231 HARDWARE MONITOR DRIVER
-P: Roger Lucas
-M: vt8231@hiddenengine.co.uk
+M: Roger Lucas <vt8231@hiddenengine.co.uk>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/vt8231.c
W1 DALLAS'S 1-WIRE BUS
-P: Evgeniy Polyakov
-M: johnpol@2ka.mipt.ru
+M: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
S: Maintained
F: Documentation/w1/
F: drivers/w1/
W83791D HARDWARE MONITORING DRIVER
-P: Marc Hulsman
-M: m.hulsman@tudelft.nl
+M: Marc Hulsman <m.hulsman@tudelft.nl>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/w83791d
F: drivers/hwmon/w83791d.c
W83793 HARDWARE MONITORING DRIVER
-P: Rudolf Marek
-M: r.marek@assembler.cz
+M: Rudolf Marek <r.marek@assembler.cz>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/w83793
F: drivers/hwmon/w83793.c
W83L51xD SD/MMC CARD INTERFACE DRIVER
-P: Pierre Ossman
-M: pierre@ossman.eu
+M: Pierre Ossman <pierre@ossman.eu>
S: Maintained
F: drivers/mmc/host/wbsd.*
WATCHDOG DEVICE DRIVERS
-P: Wim Van Sebroeck
-M: wim@iguana.be
+M: Wim Van Sebroeck <wim@iguana.be>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog.git
S: Maintained
F: Documentation/watchdog/
@@ -6445,8 +5593,7 @@ F: drivers/watchdog/
F: include/linux/watchdog.h
WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS
-P: Jean Tourrilhes
-M: jt@hpl.hp.com
+M: Jean Tourrilhes <jt@hpl.hp.com>
L: linux-wireless@vger.kernel.org
W: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
S: Maintained
@@ -6454,46 +5601,48 @@ F: Documentation/networking/wavelan.txt
F: drivers/net/wireless/wavelan*
WD7000 SCSI DRIVER
-P: Miroslav Zagorac
-M: zaga@fly.cc.fer.hr
+M: Miroslav Zagorac <zaga@fly.cc.fer.hr>
L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/wd7000.c
WIMAX STACK
-P: Inaky Perez-Gonzalez
-M: inaky.perez-gonzalez@intel.com
+M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
M: linux-wimax@intel.com
L: wimax@linuxwimax.org
S: Supported
W: http://linuxwimax.org
WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM
-P: David Vrabel
-M: david.vrabel@csr.com
+M: David Vrabel <david.vrabel@csr.com>
S: Maintained
F: include/linux/wlp.h
F: drivers/uwb/wlp/
WISTRON LAPTOP BUTTON DRIVER
-P: Miloslav Trmac
-M: mitr@volny.cz
+M: Miloslav Trmac <mitr@volny.cz>
S: Maintained
F: drivers/input/misc/wistron_btns.c
+WL1251 WIRELESS DRIVER
+P: Kalle Valo
+M: kalle.valo@nokia.com
+L: linux-wireless@vger.kernel.org
+W: http://wireless.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+S: Maintained
+F: drivers/net/wireless/wl12xx/wl1251*
+
WL3501 WIRELESS PCMCIA CARD DRIVER
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: linux-wireless@vger.kernel.org
W: http://oops.ghostprotocols.net:81/blog
S: Maintained
F: drivers/net/wireless/wl3501*
WM97XX TOUCHSCREEN DRIVERS
-P: Mark Brown
-M: broonie@opensource.wolfsonmicro.com
-P: Liam Girdwood
-M: lrg@slimlogic.co.uk
+M: Mark Brown <broonie@opensource.wolfsonmicro.com>
+M: Liam Girdwood <lrg@slimlogic.co.uk>
L: linux-input@vger.kernel.org
T: git git://opensource.wolfsonmicro.com/linux-2.6-touch
W: http://opensource.wolfsonmicro.com/node/7
@@ -6501,9 +5650,26 @@ S: Supported
F: drivers/input/touchscreen/*wm97*
F: include/linux/wm97xx.h
+WOLFSON MICROELECTRONICS PMIC DRIVERS
+P: Mark Brown
+M: broonie@opensource.wolfsonmicro.com
+L: linux-kernel@vger.kernel.org
+T: git git://opensource.wolfsonmicro.com/linux-2.6-audioplus
+W: http://opensource.wolfsonmicro.com/node/8
+S: Supported
+F: drivers/leds/leds-wm83*.c
+F: drivers/mfd/wm8*.c
+F: drivers/power/wm83*.c
+F: drivers/rtc/rtc-wm83*.c
+F: drivers/regulator/wm8*.c
+F: drivers/watchdog/wm83*_wdt.c
+F: include/linux/mfd/wm8350/
+F: include/linux/mfd/wm8400/
+F: sound/soc/codecs/wm8350.c
+F: sound/soc/codecs/wm8400.c
+
X.25 NETWORK LAYER
-P: Henner Eisen
-M: eis@baty.hanse.de
+M: Henner Eisen <eis@baty.hanse.de>
L: linux-x25@vger.kernel.org
S: Maintained
F: Documentation/networking/x25*
@@ -6511,12 +5677,9 @@ F: include/net/x25*
F: net/x25/
X86 ARCHITECTURE (32-BIT AND 64-BIT)
-P: Thomas Gleixner
-M: tglx@linutronix.de
-P: Ingo Molnar
-M: mingo@redhat.com
-P: H. Peter Anvin
-M: hpa@zytor.com
+M: Thomas Gleixner <tglx@linutronix.de>
+M: Ingo Molnar <mingo@redhat.com>
+M: "H. Peter Anvin" <hpa@zytor.com>
M: x86@kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
S: Maintained
@@ -6524,10 +5687,8 @@ F: Documentation/x86/
F: arch/x86/
XEN HYPERVISOR INTERFACE
-P: Jeremy Fitzhardinge
-M: jeremy@xensource.com
-P: Chris Wright
-M: chrisw@sous-sol.org
+M: Jeremy Fitzhardinge <jeremy@xensource.com>
+M: Chris Wright <chrisw@sous-sol.org>
L: virtualization@lists.osdl.org
L: xen-devel@lists.xensource.com
S: Supported
@@ -6539,8 +5700,7 @@ F: include/xen/
XFS FILESYSTEM
P: Silicon Graphics Inc
-P: Felix Blyakher
-M: felixb@sgi.com
+M: Felix Blyakher <felixb@sgi.com>
M: xfs-masters@oss.sgi.com
L: xfs@oss.sgi.com
W: http://oss.sgi.com/projects/xfs
@@ -6550,38 +5710,33 @@ F: Documentation/filesystems/xfs.txt
F: fs/xfs/
XILINX SYSTEMACE DRIVER
-P: Grant Likely
-M: grant.likely@secretlab.ca
+M: Grant Likely <grant.likely@secretlab.ca>
W: http://www.secretlab.ca/
S: Maintained
F: drivers/block/xsysace.c
XILINX UARTLITE SERIAL DRIVER
-P: Peter Korsgaard
-M: jacmet@sunsite.dk
+M: Peter Korsgaard <jacmet@sunsite.dk>
L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/serial/uartlite.c
YAM DRIVER FOR AX.25
-P: Jean-Paul Roubelat
-M: jpr@f6fbb.org
+M: Jean-Paul Roubelat <jpr@f6fbb.org>
L: linux-hams@vger.kernel.org
S: Maintained
F: drivers/net/hamradio/yam*
F: include/linux/yam.h
YEALINK PHONE DRIVER
-P: Henk Vergonet
-M: Henk.Vergonet@gmail.com
+M: Henk Vergonet <Henk.Vergonet@gmail.com>
L: usbb2k-api-dev@nongnu.org
S: Maintained
F: Documentation/input/yealink.txt
F: drivers/input/misc/yealink.*
Z8530 DRIVER FOR AX.25
-P: Joerg Reuter
-M: jreuter@yaina.de
+M: Joerg Reuter <jreuter@yaina.de>
W: http://yaina.de/jreuter/
W: http://www.qsl.net/dl1bke/
L: linux-hams@vger.kernel.org
@@ -6591,10 +5746,8 @@ F: drivers/net/hamradio/*scc.c
F: drivers/net/hamradio/z8530.h
ZD1211RW WIRELESS DRIVER
-P: Daniel Drake
-M: dsd@gentoo.org
-P: Ulrich Kunitz
-M: kune@deine-taler.de
+M: Daniel Drake <dsd@gentoo.org>
+M: Ulrich Kunitz <kune@deine-taler.de>
W: http://zd1211.ath.cx/wiki/DriverRewrite
L: linux-wireless@vger.kernel.org
L: zd1211-devs@lists.sourceforge.net (subscribers-only)
@@ -6610,14 +5763,12 @@ S: Odd Fixes
F: drivers/media/video/zoran/
ZS DECSTATION Z85C30 SERIAL DRIVER
-P: Maciej W. Rozycki
-M: macro@linux-mips.org
+M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/serial/zs.*
THE REST
-P: Linus Torvalds
-M: torvalds@linux-foundation.org
+M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
S: Buried alive in reporters
diff --git a/Makefile b/Makefile
index 063d738405ed..476335a73945 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 31
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc5
NAME = Man-Eating Seals of Antiquity
# *DOCUMENTATION*
@@ -325,7 +325,7 @@ CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
MODFLAGS = -DMODULE
CFLAGS_MODULE = $(MODFLAGS)
AFLAGS_MODULE = $(MODFLAGS)
-LDFLAGS_MODULE =
+LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds
CFLAGS_KERNEL =
AFLAGS_KERNEL =
CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
diff --git a/arch/Kconfig b/arch/Kconfig
index 99193b160232..beea3ccebb5e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -30,6 +30,18 @@ config OPROFILE_IBS
If unsure, say N.
+config OPROFILE_EVENT_MULTIPLEX
+ bool "OProfile multiplexing support (EXPERIMENTAL)"
+ default n
+ depends on OPROFILE && X86
+ help
+ The number of hardware counters is limited. The multiplexing
+ feature enables OProfile to gather more events than counters
+ are provided by the hardware. This is realized by switching
+ between events at an user specified time interval.
+
+ If unsure, say N.
+
config HAVE_OPROFILE
bool
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index d22ace99d13d..dd8dcabf160f 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -52,7 +52,6 @@ struct pci_controller {
bus numbers. */
#define pcibios_assign_all_busses() 1
-#define pcibios_scan_all_fns(a, b) 0
#define PCIBIOS_MIN_IO alpha_mv.min_io_address
#define PCIBIOS_MIN_MEM alpha_mv.min_mem_address
diff --git a/arch/alpha/include/asm/percpu.h b/arch/alpha/include/asm/percpu.h
index b663f1f10b6a..2c12378e3aa9 100644
--- a/arch/alpha/include/asm/percpu.h
+++ b/arch/alpha/include/asm/percpu.h
@@ -1,102 +1,18 @@
#ifndef __ALPHA_PERCPU_H
#define __ALPHA_PERCPU_H
-#include <linux/compiler.h>
-#include <linux/threads.h>
-#include <linux/percpu-defs.h>
-
-/*
- * Determine the real variable name from the name visible in the
- * kernel sources.
- */
-#define per_cpu_var(var) per_cpu__##var
-
-#ifdef CONFIG_SMP
-
-/*
- * per_cpu_offset() is the offset that has to be added to a
- * percpu variable to get to the instance for a certain processor.
- */
-extern unsigned long __per_cpu_offset[NR_CPUS];
-
-#define per_cpu_offset(x) (__per_cpu_offset[x])
-
-#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
-#ifdef CONFIG_DEBUG_PREEMPT
-#define my_cpu_offset per_cpu_offset(smp_processor_id())
-#else
-#define my_cpu_offset __my_cpu_offset
-#endif
-
-#ifndef MODULE
-#define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset))
-#define PER_CPU_DEF_ATTRIBUTES
-#else
/*
- * To calculate addresses of locally defined variables, GCC uses 32-bit
- * displacement from the GP. Which doesn't work for per cpu variables in
- * modules, as an offset to the kernel per cpu area is way above 4G.
+ * To calculate addresses of locally defined variables, GCC uses
+ * 32-bit displacement from the GP. Which doesn't work for per cpu
+ * variables in modules, as an offset to the kernel per cpu area is
+ * way above 4G.
*
- * This forces allocation of a GOT entry for per cpu variable using
- * ldq instruction with a 'literal' relocation.
- */
-#define SHIFT_PERCPU_PTR(var, offset) ({ \
- extern int simple_identifier_##var(void); \
- unsigned long __ptr, tmp_gp; \
- asm ( "br %1, 1f \n\
- 1: ldgp %1, 0(%1) \n\
- ldq %0, per_cpu__" #var"(%1)\t!literal" \
- : "=&r"(__ptr), "=&r"(tmp_gp)); \
- (typeof(&per_cpu_var(var)))(__ptr + (offset)); })
-
-#define PER_CPU_DEF_ATTRIBUTES __used
-
-#endif /* MODULE */
-
-/*
- * A percpu variable may point to a discarded regions. The following are
- * established ways to produce a usable pointer from the percpu variable
- * offset.
+ * Always use weak definitions for percpu variables in modules.
*/
-#define per_cpu(var, cpu) \
- (*SHIFT_PERCPU_PTR(var, per_cpu_offset(cpu)))
-#define __get_cpu_var(var) \
- (*SHIFT_PERCPU_PTR(var, my_cpu_offset))
-#define __raw_get_cpu_var(var) \
- (*SHIFT_PERCPU_PTR(var, __my_cpu_offset))
-
-#else /* ! SMP */
-
-#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu_var(var)))
-#define __get_cpu_var(var) per_cpu_var(var)
-#define __raw_get_cpu_var(var) per_cpu_var(var)
-
-#define PER_CPU_DEF_ATTRIBUTES
-
-#endif /* SMP */
-
-#ifdef CONFIG_SMP
-#define PER_CPU_BASE_SECTION ".data.percpu"
-#else
-#define PER_CPU_BASE_SECTION ".data"
-#endif
-
-#ifdef CONFIG_SMP
-
-#ifdef MODULE
-#define PER_CPU_SHARED_ALIGNED_SECTION ""
-#else
-#define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned"
-#endif
-#define PER_CPU_FIRST_SECTION ".first"
-
-#else
-
-#define PER_CPU_SHARED_ALIGNED_SECTION ""
-#define PER_CPU_FIRST_SECTION ""
-
+#if defined(MODULE) && defined(CONFIG_SMP)
+#define ARCH_NEEDS_WEAK_PER_CPU
#endif
-#define PER_CPU_ATTRIBUTES
+#include <asm-generic/percpu.h>
#endif /* __ALPHA_PERCPU_H */
diff --git a/arch/alpha/include/asm/smp.h b/arch/alpha/include/asm/smp.h
index 547e90951cec..3f390e8cc0b3 100644
--- a/arch/alpha/include/asm/smp.h
+++ b/arch/alpha/include/asm/smp.h
@@ -47,7 +47,7 @@ extern struct cpuinfo_alpha cpu_data[NR_CPUS];
extern int smp_num_cpus;
extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#else /* CONFIG_SMP */
diff --git a/arch/alpha/include/asm/tlb.h b/arch/alpha/include/asm/tlb.h
index c13636575fba..42866759f3fa 100644
--- a/arch/alpha/include/asm/tlb.h
+++ b/arch/alpha/include/asm/tlb.h
@@ -9,7 +9,7 @@
#include <asm-generic/tlb.h>
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
-#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte, address) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, address) pmd_free((tlb)->mm, pmd)
#endif
diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h
index 9d87aaa08c0d..e89e0c2e15b1 100644
--- a/arch/alpha/include/asm/tlbflush.h
+++ b/arch/alpha/include/asm/tlbflush.h
@@ -2,6 +2,7 @@
#define _ALPHA_TLBFLUSH_H
#include <linux/mm.h>
+#include <linux/sched.h>
#include <asm/compiler.h>
#include <asm/pgalloc.h>
diff --git a/arch/alpha/include/asm/topology.h b/arch/alpha/include/asm/topology.h
index b4f284c72ff3..36b3a30ba0e5 100644
--- a/arch/alpha/include/asm/topology.h
+++ b/arch/alpha/include/asm/topology.h
@@ -22,23 +22,6 @@ static inline int cpu_to_node(int cpu)
return node;
}
-static inline cpumask_t node_to_cpumask(int node)
-{
- cpumask_t node_cpu_mask = CPU_MASK_NONE;
- int cpu;
-
- for_each_online_cpu(cpu) {
- if (cpu_to_node(cpu) == node)
- cpu_set(cpu, node_cpu_mask);
- }
-
-#ifdef DEBUG_NUMA
- printk("node %d: cpu_mask: %016lx\n", node, node_cpu_mask);
-#endif
-
- return node_cpu_mask;
-}
-
extern struct cpumask node_to_cpumask_map[];
/* FIXME: This is dumb, recalculating every time. But simple. */
static const struct cpumask *cpumask_of_node(int node)
@@ -55,7 +38,6 @@ static const struct cpumask *cpumask_of_node(int node)
return &node_to_cpumask_map[node];
}
-#define pcibus_to_cpumask(bus) (cpu_online_map)
#define cpumask_of_pcibus(bus) (cpu_online_mask)
#endif /* !CONFIG_NUMA */
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index b1fe5674c3a1..42aa078a5e4d 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -548,16 +548,16 @@ setup_profiling_timer(unsigned int multiplier)
static void
-send_ipi_message(cpumask_t to_whom, enum ipi_message_type operation)
+send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
{
int i;
mb();
- for_each_cpu_mask(i, to_whom)
+ for_each_cpu(i, to_whom)
set_bit(operation, &ipi_data[i].bits);
mb();
- for_each_cpu_mask(i, to_whom)
+ for_each_cpu(i, to_whom)
wripir(i);
}
@@ -624,7 +624,7 @@ smp_send_reschedule(int cpu)
printk(KERN_WARNING
"smp_send_reschedule: Sending IPI to self.\n");
#endif
- send_ipi_message(cpumask_of_cpu(cpu), IPI_RESCHEDULE);
+ send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
}
void
@@ -636,17 +636,17 @@ smp_send_stop(void)
if (hard_smp_processor_id() != boot_cpu_id)
printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
#endif
- send_ipi_message(to_whom, IPI_CPU_STOP);
+ send_ipi_message(&to_whom, IPI_CPU_STOP);
}
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_CALL_FUNC);
}
void arch_send_call_function_single_ipi(int cpu)
{
- send_ipi_message(cpumask_of_cpu(cpu), IPI_CALL_FUNC_SINGLE);
+ send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
}
static void
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index b9d6568e5f7f..6dc03c35caa0 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -134,13 +134,6 @@ SECTIONS
__bss_stop = .;
_end = .;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
.mdebug 0 : {
*(.mdebug)
}
@@ -150,4 +143,6 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index aef63c8e3d2d..082a12d3660d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -46,10 +46,6 @@ config GENERIC_CLOCKEVENTS_BROADCAST
depends on GENERIC_CLOCKEVENTS
default y if SMP && !LOCAL_TIMERS
-config MMU
- bool
- default y
-
config NO_IOPORT
bool
@@ -188,6 +184,13 @@ source "kernel/Kconfig.freezer"
menu "System Type"
+config MMU
+ bool "MMU-based Paged Memory Management Support"
+ default y
+ help
+ Select if you want MMU-based virtualised addressing space
+ support by paged memory management. If unsure, say 'Y'.
+
choice
prompt "ARM system type"
default ARCH_VERSATILE
@@ -217,6 +220,7 @@ config ARCH_REALVIEW
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select ARCH_WANT_OPTIONAL_GPIOLIB
help
This enables support for ARM Ltd RealView boards.
@@ -229,6 +233,7 @@ config ARCH_VERSATILE
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select ARCH_WANT_OPTIONAL_GPIOLIB
help
This enables support for ARM Ltd Versatile board.
@@ -327,6 +332,20 @@ config ARCH_H720X
help
This enables support for systems based on the Hynix HMS720x
+config ARCH_NOMADIK
+ bool "STMicroelectronics Nomadik"
+ select ARM_AMBA
+ select ARM_VIC
+ select CPU_ARM926T
+ select HAVE_CLK
+ select COMMON_CLKDEV
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Support for the Nomadik platform by ST-Ericsson
+
config ARCH_IOP13XX
bool "IOP13xx-based"
depends on MMU
@@ -493,6 +512,7 @@ config ARCH_W90X900
select CPU_ARM926T
select ARCH_REQUIRE_GPIOLIB
select GENERIC_GPIO
+ select HAVE_CLK
select COMMON_CLKDEV
help
Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
@@ -716,6 +736,8 @@ source "arch/arm/mach-at91/Kconfig"
source "arch/arm/plat-mxc/Kconfig"
+source "arch/arm/mach-nomadik/Kconfig"
+
source "arch/arm/mach-netx/Kconfig"
source "arch/arm/mach-ns9xxx/Kconfig"
@@ -983,6 +1005,21 @@ config HZ
default AT91_TIMER_HZ if ARCH_AT91
default 100
+config THUMB2_KERNEL
+ bool "Compile the kernel in Thumb-2 mode"
+ depends on CPU_V7 && EXPERIMENTAL
+ select AEABI
+ select ARM_ASM_UNIFIED
+ help
+ By enabling this option, the kernel will be compiled in
+ Thumb-2 mode. A compiler/assembler that understand the unified
+ ARM-Thumb syntax is needed.
+
+ If unsure, say N.
+
+config ARM_ASM_UNIFIED
+ bool
+
config AEABI
bool "Use the ARM EABI to compile the kernel"
help
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index a89e4734b8f0..1a6f70e52921 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -8,6 +8,7 @@ source "lib/Kconfig.debug"
# n, but then RMK will have to kill you ;).
config FRAME_POINTER
bool
+ depends on !THUMB2_KERNEL
default y if !ARM_UNWIND
help
If you say N here, the resulting kernel will be slightly smaller and
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c877d6df23d1..712f00614bd6 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -25,7 +25,7 @@ KBUILD_CFLAGS +=$(call cc-option,-marm,)
# Select a platform tht is kept up-to-date
KBUILD_DEFCONFIG := versatile_defconfig
-# defines filename extension depending memory manement type.
+# defines filename extension depending memory management type.
ifeq ($(CONFIG_MMU),)
MMUEXT := -nommu
endif
@@ -93,9 +93,16 @@ ifeq ($(CONFIG_ARM_UNWIND),y)
CFLAGS_ABI +=-funwind-tables
endif
+ifeq ($(CONFIG_THUMB2_KERNEL),y)
+AFLAGS_AUTOIT :=$(call as-option,-Wa$(comma)-mimplicit-it=thumb,-Wa$(comma)-mauto-it)
+AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W)
+CFLAGS_THUMB2 :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN)
+AFLAGS_THUMB2 :=$(CFLAGS_THUMB2) -Wa$(comma)-mthumb
+endif
+
# Need -Uarm for gcc < 3.x
-KBUILD_CFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
-KBUILD_AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float
+KBUILD_CFLAGS +=$(CFLAGS_ABI) $(CFLAGS_THUMB2) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
+KBUILD_AFLAGS +=$(CFLAGS_ABI) $(AFLAGS_THUMB2) $(arch-y) $(tune-y) -include asm/unified.h -msoft-float
CHECKFLAGS += -D__arm__
@@ -137,6 +144,7 @@ machine-$(CONFIG_ARCH_MX1) := mx1
machine-$(CONFIG_ARCH_MX2) := mx2
machine-$(CONFIG_ARCH_MX3) := mx3
machine-$(CONFIG_ARCH_NETX) := netx
+machine-$(CONFIG_ARCH_NOMADIK) := nomadik
machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx
machine-$(CONFIG_ARCH_OMAP1) := omap1
machine-$(CONFIG_ARCH_OMAP2) := omap2
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index da226abce2d0..4a590f4113e2 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -61,7 +61,7 @@ endif
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
- -C none -a $(LOADADDR) -e $(LOADADDR) \
+ -C none -a $(LOADADDR) -e $(STARTADDR) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
ifeq ($(CONFIG_ZBOOT_ROM),y)
@@ -70,6 +70,13 @@ else
$(obj)/uImage: LOADADDR=$(ZRELADDR)
endif
+ifeq ($(CONFIG_THUMB2_KERNEL),y)
+# Set bit 0 to 1 so that "mov pc, rx" switches to Thumb-2 mode
+$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/")
+else
+$(obj)/uImage: STARTADDR=$(LOADADDR)
+endif
+
$(obj)/uImage: $(obj)/zImage FORCE
$(call if_changed,uimage)
@echo ' Image $@ is ready'
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 4515728c5345..fa6fbf45cf3b 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -140,7 +140,8 @@ start:
tst r2, #3 @ not user?
bne not_angel
mov r0, #0x17 @ angel_SWIreason_EnterSVC
- swi 0x123456 @ angel_SWI_ARM
+ ARM( swi 0x123456 ) @ angel_SWI_ARM
+ THUMB( svc 0xab ) @ angel_SWI_THUMB
not_angel:
mrs r2, cpsr @ turn off interrupts to
orr r2, r2, #0xc0 @ prevent angel from running
@@ -161,7 +162,9 @@ not_angel:
.text
adr r0, LC0
- ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
+ ARM( ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} )
+ THUMB( ldmia r0, {r1, r2, r3, r4, r5, r6, ip} )
+ THUMB( ldr sp, [r0, #28] )
subs r0, r0, r1 @ calculate the delta offset
@ if delta is zero, we are
@@ -263,22 +266,25 @@ not_relocated: mov r0, #0
* r6 = processor ID
* r7 = architecture ID
* r8 = atags pointer
- * r9-r14 = corrupted
+ * r9-r12,r14 = corrupted
*/
add r1, r5, r0 @ end of decompressed kernel
adr r2, reloc_start
ldr r3, LC1
add r3, r2, r3
-1: ldmia r2!, {r9 - r14} @ copy relocation code
- stmia r1!, {r9 - r14}
- ldmia r2!, {r9 - r14}
- stmia r1!, {r9 - r14}
+1: ldmia r2!, {r9 - r12, r14} @ copy relocation code
+ stmia r1!, {r9 - r12, r14}
+ ldmia r2!, {r9 - r12, r14}
+ stmia r1!, {r9 - r12, r14}
cmp r2, r3
blo 1b
- add sp, r1, #128 @ relocate the stack
+ mov sp, r1
+ add sp, sp, #128 @ relocate the stack
bl cache_clean_flush
- add pc, r5, r0 @ call relocation code
+ ARM( add pc, r5, r0 ) @ call relocation code
+ THUMB( add r12, r5, r0 )
+ THUMB( mov pc, r12 ) @ call relocation code
/*
* We're not in danger of overwriting ourselves. Do this the simple way.
@@ -291,6 +297,7 @@ wont_overwrite: mov r0, r4
bl decompress_kernel
b call_kernel
+ .align 2
.type LC0, #object
LC0: .word LC0 @ r1
.word __bss_start @ r2
@@ -431,6 +438,7 @@ ENDPROC(__setup_mmu)
__armv4_mmu_cache_on:
mov r12, lr
+#ifdef CONFIG_MMU
bl __setup_mmu
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
@@ -444,10 +452,12 @@ __armv4_mmu_cache_on:
bl __common_mmu_cache_on
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
+#endif
mov pc, r12
__armv7_mmu_cache_on:
mov r12, lr
+#ifdef CONFIG_MMU
mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0
tst r11, #0xf @ VMSA
blne __setup_mmu
@@ -455,9 +465,11 @@ __armv7_mmu_cache_on:
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
tst r11, #0xf @ VMSA
mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
+#endif
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x003c @ write buffer
+#ifdef CONFIG_MMU
#ifdef CONFIG_CPU_ENDIAN_BE8
orr r0, r0, #1 << 25 @ big-endian page tables
#endif
@@ -465,6 +477,7 @@ __armv7_mmu_cache_on:
movne r1, #-1
mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
+#endif
mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back
mov r0, #0
@@ -498,6 +511,7 @@ __arm6_mmu_cache_on:
mov pc, r12
__common_mmu_cache_on:
+#ifndef CONFIG_THUMB2_KERNEL
#ifndef DEBUG
orr r0, r0, #0x000d @ Write buffer, mmu
#endif
@@ -509,6 +523,7 @@ __common_mmu_cache_on:
1: mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back to
sub pc, lr, r0, lsr #32 @ properly flush pipeline
+#endif
/*
* All code following this line is relocatable. It is relocated by
@@ -522,7 +537,7 @@ __common_mmu_cache_on:
* r6 = processor ID
* r7 = architecture ID
* r8 = atags pointer
- * r9-r14 = corrupted
+ * r9-r12,r14 = corrupted
*/
.align 5
reloc_start: add r9, r5, r0
@@ -531,13 +546,14 @@ reloc_start: add r9, r5, r0
mov r1, r4
1:
.rept 4
- ldmia r5!, {r0, r2, r3, r10 - r14} @ relocate kernel
- stmia r1!, {r0, r2, r3, r10 - r14}
+ ldmia r5!, {r0, r2, r3, r10 - r12, r14} @ relocate kernel
+ stmia r1!, {r0, r2, r3, r10 - r12, r14}
.endr
cmp r5, r9
blo 1b
- add sp, r1, #128 @ relocate the stack
+ mov sp, r1
+ add sp, sp, #128 @ relocate the stack
debug_reloc_end
call_kernel: bl cache_clean_flush
@@ -571,7 +587,9 @@ call_cache_fn: adr r12, proc_types
ldr r2, [r12, #4] @ get mask
eor r1, r1, r6 @ (real ^ match)
tst r1, r2 @ & mask
- addeq pc, r12, r3 @ call cache function
+ ARM( addeq pc, r12, r3 ) @ call cache function
+ THUMB( addeq r12, r3 )
+ THUMB( moveq pc, r12 ) @ call cache function
add r12, r12, #4*5
b 1b
@@ -589,13 +607,15 @@ call_cache_fn: adr r12, proc_types
* methods. Writeback caches _must_ have the flush method
* defined.
*/
+ .align 2
.type proc_types,#object
proc_types:
.word 0x41560600 @ ARM6/610
.word 0xffffffe0
- b __arm6_mmu_cache_off @ works, but slow
- b __arm6_mmu_cache_off
+ W(b) __arm6_mmu_cache_off @ works, but slow
+ W(b) __arm6_mmu_cache_off
mov pc, lr
+ THUMB( nop )
@ b __arm6_mmu_cache_on @ untested
@ b __arm6_mmu_cache_off
@ b __armv3_mmu_cache_flush
@@ -603,76 +623,84 @@ proc_types:
.word 0x00000000 @ old ARM ID
.word 0x0000f000
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
.word 0x41007000 @ ARM7/710
.word 0xfff8fe00
- b __arm7_mmu_cache_off
- b __arm7_mmu_cache_off
+ W(b) __arm7_mmu_cache_off
+ W(b) __arm7_mmu_cache_off
mov pc, lr
+ THUMB( nop )
.word 0x41807200 @ ARM720T (writethrough)
.word 0xffffff00
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
mov pc, lr
+ THUMB( nop )
.word 0x41007400 @ ARM74x
.word 0xff00ff00
- b __armv3_mpu_cache_on
- b __armv3_mpu_cache_off
- b __armv3_mpu_cache_flush
+ W(b) __armv3_mpu_cache_on
+ W(b) __armv3_mpu_cache_off
+ W(b) __armv3_mpu_cache_flush
.word 0x41009400 @ ARM94x
.word 0xff00ff00
- b __armv4_mpu_cache_on
- b __armv4_mpu_cache_off
- b __armv4_mpu_cache_flush
+ W(b) __armv4_mpu_cache_on
+ W(b) __armv4_mpu_cache_off
+ W(b) __armv4_mpu_cache_flush
.word 0x00007000 @ ARM7 IDs
.word 0x0000f000
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
@ Everything from here on will be the new ID system.
.word 0x4401a100 @ sa110 / sa1100
.word 0xffffffe0
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x6901b110 @ sa1110
.word 0xfffffff0
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x56056930
.word 0xff0ffff0 @ PXA935
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x56158000 @ PXA168
.word 0xfffff000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv5tej_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv5tej_mmu_cache_flush
.word 0x56056930
.word 0xff0ffff0 @ PXA935
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x56050000 @ Feroceon
.word 0xff0f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv5tej_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv5tej_mmu_cache_flush
#ifdef CONFIG_CPU_FEROCEON_OLD_ID
/* this conflicts with the standard ARMv5TE entry */
@@ -685,47 +713,50 @@ proc_types:
.word 0x66015261 @ FA526
.word 0xff01fff1
- b __fa526_cache_on
- b __armv4_mmu_cache_off
- b __fa526_cache_flush
+ W(b) __fa526_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __fa526_cache_flush
@ These match on the architecture ID
.word 0x00020000 @ ARMv4T
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x00050000 @ ARMv5TE
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv4_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x00060000 @ ARMv5TEJ
.word 0x000f0000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv5tej_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv4_mmu_cache_flush
.word 0x0007b000 @ ARMv6
.word 0x000ff000
- b __armv4_mmu_cache_on
- b __armv4_mmu_cache_off
- b __armv6_mmu_cache_flush
+ W(b) __armv4_mmu_cache_on
+ W(b) __armv4_mmu_cache_off
+ W(b) __armv6_mmu_cache_flush
.word 0x000f0000 @ new CPU Id
.word 0x000f0000
- b __armv7_mmu_cache_on
- b __armv7_mmu_cache_off
- b __armv7_mmu_cache_flush
+ W(b) __armv7_mmu_cache_on
+ W(b) __armv7_mmu_cache_off
+ W(b) __armv7_mmu_cache_flush
.word 0 @ unrecognised type
.word 0
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
mov pc, lr
+ THUMB( nop )
.size proc_types, . - proc_types
@@ -760,22 +791,30 @@ __armv3_mpu_cache_off:
mov pc, lr
__armv4_mmu_cache_off:
+#ifdef CONFIG_MMU
mrc p15, 0, r0, c1, c0
bic r0, r0, #0x000d
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4
mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
+#endif
mov pc, lr
__armv7_mmu_cache_off:
mrc p15, 0, r0, c1, c0
+#ifdef CONFIG_MMU
bic r0, r0, #0x000d
+#else
+ bic r0, r0, #0x000c
+#endif
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
mov r12, lr
bl __armv7_mmu_cache_flush
mov r0, #0
+#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB
+#endif
mcr p15, 0, r0, c7, c5, 6 @ invalidate BTC
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
@@ -852,7 +891,7 @@ __armv7_mmu_cache_flush:
b iflush
hierarchical:
mcr p15, 0, r10, c7, c10, 5 @ DMB
- stmfd sp!, {r0-r5, r7, r9, r11}
+ stmfd sp!, {r0-r7, r9-r11}
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
@@ -877,8 +916,12 @@ loop1:
loop2:
mov r9, r4 @ create working copy of max way size
loop3:
- orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
- orr r11, r11, r7, lsl r2 @ factor index number into r11
+ ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
+ ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11
+ THUMB( lsl r6, r9, r5 )
+ THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
+ THUMB( lsl r6, r7, r2 )
+ THUMB( orr r11, r11, r6 ) @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge loop3
@@ -889,7 +932,7 @@ skip:
cmp r3, r10
bgt loop1
finished:
- ldmfd sp!, {r0-r5, r7, r9, r11}
+ ldmfd sp!, {r0-r7, r9-r11}
mov r10, #0 @ swith back to cache level 0
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
iflush:
@@ -923,9 +966,13 @@ __armv4_mmu_cache_flush:
mov r11, #8
mov r11, r11, lsl r3 @ cache line size in bytes
no_cache_id:
- bic r1, pc, #63 @ align to longest cache line
+ mov r1, pc
+ bic r1, r1, #63 @ align to longest cache line
add r2, r1, r2
-1: ldr r3, [r1], r11 @ s/w flush D cache
+1:
+ ARM( ldr r3, [r1], r11 ) @ s/w flush D cache
+ THUMB( ldr r3, [r1] ) @ s/w flush D cache
+ THUMB( add r1, r1, r11 )
teq r1, r2
bne 1b
@@ -945,6 +992,7 @@ __armv3_mpu_cache_flush:
* memory, which again must be relocatable.
*/
#ifdef DEBUG
+ .align 2
.type phexbuf,#object
phexbuf: .space 12
.size phexbuf, . - phexbuf
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 9e6e512f0117..17153b54613b 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -29,7 +29,6 @@ unsigned int __machine_arch_type;
static void putstr(const char *ptr);
-#include <linux/compiler.h>
#include <mach/uncompress.h>
#ifdef CONFIG_DEBUG_ICEDCC
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 6ed89836e908..bc1f9ad61ff6 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -26,6 +26,15 @@
#include <asm/mach/irq.h>
#include <asm/hardware/vic.h>
+static void vic_ack_irq(unsigned int irq)
+{
+ void __iomem *base = get_irq_chip_data(irq);
+ irq &= 31;
+ writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
+ /* moreover, clear the soft-triggered, in case it was the reason */
+ writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
+}
+
static void vic_mask_irq(unsigned int irq)
{
void __iomem *base = get_irq_chip_data(irq);
@@ -253,12 +262,21 @@ static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg
static struct irq_chip vic_chip = {
.name = "VIC",
- .ack = vic_mask_irq,
+ .ack = vic_ack_irq,
.mask = vic_mask_irq,
.unmask = vic_unmask_irq,
.set_wake = vic_set_wake,
};
+/* The PL190 cell from ARM has been modified by ST, so handle both here */
+static void vik_init_st(void __iomem *base, unsigned int irq_start,
+ u32 vic_sources);
+
+enum vic_vendor {
+ VENDOR_ARM = 0x41,
+ VENDOR_ST = 0x80,
+};
+
/**
* vic_init - initialise a vectored interrupt controller
* @base: iomem base address
@@ -270,6 +288,28 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
u32 vic_sources, u32 resume_sources)
{
unsigned int i;
+ u32 cellid = 0;
+ enum vic_vendor vendor;
+
+ /* Identify which VIC cell this one is, by reading the ID */
+ for (i = 0; i < 4; i++) {
+ u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
+ cellid |= (readl(addr) & 0xff) << (8 * i);
+ }
+ vendor = (cellid >> 12) & 0xff;
+ printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x\n",
+ base, cellid, vendor);
+
+ switch(vendor) {
+ case VENDOR_ST:
+ vik_init_st(base, irq_start, vic_sources);
+ return;
+ default:
+ printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
+ /* fall through */
+ case VENDOR_ARM:
+ break;
+ }
/* Disable all interrupts initially. */
@@ -306,3 +346,60 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
vic_pm_register(base, irq_start, resume_sources);
}
+
+/*
+ * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
+ * The original cell has 32 interrupts, while the modified one has 64,
+ * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
+ * the probe function is called twice, with base set to offset 000
+ * and 020 within the page. We call this "second block".
+ */
+static void __init vik_init_st(void __iomem *base, unsigned int irq_start,
+ u32 vic_sources)
+{
+ unsigned int i;
+ int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
+
+ /* Disable all interrupts initially. */
+
+ writel(0, base + VIC_INT_SELECT);
+ writel(0, base + VIC_INT_ENABLE);
+ writel(~0, base + VIC_INT_ENABLE_CLEAR);
+ writel(0, base + VIC_IRQ_STATUS);
+ writel(0, base + VIC_ITCR);
+ writel(~0, base + VIC_INT_SOFT_CLEAR);
+
+ /*
+ * Make sure we clear all existing interrupts. The vector registers
+ * in this cell are after the second block of general registers,
+ * so we can address them using standard offsets, but only from
+ * the second base address, which is 0x20 in the page
+ */
+ if (vic_2nd_block) {
+ writel(0, base + VIC_PL190_VECT_ADDR);
+ for (i = 0; i < 19; i++) {
+ unsigned int value;
+
+ value = readl(base + VIC_PL190_VECT_ADDR);
+ writel(value, base + VIC_PL190_VECT_ADDR);
+ }
+ /* ST has 16 vectors as well, but we don't enable them by now */
+ for (i = 0; i < 16; i++) {
+ void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
+ writel(0, reg);
+ }
+
+ writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (vic_sources & (1 << i)) {
+ unsigned int irq = irq_start + i;
+
+ set_irq_chip(irq, &vic_chip);
+ set_irq_chip_data(irq, base);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ }
+}
diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig
new file mode 100644
index 000000000000..601e7f3d5e97
--- /dev/null
+++ b/arch/arm/configs/cpu9260_defconfig
@@ -0,0 +1,1338 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc3
+# Tue Jul 14 14:57:55 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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# 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 is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_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=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance 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
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# 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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# 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=y
+# 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_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_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_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+CONFIG_ARCH_AT91SAM9260=y
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91SAM9260 Variants
+#
+# CONFIG_ARCH_AT91SAM9260_SAM9XE is not set
+
+#
+# AT91SAM9260 / AT91SAM9XE Board Type
+#
+# CONFIG_MACH_AT91SAM9260EK is not set
+# CONFIG_MACH_CAM60 is not set
+# CONFIG_MACH_SAM9_L9260 is not set
+# CONFIG_MACH_AFEB9260 is not set
+# CONFIG_MACH_USB_A9260 is not set
+# CONFIG_MACH_QIL_A9260 is not set
+CONFIG_MACH_CPU9260=y
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# 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 is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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=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=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# 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_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# 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_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 is not set
+# 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_PLATRAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_ATMEL_ECC_HW=y
+# CONFIG_MTD_NAND_ATMEL_ECC_SOFT is not set
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# 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 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# 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 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_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# 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 is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# 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 is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# 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_KS8842 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
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD 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_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# CONFIG_IPMI_HANDLER 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# 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_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# 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=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91SAM9X_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_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 is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=y
+# 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_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# 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
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AT91=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_AT91SAM9 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 is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# 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 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# 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 is not set
+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=y
+# 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 is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER 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 is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig
new file mode 100644
index 000000000000..b5b9cbbc6977
--- /dev/null
+++ b/arch/arm/configs/cpu9g20_defconfig
@@ -0,0 +1,1328 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc3
+# Tue Jul 14 15:03:43 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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# 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 is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_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=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance 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
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# 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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# 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=y
+# 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_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_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_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+CONFIG_ARCH_AT91SAM9G20=y
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91SAM9G20 Board Type
+#
+# CONFIG_MACH_AT91SAM9G20EK is not set
+CONFIG_MACH_CPU9G20=y
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# 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 is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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=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=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# 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_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# 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_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 is not set
+# 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_PLATRAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+# CONFIG_MTD_NAND_ATMEL_ECC_HW is not set
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# 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 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# 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 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_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# 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 is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# 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 is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# 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_KS8842 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
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD 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_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# CONFIG_IPMI_HANDLER 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# 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_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# 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=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91SAM9X_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_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 is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=y
+# 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_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# 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
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AT91=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_AT91SAM9 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 is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# 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 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# 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 is not set
+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=y
+# 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 is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER 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 is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/cpuat91_defconfig b/arch/arm/configs/cpuat91_defconfig
new file mode 100644
index 000000000000..4901827253fb
--- /dev/null
+++ b/arch/arm/configs/cpuat91_defconfig
@@ -0,0 +1,1316 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc3
+# Tue Jul 14 14:45:01 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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# 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 is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_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=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance 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
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# 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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# 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=y
+# 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_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_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_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+CONFIG_ARCH_AT91RM9200=y
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91RM9200 Board Type
+#
+# CONFIG_MACH_ONEARM is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MACH_AT91RM9200EK is not set
+# CONFIG_MACH_CSB337 is not set
+# CONFIG_MACH_CSB637 is not set
+# CONFIG_MACH_CARMEVA is not set
+# CONFIG_MACH_ATEB9200 is not set
+# CONFIG_MACH_KB9200 is not set
+# CONFIG_MACH_PICOTUX2XX is not set
+# CONFIG_MACH_KAFA is not set
+# CONFIG_MACH_ECBAT91 is not set
+# CONFIG_MACH_YL9200 is not set
+CONFIG_MACH_CPUAT91=y
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V4WT=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 is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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 is not set
+# 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=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# 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_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE 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
+# CONFIG_ARTHUR 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_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 is not set
+# 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_PLATRAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# 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 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# 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 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_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_ARM_AT91_ETHER=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# 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_KS8842 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
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# CONFIG_IPMI_HANDLER 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# 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_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# 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=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91RM9200_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_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 is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=y
+# 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_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# 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
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AT91=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_DRV_PCF8563=y
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_AT91RM9200 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 is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# 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 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# 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 is not set
+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=y
+# 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 is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_DEBUG_USER 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 is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/da830_omapl137_defconfig b/arch/arm/configs/da830_omapl137_defconfig
new file mode 100644
index 000000000000..7c8e38f5c5ab
--- /dev/null
+++ b/arch/arm/configs/da830_omapl137_defconfig
@@ -0,0 +1,1254 @@
+#
+# 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/da850_omapl138_defconfig
new file mode 100644
index 000000000000..842a70b079bf
--- /dev/null
+++ b/arch/arm/configs/da850_omapl138_defconfig
@@ -0,0 +1,1229 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-davinci1
+# Mon Jun 29 07:54:15 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_DM355 is not set
+# CONFIG_ARCH_DAVINCI_DM646x is not set
+# CONFIG_ARCH_DAVINCI_DA830 is not set
+CONFIG_ARCH_DAVINCI_DA850=y
+CONFIG_ARCH_DAVINCI_DA8XX=y
+# CONFIG_ARCH_DAVINCI_DM365 is not set
+
+#
+# DaVinci Board Type
+#
+CONFIG_MACH_DAVINCI_DA850_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 is not set
+# 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_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
+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 is not set
+# 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_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/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index ac18662f38cc..ddffe39d9f87 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc7
-# Tue May 26 07:24:28 2009
+# Linux kernel version: 2.6.31-rc3-davinci1
+# Fri Jul 17 08:26:52 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -9,7 +9,6 @@ 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 +17,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
@@ -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,8 +89,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Performance 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
@@ -106,6 +107,11 @@ CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
@@ -118,7 +124,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -145,13 +151,14 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# 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_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -160,26 +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_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_AINTC=y
+CONFIG_ARCH_DAVINCI_DMx=y
#
# TI DaVinci Implementations
@@ -191,6 +199,9 @@ CONFIG_AINTC=y
CONFIG_ARCH_DAVINCI_DM644x=y
CONFIG_ARCH_DAVINCI_DM355=y
CONFIG_ARCH_DAVINCI_DM646x=y
+# CONFIG_ARCH_DAVINCI_DA830 is not set
+# CONFIG_ARCH_DAVINCI_DA850 is not set
+CONFIG_ARCH_DAVINCI_DM365=y
#
# DaVinci Board Type
@@ -200,6 +211,7 @@ CONFIG_MACH_SFFSDR=y
CONFIG_MACH_DAVINCI_DM355_EVM=y
CONFIG_MACH_DM355_LEOPARD=y
CONFIG_MACH_DAVINCI_DM6467_EVM=y
+CONFIG_MACH_DAVINCI_DM365_EVM=y
CONFIG_DAVINCI_MUX=y
CONFIG_DAVINCI_MUX_DEBUG=y
CONFIG_DAVINCI_MUX_WARNINGS=y
@@ -227,7 +239,6 @@ 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_COMMON_CLKDEV=y
#
@@ -252,7 +263,6 @@ 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 +278,13 @@ 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_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
@@ -415,6 +426,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
@@ -553,6 +565,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
@@ -564,6 +577,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=m
@@ -609,10 +623,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
@@ -637,7 +647,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
@@ -684,6 +693,7 @@ CONFIG_DM9000_DEBUGLEVEL=4
# 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
@@ -748,18 +758,21 @@ CONFIG_INPUT_EVBUG=m
#
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_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_NEWTON 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
@@ -773,6 +786,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -832,6 +846,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
@@ -854,7 +869,6 @@ CONFIG_I2C_DAVINCI=y
#
# 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
@@ -935,6 +949,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -986,52 +1001,8 @@ CONFIG_SSB_POSSIBLE=y
# 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=y
-CONFIG_VIDEO_V4L2_COMMON=y
-CONFIG_VIDEO_ALLOW_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-# CONFIG_DVB_CORE is not set
-CONFIG_VIDEO_MEDIA=y
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=y
-CONFIG_MEDIA_TUNER_TDA8290=y
-CONFIG_MEDIA_TUNER_TDA9887=y
-CONFIG_MEDIA_TUNER_TEA5761=y
-CONFIG_MEDIA_TUNER_TEA5767=y
-CONFIG_MEDIA_TUNER_MT20XX=y
-CONFIG_MEDIA_TUNER_XC2028=y
-CONFIG_MEDIA_TUNER_XC5000=y
-CONFIG_MEDIA_TUNER_MC44S803=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_SOC_CAMERA is not set
-# CONFIG_V4L_USB_DRIVERS is not set
-# CONFIG_RADIO_ADAPTERS is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1102,6 +1073,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
@@ -1112,9 +1088,16 @@ CONFIG_SND_USB=y
# CONFIG_SND_USB_AUDIO is not set
# CONFIG_SND_USB_CAIAQ is not set
CONFIG_SND_SOC=m
-# CONFIG_SND_DAVINCI_SOC is not set
+CONFIG_SND_DAVINCI_SOC=m
+CONFIG_SND_DAVINCI_SOC_I2S=m
+CONFIG_SND_DAVINCI_SOC_MCASP=m
+CONFIG_SND_DAVINCI_SOC_EVM=m
+CONFIG_SND_DM6467_SOC_EVM=m
+# CONFIG_SND_DAVINCI_SOC_SFFSDR is not set
CONFIG_SND_SOC_I2C_AND_SPI=m
# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_TLV320AIC3X=m
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=m
@@ -1143,7 +1126,7 @@ CONFIG_HID_BELKIN=m
CONFIG_HID_CHERRY=m
CONFIG_HID_CHICONY=m
CONFIG_HID_CYPRESS=m
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=m
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=m
@@ -1160,10 +1143,11 @@ CONFIG_HID_PETALYNX=m
CONFIG_HID_SAMSUNG=m
CONFIG_HID_SONY=m
CONFIG_HID_SUNPLUS=m
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
# CONFIG_USB_ARCH_HAS_OHCI is not set
@@ -1266,6 +1250,7 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
@@ -1285,17 +1270,20 @@ CONFIG_USB_GADGET_SELECTED=y
# 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_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
# CONFIG_USB_GADGET_CI13XXX is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
CONFIG_USB_ZERO=m
+# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
CONFIG_USB_GADGETFS=m
@@ -1311,7 +1299,7 @@ CONFIG_USB_CDC_COMPOSITE=m
#
CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
-# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_NOP_USB_XCEIV=m
CONFIG_MMC=m
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
@@ -1328,7 +1316,6 @@ CONFIG_MMC_BLOCK=m
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_DAVINCI is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
CONFIG_NEW_LEDS=y
@@ -1340,7 +1327,7 @@ CONFIG_LEDS_CLASS=m
# CONFIG_LEDS_PCA9532 is not set
CONFIG_LEDS_GPIO=m
CONFIG_LEDS_GPIO_PLATFORM=y
-# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_BD2802 is not set
@@ -1386,6 +1373,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1433,14 +1421,16 @@ 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_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1623,6 +1613,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
@@ -1654,18 +1645,16 @@ CONFIG_DEBUG_BUGVERBOSE=y
# 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
diff --git a/arch/arm/configs/littleton_defconfig b/arch/arm/configs/littleton_defconfig
deleted file mode 100644
index 1db496908052..000000000000
--- a/arch/arm/configs/littleton_defconfig
+++ /dev/null
@@ -1,783 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24-rc5
-# Fri Dec 21 11:06:19 2007
-#
-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_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_ARCH_MTD_XIP=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=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
-CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_FAIR_USER_SCHED=y
-# CONFIG_FAIR_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-# CONFIG_KMOD is not set
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
-#
-# 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_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX 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_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_PNX4008 is not set
-CONFIG_ARCH_PXA=y
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_OMAP is not set
-
-#
-# Intel PXA2xx/PXA3xx Implementations
-#
-
-#
-# Supported PXA3xx Processor Variants
-#
-CONFIG_CPU_PXA300=y
-CONFIG_CPU_PXA310=y
-# CONFIG_CPU_PXA320 is not set
-# CONFIG_ARCH_LUBBOCK is not set
-# CONFIG_MACH_LOGICPD_PXA270 is not set
-# CONFIG_MACH_MAINSTONE is not set
-# CONFIG_ARCH_PXA_IDP is not set
-# CONFIG_PXA_SHARPSL is not set
-# CONFIG_MACH_TRIZEPS4 is not set
-# CONFIG_MACH_EM_X270 is not set
-# CONFIG_MACH_ZYLONITE is not set
-CONFIG_MACH_LITTLETON=y
-# CONFIG_MACH_ARMCORE is not set
-CONFIG_PXA3xx=y
-CONFIG_PXA_SSP=y
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSC3=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
-CONFIG_IO_36=y
-
-#
-# Processor Features
-#
-# CONFIG_ARM_THUMB is not set
-# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_BPREDICT_DISABLE is not set
-# CONFIG_OUTER_CACHE is not set
-CONFIG_IWMMXT=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 is not set
-# CONFIG_HIGH_RES_TIMERS is not set
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-CONFIG_PREEMPT=y
-CONFIG_HZ=100
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS2,38400 mem=64M"
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-CONFIG_SUSPEND_UP_POSSIBLE=y
-
-#
-# Networking
-#
-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_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 is not set
-# 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 is not set
-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 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER 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_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_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 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 is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_FW_LOADER=y
-# 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 is not set
-# CONFIG_MISC_DEVICES is not set
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_NETLINK is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_AX88796 is not set
-CONFIG_SMC91X=y
-# CONFIG_DM9000 is not set
-# CONFIG_SMC911X 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_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
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# 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=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
-# CONFIG_WATCHDOG is not set
-
-#
-# Sonics Silicon Backplane
-#
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_DAB is not set
-
-#
-# Graphics support
-#
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-# CONFIG_FB_S1D13XXX is not set
-CONFIG_FB_PXA=y
-# CONFIG_FB_PXA_PARAMETERS is not set
-# CONFIG_FB_MBX is not set
-# CONFIG_FB_VIRTUAL 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_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_7x14 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_10x18 is not set
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
-# CONFIG_NEW_LEDS is not set
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_INOTIFY is not set
-# CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# 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 is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_BIND34 is not set
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
-# CONFIG_DLM is not set
-# CONFIG_INSTRUMENTATION is not set
-
-#
-# Kernel hacking
-#
-CONFIG_PRINTK_TIME=y
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
-CONFIG_DETECT_SOFTLOCKUP=y
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_LOCK_STAT is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-CONFIG_FRAME_POINTER=y
-CONFIG_FORCED_INLINING=y
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SAMPLES is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_ECB is not set
-CONFIG_CRYPTO_CBC=y
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-CONFIG_CRYPTO_HW=y
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_CRC_CCITT=y
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/mx27_defconfig b/arch/arm/configs/mx27_defconfig
index 083516cd0d7f..75263a83741c 100644
--- a/arch/arm/configs/mx27_defconfig
+++ b/arch/arm/configs/mx27_defconfig
@@ -1,15 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc1
-# Wed Apr 8 10:18:06 2009
+# Linux kernel version: 2.6.31-rc4
+# Fri Jul 24 16:08:06 2009
#
CONFIG_ARM=y
+CONFIG_HAVE_PWM=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 +18,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_ARCH_MTD_XIP=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
@@ -85,7 +84,12 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Performance Counters
+#
CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -99,6 +103,12 @@ CONFIG_KPROBES=y
CONFIG_KRETPROBES=y
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
@@ -111,7 +121,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -138,13 +148,14 @@ CONFIG_FREEZER=y
# 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=y
+# 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_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -153,25 +164,25 @@ CONFIG_FREEZER=y
# 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=y
# 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_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
#
# Freescale MXC Implementations
@@ -188,6 +199,8 @@ CONFIG_MACH_MX27=y
CONFIG_MACH_MX27ADS=y
CONFIG_MACH_PCM038=y
CONFIG_MACH_PCM970_BASEBOARD=y
+CONFIG_MACH_MX27_3DS=y
+CONFIG_MACH_MX27LITE=y
CONFIG_MXC_IRQ_PRIOR=y
CONFIG_MXC_PWM=y
@@ -213,7 +226,6 @@ 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_COMMON_CLKDEV=y
#
@@ -238,7 +250,6 @@ CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
-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
@@ -253,10 +264,11 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096
# CONFIG_PHYS_ADDR_T_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
#
# Boot options
@@ -361,6 +373,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -474,7 +487,16 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_MXC=y
# CONFIG_MTD_ONENAND is not set
#
@@ -485,7 +507,15 @@ CONFIG_MTD_PHYSMAP=y
#
# UBI - Unsorted block images
#
-# CONFIG_MTD_UBI is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
@@ -494,7 +524,21 @@ CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_MISC_DEVICES is not set
+# CONFIG_MG_DISK 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_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -508,7 +552,6 @@ CONFIG_HAVE_IDE=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
@@ -534,6 +577,8 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
CONFIG_FEC=y
# CONFIG_FEC2 is not set
# CONFIG_NETDEV_1000 is not set
@@ -580,6 +625,11 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
@@ -592,6 +642,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
#
@@ -644,6 +695,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_IMX=y
# CONFIG_I2C_OCORES is not set
@@ -668,7 +720,6 @@ CONFIG_I2C_IMX=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -719,6 +770,7 @@ CONFIG_W1=y
#
# CONFIG_W1_MASTER_DS2482 is not set
CONFIG_W1_MASTER_MXC=y
+# CONFIG_W1_MASTER_DS1WM is not set
# CONFIG_W1_MASTER_GPIO is not set
#
@@ -753,54 +805,16 @@ CONFIG_SSB_POSSIBLE=y
# 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=y
-CONFIG_VIDEO_V4L2_COMMON=y
-CONFIG_VIDEO_ALLOW_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-# CONFIG_DVB_CORE is not set
-CONFIG_VIDEO_MEDIA=y
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=y
-CONFIG_MEDIA_TUNER_TDA8290=y
-CONFIG_MEDIA_TUNER_TDA9887=y
-CONFIG_MEDIA_TUNER_TEA5761=y
-CONFIG_MEDIA_TUNER_TEA5767=y
-CONFIG_MEDIA_TUNER_MT20XX=y
-CONFIG_MEDIA_TUNER_XC2028=y
-CONFIG_MEDIA_TUNER_XC5000=y
-CONFIG_MEDIA_TUNER_MC44S803=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_SOC_CAMERA is not set
-# CONFIG_RADIO_ADAPTERS is not set
-# CONFIG_DAB is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -917,6 +931,7 @@ CONFIG_RTC_DRV_PCF8563=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -962,12 +977,15 @@ CONFIG_RTC_DRV_PCF8563=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -1021,6 +1039,12 @@ CONFIG_JFFS2_ZLIB=y
# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -1119,25 +1143,11 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=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_FTRACE_STARTUP_TEST is not set
+# CONFIG_FTRACE is not set
# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
@@ -1151,16 +1161,104 @@ CONFIG_ARM_UNWIND=y
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# 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=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
CONFIG_BINARY_PRINTF=y
#
# Library routines
#
CONFIG_BITREVERSE=y
+CONFIG_RATIONAL=y
CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
@@ -1168,6 +1266,8 @@ CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig
index 20ada526f6de..a4f9a2a8149c 100644
--- a/arch/arm/configs/mx3_defconfig
+++ b/arch/arm/configs/mx3_defconfig
@@ -1,15 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc1
-# Wed Apr 8 11:06:37 2009
+# Linux kernel version: 2.6.31-rc4
+# Tue Jul 28 14:11:34 2009
#
CONFIG_ARM=y
+CONFIG_HAVE_PWM=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 +18,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_ARCH_MTD_XIP=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
@@ -86,7 +85,12 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Performance Counters
+#
CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -97,6 +101,11 @@ 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_SLOW_WORK is not set
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
@@ -109,7 +118,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
@@ -136,13 +145,14 @@ CONFIG_FREEZER=y
# 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=y
+# 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_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -151,25 +161,25 @@ CONFIG_FREEZER=y
# 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=y
# 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_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
#
# Freescale MXC Implementations
@@ -178,6 +188,7 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_MX2 is not set
CONFIG_ARCH_MX3=y
CONFIG_ARCH_MX31=y
+CONFIG_ARCH_MX35=y
#
# MX3 platforms:
@@ -185,12 +196,19 @@ CONFIG_ARCH_MX31=y
CONFIG_MACH_MX31ADS=y
CONFIG_MACH_MX31ADS_WM1133_EV1=y
CONFIG_MACH_PCM037=y
+CONFIG_MACH_PCM037_EET=y
CONFIG_MACH_MX31LITE=y
CONFIG_MACH_MX31_3DS=y
CONFIG_MACH_MX31MOBOARD=y
+CONFIG_MACH_MX31LILLY=y
CONFIG_MACH_QONG=y
+CONFIG_MACH_PCM043=y
+CONFIG_MACH_ARMADILLO5X0=y
+CONFIG_MACH_MX35_3DS=y
CONFIG_MXC_IRQ_PRIOR=y
CONFIG_MXC_PWM=y
+CONFIG_ARCH_HAS_RNGA=y
+CONFIG_ARCH_MXC_IOMUX_V3=y
#
# Processor Type
@@ -218,6 +236,7 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_OUTER_CACHE=y
CONFIG_CACHE_L2X0=y
+# CONFIG_ARM_ERRATA_411920 is not set
CONFIG_COMMON_CLKDEV=y
#
@@ -242,7 +261,6 @@ CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
-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
@@ -257,10 +275,11 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_PHYS_ADDR_T_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
#
# Boot options
@@ -362,6 +381,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -465,7 +485,16 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_MXC=y
# CONFIG_MTD_ONENAND is not set
#
@@ -476,10 +505,30 @@ CONFIG_MTD_PHYSMAP=y
#
# UBI - Unsorted block images
#
-# CONFIG_MTD_UBI is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES 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_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -493,7 +542,6 @@ CONFIG_HAVE_IDE=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
@@ -528,7 +576,7 @@ CONFIG_MII=y
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
CONFIG_SMSC911X=y
-# CONFIG_DNET is not set
+CONFIG_DNET=y
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -537,8 +585,10 @@ CONFIG_SMSC911X=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_CS89x0=y
-CONFIG_CS89x0_NONISA_IRQ=y
+# CONFIG_CS89x0 is not set
+# CONFIG_KS8842 is not set
+CONFIG_FEC=y
+# CONFIG_FEC2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -609,6 +659,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_IMX=y
# CONFIG_I2C_OCORES is not set
@@ -633,7 +684,6 @@ CONFIG_I2C_IMX=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -669,6 +719,7 @@ CONFIG_W1=y
#
# CONFIG_W1_MASTER_DS2482 is not set
CONFIG_W1_MASTER_MXC=y
+# CONFIG_W1_MASTER_DS1WM is not set
# CONFIG_W1_MASTER_GPIO is not set
#
@@ -703,6 +754,8 @@ CONFIG_SSB_POSSIBLE=y
# 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
@@ -711,10 +764,8 @@ CONFIG_MFD_WM8350_CONFIG_MODE_0=y
CONFIG_MFD_WM8352_CONFIG_MODE_0=y
CONFIG_MFD_WM8350_I2C=y
# CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
+# CONFIG_AB3100_CORE is not set
+CONFIG_MEDIA_SUPPORT=y
#
# Multimedia core support
@@ -758,8 +809,10 @@ CONFIG_SOC_CAMERA_MT9T031=y
CONFIG_SOC_CAMERA_MT9V022=y
CONFIG_SOC_CAMERA_TW9910=y
# CONFIG_SOC_CAMERA_PLATFORM is not set
-# CONFIG_SOC_CAMERA_OV772X is not set
+CONFIG_SOC_CAMERA_OV772X=y
+CONFIG_MX3_VIDEO=y
CONFIG_VIDEO_MX3=y
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DAB is not set
@@ -847,8 +900,11 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
CONFIG_REGULATOR_WM8350=y
+# CONFIG_REGULATOR_LP3971 is not set
# CONFIG_UIO is not set
# CONFIG_STAGING is not set
@@ -861,10 +917,12 @@ CONFIG_REGULATOR_WM8350=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -921,6 +979,12 @@ CONFIG_JFFS2_ZLIB=y
# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -937,6 +1001,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -979,22 +1044,7 @@ CONFIG_FRAME_WARN=1024
CONFIG_SYSCTL_SYSCALL_CHECK=y
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_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_ARM_UNWIND=y
@@ -1094,9 +1144,9 @@ CONFIG_CRYPTO_DES=y
#
# Compression
#
-# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_DEFLATE=y
# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_LZO=y
#
# Random Number Generation
@@ -1109,9 +1159,10 @@ CONFIG_CRYPTO_HW=y
# Library routines
#
CONFIG_BITREVERSE=y
+CONFIG_RATIONAL=y
CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
@@ -1119,6 +1170,8 @@ CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
new file mode 100644
index 000000000000..9bb45b932f04
--- /dev/null
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -0,0 +1,1316 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30
+# Tue Jun 23 22:57:16 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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# 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 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=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# 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=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# 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_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX 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_NOMADIK=y
+# 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_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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_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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Nomadik boards
+#
+CONFIG_MACH_NOMADIK_8815NHK=y
+CONFIG_NOMADIK_8815=y
+CONFIG_I2C_BITBANG_8815NHK=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 is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
+CONFIG_ARM_VIC=y
+CONFIG_ARM_VIC_NR=2
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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=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=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# 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_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# 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=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_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=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 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=y
+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 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+CONFIG_BT_HCIVHCI=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_TESTS=m
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_NOMADIK=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_GENERIC=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# 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
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+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_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=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_KS8842 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# 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=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_NETCONSOLE=m
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+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 is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=y
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# 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=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# 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 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
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_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 is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_WACOM is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# 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=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 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_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+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=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+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=y
+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=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# 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 is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_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
+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_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE 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 is not set
+# CONFIG_DEBUG_ERRORS is not set
+# 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_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# 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=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# 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=y
+# 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=y
+# 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=m
+# 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=y
+# 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=y
+# 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 is not set
+# 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_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig
index 28be17fbc157..d5ff4776cd0a 100644
--- a/arch/arm/configs/omap3_evm_defconfig
+++ b/arch/arm/configs/omap3_evm_defconfig
@@ -1107,7 +1107,7 @@ CONFIG_USB_ZERO=m
CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_ISP1301_OMAP is not set
-CONFIG_TWL4030_USB=y
+# CONFIG_TWL4030_USB is not set
# CONFIG_NOP_USB_XCEIV is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
new file mode 100644
index 000000000000..733b851e5b7e
--- /dev/null
+++ b/arch/arm/configs/pxa3xx_defconfig
@@ -0,0 +1,1332 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc1
+# Mon Jul 13 22:48:49 2009
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_CLASSIC_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+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=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# 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=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# 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_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX 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_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_LOKI is not set
+# CONFIG_ARCH_MV78XX0 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=y
+# 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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+
+#
+# Supported PXA3xx Processor Variants
+#
+CONFIG_CPU_PXA300=y
+CONFIG_CPU_PXA310=y
+CONFIG_CPU_PXA320=y
+CONFIG_CPU_PXA930=y
+CONFIG_CPU_PXA935=y
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_VIPER is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_H5000 is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
+CONFIG_MACH_ZYLONITE=y
+CONFIG_MACH_LITTLETON=y
+CONFIG_MACH_TAVOREVB=y
+CONFIG_MACH_SAAR=y
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_MACH_H4700 is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MIOA701 is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_MACH_CSB726 is not set
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA3xx=y
+CONFIG_PXA_SSP=y
+CONFIG_PXA_HAVE_BOARD_IRQS=y
+CONFIG_PLAT_PXA=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSC3=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_IO_36=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_XSC3L2=y
+CONFIG_IWMMXT=y
+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 is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+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=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=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=64M debug"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE 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_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 is not set
+# 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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 is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_PXA3xx=y
+CONFIG_MTD_NAND_PXA3xx_BUILTIN=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_GENERIC=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# 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 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_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_KS8842 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 is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+CONFIG_KEYBOARD_PXA27x=y
+CONFIG_KEYBOARD_PXA930_ROTARY=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+CONFIG_MOUSE_PXA930_TRKBALL=y
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+CONFIG_TOUCHSCREEN_DA9034=y
+# 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_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_TOUCHSCREEN_W90X900 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=y
+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 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER 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_CHARDEV is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE 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_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=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_PXA2XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 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=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCF857X=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+CONFIG_GPIO_MAX7301=y
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_SUPPLY_DEBUG=y
+CONFIG_PDA_POWER=y
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_BATTERY_DA9030=y
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# 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=y
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_OVERLAY is not set
+# CONFIG_FB_PXA_SMARTPANEL is not set
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+CONFIG_LCD_TDO24M=y
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_DA903X=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_PXA=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_PCA955X is not set
+CONFIG_LEDS_DA903X=m
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_DA903X=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# 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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# 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 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_WBUF_VERIFY=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# 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=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_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
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_ERRORS is not set
+# 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_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# 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=y
+# 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=y
+# 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=y
+# 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 is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/zylonite_defconfig b/arch/arm/configs/zylonite_defconfig
deleted file mode 100644
index 7949d04a3602..000000000000
--- a/arch/arm/configs/zylonite_defconfig
+++ /dev/null
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23
-# Tue Oct 23 13:33:20 2007
-#
-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_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_ARCH_MTD_XIP=y
-CONFIG_VECTORS_BASE=0xffff0000
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=18
-# CONFIG_CGROUPS is not set
-CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_FAIR_USER_SCHED=y
-# CONFIG_FAIR_CGROUP_SCHED is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-# CONFIG_KMOD is not set
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
-#
-# 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_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_EP93XX 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_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
-# CONFIG_ARCH_MXC is not set
-# CONFIG_ARCH_PNX4008 is not set
-CONFIG_ARCH_PXA=y
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_OMAP is not set
-
-#
-# Intel PXA2xx/PXA3xx Implementations
-#
-
-#
-# Supported PXA3xx Processor Variants
-#
-CONFIG_CPU_PXA300=y
-CONFIG_CPU_PXA310=y
-CONFIG_CPU_PXA320=y
-# CONFIG_ARCH_LUBBOCK is not set
-# CONFIG_MACH_LOGICPD_PXA270 is not set
-# CONFIG_MACH_MAINSTONE is not set
-# CONFIG_ARCH_PXA_IDP is not set
-# CONFIG_PXA_SHARPSL is not set
-# CONFIG_MACH_TRIZEPS4 is not set
-# CONFIG_MACH_EM_X270 is not set
-CONFIG_MACH_ZYLONITE=y
-# CONFIG_MACH_ARMCORE is not set
-CONFIG_PXA3xx=y
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSC3=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_CP15=y
-CONFIG_CPU_CP15_MMU=y
-CONFIG_IO_36=y
-
-#
-# Processor Features
-#
-# CONFIG_ARM_THUMB is not set
-# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_BPREDICT_DISABLE is not set
-# CONFIG_OUTER_CACHE is not set
-CONFIG_IWMMXT=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 is not set
-# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_PREEMPT is not set
-CONFIG_HZ=100
-CONFIG_AEABI=y
-CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfs/rootfs/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS0,38400 mem=64M debug"
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-CONFIG_SUSPEND_UP_POSSIBLE=y
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# 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=y
-CONFIG_IP_PNP_RARP=y
-# 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 is not set
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER 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_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_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 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=y
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-# CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES is not set
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_NETLINK is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_AX88796 is not set
-CONFIG_SMC91X=y
-# CONFIG_DM9000 is not set
-# CONFIG_SMC911X 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_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
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# 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=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
-
-#
-# Sonics Silicon Backplane
-#
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_DAB is not set
-
-#
-# Graphics support
-#
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-# CONFIG_FB_S1D13XXX is not set
-CONFIG_FB_PXA=y
-# CONFIG_FB_PXA_PARAMETERS is not set
-# CONFIG_FB_MBX is not set
-# CONFIG_FB_VIRTUAL 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_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-CONFIG_FONT_6x11=y
-# CONFIG_FONT_7x14 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_10x18 is not set
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
-# CONFIG_NEW_LEDS is not set
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_INOTIFY is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# 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 is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_BIND34 is not set
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
-# CONFIG_DLM is not set
-# CONFIG_INSTRUMENTATION is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-# CONFIG_SAMPLES is not set
-CONFIG_DEBUG_USER=y
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_ECB is not set
-CONFIG_CRYPTO_CBC=y
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_HW is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 15f8a092b700..2b60c7d05770 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -127,3 +127,87 @@
#endif
#endif
.endm
+
+#ifdef CONFIG_THUMB2_KERNEL
+ .macro setmode, mode, reg
+ mov \reg, #\mode
+ msr cpsr_c, \reg
+ .endm
+#else
+ .macro setmode, mode, reg
+ msr cpsr_c, #\mode
+ .endm
+#endif
+
+/*
+ * STRT/LDRT access macros with ARM and Thumb-2 variants
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+
+ .macro usraccoff, instr, reg, ptr, inc, off, cond, abort
+9999:
+ .if \inc == 1
+ \instr\cond\()bt \reg, [\ptr, #\off]
+ .elseif \inc == 4
+ \instr\cond\()t \reg, [\ptr, #\off]
+ .else
+ .error "Unsupported inc macro argument"
+ .endif
+
+ .section __ex_table,"a"
+ .align 3
+ .long 9999b, \abort
+ .previous
+ .endm
+
+ .macro usracc, instr, reg, ptr, inc, cond, rept, abort
+ @ explicit IT instruction needed because of the label
+ @ introduced by the USER macro
+ .ifnc \cond,al
+ .if \rept == 1
+ itt \cond
+ .elseif \rept == 2
+ ittt \cond
+ .else
+ .error "Unsupported rept macro argument"
+ .endif
+ .endif
+
+ @ Slightly optimised to avoid incrementing the pointer twice
+ usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
+ .if \rept == 2
+ usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort
+ .endif
+
+ add\cond \ptr, #\rept * \inc
+ .endm
+
+#else /* !CONFIG_THUMB2_KERNEL */
+
+ .macro usracc, instr, reg, ptr, inc, cond, rept, abort
+ .rept \rept
+9999:
+ .if \inc == 1
+ \instr\cond\()bt \reg, [\ptr], #\inc
+ .elseif \inc == 4
+ \instr\cond\()t \reg, [\ptr], #\inc
+ .else
+ .error "Unsupported inc macro argument"
+ .endif
+
+ .section __ex_table,"a"
+ .align 3
+ .long 9999b, \abort
+ .previous
+ .endr
+ .endm
+
+#endif /* CONFIG_THUMB2_KERNEL */
+
+ .macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
+ usracc str, \reg, \ptr, \inc, \cond, \rept, \abort
+ .endm
+
+ .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
+ usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort
+ .endm
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 9e07fe507029..9ed2377fe8e5 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -159,8 +159,6 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
#else /* ARM_ARCH_6 */
-#include <asm/system.h>
-
#ifdef CONFIG_SMP
#error SMP not supported on pre-ARMv6 CPUs
#endif
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 1a711ea8418b..fd03fb63a332 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -334,14 +334,14 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
#ifndef CONFIG_CPU_CACHE_VIPT
static inline void flush_cache_mm(struct mm_struct *mm)
{
- if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
__cpuc_flush_user_all();
}
static inline void
flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
{
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask))
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
vma->vm_flags);
}
@@ -349,7 +349,7 @@ flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long
static inline void
flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
{
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
unsigned long addr = user_addr & PAGE_MASK;
__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
}
@@ -360,7 +360,7 @@ flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
unsigned long uaddr, void *kaddr,
unsigned long len, int write)
{
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
unsigned long addr = (unsigned long)kaddr;
__cpuc_coherent_kern_range(addr, addr + len);
}
diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
index c61642b40603..9f390ce335cb 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -12,4 +12,7 @@ struct dev_archdata {
#endif
};
+struct pdev_archdata {
+};
+
#endif
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index c207504de84d..c3b911ee9151 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -55,6 +55,9 @@ typedef struct user_fp elf_fpregset_t;
#define R_ARM_MOVW_ABS_NC 43
#define R_ARM_MOVT_ABS 44
+#define R_ARM_THM_CALL 10
+#define R_ARM_THM_JUMP24 30
+
/*
* These are used to set parameters in the core dumps.
*/
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index 39c8bc1a006a..d74265cffd86 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -11,4 +11,38 @@ extern void mcount(void);
#endif
+#ifndef __ASSEMBLY__
+
+#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+/*
+ * return_address uses walk_stackframe to do it's work. If both
+ * CONFIG_FRAME_POINTER=y and CONFIG_ARM_UNWIND=y walk_stackframe uses unwind
+ * information. For this to work in the function tracer many functions would
+ * have to be marked with __notrace. So for now just depend on
+ * !CONFIG_ARM_UNWIND.
+ */
+
+void *return_address(unsigned int);
+
+#else
+
+extern inline void *return_address(unsigned int level)
+{
+ return NULL;
+}
+
+#endif
+
+#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 /* ifndef __ASSEMBLY__ */
+
#endif /* _ASM_ARM_FTRACE */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 9ee743b95de8..bfcc15929a7f 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -99,6 +99,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: ldrt %0, [%3]\n"
" teq %0, %1\n"
+ " it eq @ explicit IT needed for the 2b label\n"
"2: streqt %2, [%3]\n"
"3:\n"
" .section __ex_table,\"a\"\n"
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index 4da332b03144..b490ecc79def 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -10,6 +10,8 @@ struct mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
u32 (*translate_vdd)(struct device *, unsigned int);
unsigned int (*status)(struct device *);
+ int gpio_wp;
+ int gpio_cd;
};
#endif
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 85763db87449..376be1a62866 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -44,7 +44,13 @@
* The module space lives between the addresses given by TASK_SIZE
* and PAGE_OFFSET - it must be within 32MB of the kernel text.
*/
+#ifndef CONFIG_THUMB2_KERNEL
#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024)
+#else
+/* smaller range for Thumb-2 symbols relocation (2^24)*/
+#define MODULES_VADDR (PAGE_OFFSET - 8*1024*1024)
+#endif
+
#if TASK_SIZE > MODULES_VADDR
#error Top of user space clashes with start of module space
#endif
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index 263fed05ea33..de6cefb329dd 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -62,8 +62,10 @@ static inline void check_context(struct mm_struct *mm)
static inline void check_context(struct mm_struct *mm)
{
+#ifdef CONFIG_MMU
if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
__check_kvm_seq(mm);
+#endif
}
#define init_new_context(tsk,mm) 0
@@ -101,14 +103,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
#ifdef CONFIG_SMP
/* check for possible thread migration */
- if (!cpus_empty(next->cpu_vm_mask) && !cpu_isset(cpu, next->cpu_vm_mask))
+ if (!cpumask_empty(mm_cpumask(next)) &&
+ !cpumask_test_cpu(cpu, mm_cpumask(next)))
__flush_icache_all();
#endif
- if (!cpu_test_and_set(cpu, next->cpu_vm_mask) || prev != next) {
+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
check_context(next);
cpu_switch_mm(next->pgd, next);
if (cache_is_vivt())
- cpu_clear(cpu, prev->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
}
#endif
}
diff --git a/arch/arm/include/asm/page-nommu.h b/arch/arm/include/asm/page-nommu.h
index 3574c0deb37f..d1b162a18dcb 100644
--- a/arch/arm/include/asm/page-nommu.h
+++ b/arch/arm/include/asm/page-nommu.h
@@ -43,7 +43,4 @@ typedef unsigned long pgprot_t;
#define __pmd(x) (x)
#define __pgprot(x) (x)
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
#endif
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 0abf386ba3d3..226cddd2fb65 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -6,8 +6,6 @@
#include <mach/hardware.h> /* for PCIBIOS_MIN_* */
-#define pcibios_scan_all_fns(a, b) 0
-
#ifdef CONFIG_PCI_HOST_ITE8152
/* ITE bridge requires setting latency timer to avoid early bus access
termination by PIC bus mater devices
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index c433c6c73112..9655bce3d345 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -162,10 +162,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
* entries are stored 1024 bytes below.
*/
#define L_PTE_PRESENT (1 << 0)
-#define L_PTE_FILE (1 << 1) /* only when !PRESENT */
#define L_PTE_YOUNG (1 << 1)
-#define L_PTE_BUFFERABLE (1 << 2) /* obsolete, matches PTE */
-#define L_PTE_CACHEABLE (1 << 3) /* obsolete, matches PTE */
+#define L_PTE_FILE (1 << 2) /* only when !PRESENT */
#define L_PTE_DIRTY (1 << 6)
#define L_PTE_WRITE (1 << 7)
#define L_PTE_USER (1 << 8)
@@ -381,13 +379,13 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
*
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * <--------------- offset --------------------> <--- type --> 0 0
+ * <--------------- offset --------------------> <- type --> 0 0 0
*
- * This gives us up to 127 swap files and 32GB per swap file. Note that
+ * This gives us up to 63 swap files and 32GB per swap file. Note that
* the offset field is always non-zero.
*/
-#define __SWP_TYPE_SHIFT 2
-#define __SWP_TYPE_BITS 7
+#define __SWP_TYPE_SHIFT 3
+#define __SWP_TYPE_BITS 6
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
@@ -411,13 +409,13 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
*
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * <------------------------ offset -------------------------> 1 0
+ * <----------------------- offset ------------------------> 1 0 0
*/
#define pte_file(pte) (pte_val(pte) & L_PTE_FILE)
-#define pte_to_pgoff(x) (pte_val(x) >> 2)
-#define pgoff_to_pte(x) __pte(((x) << 2) | L_PTE_FILE)
+#define pte_to_pgoff(x) (pte_val(x) >> 3)
+#define pgoff_to_pte(x) __pte(((x) << 3) | L_PTE_FILE)
-#define PTE_FILE_MAX_BITS 30
+#define PTE_FILE_MAX_BITS 29
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
/* FIXME: this is not correct */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 67b833c9b6b9..bbecccda76d0 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -82,6 +82,14 @@
#define PSR_ENDSTATE 0
#endif
+/*
+ * These are 'magic' values for PTRACE_PEEKUSR that return info about where a
+ * process is located in memory.
+ */
+#define PT_TEXT_ADDR 0x10000
+#define PT_DATA_ADDR 0x10004
+#define PT_TEXT_END_ADDR 0x10008
+
#ifndef __ASSEMBLY__
/*
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index a06e735b262a..e0d763be1846 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -93,7 +93,6 @@ extern void platform_cpu_enable(unsigned int cpu);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
/*
* show local interrupt info
diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h
index 321c83e43a1e..f41a6f57cd12 100644
--- a/arch/arm/include/asm/tlb.h
+++ b/arch/arm/include/asm/tlb.h
@@ -102,8 +102,8 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
}
#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep) pte_free((tlb)->mm, ptep)
-#define pmd_free_tlb(tlb, pmdp) pmd_free((tlb)->mm, pmdp)
+#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp)
#define tlb_migrate_finish(mm) do { } while (0)
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index c964f3fc3bc5..a45ab5dd8255 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 (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), 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))
@@ -388,7 +388,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
if (tlb_flag(TLB_WB))
dsb();
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
if (tlb_flag(TLB_V3_PAGE))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_U_PAGE))
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 0da9bc9b3b1d..1d6bd40a4322 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -17,6 +17,7 @@
#include <asm/memory.h>
#include <asm/domain.h>
#include <asm/system.h>
+#include <asm/unified.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -365,8 +366,10 @@ do { \
#define __put_user_asm_dword(x,__pu_addr,err) \
__asm__ __volatile__( \
- "1: strt " __reg_oper1 ", [%1], #4\n" \
- "2: strt " __reg_oper0 ", [%1]\n" \
+ ARM( "1: strt " __reg_oper1 ", [%1], #4\n" ) \
+ ARM( "2: strt " __reg_oper0 ", [%1]\n" ) \
+ THUMB( "1: strt " __reg_oper1 ", [%1]\n" ) \
+ THUMB( "2: strt " __reg_oper0 ", [%1, #4]\n" ) \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h
new file mode 100644
index 000000000000..073e85b9b961
--- /dev/null
+++ b/arch/arm/include/asm/unified.h
@@ -0,0 +1,126 @@
+/*
+ * include/asm-arm/unified.h - Unified Assembler Syntax helper macros
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_UNIFIED_H
+#define __ASM_UNIFIED_H
+
+#if defined(__ASSEMBLY__) && defined(CONFIG_ARM_ASM_UNIFIED)
+ .syntax unified
+#endif
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+#if __GNUC__ < 4
+#error Thumb-2 kernel requires gcc >= 4
+#endif
+
+/* The CPSR bit describing the instruction set (Thumb) */
+#define PSR_ISETSTATE PSR_T_BIT
+
+#define ARM(x...)
+#define THUMB(x...) x
+#define W(instr) instr.w
+#define BSYM(sym) sym + 1
+
+#else /* !CONFIG_THUMB2_KERNEL */
+
+/* The CPSR bit describing the instruction set (ARM) */
+#define PSR_ISETSTATE 0
+
+#define ARM(x...) x
+#define THUMB(x...)
+#define W(instr) instr
+#define BSYM(sym) sym
+
+#endif /* CONFIG_THUMB2_KERNEL */
+
+#ifndef CONFIG_ARM_ASM_UNIFIED
+
+/*
+ * If the unified assembly syntax isn't used (in ARM mode), these
+ * macros expand to an empty string
+ */
+#ifdef __ASSEMBLY__
+ .macro it, cond
+ .endm
+ .macro itt, cond
+ .endm
+ .macro ite, cond
+ .endm
+ .macro ittt, cond
+ .endm
+ .macro itte, cond
+ .endm
+ .macro itet, cond
+ .endm
+ .macro itee, cond
+ .endm
+ .macro itttt, cond
+ .endm
+ .macro ittte, cond
+ .endm
+ .macro ittet, cond
+ .endm
+ .macro ittee, cond
+ .endm
+ .macro itett, cond
+ .endm
+ .macro itete, cond
+ .endm
+ .macro iteet, cond
+ .endm
+ .macro iteee, cond
+ .endm
+#else /* !__ASSEMBLY__ */
+__asm__(
+" .macro it, cond\n"
+" .endm\n"
+" .macro itt, cond\n"
+" .endm\n"
+" .macro ite, cond\n"
+" .endm\n"
+" .macro ittt, cond\n"
+" .endm\n"
+" .macro itte, cond\n"
+" .endm\n"
+" .macro itet, cond\n"
+" .endm\n"
+" .macro itee, cond\n"
+" .endm\n"
+" .macro itttt, cond\n"
+" .endm\n"
+" .macro ittte, cond\n"
+" .endm\n"
+" .macro ittet, cond\n"
+" .endm\n"
+" .macro ittee, cond\n"
+" .endm\n"
+" .macro itett, cond\n"
+" .endm\n"
+" .macro itete, cond\n"
+" .endm\n"
+" .macro iteet, cond\n"
+" .endm\n"
+" .macro iteee, cond\n"
+" .endm\n");
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARM_ASM_UNIFIED */
+
+#endif /* !__ASM_UNIFIED_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ff89d0b3abc5..3213c9382b17 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -8,10 +8,12 @@ ifdef CONFIG_DYNAMIC_FTRACE
CFLAGS_REMOVE_ftrace.o = -pg
endif
+CFLAGS_REMOVE_return_address.o = -pg
+
# Object file lists.
obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \
- process.o ptrace.o setup.o signal.o \
+ process.o ptrace.o return_address.o setup.o signal.o \
sys_arm.o stacktrace.o time.o traps.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
index 99995c2b2312..769abe15cf91 100644
--- a/arch/arm/kernel/crunch.c
+++ b/arch/arm/kernel/crunch.c
@@ -31,7 +31,7 @@ void crunch_task_release(struct thread_info *thread)
static int crunch_enabled(u32 devcfg)
{
- return !!(devcfg & EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE);
+ return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
}
static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
@@ -56,11 +56,16 @@ static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
break;
case THREAD_NOTIFY_SWITCH:
- devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
+ devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
- devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
+ /*
+ * We don't use ep93xx_syscon_swlocked_write() here
+ * because we are on the context switch path and
+ * preemption is already disabled.
+ */
+ devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
+ __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
}
break;
}
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index fc8af43c5000..468425f937dd 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -34,7 +34,7 @@
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
- adrne lr, 1b
+ adrne lr, BSYM(1b)
bne asm_do_IRQ
#ifdef CONFIG_SMP
@@ -46,13 +46,13 @@
*/
test_for_ipi r0, r6, r5, lr
movne r0, sp
- adrne lr, 1b
+ adrne lr, BSYM(1b)
bne do_IPI
#ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr
movne r0, sp
- adrne lr, 1b
+ adrne lr, BSYM(1b)
bne do_local_timer
#endif
#endif
@@ -70,7 +70,10 @@
*/
.macro inv_entry, reason
sub sp, sp, #S_FRAME_SIZE
- stmib sp, {r1 - lr}
+ ARM( stmib sp, {r1 - lr} )
+ THUMB( stmia sp, {r0 - r12} )
+ THUMB( str sp, [sp, #S_SP] )
+ THUMB( str lr, [sp, #S_LR] )
mov r1, #\reason
.endm
@@ -126,17 +129,24 @@ ENDPROC(__und_invalid)
.macro svc_entry, stack_hole=0
UNWIND(.fnstart )
UNWIND(.save {r0 - pc} )
- sub sp, sp, #(S_FRAME_SIZE + \stack_hole)
+ sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+#ifdef CONFIG_THUMB2_KERNEL
+ SPFIX( str r0, [sp] ) @ temporarily saved
+ SPFIX( mov r0, sp )
+ SPFIX( tst r0, #4 ) @ test original stack alignment
+ SPFIX( ldr r0, [sp] ) @ restored
+#else
SPFIX( tst sp, #4 )
- SPFIX( bicne sp, sp, #4 )
- stmib sp, {r1 - r12}
+#endif
+ SPFIX( subeq sp, sp, #4 )
+ stmia sp, {r1 - r12}
ldmia r0, {r1 - r3}
- add r5, sp, #S_SP @ here for interlock avoidance
+ add r5, sp, #S_SP - 4 @ here for interlock avoidance
mov r4, #-1 @ "" "" "" ""
- add r0, sp, #(S_FRAME_SIZE + \stack_hole)
- SPFIX( addne r0, r0, #4 )
- str r1, [sp] @ save the "real" r0 copied
+ add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4)
+ SPFIX( addeq r0, r0, #4 )
+ str r1, [sp, #-4]! @ save the "real" r0 copied
@ from the exception stack
mov r1, lr
@@ -196,9 +206,8 @@ __dabt_svc:
@
@ restore SPSR and restart the instruction
@
- ldr r0, [sp, #S_PSR]
- msr spsr_cxsf, r0
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ ldr r2, [sp, #S_PSR]
+ svc_exit r2 @ return from exception
UNWIND(.fnend )
ENDPROC(__dabt_svc)
@@ -225,13 +234,12 @@ __irq_svc:
tst r0, #_TIF_NEED_RESCHED
blne svc_preempt
#endif
- ldr r0, [sp, #S_PSR] @ irqs are already disabled
- msr spsr_cxsf, r0
+ ldr r4, [sp, #S_PSR] @ irqs are already disabled
#ifdef CONFIG_TRACE_IRQFLAGS
- tst r0, #PSR_I_BIT
+ tst r4, #PSR_I_BIT
bleq trace_hardirqs_on
#endif
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ svc_exit r4 @ return from exception
UNWIND(.fnend )
ENDPROC(__irq_svc)
@@ -266,7 +274,7 @@ __und_svc:
@ r0 - instruction
@
ldr r0, [r2, #-4]
- adr r9, 1f
+ adr r9, BSYM(1f)
bl call_fpe
mov r0, sp @ struct pt_regs *regs
@@ -280,9 +288,8 @@ __und_svc:
@
@ restore SPSR and restart the instruction
@
- ldr lr, [sp, #S_PSR] @ Get SVC cpsr
- msr spsr_cxsf, lr
- ldmia sp, {r0 - pc}^ @ Restore SVC registers
+ ldr r2, [sp, #S_PSR] @ Get SVC cpsr
+ svc_exit r2 @ return from exception
UNWIND(.fnend )
ENDPROC(__und_svc)
@@ -323,9 +330,8 @@ __pabt_svc:
@
@ restore SPSR and restart the instruction
@
- ldr r0, [sp, #S_PSR]
- msr spsr_cxsf, r0
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ ldr r2, [sp, #S_PSR]
+ svc_exit r2 @ return from exception
UNWIND(.fnend )
ENDPROC(__pabt_svc)
@@ -353,7 +359,8 @@ ENDPROC(__pabt_svc)
UNWIND(.fnstart )
UNWIND(.cantunwind ) @ don't unwind the user space
sub sp, sp, #S_FRAME_SIZE
- stmib sp, {r1 - r12}
+ ARM( stmib sp, {r1 - r12} )
+ THUMB( stmia sp, {r0 - r12} )
ldmia r0, {r1 - r3}
add r0, sp, #S_PC @ here for interlock avoidance
@@ -372,7 +379,8 @@ ENDPROC(__pabt_svc)
@ Also, separately save sp_usr and lr_usr
@
stmia r0, {r2 - r4}
- stmdb r0, {sp, lr}^
+ ARM( stmdb r0, {sp, lr}^ )
+ THUMB( store_user_sp_lr r0, r1, S_SP - S_PC )
@
@ Enable the alignment trap while in kernel mode
@@ -427,7 +435,7 @@ __dabt_usr:
@
enable_irq
mov r2, sp
- adr lr, ret_from_exception
+ adr lr, BSYM(ret_from_exception)
b do_DataAbort
UNWIND(.fnend )
ENDPROC(__dabt_usr)
@@ -452,7 +460,9 @@ __irq_usr:
ldr r0, [tsk, #TI_PREEMPT]
str r8, [tsk, #TI_PREEMPT]
teq r0, r7
- strne r0, [r0, -r0]
+ ARM( strne r0, [r0, -r0] )
+ THUMB( movne r0, #0 )
+ THUMB( strne r0, [r0] )
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
@@ -476,9 +486,10 @@ __und_usr:
@
@ r0 - instruction
@
- adr r9, ret_from_exception
- adr lr, __und_usr_unknown
+ adr r9, BSYM(ret_from_exception)
+ adr lr, BSYM(__und_usr_unknown)
tst r3, #PSR_T_BIT @ Thumb mode?
+ itet eq @ explicit IT needed for the 1f label
subeq r4, r2, #4 @ ARM instr at LR - 4
subne r4, r2, #2 @ Thumb instr at LR - 2
1: ldreqt r0, [r4]
@@ -488,7 +499,10 @@ __und_usr:
beq call_fpe
@ Thumb instruction
#if __LINUX_ARM_ARCH__ >= 7
-2: ldrht r5, [r4], #2
+2:
+ ARM( ldrht r5, [r4], #2 )
+ THUMB( ldrht r5, [r4] )
+ THUMB( add r4, r4, #2 )
and r0, r5, #0xf800 @ mask bits 111x x... .... ....
cmp r0, #0xe800 @ 32bit instruction if xx != 0
blo __und_usr_unknown
@@ -577,9 +591,11 @@ call_fpe:
moveq pc, lr
get_thread_info r10 @ get current thread
and r8, r0, #0x00000f00 @ mask out CP number
+ THUMB( lsr r8, r8, #8 )
mov r7, #1
add r6, r10, #TI_USED_CP
- strb r7, [r6, r8, lsr #8] @ set appropriate used_cp[]
+ ARM( strb r7, [r6, r8, lsr #8] ) @ set appropriate used_cp[]
+ THUMB( strb r7, [r6, r8] ) @ set appropriate used_cp[]
#ifdef CONFIG_IWMMXT
@ Test if we need to give access to iWMMXt coprocessors
ldr r5, [r10, #TI_FLAGS]
@@ -587,36 +603,38 @@ call_fpe:
movcss r7, r5, lsr #(TIF_USING_IWMMXT + 1)
bcs iwmmxt_task_enable
#endif
- add pc, pc, r8, lsr #6
- mov r0, r0
-
- mov pc, lr @ CP#0
- b do_fpe @ CP#1 (FPE)
- b do_fpe @ CP#2 (FPE)
- mov pc, lr @ CP#3
+ ARM( add pc, pc, r8, lsr #6 )
+ THUMB( lsl r8, r8, #2 )
+ THUMB( add pc, r8 )
+ nop
+
+ W(mov) pc, lr @ CP#0
+ W(b) do_fpe @ CP#1 (FPE)
+ W(b) do_fpe @ CP#2 (FPE)
+ W(mov) 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
- mov pc, lr @ CP#4
- mov pc, lr @ CP#5
- mov pc, lr @ CP#6
+ W(mov) pc, lr @ CP#4
+ W(mov) pc, lr @ CP#5
+ W(mov) pc, lr @ CP#6
#endif
- mov pc, lr @ CP#7
- mov pc, lr @ CP#8
- mov pc, lr @ CP#9
+ W(mov) pc, lr @ CP#7
+ W(mov) pc, lr @ CP#8
+ W(mov) pc, lr @ CP#9
#ifdef CONFIG_VFP
- b do_vfp @ CP#10 (VFP)
- b do_vfp @ CP#11 (VFP)
+ W(b) do_vfp @ CP#10 (VFP)
+ W(b) do_vfp @ CP#11 (VFP)
#else
- mov pc, lr @ CP#10 (VFP)
- mov pc, lr @ CP#11 (VFP)
+ W(mov) pc, lr @ CP#10 (VFP)
+ W(mov) pc, lr @ CP#11 (VFP)
#endif
- mov pc, lr @ CP#12
- mov pc, lr @ CP#13
- mov pc, lr @ CP#14 (Debug)
- mov pc, lr @ CP#15 (Control)
+ 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)
#ifdef CONFIG_NEON
.align 6
@@ -667,7 +685,7 @@ no_fp: mov pc, lr
__und_usr_unknown:
enable_irq
mov r0, sp
- adr lr, ret_from_exception
+ adr lr, BSYM(ret_from_exception)
b do_undefinstr
ENDPROC(__und_usr_unknown)
@@ -711,7 +729,10 @@ ENTRY(__switch_to)
UNWIND(.cantunwind )
add ip, r1, #TI_CPU_SAVE
ldr r3, [r2, #TI_TP_VALUE]
- stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack
+ ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
+ THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
+ THUMB( str sp, [ip], #4 )
+ THUMB( str lr, [ip], #4 )
#ifdef CONFIG_MMU
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
@@ -736,8 +757,12 @@ ENTRY(__switch_to)
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
+ THUMB( mov ip, r4 )
mov r0, r5
- ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
+ ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
+ THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
+ THUMB( ldr sp, [ip], #4 )
+ THUMB( ldr pc, [ip] )
UNWIND(.fnend )
ENDPROC(__switch_to)
@@ -772,6 +797,7 @@ ENDPROC(__switch_to)
* if your compiled code is not going to use the new instructions for other
* purpose.
*/
+ THUMB( .arm )
.macro usr_ret, reg
#ifdef CONFIG_ARM_THUMB
@@ -1020,6 +1046,7 @@ __kuser_helper_version: @ 0xffff0ffc
.globl __kuser_helper_end
__kuser_helper_end:
+ THUMB( .thumb )
/*
* Vector stubs.
@@ -1054,17 +1081,23 @@ vector_\name:
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
- eor r0, r0, #(\mode ^ SVC_MODE)
+ eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f
+ THUMB( adr r0, 1f )
+ THUMB( ldr lr, [r0, lr, lsl #2] )
mov r0, sp
- ldr lr, [pc, lr, lsl #2]
+ ARM( ldr lr, [pc, lr, lsl #2] )
movs pc, lr @ branch to handler in SVC mode
ENDPROC(vector_\name)
+
+ .align 2
+ @ handler addresses follow this label
+1:
.endm
.globl __stubs_start
@@ -1202,14 +1235,16 @@ __stubs_end:
.globl __vectors_start
__vectors_start:
- swi SYS_ERROR0
- b vector_und + stubs_offset
- ldr pc, .LCvswi + stubs_offset
- b vector_pabt + stubs_offset
- b vector_dabt + stubs_offset
- b vector_addrexcptn + stubs_offset
- b vector_irq + stubs_offset
- b vector_fiq + stubs_offset
+ ARM( swi SYS_ERROR0 )
+ THUMB( svc #0 )
+ THUMB( nop )
+ W(b) vector_und + stubs_offset
+ W(ldr) pc, .LCvswi + stubs_offset
+ W(b) vector_pabt + stubs_offset
+ W(b) vector_dabt + stubs_offset
+ W(b) vector_addrexcptn + stubs_offset
+ W(b) vector_irq + stubs_offset
+ W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 366e5097a41a..f6196cf0fc1d 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -33,14 +33,7 @@ ret_fast_syscall:
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
- @ fast_restore_user_regs
- ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr
- ldr lr, [sp, #S_OFF + S_PC]! @ get pc
- msr spsr_cxsf, r1 @ save in spsr_svc
- ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
- mov r0, r0
- add sp, sp, #S_FRAME_SIZE - S_PC
- movs pc, lr @ return & move spsr_svc into cpsr
+ restore_user_regs fast = 1, offset = S_OFF
UNWIND(.fnend )
/*
@@ -73,14 +66,7 @@ no_work_pending:
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
- @ slow_restore_user_regs
- ldr r1, [sp, #S_PSR] @ get calling cpsr
- ldr lr, [sp, #S_PC]! @ get pc
- msr spsr_cxsf, r1 @ save in spsr_svc
- ldmdb sp, {r0 - lr}^ @ get calling r0 - lr
- mov r0, r0
- add sp, sp, #S_FRAME_SIZE - S_PC
- movs pc, lr @ return & move spsr_svc into cpsr
+ restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user)
/*
@@ -148,7 +134,7 @@ trace:
sub r0, r0, #MCOUNT_INSN_SIZE
mov lr, pc
mov pc, r2
- mov lr, r1 @ restore lr
+ ldr lr, [fp, #-4] @ restore lr
ldmia sp!, {r0-r3, pc}
#endif /* CONFIG_DYNAMIC_FTRACE */
@@ -182,8 +168,10 @@ ftrace_stub:
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
- add r8, sp, #S_PC
- stmdb r8, {sp, lr}^ @ Calling sp, lr
+ ARM( add r8, sp, #S_PC )
+ ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
+ THUMB( mov r8, sp )
+ THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
@@ -272,7 +260,7 @@ ENTRY(vector_swi)
bne __sys_trace
cmp scno, #NR_syscalls @ check upper syscall limit
- adr lr, ret_fast_syscall @ return address
+ adr lr, BSYM(ret_fast_syscall) @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
add r1, sp, #S_OFF
@@ -293,7 +281,7 @@ __sys_trace:
mov r0, #0 @ trace entry [IP = 0]
bl syscall_trace
- adr lr, __sys_trace_return @ return address
+ adr lr, BSYM(__sys_trace_return) @ return address
mov scno, r0 @ syscall number (possibly new)
add r1, sp, #S_R0 + S_OFF @ pointer to regs
cmp scno, #NR_syscalls @ check upper syscall limit
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 87ab4e157997..a4eaf4f920c5 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -36,11 +36,6 @@
#endif
.endm
- .macro get_thread_info, rd
- mov \rd, sp, lsr #13
- mov \rd, \rd, lsl #13
- .endm
-
.macro alignment_trap, rtemp
#ifdef CONFIG_ALIGNMENT_TRAP
ldr \rtemp, .LCcralign
@@ -49,6 +44,93 @@
#endif
.endm
+ @
+ @ Store/load the USER SP and LR registers by switching to the SYS
+ @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
+ @ available. Should only be called from SVC mode
+ @
+ .macro store_user_sp_lr, rd, rtemp, offset = 0
+ mrs \rtemp, cpsr
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch to the SYS mode
+
+ str sp, [\rd, #\offset] @ save sp_usr
+ str lr, [\rd, #\offset + 4] @ save lr_usr
+
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch back to the SVC mode
+ .endm
+
+ .macro load_user_sp_lr, rd, rtemp, offset = 0
+ mrs \rtemp, cpsr
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch to the SYS mode
+
+ ldr sp, [\rd, #\offset] @ load sp_usr
+ ldr lr, [\rd, #\offset + 4] @ load lr_usr
+
+ eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
+ msr cpsr_c, \rtemp @ switch back to the SVC mode
+ .endm
+
+#ifndef CONFIG_THUMB2_KERNEL
+ .macro svc_exit, rpsr
+ msr spsr_cxsf, \rpsr
+ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
+ .endm
+
+ .macro restore_user_regs, fast = 0, offset = 0
+ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
+ ldr lr, [sp, #\offset + S_PC]! @ get pc
+ msr spsr_cxsf, r1 @ save in spsr_svc
+ .if \fast
+ ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
+ .else
+ ldmdb sp, {r0 - lr}^ @ get calling r0 - lr
+ .endif
+ add sp, sp, #S_FRAME_SIZE - S_PC
+ movs pc, lr @ return & move spsr_svc into cpsr
+ .endm
+
+ .macro get_thread_info, rd
+ mov \rd, sp, lsr #13
+ mov \rd, \rd, lsl #13
+ .endm
+#else /* CONFIG_THUMB2_KERNEL */
+ .macro svc_exit, rpsr
+ ldr r0, [sp, #S_SP] @ top of the stack
+ ldr r1, [sp, #S_PC] @ return address
+ tst r0, #4 @ orig stack 8-byte aligned?
+ stmdb r0, {r1, \rpsr} @ rfe context
+ ldmia sp, {r0 - r12}
+ ldr lr, [sp, #S_LR]
+ addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned
+ addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned
+ rfeia sp!
+ .endm
+
+ .macro restore_user_regs, fast = 0, offset = 0
+ mov r2, sp
+ load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr
+ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr
+ ldr lr, [sp, #\offset + S_PC] @ get pc
+ add sp, sp, #\offset + S_SP
+ msr spsr_cxsf, r1 @ save in spsr_svc
+ .if \fast
+ ldmdb sp, {r1 - r12} @ get calling r1 - r12
+ .else
+ ldmdb sp, {r0 - r12} @ get calling r0 - r12
+ .endif
+ add sp, sp, #S_FRAME_SIZE - S_SP
+ movs pc, lr @ return & move spsr_svc into cpsr
+ .endm
+
+ .macro get_thread_info, rd
+ mov \rd, sp
+ lsr \rd, \rd, #13
+ mov \rd, \rd, lsl #13
+ .endm
+#endif /* !CONFIG_THUMB2_KERNEL */
/*
* These are the registers used in the syscall handler, and allow us to
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 991952c644d1..93ad576b2d74 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -14,6 +14,7 @@
#define ATAG_CORE 0x54410001
#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
+ .align 2
.type __switch_data, %object
__switch_data:
.long __mmap_switched
@@ -51,7 +52,9 @@ __mmap_switched:
strcc fp, [r6],#4
bcc 1b
- ldmia r3, {r4, r5, r6, r7, sp}
+ ARM( ldmia r3, {r4, r5, r6, r7, sp})
+ THUMB( ldmia r3, {r4, r5, r6, r7} )
+ THUMB( ldr sp, [r3, #16] )
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
str r2, [r6] @ Save atags pointer
@@ -155,7 +158,8 @@ ENDPROC(__error)
*/
__lookup_processor_type:
adr r3, 3f
- ldmda r3, {r5 - r7}
+ ldmia r3, {r5 - r7}
+ add r3, r3, #8
sub r3, r3, r7 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
@@ -185,9 +189,10 @@ ENDPROC(lookup_processor_type)
* Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
* more information about the __proc_info and __arch_info structures.
*/
- .long __proc_info_begin
+ .align 2
+3: .long __proc_info_begin
.long __proc_info_end
-3: .long .
+4: .long .
.long __arch_info_begin
.long __arch_info_end
@@ -203,7 +208,7 @@ ENDPROC(lookup_processor_type)
* r5 = mach_info pointer in physical address space
*/
__lookup_machine_type:
- adr r3, 3b
+ adr r3, 4b
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index cc87e1765ed2..e5dfc2895e24 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -34,7 +34,7 @@
*/
.section ".text.head", "ax"
ENTRY(stext)
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
#ifndef CONFIG_CPU_CP15
ldr r9, =CONFIG_PROCESSOR_ID
@@ -50,8 +50,10 @@ ENTRY(stext)
ldr r13, __switch_data @ address to jump to after
@ the initialization is done
- adr lr, __after_proc_init @ return (PIC) address
- add pc, r10, #PROCINFO_INITFUNC
+ adr lr, BSYM(__after_proc_init) @ return (PIC) address
+ ARM( add pc, r10, #PROCINFO_INITFUNC )
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(stext)
/*
@@ -59,7 +61,10 @@ ENDPROC(stext)
*/
__after_proc_init:
#ifdef CONFIG_CPU_CP15
- mrc p15, 0, r0, c1, c0, 0 @ read control reg
+ /*
+ * CP15 system control register value returned in r0 from
+ * the CPU init function.
+ */
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
#else
@@ -82,7 +87,8 @@ __after_proc_init:
mcr p15, 0, r0, c1, c0, 0 @ write control reg
#endif /* CONFIG_CPU_CP15 */
- mov pc, r13 @ clear the BSS and jump
+ mov r3, r13
+ mov pc, r3 @ clear the BSS and jump
@ to start_kernel
ENDPROC(__after_proc_init)
.ltorg
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 21e17dc94cb5..38ccbe1d3b2c 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -76,7 +76,7 @@
*/
.section ".text.head", "ax"
ENTRY(stext)
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
@@ -97,8 +97,10 @@ ENTRY(stext)
*/
ldr r13, __switch_data @ address to jump to after
@ mmu has been enabled
- adr lr, __enable_mmu @ return (PIC) address
- add pc, r10, #PROCINFO_INITFUNC
+ adr lr, BSYM(__enable_mmu) @ return (PIC) address
+ ARM( add pc, r10, #PROCINFO_INITFUNC )
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(stext)
#if defined(CONFIG_SMP)
@@ -110,7 +112,7 @@ ENTRY(secondary_startup)
* the processor type - there is no need to check the machine type
* as it has already been validated by the primary processor.
*/
- msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type
movs r10, r5 @ invalid processor?
@@ -121,12 +123,15 @@ ENTRY(secondary_startup)
* Use the page tables supplied from __cpu_up.
*/
adr r4, __secondary_data
- ldmia r4, {r5, r7, r13} @ address to jump to after
+ ldmia r4, {r5, r7, r12} @ address to jump to after
sub r4, r4, r5 @ mmu has been enabled
ldr r4, [r7, r4] @ get secondary_data.pgdir
- adr lr, __enable_mmu @ return address
- add pc, r10, #PROCINFO_INITFUNC @ initialise processor
- @ (return control reg)
+ adr lr, BSYM(__enable_mmu) @ return address
+ mov r13, r12 @ __secondary_switched address
+ ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor
+ @ (return control reg)
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
ENDPROC(secondary_startup)
/*
@@ -193,8 +198,8 @@ __turn_mmu_on:
mcr p15, 0, r0, c1, c0, 0 @ write control reg
mrc p15, 0, r3, c0, c0, 0 @ read id reg
mov r3, r3
- mov r3, r3
- mov pc, r13
+ mov r3, r13
+ mov pc, r3
ENDPROC(__turn_mmu_on)
@@ -235,7 +240,8 @@ __create_page_tables:
* will be removed by paging_init(). We use our current program
* counter to determine corresponding section base address.
*/
- mov r6, pc, lsr #20 @ start of kernel section
+ mov r6, pc
+ mov r6, r6, lsr #20 @ start of kernel section
orr r3, r7, r6, lsl #20 @ flags + kernel base
str r3, [r4, r6, lsl #2] @ identity mapping
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index bac03c81489d..f28c5e9c51ea 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -102,6 +102,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
unsigned long loc;
Elf32_Sym *sym;
s32 offset;
+ u32 upper, lower, sign, j1, j2;
offset = ELF32_R_SYM(rel->r_info);
if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
@@ -184,6 +185,58 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
(offset & 0x0fff);
break;
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ upper = *(u16 *)loc;
+ lower = *(u16 *)(loc + 2);
+
+ /*
+ * 25 bit signed address range (Thumb-2 BL and B.W
+ * instructions):
+ * S:I1:I2:imm10:imm11:0
+ * where:
+ * S = upper[10] = offset[24]
+ * I1 = ~(J1 ^ S) = offset[23]
+ * I2 = ~(J2 ^ S) = offset[22]
+ * imm10 = upper[9:0] = offset[21:12]
+ * imm11 = lower[10:0] = offset[11:1]
+ * J1 = lower[13]
+ * J2 = lower[11]
+ */
+ sign = (upper >> 10) & 1;
+ j1 = (lower >> 13) & 1;
+ j2 = (lower >> 11) & 1;
+ offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
+ ((~(j2 ^ sign) & 1) << 22) |
+ ((upper & 0x03ff) << 12) |
+ ((lower & 0x07ff) << 1);
+ if (offset & 0x01000000)
+ offset -= 0x02000000;
+ offset += sym->st_value - loc;
+
+ /* only Thumb addresses allowed (no interworking) */
+ if (!(offset & 1) ||
+ offset <= (s32)0xff000000 ||
+ offset >= (s32)0x01000000) {
+ printk(KERN_ERR
+ "%s: relocation out of range, section "
+ "%d reloc %d sym '%s'\n", module->name,
+ relindex, i, strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+
+ sign = (offset >> 24) & 1;
+ j1 = sign ^ (~(offset >> 23) & 1);
+ j2 = sign ^ (~(offset >> 22) & 1);
+ *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) |
+ ((offset >> 12) & 0x03ff));
+ *(u16 *)(loc + 2) = (u16)((lower & 0xd000) |
+ (j1 << 13) | (j2 << 11) |
+ ((offset >> 1) & 0x07ff));
+ upper = *(u16 *)loc;
+ lower = *(u16 *)(loc + 2);
+ break;
+
default:
printk(KERN_ERR "%s: unknown relocation: %u\n",
module->name, ELF32_R_TYPE(rel->r_info));
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 39196dff478c..790fbee92ec5 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -388,7 +388,7 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
regs.ARM_r2 = (unsigned long)fn;
regs.ARM_r3 = (unsigned long)kernel_thread_exit;
regs.ARM_pc = (unsigned long)kernel_thread_helper;
- regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE;
+ regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 89882a1d0187..a2ea3854cb3c 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -521,7 +521,13 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
return -EIO;
tmp = 0;
- if (off < sizeof(struct pt_regs))
+ if (off == PT_TEXT_ADDR)
+ tmp = tsk->mm->start_code;
+ else if (off == PT_DATA_ADDR)
+ tmp = tsk->mm->start_data;
+ else if (off == PT_TEXT_END_ADDR)
+ tmp = tsk->mm->end_code;
+ else if (off < sizeof(struct pt_regs))
tmp = get_user_reg(tsk, off >> 2);
return put_user(tmp, ret);
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c
new file mode 100644
index 000000000000..df246da4ceca
--- /dev/null
+++ b/arch/arm/kernel/return_address.c
@@ -0,0 +1,71 @@
+/*
+ * arch/arm/kernel/return_address.c
+ *
+ * Copyright (C) 2009 Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ * for Pengutronix
+ *
+ * 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>
+
+#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
+#include <linux/sched.h>
+
+#include <asm/stacktrace.h>
+
+struct return_address_data {
+ unsigned int level;
+ void *addr;
+};
+
+static int save_return_addr(struct stackframe *frame, void *d)
+{
+ struct return_address_data *data = d;
+
+ if (!data->level) {
+ data->addr = (void *)frame->lr;
+
+ return 1;
+ } else {
+ --data->level;
+ return 0;
+ }
+}
+
+void *return_address(unsigned int level)
+{
+ struct return_address_data data;
+ struct stackframe frame;
+ register unsigned long current_sp asm ("sp");
+
+ data.level = level + 1;
+
+ frame.fp = (unsigned long)__builtin_frame_address(0);
+ frame.sp = current_sp;
+ frame.lr = (unsigned long)__builtin_return_address(0);
+ frame.pc = (unsigned long)return_address;
+
+ walk_stackframe(&frame, save_return_addr, &data);
+
+ if (!data.level)
+ return data.addr;
+ else
+ return NULL;
+}
+
+#else /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
+
+#if defined(CONFIG_ARM_UNWIND)
+#warning "TODO: return_address should use unwind tables"
+#endif
+
+void *return_address(unsigned int level)
+{
+ return NULL;
+}
+
+#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) / else */
+
+EXPORT_SYMBOL_GPL(return_address);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index bc5e4128f9f3..d4d4f77c91b2 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/fs.h>
+#include <asm/unified.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/elf.h>
@@ -327,25 +328,38 @@ void cpu_init(void)
}
/*
+ * Define the placement constraint for the inline asm directive below.
+ * In Thumb-2, msr with an immediate value is not allowed.
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+#define PLC "r"
+#else
+#define PLC "I"
+#endif
+
+ /*
* setup stacks for re-entrant exception handlers
*/
__asm__ (
"msr cpsr_c, %1\n\t"
- "add sp, %0, %2\n\t"
+ "add r14, %0, %2\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %3\n\t"
- "add sp, %0, %4\n\t"
+ "add r14, %0, %4\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %5\n\t"
- "add sp, %0, %6\n\t"
+ "add r14, %0, %6\n\t"
+ "mov sp, r14\n\t"
"msr cpsr_c, %7"
:
: "r" (stk),
- "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
"I" (offsetof(struct stack, irq[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
"I" (offsetof(struct stack, abt[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+ PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+ PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index de885fd256c5..e0d32770bb3d 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -189,7 +189,7 @@ int __cpuexit __cpu_disable(void)
read_lock(&tasklist_lock);
for_each_process(p) {
if (p->mm)
- cpu_clear(cpu, p->mm->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(p->mm));
}
read_unlock(&tasklist_lock);
@@ -257,7 +257,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count);
current->active_mm = mm;
- cpu_set(cpu, mm->cpu_vm_mask);
+ cpumask_set_cpu(cpu, mm_cpumask(mm));
cpu_switch_mm(mm->pgd, mm);
enter_lazy_tlb(mm, current);
local_flush_tlb_all();
@@ -643,7 +643,7 @@ void flush_tlb_all(void)
void flush_tlb_mm(struct mm_struct *mm)
{
if (tlb_ops_need_broadcast())
- on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
+ on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm));
else
local_flush_tlb_mm(mm);
}
@@ -654,7 +654,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
struct tlb_args ta;
ta.ta_vma = vma;
ta.ta_start = uaddr;
- on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+ on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm));
} else
local_flush_tlb_page(vma, uaddr);
}
@@ -677,7 +677,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
ta.ta_vma = vma;
ta.ta_start = start;
ta.ta_end = end;
- on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+ on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm));
} else
local_flush_tlb_range(vma, start, end);
}
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 9f444e5cc165..20b7411e47fd 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -21,7 +21,7 @@
* Note that with framepointer enabled, even the leaf functions have the same
* prologue and epilogue, therefore we can ignore the LR value in this case.
*/
-int unwind_frame(struct stackframe *frame)
+int notrace unwind_frame(struct stackframe *frame)
{
unsigned long high, low;
unsigned long fp = frame->fp;
@@ -43,7 +43,7 @@ int unwind_frame(struct stackframe *frame)
}
#endif
-void walk_stackframe(struct stackframe *frame,
+void notrace walk_stackframe(struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data)
{
while (1) {
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index dd56e11f339a..39baf1128bfa 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -62,7 +62,11 @@ struct unwind_ctrl_block {
};
enum regs {
+#ifdef CONFIG_THUMB2_KERNEL
+ FP = 7,
+#else
FP = 11,
+#endif
SP = 13,
LR = 14,
PC = 15
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 69371028a202..5cc4812c9763 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -83,6 +83,7 @@ SECTIONS
EXIT_TEXT
EXIT_DATA
*(.exitcall.exit)
+ *(.discard)
*(.ARM.exidx.exit.text)
*(.ARM.extab.exit.text)
#ifndef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/lib/ashldi3.S b/arch/arm/lib/ashldi3.S
index 1154d924080b..638deb13da1c 100644
--- a/arch/arm/lib/ashldi3.S
+++ b/arch/arm/lib/ashldi3.S
@@ -43,7 +43,9 @@ ENTRY(__aeabi_llsl)
rsb ip, r2, #32
movmi ah, ah, lsl r2
movpl ah, al, lsl r3
- orrmi ah, ah, al, lsr ip
+ ARM( orrmi ah, ah, al, lsr ip )
+ THUMB( lsrmi r3, al, ip )
+ THUMB( orrmi ah, ah, r3 )
mov al, al, lsl r2
mov pc, lr
diff --git a/arch/arm/lib/ashrdi3.S b/arch/arm/lib/ashrdi3.S
index 9f8b35572f8c..015e8aa5a1d1 100644
--- a/arch/arm/lib/ashrdi3.S
+++ b/arch/arm/lib/ashrdi3.S
@@ -43,7 +43,9 @@ ENTRY(__aeabi_lasr)
rsb ip, r2, #32
movmi al, al, lsr r2
movpl al, ah, asr r3
- orrmi al, al, ah, lsl ip
+ ARM( orrmi al, al, ah, lsl ip )
+ THUMB( lslmi r3, ah, ip )
+ THUMB( orrmi al, al, r3 )
mov ah, ah, asr r2
mov pc, lr
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index b0951d0e8b2c..aaf7220d9e30 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -38,7 +38,9 @@ ENDPROC(c_backtrace)
beq no_frame @ we have no stack frames
tst r1, #0x10 @ 26 or 32-bit mode?
- moveq mask, #0xfc000003 @ mask for 26-bit
+ ARM( moveq mask, #0xfc000003 )
+ THUMB( moveq mask, #0xfc000000 )
+ THUMB( orreq mask, #0x03 )
movne mask, #0 @ mask for 32-bit
1: stmfd sp!, {pc} @ calculate offset of PC stored
@@ -126,7 +128,9 @@ ENDPROC(c_backtrace)
mov reg, #10
mov r7, #0
1: mov r3, #1
- tst instr, r3, lsl reg
+ ARM( tst instr, r3, lsl reg )
+ THUMB( lsl r3, reg )
+ THUMB( tst instr, r3 )
beq 2f
add r7, r7, #1
teq r7, #6
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S
index 844f56785ebc..1279abd8b886 100644
--- a/arch/arm/lib/clear_user.S
+++ b/arch/arm/lib/clear_user.S
@@ -27,21 +27,20 @@ WEAK(__clear_user)
ands ip, r0, #3
beq 1f
cmp ip, #2
-USER( strbt r2, [r0], #1)
-USER( strlebt r2, [r0], #1)
-USER( strltbt r2, [r0], #1)
+ strusr r2, r0, 1
+ strusr r2, r0, 1, le
+ strusr r2, r0, 1, lt
rsb ip, ip, #4
sub r1, r1, ip @ 7 6 5 4 3 2 1
1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
-USER( strplt r2, [r0], #4)
-USER( strplt r2, [r0], #4)
+ strusr r2, r0, 4, pl, rept=2
bpl 1b
adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3
-USER( strplt r2, [r0], #4)
+ strusr r2, r0, 4, pl
2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
-USER( strnebt r2, [r0], #1)
-USER( strnebt r2, [r0], #1)
+ strusr r2, r0, 1, ne, rept=2
tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1
+ it ne @ explicit IT needed for the label
USER( strnebt r2, [r0])
mov r0, #0
ldmfd sp!, {r1, pc}
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index 56799a165cc4..e4fe124acedc 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -33,11 +33,15 @@
* Number of bytes NOT copied.
*/
+#ifndef CONFIG_THUMB2_KERNEL
+#define LDR1W_SHIFT 0
+#else
+#define LDR1W_SHIFT 1
+#endif
+#define STR1W_SHIFT 0
+
.macro ldr1w ptr reg abort
-100: ldrt \reg, [\ptr], #4
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ ldrusr \reg, \ptr, 4, abort=\abort
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -53,14 +57,11 @@
.endm
.macro ldr1b ptr reg cond=al abort
-100: ldr\cond\()bt \reg, [\ptr], #1
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ ldrusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro str1w ptr reg abort
- str \reg, [\ptr], #4
+ W(str) \reg, [\ptr], #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S
index 139cce646055..805e3f8fb007 100644
--- a/arch/arm/lib/copy_template.S
+++ b/arch/arm/lib/copy_template.S
@@ -57,6 +57,13 @@
*
* Restore registers with the values previously saved with the
* 'preserv' macro. Called upon code termination.
+ *
+ * LDR1W_SHIFT
+ * STR1W_SHIFT
+ *
+ * Correction to be applied to the "ip" register when branching into
+ * the ldr1w or str1w instructions (some of these macros may expand to
+ * than one 32bit instruction in Thumb-2)
*/
@@ -99,9 +106,15 @@
5: ands ip, r2, #28
rsb ip, ip, #32
+#if LDR1W_SHIFT > 0
+ lsl ip, ip, #LDR1W_SHIFT
+#endif
addne pc, pc, ip @ C is always clear here
b 7f
-6: nop
+6:
+ .rept (1 << LDR1W_SHIFT)
+ W(nop)
+ .endr
ldr1w r1, r3, abort=20f
ldr1w r1, r4, abort=20f
ldr1w r1, r5, abort=20f
@@ -110,9 +123,16 @@
ldr1w r1, r8, abort=20f
ldr1w r1, lr, abort=20f
+#if LDR1W_SHIFT < STR1W_SHIFT
+ lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
+#elif LDR1W_SHIFT > STR1W_SHIFT
+ lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
+#endif
add pc, pc, ip
nop
- nop
+ .rept (1 << STR1W_SHIFT)
+ W(nop)
+ .endr
str1w r0, r3, abort=20f
str1w r0, r4, abort=20f
str1w r0, r5, abort=20f
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index 878820f0a320..1a71e1584442 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -33,8 +33,15 @@
* Number of bytes NOT copied.
*/
+#define LDR1W_SHIFT 0
+#ifndef CONFIG_THUMB2_KERNEL
+#define STR1W_SHIFT 0
+#else
+#define STR1W_SHIFT 1
+#endif
+
.macro ldr1w ptr reg abort
- ldr \reg, [\ptr], #4
+ W(ldr) \reg, [\ptr], #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -50,10 +57,7 @@
.endm
.macro str1w ptr reg abort
-100: strt \reg, [\ptr], #4
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ strusr \reg, \ptr, 4, abort=\abort
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
@@ -68,10 +72,7 @@
.endm
.macro str1b ptr reg cond=al abort
-100: str\cond\()bt \reg, [\ptr], #1
- .section __ex_table, "a"
- .long 100b, \abort
- .previous
+ strusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro enter reg1 reg2
diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S
index 14677fb4b0c4..fd0e9dcd9fdc 100644
--- a/arch/arm/lib/csumpartialcopyuser.S
+++ b/arch/arm/lib/csumpartialcopyuser.S
@@ -26,50 +26,28 @@
.endm
.macro load1b, reg1
-9999: ldrbt \reg1, [r0], $1
- .section __ex_table, "a"
- .align 3
- .long 9999b, 6001f
- .previous
+ ldrusr \reg1, r0, 1
.endm
.macro load2b, reg1, reg2
-9999: ldrbt \reg1, [r0], $1
-9998: ldrbt \reg2, [r0], $1
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .previous
+ ldrusr \reg1, r0, 1
+ ldrusr \reg2, r0, 1
.endm
.macro load1l, reg1
-9999: ldrt \reg1, [r0], $4
- .section __ex_table, "a"
- .align 3
- .long 9999b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
.endm
.macro load2l, reg1, reg2
-9999: ldrt \reg1, [r0], $4
-9998: ldrt \reg2, [r0], $4
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
+ ldrusr \reg2, r0, 4
.endm
.macro load4l, reg1, reg2, reg3, reg4
-9999: ldrt \reg1, [r0], $4
-9998: ldrt \reg2, [r0], $4
-9997: ldrt \reg3, [r0], $4
-9996: ldrt \reg4, [r0], $4
- .section __ex_table, "a"
- .long 9999b, 6001f
- .long 9998b, 6001f
- .long 9997b, 6001f
- .long 9996b, 6001f
- .previous
+ ldrusr \reg1, r0, 4
+ ldrusr \reg2, r0, 4
+ ldrusr \reg3, r0, 4
+ ldrusr \reg4, r0, 4
.endm
/*
@@ -92,14 +70,14 @@
*/
.section .fixup,"ax"
.align 4
-6001: mov r4, #-EFAULT
+9001: mov r4, #-EFAULT
ldr r5, [fp, #4] @ *err_ptr
str r4, [r5]
ldmia sp, {r1, r2} @ retrieve dst, len
add r2, r2, r1
mov r0, #0 @ zero the buffer
-6002: teq r2, r1
+9002: teq r2, r1
strneb r0, [r1], #1
- bne 6002b
+ bne 9002b
load_regs
.previous
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index 1425e789ba86..faa7748142da 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -177,7 +177,9 @@ ENTRY(__do_div64)
mov yh, xh, lsr ip
mov yl, xl, lsr ip
rsb ip, ip, #32
- orr yl, yl, xh, lsl ip
+ ARM( orr yl, yl, xh, lsl ip )
+ THUMB( lsl xh, xh, ip )
+ THUMB( orr yl, yl, xh )
mov xh, xl, lsl ip
mov xh, xh, lsr ip
mov pc, lr
diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S
index 8c4defc4f3c4..1e4cbd4e7be9 100644
--- a/arch/arm/lib/findbit.S
+++ b/arch/arm/lib/findbit.S
@@ -25,7 +25,10 @@ ENTRY(_find_first_zero_bit_le)
teq r1, #0
beq 3f
mov r2, #0
-1: ldrb r3, [r0, r2, lsr #3]
+1:
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eors r3, r3, #0xff @ invert bits
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -44,7 +47,9 @@ ENTRY(_find_next_zero_bit_le)
beq 3b
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
- ldrb r3, [r0, r2, lsr #3]
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eor r3, r3, #0xff @ now looking for a 1 bit
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
@@ -61,7 +66,10 @@ ENTRY(_find_first_bit_le)
teq r1, #0
beq 3f
mov r2, #0
-1: ldrb r3, [r0, r2, lsr #3]
+1:
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -80,7 +88,9 @@ ENTRY(_find_next_bit_le)
beq 3b
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
- ldrb r3, [r0, r2, lsr #3]
+ ARM( ldrb r3, [r0, r2, lsr #3] )
+ THUMB( lsr r3, r2, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
orr r2, r2, #7 @ if zero, then no bits here
@@ -95,7 +105,9 @@ ENTRY(_find_first_zero_bit_be)
beq 3f
mov r2, #0
1: eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eors r3, r3, #0xff @ invert bits
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -111,7 +123,9 @@ ENTRY(_find_next_zero_bit_be)
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
eor r3, r3, #0xff @ now looking for a 1 bit
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
@@ -125,7 +139,9 @@ ENTRY(_find_first_bit_be)
beq 3f
mov r2, #0
1: eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3
bne .L_found @ any now set - found zero bit
add r2, r2, #8 @ next bit pointer
@@ -141,7 +157,9 @@ ENTRY(_find_next_bit_be)
ands ip, r2, #7
beq 1b @ If new byte, goto old routine
eor r3, r2, #0x18 @ big endian byte ordering
- ldrb r3, [r0, r3, lsr #3]
+ ARM( ldrb r3, [r0, r3, lsr #3] )
+ THUMB( lsr r3, #3 )
+ THUMB( ldrb r3, [r0, r3] )
movs r3, r3, lsr ip @ shift off unused bits
bne .L_found
orr r2, r2, #7 @ if zero, then no bits here
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 6763088b7607..a1814d927122 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -36,8 +36,13 @@ ENTRY(__get_user_1)
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
+#ifdef CONFIG_THUMB2_KERNEL
+2: ldrbt r2, [r0]
+3: ldrbt r3, [r0, #1]
+#else
2: ldrbt r2, [r0], #1
3: ldrbt r3, [r0]
+#endif
#ifndef __ARMEB__
orr r2, r2, r3, lsl #8
#else
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S
index d6585612c86b..ff4f71b579ee 100644
--- a/arch/arm/lib/io-writesw-armv4.S
+++ b/arch/arm/lib/io-writesw-armv4.S
@@ -75,7 +75,10 @@ ENTRY(__raw_writesw)
#endif
.Loutsw_noalign:
- ldr r3, [r1, -r3]!
+ ARM( ldr r3, [r1, -r3]! )
+ THUMB( rsb r3, r3, #0 )
+ THUMB( ldr r3, [r1, r3] )
+ THUMB( sub r1, r3 )
subcs r2, r2, #1
bcs 2f
subs r2, r2, #2
diff --git a/arch/arm/lib/lshrdi3.S b/arch/arm/lib/lshrdi3.S
index 99ea338bf87c..f83d449141f7 100644
--- a/arch/arm/lib/lshrdi3.S
+++ b/arch/arm/lib/lshrdi3.S
@@ -43,7 +43,9 @@ ENTRY(__aeabi_llsr)
rsb ip, r2, #32
movmi al, al, lsr r2
movpl al, ah, lsr r3
- orrmi al, al, ah, lsl ip
+ ARM( orrmi al, al, ah, lsl ip )
+ THUMB( lslmi r3, ah, ip )
+ THUMB( orrmi al, al, r3 )
mov ah, ah, lsr r2
mov pc, lr
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S
index e0d002641d3f..a9b9e2287a09 100644
--- a/arch/arm/lib/memcpy.S
+++ b/arch/arm/lib/memcpy.S
@@ -13,8 +13,11 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#define LDR1W_SHIFT 0
+#define STR1W_SHIFT 0
+
.macro ldr1w ptr reg abort
- ldr \reg, [\ptr], #4
+ W(ldr) \reg, [\ptr], #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
@@ -30,7 +33,7 @@
.endm
.macro str1w ptr reg abort
- str \reg, [\ptr], #4
+ W(str) \reg, [\ptr], #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S
index 12549187088c..5025c863713d 100644
--- a/arch/arm/lib/memmove.S
+++ b/arch/arm/lib/memmove.S
@@ -75,24 +75,24 @@ ENTRY(memmove)
addne pc, pc, ip @ C is always clear here
b 7f
6: nop
- ldr r3, [r1, #-4]!
- ldr r4, [r1, #-4]!
- ldr r5, [r1, #-4]!
- ldr r6, [r1, #-4]!
- ldr r7, [r1, #-4]!
- ldr r8, [r1, #-4]!
- ldr lr, [r1, #-4]!
+ W(ldr) r3, [r1, #-4]!
+ W(ldr) r4, [r1, #-4]!
+ W(ldr) r5, [r1, #-4]!
+ W(ldr) r6, [r1, #-4]!
+ W(ldr) r7, [r1, #-4]!
+ W(ldr) r8, [r1, #-4]!
+ W(ldr) lr, [r1, #-4]!
add pc, pc, ip
nop
nop
- str r3, [r0, #-4]!
- str r4, [r0, #-4]!
- str r5, [r0, #-4]!
- str r6, [r0, #-4]!
- str r7, [r0, #-4]!
- str r8, [r0, #-4]!
- str lr, [r0, #-4]!
+ W(str) r3, [r0, #-4]!
+ W(str) r4, [r0, #-4]!
+ W(str) r5, [r0, #-4]!
+ W(str) r6, [r0, #-4]!
+ W(str) r7, [r0, #-4]!
+ W(str) r8, [r0, #-4]!
+ W(str) lr, [r0, #-4]!
CALGN( bcs 2b )
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 864f3c1c4f18..02fedbf07c0d 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -37,6 +37,15 @@ ENDPROC(__put_user_1)
ENTRY(__put_user_2)
mov ip, r2, lsr #8
+#ifdef CONFIG_THUMB2_KERNEL
+#ifndef __ARMEB__
+2: strbt r2, [r0]
+3: strbt ip, [r0, #1]
+#else
+2: strbt ip, [r0]
+3: strbt r2, [r0, #1]
+#endif
+#else /* !CONFIG_THUMB2_KERNEL */
#ifndef __ARMEB__
2: strbt r2, [r0], #1
3: strbt ip, [r0]
@@ -44,6 +53,7 @@ ENTRY(__put_user_2)
2: strbt ip, [r0], #1
3: strbt r2, [r0]
#endif
+#endif /* CONFIG_THUMB2_KERNEL */
mov r0, #0
mov pc, lr
ENDPROC(__put_user_2)
@@ -55,8 +65,13 @@ ENTRY(__put_user_4)
ENDPROC(__put_user_4)
ENTRY(__put_user_8)
+#ifdef CONFIG_THUMB2_KERNEL
+5: strt r2, [r0]
+6: strt r3, [r0, #4]
+#else
5: strt r2, [r0], #4
6: strt r3, [r0]
+#endif
mov r0, #0
mov pc, lr
ENDPROC(__put_user_8)
diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S
index a16fb208c841..09b548cac1a4 100644
--- a/arch/arm/lib/sha1.S
+++ b/arch/arm/lib/sha1.S
@@ -187,6 +187,7 @@ ENTRY(sha_transform)
ENDPROC(sha_transform)
+ .align 2
.L_sha_K:
.word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
@@ -195,6 +196,7 @@ ENDPROC(sha_transform)
* void sha_init(__u32 *buf)
*/
+ .align 2
.L_sha_initial_digest:
.word 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
diff --git a/arch/arm/lib/strncpy_from_user.S b/arch/arm/lib/strncpy_from_user.S
index 330373c26dd9..1c9814f346c6 100644
--- a/arch/arm/lib/strncpy_from_user.S
+++ b/arch/arm/lib/strncpy_from_user.S
@@ -23,7 +23,7 @@
ENTRY(__strncpy_from_user)
mov ip, r1
1: subs r2, r2, #1
-USER( ldrplbt r3, [r1], #1)
+ ldrusr r3, r1, 1, pl
bmi 2f
strb r3, [r0], #1
teq r3, #0
diff --git a/arch/arm/lib/strnlen_user.S b/arch/arm/lib/strnlen_user.S
index 90bb9d020836..7855b2906659 100644
--- a/arch/arm/lib/strnlen_user.S
+++ b/arch/arm/lib/strnlen_user.S
@@ -23,7 +23,7 @@
ENTRY(__strnlen_user)
mov r2, r0
1:
-USER( ldrbt r3, [r0], #1)
+ ldrusr r3, r0, 1
teq r3, #0
beq 2f
subs r1, r1, #1
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 323b47f2b52f..a24d824c428b 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -23,6 +23,12 @@ config ARCH_AT91SAM9261
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+config ARCH_AT91SAM9G10
+ bool "AT91SAM9G10"
+ select CPU_ARM926T
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+
config ARCH_AT91SAM9263
bool "AT91SAM9263"
select CPU_ARM926T
@@ -41,6 +47,12 @@ config ARCH_AT91SAM9G20
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+config ARCH_AT91SAM9G45
+ bool "AT91SAM9G45"
+ select CPU_ARM926T
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+
config ARCH_AT91CAP9
bool "AT91CAP9"
select CPU_ARM926T
@@ -144,6 +156,13 @@ config MACH_YL9200
help
Select this if you are using the ucDragon YL-9200 board.
+config MACH_CPUAT91
+ bool "Eukrea CPUAT91"
+ depends on ARCH_AT91RM9200
+ help
+ Select this if you are using the Eukrea Electromatique's
+ CPUAT91 board <http://www.eukrea.com/>.
+
endif
# ----------------------------------------------------------
@@ -205,6 +224,13 @@ config MACH_QIL_A9260
Select this if you are using a Calao Systems QIL-A9260 Board.
<http://www.calao-systems.com>
+config MACH_CPU9260
+ bool "Eukrea CPU9260 board"
+ depends on ARCH_AT91SAM9260
+ help
+ Select this if you are using a Eukrea Electromatique's
+ CPU9260 Board <http://www.eukrea.com/>
+
endif
# ----------------------------------------------------------
@@ -224,6 +250,21 @@ endif
# ----------------------------------------------------------
+if ARCH_AT91SAM9G10
+
+comment "AT91SAM9G10 Board Type"
+
+config MACH_AT91SAM9G10EK
+ bool "Atmel AT91SAM9G10-EK Evaluation Kit"
+ depends on ARCH_AT91SAM9G10
+ help
+ Select this if you are using Atmel's AT91SAM9G10-EK Evaluation Kit.
+ <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4588>
+
+endif
+
+# ----------------------------------------------------------
+
if ARCH_AT91SAM9263
comment "AT91SAM9263 Board Type"
@@ -276,6 +317,29 @@ config MACH_AT91SAM9G20EK
help
Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit.
+config MACH_CPU9G20
+ bool "Eukrea CPU9G20 board"
+ depends on ARCH_AT91SAM9G20
+ help
+ Select this if you are using a Eukrea Electromatique's
+ CPU9G20 Board <http://www.eukrea.com/>
+
+endif
+
+# ----------------------------------------------------------
+
+if ARCH_AT91SAM9G45
+
+comment "AT91SAM9G45 Board Type"
+
+config MACH_AT91SAM9G45EKES
+ bool "Atmel AT91SAM9G45-EKES Evaluation Kit"
+ depends on ARCH_AT91SAM9G45
+ help
+ Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
+ "ES" at the end of the name means that this board is an
+ Engineering Sample.
+
endif
# ----------------------------------------------------------
@@ -315,13 +379,13 @@ comment "AT91 Board Options"
config MTD_AT91_DATAFLASH_CARD
bool "Enable DataFlash Card support"
- depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK || MACH_NEOCORE926)
+ depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK || MACH_NEOCORE926)
help
Enable support for the DataFlash card.
config MTD_NAND_ATMEL_BUSWIDTH_16
bool "Enable 16-bit data bus interface to NAND flash"
- depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_AT91CAP9ADK)
+ depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_AT91SAM9G45EKES || MACH_AT91CAP9ADK)
help
On AT91SAM926x boards both types of NAND flash can be present
(8 and 16 bit data bus width).
@@ -383,7 +447,7 @@ config AT91_EARLY_USART2
config AT91_EARLY_USART3
bool "USART3"
- depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
+ depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45)
config AT91_EARLY_USART4
bool "USART4"
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c69ff237fd14..a6ed015d82ed 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -13,9 +13,11 @@ obj-$(CONFIG_AT91_PMC_UNIT) += clock.o
obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+ obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
@@ -32,6 +34,7 @@ obj-$(CONFIG_MACH_KAFA) += board-kafa.o
obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o
obj-$(CONFIG_MACH_ECBAT91) += board-ecbat91.o
obj-$(CONFIG_MACH_YL9200) += board-yl-9200.o
+obj-$(CONFIG_MACH_CPUAT91) += board-cpuat91.o
# AT91SAM9260 board-specific support
obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
@@ -40,9 +43,11 @@ obj-$(CONFIG_MACH_SAM9_L9260) += board-sam9-l9260.o
obj-$(CONFIG_MACH_USB_A9260) += board-usb-a9260.o
obj-$(CONFIG_MACH_QIL_A9260) += board-qil-a9260.o
obj-$(CONFIG_MACH_AFEB9260) += board-afeb-9260v1.o
+obj-$(CONFIG_MACH_CPU9260) += board-cpu9krea.o
# AT91SAM9261 board-specific support
obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
+obj-$(CONFIG_MACH_AT91SAM9G10EK) += board-sam9261ek.o
# AT91SAM9263 board-specific support
obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
@@ -54,6 +59,10 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o
# AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
+obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o
+
+# AT91SAM9G45 board-specific support
+obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
# AT91CAP9 board-specific support
obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 071a2506a69f..3462b815054a 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -7,6 +7,10 @@ ifeq ($(CONFIG_ARCH_AT91CAP9),y)
zreladdr-y := 0x70008000
params_phys-y := 0x70000100
initrd_phys-y := 0x70410000
+else ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
+ zreladdr-y := 0x70008000
+params_phys-y := 0x70000100
+initrd_phys-y := 0x70410000
else
zreladdr-y := 0x20008000
params_phys-y := 0x20000100
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index d74c9ac007e7..ee4ea0e720cf 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -1113,6 +1113,122 @@ void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
+/* --------------------------------------------------------------------
+ * CF/IDE
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE) || \
+ defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \
+ defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE)
+
+static struct at91_cf_data cf0_data;
+
+static struct resource cf0_resources[] = {
+ [0] = {
+ .start = AT91_CHIPSELECT_4,
+ .end = AT91_CHIPSELECT_4 + SZ_256M - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device cf0_device = {
+ .id = 0,
+ .dev = {
+ .platform_data = &cf0_data,
+ },
+ .resource = cf0_resources,
+ .num_resources = ARRAY_SIZE(cf0_resources),
+};
+
+static struct at91_cf_data cf1_data;
+
+static struct resource cf1_resources[] = {
+ [0] = {
+ .start = AT91_CHIPSELECT_5,
+ .end = AT91_CHIPSELECT_5 + SZ_256M - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device cf1_device = {
+ .id = 1,
+ .dev = {
+ .platform_data = &cf1_data,
+ },
+ .resource = cf1_resources,
+ .num_resources = ARRAY_SIZE(cf1_resources),
+};
+
+void __init at91_add_device_cf(struct at91_cf_data *data)
+{
+ struct platform_device *pdev;
+ unsigned long csa;
+
+ if (!data)
+ return;
+
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+
+ switch (data->chipselect) {
+ case 4:
+ at91_set_multi_drive(AT91_PIN_PC8, 0);
+ at91_set_A_periph(AT91_PIN_PC8, 0);
+ csa |= AT91_MATRIX_CS4A_SMC_CF1;
+ cf0_data = *data;
+ pdev = &cf0_device;
+ break;
+ case 5:
+ at91_set_multi_drive(AT91_PIN_PC9, 0);
+ at91_set_A_periph(AT91_PIN_PC9, 0);
+ csa |= AT91_MATRIX_CS5A_SMC_CF2;
+ cf1_data = *data;
+ pdev = &cf1_device;
+ break;
+ default:
+ printk(KERN_ERR "AT91 CF: bad chip-select requested (%u)\n",
+ data->chipselect);
+ return;
+ }
+
+ at91_sys_write(AT91_MATRIX_EBICSA, csa);
+
+ if (data->rst_pin) {
+ at91_set_multi_drive(data->rst_pin, 0);
+ at91_set_gpio_output(data->rst_pin, 1);
+ }
+
+ if (data->irq_pin) {
+ at91_set_gpio_input(data->irq_pin, 0);
+ at91_set_deglitch(data->irq_pin, 1);
+ }
+
+ if (data->det_pin) {
+ at91_set_gpio_input(data->det_pin, 0);
+ at91_set_deglitch(data->det_pin, 1);
+ }
+
+ at91_set_B_periph(AT91_PIN_PC6, 0); /* CFCE1 */
+ at91_set_B_periph(AT91_PIN_PC7, 0); /* CFCE2 */
+ at91_set_A_periph(AT91_PIN_PC10, 0); /* CFRNW */
+ at91_set_A_periph(AT91_PIN_PC15, 1); /* NWAIT */
+
+ if (data->flags & AT91_CF_TRUE_IDE)
+#if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE)
+ pdev->name = "pata_at91";
+#elif defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE)
+ pdev->name = "at91_ide";
+#else
+#warning "board requires AT91_CF_TRUE_IDE: enable either at91_ide or pata_at91"
+#endif
+ else
+ pdev->name = "at91_cf";
+
+ platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_cf(struct at91_cf_data * data) {}
+#endif
/* -------------------------------------------------------------------- */
/*
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 3acd7d7e6a42..4ecf37996c77 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -16,6 +16,7 @@
#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <mach/cpu.h>
#include <mach/at91sam9261.h>
#include <mach/at91_pmc.h>
#include <mach/at91_rstc.h>
@@ -30,7 +31,11 @@ static struct map_desc at91sam9261_io_desc[] __initdata = {
.pfn = __phys_to_pfn(AT91_BASE_SYS),
.length = SZ_16K,
.type = MT_DEVICE,
- }, {
+ },
+};
+
+static struct map_desc at91sam9261_sram_desc[] __initdata = {
+ {
.virtual = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
.pfn = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
.length = AT91SAM9261_SRAM_SIZE,
@@ -38,6 +43,15 @@ static struct map_desc at91sam9261_io_desc[] __initdata = {
},
};
+static struct map_desc at91sam9g10_sram_desc[] __initdata = {
+ {
+ .virtual = AT91_IO_VIRT_BASE - AT91SAM9G10_SRAM_SIZE,
+ .pfn = __phys_to_pfn(AT91SAM9G10_SRAM_BASE),
+ .length = AT91SAM9G10_SRAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
/* --------------------------------------------------------------------
* Clocks
* -------------------------------------------------------------------- */
@@ -263,6 +277,12 @@ void __init at91sam9261_initialize(unsigned long main_clock)
/* Map peripherals */
iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
+ if (cpu_is_at91sam9g10())
+ iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
+ else
+ iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
+
+
at91_arch_reset = at91sam9261_reset;
pm_power_off = at91sam9261_poweroff;
at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
new file mode 100644
index 000000000000..85166b7e69a1
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -0,0 +1,360 @@
+/*
+ * Chip-specific setup code for the AT91SAM9G45 family
+ *
+ * Copyright (C) 2009 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9g45.h>
+#include <mach/at91_pmc.h>
+#include <mach/at91_rstc.h>
+#include <mach/at91_shdwc.h>
+
+#include "generic.h"
+#include "clock.h"
+
+static struct map_desc at91sam9g45_io_desc[] __initdata = {
+ {
+ .virtual = AT91_VA_BASE_SYS,
+ .pfn = __phys_to_pfn(AT91_BASE_SYS),
+ .length = SZ_16K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = AT91_IO_VIRT_BASE - AT91SAM9G45_SRAM_SIZE,
+ .pfn = __phys_to_pfn(AT91SAM9G45_SRAM_BASE),
+ .length = AT91SAM9G45_SRAM_SIZE,
+ .type = MT_DEVICE,
+ }
+};
+
+/* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioA_clk = {
+ .name = "pioA_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_PIOA,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+ .name = "pioB_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_PIOB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+ .name = "pioC_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_PIOC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioDE_clk = {
+ .name = "pioDE_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_PIODE,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+ .name = "usart0_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_US0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+ .name = "usart1_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_US1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+ .name = "usart2_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_US2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+ .name = "usart3_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_US3,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+ .name = "mci0_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_MCI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+ .name = "twi0_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_TWI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+ .name = "twi1_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_TWI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+ .name = "spi0_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_SPI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+ .name = "spi1_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_SPI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc0_clk = {
+ .name = "ssc0_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_SSC0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+ .name = "ssc1_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_SSC1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+ .name = "tcb_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_TCB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+ .name = "pwm_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_PWMC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tsc_clk = {
+ .name = "tsc_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_TSC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma_clk = {
+ .name = "dma_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_DMA,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhphs_clk = {
+ .name = "uhphs_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_UHPHS,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+ .name = "lcdc_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_LCDC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+ .name = "ac97_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_AC97C,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+ .name = "macb_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_EMAC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk isi_clk = {
+ .name = "isi_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_ISI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+ .name = "udphs_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_UDPHS,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+ .name = "mci1_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_MCI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+
+/* One additional fake clock for ohci */
+static struct clk ohci_clk = {
+ .name = "ohci_clk",
+ .pmc_mask = 0,
+ .type = CLK_TYPE_PERIPHERAL,
+ .parent = &uhphs_clk,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+ &pioA_clk,
+ &pioB_clk,
+ &pioC_clk,
+ &pioDE_clk,
+ &usart0_clk,
+ &usart1_clk,
+ &usart2_clk,
+ &usart3_clk,
+ &mmc0_clk,
+ &twi0_clk,
+ &twi1_clk,
+ &spi0_clk,
+ &spi1_clk,
+ &ssc0_clk,
+ &ssc1_clk,
+ &tcb_clk,
+ &pwm_clk,
+ &tsc_clk,
+ &dma_clk,
+ &uhphs_clk,
+ &lcdc_clk,
+ &ac97_clk,
+ &macb_clk,
+ &isi_clk,
+ &udphs_clk,
+ &mmc1_clk,
+ // irq0
+ &ohci_clk,
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+ .name = "pck0",
+ .pmc_mask = AT91_PMC_PCK0,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 0,
+};
+static struct clk pck1 = {
+ .name = "pck1",
+ .pmc_mask = AT91_PMC_PCK1,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 1,
+};
+
+static void __init at91sam9g45_register_clocks(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+ clk_register(periph_clocks[i]);
+
+ clk_register(&pck0);
+ clk_register(&pck1);
+}
+
+/* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+
+static struct at91_gpio_bank at91sam9g45_gpio[] = {
+ {
+ .id = AT91SAM9G45_ID_PIOA,
+ .offset = AT91_PIOA,
+ .clock = &pioA_clk,
+ }, {
+ .id = AT91SAM9G45_ID_PIOB,
+ .offset = AT91_PIOB,
+ .clock = &pioB_clk,
+ }, {
+ .id = AT91SAM9G45_ID_PIOC,
+ .offset = AT91_PIOC,
+ .clock = &pioC_clk,
+ }, {
+ .id = AT91SAM9G45_ID_PIODE,
+ .offset = AT91_PIOD,
+ .clock = &pioDE_clk,
+ }, {
+ .id = AT91SAM9G45_ID_PIODE,
+ .offset = AT91_PIOE,
+ .clock = &pioDE_clk,
+ }
+};
+
+static void at91sam9g45_reset(void)
+{
+ at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+}
+
+static void at91sam9g45_poweroff(void)
+{
+ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
+}
+
+
+/* --------------------------------------------------------------------
+ * AT91SAM9G45 processor initialization
+ * -------------------------------------------------------------------- */
+
+void __init at91sam9g45_initialize(unsigned long main_clock)
+{
+ /* Map peripherals */
+ iotable_init(at91sam9g45_io_desc, ARRAY_SIZE(at91sam9g45_io_desc));
+
+ at91_arch_reset = at91sam9g45_reset;
+ pm_power_off = at91sam9g45_poweroff;
+ at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
+
+ /* Init clock subsystem */
+ at91_clock_init(main_clock);
+
+ /* Register the processor-specific clocks */
+ at91sam9g45_register_clocks();
+
+ /* Register GPIO subsystem */
+ at91_gpio_init(at91sam9g45_gpio, 5);
+}
+
+/* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 7, /* Advanced Interrupt Controller (FIQ) */
+ 7, /* System Peripherals */
+ 1, /* Parallel IO Controller A */
+ 1, /* Parallel IO Controller B */
+ 1, /* Parallel IO Controller C */
+ 1, /* Parallel IO Controller D and E */
+ 0,
+ 5, /* USART 0 */
+ 5, /* USART 1 */
+ 5, /* USART 2 */
+ 5, /* USART 3 */
+ 0, /* Multimedia Card Interface 0 */
+ 6, /* Two-Wire Interface 0 */
+ 6, /* Two-Wire Interface 1 */
+ 5, /* Serial Peripheral Interface 0 */
+ 5, /* Serial Peripheral Interface 1 */
+ 4, /* Serial Synchronous Controller 0 */
+ 4, /* Serial Synchronous Controller 1 */
+ 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+ 0, /* Pulse Width Modulation Controller */
+ 0, /* Touch Screen Controller */
+ 0, /* DMA Controller */
+ 2, /* USB Host High Speed port */
+ 3, /* LDC Controller */
+ 5, /* AC97 Controller */
+ 3, /* Ethernet */
+ 0, /* Image Sensor Interface */
+ 2, /* USB Device High speed port */
+ 0,
+ 0, /* Multimedia Card Interface 1 */
+ 0,
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+};
+
+void __init at91sam9g45_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+{
+ if (!priority)
+ priority = at91sam9g45_default_irq_priority;
+
+ /* Initialize the AIC interrupt controller */
+ at91_aic_init(priority);
+
+ /* Enable GPIO interrupts */
+ at91_gpio_irq_setup();
+}
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
new file mode 100644
index 000000000000..d746e8621bc2
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -0,0 +1,1230 @@
+/*
+ * On-Chip devices setup code for the AT91SAM9G45 family
+ *
+ * Copyright (C) 2009 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+
+#include <linux/fb.h>
+#include <video/atmel_lcdc.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9g45.h>
+#include <mach/at91sam9g45_matrix.h>
+#include <mach/at91sam9_smc.h>
+
+#include "generic.h"
+
+
+/* --------------------------------------------------------------------
+ * USB Host (OHCI)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_ohci_data;
+
+static struct resource usbh_ohci_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_OHCI_BASE,
+ .end = AT91SAM9G45_OHCI_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_UHPHS,
+ .end = AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_usbh_ohci_device = {
+ .name = "at91_ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &usbh_ohci_data,
+ },
+ .resource = usbh_ohci_resources,
+ .num_resources = ARRAY_SIZE(usbh_ohci_resources),
+};
+
+void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data)
+{
+ int i;
+
+ if (!data)
+ return;
+
+ /* Enable VBus control for UHP ports */
+ for (i = 0; i < data->ports; i++) {
+ if (data->vbus_pin[i])
+ at91_set_gpio_output(data->vbus_pin[i], 0);
+ }
+
+ usbh_ohci_data = *data;
+ platform_device_register(&at91_usbh_ohci_device);
+}
+#else
+void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * USB HS Device (Gadget)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
+static struct resource usba_udc_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_UDPHS_FIFO,
+ .end = AT91SAM9G45_UDPHS_FIFO + SZ_512K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_BASE_UDPHS,
+ .end = AT91SAM9G45_BASE_UDPHS + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = AT91SAM9G45_ID_UDPHS,
+ .end = AT91SAM9G45_ID_UDPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
+ [idx] = { \
+ .name = nam, \
+ .index = idx, \
+ .fifo_size = maxpkt, \
+ .nr_banks = maxbk, \
+ .can_dma = dma, \
+ .can_isoc = isoc, \
+ }
+
+static struct usba_ep_data usba_udc_ep[] __initdata = {
+ EP("ep0", 0, 64, 1, 0, 0),
+ EP("ep1", 1, 1024, 2, 1, 1),
+ EP("ep2", 2, 1024, 2, 1, 1),
+ EP("ep3", 3, 1024, 3, 1, 0),
+ EP("ep4", 4, 1024, 3, 1, 0),
+ EP("ep5", 5, 1024, 3, 1, 1),
+ EP("ep6", 6, 1024, 3, 1, 1),
+};
+
+#undef EP
+
+/*
+ * pdata doesn't have room for any endpoints, so we need to
+ * append room for the ones we need right after it.
+ */
+static struct {
+ struct usba_platform_data pdata;
+ struct usba_ep_data ep[7];
+} usba_udc_data;
+
+static struct platform_device at91_usba_udc_device = {
+ .name = "atmel_usba_udc",
+ .id = -1,
+ .dev = {
+ .platform_data = &usba_udc_data.pdata,
+ },
+ .resource = usba_udc_resources,
+ .num_resources = ARRAY_SIZE(usba_udc_resources),
+};
+
+void __init at91_add_device_usba(struct usba_platform_data *data)
+{
+ usba_udc_data.pdata.vbus_pin = -EINVAL;
+ usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
+ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));;
+
+ if (data && data->vbus_pin > 0) {
+ at91_set_gpio_input(data->vbus_pin, 0);
+ at91_set_deglitch(data->vbus_pin, 1);
+ usba_udc_data.pdata.vbus_pin = data->vbus_pin;
+ }
+
+ /* Pullup pin is handled internally by USB device peripheral */
+
+ /* Clocks */
+ at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
+ at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
+
+ platform_device_register(&at91_usba_udc_device);
+}
+#else
+void __init at91_add_device_usba(struct usba_platform_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+static u64 eth_dmamask = DMA_BIT_MASK(32);
+static struct at91_eth_data eth_data;
+
+static struct resource eth_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_EMAC,
+ .end = AT91SAM9G45_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_EMAC,
+ .end = AT91SAM9G45_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_eth_device = {
+ .name = "macb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &eth_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &eth_data,
+ },
+ .resource = eth_resources,
+ .num_resources = ARRAY_SIZE(eth_resources),
+};
+
+void __init at91_add_device_eth(struct at91_eth_data *data)
+{
+ if (!data)
+ return;
+
+ if (data->phy_irq_pin) {
+ at91_set_gpio_input(data->phy_irq_pin, 0);
+ at91_set_deglitch(data->phy_irq_pin, 1);
+ }
+
+ /* Pins used for MII and RMII */
+ at91_set_A_periph(AT91_PIN_PA17, 0); /* ETXCK_EREFCK */
+ at91_set_A_periph(AT91_PIN_PA15, 0); /* ERXDV */
+ at91_set_A_periph(AT91_PIN_PA12, 0); /* ERX0 */
+ at91_set_A_periph(AT91_PIN_PA13, 0); /* ERX1 */
+ at91_set_A_periph(AT91_PIN_PA16, 0); /* ERXER */
+ at91_set_A_periph(AT91_PIN_PA14, 0); /* ETXEN */
+ at91_set_A_periph(AT91_PIN_PA10, 0); /* ETX0 */
+ at91_set_A_periph(AT91_PIN_PA11, 0); /* ETX1 */
+ at91_set_A_periph(AT91_PIN_PA19, 0); /* EMDIO */
+ at91_set_A_periph(AT91_PIN_PA18, 0); /* EMDC */
+
+ if (!data->is_rmii) {
+ at91_set_B_periph(AT91_PIN_PA29, 0); /* ECRS */
+ at91_set_B_periph(AT91_PIN_PA30, 0); /* ECOL */
+ at91_set_B_periph(AT91_PIN_PA8, 0); /* ERX2 */
+ at91_set_B_periph(AT91_PIN_PA9, 0); /* ERX3 */
+ at91_set_B_periph(AT91_PIN_PA28, 0); /* ERXCK */
+ at91_set_B_periph(AT91_PIN_PA6, 0); /* ETX2 */
+ at91_set_B_periph(AT91_PIN_PA7, 0); /* ETX3 */
+ at91_set_B_periph(AT91_PIN_PA27, 0); /* ETXER */
+ }
+
+ eth_data = *data;
+ platform_device_register(&at91sam9g45_eth_device);
+}
+#else
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
+static struct atmel_nand_data nand_data;
+
+#define NAND_BASE AT91_CHIPSELECT_3
+
+static struct resource nand_resources[] = {
+ [0] = {
+ .start = NAND_BASE,
+ .end = NAND_BASE + SZ_256M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91_BASE_SYS + AT91_ECC,
+ .end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device at91sam9g45_nand_device = {
+ .name = "atmel_nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &nand_data,
+ },
+ .resource = nand_resources,
+ .num_resources = ARRAY_SIZE(nand_resources),
+};
+
+void __init at91_add_device_nand(struct atmel_nand_data *data)
+{
+ unsigned long csa;
+
+ if (!data)
+ return;
+
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+ at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
+
+ /* enable pin */
+ if (data->enable_pin)
+ at91_set_gpio_output(data->enable_pin, 1);
+
+ /* ready/busy pin */
+ if (data->rdy_pin)
+ at91_set_gpio_input(data->rdy_pin, 1);
+
+ /* card detect pin */
+ if (data->det_pin)
+ at91_set_gpio_input(data->det_pin, 1);
+
+ nand_data = *data;
+ platform_device_register(&at91sam9g45_nand_device);
+}
+#else
+void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+static struct i2c_gpio_platform_data pdata_i2c0 = {
+ .sda_pin = AT91_PIN_PA20,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA21,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9g45_twi0_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev.platform_data = &pdata_i2c0,
+};
+
+static struct i2c_gpio_platform_data pdata_i2c1 = {
+ .sda_pin = AT91_PIN_PB10,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PB11,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9g45_twi1_device = {
+ .name = "i2c-gpio",
+ .id = 1,
+ .dev.platform_data = &pdata_i2c1,
+};
+
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
+{
+ i2c_register_board_info(i2c_id, devices, nr_devices);
+
+ if (i2c_id == 0) {
+ at91_set_GPIO_periph(AT91_PIN_PA20, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA20, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA21, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PB10, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PB11, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+static struct resource twi0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TWI0,
+ .end = AT91SAM9G45_BASE_TWI0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TWI0,
+ .end = AT91SAM9G45_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_twi0_device = {
+ .name = "at91_i2c",
+ .id = 0,
+ .resource = twi0_resources,
+ .num_resources = ARRAY_SIZE(twi0_resources),
+};
+
+static struct resource twi1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TWI1,
+ .end = AT91SAM9G45_BASE_TWI1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TWI1,
+ .end = AT91SAM9G45_ID_TWI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_twi1_device = {
+ .name = "at91_i2c",
+ .id = 1,
+ .resource = twi1_resources,
+ .num_resources = ARRAY_SIZE(twi1_resources),
+};
+
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
+{
+ i2c_register_board_info(i2c_id, devices, nr_devices);
+
+ /* pins used for TWI interface */
+ if (i2c_id == 0) {
+ at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA20, 1);
+
+ at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
+ at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PB10, 1);
+
+ at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
+ at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+}
+#else
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * SPI
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+static struct resource spi0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SPI0,
+ .end = AT91SAM9G45_BASE_SPI0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SPI0,
+ .end = AT91SAM9G45_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_spi0_device = {
+ .name = "atmel_spi",
+ .id = 0,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = spi0_resources,
+ .num_resources = ARRAY_SIZE(spi0_resources),
+};
+
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PB18, AT91_PIN_PB19, AT91_PIN_PD27 };
+
+static struct resource spi1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SPI1,
+ .end = AT91SAM9G45_BASE_SPI1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SPI1,
+ .end = AT91SAM9G45_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_spi1_device = {
+ .name = "atmel_spi",
+ .id = 1,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = spi1_resources,
+ .num_resources = ARRAY_SIZE(spi1_resources),
+};
+
+static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB17, AT91_PIN_PD28, AT91_PIN_PD18, AT91_PIN_PD19 };
+
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+{
+ int i;
+ unsigned long cs_pin;
+ short enable_spi0 = 0;
+ short enable_spi1 = 0;
+
+ /* Choose SPI chip-selects */
+ for (i = 0; i < nr_devices; i++) {
+ if (devices[i].controller_data)
+ cs_pin = (unsigned long) devices[i].controller_data;
+ else if (devices[i].bus_num == 0)
+ cs_pin = spi0_standard_cs[devices[i].chip_select];
+ else
+ cs_pin = spi1_standard_cs[devices[i].chip_select];
+
+ if (devices[i].bus_num == 0)
+ enable_spi0 = 1;
+ else
+ enable_spi1 = 1;
+
+ /* enable chip-select pin */
+ at91_set_gpio_output(cs_pin, 1);
+
+ /* pass chip-select pin to driver */
+ devices[i].controller_data = (void *) cs_pin;
+ }
+
+ spi_register_board_info(devices, nr_devices);
+
+ /* Configure SPI bus(es) */
+ if (enable_spi0) {
+ at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI0_MISO */
+ at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI0_MOSI */
+ at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI0_SPCK */
+
+ at91_clock_associate("spi0_clk", &at91sam9g45_spi0_device.dev, "spi_clk");
+ platform_device_register(&at91sam9g45_spi0_device);
+ }
+ if (enable_spi1) {
+ at91_set_A_periph(AT91_PIN_PB14, 0); /* SPI1_MISO */
+ at91_set_A_periph(AT91_PIN_PB15, 0); /* SPI1_MOSI */
+ at91_set_A_periph(AT91_PIN_PB16, 0); /* SPI1_SPCK */
+
+ at91_clock_associate("spi1_clk", &at91sam9g45_spi1_device.dev, "spi_clk");
+ platform_device_register(&at91sam9g45_spi1_device);
+ }
+}
+#else
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_LCDC_BASE,
+ .end = AT91SAM9G45_LCDC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_LCDC,
+ .end = AT91SAM9G45_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_lcdc_device = {
+ .name = "atmel_lcdfb",
+ .id = 0,
+ .dev = {
+ .dma_mask = &lcdc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &lcdc_data,
+ },
+ .resource = lcdc_resources,
+ .num_resources = ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+ if (!data)
+ return;
+
+ at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */
+
+ at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */
+ at91_set_A_periph(AT91_PIN_PE3, 0); /* LCDVSYNC */
+ at91_set_A_periph(AT91_PIN_PE4, 0); /* LCDHSYNC */
+ at91_set_A_periph(AT91_PIN_PE5, 0); /* LCDDOTCK */
+ at91_set_A_periph(AT91_PIN_PE6, 0); /* LCDDEN */
+ at91_set_A_periph(AT91_PIN_PE7, 0); /* LCDD0 */
+ at91_set_A_periph(AT91_PIN_PE8, 0); /* LCDD1 */
+ at91_set_A_periph(AT91_PIN_PE9, 0); /* LCDD2 */
+ at91_set_A_periph(AT91_PIN_PE10, 0); /* LCDD3 */
+ at91_set_A_periph(AT91_PIN_PE11, 0); /* LCDD4 */
+ at91_set_A_periph(AT91_PIN_PE12, 0); /* LCDD5 */
+ at91_set_A_periph(AT91_PIN_PE13, 0); /* LCDD6 */
+ at91_set_A_periph(AT91_PIN_PE14, 0); /* LCDD7 */
+ at91_set_A_periph(AT91_PIN_PE15, 0); /* LCDD8 */
+ at91_set_A_periph(AT91_PIN_PE16, 0); /* LCDD9 */
+ at91_set_A_periph(AT91_PIN_PE17, 0); /* LCDD10 */
+ at91_set_A_periph(AT91_PIN_PE18, 0); /* LCDD11 */
+ at91_set_A_periph(AT91_PIN_PE19, 0); /* LCDD12 */
+ at91_set_A_periph(AT91_PIN_PE20, 0); /* LCDD13 */
+ at91_set_A_periph(AT91_PIN_PE21, 0); /* LCDD14 */
+ at91_set_A_periph(AT91_PIN_PE22, 0); /* LCDD15 */
+ at91_set_A_periph(AT91_PIN_PE23, 0); /* LCDD16 */
+ at91_set_A_periph(AT91_PIN_PE24, 0); /* LCDD17 */
+ at91_set_A_periph(AT91_PIN_PE25, 0); /* LCDD18 */
+ at91_set_A_periph(AT91_PIN_PE26, 0); /* LCDD19 */
+ at91_set_A_periph(AT91_PIN_PE27, 0); /* LCDD20 */
+ at91_set_A_periph(AT91_PIN_PE28, 0); /* LCDD21 */
+ at91_set_A_periph(AT91_PIN_PE29, 0); /* LCDD22 */
+ at91_set_A_periph(AT91_PIN_PE30, 0); /* LCDD23 */
+
+ lcdc_data = *data;
+ platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * Timer/Counter block
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATMEL_TCLIB
+static struct resource tcb0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TCB0,
+ .end = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TCB,
+ .end = AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_tcb0_device = {
+ .name = "atmel_tcb",
+ .id = 0,
+ .resource = tcb0_resources,
+ .num_resources = ARRAY_SIZE(tcb0_resources),
+};
+
+/* TCB1 begins with TC3 */
+static struct resource tcb1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TCB1,
+ .end = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TCB,
+ .end = AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_tcb1_device = {
+ .name = "atmel_tcb",
+ .id = 1,
+ .resource = tcb1_resources,
+ .num_resources = ARRAY_SIZE(tcb1_resources),
+};
+
+static void __init at91_add_device_tc(void)
+{
+ /* this chip has one clock and irq for all six TC channels */
+ at91_clock_associate("tcb_clk", &at91sam9g45_tcb0_device.dev, "t0_clk");
+ platform_device_register(&at91sam9g45_tcb0_device);
+ at91_clock_associate("tcb_clk", &at91sam9g45_tcb1_device.dev, "t0_clk");
+ platform_device_register(&at91sam9g45_tcb1_device);
+}
+#else
+static void __init at91_add_device_tc(void) { }
+#endif
+
+
+/* --------------------------------------------------------------------
+ * RTC
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
+static struct platform_device at91sam9g45_rtc_device = {
+ .name = "at91_rtc",
+ .id = -1,
+ .num_resources = 0,
+};
+
+static void __init at91_add_device_rtc(void)
+{
+ platform_device_register(&at91sam9g45_rtc_device);
+}
+#else
+static void __init at91_add_device_rtc(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * RTT
+ * -------------------------------------------------------------------- */
+
+static struct resource rtt_resources[] = {
+ {
+ .start = AT91_BASE_SYS + AT91_RTT,
+ .end = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device at91sam9g45_rtt_device = {
+ .name = "at91_rtt",
+ .id = 0,
+ .resource = rtt_resources,
+ .num_resources = ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
+{
+ platform_device_register(&at91sam9g45_rtt_device);
+}
+
+
+/* --------------------------------------------------------------------
+ * Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9g45_wdt_device = {
+ .name = "at91_wdt",
+ .id = -1,
+ .num_resources = 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+ platform_device_register(&at91sam9g45_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * PWM
+ * --------------------------------------------------------------------*/
+
+#if defined(CONFIG_ATMEL_PWM) || defined(CONFIG_ATMEL_PWM_MODULE)
+static u32 pwm_mask;
+
+static struct resource pwm_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_PWMC,
+ .end = AT91SAM9G45_BASE_PWMC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_PWMC,
+ .end = AT91SAM9G45_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_pwm0_device = {
+ .name = "atmel_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &pwm_mask,
+ },
+ .resource = pwm_resources,
+ .num_resources = ARRAY_SIZE(pwm_resources),
+};
+
+void __init at91_add_device_pwm(u32 mask)
+{
+ if (mask & (1 << AT91_PWM0))
+ at91_set_B_periph(AT91_PIN_PD24, 1); /* enable PWM0 */
+
+ if (mask & (1 << AT91_PWM1))
+ at91_set_B_periph(AT91_PIN_PD31, 1); /* enable PWM1 */
+
+ if (mask & (1 << AT91_PWM2))
+ at91_set_B_periph(AT91_PIN_PD26, 1); /* enable PWM2 */
+
+ if (mask & (1 << AT91_PWM3))
+ at91_set_B_periph(AT91_PIN_PD0, 1); /* enable PWM3 */
+
+ pwm_mask = mask;
+
+ platform_device_register(&at91sam9g45_pwm0_device);
+}
+#else
+void __init at91_add_device_pwm(u32 mask) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SSC0,
+ .end = AT91SAM9G45_BASE_SSC0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SSC0,
+ .end = AT91SAM9G45_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_ssc0_device = {
+ .name = "ssc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ssc0_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = ssc0_resources,
+ .num_resources = ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+ if (pins & ATMEL_SSC_TF)
+ at91_set_A_periph(AT91_PIN_PD1, 1);
+ if (pins & ATMEL_SSC_TK)
+ at91_set_A_periph(AT91_PIN_PD0, 1);
+ if (pins & ATMEL_SSC_TD)
+ at91_set_A_periph(AT91_PIN_PD2, 1);
+ if (pins & ATMEL_SSC_RD)
+ at91_set_A_periph(AT91_PIN_PD3, 1);
+ if (pins & ATMEL_SSC_RK)
+ at91_set_A_periph(AT91_PIN_PD4, 1);
+ if (pins & ATMEL_SSC_RF)
+ at91_set_A_periph(AT91_PIN_PD5, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SSC1,
+ .end = AT91SAM9G45_BASE_SSC1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SSC1,
+ .end = AT91SAM9G45_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_ssc1_device = {
+ .name = "ssc",
+ .id = 1,
+ .dev = {
+ .dma_mask = &ssc1_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = ssc1_resources,
+ .num_resources = ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+ if (pins & ATMEL_SSC_TF)
+ at91_set_A_periph(AT91_PIN_PD14, 1);
+ if (pins & ATMEL_SSC_TK)
+ at91_set_A_periph(AT91_PIN_PD12, 1);
+ if (pins & ATMEL_SSC_TD)
+ at91_set_A_periph(AT91_PIN_PD10, 1);
+ if (pins & ATMEL_SSC_RD)
+ at91_set_A_periph(AT91_PIN_PD11, 1);
+ if (pins & ATMEL_SSC_RK)
+ at91_set_A_periph(AT91_PIN_PD13, 1);
+ if (pins & ATMEL_SSC_RF)
+ at91_set_A_periph(AT91_PIN_PD15, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver. For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+ struct platform_device *pdev;
+
+ /*
+ * NOTE: caller is responsible for passing information matching
+ * "pins" to whatever will be using each particular controller.
+ */
+ switch (id) {
+ case AT91SAM9G45_ID_SSC0:
+ pdev = &at91sam9g45_ssc0_device;
+ configure_ssc0_pins(pins);
+ at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
+ break;
+ case AT91SAM9G45_ID_SSC1:
+ pdev = &at91sam9g45_ssc1_device;
+ configure_ssc1_pins(pins);
+ at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
+ break;
+ default:
+ return;
+ }
+
+ platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * UART
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SERIAL_ATMEL)
+static struct resource dbgu_resources[] = {
+ [0] = {
+ .start = AT91_VA_BASE_SYS + AT91_DBGU,
+ .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91_ID_SYS,
+ .end = AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data dbgu_data = {
+ .use_dma_tx = 0,
+ .use_dma_rx = 0,
+ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+};
+
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_dbgu_device = {
+ .name = "atmel_usart",
+ .id = 0,
+ .dev = {
+ .dma_mask = &dbgu_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &dbgu_data,
+ },
+ .resource = dbgu_resources,
+ .num_resources = ARRAY_SIZE(dbgu_resources),
+};
+
+static inline void configure_dbgu_pins(void)
+{
+ at91_set_A_periph(AT91_PIN_PB12, 0); /* DRXD */
+ at91_set_A_periph(AT91_PIN_PB13, 1); /* DTXD */
+}
+
+static struct resource uart0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US0,
+ .end = AT91SAM9G45_BASE_US0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US0,
+ .end = AT91SAM9G45_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart0_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart0_device = {
+ .name = "atmel_usart",
+ .id = 1,
+ .dev = {
+ .dma_mask = &uart0_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart0_data,
+ },
+ .resource = uart0_resources,
+ .num_resources = ARRAY_SIZE(uart0_resources),
+};
+
+static inline void configure_usart0_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB19, 1); /* TXD0 */
+ at91_set_A_periph(AT91_PIN_PB18, 0); /* RXD0 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PB17, 0); /* RTS0 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PB15, 0); /* CTS0 */
+}
+
+static struct resource uart1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US1,
+ .end = AT91SAM9G45_BASE_US1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US1,
+ .end = AT91SAM9G45_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart1_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart1_device = {
+ .name = "atmel_usart",
+ .id = 2,
+ .dev = {
+ .dma_mask = &uart1_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart1_data,
+ },
+ .resource = uart1_resources,
+ .num_resources = ARRAY_SIZE(uart1_resources),
+};
+
+static inline void configure_usart1_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB4, 1); /* TXD1 */
+ at91_set_A_periph(AT91_PIN_PB5, 0); /* RXD1 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_A_periph(AT91_PIN_PD16, 0); /* RTS1 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_A_periph(AT91_PIN_PD17, 0); /* CTS1 */
+}
+
+static struct resource uart2_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US2,
+ .end = AT91SAM9G45_BASE_US2 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US2,
+ .end = AT91SAM9G45_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart2_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart2_device = {
+ .name = "atmel_usart",
+ .id = 3,
+ .dev = {
+ .dma_mask = &uart2_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart2_data,
+ },
+ .resource = uart2_resources,
+ .num_resources = ARRAY_SIZE(uart2_resources),
+};
+
+static inline void configure_usart2_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB6, 1); /* TXD2 */
+ at91_set_A_periph(AT91_PIN_PB7, 0); /* RXD2 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PC9, 0); /* RTS2 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PC11, 0); /* CTS2 */
+}
+
+static struct resource uart3_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US3,
+ .end = AT91SAM9G45_BASE_US3 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US3,
+ .end = AT91SAM9G45_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart3_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart3_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart3_device = {
+ .name = "atmel_usart",
+ .id = 4,
+ .dev = {
+ .dma_mask = &uart3_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart3_data,
+ },
+ .resource = uart3_resources,
+ .num_resources = ARRAY_SIZE(uart3_resources),
+};
+
+static inline void configure_usart3_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB8, 1); /* TXD3 */
+ at91_set_A_periph(AT91_PIN_PB9, 0); /* RXD3 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PA23, 0); /* RTS3 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PA24, 0); /* CTS3 */
+}
+
+static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
+struct platform_device *atmel_default_console_device; /* the serial console device */
+
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0: /* DBGU */
+ pdev = &at91sam9g45_dbgu_device;
+ configure_dbgu_pins();
+ at91_clock_associate("mck", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US0:
+ pdev = &at91sam9g45_uart0_device;
+ configure_usart0_pins(pins);
+ at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US1:
+ pdev = &at91sam9g45_uart1_device;
+ configure_usart1_pins(pins);
+ at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US2:
+ pdev = &at91sam9g45_uart2_device;
+ configure_usart2_pins(pins);
+ at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US3:
+ pdev = &at91sam9g45_uart3_device;
+ configure_usart3_pins(pins);
+ at91_clock_associate("usart3_clk", &pdev->dev, "usart");
+ break;
+ default:
+ return;
+ }
+ pdev->id = portnr; /* update to mapped ID */
+
+ if (portnr < ATMEL_MAX_UART)
+ at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+ if (portnr < ATMEL_MAX_UART)
+ atmel_default_console_device = at91_uarts[portnr];
+}
+
+void __init at91_add_device_serial(void)
+{
+ int i;
+
+ for (i = 0; i < ATMEL_MAX_UART; i++) {
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[i]);
+ }
+
+ if (!atmel_default_console_device)
+ printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+#else
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
+void __init at91_add_device_serial(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init at91_add_standard_devices(void)
+{
+ at91_add_device_rtc();
+ at91_add_device_rtt();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
+ return 0;
+}
+
+arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 970fd6b6753e..50667bed7cc9 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -53,7 +53,7 @@ static void __init afeb9260_map_io(void)
/* Initialize processor: 18.432 MHz crystal */
at91sam9260_initialize(18432000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
@@ -174,6 +174,16 @@ static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
},
};
+/*
+ * IDE (CF True IDE mode)
+ */
+static struct at91_cf_data afeb9260_cf_data = {
+ .chipselect = 4,
+ .irq_pin = AT91_PIN_PA6,
+ .rst_pin = AT91_PIN_PA7,
+ .flags = AT91_CF_TRUE_IDE,
+};
+
static void __init afeb9260_board_init(void)
{
/* Serial */
@@ -202,6 +212,8 @@ static void __init afeb9260_board_init(void)
ARRAY_SIZE(afeb9260_i2c_devices));
/* Audio */
at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
+ /* IDE */
+ at91_add_device_cf(&afeb9260_cf_data);
}
MACHINE_START(AFEB9260, "Custom afeb9260 board")
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
index d3ba29c5d8c8..02138af631e7 100644
--- a/arch/arm/mach-at91/board-cam60.c
+++ b/arch/arm/mach-at91/board-cam60.c
@@ -50,7 +50,7 @@ static void __init cam60_map_io(void)
/* Initialize processor: 10 MHz crystal */
at91sam9260_initialize(10000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* set serial console to ttyS0 (ie, DBGU) */
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
new file mode 100644
index 000000000000..4bc2e9f6ebb5
--- /dev/null
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -0,0 +1,385 @@
+/*
+ * linux/arch/arm/mach-at91/board-cpu9krea.c
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2006 Atmel
+ * Copyright (C) 2009 Eric Benard - eric@eukrea.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/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91sam9260_matrix.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+static void __init cpu9krea_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91sam9260_initialize(18432000);
+
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
+ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART3 on ttyS4. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
+
+ /* USART4 on ttyS5. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+ /* USART5 on ttyS6. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init cpu9krea_init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata cpu9krea_usbh_data = {
+ .ports = 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata cpu9krea_udc_data = {
+ .vbus_pin = AT91_PIN_PC8,
+ .pullup_pin = 0, /* pull-up driven by UDC */
+};
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata cpu9krea_macb_data = {
+ .is_rmii = 1,
+};
+
+/*
+ * NAND flash
+ */
+static struct atmel_nand_data __initdata cpu9krea_nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .rdy_pin = AT91_PIN_PC13,
+ .enable_pin = AT91_PIN_PC14,
+ .bus_width_16 = 0,
+};
+
+#ifdef CONFIG_MACH_CPU9260
+static struct sam9_smc_config __initdata cpu9krea_nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 1,
+ .ncs_write_setup = 0,
+ .nwe_setup = 1,
+
+ .ncs_read_pulse = 3,
+ .nrd_pulse = 3,
+ .ncs_write_pulse = 3,
+ .nwe_pulse = 3,
+
+ .read_cycle = 5,
+ .write_cycle = 5,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+ .tdf_cycles = 2,
+};
+#else
+static struct sam9_smc_config __initdata cpu9krea_nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 2,
+ .ncs_write_setup = 0,
+ .nwe_setup = 2,
+
+ .ncs_read_pulse = 4,
+ .nrd_pulse = 4,
+ .ncs_write_pulse = 4,
+ .nwe_pulse = 4,
+
+ .read_cycle = 7,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+ .tdf_cycles = 3,
+};
+#endif
+
+static void __init cpu9krea_add_device_nand(void)
+{
+ sam9_smc_configure(3, &cpu9krea_nand_smc_config);
+ at91_add_device_nand(&cpu9krea_nand_data);
+}
+
+/*
+ * NOR flash
+ */
+static struct physmap_flash_data cpuat9260_nor_data = {
+ .width = 2,
+};
+
+#define NOR_BASE AT91_CHIPSELECT_0
+#define NOR_SIZE SZ_64M
+
+static struct resource nor_flash_resources[] = {
+ {
+ .start = NOR_BASE,
+ .end = NOR_BASE + NOR_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device cpu9krea_nor_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &cpuat9260_nor_data,
+ },
+ .resource = nor_flash_resources,
+ .num_resources = ARRAY_SIZE(nor_flash_resources),
+};
+
+#ifdef CONFIG_MACH_CPU9260
+static struct sam9_smc_config __initdata cpu9krea_nor_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 1,
+ .ncs_write_setup = 0,
+ .nwe_setup = 1,
+
+ .ncs_read_pulse = 10,
+ .nrd_pulse = 10,
+ .ncs_write_pulse = 6,
+ .nwe_pulse = 6,
+
+ .read_cycle = 12,
+ .write_cycle = 8,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
+ | AT91_SMC_DBW_16,
+ .tdf_cycles = 2,
+};
+#else
+static struct sam9_smc_config __initdata cpu9krea_nor_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 1,
+ .ncs_write_setup = 0,
+ .nwe_setup = 1,
+
+ .ncs_read_pulse = 13,
+ .nrd_pulse = 13,
+ .ncs_write_pulse = 8,
+ .nwe_pulse = 8,
+
+ .read_cycle = 15,
+ .write_cycle = 10,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
+ | AT91_SMC_DBW_16,
+ .tdf_cycles = 2,
+};
+#endif
+
+static __init void cpu9krea_add_device_nor(void)
+{
+ unsigned long csa;
+
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+ at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
+
+ /* configure chip-select 0 (NOR) */
+ sam9_smc_configure(0, &cpu9krea_nor_smc_config);
+
+ platform_device_register(&cpu9krea_nor_flash);
+}
+
+/*
+ * LEDs
+ */
+static struct gpio_led cpu9krea_leds[] = {
+ { /* LED1 */
+ .name = "LED1",
+ .gpio = AT91_PIN_PC11,
+ .active_low = 1,
+ .default_trigger = "timer",
+ },
+ { /* LED2 */
+ .name = "LED2",
+ .gpio = AT91_PIN_PC12,
+ .active_low = 1,
+ .default_trigger = "heartbeat",
+ },
+ { /* LED3 */
+ .name = "LED3",
+ .gpio = AT91_PIN_PC7,
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+ { /* LED4 */
+ .name = "LED4",
+ .gpio = AT91_PIN_PC9,
+ .active_low = 1,
+ .default_trigger = "none",
+ }
+};
+
+static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "ds1339",
+ },
+};
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button cpu9krea_buttons[] = {
+ {
+ .gpio = AT91_PIN_PC3,
+ .code = BTN_0,
+ .desc = "BP1",
+ .active_low = 1,
+ .wakeup = 1,
+ },
+ {
+ .gpio = AT91_PIN_PB20,
+ .code = BTN_1,
+ .desc = "BP2",
+ .active_low = 1,
+ .wakeup = 1,
+ }
+};
+
+static struct gpio_keys_platform_data cpu9krea_button_data = {
+ .buttons = cpu9krea_buttons,
+ .nbuttons = ARRAY_SIZE(cpu9krea_buttons),
+};
+
+static struct platform_device cpu9krea_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &cpu9krea_button_data,
+ }
+};
+
+static void __init cpu9krea_add_device_buttons(void)
+{
+ at91_set_gpio_input(AT91_PIN_PC3, 1); /* BP1 */
+ at91_set_deglitch(AT91_PIN_PC3, 1);
+ at91_set_gpio_input(AT91_PIN_PB20, 1); /* BP2 */
+ at91_set_deglitch(AT91_PIN_PB20, 1);
+
+ platform_device_register(&cpu9krea_button_device);
+}
+#else
+static void __init cpu9krea_add_device_buttons(void)
+{
+}
+#endif
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
+ .slot_b = 0,
+ .wire4 = 1,
+ .det_pin = AT91_PIN_PA29,
+};
+
+static void __init cpu9krea_board_init(void)
+{
+ /* NOR */
+ cpu9krea_add_device_nor();
+ /* Serial */
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&cpu9krea_usbh_data);
+ /* USB Device */
+ at91_add_device_udc(&cpu9krea_udc_data);
+ /* NAND */
+ cpu9krea_add_device_nand();
+ /* Ethernet */
+ at91_add_device_eth(&cpu9krea_macb_data);
+ /* MMC */
+ at91_add_device_mmc(0, &cpu9krea_mmc_data);
+ /* I2C */
+ at91_add_device_i2c(cpu9krea_i2c_devices,
+ ARRAY_SIZE(cpu9krea_i2c_devices));
+ /* LEDs */
+ at91_gpio_leds(cpu9krea_leds, ARRAY_SIZE(cpu9krea_leds));
+ /* Push Buttons */
+ cpu9krea_add_device_buttons();
+}
+
+#ifdef CONFIG_MACH_CPU9260
+MACHINE_START(CPUAT9260, "Eukrea CPU9260")
+#else
+MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
+#endif
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = cpu9krea_map_io,
+ .init_irq = cpu9krea_init_irq,
+ .init_machine = cpu9krea_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
new file mode 100644
index 000000000000..a28d99656190
--- /dev/null
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -0,0 +1,185 @@
+/*
+ * linux/arch/arm/mach-at91/board-cpuat91.c
+ *
+ * Copyright (C) 2009 Eric Benard - eric@eukrea.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/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91rm9200_mc.h>
+
+#include "generic.h"
+
+static struct gpio_led cpuat91_leds[] = {
+ {
+ .name = "led1",
+ .default_trigger = "heartbeat",
+ .active_low = 1,
+ .gpio = AT91_PIN_PC0,
+ },
+};
+
+static void __init cpuat91_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
+ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART2 on ttyS3 (Rx, Tx) */
+ at91_register_uart(AT91RM9200_ID_US2, 3, 0);
+
+ /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init cpuat91_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata cpuat91_eth_data = {
+ .is_rmii = 1,
+};
+
+static struct at91_usbh_data __initdata cpuat91_usbh_data = {
+ .ports = 1,
+};
+
+static struct at91_udc_data __initdata cpuat91_udc_data = {
+ .vbus_pin = AT91_PIN_PC15,
+ .pullup_pin = AT91_PIN_PC14,
+};
+
+static struct at91_mmc_data __initdata cpuat91_mmc_data = {
+ .det_pin = AT91_PIN_PC2,
+ .wire4 = 1,
+};
+
+static struct physmap_flash_data cpuat91_flash_data = {
+ .width = 2,
+};
+
+static struct resource cpuat91_flash_resource = {
+ .start = AT91_CHIPSELECT_0,
+ .end = AT91_CHIPSELECT_0 + SZ_16M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device cpuat91_norflash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &cpuat91_flash_data,
+ },
+ .resource = &cpuat91_flash_resource,
+ .num_resources = 1,
+};
+
+#ifdef CONFIG_MTD_PLATRAM
+struct platdata_mtd_ram at91_sram_pdata = {
+ .mapname = "SRAM",
+ .bankwidth = 2,
+};
+
+static struct resource at91_sram_resource[] = {
+ [0] = {
+ .start = AT91RM9200_SRAM_BASE,
+ .end = AT91RM9200_SRAM_BASE + AT91RM9200_SRAM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device at91_sram = {
+ .name = "mtd-ram",
+ .id = 0,
+ .resource = at91_sram_resource,
+ .num_resources = ARRAY_SIZE(at91_sram_resource),
+ .dev = {
+ .platform_data = &at91_sram_pdata,
+ },
+};
+#endif /* MTD_PLATRAM */
+
+static struct platform_device *platform_devices[] __initdata = {
+ &cpuat91_norflash,
+#ifdef CONFIG_MTD_PLATRAM
+ &at91_sram,
+#endif /* CONFIG_MTD_PLATRAM */
+};
+
+static void __init cpuat91_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* LEDs. */
+ at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds));
+ /* Ethernet */
+ at91_add_device_eth(&cpuat91_eth_data);
+ /* USB Host */
+ at91_add_device_usbh(&cpuat91_usbh_data);
+ /* USB Device */
+ at91_add_device_udc(&cpuat91_udc_data);
+ /* MMC */
+ at91_add_device_mmc(0, &cpuat91_mmc_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* Platform devices */
+ platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+MACHINE_START(CPUAT91, "Eukrea")
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91rm9200_timer,
+ .map_io = cpuat91_map_io,
+ .init_irq = cpuat91_init_irq,
+ .init_machine = cpuat91_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 9ba7ba2cc3b1..8c0b71c95be4 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -56,7 +56,7 @@ static void __init neocore926_map_io(void)
/* Initialize processor: 20 MHz crystal */
at91sam9263_initialize(20000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index 4cff9a7e61d2..664938e8f661 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -53,7 +53,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 12.000 MHz crystal */
at91sam9260_initialize(12000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index 93a0f8b100eb..ba9d501b5c50 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -54,7 +54,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 18.432 MHz crystal */
at91sam9260_initialize(18432000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index d5266da55311..c4c8865d52d7 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -61,7 +61,7 @@ static void __init ek_map_io(void)
/* Setup the LEDs */
at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* set serial console to ttyS0 (ie, DBGU) */
@@ -287,7 +287,11 @@ static void __init ek_add_device_ts(void) {}
*/
static struct at73c213_board_info at73c213_data = {
.ssc_id = 1,
+#if defined(CONFIG_MACH_AT91SAM9261EK)
.shortname = "AT91SAM9261-EK external DAC",
+#else
+ .shortname = "AT91SAM9G10-EK external DAC",
+#endif
};
#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
@@ -414,6 +418,9 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
.default_monspecs = &at91fb_default_stn_monspecs,
.atmel_lcdfb_power_control = at91_lcdc_stn_power_control,
.guard_time = 1,
+#if defined(CONFIG_MACH_AT91SAM9G10EK)
+ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
+#endif
};
#else
@@ -467,6 +474,9 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
.default_monspecs = &at91fb_default_tft_monspecs,
.atmel_lcdfb_power_control = at91_lcdc_tft_power_control,
.guard_time = 1,
+#if defined(CONFIG_MACH_AT91SAM9G10EK)
+ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
+#endif
};
#endif
@@ -600,7 +610,11 @@ static void __init ek_board_init(void)
at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
}
+#if defined(CONFIG_MACH_AT91SAM9261EK)
MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
+#else
+MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
+#endif
/* Maintainer: Atmel */
.phys_io = AT91_BASE_SYS,
.io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 57d52528f224..924f2db46d96 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -57,7 +57,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 16.367 MHz crystal */
at91sam9263_initialize(16367660);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index a55398ed1211..29cf83177484 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -50,7 +50,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 18.432 MHz crystal */
at91sam9260_initialize(18432000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
@@ -273,6 +273,7 @@ static void __init ek_add_device_buttons(void) {}
static struct i2c_board_info __initdata ek_i2c_devices[] = {
{
I2C_BOARD_INFO("24c512", 0x50),
+ I2C_BOARD_INFO("wm8731", 0x1b),
},
};
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
new file mode 100644
index 000000000000..b8558eae5229
--- /dev/null
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -0,0 +1,389 @@
+/*
+ * Board-specific setup code for the AT91SAM9M10G45 Evaluation Kit family
+ *
+ * Covers: * AT91SAM9G45-EKES board
+ * * AT91SAM9M10G45-EK board
+ *
+ * Copyright (C) 2009 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/fb.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <video/atmel_lcdc.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91_shdwc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init ek_map_io(void)
+{
+ /* Initialize processor: 12.000 MHz crystal */
+ at91sam9g45_initialize(12000000);
+
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 not connected on the -EK board */
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init ek_init_irq(void)
+{
+ at91sam9g45_init_interrupts(NULL);
+}
+
+
+/*
+ * USB HS Host port (common to OHCI & EHCI)
+ */
+static struct at91_usbh_data __initdata ek_usbh_hs_data = {
+ .ports = 2,
+ .vbus_pin = {AT91_PIN_PD1, AT91_PIN_PD3},
+};
+
+
+/*
+ * USB HS Device port
+ */
+static struct usba_platform_data __initdata ek_usba_udc_data = {
+ .vbus_pin = AT91_PIN_PB19,
+};
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info ek_spi_devices[] = {
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 0,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata ek_macb_data = {
+ .phy_irq_pin = AT91_PIN_PD5,
+ .is_rmii = 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata ek_nand_partition[] = {
+ {
+ .name = "Partition 1",
+ .offset = 0,
+ .size = SZ_64M,
+ },
+ {
+ .name = "Partition 2",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+ *num_partitions = ARRAY_SIZE(ek_nand_partition);
+ return ek_nand_partition;
+}
+
+/* det_pin is not connected */
+static struct atmel_nand_data __initdata ek_nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .rdy_pin = AT91_PIN_PC8,
+ .enable_pin = AT91_PIN_PC14,
+ .partition_info = nand_partitions,
+#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+ .bus_width_16 = 1,
+#else
+ .bus_width_16 = 0,
+#endif
+};
+
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 2,
+ .ncs_write_setup = 0,
+ .nwe_setup = 2,
+
+ .ncs_read_pulse = 4,
+ .nrd_pulse = 4,
+ .ncs_write_pulse = 4,
+ .nwe_pulse = 4,
+
+ .read_cycle = 7,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+ .tdf_cycles = 3,
+};
+
+static void __init ek_add_device_nand(void)
+{
+ /* setup bus-width (8 or 16) */
+ if (ek_nand_data.bus_width_16)
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+ else
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+ /* configure chip-select 3 (NAND) */
+ sam9_smc_configure(3, &ek_nand_smc_config);
+
+ at91_add_device_nand(&ek_nand_data);
+}
+
+
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+ {
+ .name = "LG",
+ .refresh = 60,
+ .xres = 480, .yres = 272,
+ .pixclock = KHZ2PICOS(9000),
+
+ .left_margin = 1, .right_margin = 1,
+ .upper_margin = 40, .lower_margin = 1,
+ .hsync_len = 45, .vsync_len = 1,
+
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+ .manufacturer = "LG",
+ .monitor = "LB043WQ1",
+
+ .modedb = at91_tft_vga_modes,
+ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
+ .hfmin = 15000,
+ .hfmax = 17640,
+ .vfmin = 57,
+ .vfmax = 67,
+};
+
+#define AT91SAM9G45_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
+ | ATMEL_LCDC_DISTYPE_TFT \
+ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
+ .default_bpp = 32,
+ .default_dmacon = ATMEL_LCDC_DMAEN,
+ .default_lcdcon2 = AT91SAM9G45_DEFAULT_LCDCON2,
+ .default_monspecs = &at91fb_default_monspecs,
+ .guard_time = 9,
+ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+#endif
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+ { /* BP1, "leftclic" */
+ .code = BTN_LEFT,
+ .gpio = AT91_PIN_PB6,
+ .active_low = 1,
+ .desc = "left_click",
+ .wakeup = 1,
+ },
+ { /* BP2, "rightclic" */
+ .code = BTN_RIGHT,
+ .gpio = AT91_PIN_PB7,
+ .active_low = 1,
+ .desc = "right_click",
+ .wakeup = 1,
+ },
+ /* BP3, "joystick" */
+ {
+ .code = KEY_LEFT,
+ .gpio = AT91_PIN_PB14,
+ .active_low = 1,
+ .desc = "Joystick Left",
+ },
+ {
+ .code = KEY_RIGHT,
+ .gpio = AT91_PIN_PB15,
+ .active_low = 1,
+ .desc = "Joystick Right",
+ },
+ {
+ .code = KEY_UP,
+ .gpio = AT91_PIN_PB16,
+ .active_low = 1,
+ .desc = "Joystick Up",
+ },
+ {
+ .code = KEY_DOWN,
+ .gpio = AT91_PIN_PB17,
+ .active_low = 1,
+ .desc = "Joystick Down",
+ },
+ {
+ .code = KEY_ENTER,
+ .gpio = AT91_PIN_PB18,
+ .active_low = 1,
+ .desc = "Joystick Press",
+ },
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+ .buttons = ek_buttons,
+ .nbuttons = ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ek_button_data,
+ }
+};
+
+static void __init ek_add_device_buttons(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ek_buttons); i++) {
+ at91_set_GPIO_periph(ek_buttons[i].gpio, 1);
+ at91_set_deglitch(ek_buttons[i].gpio, 1);
+ }
+
+ platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
+/*
+ * LEDs ... these could all be PWM-driven, for variable brightness
+ */
+static struct gpio_led ek_leds[] = {
+ { /* "top" led, red, powerled */
+ .name = "d8",
+ .gpio = AT91_PIN_PD30,
+ .default_trigger = "heartbeat",
+ },
+ { /* "left" led, green, userled2, pwm3 */
+ .name = "d6",
+ .gpio = AT91_PIN_PD0,
+ .active_low = 1,
+ .default_trigger = "nand-disk",
+ },
+#if !(defined(CONFIG_LEDS_ATMEL_PWM) || defined(CONFIG_LEDS_ATMEL_PWM_MODULE))
+ { /* "right" led, green, userled1, pwm1 */
+ .name = "d7",
+ .gpio = AT91_PIN_PD31,
+ .active_low = 1,
+ .default_trigger = "mmc0",
+ },
+#endif
+};
+
+
+/*
+ * PWM Leds
+ */
+static struct gpio_led ek_pwm_led[] = {
+#if defined(CONFIG_LEDS_ATMEL_PWM) || defined(CONFIG_LEDS_ATMEL_PWM_MODULE)
+ { /* "right" led, green, userled1, pwm1 */
+ .name = "d7",
+ .gpio = 1, /* is PWM channel number */
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+#endif
+};
+
+
+
+static void __init ek_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* USB HS Host */
+ at91_add_device_usbh_ohci(&ek_usbh_hs_data);
+ /* USB HS Device */
+ at91_add_device_usba(&ek_usba_udc_data);
+ /* SPI */
+ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* NAND */
+ ek_add_device_nand();
+ /* I2C */
+ at91_add_device_i2c(0, NULL, 0);
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* Push Buttons */
+ ek_add_device_buttons();
+ /* LEDs */
+ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
+}
+
+MACHINE_START(AT91SAM9G45EKES, "Atmel AT91SAM9G45-EKES")
+ /* Maintainer: Atmel */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = ek_map_io,
+ .init_irq = ek_init_irq,
+ .init_machine = ek_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index f6b5672cabd6..94ffb5c103b9 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -15,6 +15,8 @@
#include <linux/spi/spi.h>
#include <linux/fb.h>
#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
#include <video/atmel_lcdc.h>
@@ -41,7 +43,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 12.000 MHz crystal */
at91sam9rl_initialize(12000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
@@ -208,6 +210,79 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
#endif
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+ { /* "bottom" led, green, userled1 to be defined */
+ .name = "ds1",
+ .gpio = AT91_PIN_PD15,
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+ { /* "bottom" led, green, userled2 to be defined */
+ .name = "ds2",
+ .gpio = AT91_PIN_PD16,
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+ { /* "power" led, yellow */
+ .name = "ds3",
+ .gpio = AT91_PIN_PD14,
+ .default_trigger = "heartbeat",
+ }
+};
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+ {
+ .gpio = AT91_PIN_PB0,
+ .code = BTN_2,
+ .desc = "Right Click",
+ .active_low = 1,
+ .wakeup = 1,
+ },
+ {
+ .gpio = AT91_PIN_PB1,
+ .code = BTN_1,
+ .desc = "Left Click",
+ .active_low = 1,
+ .wakeup = 1,
+ }
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+ .buttons = ek_buttons,
+ .nbuttons = ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ek_button_data,
+ }
+};
+
+static void __init ek_add_device_buttons(void)
+{
+ at91_set_gpio_input(AT91_PIN_PB1, 1); /* btn1 */
+ at91_set_deglitch(AT91_PIN_PB1, 1);
+ at91_set_gpio_input(AT91_PIN_PB0, 1); /* btn2 */
+ at91_set_deglitch(AT91_PIN_PB0, 1);
+
+ platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
static void __init ek_board_init(void)
{
/* Serial */
@@ -226,6 +301,10 @@ static void __init ek_board_init(void)
at91_add_device_lcdc(&ek_lcdc_data);
/* Touch Screen Controller */
at91_add_device_tsadcc();
+ /* LEDs */
+ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ /* Push Buttons */
+ ek_add_device_buttons();
}
MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
diff --git a/arch/arm/mach-at91/board-usb-a9260.c b/arch/arm/mach-at91/board-usb-a9260.c
index d13304c0bc45..905d6ef76807 100644
--- a/arch/arm/mach-at91/board-usb-a9260.c
+++ b/arch/arm/mach-at91/board-usb-a9260.c
@@ -53,7 +53,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 12.000 MHz crystal */
at91sam9260_initialize(12000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* set serial console to ttyS0 (ie, DBGU) */
diff --git a/arch/arm/mach-at91/board-usb-a9263.c b/arch/arm/mach-at91/board-usb-a9263.c
index d96405b7d578..b6a3480383e5 100644
--- a/arch/arm/mach-at91/board-usb-a9263.c
+++ b/arch/arm/mach-at91/board-usb-a9263.c
@@ -52,7 +52,7 @@ static void __init ek_map_io(void)
/* Initialize processor: 12.00 MHz crystal */
at91sam9263_initialize(12000000);
- /* DGBU on ttyS0. (Rx & Tx only) */
+ /* DBGU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
/* set serial console to ttyS0 (ie, DBGU) */
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index bac578fe0d3d..c042dcf4725f 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -47,20 +47,25 @@
* Chips have some kind of clocks : group them by functionality
*/
#define cpu_has_utmi() ( cpu_is_at91cap9() \
- || cpu_is_at91sam9rl())
+ || cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45())
-#define cpu_has_800M_plla() (cpu_is_at91sam9g20())
+#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
+ || cpu_is_at91sam9g45())
-#define cpu_has_pllb() (!cpu_is_at91sam9rl())
+#define cpu_has_300M_plla() (cpu_is_at91sam9g10())
-#define cpu_has_upll() (0)
+#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45()))
+
+#define cpu_has_upll() (cpu_is_at91sam9g45())
/* USB host HS & FS */
#define cpu_has_uhp() (!cpu_is_at91sam9rl())
/* USB device FS only */
-#define cpu_has_udpfs() (!cpu_is_at91sam9rl())
-
+#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45()))
static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clk_lock);
@@ -133,6 +138,13 @@ static void pmc_uckr_mode(struct clk *clk, int is_on)
{
unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+ if (cpu_is_at91sam9g45()) {
+ if (is_on)
+ uckr |= AT91_PMC_BIASEN;
+ else
+ uckr &= ~AT91_PMC_BIASEN;
+ }
+
if (is_on) {
is_on = AT91_PMC_LOCKU;
at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
@@ -310,6 +322,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
unsigned long flags;
unsigned prescale;
unsigned long actual;
+ unsigned long prev = ULONG_MAX;
if (!clk_is_programmable(clk))
return -EINVAL;
@@ -317,8 +330,16 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
actual = clk->parent->rate_hz;
for (prescale = 0; prescale < 7; prescale++) {
- if (actual && actual <= rate)
+ if (actual > rate)
+ prev = actual;
+
+ if (actual && actual <= rate) {
+ if ((prev - rate) < (rate - actual)) {
+ actual = prev;
+ prescale--;
+ }
break;
+ }
actual >>= 1;
}
@@ -373,6 +394,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
return -EBUSY;
if (!clk_is_primary(parent) || !clk_is_programmable(clk))
return -EINVAL;
+
+ if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB)
+ return -EINVAL;
+
spin_lock_irqsave(&clk_lock, flags);
clk->rate_hz = parent->rate_hz;
@@ -601,7 +626,9 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
uhpck.pmc_mask = AT91RM9200_PMC_UHP;
udpck.pmc_mask = AT91RM9200_PMC_UDP;
at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
- } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
+ cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
+ cpu_is_at91sam9g10()) {
uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
udpck.pmc_mask = AT91SAM926x_PMC_UDP;
} else if (cpu_is_at91cap9()) {
@@ -637,6 +664,7 @@ int __init at91_clock_init(unsigned long main_clock)
{
unsigned tmp, freq, mckr;
int i;
+ int pll_overclock = false;
/*
* When the bootloader initialized the main oscillator correctly,
@@ -654,12 +682,25 @@ int __init at91_clock_init(unsigned long main_clock)
/* report if PLLA is more than mildly overclocked */
plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
- if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000)
- || (cpu_has_800M_plla() && plla.rate_hz > 800000000))
+ if (cpu_has_300M_plla()) {
+ if (plla.rate_hz > 300000000)
+ pll_overclock = true;
+ } else if (cpu_has_800M_plla()) {
+ if (plla.rate_hz > 800000000)
+ pll_overclock = true;
+ } else {
+ if (plla.rate_hz > 209000000)
+ pll_overclock = true;
+ }
+ if (pll_overclock)
pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
+ if (cpu_is_at91sam9g45()) {
+ mckr = at91_sys_read(AT91_PMC_MCKR);
+ plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */
+ }
- if (cpu_has_upll() && !cpu_has_pllb()) {
+ if (!cpu_has_pllb() && cpu_has_upll()) {
/* setup UTMI clock as the fourth primary clock
* (instead of pllb) */
utmi_clk.type |= CLK_TYPE_PRIMARY;
@@ -701,6 +742,9 @@ int __init at91_clock_init(unsigned long main_clock)
freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
if (mckr & AT91_PMC_PDIV)
freq /= 2; /* processor clock division */
+ } else if (cpu_is_at91sam9g45()) {
+ mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
+ freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
} else {
mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
}
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index b5daf7f5e011..88e413b38480 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -14,6 +14,7 @@ extern void __init at91sam9260_initialize(unsigned long main_clock);
extern void __init at91sam9261_initialize(unsigned long main_clock);
extern void __init at91sam9263_initialize(unsigned long main_clock);
extern void __init at91sam9rl_initialize(unsigned long main_clock);
+extern void __init at91sam9g45_initialize(unsigned long main_clock);
extern void __init at91x40_initialize(unsigned long main_clock);
extern void __init at91cap9_initialize(unsigned long main_clock);
@@ -23,6 +24,7 @@ extern void __init at91sam9260_init_interrupts(unsigned int priority[]);
extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
+extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
extern void __init at91x40_init_interrupts(unsigned int priority[]);
extern void __init at91cap9_init_interrupts(unsigned int priority[]);
extern void __init at91_aic_init(unsigned int priority[]);
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index f2236f0e101f..ae4772e744ac 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -44,13 +44,11 @@ static int at91_gpiolib_direction_output(struct gpio_chip *chip,
unsigned offset, int val);
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset);
-static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio) \
{ \
.chip = { \
.label = name, \
- .request = at91_gpiolib_request, \
.direction_input = at91_gpiolib_direction_input, \
.direction_output = at91_gpiolib_direction_output, \
.get = at91_gpiolib_get, \
@@ -588,19 +586,6 @@ static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
__raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
}
-static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
-{
- unsigned pin = chip->base + offset;
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- /* Cannot request GPIOs that are in alternate function mode */
- if (!(__raw_readl(pio + PIO_PSR) & mask))
- return -EPERM;
-
- return 0;
-}
-
static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
int i;
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
index 3a348ca20773..87de8be17484 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
@@ -95,6 +95,9 @@
#define AT91SAM9261_SRAM_BASE 0x00300000 /* Internal SRAM base address */
#define AT91SAM9261_SRAM_SIZE 0x00028000 /* Internal SRAM size (160Kb) */
+#define AT91SAM9G10_SRAM_BASE AT91SAM9261_SRAM_BASE /* Internal SRAM base address */
+#define AT91SAM9G10_SRAM_SIZE 0x00004000 /* Internal SRAM size (16Kb) */
+
#define AT91SAM9261_ROM_BASE 0x00400000 /* Internal ROM base address */
#define AT91SAM9261_ROM_SIZE SZ_32K /* Internal ROM size (32Kb) */
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
new file mode 100644
index 000000000000..a526869aee37
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
@@ -0,0 +1,155 @@
+/*
+ * Chip-specific header file for the AT91SAM9G45 family
+ *
+ * Copyright (C) 2008-2009 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91SAM9G45 preliminary datasheet.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AT91SAM9G45_H
+#define AT91SAM9G45_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS 1 /* System Controller Interrupt */
+#define AT91SAM9G45_ID_PIOA 2 /* Parallel I/O Controller A */
+#define AT91SAM9G45_ID_PIOB 3 /* Parallel I/O Controller B */
+#define AT91SAM9G45_ID_PIOC 4 /* Parallel I/O Controller C */
+#define AT91SAM9G45_ID_PIODE 5 /* Parallel I/O Controller D and E */
+#define AT91SAM9G45_ID_TRNG 6 /* True Random Number Generator */
+#define AT91SAM9G45_ID_US0 7 /* USART 0 */
+#define AT91SAM9G45_ID_US1 8 /* USART 1 */
+#define AT91SAM9G45_ID_US2 9 /* USART 2 */
+#define AT91SAM9G45_ID_US3 10 /* USART 3 */
+#define AT91SAM9G45_ID_MCI0 11 /* High Speed Multimedia Card Interface 0 */
+#define AT91SAM9G45_ID_TWI0 12 /* Two-Wire Interface 0 */
+#define AT91SAM9G45_ID_TWI1 13 /* Two-Wire Interface 1 */
+#define AT91SAM9G45_ID_SPI0 14 /* Serial Peripheral Interface 0 */
+#define AT91SAM9G45_ID_SPI1 15 /* Serial Peripheral Interface 1 */
+#define AT91SAM9G45_ID_SSC0 16 /* Synchronous Serial Controller 0 */
+#define AT91SAM9G45_ID_SSC1 17 /* Synchronous Serial Controller 1 */
+#define AT91SAM9G45_ID_TCB 18 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9G45_ID_PWMC 19 /* Pulse Width Modulation Controller */
+#define AT91SAM9G45_ID_TSC 20 /* Touch Screen ADC Controller */
+#define AT91SAM9G45_ID_DMA 21 /* DMA Controller */
+#define AT91SAM9G45_ID_UHPHS 22 /* USB Host High Speed */
+#define AT91SAM9G45_ID_LCDC 23 /* LCD Controller */
+#define AT91SAM9G45_ID_AC97C 24 /* AC97 Controller */
+#define AT91SAM9G45_ID_EMAC 25 /* Ethernet MAC */
+#define AT91SAM9G45_ID_ISI 26 /* Image Sensor Interface */
+#define AT91SAM9G45_ID_UDPHS 27 /* USB Device High Speed */
+#define AT91SAM9G45_ID_AESTDESSHA 28 /* AES + T-DES + SHA */
+#define AT91SAM9G45_ID_MCI1 29 /* High Speed Multimedia Card Interface 1 */
+#define AT91SAM9G45_ID_VDEC 30 /* Video Decoder */
+#define AT91SAM9G45_ID_IRQ0 31 /* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9G45_BASE_UDPHS 0xfff78000
+#define AT91SAM9G45_BASE_TCB0 0xfff7c000
+#define AT91SAM9G45_BASE_TC0 0xfff7c000
+#define AT91SAM9G45_BASE_TC1 0xfff7c040
+#define AT91SAM9G45_BASE_TC2 0xfff7c080
+#define AT91SAM9G45_BASE_MCI0 0xfff80000
+#define AT91SAM9G45_BASE_TWI0 0xfff84000
+#define AT91SAM9G45_BASE_TWI1 0xfff88000
+#define AT91SAM9G45_BASE_US0 0xfff8c000
+#define AT91SAM9G45_BASE_US1 0xfff90000
+#define AT91SAM9G45_BASE_US2 0xfff94000
+#define AT91SAM9G45_BASE_US3 0xfff98000
+#define AT91SAM9G45_BASE_SSC0 0xfff9c000
+#define AT91SAM9G45_BASE_SSC1 0xfffa0000
+#define AT91SAM9G45_BASE_SPI0 0xfffa4000
+#define AT91SAM9G45_BASE_SPI1 0xfffa8000
+#define AT91SAM9G45_BASE_AC97C 0xfffac000
+#define AT91SAM9G45_BASE_TSC 0xfffb0000
+#define AT91SAM9G45_BASE_ISI 0xfffb4000
+#define AT91SAM9G45_BASE_PWMC 0xfffb8000
+#define AT91SAM9G45_BASE_EMAC 0xfffbc000
+#define AT91SAM9G45_BASE_AES 0xfffc0000
+#define AT91SAM9G45_BASE_TDES 0xfffc4000
+#define AT91SAM9G45_BASE_SHA 0xfffc8000
+#define AT91SAM9G45_BASE_TRNG 0xfffcc000
+#define AT91SAM9G45_BASE_MCI1 0xfffd0000
+#define AT91SAM9G45_BASE_TCB1 0xfffd4000
+#define AT91SAM9G45_BASE_TC3 0xfffd4000
+#define AT91SAM9G45_BASE_TC4 0xfffd4040
+#define AT91SAM9G45_BASE_TC5 0xfffd4080
+#define AT91_BASE_SYS 0xffffe200
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_ECC (0xffffe200 - AT91_BASE_SYS)
+#define AT91_DDRSDRC1 (0xffffe400 - AT91_BASE_SYS)
+#define AT91_DDRSDRC0 (0xffffe600 - AT91_BASE_SYS)
+#define AT91_SMC (0xffffe800 - AT91_BASE_SYS)
+#define AT91_MATRIX (0xffffea00 - AT91_BASE_SYS)
+#define AT91_DMA (0xffffec00 - AT91_BASE_SYS)
+#define AT91_DBGU (0xffffee00 - AT91_BASE_SYS)
+#define AT91_AIC (0xfffff000 - AT91_BASE_SYS)
+#define AT91_PIOA (0xfffff200 - AT91_BASE_SYS)
+#define AT91_PIOB (0xfffff400 - AT91_BASE_SYS)
+#define AT91_PIOC (0xfffff600 - AT91_BASE_SYS)
+#define AT91_PIOD (0xfffff800 - AT91_BASE_SYS)
+#define AT91_PIOE (0xfffffa00 - AT91_BASE_SYS)
+#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS)
+#define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS)
+#define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS)
+#define AT91_RTT (0xfffffd20 - AT91_BASE_SYS)
+#define AT91_PIT (0xfffffd30 - AT91_BASE_SYS)
+#define AT91_WDT (0xfffffd40 - AT91_BASE_SYS)
+#define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS)
+#define AT91_RTC (0xfffffdb0 - AT91_BASE_SYS)
+
+#define AT91_USART0 AT91SAM9G45_BASE_US0
+#define AT91_USART1 AT91SAM9G45_BASE_US1
+#define AT91_USART2 AT91SAM9G45_BASE_US2
+#define AT91_USART3 AT91SAM9G45_BASE_US3
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9G45_SRAM_BASE 0x00300000 /* Internal SRAM base address */
+#define AT91SAM9G45_SRAM_SIZE SZ_64K /* Internal SRAM size (64Kb) */
+
+#define AT91SAM9G45_ROM_BASE 0x00400000 /* Internal ROM base address */
+#define AT91SAM9G45_ROM_SIZE SZ_64K /* Internal ROM size (64Kb) */
+
+#define AT91SAM9G45_LCDC_BASE 0x00500000 /* LCD Controller */
+#define AT91SAM9G45_UDPHS_FIFO 0x00600000 /* USB Device HS controller */
+#define AT91SAM9G45_OHCI_BASE 0x00700000 /* USB Host controller (OHCI) */
+#define AT91SAM9G45_EHCI_BASE 0x00800000 /* USB Host controller (EHCI) */
+#define AT91SAM9G45_VDEC_BASE 0x00900000 /* Video Decoder Controller */
+
+#define CONFIG_DRAM_BASE AT91_CHIPSELECT_6
+
+#define CONSISTENT_DMA_SIZE SZ_4M
+
+/*
+ * DMA peripheral identifiers
+ * for hardware handshaking interface
+ */
+#define AT_DMA_ID_MCI0 0
+#define AT_DMA_ID_SPI0_TX 1
+#define AT_DMA_ID_SPI0_RX 2
+#define AT_DMA_ID_SPI1_TX 3
+#define AT_DMA_ID_SPI1_RX 4
+#define AT_DMA_ID_SSC0_TX 5
+#define AT_DMA_ID_SSC0_RX 6
+#define AT_DMA_ID_SSC1_TX 7
+#define AT_DMA_ID_SSC1_RX 8
+#define AT_DMA_ID_AC97_TX 9
+#define AT_DMA_ID_AC97_RX 10
+#define AT_DMA_ID_MCI1 13
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
new file mode 100644
index 000000000000..c972d60e0aeb
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
@@ -0,0 +1,153 @@
+/*
+ * Matrix-centric header file for the AT91SAM9G45 family
+ *
+ * Copyright (C) 2008-2009 Atmel Corporation.
+ *
+ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
+ * Based on AT91SAM9G45 preliminary datasheet.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AT91SAM9G45_MATRIX_H
+#define AT91SAM9G45_MATRIX_H
+
+#define AT91_MATRIX_MCFG0 (AT91_MATRIX + 0x00) /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1 (AT91_MATRIX + 0x04) /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6 (AT91_MATRIX + 0x18) /* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7 (AT91_MATRIX + 0x1C) /* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8 (AT91_MATRIX + 0x20) /* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG9 (AT91_MATRIX + 0x24) /* Master Configuration Register 9 */
+#define AT91_MATRIX_MCFG10 (AT91_MATRIX + 0x28) /* Master Configuration Register 10 */
+#define AT91_MATRIX_MCFG11 (AT91_MATRIX + 0x2C) /* Master Configuration Register 11 */
+#define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */
+#define AT91_MATRIX_ULBT_INFINITE (0 << 0)
+#define AT91_MATRIX_ULBT_SINGLE (1 << 0)
+#define AT91_MATRIX_ULBT_FOUR (2 << 0)
+#define AT91_MATRIX_ULBT_EIGHT (3 << 0)
+#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0)
+#define AT91_MATRIX_ULBT_THIRTYTWO (5 << 0)
+#define AT91_MATRIX_ULBT_SIXTYFOUR (6 << 0)
+#define AT91_MATRIX_ULBT_128 (7 << 0)
+
+#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x40) /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x44) /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2 (AT91_MATRIX + 0x48) /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3 (AT91_MATRIX + 0x4C) /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4 (AT91_MATRIX + 0x50) /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5 (AT91_MATRIX + 0x54) /* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6 (AT91_MATRIX + 0x58) /* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7 (AT91_MATRIX + 0x5C) /* Slave Configuration Register 7 */
+#define AT91_MATRIX_SLOT_CYCLE (0x1ff << 0) /* Maximum Number of Allowed Cycles for a Burst */
+#define AT91_MATRIX_DEFMSTR_TYPE (3 << 16) /* Default Master Type */
+#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16)
+#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16)
+#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16)
+#define AT91_MATRIX_FIXED_DEFMSTR (0xf << 18) /* Fixed Index of Default Master */
+
+#define AT91_MATRIX_PRAS0 (AT91_MATRIX + 0x80) /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0 (AT91_MATRIX + 0x84) /* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1 (AT91_MATRIX + 0x88) /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1 (AT91_MATRIX + 0x8C) /* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2 (AT91_MATRIX + 0x90) /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2 (AT91_MATRIX + 0x94) /* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3 (AT91_MATRIX + 0x98) /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3 (AT91_MATRIX + 0x9C) /* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4 (AT91_MATRIX + 0xA0) /* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4 (AT91_MATRIX + 0xA4) /* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5 (AT91_MATRIX + 0xA8) /* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5 (AT91_MATRIX + 0xAC) /* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6 (AT91_MATRIX + 0xB0) /* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6 (AT91_MATRIX + 0xB4) /* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7 (AT91_MATRIX + 0xB8) /* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7 (AT91_MATRIX + 0xBC) /* Priority Register B for Slave 7 */
+#define AT91_MATRIX_M0PR (3 << 0) /* Master 0 Priority */
+#define AT91_MATRIX_M1PR (3 << 4) /* Master 1 Priority */
+#define AT91_MATRIX_M2PR (3 << 8) /* Master 2 Priority */
+#define AT91_MATRIX_M3PR (3 << 12) /* Master 3 Priority */
+#define AT91_MATRIX_M4PR (3 << 16) /* Master 4 Priority */
+#define AT91_MATRIX_M5PR (3 << 20) /* Master 5 Priority */
+#define AT91_MATRIX_M6PR (3 << 24) /* Master 6 Priority */
+#define AT91_MATRIX_M7PR (3 << 28) /* Master 7 Priority */
+#define AT91_MATRIX_M8PR (3 << 0) /* Master 8 Priority (in Register B) */
+#define AT91_MATRIX_M9PR (3 << 4) /* Master 9 Priority (in Register B) */
+#define AT91_MATRIX_M10PR (3 << 8) /* Master 10 Priority (in Register B) */
+#define AT91_MATRIX_M11PR (3 << 12) /* Master 11 Priority (in Register B) */
+
+#define AT91_MATRIX_MRCR (AT91_MATRIX + 0x100) /* Master Remap Control Register */
+#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
+#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
+#define AT91_MATRIX_RCB2 (1 << 2)
+#define AT91_MATRIX_RCB3 (1 << 3)
+#define AT91_MATRIX_RCB4 (1 << 4)
+#define AT91_MATRIX_RCB5 (1 << 5)
+#define AT91_MATRIX_RCB6 (1 << 6)
+#define AT91_MATRIX_RCB7 (1 << 7)
+#define AT91_MATRIX_RCB8 (1 << 8)
+#define AT91_MATRIX_RCB9 (1 << 9)
+#define AT91_MATRIX_RCB10 (1 << 10)
+#define AT91_MATRIX_RCB11 (1 << 11)
+
+#define AT91_MATRIX_TCMR (AT91_MATRIX + 0x110) /* TCM Configuration Register */
+#define AT91_MATRIX_ITCM_SIZE (0xf << 0) /* Size of ITCM enabled memory block */
+#define AT91_MATRIX_ITCM_0 (0 << 0)
+#define AT91_MATRIX_ITCM_32 (6 << 0)
+#define AT91_MATRIX_DTCM_SIZE (0xf << 4) /* Size of DTCM enabled memory block */
+#define AT91_MATRIX_DTCM_0 (0 << 4)
+#define AT91_MATRIX_DTCM_32 (6 << 4)
+#define AT91_MATRIX_DTCM_64 (7 << 4)
+#define AT91_MATRIX_TCM_NWS (0x1 << 11) /* Wait state TCM register */
+#define AT91_MATRIX_TCM_NO_WS (0x0 << 11)
+#define AT91_MATRIX_TCM_ONE_WS (0x1 << 11)
+
+#define AT91_MATRIX_VIDEO (AT91_MATRIX + 0x118) /* Video Mode Configuration Register */
+#define AT91C_VDEC_SEL (0x1 << 0) /* Video Mode Selection */
+#define AT91C_VDEC_SEL_OFF (0 << 0)
+#define AT91C_VDEC_SEL_ON (1 << 0)
+
+#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x128) /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
+#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1)
+#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1)
+#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */
+#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3)
+#define AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA (1 << 3)
+#define AT91_MATRIX_EBI_CS4A (1 << 4) /* Chip Select 4 Assignment */
+#define AT91_MATRIX_EBI_CS4A_SMC (0 << 4)
+#define AT91_MATRIX_EBI_CS4A_SMC_CF0 (1 << 4)
+#define AT91_MATRIX_EBI_CS5A (1 << 5) /* Chip Select 5 Assignment */
+#define AT91_MATRIX_EBI_CS5A_SMC (0 << 5)
+#define AT91_MATRIX_EBI_CS5A_SMC_CF1 (1 << 5)
+#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */
+#define AT91_MATRIX_EBI_DBPU_ON (0 << 8)
+#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8)
+#define AT91_MATRIX_EBI_VDDIOMSEL (1 << 16) /* Memory voltage selection */
+#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16)
+#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16)
+#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */
+#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17)
+#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17)
+#define AT91_MATRIX_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */
+#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18)
+#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18)
+
+#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */
+#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */
+#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0)
+#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0)
+#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */
+#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */
+#define AT91_MATRIX_WPSR_NO_WPV (0 << 0)
+#define AT91_MATRIX_WPSR_WPV (1 << 0)
+#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
new file mode 100644
index 000000000000..187cb58345c0
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
@@ -0,0 +1,102 @@
+/*
+ * Header file for the Atmel AHB DMA Controller driver
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef AT_HDMAC_H
+#define AT_HDMAC_H
+
+#include <linux/dmaengine.h>
+
+/**
+ * struct at_dma_platform_data - Controller configuration parameters
+ * @nr_channels: Number of channels supported by hardware (max 8)
+ * @cap_mask: dma_capability flags supported by the platform
+ */
+struct at_dma_platform_data {
+ unsigned int nr_channels;
+ dma_cap_mask_t cap_mask;
+};
+
+/**
+ * enum at_dma_slave_width - DMA slave register access width.
+ * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses
+ * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses
+ * @AT_DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses
+ */
+enum at_dma_slave_width {
+ AT_DMA_SLAVE_WIDTH_8BIT = 0,
+ AT_DMA_SLAVE_WIDTH_16BIT,
+ AT_DMA_SLAVE_WIDTH_32BIT,
+};
+
+/**
+ * struct at_dma_slave - Controller-specific information about a slave
+ * @dma_dev: required DMA master device
+ * @tx_reg: physical address of data register used for
+ * memory-to-peripheral transfers
+ * @rx_reg: physical address of data register used for
+ * peripheral-to-memory transfers
+ * @reg_width: peripheral register width
+ * @cfg: Platform-specific initializer for the CFG register
+ * @ctrla: Platform-specific initializer for the CTRLA register
+ */
+struct at_dma_slave {
+ struct device *dma_dev;
+ dma_addr_t tx_reg;
+ dma_addr_t rx_reg;
+ enum at_dma_slave_width reg_width;
+ u32 cfg;
+ u32 ctrla;
+};
+
+
+/* Platform-configurable bits in CFG */
+#define ATC_SRC_PER(h) (0xFU & (h)) /* Channel src rq associated with periph handshaking ifc h */
+#define ATC_DST_PER(h) ((0xFU & (h)) << 4) /* Channel dst rq associated with periph handshaking ifc h */
+#define ATC_SRC_REP (0x1 << 8) /* Source Replay Mod */
+#define ATC_SRC_H2SEL (0x1 << 9) /* Source Handshaking Mod */
+#define ATC_SRC_H2SEL_SW (0x0 << 9)
+#define ATC_SRC_H2SEL_HW (0x1 << 9)
+#define ATC_DST_REP (0x1 << 12) /* Destination Replay Mod */
+#define ATC_DST_H2SEL (0x1 << 13) /* Destination Handshaking Mod */
+#define ATC_DST_H2SEL_SW (0x0 << 13)
+#define ATC_DST_H2SEL_HW (0x1 << 13)
+#define ATC_SOD (0x1 << 16) /* Stop On Done */
+#define ATC_LOCK_IF (0x1 << 20) /* Interface Lock */
+#define ATC_LOCK_B (0x1 << 21) /* AHB Bus Lock */
+#define ATC_LOCK_IF_L (0x1 << 22) /* Master Interface Arbiter Lock */
+#define ATC_LOCK_IF_L_CHUNK (0x0 << 22)
+#define ATC_LOCK_IF_L_BUFFER (0x1 << 22)
+#define ATC_AHB_PROT_MASK (0x7 << 24) /* AHB Protection */
+#define ATC_FIFOCFG_MASK (0x3 << 28) /* FIFO Request Configuration */
+#define ATC_FIFOCFG_LARGESTBURST (0x0 << 28)
+#define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
+#define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28)
+
+/* Platform-configurable bits in CTRLA */
+#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
+#define ATC_SCSIZE_1 (0x0 << 16)
+#define ATC_SCSIZE_4 (0x1 << 16)
+#define ATC_SCSIZE_8 (0x2 << 16)
+#define ATC_SCSIZE_16 (0x3 << 16)
+#define ATC_SCSIZE_32 (0x4 << 16)
+#define ATC_SCSIZE_64 (0x5 << 16)
+#define ATC_SCSIZE_128 (0x6 << 16)
+#define ATC_SCSIZE_256 (0x7 << 16)
+#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
+#define ATC_DCSIZE_1 (0x0 << 20)
+#define ATC_DCSIZE_4 (0x1 << 20)
+#define ATC_DCSIZE_8 (0x2 << 20)
+#define ATC_DCSIZE_16 (0x3 << 20)
+#define ATC_DCSIZE_32 (0x4 << 20)
+#define ATC_DCSIZE_64 (0x5 << 20)
+#define ATC_DCSIZE_128 (0x6 << 20)
+#define ATC_DCSIZE_256 (0x7 << 20)
+
+#endif /* AT_HDMAC_H */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index e6afff849b85..74801d275cdc 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -80,7 +80,8 @@ struct at91_eth_data {
};
extern void __init at91_add_device_eth(struct at91_eth_data *data);
-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9)
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \
+ || defined(CONFIG_ARCH_AT91SAM9G45)
#define eth_platform_data at91_eth_data
#endif
@@ -90,6 +91,7 @@ struct at91_usbh_data {
u8 vbus_pin[2]; /* port power-control pin */
};
extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
+extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
/* NAND / SmartMedia */
struct atmel_nand_data {
@@ -105,7 +107,11 @@ struct atmel_nand_data {
extern void __init at91_add_device_nand(struct atmel_nand_data *data);
/* I2C*/
+#if defined(CONFIG_ARCH_AT91SAM9G45)
+extern void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices);
+#else
extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices);
+#endif
/* SPI */
extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index c554c3e4d553..34a9502c48bc 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -21,8 +21,10 @@
#define ARCH_ID_AT91SAM9260 0x019803a0
#define ARCH_ID_AT91SAM9261 0x019703a0
#define ARCH_ID_AT91SAM9263 0x019607a0
+#define ARCH_ID_AT91SAM9G10 0x819903a0
#define ARCH_ID_AT91SAM9G20 0x019905a0
#define ARCH_ID_AT91SAM9RL64 0x019b03a0
+#define ARCH_ID_AT91SAM9G45 0x819b05a0
#define ARCH_ID_AT91CAP9 0x039A03A0
#define ARCH_ID_AT91SAM9XE128 0x329973a0
@@ -39,6 +41,15 @@ static inline unsigned long at91_cpu_identify(void)
return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION);
}
+#define ARCH_EXID_AT91SAM9M11 0x00000001
+#define ARCH_EXID_AT91SAM9M10 0x00000002
+#define ARCH_EXID_AT91SAM9G45 0x00000004
+
+static inline unsigned long at91_exid_identify(void)
+{
+ return at91_sys_read(AT91_DBGU_EXID);
+}
+
#define ARCH_FAMILY_AT91X92 0x09200000
#define ARCH_FAMILY_AT91SAM9 0x01900000
@@ -87,6 +98,12 @@ static inline unsigned long at91cap9_rev_identify(void)
#define cpu_is_at91sam9261() (0)
#endif
+#ifdef CONFIG_ARCH_AT91SAM9G10
+#define cpu_is_at91sam9g10() (at91_cpu_identify() == ARCH_ID_AT91SAM9G10)
+#else
+#define cpu_is_at91sam9g10() (0)
+#endif
+
#ifdef CONFIG_ARCH_AT91SAM9263
#define cpu_is_at91sam9263() (at91_cpu_identify() == ARCH_ID_AT91SAM9263)
#else
@@ -99,6 +116,12 @@ static inline unsigned long at91cap9_rev_identify(void)
#define cpu_is_at91sam9rl() (0)
#endif
+#ifdef CONFIG_ARCH_AT91SAM9G45
+#define cpu_is_at91sam9g45() (at91_cpu_identify() == ARCH_ID_AT91SAM9G45)
+#else
+#define cpu_is_at91sam9g45() (0)
+#endif
+
#ifdef CONFIG_ARCH_AT91CAP9
#define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9)
#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index da0b681c652c..a0df8b022df2 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -20,12 +20,14 @@
#include <mach/at91rm9200.h>
#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
#include <mach/at91sam9260.h>
-#elif defined(CONFIG_ARCH_AT91SAM9261)
+#elif defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10)
#include <mach/at91sam9261.h>
#elif defined(CONFIG_ARCH_AT91SAM9263)
#include <mach/at91sam9263.h>
#elif defined(CONFIG_ARCH_AT91SAM9RL)
#include <mach/at91sam9rl.h>
+#elif defined(CONFIG_ARCH_AT91SAM9G45)
+#include <mach/at91sam9g45.h>
#elif defined(CONFIG_ARCH_AT91CAP9)
#include <mach/at91cap9.h>
#elif defined(CONFIG_ARCH_AT91X40)
diff --git a/arch/arm/mach-at91/include/mach/timex.h b/arch/arm/mach-at91/include/mach/timex.h
index d84c9948becf..31ac2d97f14c 100644
--- a/arch/arm/mach-at91/include/mach/timex.h
+++ b/arch/arm/mach-at91/include/mach/timex.h
@@ -42,6 +42,11 @@
#define AT91SAM9_MASTER_CLOCK 99300000
#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+#elif defined(CONFIG_ARCH_AT91SAM9G10)
+
+#define AT91SAM9_MASTER_CLOCK 133000000
+#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+
#elif defined(CONFIG_ARCH_AT91SAM9263)
#if defined(CONFIG_MACH_USB_A9263)
@@ -62,6 +67,11 @@
#define AT91SAM9_MASTER_CLOCK 132096000
#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+#elif defined(CONFIG_ARCH_AT91SAM9G45)
+
+#define AT91SAM9_MASTER_CLOCK 133333333
+#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+
#elif defined(CONFIG_ARCH_AT91CAP9)
#define AT91CAP9_MASTER_CLOCK 100000000
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index e26c4fe61fae..4028724d490d 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -201,7 +201,8 @@ static int at91_pm_verify_clocks(void)
pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
return 0;
}
- } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()
+ || cpu_is_at91sam9g20() || cpu_is_at91sam9g10()) {
if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) {
pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
return 0;
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index be747f5c6cd8..40866c643f13 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -6,6 +6,9 @@ config AINTC
config CP_INTC
bool
+config ARCH_DAVINCI_DMx
+ bool
+
menu "TI DaVinci Implementations"
comment "DaVinci Core Type"
@@ -13,20 +16,41 @@ comment "DaVinci Core Type"
config ARCH_DAVINCI_DM644x
bool "DaVinci 644x based system"
select AINTC
+ select ARCH_DAVINCI_DMx
config ARCH_DAVINCI_DM355
bool "DaVinci 355 based system"
select AINTC
+ select ARCH_DAVINCI_DMx
config ARCH_DAVINCI_DM646x
bool "DaVinci 646x based system"
select AINTC
+ select ARCH_DAVINCI_DMx
+
+config ARCH_DAVINCI_DA830
+ bool "DA830/OMAP-L137 based system"
+ select CP_INTC
+ select ARCH_DAVINCI_DA8XX
+
+config ARCH_DAVINCI_DA850
+ bool "DA850/OMAP-L138 based system"
+ select CP_INTC
+ select ARCH_DAVINCI_DA8XX
+
+config ARCH_DAVINCI_DA8XX
+ bool
+
+config ARCH_DAVINCI_DM365
+ bool "DaVinci 365 based system"
+ select AINTC
+ select ARCH_DAVINCI_DMx
comment "DaVinci Board Type"
config MACH_DAVINCI_EVM
bool "TI DM644x EVM"
- default y
+ default ARCH_DAVINCI_DM644x
depends on ARCH_DAVINCI_DM644x
help
Configure this option to specify the whether the board used
@@ -41,6 +65,7 @@ config MACH_SFFSDR
config MACH_DAVINCI_DM355_EVM
bool "TI DM355 EVM"
+ default ARCH_DAVINCI_DM355
depends on ARCH_DAVINCI_DM355
help
Configure this option to specify the whether the board used
@@ -55,11 +80,33 @@ config MACH_DM355_LEOPARD
config MACH_DAVINCI_DM6467_EVM
bool "TI DM6467 EVM"
+ default ARCH_DAVINCI_DM646x
depends on ARCH_DAVINCI_DM646x
help
Configure this option to specify the whether the board used
for development is a DM6467 EVM
+config MACH_DAVINCI_DM365_EVM
+ bool "TI DM365 EVM"
+ default ARCH_DAVINCI_DM365
+ depends on ARCH_DAVINCI_DM365
+ help
+ Configure this option to specify whether the board used
+ for development is a DM365 EVM
+
+config MACH_DAVINCI_DA830_EVM
+ bool "TI DA830/OMAP-L137 Reference Platform"
+ default ARCH_DAVINCI_DA830
+ depends on ARCH_DAVINCI_DA830
+ help
+ Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+
+config MACH_DAVINCI_DA850_EVM
+ bool "TI DA850/OMAP-L138 Reference Platform"
+ default ARCH_DAVINCI_DA850
+ depends on ARCH_DAVINCI_DA850
+ help
+ Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
config DAVINCI_MUX
bool "DAVINCI multiplexing support"
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 059ab78084ba..2e11e847313b 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,14 +5,17 @@
# Common objects
obj-y := time.o clock.o serial.o io.o psc.o \
- gpio.o devices.o dma.o usb.o common.o sram.o
+ gpio.o dma.o usb.o common.o sram.o
obj-$(CONFIG_DAVINCI_MUX) += mux.o
# Chip specific
-obj-$(CONFIG_ARCH_DAVINCI_DM644x) += dm644x.o
-obj-$(CONFIG_ARCH_DAVINCI_DM355) += dm355.o
-obj-$(CONFIG_ARCH_DAVINCI_DM646x) += dm646x.o
+obj-$(CONFIG_ARCH_DAVINCI_DM644x) += dm644x.o devices.o
+obj-$(CONFIG_ARCH_DAVINCI_DM355) += dm355.o devices.o
+obj-$(CONFIG_ARCH_DAVINCI_DM646x) += dm646x.o devices.o
+obj-$(CONFIG_ARCH_DAVINCI_DM365) += dm365.o devices.o
+obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o
+obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o
obj-$(CONFIG_AINTC) += irq.o
obj-$(CONFIG_CP_INTC) += cp_intc.o
@@ -23,3 +26,6 @@ obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o
obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o
obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o
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
diff --git a/arch/arm/mach-davinci/Makefile.boot b/arch/arm/mach-davinci/Makefile.boot
index e1dd366f836b..db97ef2c6477 100644
--- a/arch/arm/mach-davinci/Makefile.boot
+++ b/arch/arm/mach-davinci/Makefile.boot
@@ -1,3 +1,13 @@
+ifeq ($(CONFIG_ARCH_DAVINCI_DA8XX),y)
+ifeq ($(CONFIG_ARCH_DAVINCI_DMx),y)
+$(error Cannot enable DaVinci and DA8XX platforms concurrently)
+else
+ zreladdr-y := 0xc0008000
+params_phys-y := 0xc0000100
+initrd_phys-y := 0xc0800000
+endif
+else
zreladdr-y := 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000
+endif
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
new file mode 100644
index 000000000000..90256693b8d8
--- /dev/null
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -0,0 +1,127 @@
+/*
+ * TI DA830/OMAP L137 EVM board
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ * Derived from: arch/arm/mach-davinci/board-dm644x-evm.c
+ *
+ * 2007, 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/i2c.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/da8xx.h>
+
+#define DA830_EVM_PHY_MASK 0x0
+#define DA830_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+
+static struct at24_platform_data da830_evm_i2c_eeprom_info = {
+ .byte_len = SZ_256K / 8,
+ .page_size = 64,
+ .flags = AT24_FLAG_ADDR16,
+ .setup = davinci_get_mac_addr,
+ .context = (void *)0x7f00,
+};
+
+static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("24c256", 0x50),
+ .platform_data = &da830_evm_i2c_eeprom_info,
+ },
+};
+
+static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+static struct davinci_uart_config da830_evm_uart_config __initdata = {
+ .enabled_uarts = 0x7,
+};
+
+static __init void da830_evm_init(void)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int ret;
+
+ ret = da8xx_register_edma();
+ if (ret)
+ pr_warning("da830_evm_init: edma registration failed: %d\n",
+ ret);
+
+ ret = da8xx_pinmux_setup(da830_i2c0_pins);
+ if (ret)
+ pr_warning("da830_evm_init: i2c0 mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_i2c(0, &da830_evm_i2c_0_pdata);
+ if (ret)
+ pr_warning("da830_evm_init: i2c0 registration failed: %d\n",
+ ret);
+
+ 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;
+
+ ret = da8xx_pinmux_setup(da830_cpgmac_pins);
+ if (ret)
+ pr_warning("da830_evm_init: cpgmac mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("da830_evm_init: emac registration failed: %d\n",
+ ret);
+
+ ret = da8xx_register_watchdog();
+ if (ret)
+ pr_warning("da830_evm_init: watchdog registration failed: %d\n",
+ ret);
+
+ davinci_serial_init(&da830_evm_uart_config);
+ i2c_register_board_info(1, da830_evm_i2c_devices,
+ ARRAY_SIZE(da830_evm_i2c_devices));
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init da830_evm_console_init(void)
+{
+ return add_preferred_console("ttyS", 2, "115200");
+}
+console_initcall(da830_evm_console_init);
+#endif
+
+static __init void da830_evm_irq_init(void)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ cp_intc_init((void __iomem *)DA8XX_CP_INTC_VIRT, DA830_N_CP_INTC_IRQ,
+ soc_info->intc_irq_prios);
+}
+
+static void __init da830_evm_map_io(void)
+{
+ da830_init();
+}
+
+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),
+ .map_io = da830_evm_map_io,
+ .init_irq = da830_evm_irq_init,
+ .timer = &davinci_timer,
+ .init_machine = da830_evm_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
new file mode 100644
index 000000000000..d98934629604
--- /dev/null
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -0,0 +1,120 @@
+/*
+ * TI DA850/OMAP-L138 EVM board
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Derived from: arch/arm/mach-davinci/board-da830-evm.c
+ * Original Copyrights follow:
+ *
+ * 2007, 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/i2c.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/da8xx.h>
+
+#define DA850_EVM_PHY_MASK 0x1
+#define DA850_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+
+static struct davinci_i2c_platform_data da850_evm_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+static struct davinci_uart_config da850_evm_uart_config __initdata = {
+ .enabled_uarts = 0x7,
+};
+
+static __init void da850_evm_init(void)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int ret;
+
+ ret = da8xx_register_edma();
+ if (ret)
+ pr_warning("da850_evm_init: edma registration failed: %d\n",
+ ret);
+
+ ret = da8xx_pinmux_setup(da850_i2c0_pins);
+ if (ret)
+ pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_i2c(0, &da850_evm_i2c_0_pdata);
+ if (ret)
+ pr_warning("da850_evm_init: i2c0 registration failed: %d\n",
+ ret);
+
+ soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
+ soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+ soc_info->emac_pdata->rmii_en = 0;
+
+ ret = da8xx_pinmux_setup(da850_cpgmac_pins);
+ if (ret)
+ pr_warning("da850_evm_init: cpgmac mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("da850_evm_init: emac registration failed: %d\n",
+ ret);
+
+ ret = da8xx_register_watchdog();
+ if (ret)
+ pr_warning("da830_evm_init: watchdog registration failed: %d\n",
+ ret);
+
+ davinci_serial_init(&da850_evm_uart_config);
+
+ /*
+ * shut down uart 0 and 1; they are not used on the board and
+ * accessing them causes endless "too much work in irq53" messages
+ * with arago fs
+ */
+ __raw_writel(0, IO_ADDRESS(DA8XX_UART1_BASE) + 0x30);
+ __raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init da850_evm_console_init(void)
+{
+ return add_preferred_console("ttyS", 2, "115200");
+}
+console_initcall(da850_evm_console_init);
+#endif
+
+static __init void da850_evm_irq_init(void)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ cp_intc_init((void __iomem *)DA8XX_CP_INTC_VIRT, DA850_N_CP_INTC_IRQ,
+ soc_info->intc_irq_prios);
+}
+
+static void __init da850_evm_map_io(void)
+{
+ da850_init();
+}
+
+MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
+ .phys_io = IO_PHYS,
+ .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+ .boot_params = (DA8XX_DDR_BASE + 0x100),
+ .map_io = da850_evm_map_io,
+ .init_irq = da850_evm_irq_init,
+ .timer = &davinci_timer,
+ .init_machine = da850_evm_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 5ac2f565d860..763e02b3b3ba 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -20,6 +20,8 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/clk.h>
+#include <linux/videodev2.h>
+#include <media/tvp514x.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
@@ -37,7 +39,6 @@
#include <mach/serial.h>
#include <mach/nand.h>
#include <mach/mmc.h>
-#include <mach/common.h>
#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000
#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
@@ -118,6 +119,8 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
+static struct snd_platform_data dm355_evm_snd_data;
+
static int dm355evm_mmc_gpios = -EINVAL;
static void dm355evm_mmcsd_gpios(unsigned gpio)
@@ -135,11 +138,11 @@ static void dm355evm_mmcsd_gpios(unsigned gpio)
}
static struct i2c_board_info dm355evm_i2c_info[] = {
- { I2C_BOARD_INFO("dm355evm_msp", 0x25),
+ { I2C_BOARD_INFO("dm355evm_msp", 0x25),
.platform_data = dm355evm_mmcsd_gpios,
- /* plus irq */ },
+ },
+ /* { plus irq }, */
/* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */
- /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */
};
static void __init evm_init_i2c(void)
@@ -178,6 +181,72 @@ static struct platform_device dm355evm_dm9000 = {
.num_resources = ARRAY_SIZE(dm355evm_dm9000_rsrc),
};
+static struct tvp514x_platform_data tvp5146_pdata = {
+ .clk_polarity = 0,
+ .hs_polarity = 1,
+ .vs_polarity = 1
+};
+
+#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
+/* Inputs available at the TVP5146 */
+static struct v4l2_input tvp5146_inputs[] = {
+ {
+ .index = 0,
+ .name = "Composite",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = TVP514X_STD_ALL,
+ },
+ {
+ .index = 1,
+ .name = "S-Video",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = TVP514X_STD_ALL,
+ },
+};
+
+/*
+ * this is the route info for connecting each input to decoder
+ * ouput that goes to vpfe. There is a one to one correspondence
+ * with tvp5146_inputs
+ */
+static struct vpfe_route tvp5146_routes[] = {
+ {
+ .input = INPUT_CVBS_VI2B,
+ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+ },
+ {
+ .input = INPUT_SVIDEO_VI2C_VI1C,
+ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+ },
+};
+
+static struct vpfe_subdev_info vpfe_sub_devs[] = {
+ {
+ .name = "tvp5146",
+ .grp_id = 0,
+ .num_inputs = ARRAY_SIZE(tvp5146_inputs),
+ .inputs = tvp5146_inputs,
+ .routes = tvp5146_routes,
+ .can_route = 1,
+ .ccdc_if_params = {
+ .if_type = VPFE_BT656,
+ .hdpol = VPFE_PINPOL_POSITIVE,
+ .vdpol = VPFE_PINPOL_POSITIVE,
+ },
+ .board_info = {
+ I2C_BOARD_INFO("tvp5146", 0x5d),
+ .platform_data = &tvp5146_pdata,
+ },
+ }
+};
+
+static struct vpfe_config vpfe_cfg = {
+ .num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+ .sub_devs = vpfe_sub_devs,
+ .card_name = "DM355 EVM",
+ .ccdc = "DM355 CCDC",
+};
+
static struct platform_device *davinci_evm_devices[] __initdata = {
&dm355evm_dm9000,
&davinci_nand_device,
@@ -189,6 +258,8 @@ static struct davinci_uart_config uart_config __initdata = {
static void __init dm355_evm_map_io(void)
{
+ /* setup input configuration for VPFE input devices */
+ dm355_set_vpfe_config(&vpfe_cfg);
dm355_init();
}
@@ -280,6 +351,9 @@ static __init void dm355_evm_init(void)
dm355_init_spi0(BIT(0), dm355_evm_spi_info,
ARRAY_SIZE(dm355_evm_spi_info));
+
+ /* DM335 EVM uses ASP1; line-out is a stereo mini-jack */
+ dm355_init_asp1(ASP1_TX_EVT_EN | ASP1_RX_EVT_EN, &dm355_evm_snd_data);
}
static __init void dm355_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index 28c9008df4f4..84ad5d161a87 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -36,7 +36,6 @@
#include <mach/serial.h>
#include <mach/nand.h>
#include <mach/mmc.h>
-#include <mach/common.h>
#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000
#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
new file mode 100644
index 000000000000..a1d5e7dac741
--- /dev/null
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -0,0 +1,492 @@
+/*
+ * TI DaVinci DM365 EVM board support
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/i2c/at24.h>
+#include <linux/leds.h>
+#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/common.h>
+#include <mach/mmc.h>
+#include <mach/nand.h>
+
+
+static inline int have_imager(void)
+{
+ /* REVISIT when it's supported, trigger via Kconfig */
+ return 0;
+}
+
+static inline int have_tvp7002(void)
+{
+ /* REVISIT when it's supported, trigger via Kconfig */
+ return 0;
+}
+
+
+#define DM365_ASYNC_EMIF_CONTROL_BASE 0x01d10000
+#define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+#define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
+
+#define DM365_EVM_PHY_MASK (0x2)
+#define DM365_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
+
+/*
+ * A MAX-II CPLD is used for various board control functions.
+ */
+#define CPLD_OFFSET(a13a8,a2a1) (((a13a8) << 10) + ((a2a1) << 3))
+
+#define CPLD_VERSION CPLD_OFFSET(0,0) /* r/o */
+#define CPLD_TEST CPLD_OFFSET(0,1)
+#define CPLD_LEDS CPLD_OFFSET(0,2)
+#define CPLD_MUX CPLD_OFFSET(0,3)
+#define CPLD_SWITCH CPLD_OFFSET(1,0) /* r/o */
+#define CPLD_POWER CPLD_OFFSET(1,1)
+#define CPLD_VIDEO CPLD_OFFSET(1,2)
+#define CPLD_CARDSTAT CPLD_OFFSET(1,3) /* r/o */
+
+#define CPLD_DILC_OUT CPLD_OFFSET(2,0)
+#define CPLD_DILC_IN CPLD_OFFSET(2,1) /* r/o */
+
+#define CPLD_IMG_DIR0 CPLD_OFFSET(2,2)
+#define CPLD_IMG_MUX0 CPLD_OFFSET(2,3)
+#define CPLD_IMG_MUX1 CPLD_OFFSET(3,0)
+#define CPLD_IMG_DIR1 CPLD_OFFSET(3,1)
+#define CPLD_IMG_MUX2 CPLD_OFFSET(3,2)
+#define CPLD_IMG_MUX3 CPLD_OFFSET(3,3)
+#define CPLD_IMG_DIR2 CPLD_OFFSET(4,0)
+#define CPLD_IMG_MUX4 CPLD_OFFSET(4,1)
+#define CPLD_IMG_MUX5 CPLD_OFFSET(4,2)
+
+#define CPLD_RESETS CPLD_OFFSET(4,3)
+
+#define CPLD_CCD_DIR1 CPLD_OFFSET(0x3e,0)
+#define CPLD_CCD_IO1 CPLD_OFFSET(0x3e,1)
+#define CPLD_CCD_DIR2 CPLD_OFFSET(0x3e,2)
+#define CPLD_CCD_IO2 CPLD_OFFSET(0x3e,3)
+#define CPLD_CCD_DIR3 CPLD_OFFSET(0x3f,0)
+#define CPLD_CCD_IO3 CPLD_OFFSET(0x3f,1)
+
+static void __iomem *cpld;
+
+
+/* NOTE: this is geared for the standard config, with a socketed
+ * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors. If you
+ * swap chips with a different block size, partitioning will
+ * need to be changed. This NAND chip MT29F16G08FAA is the default
+ * NAND shipped with the Spectrum Digital DM365 EVM
+ */
+#define NAND_BLOCK_SIZE SZ_128K
+
+static struct mtd_partition davinci_nand_partitions[] = {
+ {
+ /* UBL (a few copies) plus U-Boot */
+ .name = "bootloader",
+ .offset = 0,
+ .size = 28 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ /* U-Boot environment */
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * NAND_BLOCK_SIZE,
+ .mask_flags = 0,
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem1",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_512M,
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem2",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+ /* two blocks with bad block table (and mirror) at the end */
+};
+
+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,
+ .options = NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_nand_resources[] = {
+ {
+ .start = DM365_ASYNC_EMIF_DATA_CE0_BASE,
+ .end = DM365_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = DM365_ASYNC_EMIF_CONTROL_BASE,
+ .end = DM365_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,
+ },
+};
+
+static struct at24_platform_data eeprom_info = {
+ .byte_len = (256*1024) / 8,
+ .page_size = 64,
+ .flags = AT24_FLAG_ADDR16,
+ .setup = davinci_get_mac_addr,
+ .context = (void *)0x7f00,
+};
+
+static struct i2c_board_info i2c_info[] = {
+ {
+ I2C_BOARD_INFO("24c256", 0x50),
+ .platform_data = &eeprom_info,
+ },
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+ .bus_freq = 400 /* kHz */,
+ .bus_delay = 0 /* usec */,
+};
+
+static int cpld_mmc_get_cd(int module)
+{
+ if (!cpld)
+ return -ENXIO;
+
+ /* low == card present */
+ return !(__raw_readb(cpld + CPLD_CARDSTAT) & BIT(module ? 4 : 0));
+}
+
+static int cpld_mmc_get_ro(int module)
+{
+ if (!cpld)
+ return -ENXIO;
+
+ /* high == card's write protect switch active */
+ return !!(__raw_readb(cpld + CPLD_CARDSTAT) & BIT(module ? 5 : 1));
+}
+
+static struct davinci_mmc_config dm365evm_mmc_config = {
+ .get_cd = cpld_mmc_get_cd,
+ .get_ro = cpld_mmc_get_ro,
+ .wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .version = MMC_CTLR_VERSION_2,
+};
+
+static void dm365evm_emac_configure(void)
+{
+ /*
+ * EMAC pins are multiplexed with GPIO and UART
+ * Further details are available at the DM365 ARM
+ * Subsystem Users Guide(sprufg5.pdf) pages 125 - 127
+ */
+ davinci_cfg_reg(DM365_EMAC_TX_EN);
+ davinci_cfg_reg(DM365_EMAC_TX_CLK);
+ davinci_cfg_reg(DM365_EMAC_COL);
+ davinci_cfg_reg(DM365_EMAC_TXD3);
+ davinci_cfg_reg(DM365_EMAC_TXD2);
+ davinci_cfg_reg(DM365_EMAC_TXD1);
+ davinci_cfg_reg(DM365_EMAC_TXD0);
+ davinci_cfg_reg(DM365_EMAC_RXD3);
+ davinci_cfg_reg(DM365_EMAC_RXD2);
+ davinci_cfg_reg(DM365_EMAC_RXD1);
+ davinci_cfg_reg(DM365_EMAC_RXD0);
+ davinci_cfg_reg(DM365_EMAC_RX_CLK);
+ davinci_cfg_reg(DM365_EMAC_RX_DV);
+ davinci_cfg_reg(DM365_EMAC_RX_ER);
+ davinci_cfg_reg(DM365_EMAC_CRS);
+ davinci_cfg_reg(DM365_EMAC_MDIO);
+ davinci_cfg_reg(DM365_EMAC_MDCLK);
+
+ /*
+ * EMAC interrupts are multiplexed with GPIO interrupts
+ * Details are available at the DM365 ARM
+ * Subsystem Users Guide(sprufg5.pdf) pages 133 - 134
+ */
+ davinci_cfg_reg(DM365_INT_EMAC_RXTHRESH);
+ davinci_cfg_reg(DM365_INT_EMAC_RXPULSE);
+ davinci_cfg_reg(DM365_INT_EMAC_TXPULSE);
+ davinci_cfg_reg(DM365_INT_EMAC_MISCPULSE);
+}
+
+static void dm365evm_mmc_configure(void)
+{
+ /*
+ * MMC/SD pins are multiplexed with GPIO and EMIF
+ * Further details are available at the DM365 ARM
+ * Subsystem Users Guide(sprufg5.pdf) pages 118, 128 - 131
+ */
+ davinci_cfg_reg(DM365_SD1_CLK);
+ davinci_cfg_reg(DM365_SD1_CMD);
+ davinci_cfg_reg(DM365_SD1_DATA3);
+ davinci_cfg_reg(DM365_SD1_DATA2);
+ davinci_cfg_reg(DM365_SD1_DATA1);
+ davinci_cfg_reg(DM365_SD1_DATA0);
+}
+
+static void __init evm_init_i2c(void)
+{
+ davinci_init_i2c(&i2c_pdata);
+ i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
+static struct platform_device *dm365_evm_nand_devices[] __initdata = {
+ &davinci_nand_device,
+};
+
+static inline int have_leds(void)
+{
+#ifdef CONFIG_LEDS_CLASS
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+struct cpld_led {
+ struct led_classdev cdev;
+ u8 mask;
+};
+
+static const struct {
+ const char *name;
+ const char *trigger;
+} cpld_leds[] = {
+ { "dm365evm::ds2", },
+ { "dm365evm::ds3", },
+ { "dm365evm::ds4", },
+ { "dm365evm::ds5", },
+ { "dm365evm::ds6", "nand-disk", },
+ { "dm365evm::ds7", "mmc1", },
+ { "dm365evm::ds8", "mmc0", },
+ { "dm365evm::ds9", "heartbeat", },
+};
+
+static void cpld_led_set(struct led_classdev *cdev, enum led_brightness b)
+{
+ struct cpld_led *led = container_of(cdev, struct cpld_led, cdev);
+ u8 reg = __raw_readb(cpld + CPLD_LEDS);
+
+ if (b != LED_OFF)
+ reg &= ~led->mask;
+ else
+ reg |= led->mask;
+ __raw_writeb(reg, cpld + CPLD_LEDS);
+}
+
+static enum led_brightness cpld_led_get(struct led_classdev *cdev)
+{
+ struct cpld_led *led = container_of(cdev, struct cpld_led, cdev);
+ u8 reg = __raw_readb(cpld + CPLD_LEDS);
+
+ return (reg & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init cpld_leds_init(void)
+{
+ int i;
+
+ if (!have_leds() || !cpld)
+ return 0;
+
+ /* setup LEDs */
+ __raw_writeb(0xff, cpld + CPLD_LEDS);
+ for (i = 0; i < ARRAY_SIZE(cpld_leds); i++) {
+ struct cpld_led *led;
+
+ led = kzalloc(sizeof(*led), GFP_KERNEL);
+ if (!led)
+ break;
+
+ led->cdev.name = cpld_leds[i].name;
+ led->cdev.brightness_set = cpld_led_set;
+ led->cdev.brightness_get = cpld_led_get;
+ led->cdev.default_trigger = cpld_leds[i].trigger;
+ led->mask = BIT(i);
+
+ if (led_classdev_register(NULL, &led->cdev) < 0) {
+ kfree(led);
+ break;
+ }
+ }
+
+ return 0;
+}
+/* run after subsys_initcall() for LEDs */
+fs_initcall(cpld_leds_init);
+
+
+static void __init evm_init_cpld(void)
+{
+ u8 mux, resets;
+ const char *label;
+ struct clk *aemif_clk;
+
+ /* Make sure we can configure the CPLD through CS1. Then
+ * leave it on for later access to MMC and LED registers.
+ */
+ aemif_clk = clk_get(NULL, "aemif");
+ if (IS_ERR(aemif_clk))
+ return;
+ clk_enable(aemif_clk);
+
+ if (request_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE,
+ "cpld") == NULL)
+ goto fail;
+ cpld = ioremap(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE);
+ if (!cpld) {
+ release_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE,
+ SECTION_SIZE);
+fail:
+ pr_err("ERROR: can't map CPLD\n");
+ clk_disable(aemif_clk);
+ return;
+ }
+
+ /* External muxing for some signals */
+ mux = 0;
+
+ /* Read SW5 to set up NAND + keypad _or_ OneNAND (sync read).
+ * NOTE: SW4 bus width setting must match!
+ */
+ if ((__raw_readb(cpld + CPLD_SWITCH) & BIT(5)) == 0) {
+ /* external keypad mux */
+ mux |= BIT(7);
+
+ platform_add_devices(dm365_evm_nand_devices,
+ ARRAY_SIZE(dm365_evm_nand_devices));
+ } else {
+ /* no OneNAND support yet */
+ }
+
+ /* Leave external chips in reset when unused. */
+ resets = BIT(3) | BIT(2) | BIT(1) | BIT(0);
+
+ /* Static video input config with SN74CBT16214 1-of-3 mux:
+ * - port b1 == tvp7002 (mux lowbits == 1 or 6)
+ * - port b2 == imager (mux lowbits == 2 or 7)
+ * - port b3 == tvp5146 (mux lowbits == 5)
+ *
+ * Runtime switching could work too, with limitations.
+ */
+ if (have_imager()) {
+ label = "HD imager";
+ mux |= 1;
+
+ /* externally mux MMC1/ENET/AIC33 to imager */
+ mux |= BIT(6) | BIT(5) | BIT(3);
+ } else {
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ /* we can use MMC1 ... */
+ dm365evm_mmc_configure();
+ davinci_setup_mmc(1, &dm365evm_mmc_config);
+
+ /* ... and ENET ... */
+ dm365evm_emac_configure();
+ soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
+ soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
+ resets &= ~BIT(3);
+
+ /* ... and AIC33 */
+ resets &= ~BIT(1);
+
+ if (have_tvp7002()) {
+ mux |= 2;
+ resets &= ~BIT(2);
+ label = "tvp7002 HD";
+ } else {
+ /* default to tvp5146 */
+ mux |= 5;
+ resets &= ~BIT(0);
+ label = "tvp5146 SD";
+ }
+ }
+ __raw_writeb(mux, cpld + CPLD_MUX);
+ __raw_writeb(resets, cpld + CPLD_RESETS);
+ pr_info("EVM: %s video input\n", label);
+
+ /* REVISIT export switches: NTSC/PAL (SW5.6), EXTRA1 (SW5.2), etc */
+}
+
+static struct davinci_uart_config uart_config __initdata = {
+ .enabled_uarts = (1 << 0),
+};
+
+static void __init dm365_evm_map_io(void)
+{
+ dm365_init();
+}
+
+static __init void dm365_evm_init(void)
+{
+ evm_init_i2c();
+ davinci_serial_init(&uart_config);
+
+ dm365evm_emac_configure();
+ dm365evm_mmc_configure();
+
+ davinci_setup_mmc(0, &dm365evm_mmc_config);
+
+ /* maybe setup mmc1/etc ... _after_ mmc0 */
+ evm_init_cpld();
+}
+
+static __init void dm365_evm_irq_init(void)
+{
+ davinci_irq_init();
+}
+
+MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM")
+ .phys_io = IO_PHYS,
+ .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+ .boot_params = (0x80000100),
+ .map_io = dm365_evm_map_io,
+ .init_irq = dm365_evm_irq_init,
+ .timer = &davinci_timer,
+ .init_machine = dm365_evm_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index d9d40450bdc5..9675daa9eecf 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -28,7 +28,8 @@
#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>
@@ -45,7 +46,6 @@
#include <mach/nand.h>
#include <mach/mmc.h>
#include <mach/emac.h>
-#include <mach/common.h>
#define DM644X_EVM_PHY_MASK (0x2)
#define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
@@ -195,6 +195,72 @@ static struct platform_device davinci_fb_device = {
.num_resources = 0,
};
+static struct tvp514x_platform_data tvp5146_pdata = {
+ .clk_polarity = 0,
+ .hs_polarity = 1,
+ .vs_polarity = 1
+};
+
+#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
+/* Inputs available at the TVP5146 */
+static struct v4l2_input tvp5146_inputs[] = {
+ {
+ .index = 0,
+ .name = "Composite",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = TVP514X_STD_ALL,
+ },
+ {
+ .index = 1,
+ .name = "S-Video",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = TVP514X_STD_ALL,
+ },
+};
+
+/*
+ * this is the route info for connecting each input to decoder
+ * ouput that goes to vpfe. There is a one to one correspondence
+ * with tvp5146_inputs
+ */
+static struct vpfe_route tvp5146_routes[] = {
+ {
+ .input = INPUT_CVBS_VI2B,
+ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+ },
+ {
+ .input = INPUT_SVIDEO_VI2C_VI1C,
+ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+ },
+};
+
+static struct vpfe_subdev_info vpfe_sub_devs[] = {
+ {
+ .name = "tvp5146",
+ .grp_id = 0,
+ .num_inputs = ARRAY_SIZE(tvp5146_inputs),
+ .inputs = tvp5146_inputs,
+ .routes = tvp5146_routes,
+ .can_route = 1,
+ .ccdc_if_params = {
+ .if_type = VPFE_BT656,
+ .hdpol = VPFE_PINPOL_POSITIVE,
+ .vdpol = VPFE_PINPOL_POSITIVE,
+ },
+ .board_info = {
+ I2C_BOARD_INFO("tvp5146", 0x5d),
+ .platform_data = &tvp5146_pdata,
+ },
+ },
+};
+
+static struct vpfe_config vpfe_cfg = {
+ .num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+ .sub_devs = vpfe_sub_devs,
+ .card_name = "DM6446 EVM",
+ .ccdc = "DM6446 CCDC",
+};
+
static struct platform_device rtc_dev = {
.name = "rtc_davinci_evm",
.id = -1,
@@ -226,6 +292,8 @@ static struct platform_device ide_dev = {
},
};
+static struct snd_platform_data dm644x_evm_snd_data;
+
/*----------------------------------------------------------------------*/
/*
@@ -560,7 +628,6 @@ static struct i2c_board_info __initdata i2c_info[] = {
},
/* ALSO:
* - tvl320aic33 audio codec (0x1b)
- * - tvp5146 video decoder (0x5d)
*/
};
@@ -591,6 +658,8 @@ static struct davinci_uart_config uart_config __initdata = {
static void __init
davinci_evm_map_io(void)
{
+ /* setup input configuration for VPFE input devices */
+ dm644x_set_vpfe_config(&vpfe_cfg);
dm644x_init();
}
@@ -667,6 +736,7 @@ static __init void davinci_evm_init(void)
davinci_setup_mmc(0, &dm6446evm_mmc_config);
davinci_serial_init(&uart_config);
+ dm644x_init_asp(&dm644x_evm_snd_data);
soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index e17de6352624..74613ed978cf 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -47,15 +47,79 @@
#include <mach/i2c.h>
#include <mach/mmc.h>
#include <mach/emac.h>
-#include <mach/common.h>
+
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#define HAS_ATA 1
+#else
+#define HAS_ATA 0
+#endif
+
+/* CPLD Register 0 bits to control ATA */
+#define DM646X_EVM_ATA_RST BIT(0)
+#define DM646X_EVM_ATA_PWD BIT(1)
#define DM646X_EVM_PHY_MASK (0x2)
#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
+#define VIDCLKCTL_OFFSET (0x38)
+#define VSCLKDIS_OFFSET (0x6c)
+
+#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
+#define VCH2CLK_SYSCLK8 (BIT(9))
+#define VCH2CLK_AUXCLK (BIT(9) | BIT(8))
+#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
+#define VCH3CLK_SYSCLK8 (BIT(13))
+#define VCH3CLK_AUXCLK (BIT(14) | BIT(13))
+
+#define VIDCH2CLK (BIT(10))
+#define VIDCH3CLK (BIT(11))
+
static struct davinci_uart_config uart_config __initdata = {
.enabled_uarts = (1 << 0),
};
+/* CPLD Register 0 Client: used for I/O Control */
+static int cpld_reg0_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ if (HAS_ATA) {
+ u8 data;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &data,
+ },
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &data,
+ },
+ };
+
+ /* Clear ATA_RSTn and ATA_PWD bits to enable ATA operation. */
+ i2c_transfer(client->adapter, msg, 1);
+ data &= ~(DM646X_EVM_ATA_RST | DM646X_EVM_ATA_PWD);
+ i2c_transfer(client->adapter, msg + 1, 1);
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id cpld_reg_ids[] = {
+ { "cpld_reg0", 0, },
+ { },
+};
+
+static struct i2c_driver dm6467evm_cpld_driver = {
+ .driver.name = "cpld_reg0",
+ .id_table = cpld_reg_ids,
+ .probe = cpld_reg0_probe,
+};
+
/* LEDS */
static struct gpio_led evm_leds[] = {
@@ -207,6 +271,69 @@ static struct at24_platform_data eeprom_info = {
.context = (void *)0x7f00,
};
+static u8 dm646x_iis_serializer_direction[] = {
+ TX_MODE, RX_MODE, INACTIVE_MODE, INACTIVE_MODE,
+};
+
+static u8 dm646x_dit_serializer_direction[] = {
+ TX_MODE,
+};
+
+static struct snd_platform_data dm646x_evm_snd_data[] = {
+ {
+ .tx_dma_offset = 0x400,
+ .rx_dma_offset = 0x400,
+ .op_mode = DAVINCI_MCASP_IIS_MODE,
+ .num_serializer = ARRAY_SIZE(dm646x_iis_serializer_direction),
+ .tdm_slots = 2,
+ .serial_dir = dm646x_iis_serializer_direction,
+ .eventq_no = EVENTQ_0,
+ },
+ {
+ .tx_dma_offset = 0x400,
+ .rx_dma_offset = 0,
+ .op_mode = DAVINCI_MCASP_DIT_MODE,
+ .num_serializer = ARRAY_SIZE(dm646x_dit_serializer_direction),
+ .tdm_slots = 32,
+ .serial_dir = dm646x_dit_serializer_direction,
+ .eventq_no = EVENTQ_0,
+ },
+};
+
+static struct i2c_client *cpld_client;
+
+static int cpld_video_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ cpld_client = client;
+ return 0;
+}
+
+static int __devexit cpld_video_remove(struct i2c_client *client)
+{
+ cpld_client = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id cpld_video_id[] = {
+ { "cpld_video", 0 },
+ { }
+};
+
+static struct i2c_driver cpld_video_driver = {
+ .driver = {
+ .name = "cpld_video",
+ },
+ .probe = cpld_video_probe,
+ .remove = cpld_video_remove,
+ .id_table = cpld_video_id,
+};
+
+static void evm_init_cpld(void)
+{
+ i2c_add_driver(&cpld_video_driver);
+}
+
static struct i2c_board_info __initdata i2c_info[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
@@ -216,6 +343,12 @@ static struct i2c_board_info __initdata i2c_info[] = {
I2C_BOARD_INFO("pcf8574a", 0x38),
.platform_data = &pcf_data,
},
+ {
+ I2C_BOARD_INFO("cpld_reg0", 0x3a),
+ },
+ {
+ I2C_BOARD_INFO("cpld_video", 0x3B),
+ },
};
static struct davinci_i2c_platform_data i2c_pdata = {
@@ -223,10 +356,82 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
+static int set_vpif_clock(int mux_mode, int hd)
+{
+ int val = 0;
+ int err = 0;
+ unsigned int value;
+ void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+
+ /* disable the clock */
+ value = __raw_readl(base + VSCLKDIS_OFFSET);
+ value |= (VIDCH3CLK | VIDCH2CLK);
+ __raw_writel(value, base + VSCLKDIS_OFFSET);
+
+ val = i2c_smbus_read_byte(cpld_client);
+ if (val < 0)
+ return val;
+
+ if (mux_mode == 1)
+ val &= ~0x40;
+ else
+ val |= 0x40;
+
+ err = i2c_smbus_write_byte(cpld_client, val);
+ if (err)
+ return err;
+
+ value = __raw_readl(base + VIDCLKCTL_OFFSET);
+ value &= ~(VCH2CLK_MASK);
+ value &= ~(VCH3CLK_MASK);
+
+ if (hd >= 1)
+ value |= (VCH2CLK_SYSCLK8 | VCH3CLK_SYSCLK8);
+ else
+ value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK);
+
+ __raw_writel(value, base + VIDCLKCTL_OFFSET);
+
+ /* enable the clock */
+ value = __raw_readl(base + VSCLKDIS_OFFSET);
+ value &= ~(VIDCH3CLK | VIDCH2CLK);
+ __raw_writel(value, base + VSCLKDIS_OFFSET);
+
+ return 0;
+}
+
+static const struct subdev_info dm646x_vpif_subdev[] = {
+ {
+ .addr = 0x2A,
+ .name = "adv7343",
+ },
+ {
+ .addr = 0x2C,
+ .name = "ths7303",
+ },
+};
+
+static const char *output[] = {
+ "Composite",
+ "Component",
+ "S-Video",
+};
+
+static struct vpif_config dm646x_vpif_config = {
+ .set_clock = set_vpif_clock,
+ .subdevinfo = dm646x_vpif_subdev,
+ .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev),
+ .output = output,
+ .output_count = ARRAY_SIZE(output),
+ .card_name = "DM646x EVM",
+};
+
static void __init evm_init_i2c(void)
{
davinci_init_i2c(&i2c_pdata);
+ i2c_add_driver(&dm6467evm_cpld_driver);
i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+ evm_init_cpld();
}
static void __init davinci_map_io(void)
@@ -240,9 +445,15 @@ static __init void evm_init(void)
evm_init_i2c();
davinci_serial_init(&uart_config);
+ dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
+ dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
+
+ if (HAS_ATA)
+ dm646x_init_ide();
soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+ dm646x_setup_vpif(&dm646x_vpif_config);
}
static __init void davinci_dm646x_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 748a8e48541e..7acdfd8ac071 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -52,7 +52,6 @@
#include <mach/serial.h>
#include <mach/psc.h>
#include <mach/mux.h>
-#include <mach/common.h>
#define SFFSDR_PHY_MASK (0x2)
#define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 39bf321d70a2..83d54d50b5ea 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -227,7 +227,10 @@ static void __init clk_pll_init(struct clk *clk)
if (ctrl & PLLCTL_PLLEN) {
bypass = 0;
mult = __raw_readl(pll->base + PLLM);
- mult = (mult & PLLM_PLLM_MASK) + 1;
+ if (cpu_is_davinci_dm365())
+ mult = 2 * (mult & PLLM_PLLM_MASK);
+ else
+ mult = (mult & PLLM_PLLM_MASK) + 1;
} else
bypass = 1;
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
new file mode 100644
index 000000000000..3a9b6346c310
--- /dev/null
+++ b/arch/arm/mach-davinci/da830.c
@@ -0,0 +1,1204 @@
+/*
+ * TI DA830/OMAP L137 chip specific setup
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/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 "clock.h"
+#include "mux.h"
+
+/* Offsets of the 8 compare registers on the da830 */
+#define DA830_CMP12_0 0x60
+#define DA830_CMP12_1 0x64
+#define DA830_CMP12_2 0x68
+#define DA830_CMP12_3 0x6c
+#define DA830_CMP12_4 0x70
+#define DA830_CMP12_5 0x74
+#define DA830_CMP12_6 0x78
+#define DA830_CMP12_7 0x7c
+
+#define DA830_REF_FREQ 24000000
+
+static struct pll_data pll0_data = {
+ .num = 1,
+ .phys_base = DA8XX_PLL0_BASE,
+ .flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
+};
+
+static struct clk ref_clk = {
+ .name = "ref_clk",
+ .rate = DA830_REF_FREQ,
+};
+
+static struct clk pll0_clk = {
+ .name = "pll0",
+ .parent = &ref_clk,
+ .pll_data = &pll0_data,
+ .flags = CLK_PLL,
+};
+
+static struct clk pll0_aux_clk = {
+ .name = "pll0_aux_clk",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll0_sysclk2 = {
+ .name = "pll0_sysclk2",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV2,
+};
+
+static struct clk pll0_sysclk3 = {
+ .name = "pll0_sysclk3",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV3,
+};
+
+static struct clk pll0_sysclk4 = {
+ .name = "pll0_sysclk4",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV4,
+};
+
+static struct clk pll0_sysclk5 = {
+ .name = "pll0_sysclk5",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV5,
+};
+
+static struct clk pll0_sysclk6 = {
+ .name = "pll0_sysclk6",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV6,
+};
+
+static struct clk pll0_sysclk7 = {
+ .name = "pll0_sysclk7",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV7,
+};
+
+static struct clk i2c0_clk = {
+ .name = "i2c0",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk timerp64_0_clk = {
+ .name = "timer0",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk timerp64_1_clk = {
+ .name = "timer1",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk arm_rom_clk = {
+ .name = "arm_rom",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_ARM_RAM_ROM,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk scr0_ss_clk = {
+ .name = "scr0_ss",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_SCR0_SS,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk scr1_ss_clk = {
+ .name = "scr1_ss",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_SCR1_SS,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk scr2_ss_clk = {
+ .name = "scr2_ss",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_SCR2_SS,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk dmax_clk = {
+ .name = "dmax",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_DMAX,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk tpcc_clk = {
+ .name = "tpcc",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPCC,
+ .flags = ALWAYS_ENABLED | CLK_PSC,
+};
+
+static struct clk tptc0_clk = {
+ .name = "tptc0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPTC0,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk tptc1_clk = {
+ .name = "tptc1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPTC1,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk mmcsd_clk = {
+ .name = "mmcsd",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_MMC_SD,
+};
+
+static struct clk uart0_clk = {
+ .name = "uart0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_UART0,
+};
+
+static struct clk uart1_clk = {
+ .name = "uart1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_UART1,
+ .psc_ctlr = 1,
+};
+
+static struct clk uart2_clk = {
+ .name = "uart2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_UART2,
+ .psc_ctlr = 1,
+};
+
+static struct clk spi0_clk = {
+ .name = "spi0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_SPI0,
+};
+
+static struct clk spi1_clk = {
+ .name = "spi1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_SPI1,
+ .psc_ctlr = 1,
+};
+
+static struct clk ecap0_clk = {
+ .name = "ecap0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_ECAP,
+ .psc_ctlr = 1,
+};
+
+static struct clk ecap1_clk = {
+ .name = "ecap1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_ECAP,
+ .psc_ctlr = 1,
+};
+
+static struct clk ecap2_clk = {
+ .name = "ecap2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_ECAP,
+ .psc_ctlr = 1,
+};
+
+static struct clk pwm0_clk = {
+ .name = "pwm0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_PWM,
+ .psc_ctlr = 1,
+};
+
+static struct clk pwm1_clk = {
+ .name = "pwm1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_PWM,
+ .psc_ctlr = 1,
+};
+
+static struct clk pwm2_clk = {
+ .name = "pwm2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_PWM,
+ .psc_ctlr = 1,
+};
+
+static struct clk eqep0_clk = {
+ .name = "eqep0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA830_LPSC1_EQEP,
+ .psc_ctlr = 1,
+};
+
+static struct clk eqep1_clk = {
+ .name = "eqep1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA830_LPSC1_EQEP,
+ .psc_ctlr = 1,
+};
+
+static struct clk lcdc_clk = {
+ .name = "lcdc",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_LCDC,
+ .psc_ctlr = 1,
+};
+
+static struct clk mcasp0_clk = {
+ .name = "mcasp0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_McASP0,
+ .psc_ctlr = 1,
+};
+
+static struct clk mcasp1_clk = {
+ .name = "mcasp1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA830_LPSC1_McASP1,
+ .psc_ctlr = 1,
+};
+
+static struct clk mcasp2_clk = {
+ .name = "mcasp2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA830_LPSC1_McASP2,
+ .psc_ctlr = 1,
+};
+
+static struct clk usb20_clk = {
+ .name = "usb20",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_USB20,
+ .psc_ctlr = 1,
+};
+
+static struct clk aemif_clk = {
+ .name = "aemif",
+ .parent = &pll0_sysclk3,
+ .lpsc = DA8XX_LPSC0_EMIF25,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk aintc_clk = {
+ .name = "aintc",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC0_AINTC,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk secu_mgr_clk = {
+ .name = "secu_mgr",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC0_SECU_MGR,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk emac_clk = {
+ .name = "emac",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_CPGMAC,
+ .psc_ctlr = 1,
+};
+
+static struct clk gpio_clk = {
+ .name = "gpio",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_GPIO,
+ .psc_ctlr = 1,
+};
+
+static struct clk i2c1_clk = {
+ .name = "i2c1",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_I2C,
+ .psc_ctlr = 1,
+};
+
+static struct clk usb11_clk = {
+ .name = "usb11",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_USB11,
+ .psc_ctlr = 1,
+};
+
+static struct clk emif3_clk = {
+ .name = "emif3",
+ .parent = &pll0_sysclk5,
+ .lpsc = DA8XX_LPSC1_EMIF3C,
+ .flags = ALWAYS_ENABLED,
+ .psc_ctlr = 1,
+};
+
+static struct clk arm_clk = {
+ .name = "arm",
+ .parent = &pll0_sysclk6,
+ .lpsc = DA8XX_LPSC0_ARM,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk rmii_clk = {
+ .name = "rmii",
+ .parent = &pll0_sysclk7,
+};
+
+static struct davinci_clk da830_clks[] = {
+ CLK(NULL, "ref", &ref_clk),
+ CLK(NULL, "pll0", &pll0_clk),
+ CLK(NULL, "pll0_aux", &pll0_aux_clk),
+ CLK(NULL, "pll0_sysclk2", &pll0_sysclk2),
+ CLK(NULL, "pll0_sysclk3", &pll0_sysclk3),
+ CLK(NULL, "pll0_sysclk4", &pll0_sysclk4),
+ CLK(NULL, "pll0_sysclk5", &pll0_sysclk5),
+ CLK(NULL, "pll0_sysclk6", &pll0_sysclk6),
+ CLK(NULL, "pll0_sysclk7", &pll0_sysclk7),
+ CLK("i2c_davinci.1", NULL, &i2c0_clk),
+ CLK(NULL, "timer0", &timerp64_0_clk),
+ CLK("watchdog", NULL, &timerp64_1_clk),
+ CLK(NULL, "arm_rom", &arm_rom_clk),
+ CLK(NULL, "scr0_ss", &scr0_ss_clk),
+ CLK(NULL, "scr1_ss", &scr1_ss_clk),
+ CLK(NULL, "scr2_ss", &scr2_ss_clk),
+ CLK(NULL, "dmax", &dmax_clk),
+ CLK(NULL, "tpcc", &tpcc_clk),
+ CLK(NULL, "tptc0", &tptc0_clk),
+ CLK(NULL, "tptc1", &tptc1_clk),
+ CLK("davinci_mmc.0", NULL, &mmcsd_clk),
+ CLK(NULL, "uart0", &uart0_clk),
+ CLK(NULL, "uart1", &uart1_clk),
+ CLK(NULL, "uart2", &uart2_clk),
+ CLK("dm_spi.0", NULL, &spi0_clk),
+ CLK("dm_spi.1", NULL, &spi1_clk),
+ CLK(NULL, "ecap0", &ecap0_clk),
+ CLK(NULL, "ecap1", &ecap1_clk),
+ CLK(NULL, "ecap2", &ecap2_clk),
+ CLK(NULL, "pwm0", &pwm0_clk),
+ CLK(NULL, "pwm1", &pwm1_clk),
+ CLK(NULL, "pwm2", &pwm2_clk),
+ CLK("eqep.0", NULL, &eqep0_clk),
+ CLK("eqep.1", NULL, &eqep1_clk),
+ CLK("da830_lcdc", NULL, &lcdc_clk),
+ CLK("soc-audio.0", NULL, &mcasp0_clk),
+ CLK("soc-audio.1", NULL, &mcasp1_clk),
+ CLK("soc-audio.2", NULL, &mcasp2_clk),
+ CLK("musb_hdrc", NULL, &usb20_clk),
+ CLK(NULL, "aemif", &aemif_clk),
+ CLK(NULL, "aintc", &aintc_clk),
+ CLK(NULL, "secu_mgr", &secu_mgr_clk),
+ CLK("davinci_emac.1", NULL, &emac_clk),
+ CLK(NULL, "gpio", &gpio_clk),
+ CLK("i2c_davinci.2", NULL, &i2c1_clk),
+ CLK(NULL, "usb11", &usb11_clk),
+ CLK(NULL, "emif3", &emif3_clk),
+ CLK(NULL, "arm", &arm_clk),
+ CLK(NULL, "rmii", &rmii_clk),
+ CLK(NULL, NULL, NULL),
+};
+
+/*
+ * Device specific mux setup
+ *
+ * soc description mux mode mode mux dbg
+ * reg offset mask mode
+ */
+static const struct mux_config da830_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+ MUX_CFG(DA830, GPIO7_14, 0, 0, 0xf, 1, false)
+ MUX_CFG(DA830, RTCK, 0, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_15, 0, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMU_0, 0, 4, 0xf, 8, false)
+ MUX_CFG(DA830, EMB_SDCKE, 0, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_CLK_GLUE, 0, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_CLK, 0, 12, 0xf, 2, false)
+ MUX_CFG(DA830, NEMB_CS_0, 0, 16, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_CAS, 0, 20, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_RAS, 0, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_WE, 0, 28, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_BA_1, 1, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_BA_0, 1, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_0, 1, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_1, 1, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_2, 1, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_3, 1, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_4, 1, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_5, 1, 28, 0xf, 1, false)
+ MUX_CFG(DA830, GPIO7_0, 1, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_1, 1, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_2, 1, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_3, 1, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_4, 1, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_5, 1, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_6, 1, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_7, 1, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMB_A_6, 2, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_7, 2, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_8, 2, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_9, 2, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_10, 2, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_11, 2, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_A_12, 2, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_31, 2, 28, 0xf, 1, false)
+ MUX_CFG(DA830, GPIO7_8, 2, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_9, 2, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_10, 2, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_11, 2, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_12, 2, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO7_13, 2, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_13, 2, 24, 0xf, 8, false)
+ MUX_CFG(DA830, EMB_D_30, 3, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_29, 3, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_28, 3, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_27, 3, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_26, 3, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_25, 3, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_24, 3, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_23, 3, 28, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_22, 4, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_21, 4, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_20, 4, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_19, 4, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_18, 4, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_17, 4, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_16, 4, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_WE_DQM_3, 4, 28, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_WE_DQM_2, 5, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_0, 5, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_1, 5, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_2, 5, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_3, 5, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_4, 5, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_5, 5, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_6, 5, 28, 0xf, 1, false)
+ MUX_CFG(DA830, GPIO6_0, 5, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_1, 5, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_2, 5, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_3, 5, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_4, 5, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_5, 5, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_6, 5, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMB_D_7, 6, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_8, 6, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_9, 6, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_10, 6, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_11, 6, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_12, 6, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_13, 6, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMB_D_14, 6, 28, 0xf, 1, false)
+ MUX_CFG(DA830, GPIO6_7, 6, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_8, 6, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_9, 6, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_10, 6, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_11, 6, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_12, 6, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_13, 6, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO6_14, 6, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMB_D_15, 7, 0, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_WE_DQM_1, 7, 4, 0xf, 1, false)
+ MUX_CFG(DA830, NEMB_WE_DQM_0, 7, 8, 0xf, 1, false)
+ MUX_CFG(DA830, SPI0_SOMI_0, 7, 12, 0xf, 1, false)
+ MUX_CFG(DA830, SPI0_SIMO_0, 7, 16, 0xf, 1, false)
+ MUX_CFG(DA830, SPI0_CLK, 7, 20, 0xf, 1, false)
+ MUX_CFG(DA830, NSPI0_ENA, 7, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NSPI0_SCS_0, 7, 28, 0xf, 1, false)
+ MUX_CFG(DA830, EQEP0I, 7, 12, 0xf, 2, false)
+ MUX_CFG(DA830, EQEP0S, 7, 16, 0xf, 2, false)
+ MUX_CFG(DA830, EQEP1I, 7, 20, 0xf, 2, false)
+ MUX_CFG(DA830, NUART0_CTS, 7, 24, 0xf, 2, false)
+ MUX_CFG(DA830, NUART0_RTS, 7, 28, 0xf, 2, false)
+ MUX_CFG(DA830, EQEP0A, 7, 24, 0xf, 4, false)
+ MUX_CFG(DA830, EQEP0B, 7, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO6_15, 7, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_14, 7, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_15, 7, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_0, 7, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_1, 7, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_2, 7, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_3, 7, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_4, 7, 28, 0xf, 8, false)
+ MUX_CFG(DA830, SPI1_SOMI_0, 8, 0, 0xf, 1, false)
+ MUX_CFG(DA830, SPI1_SIMO_0, 8, 4, 0xf, 1, false)
+ MUX_CFG(DA830, SPI1_CLK, 8, 8, 0xf, 1, false)
+ MUX_CFG(DA830, UART0_RXD, 8, 12, 0xf, 1, false)
+ MUX_CFG(DA830, UART0_TXD, 8, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_10, 8, 20, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_11, 8, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NSPI1_ENA, 8, 28, 0xf, 1, false)
+ MUX_CFG(DA830, I2C1_SCL, 8, 0, 0xf, 2, false)
+ MUX_CFG(DA830, I2C1_SDA, 8, 4, 0xf, 2, false)
+ MUX_CFG(DA830, EQEP1S, 8, 8, 0xf, 2, false)
+ MUX_CFG(DA830, I2C0_SDA, 8, 12, 0xf, 2, false)
+ MUX_CFG(DA830, I2C0_SCL, 8, 16, 0xf, 2, false)
+ MUX_CFG(DA830, UART2_RXD, 8, 28, 0xf, 2, false)
+ MUX_CFG(DA830, TM64P0_IN12, 8, 12, 0xf, 4, false)
+ MUX_CFG(DA830, TM64P0_OUT12, 8, 16, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO5_5, 8, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_6, 8, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_7, 8, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_8, 8, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_9, 8, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_10, 8, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_11, 8, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO5_12, 8, 28, 0xf, 8, false)
+ MUX_CFG(DA830, NSPI1_SCS_0, 9, 0, 0xf, 1, false)
+ MUX_CFG(DA830, USB0_DRVVBUS, 9, 4, 0xf, 1, false)
+ MUX_CFG(DA830, AHCLKX0, 9, 8, 0xf, 1, false)
+ MUX_CFG(DA830, ACLKX0, 9, 12, 0xf, 1, false)
+ MUX_CFG(DA830, AFSX0, 9, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AHCLKR0, 9, 20, 0xf, 1, false)
+ MUX_CFG(DA830, ACLKR0, 9, 24, 0xf, 1, false)
+ MUX_CFG(DA830, AFSR0, 9, 28, 0xf, 1, false)
+ MUX_CFG(DA830, UART2_TXD, 9, 0, 0xf, 2, false)
+ MUX_CFG(DA830, AHCLKX2, 9, 8, 0xf, 2, false)
+ MUX_CFG(DA830, ECAP0_APWM0, 9, 12, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_MHZ_50_CLK, 9, 20, 0xf, 2, false)
+ MUX_CFG(DA830, ECAP1_APWM1, 9, 24, 0xf, 2, false)
+ MUX_CFG(DA830, USB_REFCLKIN, 9, 8, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO5_13, 9, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_15, 9, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_11, 9, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_12, 9, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_13, 9, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_14, 9, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_15, 9, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_12, 9, 28, 0xf, 8, false)
+ MUX_CFG(DA830, AMUTE0, 10, 0, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_0, 10, 4, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_1, 10, 8, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_2, 10, 12, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_3, 10, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_4, 10, 20, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_5, 10, 24, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_6, 10, 28, 0xf, 1, false)
+ MUX_CFG(DA830, RMII_TXD_0, 10, 4, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_TXD_1, 10, 8, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_TXEN, 10, 12, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_CRS_DV, 10, 16, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_RXD_0, 10, 20, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_RXD_1, 10, 24, 0xf, 2, false)
+ MUX_CFG(DA830, RMII_RXER, 10, 28, 0xf, 2, false)
+ MUX_CFG(DA830, AFSR2, 10, 4, 0xf, 4, false)
+ MUX_CFG(DA830, ACLKX2, 10, 8, 0xf, 4, false)
+ MUX_CFG(DA830, AXR2_3, 10, 12, 0xf, 4, false)
+ MUX_CFG(DA830, AXR2_2, 10, 16, 0xf, 4, false)
+ MUX_CFG(DA830, AXR2_1, 10, 20, 0xf, 4, false)
+ MUX_CFG(DA830, AFSX2, 10, 24, 0xf, 4, false)
+ MUX_CFG(DA830, ACLKR2, 10, 28, 0xf, 4, false)
+ MUX_CFG(DA830, NRESETOUT, 10, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_0, 10, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_1, 10, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_2, 10, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_3, 10, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_4, 10, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_5, 10, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_6, 10, 28, 0xf, 8, false)
+ MUX_CFG(DA830, AXR0_7, 11, 0, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_8, 11, 4, 0xf, 1, false)
+ MUX_CFG(DA830, UART1_RXD, 11, 8, 0xf, 1, false)
+ MUX_CFG(DA830, UART1_TXD, 11, 12, 0xf, 1, false)
+ MUX_CFG(DA830, AXR0_11, 11, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AHCLKX1, 11, 20, 0xf, 1, false)
+ MUX_CFG(DA830, ACLKX1, 11, 24, 0xf, 1, false)
+ MUX_CFG(DA830, AFSX1, 11, 28, 0xf, 1, false)
+ MUX_CFG(DA830, MDIO_CLK, 11, 0, 0xf, 2, false)
+ MUX_CFG(DA830, MDIO_D, 11, 4, 0xf, 2, false)
+ MUX_CFG(DA830, AXR0_9, 11, 8, 0xf, 2, false)
+ MUX_CFG(DA830, AXR0_10, 11, 12, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM0B, 11, 20, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM0A, 11, 24, 0xf, 2, false)
+ MUX_CFG(DA830, EPWMSYNCI, 11, 28, 0xf, 2, false)
+ MUX_CFG(DA830, AXR2_0, 11, 16, 0xf, 4, false)
+ MUX_CFG(DA830, EPWMSYNC0, 11, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO3_7, 11, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_8, 11, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_9, 11, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_10, 11, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_11, 11, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_14, 11, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO3_15, 11, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_10, 11, 28, 0xf, 8, false)
+ MUX_CFG(DA830, AHCLKR1, 12, 0, 0xf, 1, false)
+ MUX_CFG(DA830, ACLKR1, 12, 4, 0xf, 1, false)
+ MUX_CFG(DA830, AFSR1, 12, 8, 0xf, 1, false)
+ MUX_CFG(DA830, AMUTE1, 12, 12, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_0, 12, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_1, 12, 20, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_2, 12, 24, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_3, 12, 28, 0xf, 1, false)
+ MUX_CFG(DA830, ECAP2_APWM2, 12, 4, 0xf, 2, false)
+ MUX_CFG(DA830, EHRPWMGLUETZ, 12, 12, 0xf, 2, false)
+ MUX_CFG(DA830, EQEP1A, 12, 28, 0xf, 2, false)
+ MUX_CFG(DA830, GPIO4_11, 12, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_12, 12, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_13, 12, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_14, 12, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_0, 12, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_1, 12, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_2, 12, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_3, 12, 28, 0xf, 8, false)
+ MUX_CFG(DA830, AXR1_4, 13, 0, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_5, 13, 4, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_6, 13, 8, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_7, 13, 12, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_8, 13, 16, 0xf, 1, false)
+ MUX_CFG(DA830, AXR1_9, 13, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_0, 13, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_1, 13, 28, 0xf, 1, false)
+ MUX_CFG(DA830, EQEP1B, 13, 0, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM2B, 13, 4, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM2A, 13, 8, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM1B, 13, 12, 0xf, 2, false)
+ MUX_CFG(DA830, EPWM1A, 13, 16, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_0, 13, 24, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_1, 13, 28, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_0, 13, 24, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_1, 13, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO4_4, 13, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_5, 13, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_6, 13, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_7, 13, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_8, 13, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO4_9, 13, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_0, 13, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_1, 13, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMA_D_2, 14, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_3, 14, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_4, 14, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_5, 14, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_6, 14, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_7, 14, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_8, 14, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_9, 14, 28, 0xf, 1, false)
+ MUX_CFG(DA830, MMCSD_DAT_2, 14, 0, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_3, 14, 4, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_4, 14, 8, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_5, 14, 12, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_6, 14, 16, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_DAT_7, 14, 20, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_8, 14, 24, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_9, 14, 28, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_2, 14, 0, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_3, 14, 4, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_4, 14, 8, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_5, 14, 12, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_6, 14, 16, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HD_7, 14, 20, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_8, 14, 24, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_9, 14, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO0_2, 14, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_3, 14, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_4, 14, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_5, 14, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_6, 14, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_7, 14, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_8, 14, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_9, 14, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMA_D_10, 15, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_11, 15, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_12, 15, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_13, 15, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_14, 15, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_D_15, 15, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_0, 15, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_1, 15, 28, 0xf, 1, false)
+ MUX_CFG(DA830, UHPI_HD_10, 15, 0, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_11, 15, 4, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_12, 15, 8, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_13, 15, 12, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_14, 15, 16, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HD_15, 15, 20, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_7, 15, 24, 0xf, 2, false)
+ MUX_CFG(DA830, MMCSD_CLK, 15, 28, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_10, 15, 0, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_11, 15, 4, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_12, 15, 8, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_13, 15, 12, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_14, 15, 16, 0xf, 4, false)
+ MUX_CFG(DA830, LCD_D_15, 15, 20, 0xf, 4, false)
+ MUX_CFG(DA830, UHPI_HCNTL0, 15, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO0_10, 15, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_11, 15, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_12, 15, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_13, 15, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_14, 15, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO0_15, 15, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_0, 15, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_1, 15, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMA_A_2, 16, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_3, 16, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_4, 16, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_5, 16, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_6, 16, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_7, 16, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_8, 16, 24, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_9, 16, 28, 0xf, 1, false)
+ MUX_CFG(DA830, MMCSD_CMD, 16, 0, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_6, 16, 4, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_3, 16, 8, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_2, 16, 12, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_1, 16, 16, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_0, 16, 20, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_PCLK, 16, 24, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_HSYNC, 16, 28, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HCNTL1, 16, 0, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO1_2, 16, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_3, 16, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_4, 16, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_5, 16, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_6, 16, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_7, 16, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_8, 16, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_9, 16, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMA_A_10, 17, 0, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_11, 17, 4, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_A_12, 17, 8, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_BA_1, 17, 12, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_BA_0, 17, 16, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_CLK, 17, 20, 0xf, 1, false)
+ MUX_CFG(DA830, EMA_SDCKE, 17, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_CAS, 17, 28, 0xf, 1, false)
+ MUX_CFG(DA830, LCD_VSYNC, 17, 0, 0xf, 2, false)
+ MUX_CFG(DA830, NLCD_AC_ENB_CS, 17, 4, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_MCLK, 17, 8, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_5, 17, 12, 0xf, 2, false)
+ MUX_CFG(DA830, LCD_D_4, 17, 16, 0xf, 2, false)
+ MUX_CFG(DA830, OBSCLK, 17, 20, 0xf, 2, false)
+ MUX_CFG(DA830, NEMA_CS_4, 17, 28, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HHWIL, 17, 12, 0xf, 4, false)
+ MUX_CFG(DA830, AHCLKR2, 17, 20, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO1_10, 17, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_11, 17, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_12, 17, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_13, 17, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_14, 17, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO1_15, 17, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_0, 17, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_1, 17, 28, 0xf, 8, false)
+ MUX_CFG(DA830, NEMA_RAS, 18, 0, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_WE, 18, 4, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_CS_0, 18, 8, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_CS_2, 18, 12, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_CS_3, 18, 16, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_OE, 18, 20, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_WE_DQM_1, 18, 24, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_WE_DQM_0, 18, 28, 0xf, 1, false)
+ MUX_CFG(DA830, NEMA_CS_5, 18, 0, 0xf, 2, false)
+ MUX_CFG(DA830, UHPI_HRNW, 18, 4, 0xf, 2, false)
+ MUX_CFG(DA830, NUHPI_HAS, 18, 8, 0xf, 2, false)
+ MUX_CFG(DA830, NUHPI_HCS, 18, 12, 0xf, 2, false)
+ MUX_CFG(DA830, NUHPI_HDS1, 18, 20, 0xf, 2, false)
+ MUX_CFG(DA830, NUHPI_HDS2, 18, 24, 0xf, 2, false)
+ MUX_CFG(DA830, NUHPI_HINT, 18, 28, 0xf, 2, false)
+ MUX_CFG(DA830, AXR0_12, 18, 4, 0xf, 4, false)
+ MUX_CFG(DA830, AMUTE2, 18, 16, 0xf, 4, false)
+ MUX_CFG(DA830, AXR0_13, 18, 20, 0xf, 4, false)
+ MUX_CFG(DA830, AXR0_14, 18, 24, 0xf, 4, false)
+ MUX_CFG(DA830, AXR0_15, 18, 28, 0xf, 4, false)
+ MUX_CFG(DA830, GPIO2_2, 18, 0, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_3, 18, 4, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_4, 18, 8, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_5, 18, 12, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_6, 18, 16, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_7, 18, 20, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_8, 18, 24, 0xf, 8, false)
+ MUX_CFG(DA830, GPIO2_9, 18, 28, 0xf, 8, false)
+ MUX_CFG(DA830, EMA_WAIT_0, 19, 0, 0xf, 1, false)
+ MUX_CFG(DA830, NUHPI_HRDY, 19, 0, 0xf, 2, false)
+ MUX_CFG(DA830, GPIO2_10, 19, 0, 0xf, 8, false)
+#endif
+};
+
+const short da830_emif25_pins[] __initdata = {
+ DA830_EMA_D_0, DA830_EMA_D_1, DA830_EMA_D_2, DA830_EMA_D_3,
+ DA830_EMA_D_4, DA830_EMA_D_5, DA830_EMA_D_6, DA830_EMA_D_7,
+ DA830_EMA_D_8, DA830_EMA_D_9, DA830_EMA_D_10, DA830_EMA_D_11,
+ DA830_EMA_D_12, DA830_EMA_D_13, DA830_EMA_D_14, DA830_EMA_D_15,
+ DA830_EMA_A_0, DA830_EMA_A_1, DA830_EMA_A_2, DA830_EMA_A_3,
+ DA830_EMA_A_4, DA830_EMA_A_5, DA830_EMA_A_6, DA830_EMA_A_7,
+ DA830_EMA_A_8, DA830_EMA_A_9, DA830_EMA_A_10, DA830_EMA_A_11,
+ DA830_EMA_A_12, DA830_EMA_BA_0, DA830_EMA_BA_1, DA830_EMA_CLK,
+ DA830_EMA_SDCKE, DA830_NEMA_CS_4, DA830_NEMA_CS_5, DA830_NEMA_WE,
+ DA830_NEMA_CS_0, DA830_NEMA_CS_2, DA830_NEMA_CS_3, DA830_NEMA_OE,
+ DA830_NEMA_WE_DQM_1, DA830_NEMA_WE_DQM_0, DA830_EMA_WAIT_0,
+ -1
+};
+
+const short da830_spi0_pins[] __initdata = {
+ DA830_SPI0_SOMI_0, DA830_SPI0_SIMO_0, DA830_SPI0_CLK, DA830_NSPI0_ENA,
+ DA830_NSPI0_SCS_0,
+ -1
+};
+
+const short da830_spi1_pins[] __initdata = {
+ DA830_SPI1_SOMI_0, DA830_SPI1_SIMO_0, DA830_SPI1_CLK, DA830_NSPI1_ENA,
+ DA830_NSPI1_SCS_0,
+ -1
+};
+
+const short da830_mmc_sd_pins[] __initdata = {
+ 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,
+ -1
+};
+
+const short da830_uart0_pins[] __initdata = {
+ DA830_NUART0_CTS, DA830_NUART0_RTS, DA830_UART0_RXD, DA830_UART0_TXD,
+ -1
+};
+
+const short da830_uart1_pins[] __initdata = {
+ DA830_UART1_RXD, DA830_UART1_TXD,
+ -1
+};
+
+const short da830_uart2_pins[] __initdata = {
+ DA830_UART2_RXD, DA830_UART2_TXD,
+ -1
+};
+
+const short da830_usb20_pins[] __initdata = {
+ DA830_USB0_DRVVBUS, DA830_USB_REFCLKIN,
+ -1
+};
+
+const short da830_usb11_pins[] __initdata = {
+ DA830_USB_REFCLKIN,
+ -1
+};
+
+const short da830_uhpi_pins[] __initdata = {
+ DA830_UHPI_HD_0, DA830_UHPI_HD_1, DA830_UHPI_HD_2, DA830_UHPI_HD_3,
+ DA830_UHPI_HD_4, DA830_UHPI_HD_5, DA830_UHPI_HD_6, DA830_UHPI_HD_7,
+ DA830_UHPI_HD_8, DA830_UHPI_HD_9, DA830_UHPI_HD_10, DA830_UHPI_HD_11,
+ DA830_UHPI_HD_12, DA830_UHPI_HD_13, DA830_UHPI_HD_14, DA830_UHPI_HD_15,
+ DA830_UHPI_HCNTL0, DA830_UHPI_HCNTL1, DA830_UHPI_HHWIL, DA830_UHPI_HRNW,
+ DA830_NUHPI_HAS, DA830_NUHPI_HCS, DA830_NUHPI_HDS1, DA830_NUHPI_HDS2,
+ DA830_NUHPI_HINT, DA830_NUHPI_HRDY,
+ -1
+};
+
+const short da830_cpgmac_pins[] __initdata = {
+ DA830_RMII_TXD_0, DA830_RMII_TXD_1, DA830_RMII_TXEN, DA830_RMII_CRS_DV,
+ DA830_RMII_RXD_0, DA830_RMII_RXD_1, DA830_RMII_RXER, DA830_MDIO_CLK,
+ DA830_MDIO_D,
+ -1
+};
+
+const short da830_emif3c_pins[] __initdata = {
+ DA830_EMB_SDCKE, DA830_EMB_CLK_GLUE, DA830_EMB_CLK, DA830_NEMB_CS_0,
+ DA830_NEMB_CAS, DA830_NEMB_RAS, DA830_NEMB_WE, DA830_EMB_BA_1,
+ DA830_EMB_BA_0, DA830_EMB_A_0, DA830_EMB_A_1, DA830_EMB_A_2,
+ DA830_EMB_A_3, DA830_EMB_A_4, DA830_EMB_A_5, DA830_EMB_A_6,
+ DA830_EMB_A_7, DA830_EMB_A_8, DA830_EMB_A_9, DA830_EMB_A_10,
+ DA830_EMB_A_11, DA830_EMB_A_12, DA830_NEMB_WE_DQM_3,
+ DA830_NEMB_WE_DQM_2, DA830_EMB_D_0, DA830_EMB_D_1, DA830_EMB_D_2,
+ DA830_EMB_D_3, DA830_EMB_D_4, DA830_EMB_D_5, DA830_EMB_D_6,
+ DA830_EMB_D_7, DA830_EMB_D_8, DA830_EMB_D_9, DA830_EMB_D_10,
+ DA830_EMB_D_11, DA830_EMB_D_12, DA830_EMB_D_13, DA830_EMB_D_14,
+ DA830_EMB_D_15, DA830_EMB_D_16, DA830_EMB_D_17, DA830_EMB_D_18,
+ DA830_EMB_D_19, DA830_EMB_D_20, DA830_EMB_D_21, DA830_EMB_D_22,
+ DA830_EMB_D_23, DA830_EMB_D_24, DA830_EMB_D_25, DA830_EMB_D_26,
+ DA830_EMB_D_27, DA830_EMB_D_28, DA830_EMB_D_29, DA830_EMB_D_30,
+ DA830_EMB_D_31, DA830_NEMB_WE_DQM_1, DA830_NEMB_WE_DQM_0,
+ -1
+};
+
+const short da830_mcasp0_pins[] __initdata = {
+ DA830_AHCLKX0, DA830_ACLKX0, DA830_AFSX0,
+ DA830_AHCLKR0, DA830_ACLKR0, DA830_AFSR0, DA830_AMUTE0,
+ DA830_AXR0_0, DA830_AXR0_1, DA830_AXR0_2, DA830_AXR0_3,
+ DA830_AXR0_4, DA830_AXR0_5, DA830_AXR0_6, DA830_AXR0_7,
+ DA830_AXR0_8, DA830_AXR0_9, DA830_AXR0_10, DA830_AXR0_11,
+ DA830_AXR0_12, DA830_AXR0_13, DA830_AXR0_14, DA830_AXR0_15,
+ -1
+};
+
+const short da830_mcasp1_pins[] __initdata = {
+ DA830_AHCLKX1, DA830_ACLKX1, DA830_AFSX1,
+ DA830_AHCLKR1, DA830_ACLKR1, DA830_AFSR1, DA830_AMUTE1,
+ DA830_AXR1_0, DA830_AXR1_1, DA830_AXR1_2, DA830_AXR1_3,
+ DA830_AXR1_4, DA830_AXR1_5, DA830_AXR1_6, DA830_AXR1_7,
+ DA830_AXR1_8, DA830_AXR1_9, DA830_AXR1_10, DA830_AXR1_11,
+ -1
+};
+
+const short da830_mcasp2_pins[] __initdata = {
+ DA830_AHCLKX2, DA830_ACLKX2, DA830_AFSX2,
+ DA830_AHCLKR2, DA830_ACLKR2, DA830_AFSR2, DA830_AMUTE2,
+ DA830_AXR2_0, DA830_AXR2_1, DA830_AXR2_2, DA830_AXR2_3,
+ -1
+};
+
+const short da830_i2c0_pins[] __initdata = {
+ DA830_I2C0_SDA, DA830_I2C0_SCL,
+ -1
+};
+
+const short da830_i2c1_pins[] __initdata = {
+ DA830_I2C1_SCL, DA830_I2C1_SDA,
+ -1
+};
+
+const short da830_lcdcntl_pins[] __initdata = {
+ DA830_LCD_D_0, DA830_LCD_D_1, DA830_LCD_D_2, DA830_LCD_D_3,
+ DA830_LCD_D_4, DA830_LCD_D_5, DA830_LCD_D_6, DA830_LCD_D_7,
+ DA830_LCD_D_8, DA830_LCD_D_9, DA830_LCD_D_10, DA830_LCD_D_11,
+ DA830_LCD_D_12, DA830_LCD_D_13, DA830_LCD_D_14, DA830_LCD_D_15,
+ DA830_LCD_PCLK, DA830_LCD_HSYNC, DA830_LCD_VSYNC, DA830_NLCD_AC_ENB_CS,
+ DA830_LCD_MCLK,
+ -1
+};
+
+const short da830_pwm_pins[] __initdata = {
+ DA830_ECAP0_APWM0, DA830_ECAP1_APWM1, DA830_EPWM0B, DA830_EPWM0A,
+ DA830_EPWMSYNCI, DA830_EPWMSYNC0, DA830_ECAP2_APWM2, DA830_EHRPWMGLUETZ,
+ DA830_EPWM2B, DA830_EPWM2A, DA830_EPWM1B, DA830_EPWM1A,
+ -1
+};
+
+const short da830_ecap0_pins[] __initdata = {
+ DA830_ECAP0_APWM0,
+ -1
+};
+
+const short da830_ecap1_pins[] __initdata = {
+ DA830_ECAP1_APWM1,
+ -1
+};
+
+const short da830_ecap2_pins[] __initdata = {
+ DA830_ECAP2_APWM2,
+ -1
+};
+
+const short da830_eqep0_pins[] __initdata = {
+ DA830_EQEP0I, DA830_EQEP0S, DA830_EQEP0A, DA830_EQEP0B,
+ -1
+};
+
+const short da830_eqep1_pins[] __initdata = {
+ DA830_EQEP1I, DA830_EQEP1S, DA830_EQEP1A, DA830_EQEP1B,
+ -1
+};
+
+/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
+static u8 da830_default_priorities[DA830_N_CP_INTC_IRQ] = {
+ [IRQ_DA8XX_COMMTX] = 7,
+ [IRQ_DA8XX_COMMRX] = 7,
+ [IRQ_DA8XX_NINT] = 7,
+ [IRQ_DA8XX_EVTOUT0] = 7,
+ [IRQ_DA8XX_EVTOUT1] = 7,
+ [IRQ_DA8XX_EVTOUT2] = 7,
+ [IRQ_DA8XX_EVTOUT3] = 7,
+ [IRQ_DA8XX_EVTOUT4] = 7,
+ [IRQ_DA8XX_EVTOUT5] = 7,
+ [IRQ_DA8XX_EVTOUT6] = 7,
+ [IRQ_DA8XX_EVTOUT6] = 7,
+ [IRQ_DA8XX_EVTOUT7] = 7,
+ [IRQ_DA8XX_CCINT0] = 7,
+ [IRQ_DA8XX_CCERRINT] = 7,
+ [IRQ_DA8XX_TCERRINT0] = 7,
+ [IRQ_DA8XX_AEMIFINT] = 7,
+ [IRQ_DA8XX_I2CINT0] = 7,
+ [IRQ_DA8XX_MMCSDINT0] = 7,
+ [IRQ_DA8XX_MMCSDINT1] = 7,
+ [IRQ_DA8XX_ALLINT0] = 7,
+ [IRQ_DA8XX_RTC] = 7,
+ [IRQ_DA8XX_SPINT0] = 7,
+ [IRQ_DA8XX_TINT12_0] = 7,
+ [IRQ_DA8XX_TINT34_0] = 7,
+ [IRQ_DA8XX_TINT12_1] = 7,
+ [IRQ_DA8XX_TINT34_1] = 7,
+ [IRQ_DA8XX_UARTINT0] = 7,
+ [IRQ_DA8XX_KEYMGRINT] = 7,
+ [IRQ_DA8XX_SECINT] = 7,
+ [IRQ_DA8XX_SECKEYERR] = 7,
+ [IRQ_DA830_MPUERR] = 7,
+ [IRQ_DA830_IOPUERR] = 7,
+ [IRQ_DA830_BOOTCFGERR] = 7,
+ [IRQ_DA8XX_CHIPINT0] = 7,
+ [IRQ_DA8XX_CHIPINT1] = 7,
+ [IRQ_DA8XX_CHIPINT2] = 7,
+ [IRQ_DA8XX_CHIPINT3] = 7,
+ [IRQ_DA8XX_TCERRINT1] = 7,
+ [IRQ_DA8XX_C0_RX_THRESH_PULSE] = 7,
+ [IRQ_DA8XX_C0_RX_PULSE] = 7,
+ [IRQ_DA8XX_C0_TX_PULSE] = 7,
+ [IRQ_DA8XX_C0_MISC_PULSE] = 7,
+ [IRQ_DA8XX_C1_RX_THRESH_PULSE] = 7,
+ [IRQ_DA8XX_C1_RX_PULSE] = 7,
+ [IRQ_DA8XX_C1_TX_PULSE] = 7,
+ [IRQ_DA8XX_C1_MISC_PULSE] = 7,
+ [IRQ_DA8XX_MEMERR] = 7,
+ [IRQ_DA8XX_GPIO0] = 7,
+ [IRQ_DA8XX_GPIO1] = 7,
+ [IRQ_DA8XX_GPIO2] = 7,
+ [IRQ_DA8XX_GPIO3] = 7,
+ [IRQ_DA8XX_GPIO4] = 7,
+ [IRQ_DA8XX_GPIO5] = 7,
+ [IRQ_DA8XX_GPIO6] = 7,
+ [IRQ_DA8XX_GPIO7] = 7,
+ [IRQ_DA8XX_GPIO8] = 7,
+ [IRQ_DA8XX_I2CINT1] = 7,
+ [IRQ_DA8XX_LCDINT] = 7,
+ [IRQ_DA8XX_UARTINT1] = 7,
+ [IRQ_DA8XX_MCASPINT] = 7,
+ [IRQ_DA8XX_ALLINT1] = 7,
+ [IRQ_DA8XX_SPINT1] = 7,
+ [IRQ_DA8XX_UHPI_INT1] = 7,
+ [IRQ_DA8XX_USB_INT] = 7,
+ [IRQ_DA8XX_IRQN] = 7,
+ [IRQ_DA8XX_RWAKEUP] = 7,
+ [IRQ_DA8XX_UARTINT2] = 7,
+ [IRQ_DA8XX_DFTSSINT] = 7,
+ [IRQ_DA8XX_EHRPWM0] = 7,
+ [IRQ_DA8XX_EHRPWM0TZ] = 7,
+ [IRQ_DA8XX_EHRPWM1] = 7,
+ [IRQ_DA8XX_EHRPWM1TZ] = 7,
+ [IRQ_DA830_EHRPWM2] = 7,
+ [IRQ_DA830_EHRPWM2TZ] = 7,
+ [IRQ_DA8XX_ECAP0] = 7,
+ [IRQ_DA8XX_ECAP1] = 7,
+ [IRQ_DA8XX_ECAP2] = 7,
+ [IRQ_DA830_EQEP0] = 7,
+ [IRQ_DA830_EQEP1] = 7,
+ [IRQ_DA830_T12CMPINT0_0] = 7,
+ [IRQ_DA830_T12CMPINT1_0] = 7,
+ [IRQ_DA830_T12CMPINT2_0] = 7,
+ [IRQ_DA830_T12CMPINT3_0] = 7,
+ [IRQ_DA830_T12CMPINT4_0] = 7,
+ [IRQ_DA830_T12CMPINT5_0] = 7,
+ [IRQ_DA830_T12CMPINT6_0] = 7,
+ [IRQ_DA830_T12CMPINT7_0] = 7,
+ [IRQ_DA830_T12CMPINT0_1] = 7,
+ [IRQ_DA830_T12CMPINT1_1] = 7,
+ [IRQ_DA830_T12CMPINT2_1] = 7,
+ [IRQ_DA830_T12CMPINT3_1] = 7,
+ [IRQ_DA830_T12CMPINT4_1] = 7,
+ [IRQ_DA830_T12CMPINT5_1] = 7,
+ [IRQ_DA830_T12CMPINT6_1] = 7,
+ [IRQ_DA830_T12CMPINT7_1] = 7,
+ [IRQ_DA8XX_ARMCLKSTOPREQ] = 7,
+};
+
+static struct map_desc da830_io_desc[] = {
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = DA8XX_CP_INTC_VIRT,
+ .pfn = __phys_to_pfn(DA8XX_CP_INTC_BASE),
+ .length = DA8XX_CP_INTC_SIZE,
+ .type = MT_DEVICE
+ },
+};
+
+static void __iomem *da830_psc_bases[] = {
+ IO_ADDRESS(DA8XX_PSC0_BASE),
+ IO_ADDRESS(DA8XX_PSC1_BASE),
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id da830_ids[] = {
+ {
+ .variant = 0x0,
+ .part_no = 0xb7df,
+ .manufacturer = 0x017, /* 0x02f >> 1 */
+ .cpu_id = DAVINCI_CPU_ID_DA830,
+ .name = "da830/omap l137",
+ },
+};
+
+static struct davinci_timer_instance da830_timer_instance[2] = {
+ {
+ .base = IO_ADDRESS(DA8XX_TIMER64P0_BASE),
+ .bottom_irq = IRQ_DA8XX_TINT12_0,
+ .top_irq = IRQ_DA8XX_TINT34_0,
+ .cmp_off = DA830_CMP12_0,
+ .cmp_irq = IRQ_DA830_T12CMPINT0_0,
+ },
+ {
+ .base = IO_ADDRESS(DA8XX_TIMER64P1_BASE),
+ .bottom_irq = IRQ_DA8XX_TINT12_1,
+ .top_irq = IRQ_DA8XX_TINT34_1,
+ .cmp_off = DA830_CMP12_0,
+ .cmp_irq = IRQ_DA830_T12CMPINT0_1,
+ },
+};
+
+/*
+ * T0_BOT: Timer 0, bottom : Used for clock_event & clocksource
+ * T0_TOP: Timer 0, top : Used by DSP
+ * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer
+ */
+static struct davinci_timer_info da830_timer_info = {
+ .timers = da830_timer_instance,
+ .clockevent_id = T0_BOT,
+ .clocksource_id = T0_BOT,
+};
+
+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,
+ .intc_type = DAVINCI_INTC_TYPE_CP_INTC,
+ .intc_irq_prios = da830_default_priorities,
+ .intc_irq_num = DA830_N_CP_INTC_IRQ,
+ .timer_info = &da830_timer_info,
+ .gpio_base = IO_ADDRESS(DA8XX_GPIO_BASE),
+ .gpio_num = 128,
+ .gpio_irq = IRQ_DA8XX_GPIO0,
+ .serial_dev = &da8xx_serial_device,
+ .emac_pdata = &da8xx_emac_pdata,
+};
+
+void __init da830_init(void)
+{
+ davinci_common_init(&davinci_soc_info_da830);
+}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
new file mode 100644
index 000000000000..4a43ae2bec09
--- /dev/null
+++ b/arch/arm/mach-davinci/da850.c
@@ -0,0 +1,631 @@
+/*
+ * TI DA850/OMAP-L138 chip specific setup
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Derived from: arch/arm/mach-davinci/da830.c
+ * Original Copyrights follow:
+ *
+ * 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/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 "clock.h"
+#include "mux.h"
+
+#define DA850_PLL1_BASE 0x01e1a000
+#define DA850_TIMER64P2_BASE 0x01f0c000
+#define DA850_TIMER64P3_BASE 0x01f0d000
+
+#define DA850_REF_FREQ 24000000
+
+static struct pll_data pll0_data = {
+ .num = 1,
+ .phys_base = DA8XX_PLL0_BASE,
+ .flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
+};
+
+static struct clk ref_clk = {
+ .name = "ref_clk",
+ .rate = DA850_REF_FREQ,
+};
+
+static struct clk pll0_clk = {
+ .name = "pll0",
+ .parent = &ref_clk,
+ .pll_data = &pll0_data,
+ .flags = CLK_PLL,
+};
+
+static struct clk pll0_aux_clk = {
+ .name = "pll0_aux_clk",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll0_sysclk2 = {
+ .name = "pll0_sysclk2",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV2,
+};
+
+static struct clk pll0_sysclk3 = {
+ .name = "pll0_sysclk3",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV3,
+};
+
+static struct clk pll0_sysclk4 = {
+ .name = "pll0_sysclk4",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV4,
+};
+
+static struct clk pll0_sysclk5 = {
+ .name = "pll0_sysclk5",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV5,
+};
+
+static struct clk pll0_sysclk6 = {
+ .name = "pll0_sysclk6",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV6,
+};
+
+static struct clk pll0_sysclk7 = {
+ .name = "pll0_sysclk7",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV7,
+};
+
+static struct pll_data pll1_data = {
+ .num = 2,
+ .phys_base = DA850_PLL1_BASE,
+ .flags = PLL_HAS_POSTDIV,
+};
+
+static struct clk pll1_clk = {
+ .name = "pll1",
+ .parent = &ref_clk,
+ .pll_data = &pll1_data,
+ .flags = CLK_PLL,
+};
+
+static struct clk pll1_aux_clk = {
+ .name = "pll1_aux_clk",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll1_sysclk2 = {
+ .name = "pll1_sysclk2",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+ .name = "pll1_sysclk3",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+ .name = "pll1_sysclk4",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclk5 = {
+ .name = "pll1_sysclk5",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV5,
+};
+
+static struct clk pll1_sysclk6 = {
+ .name = "pll0_sysclk6",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV6,
+};
+
+static struct clk pll1_sysclk7 = {
+ .name = "pll1_sysclk7",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV7,
+};
+
+static struct clk i2c0_clk = {
+ .name = "i2c0",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk timerp64_0_clk = {
+ .name = "timer0",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk timerp64_1_clk = {
+ .name = "timer1",
+ .parent = &pll0_aux_clk,
+};
+
+static struct clk arm_rom_clk = {
+ .name = "arm_rom",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_ARM_RAM_ROM,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk tpcc0_clk = {
+ .name = "tpcc0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPCC,
+ .flags = ALWAYS_ENABLED | CLK_PSC,
+};
+
+static struct clk tptc0_clk = {
+ .name = "tptc0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPTC0,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk tptc1_clk = {
+ .name = "tptc1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_TPTC1,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk tpcc1_clk = {
+ .name = "tpcc1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA850_LPSC1_TPCC1,
+ .flags = CLK_PSC | ALWAYS_ENABLED,
+ .psc_ctlr = 1,
+};
+
+static struct clk tptc2_clk = {
+ .name = "tptc2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA850_LPSC1_TPTC2,
+ .flags = ALWAYS_ENABLED,
+ .psc_ctlr = 1,
+};
+
+static struct clk uart0_clk = {
+ .name = "uart0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_UART0,
+};
+
+static struct clk uart1_clk = {
+ .name = "uart1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_UART1,
+ .psc_ctlr = 1,
+};
+
+static struct clk uart2_clk = {
+ .name = "uart2",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_UART2,
+ .psc_ctlr = 1,
+};
+
+static struct clk aintc_clk = {
+ .name = "aintc",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC0_AINTC,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk gpio_clk = {
+ .name = "gpio",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_GPIO,
+ .psc_ctlr = 1,
+};
+
+static struct clk i2c1_clk = {
+ .name = "i2c1",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_I2C,
+ .psc_ctlr = 1,
+};
+
+static struct clk emif3_clk = {
+ .name = "emif3",
+ .parent = &pll0_sysclk5,
+ .lpsc = DA8XX_LPSC1_EMIF3C,
+ .flags = ALWAYS_ENABLED,
+ .psc_ctlr = 1,
+};
+
+static struct clk arm_clk = {
+ .name = "arm",
+ .parent = &pll0_sysclk6,
+ .lpsc = DA8XX_LPSC0_ARM,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk rmii_clk = {
+ .name = "rmii",
+ .parent = &pll0_sysclk7,
+};
+
+static struct clk emac_clk = {
+ .name = "emac",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_CPGMAC,
+};
+
+static struct davinci_clk da850_clks[] = {
+ CLK(NULL, "ref", &ref_clk),
+ CLK(NULL, "pll0", &pll0_clk),
+ CLK(NULL, "pll0_aux", &pll0_aux_clk),
+ CLK(NULL, "pll0_sysclk2", &pll0_sysclk2),
+ CLK(NULL, "pll0_sysclk3", &pll0_sysclk3),
+ CLK(NULL, "pll0_sysclk4", &pll0_sysclk4),
+ CLK(NULL, "pll0_sysclk5", &pll0_sysclk5),
+ CLK(NULL, "pll0_sysclk6", &pll0_sysclk6),
+ CLK(NULL, "pll0_sysclk7", &pll0_sysclk7),
+ CLK(NULL, "pll1", &pll1_clk),
+ CLK(NULL, "pll1_aux", &pll1_aux_clk),
+ CLK(NULL, "pll1_sysclk2", &pll1_sysclk2),
+ CLK(NULL, "pll1_sysclk3", &pll1_sysclk3),
+ CLK(NULL, "pll1_sysclk4", &pll1_sysclk4),
+ CLK(NULL, "pll1_sysclk5", &pll1_sysclk5),
+ CLK(NULL, "pll1_sysclk6", &pll1_sysclk6),
+ CLK(NULL, "pll1_sysclk7", &pll1_sysclk7),
+ CLK("i2c_davinci.1", NULL, &i2c0_clk),
+ CLK(NULL, "timer0", &timerp64_0_clk),
+ CLK("watchdog", NULL, &timerp64_1_clk),
+ CLK(NULL, "arm_rom", &arm_rom_clk),
+ CLK(NULL, "tpcc0", &tpcc0_clk),
+ CLK(NULL, "tptc0", &tptc0_clk),
+ CLK(NULL, "tptc1", &tptc1_clk),
+ CLK(NULL, "tpcc1", &tpcc1_clk),
+ CLK(NULL, "tptc2", &tptc2_clk),
+ CLK(NULL, "uart0", &uart0_clk),
+ CLK(NULL, "uart1", &uart1_clk),
+ CLK(NULL, "uart2", &uart2_clk),
+ CLK(NULL, "aintc", &aintc_clk),
+ CLK(NULL, "gpio", &gpio_clk),
+ CLK("i2c_davinci.2", NULL, &i2c1_clk),
+ CLK(NULL, "emif3", &emif3_clk),
+ CLK(NULL, "arm", &arm_clk),
+ CLK(NULL, "rmii", &rmii_clk),
+ CLK("davinci_emac.1", NULL, &emac_clk),
+ CLK(NULL, NULL, NULL),
+};
+
+/*
+ * Device specific mux setup
+ *
+ * soc description mux mode mode mux dbg
+ * reg offset mask mode
+ */
+static const struct mux_config da850_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+ /* UART0 function */
+ MUX_CFG(DA850, NUART0_CTS, 3, 24, 15, 2, false)
+ MUX_CFG(DA850, NUART0_RTS, 3, 28, 15, 2, false)
+ MUX_CFG(DA850, UART0_RXD, 3, 16, 15, 2, false)
+ MUX_CFG(DA850, UART0_TXD, 3, 20, 15, 2, false)
+ /* UART1 function */
+ MUX_CFG(DA850, UART1_RXD, 4, 24, 15, 2, false)
+ MUX_CFG(DA850, UART1_TXD, 4, 28, 15, 2, false)
+ /* UART2 function */
+ MUX_CFG(DA850, UART2_RXD, 4, 16, 15, 2, false)
+ MUX_CFG(DA850, UART2_TXD, 4, 20, 15, 2, false)
+ /* I2C1 function */
+ MUX_CFG(DA850, I2C1_SCL, 4, 16, 15, 4, false)
+ MUX_CFG(DA850, I2C1_SDA, 4, 20, 15, 4, false)
+ /* I2C0 function */
+ MUX_CFG(DA850, I2C0_SDA, 4, 12, 15, 2, false)
+ MUX_CFG(DA850, I2C0_SCL, 4, 8, 15, 2, false)
+ /* EMAC function */
+ MUX_CFG(DA850, MII_TXEN, 2, 4, 15, 8, false)
+ MUX_CFG(DA850, MII_TXCLK, 2, 8, 15, 8, false)
+ MUX_CFG(DA850, MII_COL, 2, 12, 15, 8, false)
+ MUX_CFG(DA850, MII_TXD_3, 2, 16, 15, 8, false)
+ MUX_CFG(DA850, MII_TXD_2, 2, 20, 15, 8, false)
+ MUX_CFG(DA850, MII_TXD_1, 2, 24, 15, 8, false)
+ MUX_CFG(DA850, MII_TXD_0, 2, 28, 15, 8, false)
+ MUX_CFG(DA850, MII_RXCLK, 3, 0, 15, 8, false)
+ MUX_CFG(DA850, MII_RXDV, 3, 4, 15, 8, false)
+ MUX_CFG(DA850, MII_RXER, 3, 8, 15, 8, false)
+ MUX_CFG(DA850, MII_CRS, 3, 12, 15, 8, false)
+ MUX_CFG(DA850, MII_RXD_3, 3, 16, 15, 8, false)
+ MUX_CFG(DA850, MII_RXD_2, 3, 20, 15, 8, false)
+ MUX_CFG(DA850, MII_RXD_1, 3, 24, 15, 8, false)
+ MUX_CFG(DA850, MII_RXD_0, 3, 28, 15, 8, false)
+#endif
+};
+
+const short da850_uart0_pins[] __initdata = {
+ DA850_NUART0_CTS, DA850_NUART0_RTS, DA850_UART0_RXD, DA850_UART0_TXD,
+ -1
+};
+
+const short da850_uart1_pins[] __initdata = {
+ DA850_UART1_RXD, DA850_UART1_TXD,
+ -1
+};
+
+const short da850_uart2_pins[] __initdata = {
+ DA850_UART2_RXD, DA850_UART2_TXD,
+ -1
+};
+
+const short da850_i2c0_pins[] __initdata = {
+ DA850_I2C0_SDA, DA850_I2C0_SCL,
+ -1
+};
+
+const short da850_i2c1_pins[] __initdata = {
+ DA850_I2C1_SCL, DA850_I2C1_SDA,
+ -1
+};
+
+const short da850_cpgmac_pins[] __initdata = {
+ DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+ DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+ DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+ DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0,
+ -1
+};
+
+/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
+static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
+ [IRQ_DA8XX_COMMTX] = 7,
+ [IRQ_DA8XX_COMMRX] = 7,
+ [IRQ_DA8XX_NINT] = 7,
+ [IRQ_DA8XX_EVTOUT0] = 7,
+ [IRQ_DA8XX_EVTOUT1] = 7,
+ [IRQ_DA8XX_EVTOUT2] = 7,
+ [IRQ_DA8XX_EVTOUT3] = 7,
+ [IRQ_DA8XX_EVTOUT4] = 7,
+ [IRQ_DA8XX_EVTOUT5] = 7,
+ [IRQ_DA8XX_EVTOUT6] = 7,
+ [IRQ_DA8XX_EVTOUT6] = 7,
+ [IRQ_DA8XX_EVTOUT7] = 7,
+ [IRQ_DA8XX_CCINT0] = 7,
+ [IRQ_DA8XX_CCERRINT] = 7,
+ [IRQ_DA8XX_TCERRINT0] = 7,
+ [IRQ_DA8XX_AEMIFINT] = 7,
+ [IRQ_DA8XX_I2CINT0] = 7,
+ [IRQ_DA8XX_MMCSDINT0] = 7,
+ [IRQ_DA8XX_MMCSDINT1] = 7,
+ [IRQ_DA8XX_ALLINT0] = 7,
+ [IRQ_DA8XX_RTC] = 7,
+ [IRQ_DA8XX_SPINT0] = 7,
+ [IRQ_DA8XX_TINT12_0] = 7,
+ [IRQ_DA8XX_TINT34_0] = 7,
+ [IRQ_DA8XX_TINT12_1] = 7,
+ [IRQ_DA8XX_TINT34_1] = 7,
+ [IRQ_DA8XX_UARTINT0] = 7,
+ [IRQ_DA8XX_KEYMGRINT] = 7,
+ [IRQ_DA8XX_SECINT] = 7,
+ [IRQ_DA8XX_SECKEYERR] = 7,
+ [IRQ_DA850_MPUADDRERR0] = 7,
+ [IRQ_DA850_MPUPROTERR0] = 7,
+ [IRQ_DA850_IOPUADDRERR0] = 7,
+ [IRQ_DA850_IOPUPROTERR0] = 7,
+ [IRQ_DA850_IOPUADDRERR1] = 7,
+ [IRQ_DA850_IOPUPROTERR1] = 7,
+ [IRQ_DA850_IOPUADDRERR2] = 7,
+ [IRQ_DA850_IOPUPROTERR2] = 7,
+ [IRQ_DA850_BOOTCFG_ADDR_ERR] = 7,
+ [IRQ_DA850_BOOTCFG_PROT_ERR] = 7,
+ [IRQ_DA850_MPUADDRERR1] = 7,
+ [IRQ_DA850_MPUPROTERR1] = 7,
+ [IRQ_DA850_IOPUADDRERR3] = 7,
+ [IRQ_DA850_IOPUPROTERR3] = 7,
+ [IRQ_DA850_IOPUADDRERR4] = 7,
+ [IRQ_DA850_IOPUPROTERR4] = 7,
+ [IRQ_DA850_IOPUADDRERR5] = 7,
+ [IRQ_DA850_IOPUPROTERR5] = 7,
+ [IRQ_DA850_MIOPU_BOOTCFG_ERR] = 7,
+ [IRQ_DA8XX_CHIPINT0] = 7,
+ [IRQ_DA8XX_CHIPINT1] = 7,
+ [IRQ_DA8XX_CHIPINT2] = 7,
+ [IRQ_DA8XX_CHIPINT3] = 7,
+ [IRQ_DA8XX_TCERRINT1] = 7,
+ [IRQ_DA8XX_C0_RX_THRESH_PULSE] = 7,
+ [IRQ_DA8XX_C0_RX_PULSE] = 7,
+ [IRQ_DA8XX_C0_TX_PULSE] = 7,
+ [IRQ_DA8XX_C0_MISC_PULSE] = 7,
+ [IRQ_DA8XX_C1_RX_THRESH_PULSE] = 7,
+ [IRQ_DA8XX_C1_RX_PULSE] = 7,
+ [IRQ_DA8XX_C1_TX_PULSE] = 7,
+ [IRQ_DA8XX_C1_MISC_PULSE] = 7,
+ [IRQ_DA8XX_MEMERR] = 7,
+ [IRQ_DA8XX_GPIO0] = 7,
+ [IRQ_DA8XX_GPIO1] = 7,
+ [IRQ_DA8XX_GPIO2] = 7,
+ [IRQ_DA8XX_GPIO3] = 7,
+ [IRQ_DA8XX_GPIO4] = 7,
+ [IRQ_DA8XX_GPIO5] = 7,
+ [IRQ_DA8XX_GPIO6] = 7,
+ [IRQ_DA8XX_GPIO7] = 7,
+ [IRQ_DA8XX_GPIO8] = 7,
+ [IRQ_DA8XX_I2CINT1] = 7,
+ [IRQ_DA8XX_LCDINT] = 7,
+ [IRQ_DA8XX_UARTINT1] = 7,
+ [IRQ_DA8XX_MCASPINT] = 7,
+ [IRQ_DA8XX_ALLINT1] = 7,
+ [IRQ_DA8XX_SPINT1] = 7,
+ [IRQ_DA8XX_UHPI_INT1] = 7,
+ [IRQ_DA8XX_USB_INT] = 7,
+ [IRQ_DA8XX_IRQN] = 7,
+ [IRQ_DA8XX_RWAKEUP] = 7,
+ [IRQ_DA8XX_UARTINT2] = 7,
+ [IRQ_DA8XX_DFTSSINT] = 7,
+ [IRQ_DA8XX_EHRPWM0] = 7,
+ [IRQ_DA8XX_EHRPWM0TZ] = 7,
+ [IRQ_DA8XX_EHRPWM1] = 7,
+ [IRQ_DA8XX_EHRPWM1TZ] = 7,
+ [IRQ_DA850_SATAINT] = 7,
+ [IRQ_DA850_TINT12_2] = 7,
+ [IRQ_DA850_TINT34_2] = 7,
+ [IRQ_DA850_TINTALL_2] = 7,
+ [IRQ_DA8XX_ECAP0] = 7,
+ [IRQ_DA8XX_ECAP1] = 7,
+ [IRQ_DA8XX_ECAP2] = 7,
+ [IRQ_DA850_MMCSDINT0_1] = 7,
+ [IRQ_DA850_MMCSDINT1_1] = 7,
+ [IRQ_DA850_T12CMPINT0_2] = 7,
+ [IRQ_DA850_T12CMPINT1_2] = 7,
+ [IRQ_DA850_T12CMPINT2_2] = 7,
+ [IRQ_DA850_T12CMPINT3_2] = 7,
+ [IRQ_DA850_T12CMPINT4_2] = 7,
+ [IRQ_DA850_T12CMPINT5_2] = 7,
+ [IRQ_DA850_T12CMPINT6_2] = 7,
+ [IRQ_DA850_T12CMPINT7_2] = 7,
+ [IRQ_DA850_T12CMPINT0_3] = 7,
+ [IRQ_DA850_T12CMPINT1_3] = 7,
+ [IRQ_DA850_T12CMPINT2_3] = 7,
+ [IRQ_DA850_T12CMPINT3_3] = 7,
+ [IRQ_DA850_T12CMPINT4_3] = 7,
+ [IRQ_DA850_T12CMPINT5_3] = 7,
+ [IRQ_DA850_T12CMPINT6_3] = 7,
+ [IRQ_DA850_T12CMPINT7_3] = 7,
+ [IRQ_DA850_RPIINT] = 7,
+ [IRQ_DA850_VPIFINT] = 7,
+ [IRQ_DA850_CCINT1] = 7,
+ [IRQ_DA850_CCERRINT1] = 7,
+ [IRQ_DA850_TCERRINT2] = 7,
+ [IRQ_DA850_TINT12_3] = 7,
+ [IRQ_DA850_TINT34_3] = 7,
+ [IRQ_DA850_TINTALL_3] = 7,
+ [IRQ_DA850_MCBSP0RINT] = 7,
+ [IRQ_DA850_MCBSP0XINT] = 7,
+ [IRQ_DA850_MCBSP1RINT] = 7,
+ [IRQ_DA850_MCBSP1XINT] = 7,
+ [IRQ_DA8XX_ARMCLKSTOPREQ] = 7,
+};
+
+static struct map_desc da850_io_desc[] = {
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = DA8XX_CP_INTC_VIRT,
+ .pfn = __phys_to_pfn(DA8XX_CP_INTC_BASE),
+ .length = DA8XX_CP_INTC_SIZE,
+ .type = MT_DEVICE
+ },
+};
+
+static void __iomem *da850_psc_bases[] = {
+ IO_ADDRESS(DA8XX_PSC0_BASE),
+ IO_ADDRESS(DA8XX_PSC1_BASE),
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id da850_ids[] = {
+ {
+ .variant = 0x0,
+ .part_no = 0xb7d1,
+ .manufacturer = 0x017, /* 0x02f >> 1 */
+ .cpu_id = DAVINCI_CPU_ID_DA850,
+ .name = "da850/omap-l138",
+ },
+};
+
+static struct davinci_timer_instance da850_timer_instance[4] = {
+ {
+ .base = IO_ADDRESS(DA8XX_TIMER64P0_BASE),
+ .bottom_irq = IRQ_DA8XX_TINT12_0,
+ .top_irq = IRQ_DA8XX_TINT34_0,
+ },
+ {
+ .base = IO_ADDRESS(DA8XX_TIMER64P1_BASE),
+ .bottom_irq = IRQ_DA8XX_TINT12_1,
+ .top_irq = IRQ_DA8XX_TINT34_1,
+ },
+ {
+ .base = IO_ADDRESS(DA850_TIMER64P2_BASE),
+ .bottom_irq = IRQ_DA850_TINT12_2,
+ .top_irq = IRQ_DA850_TINT34_2,
+ },
+ {
+ .base = IO_ADDRESS(DA850_TIMER64P3_BASE),
+ .bottom_irq = IRQ_DA850_TINT12_3,
+ .top_irq = IRQ_DA850_TINT34_3,
+ },
+};
+
+/*
+ * T0_BOT: Timer 0, bottom : Used for clock_event
+ * T0_TOP: Timer 0, top : Used for clocksource
+ * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer
+ */
+static struct davinci_timer_info da850_timer_info = {
+ .timers = da850_timer_instance,
+ .clockevent_id = T0_BOT,
+ .clocksource_id = T0_TOP,
+};
+
+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,
+ .intc_type = DAVINCI_INTC_TYPE_CP_INTC,
+ .intc_irq_prios = da850_default_priorities,
+ .intc_irq_num = DA850_N_CP_INTC_IRQ,
+ .timer_info = &da850_timer_info,
+ .gpio_base = IO_ADDRESS(DA8XX_GPIO_BASE),
+ .gpio_num = 128,
+ .gpio_irq = IRQ_DA8XX_GPIO0,
+ .serial_dev = &da8xx_serial_device,
+ .emac_pdata = &da8xx_emac_pdata,
+};
+
+void __init da850_init(void)
+{
+ davinci_common_init(&davinci_soc_info_da850);
+}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
new file mode 100644
index 000000000000..11c0971e13a6
--- /dev/null
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -0,0 +1,287 @@
+/*
+ * DA8XX/OMAP L1XX platform device data
+ *
+ * Copyright (c) 2007-2009, MontaVista Software, Inc. <source@mvista.com>
+ * Derived from code that was:
+ * Copyright (C) 2006 Komal Shah <komal_shah802003@yahoo.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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_8250.h>
+
+#include <mach/cputype.h>
+#include <mach/common.h>
+#include <mach/time.h>
+#include <mach/da8xx.h>
+
+#include "clock.h"
+
+#define DA8XX_TPCC_BASE 0x01c00000
+#define DA8XX_TPTC0_BASE 0x01c08000
+#define DA8XX_TPTC1_BASE 0x01c08400
+#define DA8XX_WDOG_BASE 0x01c21000 /* DA8XX_TIMER64P1_BASE */
+#define DA8XX_I2C0_BASE 0x01c22000
+#define DA8XX_EMAC_CPPI_PORT_BASE 0x01e20000
+#define DA8XX_EMAC_CPGMACSS_BASE 0x01e22000
+#define DA8XX_EMAC_CPGMAC_BASE 0x01e23000
+#define DA8XX_EMAC_MDIO_BASE 0x01e24000
+#define DA8XX_GPIO_BASE 0x01e26000
+#define DA8XX_I2C1_BASE 0x01e28000
+
+#define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000
+#define DA8XX_EMAC_MOD_REG_OFFSET 0x2000
+#define DA8XX_EMAC_RAM_OFFSET 0x0000
+#define DA8XX_MDIO_REG_OFFSET 0x4000
+#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
+
+static struct plat_serial8250_port da8xx_serial_pdata[] = {
+ {
+ .mapbase = DA8XX_UART0_BASE,
+ .irq = IRQ_DA8XX_UARTINT0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_IOREMAP,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ },
+ {
+ .mapbase = DA8XX_UART1_BASE,
+ .irq = IRQ_DA8XX_UARTINT1,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_IOREMAP,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ },
+ {
+ .mapbase = DA8XX_UART2_BASE,
+ .irq = IRQ_DA8XX_UARTINT2,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_IOREMAP,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ },
+ {
+ .flags = 0,
+ },
+};
+
+struct platform_device da8xx_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = da8xx_serial_pdata,
+ },
+};
+
+static const s8 da8xx_dma_chan_no_event[] = {
+ 20, 21,
+ -1
+};
+
+static const s8 da8xx_queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {-1, -1}
+};
+
+static const s8 da8xx_queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 3},
+ {1, 7},
+ {-1, -1}
+};
+
+static struct edma_soc_info da8xx_edma_info[] = {
+ {
+ .n_channel = 32,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .noevent = da8xx_dma_chan_no_event,
+ .queue_tc_mapping = da8xx_queue_tc_mapping,
+ .queue_priority_mapping = da8xx_queue_priority_mapping,
+ },
+};
+
+static struct resource da8xx_edma_resources[] = {
+ {
+ .name = "edma_cc0",
+ .start = DA8XX_TPCC_BASE,
+ .end = DA8XX_TPCC_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc0",
+ .start = DA8XX_TPTC0_BASE,
+ .end = DA8XX_TPTC0_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc1",
+ .start = DA8XX_TPTC1_BASE,
+ .end = DA8XX_TPTC1_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma0",
+ .start = IRQ_DA8XX_CCINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma0_err",
+ .start = IRQ_DA8XX_CCERRINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da8xx_edma_device = {
+ .name = "edma",
+ .id = -1,
+ .dev = {
+ .platform_data = da8xx_edma_info,
+ },
+ .num_resources = ARRAY_SIZE(da8xx_edma_resources),
+ .resource = da8xx_edma_resources,
+};
+
+int __init da8xx_register_edma(void)
+{
+ return platform_device_register(&da8xx_edma_device);
+}
+
+static struct resource da8xx_i2c_resources0[] = {
+ {
+ .start = DA8XX_I2C0_BASE,
+ .end = DA8XX_I2C0_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DA8XX_I2CINT0,
+ .end = IRQ_DA8XX_I2CINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da8xx_i2c_device0 = {
+ .name = "i2c_davinci",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(da8xx_i2c_resources0),
+ .resource = da8xx_i2c_resources0,
+};
+
+static struct resource da8xx_i2c_resources1[] = {
+ {
+ .start = DA8XX_I2C1_BASE,
+ .end = DA8XX_I2C1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DA8XX_I2CINT1,
+ .end = IRQ_DA8XX_I2CINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da8xx_i2c_device1 = {
+ .name = "i2c_davinci",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(da8xx_i2c_resources1),
+ .resource = da8xx_i2c_resources1,
+};
+
+int __init da8xx_register_i2c(int instance,
+ struct davinci_i2c_platform_data *pdata)
+{
+ struct platform_device *pdev;
+
+ if (instance == 0)
+ pdev = &da8xx_i2c_device0;
+ else if (instance == 1)
+ pdev = &da8xx_i2c_device1;
+ else
+ return -EINVAL;
+
+ pdev->dev.platform_data = pdata;
+ return platform_device_register(pdev);
+}
+
+static struct resource da8xx_watchdog_resources[] = {
+ {
+ .start = DA8XX_WDOG_BASE,
+ .end = DA8XX_WDOG_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device davinci_wdt_device = {
+ .name = "watchdog",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(da8xx_watchdog_resources),
+ .resource = da8xx_watchdog_resources,
+};
+
+int __init da8xx_register_watchdog(void)
+{
+ return platform_device_register(&davinci_wdt_device);
+}
+
+static struct resource da8xx_emac_resources[] = {
+ {
+ .start = DA8XX_EMAC_CPPI_PORT_BASE,
+ .end = DA8XX_EMAC_CPPI_PORT_BASE + 0x5000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DA8XX_C0_RX_THRESH_PULSE,
+ .end = IRQ_DA8XX_C0_RX_THRESH_PULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DA8XX_C0_RX_PULSE,
+ .end = IRQ_DA8XX_C0_RX_PULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DA8XX_C0_TX_PULSE,
+ .end = IRQ_DA8XX_C0_TX_PULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DA8XX_C0_MISC_PULSE,
+ .end = IRQ_DA8XX_C0_MISC_PULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct emac_platform_data da8xx_emac_pdata = {
+ .ctrl_reg_offset = DA8XX_EMAC_CTRL_REG_OFFSET,
+ .ctrl_mod_reg_offset = DA8XX_EMAC_MOD_REG_OFFSET,
+ .ctrl_ram_offset = DA8XX_EMAC_RAM_OFFSET,
+ .mdio_reg_offset = DA8XX_MDIO_REG_OFFSET,
+ .ctrl_ram_size = DA8XX_EMAC_CTRL_RAM_SIZE,
+ .version = EMAC_VERSION_2,
+};
+
+static struct platform_device da8xx_emac_device = {
+ .name = "davinci_emac",
+ .id = 1,
+ .dev = {
+ .platform_data = &da8xx_emac_pdata,
+ },
+ .num_resources = ARRAY_SIZE(da8xx_emac_resources),
+ .resource = da8xx_emac_resources,
+};
+
+int __init da8xx_register_emac(void)
+{
+ return platform_device_register(&da8xx_emac_device);
+}
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index de16f347566a..a55b650db71e 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -31,6 +31,8 @@
#define DAVINCI_MMCSD0_BASE 0x01E10000
#define DM355_MMCSD0_BASE 0x01E11000
#define DM355_MMCSD1_BASE 0x01E00000
+#define DM365_MMCSD0_BASE 0x01D11000
+#define DM365_MMCSD1_BASE 0x01D00000
static struct resource i2c_resources[] = {
{
@@ -82,10 +84,10 @@ static struct resource mmcsd0_resources[] = {
},
/* DMA channels: RX, then TX */
{
- .start = DAVINCI_DMA_MMCRXEVT,
+ .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCRXEVT),
.flags = IORESOURCE_DMA,
}, {
- .start = DAVINCI_DMA_MMCTXEVT,
+ .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCTXEVT),
.flags = IORESOURCE_DMA,
},
};
@@ -119,10 +121,10 @@ static struct resource mmcsd1_resources[] = {
},
/* DMA channels: RX, then TX */
{
- .start = 30, /* rx */
+ .start = EDMA_CTLR_CHAN(0, 30), /* rx */
.flags = IORESOURCE_DMA,
}, {
- .start = 31, /* tx */
+ .start = EDMA_CTLR_CHAN(0, 31), /* tx */
.flags = IORESOURCE_DMA,
},
};
@@ -154,19 +156,31 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
*/
switch (module) {
case 1:
- if (!cpu_is_davinci_dm355())
+ if (cpu_is_davinci_dm355()) {
+ /* REVISIT we may not need all these pins if e.g. this
+ * is a hard-wired SDIO device...
+ */
+ davinci_cfg_reg(DM355_SD1_CMD);
+ davinci_cfg_reg(DM355_SD1_CLK);
+ davinci_cfg_reg(DM355_SD1_DATA0);
+ davinci_cfg_reg(DM355_SD1_DATA1);
+ davinci_cfg_reg(DM355_SD1_DATA2);
+ davinci_cfg_reg(DM355_SD1_DATA3);
+ } else if (cpu_is_davinci_dm365()) {
+ void __iomem *pupdctl1 =
+ IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
+
+ /* Configure pull down control */
+ __raw_writel((__raw_readl(pupdctl1) & ~0x400),
+ pupdctl1);
+
+ mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
+ mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
+ SZ_4K - 1;
+ mmcsd0_resources[2].start = IRQ_DM365_SDIOINT1;
+ } else
break;
- /* REVISIT we may not need all these pins if e.g. this
- * is a hard-wired SDIO device...
- */
- davinci_cfg_reg(DM355_SD1_CMD);
- davinci_cfg_reg(DM355_SD1_CLK);
- davinci_cfg_reg(DM355_SD1_DATA0);
- davinci_cfg_reg(DM355_SD1_DATA1);
- davinci_cfg_reg(DM355_SD1_DATA2);
- davinci_cfg_reg(DM355_SD1_DATA3);
-
pdev = &davinci_mmcsd1_device;
break;
case 0:
@@ -180,9 +194,12 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
/* enable RX EDMA */
davinci_cfg_reg(DM355_EVT26_MMC0_RX);
- }
-
- else if (cpu_is_davinci_dm644x()) {
+ } else if (cpu_is_davinci_dm365()) {
+ mmcsd0_resources[0].start = DM365_MMCSD0_BASE;
+ mmcsd0_resources[0].end = DM365_MMCSD0_BASE +
+ SZ_4K - 1;
+ mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0;
+ } else if (cpu_is_davinci_dm644x()) {
/* REVISIT: should this be in board-init code? */
void __iomem *base =
IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
@@ -216,6 +233,8 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
static struct resource wdt_resources[] = {
{
+ .start = DAVINCI_WDOG_BASE,
+ .end = DAVINCI_WDOG_BASE + SZ_1K - 1,
.flags = IORESOURCE_MEM,
},
};
@@ -229,11 +248,6 @@ struct platform_device davinci_wdt_device = {
static void davinci_init_wdt(void)
{
- struct davinci_soc_info *soc_info = &davinci_soc_info;
-
- wdt_resources[0].start = (resource_size_t)soc_info->wdt_base;
- wdt_resources[0].end = (resource_size_t)soc_info->wdt_base + SZ_1K - 1;
-
platform_device_register(&davinci_wdt_device);
}
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index baaaf328de2e..3cae0266e2ff 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -30,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"
@@ -360,8 +361,8 @@ static struct davinci_clk dm355_clks[] = {
CLK(NULL, "uart1", &uart1_clk),
CLK(NULL, "uart2", &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
- CLK("soc-audio.0", NULL, &asp0_clk),
- CLK("soc-audio.1", NULL, &asp1_clk),
+ CLK("davinci-asp.0", NULL, &asp0_clk),
+ CLK("davinci-asp.1", NULL, &asp1_clk),
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK(NULL, "spi0", &spi0_clk),
@@ -481,6 +482,14 @@ INT_CFG(DM355, INT_EDMA_TC1_ERR, 4, 1, 1, false)
EVT_CFG(DM355, EVT8_ASP1_TX, 0, 1, 0, false)
EVT_CFG(DM355, EVT9_ASP1_RX, 1, 1, 0, false)
EVT_CFG(DM355, EVT26_MMC0_RX, 2, 1, 0, false)
+
+MUX_CFG(DM355, VIN_PCLK, 0, 14, 1, 1, false)
+MUX_CFG(DM355, VIN_CAM_WEN, 0, 13, 1, 1, false)
+MUX_CFG(DM355, VIN_CAM_VD, 0, 12, 1, 1, false)
+MUX_CFG(DM355, VIN_CAM_HD, 0, 11, 1, 1, false)
+MUX_CFG(DM355, VIN_YIN_EN, 0, 10, 1, 1, false)
+MUX_CFG(DM355, VIN_CINL_EN, 0, 0, 0xff, 0x55, false)
+MUX_CFG(DM355, VIN_CINH_EN, 0, 8, 3, 3, false)
#endif
};
@@ -558,17 +567,38 @@ static const s8 dma_chan_dm355_no_event[] = {
-1
};
-static struct edma_soc_info dm355_edma_info = {
- .n_channel = 64,
- .n_region = 4,
- .n_slot = 128,
- .n_tc = 2,
- .noevent = dma_chan_dm355_no_event,
+static const s8
+queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {-1, -1},
+};
+
+static const s8
+queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 3},
+ {1, 7},
+ {-1, -1},
+};
+
+static struct edma_soc_info dm355_edma_info[] = {
+ {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .noevent = dma_chan_dm355_no_event,
+ .queue_tc_mapping = queue_tc_mapping,
+ .queue_priority_mapping = queue_priority_mapping,
+ },
};
static struct resource edma_resources[] = {
{
- .name = "edma_cc",
+ .name = "edma_cc0",
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
@@ -586,10 +616,12 @@ static struct resource edma_resources[] = {
.flags = IORESOURCE_MEM,
},
{
+ .name = "edma0",
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
+ .name = "edma0_err",
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
@@ -598,12 +630,98 @@ static struct resource edma_resources[] = {
static struct platform_device dm355_edma_device = {
.name = "edma",
- .id = -1,
- .dev.platform_data = &dm355_edma_info,
+ .id = 0,
+ .dev.platform_data = dm355_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
+static struct resource dm355_asp1_resources[] = {
+ {
+ .start = DAVINCI_ASP1_BASE,
+ .end = DAVINCI_ASP1_BASE + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DAVINCI_DMA_ASP1_TX,
+ .end = DAVINCI_DMA_ASP1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DAVINCI_DMA_ASP1_RX,
+ .end = DAVINCI_DMA_ASP1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device dm355_asp1_device = {
+ .name = "davinci-asp",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(dm355_asp1_resources),
+ .resource = dm355_asp1_resources,
+};
+
+static struct resource dm355_vpss_resources[] = {
+ {
+ /* VPSS BL Base address */
+ .name = "vpss",
+ .start = 0x01c70800,
+ .end = 0x01c70800 + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* VPSS CLK Base address */
+ .name = "vpss",
+ .start = 0x01c70000,
+ .end = 0x01c70000 + 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm355_vpss_device = {
+ .name = "vpss",
+ .id = -1,
+ .dev.platform_data = "dm355_vpss",
+ .num_resources = ARRAY_SIZE(dm355_vpss_resources),
+ .resource = dm355_vpss_resources,
+};
+
+static struct resource vpfe_resources[] = {
+ {
+ .start = IRQ_VDINT0,
+ .end = IRQ_VDINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_VDINT1,
+ .end = IRQ_VDINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* CCDC Base address */
+ {
+ .flags = IORESOURCE_MEM,
+ .start = 0x01c70600,
+ .end = 0x01c70600 + 0x1ff,
+ },
+};
+
+static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device vpfe_capture_dev = {
+ .name = CAPTURE_DRV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(vpfe_resources),
+ .resource = vpfe_resources,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void dm355_set_vpfe_config(struct vpfe_config *cfg)
+{
+ vpfe_capture_dev.dev.platform_data = cfg;
+}
+
/*----------------------------------------------------------------------*/
static struct map_desc dm355_io_desc[] = {
@@ -704,7 +822,6 @@ static struct davinci_soc_info davinci_soc_info_dm355 = {
.intc_irq_prios = dm355_default_priorities,
.intc_irq_num = DAVINCI_N_AINTC_IRQ,
.timer_info = &dm355_timer_info,
- .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE),
.gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
.gpio_num = 104,
.gpio_irq = IRQ_DM355_GPIOBNK0,
@@ -713,6 +830,19 @@ static struct davinci_soc_info davinci_soc_info_dm355 = {
.sram_len = SZ_32K,
};
+void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata)
+{
+ /* we don't use ASP1 IRQs, or we'd need to mux them ... */
+ if (evt_enable & ASP1_TX_EVT_EN)
+ davinci_cfg_reg(DM355_EVT8_ASP1_TX);
+
+ if (evt_enable & ASP1_RX_EVT_EN)
+ davinci_cfg_reg(DM355_EVT9_ASP1_RX);
+
+ dm355_asp1_device.dev.platform_data = pdata;
+ platform_device_register(&dm355_asp1_device);
+}
+
void __init dm355_init(void)
{
davinci_common_init(&davinci_soc_info_dm355);
@@ -725,6 +855,20 @@ static int __init dm355_init_devices(void)
davinci_cfg_reg(DM355_INT_EDMA_CC);
platform_device_register(&dm355_edma_device);
+ platform_device_register(&dm355_vpss_device);
+ /*
+ * setup Mux configuration for vpfe input and register
+ * vpfe capture platform device
+ */
+ davinci_cfg_reg(DM355_VIN_PCLK);
+ davinci_cfg_reg(DM355_VIN_CAM_WEN);
+ davinci_cfg_reg(DM355_VIN_CAM_VD);
+ davinci_cfg_reg(DM355_VIN_CAM_HD);
+ davinci_cfg_reg(DM355_VIN_YIN_EN);
+ davinci_cfg_reg(DM355_VIN_CINL_EN);
+ davinci_cfg_reg(DM355_VIN_CINH_EN);
+ platform_device_register(&vpfe_capture_dev);
+
return 0;
}
postcore_initcall(dm355_init_devices);
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
new file mode 100644
index 000000000000..f02bce8eeba4
--- /dev/null
+++ b/arch/arm/mach-davinci/dm365.c
@@ -0,0 +1,909 @@
+/*
+ * TI DaVinci DM365 chip specific setup
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#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>
+#include <mach/mux.h>
+#include <mach/irqs.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
+
+#include "clock.h"
+#include "mux.h"
+
+#define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */
+
+static struct pll_data pll1_data = {
+ .num = 1,
+ .phys_base = DAVINCI_PLL1_BASE,
+ .flags = PLL_HAS_POSTDIV | PLL_HAS_PREDIV,
+};
+
+static struct pll_data pll2_data = {
+ .num = 2,
+ .phys_base = DAVINCI_PLL2_BASE,
+ .flags = PLL_HAS_POSTDIV | PLL_HAS_PREDIV,
+};
+
+static struct clk ref_clk = {
+ .name = "ref_clk",
+ .rate = DM365_REF_FREQ,
+};
+
+static struct clk pll1_clk = {
+ .name = "pll1",
+ .parent = &ref_clk,
+ .flags = CLK_PLL,
+ .pll_data = &pll1_data,
+};
+
+static struct clk pll1_aux_clk = {
+ .name = "pll1_aux_clk",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll1_sysclkbp = {
+ .name = "pll1_sysclkbp",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL | PRE_PLL,
+ .div_reg = BPDIV
+};
+
+static struct clk clkout0_clk = {
+ .name = "clkout0",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll1_sysclk1 = {
+ .name = "pll1_sysclk1",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV1,
+};
+
+static struct clk pll1_sysclk2 = {
+ .name = "pll1_sysclk2",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+ .name = "pll1_sysclk3",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+ .name = "pll1_sysclk4",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclk5 = {
+ .name = "pll1_sysclk5",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV5,
+};
+
+static struct clk pll1_sysclk6 = {
+ .name = "pll1_sysclk6",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV6,
+};
+
+static struct clk pll1_sysclk7 = {
+ .name = "pll1_sysclk7",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV7,
+};
+
+static struct clk pll1_sysclk8 = {
+ .name = "pll1_sysclk8",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV8,
+};
+
+static struct clk pll1_sysclk9 = {
+ .name = "pll1_sysclk9",
+ .parent = &pll1_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV9,
+};
+
+static struct clk pll2_clk = {
+ .name = "pll2",
+ .parent = &ref_clk,
+ .flags = CLK_PLL,
+ .pll_data = &pll2_data,
+};
+
+static struct clk pll2_aux_clk = {
+ .name = "pll2_aux_clk",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk clkout1_clk = {
+ .name = "clkout1",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll2_sysclk1 = {
+ .name = "pll2_sysclk1",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV1,
+};
+
+static struct clk pll2_sysclk2 = {
+ .name = "pll2_sysclk2",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV2,
+};
+
+static struct clk pll2_sysclk3 = {
+ .name = "pll2_sysclk3",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV3,
+};
+
+static struct clk pll2_sysclk4 = {
+ .name = "pll2_sysclk4",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV4,
+};
+
+static struct clk pll2_sysclk5 = {
+ .name = "pll2_sysclk5",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV5,
+};
+
+static struct clk pll2_sysclk6 = {
+ .name = "pll2_sysclk6",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV6,
+};
+
+static struct clk pll2_sysclk7 = {
+ .name = "pll2_sysclk7",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV7,
+};
+
+static struct clk pll2_sysclk8 = {
+ .name = "pll2_sysclk8",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV8,
+};
+
+static struct clk pll2_sysclk9 = {
+ .name = "pll2_sysclk9",
+ .parent = &pll2_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV9,
+};
+
+static struct clk vpss_dac_clk = {
+ .name = "vpss_dac",
+ .parent = &pll1_sysclk3,
+ .lpsc = DM365_LPSC_DAC_CLK,
+};
+
+static struct clk vpss_master_clk = {
+ .name = "vpss_master",
+ .parent = &pll1_sysclk5,
+ .lpsc = DM365_LPSC_VPSSMSTR,
+ .flags = CLK_PSC,
+};
+
+static struct clk arm_clk = {
+ .name = "arm_clk",
+ .parent = &pll2_sysclk2,
+ .lpsc = DAVINCI_LPSC_ARM,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk uart0_clk = {
+ .name = "uart0",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_UART0,
+};
+
+static struct clk uart1_clk = {
+ .name = "uart1",
+ .parent = &pll1_sysclk4,
+ .lpsc = DAVINCI_LPSC_UART1,
+};
+
+static struct clk i2c_clk = {
+ .name = "i2c",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_I2C,
+};
+
+static struct clk mmcsd0_clk = {
+ .name = "mmcsd0",
+ .parent = &pll1_sysclk8,
+ .lpsc = DAVINCI_LPSC_MMC_SD,
+};
+
+static struct clk mmcsd1_clk = {
+ .name = "mmcsd1",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_MMC_SD1,
+};
+
+static struct clk spi0_clk = {
+ .name = "spi0",
+ .parent = &pll1_sysclk4,
+ .lpsc = DAVINCI_LPSC_SPI,
+};
+
+static struct clk spi1_clk = {
+ .name = "spi1",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_SPI1,
+};
+
+static struct clk spi2_clk = {
+ .name = "spi2",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_SPI2,
+};
+
+static struct clk spi3_clk = {
+ .name = "spi3",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_SPI3,
+};
+
+static struct clk spi4_clk = {
+ .name = "spi4",
+ .parent = &pll1_aux_clk,
+ .lpsc = DM365_LPSC_SPI4,
+};
+
+static struct clk gpio_clk = {
+ .name = "gpio",
+ .parent = &pll1_sysclk4,
+ .lpsc = DAVINCI_LPSC_GPIO,
+};
+
+static struct clk aemif_clk = {
+ .name = "aemif",
+ .parent = &pll1_sysclk4,
+ .lpsc = DAVINCI_LPSC_AEMIF,
+};
+
+static struct clk pwm0_clk = {
+ .name = "pwm0",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_PWM0,
+};
+
+static struct clk pwm1_clk = {
+ .name = "pwm1",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_PWM1,
+};
+
+static struct clk pwm2_clk = {
+ .name = "pwm2",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_PWM2,
+};
+
+static struct clk pwm3_clk = {
+ .name = "pwm3",
+ .parent = &ref_clk,
+ .lpsc = DM365_LPSC_PWM3,
+};
+
+static struct clk timer0_clk = {
+ .name = "timer0",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_TIMER0,
+};
+
+static struct clk timer1_clk = {
+ .name = "timer1",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_TIMER1,
+};
+
+static struct clk timer2_clk = {
+ .name = "timer2",
+ .parent = &pll1_aux_clk,
+ .lpsc = DAVINCI_LPSC_TIMER2,
+ .usecount = 1,
+};
+
+static struct clk timer3_clk = {
+ .name = "timer3",
+ .parent = &pll1_aux_clk,
+ .lpsc = DM365_LPSC_TIMER3,
+};
+
+static struct clk usb_clk = {
+ .name = "usb",
+ .parent = &pll2_sysclk1,
+ .lpsc = DAVINCI_LPSC_USB,
+};
+
+static struct clk emac_clk = {
+ .name = "emac",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_EMAC,
+};
+
+static struct clk voicecodec_clk = {
+ .name = "voice_codec",
+ .parent = &pll2_sysclk4,
+ .lpsc = DM365_LPSC_VOICE_CODEC,
+};
+
+static struct clk asp0_clk = {
+ .name = "asp0",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_McBSP1,
+};
+
+static struct clk rto_clk = {
+ .name = "rto",
+ .parent = &pll1_sysclk4,
+ .lpsc = DM365_LPSC_RTO,
+};
+
+static struct clk mjcp_clk = {
+ .name = "mjcp",
+ .parent = &pll1_sysclk3,
+ .lpsc = DM365_LPSC_MJCP,
+};
+
+static struct davinci_clk dm365_clks[] = {
+ CLK(NULL, "ref", &ref_clk),
+ CLK(NULL, "pll1", &pll1_clk),
+ CLK(NULL, "pll1_aux", &pll1_aux_clk),
+ CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp),
+ CLK(NULL, "clkout0", &clkout0_clk),
+ CLK(NULL, "pll1_sysclk1", &pll1_sysclk1),
+ CLK(NULL, "pll1_sysclk2", &pll1_sysclk2),
+ CLK(NULL, "pll1_sysclk3", &pll1_sysclk3),
+ CLK(NULL, "pll1_sysclk4", &pll1_sysclk4),
+ CLK(NULL, "pll1_sysclk5", &pll1_sysclk5),
+ CLK(NULL, "pll1_sysclk6", &pll1_sysclk6),
+ CLK(NULL, "pll1_sysclk7", &pll1_sysclk7),
+ CLK(NULL, "pll1_sysclk8", &pll1_sysclk8),
+ CLK(NULL, "pll1_sysclk9", &pll1_sysclk9),
+ CLK(NULL, "pll2", &pll2_clk),
+ CLK(NULL, "pll2_aux", &pll2_aux_clk),
+ CLK(NULL, "clkout1", &clkout1_clk),
+ CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
+ CLK(NULL, "pll2_sysclk2", &pll2_sysclk2),
+ CLK(NULL, "pll2_sysclk3", &pll2_sysclk3),
+ CLK(NULL, "pll2_sysclk4", &pll2_sysclk4),
+ CLK(NULL, "pll2_sysclk5", &pll2_sysclk5),
+ CLK(NULL, "pll2_sysclk6", &pll2_sysclk6),
+ CLK(NULL, "pll2_sysclk7", &pll2_sysclk7),
+ CLK(NULL, "pll2_sysclk8", &pll2_sysclk8),
+ CLK(NULL, "pll2_sysclk9", &pll2_sysclk9),
+ CLK(NULL, "vpss_dac", &vpss_dac_clk),
+ CLK(NULL, "vpss_master", &vpss_master_clk),
+ CLK(NULL, "arm", &arm_clk),
+ CLK(NULL, "uart0", &uart0_clk),
+ CLK(NULL, "uart1", &uart1_clk),
+ CLK("i2c_davinci.1", NULL, &i2c_clk),
+ CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
+ CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
+ CLK("spi_davinci.0", NULL, &spi0_clk),
+ CLK("spi_davinci.1", NULL, &spi1_clk),
+ CLK("spi_davinci.2", NULL, &spi2_clk),
+ CLK("spi_davinci.3", NULL, &spi3_clk),
+ CLK("spi_davinci.4", NULL, &spi4_clk),
+ CLK(NULL, "gpio", &gpio_clk),
+ CLK(NULL, "aemif", &aemif_clk),
+ CLK(NULL, "pwm0", &pwm0_clk),
+ CLK(NULL, "pwm1", &pwm1_clk),
+ CLK(NULL, "pwm2", &pwm2_clk),
+ CLK(NULL, "pwm3", &pwm3_clk),
+ CLK(NULL, "timer0", &timer0_clk),
+ CLK(NULL, "timer1", &timer1_clk),
+ CLK("watchdog", NULL, &timer2_clk),
+ CLK(NULL, "timer3", &timer3_clk),
+ 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(NULL, "rto", &rto_clk),
+ CLK(NULL, "mjcp", &mjcp_clk),
+ CLK(NULL, NULL, NULL),
+};
+
+/*----------------------------------------------------------------------*/
+
+#define PINMUX0 0x00
+#define PINMUX1 0x04
+#define PINMUX2 0x08
+#define PINMUX3 0x0c
+#define PINMUX4 0x10
+#define INTMUX 0x18
+#define EVTMUX 0x1c
+
+
+static const struct mux_config dm365_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+MUX_CFG(DM365, MMCSD0, 0, 24, 1, 0, false)
+
+MUX_CFG(DM365, SD1_CLK, 0, 16, 3, 1, false)
+MUX_CFG(DM365, SD1_CMD, 4, 30, 3, 1, false)
+MUX_CFG(DM365, SD1_DATA3, 4, 28, 3, 1, false)
+MUX_CFG(DM365, SD1_DATA2, 4, 26, 3, 1, false)
+MUX_CFG(DM365, SD1_DATA1, 4, 24, 3, 1, false)
+MUX_CFG(DM365, SD1_DATA0, 4, 22, 3, 1, false)
+
+MUX_CFG(DM365, I2C_SDA, 3, 23, 3, 2, false)
+MUX_CFG(DM365, I2C_SCL, 3, 21, 3, 2, false)
+
+MUX_CFG(DM365, AEMIF_AR, 2, 0, 3, 1, false)
+MUX_CFG(DM365, AEMIF_A3, 2, 2, 3, 1, false)
+MUX_CFG(DM365, AEMIF_A7, 2, 4, 3, 1, false)
+MUX_CFG(DM365, AEMIF_D15_8, 2, 6, 1, 1, false)
+MUX_CFG(DM365, AEMIF_CE0, 2, 7, 1, 0, false)
+
+MUX_CFG(DM365, MCBSP0_BDX, 0, 23, 1, 1, false)
+MUX_CFG(DM365, MCBSP0_X, 0, 22, 1, 1, false)
+MUX_CFG(DM365, MCBSP0_BFSX, 0, 21, 1, 1, false)
+MUX_CFG(DM365, MCBSP0_BDR, 0, 20, 1, 1, false)
+MUX_CFG(DM365, MCBSP0_R, 0, 19, 1, 1, false)
+MUX_CFG(DM365, MCBSP0_BFSR, 0, 18, 1, 1, false)
+
+MUX_CFG(DM365, SPI0_SCLK, 3, 28, 1, 1, false)
+MUX_CFG(DM365, SPI0_SDI, 3, 26, 3, 1, false)
+MUX_CFG(DM365, SPI0_SDO, 3, 25, 1, 1, false)
+MUX_CFG(DM365, SPI0_SDENA0, 3, 29, 3, 1, false)
+MUX_CFG(DM365, SPI0_SDENA1, 3, 26, 3, 2, false)
+
+MUX_CFG(DM365, UART0_RXD, 3, 20, 1, 1, false)
+MUX_CFG(DM365, UART0_TXD, 3, 19, 1, 1, false)
+MUX_CFG(DM365, UART1_RXD, 3, 17, 3, 2, false)
+MUX_CFG(DM365, UART1_TXD, 3, 15, 3, 2, false)
+MUX_CFG(DM365, UART1_RTS, 3, 23, 3, 1, false)
+MUX_CFG(DM365, UART1_CTS, 3, 21, 3, 1, false)
+
+MUX_CFG(DM365, EMAC_TX_EN, 3, 17, 3, 1, false)
+MUX_CFG(DM365, EMAC_TX_CLK, 3, 15, 3, 1, false)
+MUX_CFG(DM365, EMAC_COL, 3, 14, 1, 1, false)
+MUX_CFG(DM365, EMAC_TXD3, 3, 13, 1, 1, false)
+MUX_CFG(DM365, EMAC_TXD2, 3, 12, 1, 1, false)
+MUX_CFG(DM365, EMAC_TXD1, 3, 11, 1, 1, false)
+MUX_CFG(DM365, EMAC_TXD0, 3, 10, 1, 1, false)
+MUX_CFG(DM365, EMAC_RXD3, 3, 9, 1, 1, false)
+MUX_CFG(DM365, EMAC_RXD2, 3, 8, 1, 1, false)
+MUX_CFG(DM365, EMAC_RXD1, 3, 7, 1, 1, false)
+MUX_CFG(DM365, EMAC_RXD0, 3, 6, 1, 1, false)
+MUX_CFG(DM365, EMAC_RX_CLK, 3, 5, 1, 1, false)
+MUX_CFG(DM365, EMAC_RX_DV, 3, 4, 1, 1, false)
+MUX_CFG(DM365, EMAC_RX_ER, 3, 3, 1, 1, false)
+MUX_CFG(DM365, EMAC_CRS, 3, 2, 1, 1, false)
+MUX_CFG(DM365, EMAC_MDIO, 3, 1, 1, 1, false)
+MUX_CFG(DM365, EMAC_MDCLK, 3, 0, 1, 1, false)
+
+MUX_CFG(DM365, KEYPAD, 2, 0, 0x3f, 0x3f, false)
+
+MUX_CFG(DM365, PWM0, 1, 0, 3, 2, false)
+MUX_CFG(DM365, PWM0_G23, 3, 26, 3, 3, false)
+MUX_CFG(DM365, PWM1, 1, 2, 3, 2, false)
+MUX_CFG(DM365, PWM1_G25, 3, 29, 3, 2, false)
+MUX_CFG(DM365, PWM2_G87, 1, 10, 3, 2, false)
+MUX_CFG(DM365, PWM2_G88, 1, 8, 3, 2, false)
+MUX_CFG(DM365, PWM2_G89, 1, 6, 3, 2, false)
+MUX_CFG(DM365, PWM2_G90, 1, 4, 3, 2, false)
+MUX_CFG(DM365, PWM3_G80, 1, 20, 3, 3, false)
+MUX_CFG(DM365, PWM3_G81, 1, 18, 3, 3, false)
+MUX_CFG(DM365, PWM3_G85, 1, 14, 3, 2, false)
+MUX_CFG(DM365, PWM3_G86, 1, 12, 3, 2, false)
+
+MUX_CFG(DM365, SPI1_SCLK, 4, 2, 3, 1, false)
+MUX_CFG(DM365, SPI1_SDI, 3, 31, 1, 1, false)
+MUX_CFG(DM365, SPI1_SDO, 4, 0, 3, 1, false)
+MUX_CFG(DM365, SPI1_SDENA0, 4, 4, 3, 1, false)
+MUX_CFG(DM365, SPI1_SDENA1, 4, 0, 3, 2, false)
+
+MUX_CFG(DM365, SPI2_SCLK, 4, 10, 3, 1, false)
+MUX_CFG(DM365, SPI2_SDI, 4, 6, 3, 1, false)
+MUX_CFG(DM365, SPI2_SDO, 4, 8, 3, 1, false)
+MUX_CFG(DM365, SPI2_SDENA0, 4, 12, 3, 1, false)
+MUX_CFG(DM365, SPI2_SDENA1, 4, 8, 3, 2, false)
+
+MUX_CFG(DM365, SPI3_SCLK, 0, 0, 3, 2, false)
+MUX_CFG(DM365, SPI3_SDI, 0, 2, 3, 2, false)
+MUX_CFG(DM365, SPI3_SDO, 0, 6, 3, 2, false)
+MUX_CFG(DM365, SPI3_SDENA0, 0, 4, 3, 2, false)
+MUX_CFG(DM365, SPI3_SDENA1, 0, 6, 3, 3, false)
+
+MUX_CFG(DM365, SPI4_SCLK, 4, 18, 3, 1, false)
+MUX_CFG(DM365, SPI4_SDI, 4, 14, 3, 1, false)
+MUX_CFG(DM365, SPI4_SDO, 4, 16, 3, 1, false)
+MUX_CFG(DM365, SPI4_SDENA0, 4, 20, 3, 1, false)
+MUX_CFG(DM365, SPI4_SDENA1, 4, 16, 3, 2, false)
+
+MUX_CFG(DM365, GPIO20, 3, 21, 3, 0, false)
+MUX_CFG(DM365, GPIO33, 4, 12, 3, 0, false)
+MUX_CFG(DM365, GPIO40, 4, 26, 3, 0, false)
+
+MUX_CFG(DM365, VOUT_FIELD, 1, 18, 3, 1, false)
+MUX_CFG(DM365, VOUT_FIELD_G81, 1, 18, 3, 0, false)
+MUX_CFG(DM365, VOUT_HVSYNC, 1, 16, 1, 0, false)
+MUX_CFG(DM365, VOUT_COUTL_EN, 1, 0, 0xff, 0x55, false)
+MUX_CFG(DM365, VOUT_COUTH_EN, 1, 8, 0xff, 0x55, false)
+MUX_CFG(DM365, VIN_CAM_WEN, 0, 14, 3, 0, false)
+MUX_CFG(DM365, VIN_CAM_VD, 0, 13, 1, 0, false)
+MUX_CFG(DM365, VIN_CAM_HD, 0, 12, 1, 0, false)
+MUX_CFG(DM365, VIN_YIN_EN, 0, 0, 0xfff, 0, false)
+
+INT_CFG(DM365, INT_EDMA_CC, 2, 1, 1, false)
+INT_CFG(DM365, INT_EDMA_TC0_ERR, 3, 1, 1, false)
+INT_CFG(DM365, INT_EDMA_TC1_ERR, 4, 1, 1, false)
+INT_CFG(DM365, INT_EDMA_TC2_ERR, 22, 1, 1, false)
+INT_CFG(DM365, INT_EDMA_TC3_ERR, 23, 1, 1, false)
+INT_CFG(DM365, INT_PRTCSS, 10, 1, 1, false)
+INT_CFG(DM365, INT_EMAC_RXTHRESH, 14, 1, 1, false)
+INT_CFG(DM365, INT_EMAC_RXPULSE, 15, 1, 1, false)
+INT_CFG(DM365, INT_EMAC_TXPULSE, 16, 1, 1, false)
+INT_CFG(DM365, INT_EMAC_MISCPULSE, 17, 1, 1, false)
+#endif
+};
+
+static struct emac_platform_data dm365_emac_pdata = {
+ .ctrl_reg_offset = DM365_EMAC_CNTRL_OFFSET,
+ .ctrl_mod_reg_offset = DM365_EMAC_CNTRL_MOD_OFFSET,
+ .ctrl_ram_offset = DM365_EMAC_CNTRL_RAM_OFFSET,
+ .mdio_reg_offset = DM365_EMAC_MDIO_OFFSET,
+ .ctrl_ram_size = DM365_EMAC_CNTRL_RAM_SIZE,
+ .version = EMAC_VERSION_2,
+};
+
+static struct resource dm365_emac_resources[] = {
+ {
+ .start = DM365_EMAC_BASE,
+ .end = DM365_EMAC_BASE + 0x47ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DM365_EMAC_RXTHRESH,
+ .end = IRQ_DM365_EMAC_RXTHRESH,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DM365_EMAC_RXPULSE,
+ .end = IRQ_DM365_EMAC_RXPULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DM365_EMAC_TXPULSE,
+ .end = IRQ_DM365_EMAC_TXPULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DM365_EMAC_MISCPULSE,
+ .end = IRQ_DM365_EMAC_MISCPULSE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dm365_emac_device = {
+ .name = "davinci_emac",
+ .id = 1,
+ .dev = {
+ .platform_data = &dm365_emac_pdata,
+ },
+ .num_resources = ARRAY_SIZE(dm365_emac_resources),
+ .resource = dm365_emac_resources,
+};
+
+static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+ [IRQ_VDINT0] = 2,
+ [IRQ_VDINT1] = 6,
+ [IRQ_VDINT2] = 6,
+ [IRQ_HISTINT] = 6,
+ [IRQ_H3AINT] = 6,
+ [IRQ_PRVUINT] = 6,
+ [IRQ_RSZINT] = 6,
+ [IRQ_DM365_INSFINT] = 7,
+ [IRQ_VENCINT] = 6,
+ [IRQ_ASQINT] = 6,
+ [IRQ_IMXINT] = 6,
+ [IRQ_DM365_IMCOPINT] = 4,
+ [IRQ_USBINT] = 4,
+ [IRQ_DM365_RTOINT] = 7,
+ [IRQ_DM365_TINT5] = 7,
+ [IRQ_DM365_TINT6] = 5,
+ [IRQ_CCINT0] = 5,
+ [IRQ_CCERRINT] = 5,
+ [IRQ_TCERRINT0] = 5,
+ [IRQ_TCERRINT] = 7,
+ [IRQ_PSCIN] = 4,
+ [IRQ_DM365_SPINT2_1] = 7,
+ [IRQ_DM365_TINT7] = 7,
+ [IRQ_DM365_SDIOINT0] = 7,
+ [IRQ_MBXINT] = 7,
+ [IRQ_MBRINT] = 7,
+ [IRQ_MMCINT] = 7,
+ [IRQ_DM365_MMCINT1] = 7,
+ [IRQ_DM365_PWMINT3] = 7,
+ [IRQ_DDRINT] = 4,
+ [IRQ_AEMIFINT] = 2,
+ [IRQ_DM365_SDIOINT1] = 2,
+ [IRQ_TINT0_TINT12] = 7,
+ [IRQ_TINT0_TINT34] = 7,
+ [IRQ_TINT1_TINT12] = 7,
+ [IRQ_TINT1_TINT34] = 7,
+ [IRQ_PWMINT0] = 7,
+ [IRQ_PWMINT1] = 3,
+ [IRQ_PWMINT2] = 3,
+ [IRQ_I2C] = 3,
+ [IRQ_UARTINT0] = 3,
+ [IRQ_UARTINT1] = 3,
+ [IRQ_DM365_SPIINT0_0] = 3,
+ [IRQ_DM365_SPIINT3_0] = 3,
+ [IRQ_DM365_GPIO0] = 3,
+ [IRQ_DM365_GPIO1] = 7,
+ [IRQ_DM365_GPIO2] = 4,
+ [IRQ_DM365_GPIO3] = 4,
+ [IRQ_DM365_GPIO4] = 7,
+ [IRQ_DM365_GPIO5] = 7,
+ [IRQ_DM365_GPIO6] = 7,
+ [IRQ_DM365_GPIO7] = 7,
+ [IRQ_DM365_EMAC_RXTHRESH] = 7,
+ [IRQ_DM365_EMAC_RXPULSE] = 7,
+ [IRQ_DM365_EMAC_TXPULSE] = 7,
+ [IRQ_DM365_EMAC_MISCPULSE] = 7,
+ [IRQ_DM365_GPIO12] = 7,
+ [IRQ_DM365_GPIO13] = 7,
+ [IRQ_DM365_GPIO14] = 7,
+ [IRQ_DM365_GPIO15] = 7,
+ [IRQ_DM365_KEYINT] = 7,
+ [IRQ_DM365_TCERRINT2] = 7,
+ [IRQ_DM365_TCERRINT3] = 7,
+ [IRQ_DM365_EMUINT] = 7,
+};
+
+/* Four Transfer Controllers on DM365 */
+static const s8
+dm365_queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {-1, -1},
+};
+
+static const s8
+dm365_queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 7},
+ {1, 7},
+ {2, 7},
+ {3, 0},
+ {-1, -1},
+};
+
+static struct edma_soc_info dm365_edma_info[] = {
+ {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 256,
+ .n_tc = 4,
+ .n_cc = 1,
+ .queue_tc_mapping = dm365_queue_tc_mapping,
+ .queue_priority_mapping = dm365_queue_priority_mapping,
+ },
+};
+
+static struct resource edma_resources[] = {
+ {
+ .name = "edma_cc0",
+ .start = 0x01c00000,
+ .end = 0x01c00000 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc0",
+ .start = 0x01c10000,
+ .end = 0x01c10000 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc1",
+ .start = 0x01c10400,
+ .end = 0x01c10400 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc2",
+ .start = 0x01c10800,
+ .end = 0x01c10800 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc3",
+ .start = 0x01c10c00,
+ .end = 0x01c10c00 + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma0",
+ .start = IRQ_CCINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma0_err",
+ .start = IRQ_CCERRINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* not using TC*_ERR */
+};
+
+static struct platform_device dm365_edma_device = {
+ .name = "edma",
+ .id = 0,
+ .dev.platform_data = dm365_edma_info,
+ .num_resources = ARRAY_SIZE(edma_resources),
+ .resource = edma_resources,
+};
+
+static struct map_desc dm365_io_desc[] = {
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = SRAM_VIRT,
+ .pfn = __phys_to_pfn(0x00010000),
+ .length = SZ_32K,
+ /* MT_MEMORY_NONCACHED requires supersection alignment */
+ .type = MT_DEVICE,
+ },
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm365_ids[] = {
+ {
+ .variant = 0x0,
+ .part_no = 0xb83e,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DM365,
+ .name = "dm365",
+ },
+};
+
+static void __iomem *dm365_psc_bases[] = {
+ IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+struct davinci_timer_info dm365_timer_info = {
+ .timers = davinci_timer_instance,
+ .clockevent_id = T0_BOT,
+ .clocksource_id = T0_TOP,
+};
+
+static struct plat_serial8250_port dm365_serial_platform_data[] = {
+ {
+ .mapbase = DAVINCI_UART0_BASE,
+ .irq = IRQ_UARTINT0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_IOREMAP,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ },
+ {
+ .mapbase = DAVINCI_UART1_BASE,
+ .irq = IRQ_UARTINT1,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_IOREMAP,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ },
+ {
+ .flags = 0
+ },
+};
+
+static struct platform_device dm365_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = dm365_serial_platform_data,
+ },
+};
+
+static struct davinci_soc_info davinci_soc_info_dm365 = {
+ .io_desc = dm365_io_desc,
+ .io_desc_num = ARRAY_SIZE(dm365_io_desc),
+ .jtag_id_base = IO_ADDRESS(0x01c40028),
+ .ids = dm365_ids,
+ .ids_num = ARRAY_SIZE(dm365_ids),
+ .cpu_clks = dm365_clks,
+ .psc_bases = dm365_psc_bases,
+ .psc_bases_num = ARRAY_SIZE(dm365_psc_bases),
+ .pinmux_base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+ .pinmux_pins = dm365_pins,
+ .pinmux_pins_num = ARRAY_SIZE(dm365_pins),
+ .intc_base = IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+ .intc_type = DAVINCI_INTC_TYPE_AINTC,
+ .intc_irq_prios = dm365_default_priorities,
+ .intc_irq_num = DAVINCI_N_AINTC_IRQ,
+ .timer_info = &dm365_timer_info,
+ .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
+ .gpio_num = 104,
+ .gpio_irq = IRQ_DM365_GPIO0,
+ .gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */
+ .serial_dev = &dm365_serial_device,
+ .emac_pdata = &dm365_emac_pdata,
+ .sram_dma = 0x00010000,
+ .sram_len = SZ_32K,
+};
+
+void __init dm365_init(void)
+{
+ davinci_common_init(&davinci_soc_info_dm365);
+}
+
+static int __init dm365_init_devices(void)
+{
+ if (!cpu_is_davinci_dm365())
+ return 0;
+
+ davinci_cfg_reg(DM365_INT_EDMA_CC);
+ platform_device_register(&dm365_edma_device);
+ platform_device_register(&dm365_emac_device);
+
+ return 0;
+}
+postcore_initcall(dm365_init_devices);
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index fb5449b3c97b..d6e0fa5a8d8a 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -27,6 +27,7 @@
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
+#include <mach/asp.h>
#include "clock.h"
#include "mux.h"
@@ -303,7 +304,7 @@ struct davinci_clk dm644x_clks[] = {
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("palm_bk3710", NULL, &ide_clk),
- CLK("soc-audio.0", NULL, &asp_clk),
+ CLK("davinci-asp", NULL, &asp_clk),
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
CLK(NULL, "spi", &spi_clk),
CLK(NULL, "gpio", &gpio_clk),
@@ -484,17 +485,38 @@ static const s8 dma_chan_dm644x_no_event[] = {
-1
};
-static struct edma_soc_info dm644x_edma_info = {
- .n_channel = 64,
- .n_region = 4,
- .n_slot = 128,
- .n_tc = 2,
- .noevent = dma_chan_dm644x_no_event,
+static const s8
+queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {-1, -1},
+};
+
+static const s8
+queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 3},
+ {1, 7},
+ {-1, -1},
+};
+
+static struct edma_soc_info dm644x_edma_info[] = {
+ {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .noevent = dma_chan_dm644x_no_event,
+ .queue_tc_mapping = queue_tc_mapping,
+ .queue_priority_mapping = queue_priority_mapping,
+ },
};
static struct resource edma_resources[] = {
{
- .name = "edma_cc",
+ .name = "edma_cc0",
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
@@ -512,10 +534,12 @@ static struct resource edma_resources[] = {
.flags = IORESOURCE_MEM,
},
{
+ .name = "edma0",
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
+ .name = "edma0_err",
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
@@ -524,12 +548,91 @@ static struct resource edma_resources[] = {
static struct platform_device dm644x_edma_device = {
.name = "edma",
- .id = -1,
- .dev.platform_data = &dm644x_edma_info,
+ .id = 0,
+ .dev.platform_data = dm644x_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
+/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */
+static struct resource dm644x_asp_resources[] = {
+ {
+ .start = DAVINCI_ASP0_BASE,
+ .end = DAVINCI_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 dm644x_asp_device = {
+ .name = "davinci-asp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm644x_asp_resources),
+ .resource = dm644x_asp_resources,
+};
+
+static struct resource dm644x_vpss_resources[] = {
+ {
+ /* VPSS Base address */
+ .name = "vpss",
+ .start = 0x01c73400,
+ .end = 0x01c73400 + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm644x_vpss_device = {
+ .name = "vpss",
+ .id = -1,
+ .dev.platform_data = "dm644x_vpss",
+ .num_resources = ARRAY_SIZE(dm644x_vpss_resources),
+ .resource = dm644x_vpss_resources,
+};
+
+static struct resource vpfe_resources[] = {
+ {
+ .start = IRQ_VDINT0,
+ .end = IRQ_VDINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_VDINT1,
+ .end = IRQ_VDINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = 0x01c70400,
+ .end = 0x01c70400 + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device vpfe_capture_dev = {
+ .name = CAPTURE_DRV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(vpfe_resources),
+ .resource = vpfe_resources,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void dm644x_set_vpfe_config(struct vpfe_config *cfg)
+{
+ vpfe_capture_dev.dev.platform_data = cfg;
+}
+
/*----------------------------------------------------------------------*/
static struct map_desc dm644x_io_desc[] = {
@@ -557,6 +660,13 @@ static struct davinci_id dm644x_ids[] = {
.cpu_id = DAVINCI_CPU_ID_DM6446,
.name = "dm6446",
},
+ {
+ .variant = 0x1,
+ .part_no = 0xb700,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DM6446,
+ .name = "dm6446a",
+ },
};
static void __iomem *dm644x_psc_bases[] = {
@@ -630,7 +740,6 @@ static struct davinci_soc_info davinci_soc_info_dm644x = {
.intc_irq_prios = dm644x_default_priorities,
.intc_irq_num = DAVINCI_N_AINTC_IRQ,
.timer_info = &dm644x_timer_info,
- .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE),
.gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
.gpio_num = 71,
.gpio_irq = IRQ_GPIOBNK0,
@@ -640,6 +749,13 @@ static struct davinci_soc_info davinci_soc_info_dm644x = {
.sram_len = SZ_16K,
};
+void __init dm644x_init_asp(struct snd_platform_data *pdata)
+{
+ davinci_cfg_reg(DM644X_MCBSP);
+ dm644x_asp_device.dev.platform_data = pdata;
+ platform_device_register(&dm644x_asp_device);
+}
+
void __init dm644x_init(void)
{
davinci_common_init(&davinci_soc_info_dm644x);
@@ -652,6 +768,9 @@ static int __init dm644x_init_devices(void)
platform_device_register(&dm644x_edma_device);
platform_device_register(&dm644x_emac_device);
+ platform_device_register(&dm644x_vpss_device);
+ platform_device_register(&vpfe_capture_dev);
+
return 0;
}
postcore_initcall(dm644x_init_devices);
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 334f0711e0f5..73a7e8b856b5 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -27,10 +27,20 @@
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
+#include <mach/asp.h>
#include "clock.h"
#include "mux.h"
+#define DAVINCI_VPIF_BASE (0x01C12000)
+#define VDD3P3V_PWDN_OFFSET (0x48)
+#define VSCLKDIS_OFFSET (0x6C)
+
+#define VDD3P3V_VID_MASK (BIT_MASK(7) | BIT_MASK(6) | BIT_MASK(5) |\
+ BIT_MASK(4))
+#define VSCLKDIS_MASK (BIT_MASK(11) | BIT_MASK(10) | BIT_MASK(9) |\
+ BIT_MASK(8))
+
/*
* Device specific clocks
*/
@@ -162,6 +172,41 @@ static struct clk arm_clk = {
.flags = ALWAYS_ENABLED,
};
+static struct clk edma_cc_clk = {
+ .name = "edma_cc",
+ .parent = &pll1_sysclk2,
+ .lpsc = DM646X_LPSC_TPCC,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk edma_tc0_clk = {
+ .name = "edma_tc0",
+ .parent = &pll1_sysclk2,
+ .lpsc = DM646X_LPSC_TPTC0,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk edma_tc1_clk = {
+ .name = "edma_tc1",
+ .parent = &pll1_sysclk2,
+ .lpsc = DM646X_LPSC_TPTC1,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk edma_tc2_clk = {
+ .name = "edma_tc2",
+ .parent = &pll1_sysclk2,
+ .lpsc = DM646X_LPSC_TPTC2,
+ .flags = ALWAYS_ENABLED,
+};
+
+static struct clk edma_tc3_clk = {
+ .name = "edma_tc3",
+ .parent = &pll1_sysclk2,
+ .lpsc = DM646X_LPSC_TPTC3,
+ .flags = ALWAYS_ENABLED,
+};
+
static struct clk uart0_clk = {
.name = "uart0",
.parent = &aux_clkin,
@@ -192,6 +237,18 @@ static struct clk gpio_clk = {
.lpsc = DM646X_LPSC_GPIO,
};
+static struct clk mcasp0_clk = {
+ .name = "mcasp0",
+ .parent = &pll1_sysclk3,
+ .lpsc = DM646X_LPSC_McASP0,
+};
+
+static struct clk mcasp1_clk = {
+ .name = "mcasp1",
+ .parent = &pll1_sysclk3,
+ .lpsc = DM646X_LPSC_McASP1,
+};
+
static struct clk aemif_clk = {
.name = "aemif",
.parent = &pll1_sysclk3,
@@ -237,6 +294,13 @@ static struct clk timer2_clk = {
.flags = ALWAYS_ENABLED, /* no LPSC, always enabled; c.f. spruep9a */
};
+
+static struct clk ide_clk = {
+ .name = "ide",
+ .parent = &pll1_sysclk4,
+ .lpsc = DAVINCI_LPSC_ATA,
+};
+
static struct clk vpif0_clk = {
.name = "vpif0",
.parent = &ref_clk,
@@ -269,11 +333,18 @@ struct davinci_clk dm646x_clks[] = {
CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
CLK(NULL, "dsp", &dsp_clk),
CLK(NULL, "arm", &arm_clk),
+ CLK(NULL, "edma_cc", &edma_cc_clk),
+ CLK(NULL, "edma_tc0", &edma_tc0_clk),
+ CLK(NULL, "edma_tc1", &edma_tc1_clk),
+ CLK(NULL, "edma_tc2", &edma_tc2_clk),
+ CLK(NULL, "edma_tc3", &edma_tc3_clk),
CLK(NULL, "uart0", &uart0_clk),
CLK(NULL, "uart1", &uart1_clk),
CLK(NULL, "uart2", &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK(NULL, "gpio", &gpio_clk),
+ CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
+ CLK("davinci-mcasp.1", NULL, &mcasp1_clk),
CLK(NULL, "aemif", &aemif_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK(NULL, "pwm0", &pwm0_clk),
@@ -281,6 +352,7 @@ struct davinci_clk dm646x_clks[] = {
CLK(NULL, "timer0", &timer0_clk),
CLK(NULL, "timer1", &timer1_clk),
CLK("watchdog", NULL, &timer2_clk),
+ CLK("palm_bk3710", NULL, &ide_clk),
CLK(NULL, "vpif0", &vpif0_clk),
CLK(NULL, "vpif1", &vpif1_clk),
CLK(NULL, NULL, NULL),
@@ -344,7 +416,7 @@ static struct platform_device dm646x_emac_device = {
*/
static const struct mux_config dm646x_pins[] = {
#ifdef CONFIG_DAVINCI_MUX
-MUX_CFG(DM646X, ATAEN, 0, 0, 1, 1, true)
+MUX_CFG(DM646X, ATAEN, 0, 0, 5, 1, true)
MUX_CFG(DM646X, AUDCK1, 0, 29, 1, 0, false)
@@ -451,17 +523,43 @@ static const s8 dma_chan_dm646x_no_event[] = {
-1
};
-static struct edma_soc_info dm646x_edma_info = {
- .n_channel = 64,
- .n_region = 6, /* 0-1, 4-7 */
- .n_slot = 512,
- .n_tc = 4,
- .noevent = dma_chan_dm646x_no_event,
+/* Four Transfer Controllers on DM646x */
+static const s8
+dm646x_queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {-1, -1},
+};
+
+static const s8
+dm646x_queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 4},
+ {1, 0},
+ {2, 5},
+ {3, 1},
+ {-1, -1},
+};
+
+static struct edma_soc_info dm646x_edma_info[] = {
+ {
+ .n_channel = 64,
+ .n_region = 6, /* 0-1, 4-7 */
+ .n_slot = 512,
+ .n_tc = 4,
+ .n_cc = 1,
+ .noevent = dma_chan_dm646x_no_event,
+ .queue_tc_mapping = dm646x_queue_tc_mapping,
+ .queue_priority_mapping = dm646x_queue_priority_mapping,
+ },
};
static struct resource edma_resources[] = {
{
- .name = "edma_cc",
+ .name = "edma_cc0",
.start = 0x01c00000,
.end = 0x01c00000 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
@@ -491,10 +589,12 @@ static struct resource edma_resources[] = {
.flags = IORESOURCE_MEM,
},
{
+ .name = "edma0",
.start = IRQ_CCINT0,
.flags = IORESOURCE_IRQ,
},
{
+ .name = "edma0_err",
.start = IRQ_CCERRINT,
.flags = IORESOURCE_IRQ,
},
@@ -503,12 +603,129 @@ static struct resource edma_resources[] = {
static struct platform_device dm646x_edma_device = {
.name = "edma",
- .id = -1,
- .dev.platform_data = &dm646x_edma_info,
+ .id = 0,
+ .dev.platform_data = dm646x_edma_info,
.num_resources = ARRAY_SIZE(edma_resources),
.resource = edma_resources,
};
+static struct resource ide_resources[] = {
+ {
+ .start = DM646X_ATA_REG_BASE,
+ .end = DM646X_ATA_REG_BASE + 0x7ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DM646X_IDE,
+ .end = IRQ_DM646X_IDE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ide_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device ide_dev = {
+ .name = "palm_bk3710",
+ .id = -1,
+ .resource = ide_resources,
+ .num_resources = ARRAY_SIZE(ide_resources),
+ .dev = {
+ .dma_mask = &ide_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource dm646x_mcasp0_resources[] = {
+ {
+ .name = "mcasp0",
+ .start = DAVINCI_DM646X_MCASP0_REG_BASE,
+ .end = DAVINCI_DM646X_MCASP0_REG_BASE + (SZ_1K << 1) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /* first TX, then RX */
+ {
+ .start = DAVINCI_DM646X_DMA_MCASP0_AXEVT0,
+ .end = DAVINCI_DM646X_DMA_MCASP0_AXEVT0,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DAVINCI_DM646X_DMA_MCASP0_AREVT0,
+ .end = DAVINCI_DM646X_DMA_MCASP0_AREVT0,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource dm646x_mcasp1_resources[] = {
+ {
+ .name = "mcasp1",
+ .start = DAVINCI_DM646X_MCASP1_REG_BASE,
+ .end = DAVINCI_DM646X_MCASP1_REG_BASE + (SZ_1K << 1) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /* DIT mode, only TX event */
+ {
+ .start = DAVINCI_DM646X_DMA_MCASP1_AXEVT1,
+ .end = DAVINCI_DM646X_DMA_MCASP1_AXEVT1,
+ .flags = IORESOURCE_DMA,
+ },
+ /* DIT mode, dummy entry */
+ {
+ .start = -1,
+ .end = -1,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device dm646x_mcasp0_device = {
+ .name = "davinci-mcasp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm646x_mcasp0_resources),
+ .resource = dm646x_mcasp0_resources,
+};
+
+static struct platform_device dm646x_mcasp1_device = {
+ .name = "davinci-mcasp",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(dm646x_mcasp1_resources),
+ .resource = dm646x_mcasp1_resources,
+};
+
+static struct platform_device dm646x_dit_device = {
+ .name = "spdif-dit",
+ .id = -1,
+};
+
+static u64 vpif_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource vpif_resource[] = {
+ {
+ .start = DAVINCI_VPIF_BASE,
+ .end = DAVINCI_VPIF_BASE + 0x03fff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DM646X_VP_VERTINT2,
+ .end = IRQ_DM646X_VP_VERTINT2,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_DM646X_VP_VERTINT3,
+ .end = IRQ_DM646X_VP_VERTINT3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device vpif_display_dev = {
+ .name = "vpif_display",
+ .id = -1,
+ .dev = {
+ .dma_mask = &vpif_dma_mask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .resource = vpif_resource,
+ .num_resources = ARRAY_SIZE(vpif_resource),
+};
+
/*----------------------------------------------------------------------*/
static struct map_desc dm646x_io_desc[] = {
@@ -609,7 +826,6 @@ static struct davinci_soc_info davinci_soc_info_dm646x = {
.intc_irq_prios = dm646x_default_priorities,
.intc_irq_num = DAVINCI_N_AINTC_IRQ,
.timer_info = &dm646x_timer_info,
- .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE),
.gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
.gpio_num = 43, /* Only 33 usable */
.gpio_irq = IRQ_DM646X_GPIOBNK0,
@@ -619,6 +835,47 @@ static struct davinci_soc_info davinci_soc_info_dm646x = {
.sram_len = SZ_32K,
};
+void __init dm646x_init_ide()
+{
+ davinci_cfg_reg(DM646X_ATAEN);
+ platform_device_register(&ide_dev);
+}
+
+void __init dm646x_init_mcasp0(struct snd_platform_data *pdata)
+{
+ dm646x_mcasp0_device.dev.platform_data = pdata;
+ platform_device_register(&dm646x_mcasp0_device);
+}
+
+void __init dm646x_init_mcasp1(struct snd_platform_data *pdata)
+{
+ dm646x_mcasp1_device.dev.platform_data = pdata;
+ platform_device_register(&dm646x_mcasp1_device);
+ platform_device_register(&dm646x_dit_device);
+}
+
+void dm646x_setup_vpif(struct vpif_config *config)
+{
+ unsigned int value;
+ void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+
+ value = __raw_readl(base + VSCLKDIS_OFFSET);
+ value &= ~VSCLKDIS_MASK;
+ __raw_writel(value, base + VSCLKDIS_OFFSET);
+
+ value = __raw_readl(base + VDD3P3V_PWDN_OFFSET);
+ value &= ~VDD3P3V_VID_MASK;
+ __raw_writel(value, base + VDD3P3V_PWDN_OFFSET);
+
+ davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
+ davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
+ davinci_cfg_reg(DM646X_PTSOMUX_DISABLE);
+ davinci_cfg_reg(DM646X_PTSIMUX_DISABLE);
+
+ vpif_display_dev.dev.platform_data = config;
+ platform_device_register(&vpif_display_dev);
+}
+
void __init dm646x_init(void)
{
davinci_common_init(&davinci_soc_info_dm646x);
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index 15e9eb158bb7..5908f7717b29 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -100,132 +100,157 @@
#define EDMA_SHADOW0 0x2000 /* 4 regions shadowing global channels */
#define EDMA_PARM 0x4000 /* 128 param entries */
-#define DAVINCI_DMA_3PCC_BASE 0x01C00000
-
#define PARM_OFFSET(param_no) (EDMA_PARM + ((param_no) << 5))
+#define EDMA_DCHMAP 0x0100 /* 64 registers */
+#define CHMAP_EXIST BIT(24)
+
#define EDMA_MAX_DMACH 64
#define EDMA_MAX_PARAMENTRY 512
-#define EDMA_MAX_EVQUE 2 /* FIXME too small */
+#define EDMA_MAX_CC 2
/*****************************************************************************/
-static void __iomem *edmacc_regs_base;
+static void __iomem *edmacc_regs_base[EDMA_MAX_CC];
-static inline unsigned int edma_read(int offset)
+static inline unsigned int edma_read(unsigned ctlr, int offset)
{
- return (unsigned int)__raw_readl(edmacc_regs_base + offset);
+ return (unsigned int)__raw_readl(edmacc_regs_base[ctlr] + offset);
}
-static inline void edma_write(int offset, int val)
+static inline void edma_write(unsigned ctlr, int offset, int val)
{
- __raw_writel(val, edmacc_regs_base + offset);
+ __raw_writel(val, edmacc_regs_base[ctlr] + offset);
}
-static inline void edma_modify(int offset, unsigned and, unsigned or)
+static inline void edma_modify(unsigned ctlr, int offset, unsigned and,
+ unsigned or)
{
- unsigned val = edma_read(offset);
+ unsigned val = edma_read(ctlr, offset);
val &= and;
val |= or;
- edma_write(offset, val);
+ edma_write(ctlr, offset, val);
}
-static inline void edma_and(int offset, unsigned and)
+static inline void edma_and(unsigned ctlr, int offset, unsigned and)
{
- unsigned val = edma_read(offset);
+ unsigned val = edma_read(ctlr, offset);
val &= and;
- edma_write(offset, val);
+ edma_write(ctlr, offset, val);
}
-static inline void edma_or(int offset, unsigned or)
+static inline void edma_or(unsigned ctlr, int offset, unsigned or)
{
- unsigned val = edma_read(offset);
+ unsigned val = edma_read(ctlr, offset);
val |= or;
- edma_write(offset, val);
+ edma_write(ctlr, offset, val);
}
-static inline unsigned int edma_read_array(int offset, int i)
+static inline unsigned int edma_read_array(unsigned ctlr, int offset, int i)
{
- return edma_read(offset + (i << 2));
+ return edma_read(ctlr, offset + (i << 2));
}
-static inline void edma_write_array(int offset, int i, unsigned val)
+static inline void edma_write_array(unsigned ctlr, int offset, int i,
+ unsigned val)
{
- edma_write(offset + (i << 2), val);
+ edma_write(ctlr, offset + (i << 2), val);
}
-static inline void edma_modify_array(int offset, int i,
+static inline void edma_modify_array(unsigned ctlr, int offset, int i,
unsigned and, unsigned or)
{
- edma_modify(offset + (i << 2), and, or);
+ edma_modify(ctlr, offset + (i << 2), and, or);
}
-static inline void edma_or_array(int offset, int i, unsigned or)
+static inline void edma_or_array(unsigned ctlr, int offset, int i, unsigned or)
{
- edma_or(offset + (i << 2), or);
+ edma_or(ctlr, offset + (i << 2), or);
}
-static inline void edma_or_array2(int offset, int i, int j, unsigned or)
+static inline void edma_or_array2(unsigned ctlr, int offset, int i, int j,
+ unsigned or)
{
- edma_or(offset + ((i*2 + j) << 2), or);
+ edma_or(ctlr, offset + ((i*2 + j) << 2), or);
}
-static inline void edma_write_array2(int offset, int i, int j, unsigned val)
+static inline void edma_write_array2(unsigned ctlr, int offset, int i, int j,
+ unsigned val)
{
- edma_write(offset + ((i*2 + j) << 2), val);
+ edma_write(ctlr, offset + ((i*2 + j) << 2), val);
}
-static inline unsigned int edma_shadow0_read(int offset)
+static inline unsigned int edma_shadow0_read(unsigned ctlr, int offset)
{
- return edma_read(EDMA_SHADOW0 + offset);
+ return edma_read(ctlr, EDMA_SHADOW0 + offset);
}
-static inline unsigned int edma_shadow0_read_array(int offset, int i)
+static inline unsigned int edma_shadow0_read_array(unsigned ctlr, int offset,
+ int i)
{
- return edma_read(EDMA_SHADOW0 + offset + (i << 2));
+ return edma_read(ctlr, EDMA_SHADOW0 + offset + (i << 2));
}
-static inline void edma_shadow0_write(int offset, unsigned val)
+static inline void edma_shadow0_write(unsigned ctlr, int offset, unsigned val)
{
- edma_write(EDMA_SHADOW0 + offset, val);
+ edma_write(ctlr, EDMA_SHADOW0 + offset, val);
}
-static inline void edma_shadow0_write_array(int offset, int i, unsigned val)
+static inline void edma_shadow0_write_array(unsigned ctlr, int offset, int i,
+ unsigned val)
{
- edma_write(EDMA_SHADOW0 + offset + (i << 2), val);
+ edma_write(ctlr, EDMA_SHADOW0 + offset + (i << 2), val);
}
-static inline unsigned int edma_parm_read(int offset, int param_no)
+static inline unsigned int edma_parm_read(unsigned ctlr, int offset,
+ int param_no)
{
- return edma_read(EDMA_PARM + offset + (param_no << 5));
+ return edma_read(ctlr, EDMA_PARM + offset + (param_no << 5));
}
-static inline void edma_parm_write(int offset, int param_no, unsigned val)
+static inline void edma_parm_write(unsigned ctlr, int offset, int param_no,
+ unsigned val)
{
- edma_write(EDMA_PARM + offset + (param_no << 5), val);
+ edma_write(ctlr, EDMA_PARM + offset + (param_no << 5), val);
}
-static inline void edma_parm_modify(int offset, int param_no,
+static inline void edma_parm_modify(unsigned ctlr, int offset, int param_no,
unsigned and, unsigned or)
{
- edma_modify(EDMA_PARM + offset + (param_no << 5), and, or);
+ edma_modify(ctlr, EDMA_PARM + offset + (param_no << 5), and, or);
}
-static inline void edma_parm_and(int offset, int param_no, unsigned and)
+static inline void edma_parm_and(unsigned ctlr, int offset, int param_no,
+ unsigned and)
{
- edma_and(EDMA_PARM + offset + (param_no << 5), and);
+ edma_and(ctlr, EDMA_PARM + offset + (param_no << 5), and);
}
-static inline void edma_parm_or(int offset, int param_no, unsigned or)
+static inline void edma_parm_or(unsigned ctlr, int offset, int param_no,
+ unsigned or)
{
- edma_or(EDMA_PARM + offset + (param_no << 5), or);
+ edma_or(ctlr, EDMA_PARM + offset + (param_no << 5), or);
}
/*****************************************************************************/
/* actual number of DMA channels and slots on this silicon */
-static unsigned num_channels;
-static unsigned num_slots;
+struct edma {
+ /* how many dma resources of each type */
+ unsigned num_channels;
+ unsigned num_region;
+ unsigned num_slots;
+ unsigned num_tc;
+ unsigned num_cc;
+
+ /* list of channels with no even trigger; terminated by "-1" */
+ const s8 *noevent;
+
+ /* The edma_inuse bit for each PaRAM slot is clear unless the
+ * channel is in use ... by ARM or DSP, for QDMA, or whatever.
+ */
+ DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
-static struct dma_interrupt_data {
- void (*callback)(unsigned channel, unsigned short ch_status,
- void *data);
- void *data;
-} intr_data[EDMA_MAX_DMACH];
+ /* The edma_noevent bit for each channel is clear unless
+ * it doesn't trigger DMA events on this platform. It uses a
+ * bit of SOC-specific initialization code.
+ */
+ DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
-/* The edma_inuse bit for each PaRAM slot is clear unless the
- * channel is in use ... by ARM or DSP, for QDMA, or whatever.
- */
-static DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
+ unsigned irq_res_start;
+ unsigned irq_res_end;
-/* The edma_noevent bit for each channel is clear unless
- * it doesn't trigger DMA events on this platform. It uses a
- * bit of SOC-specific initialization code.
- */
-static DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
+ struct dma_interrupt_data {
+ void (*callback)(unsigned channel, unsigned short ch_status,
+ void *data);
+ void *data;
+ } intr_data[EDMA_MAX_DMACH];
+};
+
+static struct edma *edma_info[EDMA_MAX_CC];
/* dummy param set used to (re)initialize parameter RAM slots */
static const struct edmacc_param dummy_paramset = {
@@ -233,25 +258,10 @@ static const struct edmacc_param dummy_paramset = {
.ccnt = 1,
};
-static const int __initconst
-queue_tc_mapping[EDMA_MAX_EVQUE + 1][2] = {
-/* {event queue no, TC no} */
- {0, 0},
- {1, 1},
- {-1, -1}
-};
-
-static const int __initconst
-queue_priority_mapping[EDMA_MAX_EVQUE + 1][2] = {
- /* {event queue no, Priority} */
- {0, 3},
- {1, 7},
- {-1, -1}
-};
-
/*****************************************************************************/
-static void map_dmach_queue(unsigned ch_no, enum dma_event_q queue_no)
+static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
+ enum dma_event_q queue_no)
{
int bit = (ch_no & 0x7) * 4;
@@ -260,20 +270,40 @@ static void map_dmach_queue(unsigned ch_no, enum dma_event_q queue_no)
queue_no = EVENTQ_1;
queue_no &= 7;
- edma_modify_array(EDMA_DMAQNUM, (ch_no >> 3),
+ edma_modify_array(ctlr, EDMA_DMAQNUM, (ch_no >> 3),
~(0x7 << bit), queue_no << bit);
}
-static void __init map_queue_tc(int queue_no, int tc_no)
+static void __init map_queue_tc(unsigned ctlr, int queue_no, int tc_no)
{
int bit = queue_no * 4;
- edma_modify(EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit));
+ edma_modify(ctlr, EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit));
}
-static void __init assign_priority_to_queue(int queue_no, int priority)
+static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
+ int priority)
{
int bit = queue_no * 4;
- edma_modify(EDMA_QUEPRI, ~(0x7 << bit), ((priority & 0x7) << bit));
+ edma_modify(ctlr, EDMA_QUEPRI, ~(0x7 << bit),
+ ((priority & 0x7) << bit));
+}
+
+/**
+ * map_dmach_param - Maps channel number to param entry number
+ *
+ * This maps the dma channel number to param entry numberter. In
+ * other words using the DMA channel mapping registers a param entry
+ * can be mapped to any channel
+ *
+ * Callers are responsible for ensuring the channel mapping logic is
+ * included in that particular EDMA variant (Eg : dm646x)
+ *
+ */
+static void __init map_dmach_param(unsigned ctlr)
+{
+ int i;
+ for (i = 0; i < EDMA_MAX_DMACH; i++)
+ edma_write_array(ctlr, EDMA_DCHMAP , i , (i << 5));
}
static inline void
@@ -281,22 +311,39 @@ setup_dma_interrupt(unsigned lch,
void (*callback)(unsigned channel, u16 ch_status, void *data),
void *data)
{
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(lch);
+ lch = EDMA_CHAN_SLOT(lch);
+
if (!callback) {
- edma_shadow0_write_array(SH_IECR, lch >> 5,
+ edma_shadow0_write_array(ctlr, SH_IECR, lch >> 5,
(1 << (lch & 0x1f)));
}
- intr_data[lch].callback = callback;
- intr_data[lch].data = data;
+ edma_info[ctlr]->intr_data[lch].callback = callback;
+ edma_info[ctlr]->intr_data[lch].data = data;
if (callback) {
- edma_shadow0_write_array(SH_ICR, lch >> 5,
+ edma_shadow0_write_array(ctlr, SH_ICR, lch >> 5,
(1 << (lch & 0x1f)));
- edma_shadow0_write_array(SH_IESR, lch >> 5,
+ edma_shadow0_write_array(ctlr, SH_IESR, lch >> 5,
(1 << (lch & 0x1f)));
}
}
+static int irq2ctlr(int irq)
+{
+ if (irq >= edma_info[0]->irq_res_start &&
+ irq <= edma_info[0]->irq_res_end)
+ return 0;
+ else if (irq >= edma_info[1]->irq_res_start &&
+ irq <= edma_info[1]->irq_res_end)
+ return 1;
+
+ return -1;
+}
+
/******************************************************************************
*
* DMA interrupt handler
@@ -305,32 +352,39 @@ setup_dma_interrupt(unsigned lch,
static irqreturn_t dma_irq_handler(int irq, void *data)
{
int i;
+ unsigned ctlr;
unsigned int cnt = 0;
+ ctlr = irq2ctlr(irq);
+
dev_dbg(data, "dma_irq_handler\n");
- if ((edma_shadow0_read_array(SH_IPR, 0) == 0)
- && (edma_shadow0_read_array(SH_IPR, 1) == 0))
+ if ((edma_shadow0_read_array(ctlr, SH_IPR, 0) == 0)
+ && (edma_shadow0_read_array(ctlr, SH_IPR, 1) == 0))
return IRQ_NONE;
while (1) {
int j;
- if (edma_shadow0_read_array(SH_IPR, 0))
+ if (edma_shadow0_read_array(ctlr, SH_IPR, 0))
j = 0;
- else if (edma_shadow0_read_array(SH_IPR, 1))
+ else if (edma_shadow0_read_array(ctlr, SH_IPR, 1))
j = 1;
else
break;
dev_dbg(data, "IPR%d %08x\n", j,
- edma_shadow0_read_array(SH_IPR, j));
+ edma_shadow0_read_array(ctlr, SH_IPR, j));
for (i = 0; i < 32; i++) {
int k = (j << 5) + i;
- if (edma_shadow0_read_array(SH_IPR, j) & (1 << i)) {
+ if (edma_shadow0_read_array(ctlr, SH_IPR, j) &
+ (1 << i)) {
/* Clear the corresponding IPR bits */
- edma_shadow0_write_array(SH_ICR, j, (1 << i));
- if (intr_data[k].callback) {
- intr_data[k].callback(k, DMA_COMPLETE,
- intr_data[k].data);
+ edma_shadow0_write_array(ctlr, SH_ICR, j,
+ (1 << i));
+ if (edma_info[ctlr]->intr_data[k].callback) {
+ edma_info[ctlr]->intr_data[k].callback(
+ k, DMA_COMPLETE,
+ edma_info[ctlr]->intr_data[k].
+ data);
}
}
}
@@ -338,7 +392,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
if (cnt > 10)
break;
}
- edma_shadow0_write(SH_IEVAL, 1);
+ edma_shadow0_write(ctlr, SH_IEVAL, 1);
return IRQ_HANDLED;
}
@@ -350,78 +404,87 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
static irqreturn_t dma_ccerr_handler(int irq, void *data)
{
int i;
+ unsigned ctlr;
unsigned int cnt = 0;
+ ctlr = irq2ctlr(irq);
+
dev_dbg(data, "dma_ccerr_handler\n");
- if ((edma_read_array(EDMA_EMR, 0) == 0) &&
- (edma_read_array(EDMA_EMR, 1) == 0) &&
- (edma_read(EDMA_QEMR) == 0) && (edma_read(EDMA_CCERR) == 0))
+ if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) &&
+ (edma_read_array(ctlr, EDMA_EMR, 1) == 0) &&
+ (edma_read(ctlr, EDMA_QEMR) == 0) &&
+ (edma_read(ctlr, EDMA_CCERR) == 0))
return IRQ_NONE;
while (1) {
int j = -1;
- if (edma_read_array(EDMA_EMR, 0))
+ if (edma_read_array(ctlr, EDMA_EMR, 0))
j = 0;
- else if (edma_read_array(EDMA_EMR, 1))
+ else if (edma_read_array(ctlr, EDMA_EMR, 1))
j = 1;
if (j >= 0) {
dev_dbg(data, "EMR%d %08x\n", j,
- edma_read_array(EDMA_EMR, j));
+ edma_read_array(ctlr, EDMA_EMR, j));
for (i = 0; i < 32; i++) {
int k = (j << 5) + i;
- if (edma_read_array(EDMA_EMR, j) & (1 << i)) {
+ if (edma_read_array(ctlr, EDMA_EMR, j) &
+ (1 << i)) {
/* Clear the corresponding EMR bits */
- edma_write_array(EDMA_EMCR, j, 1 << i);
+ edma_write_array(ctlr, EDMA_EMCR, j,
+ 1 << i);
/* Clear any SER */
- edma_shadow0_write_array(SH_SECR, j,
- (1 << i));
- if (intr_data[k].callback) {
- intr_data[k].callback(k,
- DMA_CC_ERROR,
- intr_data
- [k].data);
+ edma_shadow0_write_array(ctlr, SH_SECR,
+ j, (1 << i));
+ if (edma_info[ctlr]->intr_data[k].
+ callback) {
+ edma_info[ctlr]->intr_data[k].
+ callback(k,
+ DMA_CC_ERROR,
+ edma_info[ctlr]->intr_data
+ [k].data);
}
}
}
- } else if (edma_read(EDMA_QEMR)) {
+ } else if (edma_read(ctlr, EDMA_QEMR)) {
dev_dbg(data, "QEMR %02x\n",
- edma_read(EDMA_QEMR));
+ edma_read(ctlr, EDMA_QEMR));
for (i = 0; i < 8; i++) {
- if (edma_read(EDMA_QEMR) & (1 << i)) {
+ if (edma_read(ctlr, EDMA_QEMR) & (1 << i)) {
/* Clear the corresponding IPR bits */
- edma_write(EDMA_QEMCR, 1 << i);
- edma_shadow0_write(SH_QSECR, (1 << i));
+ edma_write(ctlr, EDMA_QEMCR, 1 << i);
+ edma_shadow0_write(ctlr, SH_QSECR,
+ (1 << i));
/* NOTE: not reported!! */
}
}
- } else if (edma_read(EDMA_CCERR)) {
+ } else if (edma_read(ctlr, EDMA_CCERR)) {
dev_dbg(data, "CCERR %08x\n",
- edma_read(EDMA_CCERR));
+ edma_read(ctlr, EDMA_CCERR));
/* FIXME: CCERR.BIT(16) ignored! much better
* to just write CCERRCLR with CCERR value...
*/
for (i = 0; i < 8; i++) {
- if (edma_read(EDMA_CCERR) & (1 << i)) {
+ if (edma_read(ctlr, EDMA_CCERR) & (1 << i)) {
/* Clear the corresponding IPR bits */
- edma_write(EDMA_CCERRCLR, 1 << i);
+ edma_write(ctlr, EDMA_CCERRCLR, 1 << i);
/* NOTE: not reported!! */
}
}
}
- if ((edma_read_array(EDMA_EMR, 0) == 0)
- && (edma_read_array(EDMA_EMR, 1) == 0)
- && (edma_read(EDMA_QEMR) == 0)
- && (edma_read(EDMA_CCERR) == 0)) {
+ if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0)
+ && (edma_read_array(ctlr, EDMA_EMR, 1) == 0)
+ && (edma_read(ctlr, EDMA_QEMR) == 0)
+ && (edma_read(ctlr, EDMA_CCERR) == 0)) {
break;
}
cnt++;
if (cnt > 10)
break;
}
- edma_write(EDMA_EEVAL, 1);
+ edma_write(ctlr, EDMA_EEVAL, 1);
return IRQ_HANDLED;
}
@@ -484,35 +547,53 @@ int edma_alloc_channel(int channel,
void *data,
enum dma_event_q eventq_no)
{
+ unsigned i, done, ctlr = 0;
+
+ if (channel >= 0) {
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+ }
+
if (channel < 0) {
- channel = 0;
- for (;;) {
- channel = find_next_bit(edma_noevent,
- num_channels, channel);
- if (channel == num_channels)
- return -ENOMEM;
- if (!test_and_set_bit(channel, edma_inuse))
+ for (i = 0; i < EDMA_MAX_CC; i++) {
+ channel = 0;
+ for (;;) {
+ channel = find_next_bit(edma_info[i]->
+ edma_noevent,
+ edma_info[i]->num_channels,
+ channel);
+ if (channel == edma_info[i]->num_channels)
+ return -ENOMEM;
+ if (!test_and_set_bit(channel,
+ edma_info[i]->edma_inuse)) {
+ done = 1;
+ ctlr = i;
+ break;
+ }
+ channel++;
+ }
+ if (done)
break;
- channel++;
}
- } else if (channel >= num_channels) {
+ } else if (channel >= edma_info[ctlr]->num_channels) {
return -EINVAL;
- } else if (test_and_set_bit(channel, edma_inuse)) {
+ } else if (test_and_set_bit(channel, edma_info[ctlr]->edma_inuse)) {
return -EBUSY;
}
/* ensure access through shadow region 0 */
- edma_or_array2(EDMA_DRAE, 0, channel >> 5, 1 << (channel & 0x1f));
+ edma_or_array2(ctlr, EDMA_DRAE, 0, channel >> 5, 1 << (channel & 0x1f));
/* ensure no events are pending */
- edma_stop(channel);
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(channel),
+ edma_stop(EDMA_CTLR_CHAN(ctlr, channel));
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel),
&dummy_paramset, PARM_SIZE);
if (callback)
- setup_dma_interrupt(channel, callback, data);
+ setup_dma_interrupt(EDMA_CTLR_CHAN(ctlr, channel),
+ callback, data);
- map_dmach_queue(channel, eventq_no);
+ map_dmach_queue(ctlr, channel, eventq_no);
return channel;
}
@@ -532,15 +613,20 @@ EXPORT_SYMBOL(edma_alloc_channel);
*/
void edma_free_channel(unsigned channel)
{
- if (channel >= num_channels)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel >= edma_info[ctlr]->num_channels)
return;
setup_dma_interrupt(channel, NULL, NULL);
/* REVISIT should probably take out of shadow region 0 */
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(channel),
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(channel),
&dummy_paramset, PARM_SIZE);
- clear_bit(channel, edma_inuse);
+ clear_bit(channel, edma_info[ctlr]->edma_inuse);
}
EXPORT_SYMBOL(edma_free_channel);
@@ -558,28 +644,33 @@ EXPORT_SYMBOL(edma_free_channel);
*
* Returns the number of the slot, else negative errno.
*/
-int edma_alloc_slot(int slot)
+int edma_alloc_slot(unsigned ctlr, int slot)
{
+ if (slot >= 0)
+ slot = EDMA_CHAN_SLOT(slot);
+
if (slot < 0) {
- slot = num_channels;
+ slot = edma_info[ctlr]->num_channels;
for (;;) {
- slot = find_next_zero_bit(edma_inuse,
- num_slots, slot);
- if (slot == num_slots)
+ slot = find_next_zero_bit(edma_info[ctlr]->edma_inuse,
+ edma_info[ctlr]->num_slots, slot);
+ if (slot == edma_info[ctlr]->num_slots)
return -ENOMEM;
- if (!test_and_set_bit(slot, edma_inuse))
+ if (!test_and_set_bit(slot,
+ edma_info[ctlr]->edma_inuse))
break;
}
- } else if (slot < num_channels || slot >= num_slots) {
+ } else if (slot < edma_info[ctlr]->num_channels ||
+ slot >= edma_info[ctlr]->num_slots) {
return -EINVAL;
- } else if (test_and_set_bit(slot, edma_inuse)) {
+ } else if (test_and_set_bit(slot, edma_info[ctlr]->edma_inuse)) {
return -EBUSY;
}
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot),
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot),
&dummy_paramset, PARM_SIZE);
- return slot;
+ return EDMA_CTLR_CHAN(ctlr, slot);
}
EXPORT_SYMBOL(edma_alloc_slot);
@@ -593,12 +684,18 @@ EXPORT_SYMBOL(edma_alloc_slot);
*/
void edma_free_slot(unsigned slot)
{
- if (slot < num_channels || slot >= num_slots)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_channels ||
+ slot >= edma_info[ctlr]->num_slots)
return;
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot),
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot),
&dummy_paramset, PARM_SIZE);
- clear_bit(slot, edma_inuse);
+ clear_bit(slot, edma_info[ctlr]->edma_inuse);
}
EXPORT_SYMBOL(edma_free_slot);
@@ -620,8 +717,13 @@ EXPORT_SYMBOL(edma_free_slot);
void edma_set_src(unsigned slot, dma_addr_t src_port,
enum address_mode mode, enum fifo_width width)
{
- if (slot < num_slots) {
- unsigned int i = edma_parm_read(PARM_OPT, slot);
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_slots) {
+ unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot);
if (mode) {
/* set SAM and program FWID */
@@ -630,11 +732,11 @@ void edma_set_src(unsigned slot, dma_addr_t src_port,
/* clear SAM */
i &= ~SAM;
}
- edma_parm_write(PARM_OPT, slot, i);
+ edma_parm_write(ctlr, PARM_OPT, slot, i);
/* set the source port address
in source register of param structure */
- edma_parm_write(PARM_SRC, slot, src_port);
+ edma_parm_write(ctlr, PARM_SRC, slot, src_port);
}
}
EXPORT_SYMBOL(edma_set_src);
@@ -653,8 +755,13 @@ EXPORT_SYMBOL(edma_set_src);
void edma_set_dest(unsigned slot, dma_addr_t dest_port,
enum address_mode mode, enum fifo_width width)
{
- if (slot < num_slots) {
- unsigned int i = edma_parm_read(PARM_OPT, slot);
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_slots) {
+ unsigned int i = edma_parm_read(ctlr, PARM_OPT, slot);
if (mode) {
/* set DAM and program FWID */
@@ -663,10 +770,10 @@ void edma_set_dest(unsigned slot, dma_addr_t dest_port,
/* clear DAM */
i &= ~DAM;
}
- edma_parm_write(PARM_OPT, slot, i);
+ edma_parm_write(ctlr, PARM_OPT, slot, i);
/* set the destination port address
in dest register of param structure */
- edma_parm_write(PARM_DST, slot, dest_port);
+ edma_parm_write(ctlr, PARM_DST, slot, dest_port);
}
}
EXPORT_SYMBOL(edma_set_dest);
@@ -683,8 +790,12 @@ EXPORT_SYMBOL(edma_set_dest);
void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst)
{
struct edmacc_param temp;
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
- edma_read_slot(slot, &temp);
+ edma_read_slot(EDMA_CTLR_CHAN(ctlr, slot), &temp);
if (src != NULL)
*src = temp.src;
if (dst != NULL)
@@ -704,10 +815,15 @@ EXPORT_SYMBOL(edma_get_position);
*/
void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx)
{
- if (slot < num_slots) {
- edma_parm_modify(PARM_SRC_DST_BIDX, slot,
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_slots) {
+ edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot,
0xffff0000, src_bidx);
- edma_parm_modify(PARM_SRC_DST_CIDX, slot,
+ edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot,
0xffff0000, src_cidx);
}
}
@@ -725,10 +841,15 @@ EXPORT_SYMBOL(edma_set_src_index);
*/
void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx)
{
- if (slot < num_slots) {
- edma_parm_modify(PARM_SRC_DST_BIDX, slot,
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_slots) {
+ edma_parm_modify(ctlr, PARM_SRC_DST_BIDX, slot,
0x0000ffff, dest_bidx << 16);
- edma_parm_modify(PARM_SRC_DST_CIDX, slot,
+ edma_parm_modify(ctlr, PARM_SRC_DST_CIDX, slot,
0x0000ffff, dest_cidx << 16);
}
}
@@ -767,16 +888,21 @@ void edma_set_transfer_params(unsigned slot,
u16 acnt, u16 bcnt, u16 ccnt,
u16 bcnt_rld, enum sync_dimension sync_mode)
{
- if (slot < num_slots) {
- edma_parm_modify(PARM_LINK_BCNTRLD, slot,
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot < edma_info[ctlr]->num_slots) {
+ edma_parm_modify(ctlr, PARM_LINK_BCNTRLD, slot,
0x0000ffff, bcnt_rld << 16);
if (sync_mode == ASYNC)
- edma_parm_and(PARM_OPT, slot, ~SYNCDIM);
+ edma_parm_and(ctlr, PARM_OPT, slot, ~SYNCDIM);
else
- edma_parm_or(PARM_OPT, slot, SYNCDIM);
+ edma_parm_or(ctlr, PARM_OPT, slot, SYNCDIM);
/* Set the acount, bcount, ccount registers */
- edma_parm_write(PARM_A_B_CNT, slot, (bcnt << 16) | acnt);
- edma_parm_write(PARM_CCNT, slot, ccnt);
+ edma_parm_write(ctlr, PARM_A_B_CNT, slot, (bcnt << 16) | acnt);
+ edma_parm_write(ctlr, PARM_CCNT, slot, ccnt);
}
}
EXPORT_SYMBOL(edma_set_transfer_params);
@@ -790,11 +916,19 @@ EXPORT_SYMBOL(edma_set_transfer_params);
*/
void edma_link(unsigned from, unsigned to)
{
- if (from >= num_slots)
+ unsigned ctlr_from, ctlr_to;
+
+ ctlr_from = EDMA_CTLR(from);
+ from = EDMA_CHAN_SLOT(from);
+ ctlr_to = EDMA_CTLR(to);
+ to = EDMA_CHAN_SLOT(to);
+
+ if (from >= edma_info[ctlr_from]->num_slots)
return;
- if (to >= num_slots)
+ if (to >= edma_info[ctlr_to]->num_slots)
return;
- edma_parm_modify(PARM_LINK_BCNTRLD, from, 0xffff0000, PARM_OFFSET(to));
+ edma_parm_modify(ctlr_from, PARM_LINK_BCNTRLD, from, 0xffff0000,
+ PARM_OFFSET(to));
}
EXPORT_SYMBOL(edma_link);
@@ -807,9 +941,14 @@ EXPORT_SYMBOL(edma_link);
*/
void edma_unlink(unsigned from)
{
- if (from >= num_slots)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(from);
+ from = EDMA_CHAN_SLOT(from);
+
+ if (from >= edma_info[ctlr]->num_slots)
return;
- edma_parm_or(PARM_LINK_BCNTRLD, from, 0xffff);
+ edma_parm_or(ctlr, PARM_LINK_BCNTRLD, from, 0xffff);
}
EXPORT_SYMBOL(edma_unlink);
@@ -829,9 +968,15 @@ EXPORT_SYMBOL(edma_unlink);
*/
void edma_write_slot(unsigned slot, const struct edmacc_param *param)
{
- if (slot >= num_slots)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot >= edma_info[ctlr]->num_slots)
return;
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), param, PARM_SIZE);
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot), param,
+ PARM_SIZE);
}
EXPORT_SYMBOL(edma_write_slot);
@@ -845,9 +990,15 @@ EXPORT_SYMBOL(edma_write_slot);
*/
void edma_read_slot(unsigned slot, struct edmacc_param *param)
{
- if (slot >= num_slots)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(slot);
+ slot = EDMA_CHAN_SLOT(slot);
+
+ if (slot >= edma_info[ctlr]->num_slots)
return;
- memcpy_fromio(param, edmacc_regs_base + PARM_OFFSET(slot), PARM_SIZE);
+ memcpy_fromio(param, edmacc_regs_base[ctlr] + PARM_OFFSET(slot),
+ PARM_SIZE);
}
EXPORT_SYMBOL(edma_read_slot);
@@ -864,10 +1015,15 @@ EXPORT_SYMBOL(edma_read_slot);
*/
void edma_pause(unsigned channel)
{
- if (channel < num_channels) {
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel < edma_info[ctlr]->num_channels) {
unsigned int mask = (1 << (channel & 0x1f));
- edma_shadow0_write_array(SH_EECR, channel >> 5, mask);
+ edma_shadow0_write_array(ctlr, SH_EECR, channel >> 5, mask);
}
}
EXPORT_SYMBOL(edma_pause);
@@ -880,10 +1036,15 @@ EXPORT_SYMBOL(edma_pause);
*/
void edma_resume(unsigned channel)
{
- if (channel < num_channels) {
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel < edma_info[ctlr]->num_channels) {
unsigned int mask = (1 << (channel & 0x1f));
- edma_shadow0_write_array(SH_EESR, channel >> 5, mask);
+ edma_shadow0_write_array(ctlr, SH_EESR, channel >> 5, mask);
}
}
EXPORT_SYMBOL(edma_resume);
@@ -901,28 +1062,33 @@ EXPORT_SYMBOL(edma_resume);
*/
int edma_start(unsigned channel)
{
- if (channel < num_channels) {
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel < edma_info[ctlr]->num_channels) {
int j = channel >> 5;
unsigned int mask = (1 << (channel & 0x1f));
/* EDMA channels without event association */
- if (test_bit(channel, edma_noevent)) {
+ if (test_bit(channel, edma_info[ctlr]->edma_noevent)) {
pr_debug("EDMA: ESR%d %08x\n", j,
- edma_shadow0_read_array(SH_ESR, j));
- edma_shadow0_write_array(SH_ESR, j, mask);
+ edma_shadow0_read_array(ctlr, SH_ESR, j));
+ edma_shadow0_write_array(ctlr, SH_ESR, j, mask);
return 0;
}
/* EDMA channel with event association */
pr_debug("EDMA: ER%d %08x\n", j,
- edma_shadow0_read_array(SH_ER, j));
+ edma_shadow0_read_array(ctlr, SH_ER, j));
/* Clear any pending error */
- edma_write_array(EDMA_EMCR, j, mask);
+ edma_write_array(ctlr, EDMA_EMCR, j, mask);
/* Clear any SER */
- edma_shadow0_write_array(SH_SECR, j, mask);
- edma_shadow0_write_array(SH_EESR, j, mask);
+ edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
+ edma_shadow0_write_array(ctlr, SH_EESR, j, mask);
pr_debug("EDMA: EER%d %08x\n", j,
- edma_shadow0_read_array(SH_EER, j));
+ edma_shadow0_read_array(ctlr, SH_EER, j));
return 0;
}
@@ -941,17 +1107,22 @@ EXPORT_SYMBOL(edma_start);
*/
void edma_stop(unsigned channel)
{
- if (channel < num_channels) {
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel < edma_info[ctlr]->num_channels) {
int j = channel >> 5;
unsigned int mask = (1 << (channel & 0x1f));
- edma_shadow0_write_array(SH_EECR, j, mask);
- edma_shadow0_write_array(SH_ECR, j, mask);
- edma_shadow0_write_array(SH_SECR, j, mask);
- edma_write_array(EDMA_EMCR, j, mask);
+ edma_shadow0_write_array(ctlr, SH_EECR, j, mask);
+ edma_shadow0_write_array(ctlr, SH_ECR, j, mask);
+ edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
+ edma_write_array(ctlr, EDMA_EMCR, j, mask);
pr_debug("EDMA: EER%d %08x\n", j,
- edma_shadow0_read_array(SH_EER, j));
+ edma_shadow0_read_array(ctlr, SH_EER, j));
/* REVISIT: consider guarding against inappropriate event
* chaining by overwriting with dummy_paramset.
@@ -975,18 +1146,23 @@ EXPORT_SYMBOL(edma_stop);
void edma_clean_channel(unsigned channel)
{
- if (channel < num_channels) {
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel < edma_info[ctlr]->num_channels) {
int j = (channel >> 5);
unsigned int mask = 1 << (channel & 0x1f);
pr_debug("EDMA: EMR%d %08x\n", j,
- edma_read_array(EDMA_EMR, j));
- edma_shadow0_write_array(SH_ECR, j, mask);
+ edma_read_array(ctlr, EDMA_EMR, j));
+ edma_shadow0_write_array(ctlr, SH_ECR, j, mask);
/* Clear the corresponding EMR bits */
- edma_write_array(EDMA_EMCR, j, mask);
+ edma_write_array(ctlr, EDMA_EMCR, j, mask);
/* Clear any SER */
- edma_shadow0_write_array(SH_SECR, j, mask);
- edma_write(EDMA_CCERRCLR, (1 << 16) | 0x3);
+ edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
+ edma_write(ctlr, EDMA_CCERRCLR, (1 << 16) | 0x3);
}
}
EXPORT_SYMBOL(edma_clean_channel);
@@ -998,12 +1174,17 @@ EXPORT_SYMBOL(edma_clean_channel);
*/
void edma_clear_event(unsigned channel)
{
- if (channel >= num_channels)
+ unsigned ctlr;
+
+ ctlr = EDMA_CTLR(channel);
+ channel = EDMA_CHAN_SLOT(channel);
+
+ if (channel >= edma_info[ctlr]->num_channels)
return;
if (channel < 32)
- edma_write(EDMA_ECR, 1 << channel);
+ edma_write(ctlr, EDMA_ECR, 1 << channel);
else
- edma_write(EDMA_ECRH, 1 << (channel - 32));
+ edma_write(ctlr, EDMA_ECRH, 1 << (channel - 32));
}
EXPORT_SYMBOL(edma_clear_event);
@@ -1012,62 +1193,129 @@ EXPORT_SYMBOL(edma_clear_event);
static int __init edma_probe(struct platform_device *pdev)
{
struct edma_soc_info *info = pdev->dev.platform_data;
- int i;
- int status;
+ const s8 (*queue_priority_mapping)[2];
+ const s8 (*queue_tc_mapping)[2];
+ int i, j, found = 0;
+ int status = -1;
const s8 *noevent;
- int irq = 0, err_irq = 0;
- struct resource *r;
- resource_size_t len;
+ int irq[EDMA_MAX_CC] = {0, 0};
+ int err_irq[EDMA_MAX_CC] = {0, 0};
+ struct resource *r[EDMA_MAX_CC] = {NULL};
+ resource_size_t len[EDMA_MAX_CC];
+ char res_name[10];
+ char irq_name[10];
if (!info)
return -ENODEV;
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma_cc");
- if (!r)
- return -ENODEV;
+ for (j = 0; j < EDMA_MAX_CC; j++) {
+ sprintf(res_name, "edma_cc%d", j);
+ r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ res_name);
+ if (!r[j]) {
+ if (found)
+ break;
+ else
+ return -ENODEV;
+ } else
+ found = 1;
+
+ len[j] = resource_size(r[j]);
+
+ r[j] = request_mem_region(r[j]->start, len[j],
+ dev_name(&pdev->dev));
+ if (!r[j]) {
+ status = -EBUSY;
+ goto fail1;
+ }
- len = r->end - r->start + 1;
+ edmacc_regs_base[j] = ioremap(r[j]->start, len[j]);
+ if (!edmacc_regs_base[j]) {
+ status = -EBUSY;
+ goto fail1;
+ }
- r = request_mem_region(r->start, len, r->name);
- if (!r)
- return -EBUSY;
+ edma_info[j] = kmalloc(sizeof(struct edma), GFP_KERNEL);
+ if (!edma_info[j]) {
+ status = -ENOMEM;
+ goto fail1;
+ }
+ memset(edma_info[j], 0, sizeof(struct edma));
+
+ edma_info[j]->num_channels = min_t(unsigned, info[j].n_channel,
+ EDMA_MAX_DMACH);
+ edma_info[j]->num_slots = min_t(unsigned, info[j].n_slot,
+ EDMA_MAX_PARAMENTRY);
+ edma_info[j]->num_cc = min_t(unsigned, info[j].n_cc,
+ EDMA_MAX_CC);
+
+ dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n",
+ edmacc_regs_base[j]);
+
+ for (i = 0; i < edma_info[j]->num_slots; i++)
+ memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i),
+ &dummy_paramset, PARM_SIZE);
+
+ noevent = info[j].noevent;
+ if (noevent) {
+ while (*noevent != -1)
+ set_bit(*noevent++, edma_info[j]->edma_noevent);
+ }
- edmacc_regs_base = ioremap(r->start, len);
- if (!edmacc_regs_base) {
- status = -EBUSY;
- goto fail1;
- }
+ sprintf(irq_name, "edma%d", j);
+ irq[j] = platform_get_irq_byname(pdev, irq_name);
+ edma_info[j]->irq_res_start = irq[j];
+ status = request_irq(irq[j], dma_irq_handler, 0, "edma",
+ &pdev->dev);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
+ irq[j], status);
+ goto fail;
+ }
- num_channels = min_t(unsigned, info->n_channel, EDMA_MAX_DMACH);
- num_slots = min_t(unsigned, info->n_slot, EDMA_MAX_PARAMENTRY);
+ sprintf(irq_name, "edma%d_err", j);
+ err_irq[j] = platform_get_irq_byname(pdev, irq_name);
+ edma_info[j]->irq_res_end = err_irq[j];
+ status = request_irq(err_irq[j], dma_ccerr_handler, 0,
+ "edma_error", &pdev->dev);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
+ err_irq[j], status);
+ goto fail;
+ }
- dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", edmacc_regs_base);
+ /* Everything lives on transfer controller 1 until otherwise
+ * specified. This way, long transfers on the low priority queue
+ * started by the codec engine will not cause audio defects.
+ */
+ for (i = 0; i < edma_info[j]->num_channels; i++)
+ map_dmach_queue(j, i, EVENTQ_1);
- for (i = 0; i < num_slots; i++)
- memcpy_toio(edmacc_regs_base + PARM_OFFSET(i),
- &dummy_paramset, PARM_SIZE);
+ queue_tc_mapping = info[j].queue_tc_mapping;
+ queue_priority_mapping = info[j].queue_priority_mapping;
- noevent = info->noevent;
- if (noevent) {
- while (*noevent != -1)
- set_bit(*noevent++, edma_noevent);
- }
+ /* Event queue to TC mapping */
+ for (i = 0; queue_tc_mapping[i][0] != -1; i++)
+ map_queue_tc(j, queue_tc_mapping[i][0],
+ queue_tc_mapping[i][1]);
- irq = platform_get_irq(pdev, 0);
- status = request_irq(irq, dma_irq_handler, 0, "edma", &pdev->dev);
- if (status < 0) {
- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
- irq, status);
- goto fail;
- }
+ /* Event queue priority mapping */
+ for (i = 0; queue_priority_mapping[i][0] != -1; i++)
+ assign_priority_to_queue(j,
+ queue_priority_mapping[i][0],
+ queue_priority_mapping[i][1]);
+
+ /* Map the channel to param entry if channel mapping logic
+ * exist
+ */
+ if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
+ map_dmach_param(j);
- err_irq = platform_get_irq(pdev, 1);
- status = request_irq(err_irq, dma_ccerr_handler, 0,
- "edma_error", &pdev->dev);
- if (status < 0) {
- dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n",
- err_irq, status);
- goto fail;
+ for (i = 0; i < info[j].n_region; i++) {
+ edma_write_array2(j, EDMA_DRAE, i, 0, 0x0);
+ edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
+ edma_write_array(j, EDMA_QRAE, i, 0x0);
+ }
}
if (tc_errs_handled) {
@@ -1087,38 +1335,23 @@ static int __init edma_probe(struct platform_device *pdev)
}
}
- /* Everything lives on transfer controller 1 until otherwise specified.
- * This way, long transfers on the low priority queue
- * started by the codec engine will not cause audio defects.
- */
- for (i = 0; i < num_channels; i++)
- map_dmach_queue(i, EVENTQ_1);
-
- /* Event queue to TC mapping */
- for (i = 0; queue_tc_mapping[i][0] != -1; i++)
- map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]);
-
- /* Event queue priority mapping */
- for (i = 0; queue_priority_mapping[i][0] != -1; i++)
- assign_priority_to_queue(queue_priority_mapping[i][0],
- queue_priority_mapping[i][1]);
-
- for (i = 0; i < info->n_region; i++) {
- edma_write_array2(EDMA_DRAE, i, 0, 0x0);
- edma_write_array2(EDMA_DRAE, i, 1, 0x0);
- edma_write_array(EDMA_QRAE, i, 0x0);
- }
-
return 0;
fail:
- if (err_irq)
- free_irq(err_irq, NULL);
- if (irq)
- free_irq(irq, NULL);
- iounmap(edmacc_regs_base);
+ for (i = 0; i < EDMA_MAX_CC; i++) {
+ if (err_irq[i])
+ free_irq(err_irq[i], &pdev->dev);
+ if (irq[i])
+ free_irq(irq[i], &pdev->dev);
+ }
fail1:
- release_mem_region(r->start, len);
+ for (i = 0; i < EDMA_MAX_CC; i++) {
+ if (r[i])
+ release_mem_region(r[i]->start, len[i]);
+ if (edmacc_regs_base[i])
+ iounmap(edmacc_regs_base[i]);
+ kfree(edma_info[i]);
+ }
return status;
}
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index 1b6532159c58..f6ea9db11f41 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock);
struct davinci_gpio {
struct gpio_chip chip;
struct gpio_controller *__iomem regs;
+ int irq_base;
};
static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
@@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup);
* used as output pins ... which is convenient for testing.
*
* NOTE: The first few GPIOs also have direct INTC hookups in addition
- * to their GPIOBNK0 irq, with a bit less overhead but less flexibility
- * on triggering (e.g. no edge options). We don't try to use those.
+ * to their GPIOBNK0 irq, with a bit less overhead.
*
* All those INTC hookups (direct, plus several IRQ banks) can also
* serve as EDMA event triggers.
@@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup);
static void gpio_irq_disable(unsigned irq)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
- u32 mask = __gpio_mask(irq_to_gpio(irq));
+ u32 mask = (u32) get_irq_data(irq);
__raw_writel(mask, &g->clr_falling);
__raw_writel(mask, &g->clr_rising);
@@ -180,7 +180,7 @@ static void gpio_irq_disable(unsigned irq)
static void gpio_irq_enable(unsigned irq)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
- u32 mask = __gpio_mask(irq_to_gpio(irq));
+ u32 mask = (u32) get_irq_data(irq);
unsigned status = irq_desc[irq].status;
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
@@ -196,7 +196,7 @@ static void gpio_irq_enable(unsigned irq)
static int gpio_irq_type(unsigned irq, unsigned trigger)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
- u32 mask = __gpio_mask(irq_to_gpio(irq));
+ u32 mask = (u32) get_irq_data(irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
@@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
/* now it may re-trigger */
}
+static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+
+ if (d->irq_base >= 0)
+ return d->irq_base + offset;
+ else
+ return -ENODEV;
+}
+
+static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ /* NOTE: we assume for now that only irqs in the first gpio_chip
+ * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
+ */
+ if (offset < soc_info->gpio_unbanked)
+ return soc_info->gpio_irq + offset;
+ else
+ return -ENODEV;
+}
+
+static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
+{
+ struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ u32 mask = (u32) get_irq_data(irq);
+
+ if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+ return -EINVAL;
+
+ __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+ ? &g->set_falling : &g->clr_falling);
+ __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+ ? &g->set_rising : &g->clr_rising);
+
+ return 0;
+}
+
/*
* NOTE: for suspend/resume, probably best to make a platform_device with
* suspend_late/resume_resume calls hooking into results of the set_wake()
@@ -275,6 +314,7 @@ static int __init davinci_gpio_irq_setup(void)
u32 binten = 0;
unsigned ngpio, bank_irq;
struct davinci_soc_info *soc_info = &davinci_soc_info;
+ struct gpio_controller *__iomem g;
ngpio = soc_info->gpio_num;
@@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup(void)
}
clk_enable(clk);
+ /* Arrange gpio_to_irq() support, handling either direct IRQs or
+ * banked IRQs. Having GPIOs in the first GPIO bank use direct
+ * IRQs, while the others use banked IRQs, would need some setup
+ * tweaks to recognize hardware which can do that.
+ */
+ for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
+ chips[bank].chip.to_irq = gpio_to_irq_banked;
+ chips[bank].irq_base = soc_info->gpio_unbanked
+ ? -EINVAL
+ : (soc_info->intc_irq_num + gpio);
+ }
+
+ /*
+ * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
+ * controller only handling trigger modes. We currently assume no
+ * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
+ */
+ if (soc_info->gpio_unbanked) {
+ static struct irq_chip gpio_irqchip_unbanked;
+
+ /* pass "bank 0" GPIO IRQs to AINTC */
+ chips[0].chip.to_irq = gpio_to_irq_unbanked;
+ binten = BIT(0);
+
+ /* AINTC handles mask/unmask; GPIO handles triggering */
+ irq = bank_irq;
+ gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq));
+ gpio_irqchip_unbanked.name = "GPIO-AINTC";
+ gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;
+
+ /* default trigger: both edges */
+ g = gpio2controller(0);
+ __raw_writel(~0, &g->set_falling);
+ __raw_writel(~0, &g->set_rising);
+
+ /* set the direct IRQs up to use that irqchip */
+ for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
+ set_irq_chip(irq, &gpio_irqchip_unbanked);
+ set_irq_data(irq, (void *) __gpio_mask(gpio));
+ set_irq_chip_data(irq, g);
+ irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
+ * then chain through our own handler.
+ */
for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
gpio < ngpio;
bank++, bank_irq++) {
- struct gpio_controller *__iomem g = gpio2controller(gpio);
unsigned i;
+ /* disabled by default, enabled only as needed */
+ g = gpio2controller(gpio);
__raw_writel(~0, &g->clr_falling);
__raw_writel(~0, &g->clr_rising);
@@ -309,6 +400,7 @@ static int __init davinci_gpio_irq_setup(void)
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
set_irq_chip(irq, &gpio_irqchip);
set_irq_chip_data(irq, g);
+ set_irq_data(irq, (void *) __gpio_mask(gpio));
set_irq_handler(irq, handle_simple_irq);
set_irq_flags(irq, IRQF_VALID);
}
@@ -316,6 +408,7 @@ static int __init davinci_gpio_irq_setup(void)
binten |= BIT(bank);
}
+done:
/* BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set/cleared dynamically.
*/
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
index e0abc437d796..cdf1f4442330 100644
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ b/arch/arm/mach-davinci/include/mach/asp.h
@@ -5,21 +5,51 @@
#define __ASM_ARCH_DAVINCI_ASP_H
#include <mach/irqs.h>
+#include <mach/edma.h>
-/* Bases of register banks */
+/* Bases of dm644x and dm355 register banks */
#define DAVINCI_ASP0_BASE 0x01E02000
#define DAVINCI_ASP1_BASE 0x01E04000
-/* EDMA channels */
+/* Bases of dm646x register banks */
+#define DAVINCI_DM646X_MCASP0_REG_BASE 0x01D01000
+#define DAVINCI_DM646X_MCASP1_REG_BASE 0x01D01800
+
+/* EDMA channels of dm644x and dm355 */
#define DAVINCI_DMA_ASP0_TX 2
#define DAVINCI_DMA_ASP0_RX 3
#define DAVINCI_DMA_ASP1_TX 8
#define DAVINCI_DMA_ASP1_RX 9
+/* EDMA channels of dm646x */
+#define DAVINCI_DM646X_DMA_MCASP0_AXEVT0 6
+#define DAVINCI_DM646X_DMA_MCASP0_AREVT0 9
+#define DAVINCI_DM646X_DMA_MCASP1_AXEVT1 12
+
/* Interrupts */
#define DAVINCI_ASP0_RX_INT IRQ_MBRINT
#define DAVINCI_ASP0_TX_INT IRQ_MBXINT
#define DAVINCI_ASP1_RX_INT IRQ_MBRINT
#define DAVINCI_ASP1_TX_INT IRQ_MBXINT
+struct snd_platform_data {
+ u32 tx_dma_offset;
+ u32 rx_dma_offset;
+ enum dma_event_q eventq_no; /* event queue number */
+ unsigned int codec_fmt;
+
+ /* McASP specific fields */
+ int tdm_slots;
+ u8 op_mode;
+ u8 num_serializer;
+ u8 *serial_dir;
+};
+
+#define INACTIVE_MODE 0
+#define TX_MODE 1
+#define RX_MODE 2
+
+#define DAVINCI_MCASP_IIS_MODE 0
+#define DAVINCI_MCASP_DIT_MODE 1
+
#endif /* __ASM_ARCH_DAVINCI_ASP_H */
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index a1f03b606d8f..1fd3917cae4e 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -60,10 +60,10 @@ struct davinci_soc_info {
u8 *intc_irq_prios;
unsigned long intc_irq_num;
struct davinci_timer_info *timer_info;
- void __iomem *wdt_base;
void __iomem *gpio_base;
unsigned gpio_num;
unsigned gpio_irq;
+ unsigned gpio_unbanked;
struct platform_device *serial_dev;
struct emac_platform_data *emac_pdata;
dma_addr_t sram_dma;
diff --git a/arch/arm/mach-davinci/include/mach/cputype.h b/arch/arm/mach-davinci/include/mach/cputype.h
index d12a5ed2959a..189b1ff13642 100644
--- a/arch/arm/mach-davinci/include/mach/cputype.h
+++ b/arch/arm/mach-davinci/include/mach/cputype.h
@@ -30,6 +30,9 @@ struct davinci_id {
#define DAVINCI_CPU_ID_DM6446 0x64460000
#define DAVINCI_CPU_ID_DM6467 0x64670000
#define DAVINCI_CPU_ID_DM355 0x03550000
+#define DAVINCI_CPU_ID_DM365 0x03650000
+#define DAVINCI_CPU_ID_DA830 0x08300000
+#define DAVINCI_CPU_ID_DA850 0x08500000
#define IS_DAVINCI_CPU(type, id) \
static inline int is_davinci_ ##type(void) \
@@ -40,6 +43,9 @@ static inline int is_davinci_ ##type(void) \
IS_DAVINCI_CPU(dm644x, DAVINCI_CPU_ID_DM6446)
IS_DAVINCI_CPU(dm646x, DAVINCI_CPU_ID_DM6467)
IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355)
+IS_DAVINCI_CPU(dm365, DAVINCI_CPU_ID_DM365)
+IS_DAVINCI_CPU(da830, DAVINCI_CPU_ID_DA830)
+IS_DAVINCI_CPU(da850, DAVINCI_CPU_ID_DA850)
#ifdef CONFIG_ARCH_DAVINCI_DM644x
#define cpu_is_davinci_dm644x() is_davinci_dm644x()
@@ -59,4 +65,22 @@ IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355)
#define cpu_is_davinci_dm355() 0
#endif
+#ifdef CONFIG_ARCH_DAVINCI_DM365
+#define cpu_is_davinci_dm365() is_davinci_dm365()
+#else
+#define cpu_is_davinci_dm365() 0
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI_DA830
+#define cpu_is_davinci_da830() is_davinci_da830()
+#else
+#define cpu_is_davinci_da830() 0
+#endif
+
+#ifdef CONFIG_ARCH_DAVINCI_DA850
+#define cpu_is_davinci_da850() is_davinci_da850()
+#else
+#define cpu_is_davinci_da850() 0
+#endif
+
#endif
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
new file mode 100644
index 000000000000..a8cb5709848d
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -0,0 +1,106 @@
+/*
+ * Chip specific defines for DA8XX/OMAP L1XX SoC
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2007, 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ASM_ARCH_DAVINCI_DA8XX_H
+#define __ASM_ARCH_DAVINCI_DA8XX_H
+
+#include <mach/serial.h>
+#include <mach/edma.h>
+#include <mach/i2c.h>
+#include <mach/emac.h>
+
+/*
+ * The cp_intc interrupt controller for the da8xx isn't in the same
+ * chunk of physical memory space as the other registers (like it is
+ * on the davincis) so it needs to be mapped separately. It will be
+ * mapped early on when the I/O space is mapped and we'll put it just
+ * before the I/O space in the processor's virtual memory space.
+ */
+#define DA8XX_CP_INTC_BASE 0xfffee000
+#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_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
+#define DA8XX_PSC1_BASE 0x01e27000
+
+#define PINMUX0 0x00
+#define PINMUX1 0x04
+#define PINMUX2 0x08
+#define PINMUX3 0x0c
+#define PINMUX4 0x10
+#define PINMUX5 0x14
+#define PINMUX6 0x18
+#define PINMUX7 0x1c
+#define PINMUX8 0x20
+#define PINMUX9 0x24
+#define PINMUX10 0x28
+#define PINMUX11 0x2c
+#define PINMUX12 0x30
+#define PINMUX13 0x34
+#define PINMUX14 0x38
+#define PINMUX15 0x3c
+#define PINMUX16 0x40
+#define PINMUX17 0x44
+#define PINMUX18 0x48
+#define PINMUX19 0x4c
+
+void __init da830_init(void);
+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_emac(void);
+
+extern struct platform_device da8xx_serial_device;
+extern struct emac_platform_data da8xx_emac_pdata;
+
+extern const short da830_emif25_pins[];
+extern const short da830_spi0_pins[];
+extern const short da830_spi1_pins[];
+extern const short da830_mmc_sd_pins[];
+extern const short da830_uart0_pins[];
+extern const short da830_uart1_pins[];
+extern const short da830_uart2_pins[];
+extern const short da830_usb20_pins[];
+extern const short da830_usb11_pins[];
+extern const short da830_uhpi_pins[];
+extern const short da830_cpgmac_pins[];
+extern const short da830_emif3c_pins[];
+extern const short da830_mcasp0_pins[];
+extern const short da830_mcasp1_pins[];
+extern const short da830_mcasp2_pins[];
+extern const short da830_i2c0_pins[];
+extern const short da830_i2c1_pins[];
+extern const short da830_lcdcntl_pins[];
+extern const short da830_pwm_pins[];
+extern const short da830_ecap0_pins[];
+extern const short da830_ecap1_pins[];
+extern const short da830_ecap2_pins[];
+extern const short da830_eqep0_pins[];
+extern const short da830_eqep1_pins[];
+
+extern const short da850_uart0_pins[];
+extern const short da850_uart1_pins[];
+extern const short da850_uart2_pins[];
+extern const short da850_i2c0_pins[];
+extern const short da850_i2c1_pins[];
+extern const short da850_cpgmac_pins[];
+
+int da8xx_pinmux_setup(const short pins[]);
+
+#endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S
index de3fc2182b47..17ab5236da66 100644
--- a/arch/arm/mach-davinci/include/mach/debug-macro.S
+++ b/arch/arm/mach-davinci/include/mach/debug-macro.S
@@ -24,7 +24,15 @@
tst \rx, #1 @ MMU enabled?
moveq \rx, #0x01000000 @ physical base address
movne \rx, #0xfe000000 @ virtual base
+#if defined(CONFIG_ARCH_DAVINCI_DA8XX) && defined(CONFIG_ARCH_DAVINCI_DMx)
+#error Cannot enable DaVinci and DA8XX platforms concurrently
+#elif defined(CONFIG_MACH_DAVINCI_DA830_EVM) || \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM)
+ orr \rx, \rx, #0x00d00000 @ physical base address
+ orr \rx, \rx, #0x0000d000 @ of UART 2
+#else
orr \rx, \rx, #0x00c20000 @ UART 0
+#endif
.endm
.macro senduart,rd,rx
diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h
index 54903b72438e..85536d8e8336 100644
--- a/arch/arm/mach-davinci/include/mach/dm355.h
+++ b/arch/arm/mach-davinci/include/mach/dm355.h
@@ -12,11 +12,18 @@
#define __ASM_ARCH_DM355_H
#include <mach/hardware.h>
+#include <mach/asp.h>
+#include <media/davinci/vpfe_capture.h>
+
+#define ASP1_TX_EVT_EN 1
+#define ASP1_RX_EVT_EN 2
struct spi_board_info;
void __init dm355_init(void);
void dm355_init_spi0(unsigned chipselect_mask,
struct spi_board_info *info, unsigned len);
+void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
+void dm355_set_vpfe_config(struct vpfe_config *cfg);
#endif /* __ASM_ARCH_DM355_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
new file mode 100644
index 000000000000..09db4343bb4c
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * This program is free software; 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 __ASM_ARCH_DM365_H
+#define __ASM_ARCH_DM665_H
+
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <mach/emac.h>
+
+#define DM365_EMAC_BASE (0x01D07000)
+#define DM365_EMAC_CNTRL_OFFSET (0x0000)
+#define DM365_EMAC_CNTRL_MOD_OFFSET (0x3000)
+#define DM365_EMAC_CNTRL_RAM_OFFSET (0x1000)
+#define DM365_EMAC_MDIO_OFFSET (0x4000)
+#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
+
+void __init dm365_init(void);
+
+#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 15d42b92a8c9..0efb73852c2c 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -25,6 +25,8 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
+#include <mach/asp.h>
+#include <media/davinci/vpfe_capture.h>
#define DM644X_EMAC_BASE (0x01C80000)
#define DM644X_EMAC_CNTRL_OFFSET (0x0000)
@@ -34,5 +36,7 @@
#define DM644X_EMAC_CNTRL_RAM_SIZE (0x2000)
void __init dm644x_init(void);
+void __init dm644x_init_asp(struct snd_platform_data *pdata);
+void dm644x_set_vpfe_config(struct vpfe_config *cfg);
#endif /* __ASM_ARCH_DM644X_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
index 1fc764c8646e..4ecfec479c30 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -13,6 +13,7 @@
#include <mach/hardware.h>
#include <mach/emac.h>
+#include <mach/asp.h>
#define DM646X_EMAC_BASE (0x01C80000)
#define DM646X_EMAC_CNTRL_OFFSET (0x0000)
@@ -21,6 +22,35 @@
#define DM646X_EMAC_MDIO_OFFSET (0x4000)
#define DM646X_EMAC_CNTRL_RAM_SIZE (0x2000)
+#define DM646X_ATA_REG_BASE (0x01C66000)
+
void __init dm646x_init(void);
+void __init dm646x_init_ide(void);
+void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
+void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+
+void dm646x_video_init(void);
+
+struct vpif_output {
+ u16 id;
+ const char *name;
+};
+
+struct subdev_info {
+ unsigned short addr;
+ const char *name;
+};
+
+struct vpif_config {
+ int (*set_clock)(int, int);
+ const struct subdev_info *subdevinfo;
+ int subdev_count;
+ const char **output;
+ int output_count;
+ const char *card_name;
+};
+
+
+void dm646x_setup_vpif(struct vpif_config *config);
#endif /* __ASM_ARCH_DM646X_H */
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index 24a379239d7f..a85cbedc9b0a 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -139,6 +139,54 @@ struct edmacc_param {
#define DAVINCI_DMA_PWM1 53
#define DAVINCI_DMA_PWM2 54
+/* DA830 specific EDMA3 information */
+#define EDMA_DA830_NUM_DMACH 32
+#define EDMA_DA830_NUM_TCC 32
+#define EDMA_DA830_NUM_PARAMENTRY 128
+#define EDMA_DA830_NUM_EVQUE 2
+#define EDMA_DA830_NUM_TC 2
+#define EDMA_DA830_CHMAP_EXIST 0
+#define EDMA_DA830_NUM_REGIONS 4
+#define DA830_DMACH2EVENT_MAP0 0x000FC03Fu
+#define DA830_DMACH2EVENT_MAP1 0x00000000u
+#define DA830_EDMA_ARM_OWN 0x30FFCCFFu
+
+/* DA830 specific EDMA3 Events Information */
+enum DA830_edma_ch {
+ DA830_DMACH_MCASP0_RX,
+ DA830_DMACH_MCASP0_TX,
+ DA830_DMACH_MCASP1_RX,
+ DA830_DMACH_MCASP1_TX,
+ DA830_DMACH_MCASP2_RX,
+ DA830_DMACH_MCASP2_TX,
+ DA830_DMACH_GPIO_BNK0INT,
+ DA830_DMACH_GPIO_BNK1INT,
+ DA830_DMACH_UART0_RX,
+ DA830_DMACH_UART0_TX,
+ DA830_DMACH_TMR64P0_EVTOUT12,
+ DA830_DMACH_TMR64P0_EVTOUT34,
+ DA830_DMACH_UART1_RX,
+ DA830_DMACH_UART1_TX,
+ DA830_DMACH_SPI0_RX,
+ DA830_DMACH_SPI0_TX,
+ DA830_DMACH_MMCSD_RX,
+ DA830_DMACH_MMCSD_TX,
+ DA830_DMACH_SPI1_RX,
+ DA830_DMACH_SPI1_TX,
+ DA830_DMACH_DMAX_EVTOUT6,
+ DA830_DMACH_DMAX_EVTOUT7,
+ DA830_DMACH_GPIO_BNK2INT,
+ DA830_DMACH_GPIO_BNK3INT,
+ DA830_DMACH_I2C0_RX,
+ DA830_DMACH_I2C0_TX,
+ DA830_DMACH_I2C1_RX,
+ DA830_DMACH_I2C1_TX,
+ DA830_DMACH_GPIO_BNK4INT,
+ DA830_DMACH_GPIO_BNK5INT,
+ DA830_DMACH_UART2_RX,
+ DA830_DMACH_UART2_TX
+};
+
/*ch_status paramater of callback function possible values*/
#define DMA_COMPLETE 1
#define DMA_CC_ERROR 2
@@ -170,6 +218,10 @@ enum sync_dimension {
ABSYNC = 1
};
+#define EDMA_CTLR_CHAN(ctlr, chan) (((ctlr) << 16) | (chan))
+#define EDMA_CTLR(i) ((i) >> 16)
+#define EDMA_CHAN_SLOT(i) ((i) & 0xffff)
+
#define EDMA_CHANNEL_ANY -1 /* for edma_alloc_channel() */
#define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */
@@ -180,7 +232,7 @@ int edma_alloc_channel(int channel,
void edma_free_channel(unsigned channel);
/* alloc/free parameter RAM slots */
-int edma_alloc_slot(int slot);
+int edma_alloc_slot(unsigned ctlr, int slot);
void edma_free_slot(unsigned slot);
/* calls that operate on part of a parameter RAM slot */
@@ -216,9 +268,12 @@ struct edma_soc_info {
unsigned n_region;
unsigned n_slot;
unsigned n_tc;
+ unsigned n_cc;
/* list of channels with no even trigger; terminated by "-1" */
const s8 *noevent;
+ const s8 (*queue_tc_mapping)[2];
+ const s8 (*queue_priority_mapping)[2];
};
#endif
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index ae0745568316..ebcc29babeae 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio)
{
- if (gpio >= DAVINCI_N_GPIO)
- return -EINVAL;
- return davinci_soc_info.intc_irq_num + gpio;
+ return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned irq)
{
- /* caller guarantees gpio_to_irq() succeeded */
- return irq - davinci_soc_info.intc_irq_num;
+ /* don't support the reverse mapping */
+ return -ENOSYS;
}
#endif /* __DAVINCI_GPIO_H */
diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h
index 48c77934d519..41c89386e39b 100644
--- a/arch/arm/mach-davinci/include/mach/hardware.h
+++ b/arch/arm/mach-davinci/include/mach/hardware.h
@@ -24,4 +24,21 @@
/* System control register offsets */
#define DM64XX_VDD3P3V_PWDN 0x48
+/*
+ * I/O mapping
+ */
+#define IO_PHYS 0x01c00000
+#define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */
+#define IO_SIZE 0x00400000
+#define IO_VIRT (IO_PHYS + IO_OFFSET)
+#define io_v2p(va) ((va) - IO_OFFSET)
+#define __IO_ADDRESS(x) ((x) + IO_OFFSET)
+#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x) x
+#else
+#define IOMEM(x) ((void __force __iomem *)(x))
+#endif
+
#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-davinci/include/mach/io.h b/arch/arm/mach-davinci/include/mach/io.h
index 2479785405af..62b0a90309ad 100644
--- a/arch/arm/mach-davinci/include/mach/io.h
+++ b/arch/arm/mach-davinci/include/mach/io.h
@@ -14,18 +14,6 @@
#define IO_SPACE_LIMIT 0xffffffff
/*
- * ----------------------------------------------------------------------------
- * I/O mapping
- * ----------------------------------------------------------------------------
- */
-#define IO_PHYS 0x01c00000
-#define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */
-#define IO_SIZE 0x00400000
-#define IO_VIRT (IO_PHYS + IO_OFFSET)
-#define io_v2p(va) ((va) - IO_OFFSET)
-#define __IO_ADDRESS(x) ((x) + IO_OFFSET)
-
-/*
* We don't actually have real ISA nor PCI buses, but there is so many
* drivers out there that might just work if we fake them...
*/
@@ -33,19 +21,12 @@
#define __mem_pci(a) (a)
#define __mem_isa(a) (a)
-#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
-
-#ifdef __ASSEMBLER__
-#define IOMEM(x) x
-#else
-#define IOMEM(x) ((void __force __iomem *)(x))
-
+#ifndef __ASSEMBLER__
#define __arch_ioremap(p, s, t) davinci_ioremap(p, s, t)
#define __arch_iounmap(v) davinci_iounmap(v)
void __iomem *davinci_ioremap(unsigned long phys, size_t size,
unsigned int type);
void davinci_iounmap(volatile void __iomem *addr);
-
-#endif /* __ASSEMBLER__ */
+#endif
#endif /* __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h
index bc5d6aaa69a3..6047c2d9da33 100644
--- a/arch/arm/mach-davinci/include/mach/irqs.h
+++ b/arch/arm/mach-davinci/include/mach/irqs.h
@@ -99,9 +99,6 @@
#define IRQ_EMUINT 63
#define DAVINCI_N_AINTC_IRQ 64
-#define DAVINCI_N_GPIO 104
-
-#define NR_IRQS (DAVINCI_N_AINTC_IRQ + DAVINCI_N_GPIO)
#define ARCH_TIMER_IRQ IRQ_TINT1_TINT34
@@ -206,4 +203,203 @@
#define IRQ_DM355_GPIOBNK5 59
#define IRQ_DM355_GPIOBNK6 60
+/* DaVinci DM365-specific Interrupts */
+#define IRQ_DM365_INSFINT 7
+#define IRQ_DM365_IMCOPINT 11
+#define IRQ_DM365_RTOINT 13
+#define IRQ_DM365_TINT5 14
+#define IRQ_DM365_TINT6 15
+#define IRQ_DM365_SPINT2_1 21
+#define IRQ_DM365_TINT7 22
+#define IRQ_DM365_SDIOINT0 23
+#define IRQ_DM365_MMCINT1 27
+#define IRQ_DM365_PWMINT3 28
+#define IRQ_DM365_SDIOINT1 31
+#define IRQ_DM365_SPIINT0_0 42
+#define IRQ_DM365_SPIINT3_0 43
+#define IRQ_DM365_GPIO0 44
+#define IRQ_DM365_GPIO1 45
+#define IRQ_DM365_GPIO2 46
+#define IRQ_DM365_GPIO3 47
+#define IRQ_DM365_GPIO4 48
+#define IRQ_DM365_GPIO5 49
+#define IRQ_DM365_GPIO6 50
+#define IRQ_DM365_GPIO7 51
+#define IRQ_DM365_EMAC_RXTHRESH 52
+#define IRQ_DM365_EMAC_RXPULSE 53
+#define IRQ_DM365_EMAC_TXPULSE 54
+#define IRQ_DM365_EMAC_MISCPULSE 55
+#define IRQ_DM365_GPIO12 56
+#define IRQ_DM365_GPIO13 57
+#define IRQ_DM365_GPIO14 58
+#define IRQ_DM365_GPIO15 59
+#define IRQ_DM365_ADCINT 59
+#define IRQ_DM365_KEYINT 60
+#define IRQ_DM365_TCERRINT2 61
+#define IRQ_DM365_TCERRINT3 62
+#define IRQ_DM365_EMUINT 63
+
+/* DA8XX interrupts */
+#define IRQ_DA8XX_COMMTX 0
+#define IRQ_DA8XX_COMMRX 1
+#define IRQ_DA8XX_NINT 2
+#define IRQ_DA8XX_EVTOUT0 3
+#define IRQ_DA8XX_EVTOUT1 4
+#define IRQ_DA8XX_EVTOUT2 5
+#define IRQ_DA8XX_EVTOUT3 6
+#define IRQ_DA8XX_EVTOUT4 7
+#define IRQ_DA8XX_EVTOUT5 8
+#define IRQ_DA8XX_EVTOUT6 9
+#define IRQ_DA8XX_EVTOUT7 10
+#define IRQ_DA8XX_CCINT0 11
+#define IRQ_DA8XX_CCERRINT 12
+#define IRQ_DA8XX_TCERRINT0 13
+#define IRQ_DA8XX_AEMIFINT 14
+#define IRQ_DA8XX_I2CINT0 15
+#define IRQ_DA8XX_MMCSDINT0 16
+#define IRQ_DA8XX_MMCSDINT1 17
+#define IRQ_DA8XX_ALLINT0 18
+#define IRQ_DA8XX_RTC 19
+#define IRQ_DA8XX_SPINT0 20
+#define IRQ_DA8XX_TINT12_0 21
+#define IRQ_DA8XX_TINT34_0 22
+#define IRQ_DA8XX_TINT12_1 23
+#define IRQ_DA8XX_TINT34_1 24
+#define IRQ_DA8XX_UARTINT0 25
+#define IRQ_DA8XX_KEYMGRINT 26
+#define IRQ_DA8XX_SECINT 26
+#define IRQ_DA8XX_SECKEYERR 26
+#define IRQ_DA8XX_CHIPINT0 28
+#define IRQ_DA8XX_CHIPINT1 29
+#define IRQ_DA8XX_CHIPINT2 30
+#define IRQ_DA8XX_CHIPINT3 31
+#define IRQ_DA8XX_TCERRINT1 32
+#define IRQ_DA8XX_C0_RX_THRESH_PULSE 33
+#define IRQ_DA8XX_C0_RX_PULSE 34
+#define IRQ_DA8XX_C0_TX_PULSE 35
+#define IRQ_DA8XX_C0_MISC_PULSE 36
+#define IRQ_DA8XX_C1_RX_THRESH_PULSE 37
+#define IRQ_DA8XX_C1_RX_PULSE 38
+#define IRQ_DA8XX_C1_TX_PULSE 39
+#define IRQ_DA8XX_C1_MISC_PULSE 40
+#define IRQ_DA8XX_MEMERR 41
+#define IRQ_DA8XX_GPIO0 42
+#define IRQ_DA8XX_GPIO1 43
+#define IRQ_DA8XX_GPIO2 44
+#define IRQ_DA8XX_GPIO3 45
+#define IRQ_DA8XX_GPIO4 46
+#define IRQ_DA8XX_GPIO5 47
+#define IRQ_DA8XX_GPIO6 48
+#define IRQ_DA8XX_GPIO7 49
+#define IRQ_DA8XX_GPIO8 50
+#define IRQ_DA8XX_I2CINT1 51
+#define IRQ_DA8XX_LCDINT 52
+#define IRQ_DA8XX_UARTINT1 53
+#define IRQ_DA8XX_MCASPINT 54
+#define IRQ_DA8XX_ALLINT1 55
+#define IRQ_DA8XX_SPINT1 56
+#define IRQ_DA8XX_UHPI_INT1 57
+#define IRQ_DA8XX_USB_INT 58
+#define IRQ_DA8XX_IRQN 59
+#define IRQ_DA8XX_RWAKEUP 60
+#define IRQ_DA8XX_UARTINT2 61
+#define IRQ_DA8XX_DFTSSINT 62
+#define IRQ_DA8XX_EHRPWM0 63
+#define IRQ_DA8XX_EHRPWM0TZ 64
+#define IRQ_DA8XX_EHRPWM1 65
+#define IRQ_DA8XX_EHRPWM1TZ 66
+#define IRQ_DA8XX_ECAP0 69
+#define IRQ_DA8XX_ECAP1 70
+#define IRQ_DA8XX_ECAP2 71
+#define IRQ_DA8XX_ARMCLKSTOPREQ 90
+
+/* DA830 specific interrupts */
+#define IRQ_DA830_MPUERR 27
+#define IRQ_DA830_IOPUERR 27
+#define IRQ_DA830_BOOTCFGERR 27
+#define IRQ_DA830_EHRPWM2 67
+#define IRQ_DA830_EHRPWM2TZ 68
+#define IRQ_DA830_EQEP0 72
+#define IRQ_DA830_EQEP1 73
+#define IRQ_DA830_T12CMPINT0_0 74
+#define IRQ_DA830_T12CMPINT1_0 75
+#define IRQ_DA830_T12CMPINT2_0 76
+#define IRQ_DA830_T12CMPINT3_0 77
+#define IRQ_DA830_T12CMPINT4_0 78
+#define IRQ_DA830_T12CMPINT5_0 79
+#define IRQ_DA830_T12CMPINT6_0 80
+#define IRQ_DA830_T12CMPINT7_0 81
+#define IRQ_DA830_T12CMPINT0_1 82
+#define IRQ_DA830_T12CMPINT1_1 83
+#define IRQ_DA830_T12CMPINT2_1 84
+#define IRQ_DA830_T12CMPINT3_1 85
+#define IRQ_DA830_T12CMPINT4_1 86
+#define IRQ_DA830_T12CMPINT5_1 87
+#define IRQ_DA830_T12CMPINT6_1 88
+#define IRQ_DA830_T12CMPINT7_1 89
+
+#define DA830_N_CP_INTC_IRQ 96
+
+/* DA850 speicific interrupts */
+#define IRQ_DA850_MPUADDRERR0 27
+#define IRQ_DA850_MPUPROTERR0 27
+#define IRQ_DA850_IOPUADDRERR0 27
+#define IRQ_DA850_IOPUPROTERR0 27
+#define IRQ_DA850_IOPUADDRERR1 27
+#define IRQ_DA850_IOPUPROTERR1 27
+#define IRQ_DA850_IOPUADDRERR2 27
+#define IRQ_DA850_IOPUPROTERR2 27
+#define IRQ_DA850_BOOTCFG_ADDR_ERR 27
+#define IRQ_DA850_BOOTCFG_PROT_ERR 27
+#define IRQ_DA850_MPUADDRERR1 27
+#define IRQ_DA850_MPUPROTERR1 27
+#define IRQ_DA850_IOPUADDRERR3 27
+#define IRQ_DA850_IOPUPROTERR3 27
+#define IRQ_DA850_IOPUADDRERR4 27
+#define IRQ_DA850_IOPUPROTERR4 27
+#define IRQ_DA850_IOPUADDRERR5 27
+#define IRQ_DA850_IOPUPROTERR5 27
+#define IRQ_DA850_MIOPU_BOOTCFG_ERR 27
+#define IRQ_DA850_SATAINT 67
+#define IRQ_DA850_TINT12_2 68
+#define IRQ_DA850_TINT34_2 68
+#define IRQ_DA850_TINTALL_2 68
+#define IRQ_DA850_MMCSDINT0_1 72
+#define IRQ_DA850_MMCSDINT1_1 73
+#define IRQ_DA850_T12CMPINT0_2 74
+#define IRQ_DA850_T12CMPINT1_2 75
+#define IRQ_DA850_T12CMPINT2_2 76
+#define IRQ_DA850_T12CMPINT3_2 77
+#define IRQ_DA850_T12CMPINT4_2 78
+#define IRQ_DA850_T12CMPINT5_2 79
+#define IRQ_DA850_T12CMPINT6_2 80
+#define IRQ_DA850_T12CMPINT7_2 81
+#define IRQ_DA850_T12CMPINT0_3 82
+#define IRQ_DA850_T12CMPINT1_3 83
+#define IRQ_DA850_T12CMPINT2_3 84
+#define IRQ_DA850_T12CMPINT3_3 85
+#define IRQ_DA850_T12CMPINT4_3 86
+#define IRQ_DA850_T12CMPINT5_3 87
+#define IRQ_DA850_T12CMPINT6_3 88
+#define IRQ_DA850_T12CMPINT7_3 89
+#define IRQ_DA850_RPIINT 91
+#define IRQ_DA850_VPIFINT 92
+#define IRQ_DA850_CCINT1 93
+#define IRQ_DA850_CCERRINT1 94
+#define IRQ_DA850_TCERRINT2 95
+#define IRQ_DA850_TINT12_3 96
+#define IRQ_DA850_TINT34_3 96
+#define IRQ_DA850_TINTALL_3 96
+#define IRQ_DA850_MCBSP0RINT 97
+#define IRQ_DA850_MCBSP0XINT 98
+#define IRQ_DA850_MCBSP1RINT 99
+#define IRQ_DA850_MCBSP1XINT 100
+
+#define DA850_N_CP_INTC_IRQ 101
+
+/* da830/da850 currently has the most gpio pins (128) */
+#define DAVINCI_N_GPIO 128
+/* da850 currently has the most irqs so use DA850_N_CP_INTC_IRQ */
+#define NR_IRQS (DA850_N_CP_INTC_IRQ + DAVINCI_N_GPIO)
+
#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h
index c712c7cdf38f..80309aed534a 100644
--- a/arch/arm/mach-davinci/include/mach/memory.h
+++ b/arch/arm/mach-davinci/include/mach/memory.h
@@ -20,9 +20,16 @@
/**************************************************************************
* Definitions
**************************************************************************/
-#define DAVINCI_DDR_BASE 0x80000000
+#define DAVINCI_DDR_BASE 0x80000000
+#define DA8XX_DDR_BASE 0xc0000000
+#if defined(CONFIG_ARCH_DAVINCI_DA8XX) && defined(CONFIG_ARCH_DAVINCI_DMx)
+#error Cannot enable DaVinci and DA8XX platforms concurrently
+#elif defined(CONFIG_ARCH_DAVINCI_DA8XX)
+#define PHYS_OFFSET DA8XX_DDR_BASE
+#else
#define PHYS_OFFSET DAVINCI_DDR_BASE
+#endif
/*
* Increase size of DMA-consistent memory region
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 27378458542f..d70cf4da1f51 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -154,6 +154,608 @@ enum davinci_dm355_index {
DM355_EVT8_ASP1_TX,
DM355_EVT9_ASP1_RX,
DM355_EVT26_MMC0_RX,
+
+ /* Video In Pin Mux */
+ DM355_VIN_PCLK,
+ DM355_VIN_CAM_WEN,
+ DM355_VIN_CAM_VD,
+ DM355_VIN_CAM_HD,
+ DM355_VIN_YIN_EN,
+ DM355_VIN_CINL_EN,
+ DM355_VIN_CINH_EN,
+};
+
+enum davinci_dm365_index {
+ /* MMC/SD 0 */
+ DM365_MMCSD0,
+
+ /* MMC/SD 1 */
+ DM365_SD1_CLK,
+ DM365_SD1_CMD,
+ DM365_SD1_DATA3,
+ DM365_SD1_DATA2,
+ DM365_SD1_DATA1,
+ DM365_SD1_DATA0,
+
+ /* I2C */
+ DM365_I2C_SDA,
+ DM365_I2C_SCL,
+
+ /* AEMIF */
+ DM365_AEMIF_AR,
+ DM365_AEMIF_A3,
+ DM365_AEMIF_A7,
+ DM365_AEMIF_D15_8,
+ DM365_AEMIF_CE0,
+
+ /* ASP0 function */
+ DM365_MCBSP0_BDX,
+ DM365_MCBSP0_X,
+ DM365_MCBSP0_BFSX,
+ DM365_MCBSP0_BDR,
+ DM365_MCBSP0_R,
+ DM365_MCBSP0_BFSR,
+
+ /* SPI0 */
+ DM365_SPI0_SCLK,
+ DM365_SPI0_SDI,
+ DM365_SPI0_SDO,
+ DM365_SPI0_SDENA0,
+ DM365_SPI0_SDENA1,
+
+ /* UART */
+ DM365_UART0_RXD,
+ DM365_UART0_TXD,
+ DM365_UART1_RXD,
+ DM365_UART1_TXD,
+ DM365_UART1_RTS,
+ DM365_UART1_CTS,
+
+ /* EMAC */
+ DM365_EMAC_TX_EN,
+ DM365_EMAC_TX_CLK,
+ DM365_EMAC_COL,
+ DM365_EMAC_TXD3,
+ DM365_EMAC_TXD2,
+ DM365_EMAC_TXD1,
+ DM365_EMAC_TXD0,
+ DM365_EMAC_RXD3,
+ DM365_EMAC_RXD2,
+ DM365_EMAC_RXD1,
+ DM365_EMAC_RXD0,
+ DM365_EMAC_RX_CLK,
+ DM365_EMAC_RX_DV,
+ DM365_EMAC_RX_ER,
+ DM365_EMAC_CRS,
+ DM365_EMAC_MDIO,
+ DM365_EMAC_MDCLK,
+
+ /* Keypad */
+ DM365_KEYPAD,
+
+ /* PWM */
+ DM365_PWM0,
+ DM365_PWM0_G23,
+ DM365_PWM1,
+ DM365_PWM1_G25,
+ DM365_PWM2_G87,
+ DM365_PWM2_G88,
+ DM365_PWM2_G89,
+ DM365_PWM2_G90,
+ DM365_PWM3_G80,
+ DM365_PWM3_G81,
+ DM365_PWM3_G85,
+ DM365_PWM3_G86,
+
+ /* SPI1 */
+ DM365_SPI1_SCLK,
+ DM365_SPI1_SDO,
+ DM365_SPI1_SDI,
+ DM365_SPI1_SDENA0,
+ DM365_SPI1_SDENA1,
+
+ /* SPI2 */
+ DM365_SPI2_SCLK,
+ DM365_SPI2_SDO,
+ DM365_SPI2_SDI,
+ DM365_SPI2_SDENA0,
+ DM365_SPI2_SDENA1,
+
+ /* SPI3 */
+ DM365_SPI3_SCLK,
+ DM365_SPI3_SDO,
+ DM365_SPI3_SDI,
+ DM365_SPI3_SDENA0,
+ DM365_SPI3_SDENA1,
+
+ /* SPI4 */
+ DM365_SPI4_SCLK,
+ DM365_SPI4_SDO,
+ DM365_SPI4_SDI,
+ DM365_SPI4_SDENA0,
+ DM365_SPI4_SDENA1,
+
+ /* GPIO */
+ DM365_GPIO20,
+ DM365_GPIO33,
+ DM365_GPIO40,
+
+ /* Video */
+ DM365_VOUT_FIELD,
+ DM365_VOUT_FIELD_G81,
+ DM365_VOUT_HVSYNC,
+ DM365_VOUT_COUTL_EN,
+ DM365_VOUT_COUTH_EN,
+ DM365_VIN_CAM_WEN,
+ DM365_VIN_CAM_VD,
+ DM365_VIN_CAM_HD,
+ DM365_VIN_YIN_EN,
+
+ /* IRQ muxing */
+ DM365_INT_EDMA_CC,
+ DM365_INT_EDMA_TC0_ERR,
+ DM365_INT_EDMA_TC1_ERR,
+ DM365_INT_EDMA_TC2_ERR,
+ DM365_INT_EDMA_TC3_ERR,
+ DM365_INT_PRTCSS,
+ DM365_INT_EMAC_RXTHRESH,
+ DM365_INT_EMAC_RXPULSE,
+ DM365_INT_EMAC_TXPULSE,
+ DM365_INT_EMAC_MISCPULSE,
+
+ /* EDMA event muxing */
+ DM365_EVT2_ASP_TX,
+ DM365_EVT3_ASP_RX,
+ DM365_EVT26_MMC0_RX,
+};
+
+enum da830_index {
+ DA830_GPIO7_14,
+ DA830_RTCK,
+ DA830_GPIO7_15,
+ DA830_EMU_0,
+ DA830_EMB_SDCKE,
+ DA830_EMB_CLK_GLUE,
+ DA830_EMB_CLK,
+ DA830_NEMB_CS_0,
+ DA830_NEMB_CAS,
+ DA830_NEMB_RAS,
+ DA830_NEMB_WE,
+ DA830_EMB_BA_1,
+ DA830_EMB_BA_0,
+ DA830_EMB_A_0,
+ DA830_EMB_A_1,
+ DA830_EMB_A_2,
+ DA830_EMB_A_3,
+ DA830_EMB_A_4,
+ DA830_EMB_A_5,
+ DA830_GPIO7_0,
+ DA830_GPIO7_1,
+ DA830_GPIO7_2,
+ DA830_GPIO7_3,
+ DA830_GPIO7_4,
+ DA830_GPIO7_5,
+ DA830_GPIO7_6,
+ DA830_GPIO7_7,
+ DA830_EMB_A_6,
+ DA830_EMB_A_7,
+ DA830_EMB_A_8,
+ DA830_EMB_A_9,
+ DA830_EMB_A_10,
+ DA830_EMB_A_11,
+ DA830_EMB_A_12,
+ DA830_EMB_D_31,
+ DA830_GPIO7_8,
+ DA830_GPIO7_9,
+ DA830_GPIO7_10,
+ DA830_GPIO7_11,
+ DA830_GPIO7_12,
+ DA830_GPIO7_13,
+ DA830_GPIO3_13,
+ DA830_EMB_D_30,
+ DA830_EMB_D_29,
+ DA830_EMB_D_28,
+ DA830_EMB_D_27,
+ DA830_EMB_D_26,
+ DA830_EMB_D_25,
+ DA830_EMB_D_24,
+ DA830_EMB_D_23,
+ DA830_EMB_D_22,
+ DA830_EMB_D_21,
+ DA830_EMB_D_20,
+ DA830_EMB_D_19,
+ DA830_EMB_D_18,
+ DA830_EMB_D_17,
+ DA830_EMB_D_16,
+ DA830_NEMB_WE_DQM_3,
+ DA830_NEMB_WE_DQM_2,
+ DA830_EMB_D_0,
+ DA830_EMB_D_1,
+ DA830_EMB_D_2,
+ DA830_EMB_D_3,
+ DA830_EMB_D_4,
+ DA830_EMB_D_5,
+ DA830_EMB_D_6,
+ DA830_GPIO6_0,
+ DA830_GPIO6_1,
+ DA830_GPIO6_2,
+ DA830_GPIO6_3,
+ DA830_GPIO6_4,
+ DA830_GPIO6_5,
+ DA830_GPIO6_6,
+ DA830_EMB_D_7,
+ DA830_EMB_D_8,
+ DA830_EMB_D_9,
+ DA830_EMB_D_10,
+ DA830_EMB_D_11,
+ DA830_EMB_D_12,
+ DA830_EMB_D_13,
+ DA830_EMB_D_14,
+ DA830_GPIO6_7,
+ DA830_GPIO6_8,
+ DA830_GPIO6_9,
+ DA830_GPIO6_10,
+ DA830_GPIO6_11,
+ DA830_GPIO6_12,
+ DA830_GPIO6_13,
+ DA830_GPIO6_14,
+ DA830_EMB_D_15,
+ DA830_NEMB_WE_DQM_1,
+ DA830_NEMB_WE_DQM_0,
+ DA830_SPI0_SOMI_0,
+ DA830_SPI0_SIMO_0,
+ DA830_SPI0_CLK,
+ DA830_NSPI0_ENA,
+ DA830_NSPI0_SCS_0,
+ DA830_EQEP0I,
+ DA830_EQEP0S,
+ DA830_EQEP1I,
+ DA830_NUART0_CTS,
+ DA830_NUART0_RTS,
+ DA830_EQEP0A,
+ DA830_EQEP0B,
+ DA830_GPIO6_15,
+ DA830_GPIO5_14,
+ DA830_GPIO5_15,
+ DA830_GPIO5_0,
+ DA830_GPIO5_1,
+ DA830_GPIO5_2,
+ DA830_GPIO5_3,
+ DA830_GPIO5_4,
+ DA830_SPI1_SOMI_0,
+ DA830_SPI1_SIMO_0,
+ DA830_SPI1_CLK,
+ DA830_UART0_RXD,
+ DA830_UART0_TXD,
+ DA830_AXR1_10,
+ DA830_AXR1_11,
+ DA830_NSPI1_ENA,
+ DA830_I2C1_SCL,
+ DA830_I2C1_SDA,
+ DA830_EQEP1S,
+ DA830_I2C0_SDA,
+ DA830_I2C0_SCL,
+ DA830_UART2_RXD,
+ DA830_TM64P0_IN12,
+ DA830_TM64P0_OUT12,
+ DA830_GPIO5_5,
+ DA830_GPIO5_6,
+ DA830_GPIO5_7,
+ DA830_GPIO5_8,
+ DA830_GPIO5_9,
+ DA830_GPIO5_10,
+ DA830_GPIO5_11,
+ DA830_GPIO5_12,
+ DA830_NSPI1_SCS_0,
+ DA830_USB0_DRVVBUS,
+ DA830_AHCLKX0,
+ DA830_ACLKX0,
+ DA830_AFSX0,
+ DA830_AHCLKR0,
+ DA830_ACLKR0,
+ DA830_AFSR0,
+ DA830_UART2_TXD,
+ DA830_AHCLKX2,
+ DA830_ECAP0_APWM0,
+ DA830_RMII_MHZ_50_CLK,
+ DA830_ECAP1_APWM1,
+ DA830_USB_REFCLKIN,
+ DA830_GPIO5_13,
+ DA830_GPIO4_15,
+ DA830_GPIO2_11,
+ DA830_GPIO2_12,
+ DA830_GPIO2_13,
+ DA830_GPIO2_14,
+ DA830_GPIO2_15,
+ DA830_GPIO3_12,
+ DA830_AMUTE0,
+ DA830_AXR0_0,
+ DA830_AXR0_1,
+ DA830_AXR0_2,
+ DA830_AXR0_3,
+ DA830_AXR0_4,
+ DA830_AXR0_5,
+ DA830_AXR0_6,
+ DA830_RMII_TXD_0,
+ DA830_RMII_TXD_1,
+ DA830_RMII_TXEN,
+ DA830_RMII_CRS_DV,
+ DA830_RMII_RXD_0,
+ DA830_RMII_RXD_1,
+ DA830_RMII_RXER,
+ DA830_AFSR2,
+ DA830_ACLKX2,
+ DA830_AXR2_3,
+ DA830_AXR2_2,
+ DA830_AXR2_1,
+ DA830_AFSX2,
+ DA830_ACLKR2,
+ DA830_NRESETOUT,
+ DA830_GPIO3_0,
+ DA830_GPIO3_1,
+ DA830_GPIO3_2,
+ DA830_GPIO3_3,
+ DA830_GPIO3_4,
+ DA830_GPIO3_5,
+ DA830_GPIO3_6,
+ DA830_AXR0_7,
+ DA830_AXR0_8,
+ DA830_UART1_RXD,
+ DA830_UART1_TXD,
+ DA830_AXR0_11,
+ DA830_AHCLKX1,
+ DA830_ACLKX1,
+ DA830_AFSX1,
+ DA830_MDIO_CLK,
+ DA830_MDIO_D,
+ DA830_AXR0_9,
+ DA830_AXR0_10,
+ DA830_EPWM0B,
+ DA830_EPWM0A,
+ DA830_EPWMSYNCI,
+ DA830_AXR2_0,
+ DA830_EPWMSYNC0,
+ DA830_GPIO3_7,
+ DA830_GPIO3_8,
+ DA830_GPIO3_9,
+ DA830_GPIO3_10,
+ DA830_GPIO3_11,
+ DA830_GPIO3_14,
+ DA830_GPIO3_15,
+ DA830_GPIO4_10,
+ DA830_AHCLKR1,
+ DA830_ACLKR1,
+ DA830_AFSR1,
+ DA830_AMUTE1,
+ DA830_AXR1_0,
+ DA830_AXR1_1,
+ DA830_AXR1_2,
+ DA830_AXR1_3,
+ DA830_ECAP2_APWM2,
+ DA830_EHRPWMGLUETZ,
+ DA830_EQEP1A,
+ DA830_GPIO4_11,
+ DA830_GPIO4_12,
+ DA830_GPIO4_13,
+ DA830_GPIO4_14,
+ DA830_GPIO4_0,
+ DA830_GPIO4_1,
+ DA830_GPIO4_2,
+ DA830_GPIO4_3,
+ DA830_AXR1_4,
+ DA830_AXR1_5,
+ DA830_AXR1_6,
+ DA830_AXR1_7,
+ DA830_AXR1_8,
+ DA830_AXR1_9,
+ DA830_EMA_D_0,
+ DA830_EMA_D_1,
+ DA830_EQEP1B,
+ DA830_EPWM2B,
+ DA830_EPWM2A,
+ DA830_EPWM1B,
+ DA830_EPWM1A,
+ DA830_MMCSD_DAT_0,
+ DA830_MMCSD_DAT_1,
+ DA830_UHPI_HD_0,
+ DA830_UHPI_HD_1,
+ DA830_GPIO4_4,
+ DA830_GPIO4_5,
+ DA830_GPIO4_6,
+ DA830_GPIO4_7,
+ DA830_GPIO4_8,
+ DA830_GPIO4_9,
+ DA830_GPIO0_0,
+ DA830_GPIO0_1,
+ DA830_EMA_D_2,
+ DA830_EMA_D_3,
+ DA830_EMA_D_4,
+ DA830_EMA_D_5,
+ DA830_EMA_D_6,
+ DA830_EMA_D_7,
+ DA830_EMA_D_8,
+ DA830_EMA_D_9,
+ 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_UHPI_HD_8,
+ DA830_UHPI_HD_9,
+ DA830_UHPI_HD_2,
+ DA830_UHPI_HD_3,
+ DA830_UHPI_HD_4,
+ DA830_UHPI_HD_5,
+ DA830_UHPI_HD_6,
+ DA830_UHPI_HD_7,
+ DA830_LCD_D_8,
+ DA830_LCD_D_9,
+ DA830_GPIO0_2,
+ DA830_GPIO0_3,
+ DA830_GPIO0_4,
+ DA830_GPIO0_5,
+ DA830_GPIO0_6,
+ DA830_GPIO0_7,
+ DA830_GPIO0_8,
+ DA830_GPIO0_9,
+ DA830_EMA_D_10,
+ DA830_EMA_D_11,
+ DA830_EMA_D_12,
+ DA830_EMA_D_13,
+ DA830_EMA_D_14,
+ DA830_EMA_D_15,
+ DA830_EMA_A_0,
+ DA830_EMA_A_1,
+ DA830_UHPI_HD_10,
+ DA830_UHPI_HD_11,
+ DA830_UHPI_HD_12,
+ DA830_UHPI_HD_13,
+ DA830_UHPI_HD_14,
+ DA830_UHPI_HD_15,
+ DA830_LCD_D_7,
+ DA830_MMCSD_CLK,
+ DA830_LCD_D_10,
+ DA830_LCD_D_11,
+ DA830_LCD_D_12,
+ DA830_LCD_D_13,
+ DA830_LCD_D_14,
+ DA830_LCD_D_15,
+ DA830_UHPI_HCNTL0,
+ DA830_GPIO0_10,
+ DA830_GPIO0_11,
+ DA830_GPIO0_12,
+ DA830_GPIO0_13,
+ DA830_GPIO0_14,
+ DA830_GPIO0_15,
+ DA830_GPIO1_0,
+ DA830_GPIO1_1,
+ DA830_EMA_A_2,
+ DA830_EMA_A_3,
+ DA830_EMA_A_4,
+ DA830_EMA_A_5,
+ DA830_EMA_A_6,
+ DA830_EMA_A_7,
+ DA830_EMA_A_8,
+ DA830_EMA_A_9,
+ DA830_MMCSD_CMD,
+ DA830_LCD_D_6,
+ DA830_LCD_D_3,
+ DA830_LCD_D_2,
+ DA830_LCD_D_1,
+ DA830_LCD_D_0,
+ DA830_LCD_PCLK,
+ DA830_LCD_HSYNC,
+ DA830_UHPI_HCNTL1,
+ DA830_GPIO1_2,
+ DA830_GPIO1_3,
+ DA830_GPIO1_4,
+ DA830_GPIO1_5,
+ DA830_GPIO1_6,
+ DA830_GPIO1_7,
+ DA830_GPIO1_8,
+ DA830_GPIO1_9,
+ DA830_EMA_A_10,
+ DA830_EMA_A_11,
+ DA830_EMA_A_12,
+ DA830_EMA_BA_1,
+ DA830_EMA_BA_0,
+ DA830_EMA_CLK,
+ DA830_EMA_SDCKE,
+ DA830_NEMA_CAS,
+ DA830_LCD_VSYNC,
+ DA830_NLCD_AC_ENB_CS,
+ DA830_LCD_MCLK,
+ DA830_LCD_D_5,
+ DA830_LCD_D_4,
+ DA830_OBSCLK,
+ DA830_NEMA_CS_4,
+ DA830_UHPI_HHWIL,
+ DA830_AHCLKR2,
+ DA830_GPIO1_10,
+ DA830_GPIO1_11,
+ DA830_GPIO1_12,
+ DA830_GPIO1_13,
+ DA830_GPIO1_14,
+ DA830_GPIO1_15,
+ DA830_GPIO2_0,
+ DA830_GPIO2_1,
+ DA830_NEMA_RAS,
+ DA830_NEMA_WE,
+ DA830_NEMA_CS_0,
+ DA830_NEMA_CS_2,
+ DA830_NEMA_CS_3,
+ DA830_NEMA_OE,
+ DA830_NEMA_WE_DQM_1,
+ DA830_NEMA_WE_DQM_0,
+ DA830_NEMA_CS_5,
+ DA830_UHPI_HRNW,
+ DA830_NUHPI_HAS,
+ DA830_NUHPI_HCS,
+ DA830_NUHPI_HDS1,
+ DA830_NUHPI_HDS2,
+ DA830_NUHPI_HINT,
+ DA830_AXR0_12,
+ DA830_AMUTE2,
+ DA830_AXR0_13,
+ DA830_AXR0_14,
+ DA830_AXR0_15,
+ DA830_GPIO2_2,
+ DA830_GPIO2_3,
+ DA830_GPIO2_4,
+ DA830_GPIO2_5,
+ DA830_GPIO2_6,
+ DA830_GPIO2_7,
+ DA830_GPIO2_8,
+ DA830_GPIO2_9,
+ DA830_EMA_WAIT_0,
+ DA830_NUHPI_HRDY,
+ DA830_GPIO2_10,
+};
+
+enum davinci_da850_index {
+ /* UART0 function */
+ DA850_NUART0_CTS,
+ DA850_NUART0_RTS,
+ DA850_UART0_RXD,
+ DA850_UART0_TXD,
+
+ /* UART1 function */
+ DA850_NUART1_CTS,
+ DA850_NUART1_RTS,
+ DA850_UART1_RXD,
+ DA850_UART1_TXD,
+
+ /* UART2 function */
+ DA850_NUART2_CTS,
+ DA850_NUART2_RTS,
+ DA850_UART2_RXD,
+ DA850_UART2_TXD,
+
+ /* I2C1 function */
+ DA850_I2C1_SCL,
+ DA850_I2C1_SDA,
+
+ /* I2C0 function */
+ DA850_I2C0_SDA,
+ DA850_I2C0_SCL,
+
+ /* EMAC function */
+ DA850_MII_TXEN,
+ DA850_MII_TXCLK,
+ DA850_MII_COL,
+ DA850_MII_TXD_3,
+ DA850_MII_TXD_2,
+ DA850_MII_TXD_1,
+ DA850_MII_TXD_0,
+ DA850_MII_RXER,
+ DA850_MII_CRS,
+ DA850_MII_RXCLK,
+ DA850_MII_RXDV,
+ DA850_MII_RXD_3,
+ DA850_MII_RXD_2,
+ DA850_MII_RXD_1,
+ DA850_MII_RXD_0,
};
#ifdef CONFIG_DAVINCI_MUX
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index ab8a2586d1cc..171173c1dbad 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -81,6 +81,24 @@
#define DM355_LPSC_RTO 12
#define DM355_LPSC_VPSS_DAC 41
+/* DM365 */
+#define DM365_LPSC_TIMER3 5
+#define DM365_LPSC_SPI1 6
+#define DM365_LPSC_MMC_SD1 7
+#define DM365_LPSC_McBSP1 8
+#define DM365_LPSC_PWM3 10
+#define DM365_LPSC_SPI2 11
+#define DM365_LPSC_RTO 12
+#define DM365_LPSC_TIMER4 17
+#define DM365_LPSC_SPI0 22
+#define DM365_LPSC_SPI3 38
+#define DM365_LPSC_SPI4 39
+#define DM365_LPSC_EMAC 40
+#define DM365_LPSC_VOICE_CODEC 44
+#define DM365_LPSC_DAC_CLK 46
+#define DM365_LPSC_VPSSMSTR 47
+#define DM365_LPSC_MJCP 50
+
/*
* LPSC Assignments
*/
@@ -118,6 +136,50 @@
#define DM646X_LPSC_TIMER1 35
#define DM646X_LPSC_ARM_INTC 45
+/* PSC0 defines */
+#define DA8XX_LPSC0_TPCC 0
+#define DA8XX_LPSC0_TPTC0 1
+#define DA8XX_LPSC0_TPTC1 2
+#define DA8XX_LPSC0_EMIF25 3
+#define DA8XX_LPSC0_SPI0 4
+#define DA8XX_LPSC0_MMC_SD 5
+#define DA8XX_LPSC0_AINTC 6
+#define DA8XX_LPSC0_ARM_RAM_ROM 7
+#define DA8XX_LPSC0_SECU_MGR 8
+#define DA8XX_LPSC0_UART0 9
+#define DA8XX_LPSC0_SCR0_SS 10
+#define DA8XX_LPSC0_SCR1_SS 11
+#define DA8XX_LPSC0_SCR2_SS 12
+#define DA8XX_LPSC0_DMAX 13
+#define DA8XX_LPSC0_ARM 14
+#define DA8XX_LPSC0_GEM 15
+
+/* PSC1 defines */
+#define DA850_LPSC1_TPCC1 0
+#define DA8XX_LPSC1_USB20 1
+#define DA8XX_LPSC1_USB11 2
+#define DA8XX_LPSC1_GPIO 3
+#define DA8XX_LPSC1_UHPI 4
+#define DA8XX_LPSC1_CPGMAC 5
+#define DA8XX_LPSC1_EMIF3C 6
+#define DA8XX_LPSC1_McASP0 7
+#define DA830_LPSC1_McASP1 8
+#define DA850_LPSC1_SATA 8
+#define DA830_LPSC1_McASP2 9
+#define DA8XX_LPSC1_SPI1 10
+#define DA8XX_LPSC1_I2C 11
+#define DA8XX_LPSC1_UART1 12
+#define DA8XX_LPSC1_UART2 13
+#define DA8XX_LPSC1_LCDC 16
+#define DA8XX_LPSC1_PWM 17
+#define DA8XX_LPSC1_ECAP 20
+#define DA830_LPSC1_EQEP 21
+#define DA850_LPSC1_TPTC2 21
+#define DA8XX_LPSC1_SCR_P0_SS 24
+#define DA8XX_LPSC1_SCR_P1_SS 25
+#define DA8XX_LPSC1_CR_P3_SS 26
+#define DA8XX_LPSC1_L3_CBA_RAM 31
+
extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
unsigned int id, char enable);
diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h
index 794fa5cf93c1..a584697a9e70 100644
--- a/arch/arm/mach-davinci/include/mach/serial.h
+++ b/arch/arm/mach-davinci/include/mach/serial.h
@@ -11,13 +11,17 @@
#ifndef __ASM_ARCH_SERIAL_H
#define __ASM_ARCH_SERIAL_H
-#include <mach/io.h>
+#include <mach/hardware.h>
#define DAVINCI_MAX_NR_UARTS 3
#define DAVINCI_UART0_BASE (IO_PHYS + 0x20000)
#define DAVINCI_UART1_BASE (IO_PHYS + 0x20400)
#define DAVINCI_UART2_BASE (IO_PHYS + 0x20800)
+#define DA8XX_UART0_BASE (IO_PHYS + 0x042000)
+#define DA8XX_UART1_BASE (IO_PHYS + 0x10c000)
+#define DA8XX_UART2_BASE (IO_PHYS + 0x10d000)
+
/* DaVinci UART register offsets */
#define UART_DAVINCI_PWREMU 0x0c
#define UART_DM646X_SCR 0x10
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
index b7e7036674fa..8e4f10fe1263 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -16,12 +16,12 @@
extern void davinci_watchdog_reset(void);
-static void arch_idle(void)
+static inline void arch_idle(void)
{
cpu_do_idle();
}
-static void arch_reset(char mode, const char *cmd)
+static inline void arch_reset(char mode, const char *cmd)
{
davinci_watchdog_reset();
}
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 1e27475f9a23..33796b4db17f 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -21,8 +21,11 @@ static u32 *uart;
static u32 *get_uart_base(void)
{
- /* Add logic here for new platforms, using __macine_arch_type */
- return (u32 *)DAVINCI_UART0_BASE;
+ if (__machine_arch_type == MACH_TYPE_DAVINCI_DA830_EVM ||
+ __machine_arch_type == MACH_TYPE_DAVINCI_DA850_EVM)
+ return (u32 *)DA8XX_UART2_BASE;
+ else
+ return (u32 *)DAVINCI_UART0_BASE;
}
/* PORT_16C550A, in polled non-fifo mode */
diff --git a/arch/arm/mach-davinci/include/mach/vmalloc.h b/arch/arm/mach-davinci/include/mach/vmalloc.h
index ad51625b6609..d49646a8e206 100644
--- a/arch/arm/mach-davinci/include/mach/vmalloc.h
+++ b/arch/arm/mach-davinci/include/mach/vmalloc.h
@@ -8,7 +8,7 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <mach/io.h>
+#include <mach/hardware.h>
/* Allow vmalloc range until the IO virtual range minus a 2M "hole" */
#define VMALLOC_END (IO_VIRT - (2<<20))
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
index d310f579aa85..898905e48946 100644
--- a/arch/arm/mach-davinci/mux.c
+++ b/arch/arm/mach-davinci/mux.c
@@ -91,3 +91,17 @@ int __init_or_module davinci_cfg_reg(const unsigned long index)
return 0;
}
EXPORT_SYMBOL(davinci_cfg_reg);
+
+int da8xx_pinmux_setup(const short pins[])
+{
+ int i, error = -EINVAL;
+
+ if (pins)
+ for (i = 0; pins[i] >= 0; i++) {
+ error = davinci_cfg_reg(pins[i]);
+ if (error)
+ break;
+ }
+
+ return error;
+}
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
index db54b2a66b4d..4f1fc9b318b3 100644
--- a/arch/arm/mach-davinci/sram.c
+++ b/arch/arm/mach-davinci/sram.c
@@ -60,7 +60,7 @@ static int __init sram_init(void)
int status = 0;
if (len) {
- len = min(len, SRAM_SIZE);
+ len = min_t(unsigned, len, SRAM_SIZE);
sram_pool = gen_pool_create(ilog2(SRAM_GRANULARITY), -1);
if (!sram_pool)
status = -ENOMEM;
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 0884ca57bfb0..0d1b6d407b46 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -406,11 +406,11 @@ struct sys_timer davinci_timer = {
void davinci_watchdog_reset(void)
{
u32 tgcr, wdtcr;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
- void __iomem *base = soc_info->wdt_base;
+ struct platform_device *pdev = &davinci_wdt_device;
+ void __iomem *base = IO_ADDRESS(pdev->resource[0].start);
struct clk *wd_clk;
- wd_clk = clk_get(&davinci_wdt_device.dev, NULL);
+ wd_clk = clk_get(&pdev->dev, NULL);
if (WARN_ON(IS_ERR(wd_clk)))
return;
clk_enable(wd_clk);
@@ -420,11 +420,11 @@ void davinci_watchdog_reset(void)
/* reset timer, set mode to 64-bit watchdog, and unreset */
tgcr = 0;
- __raw_writel(tgcr, base + TCR);
+ __raw_writel(tgcr, base + TGCR);
tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT;
tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
(TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
- __raw_writel(tgcr, base + TCR);
+ __raw_writel(tgcr, base + TGCR);
/* clear counter and period regs */
__raw_writel(0, base + TIM12);
@@ -432,12 +432,8 @@ void davinci_watchdog_reset(void)
__raw_writel(0, base + PRD12);
__raw_writel(0, base + PRD34);
- /* enable */
- wdtcr = __raw_readl(base + WDTCR);
- wdtcr |= WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT;
- __raw_writel(wdtcr, base + WDTCR);
-
/* put watchdog in pre-active state */
+ wdtcr = __raw_readl(base + WDTCR);
wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) |
(WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
__raw_writel(wdtcr, base + WDTCR);
diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c
index abedb6337182..06f55931620c 100644
--- a/arch/arm/mach-davinci/usb.c
+++ b/arch/arm/mach-davinci/usb.c
@@ -13,6 +13,7 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
+#include <mach/cputype.h>
#define DAVINCI_USB_OTG_BASE 0x01C64000
@@ -64,6 +65,10 @@ static struct resource usb_resources[] = {
.start = IRQ_USBINT,
.flags = IORESOURCE_IRQ,
},
+ {
+ /* placeholder for the dedicated CPPI IRQ */
+ .flags = IORESOURCE_IRQ,
+ },
};
static u64 usb_dmamask = DMA_BIT_MASK(32);
@@ -84,6 +89,14 @@ void __init setup_usb(unsigned mA, unsigned potpgt_msec)
{
usb_data.power = mA / 2;
usb_data.potpgt = potpgt_msec / 2;
+
+ if (cpu_is_davinci_dm646x()) {
+ /* Override the defaults as DM6467 uses different IRQs. */
+ usb_dev.resource[1].start = IRQ_DM646X_USBINT;
+ usb_dev.resource[2].start = IRQ_DM646X_USBDMAINT;
+ } else /* other devices don't have dedicated CPPI IRQ */
+ usb_dev.num_resources = 2;
+
platform_device_register(&usb_dev);
}
diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c
index 3fbd9b0fbe24..caf6d5154aec 100644
--- a/arch/arm/mach-ep93xx/adssphere.c
+++ b/arch/arm/mach-ep93xx/adssphere.c
@@ -12,18 +12,15 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
+#include <linux/mtd/physmap.h>
+
#include <mach/hardware.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+
static struct physmap_flash_data adssphere_flash_data = {
.width = 4,
};
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 6c4c1633ed12..3dd0e2a23095 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -22,48 +22,39 @@
#include <mach/hardware.h>
-/*
- * The EP93xx has two external crystal oscillators. To generate the
- * required high-frequency clocks, the processor uses two phase-locked-
- * loops (PLLs) to multiply the incoming external clock signal to much
- * higher frequencies that are then divided down by programmable dividers
- * to produce the needed clocks. The PLLs operate independently of one
- * another.
- */
-#define EP93XX_EXT_CLK_RATE 14745600
-#define EP93XX_EXT_RTC_RATE 32768
-
-
struct clk {
unsigned long rate;
int users;
int sw_locked;
- u32 enable_reg;
+ void __iomem *enable_reg;
u32 enable_mask;
unsigned long (*get_rate)(struct clk *clk);
+ int (*set_rate)(struct clk *clk, unsigned long rate);
};
static unsigned long get_uart_rate(struct clk *clk);
+static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
+
static struct clk clk_uart1 = {
.sw_locked = 1,
- .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
- .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN,
+ .enable_reg = EP93XX_SYSCON_DEVCFG,
+ .enable_mask = EP93XX_SYSCON_DEVCFG_U1EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart2 = {
.sw_locked = 1,
- .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
- .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN,
+ .enable_reg = EP93XX_SYSCON_DEVCFG,
+ .enable_mask = EP93XX_SYSCON_DEVCFG_U2EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart3 = {
.sw_locked = 1,
- .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
- .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN,
+ .enable_reg = EP93XX_SYSCON_DEVCFG,
+ .enable_mask = EP93XX_SYSCON_DEVCFG_U3EN,
.get_rate = get_uart_rate,
};
static struct clk clk_pll1;
@@ -75,6 +66,15 @@ static struct clk clk_usb_host = {
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN,
};
+static struct clk clk_keypad = {
+ .sw_locked = 1,
+ .enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV,
+ .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
+ .set_rate = set_keytchclk_rate,
+};
+static struct clk clk_pwm = {
+ .rate = EP93XX_EXT_CLK_RATE,
+};
/* DMA Clocks */
static struct clk clk_m2p0 = {
@@ -130,27 +130,29 @@ static struct clk clk_m2m1 = {
{ .dev_id = dev, .con_id = con, .clk = ck }
static struct clk_lookup clocks[] = {
- INIT_CK("apb:uart1", NULL, &clk_uart1),
- INIT_CK("apb:uart2", NULL, &clk_uart2),
- INIT_CK("apb:uart3", NULL, &clk_uart3),
- INIT_CK(NULL, "pll1", &clk_pll1),
- INIT_CK(NULL, "fclk", &clk_f),
- INIT_CK(NULL, "hclk", &clk_h),
- INIT_CK(NULL, "pclk", &clk_p),
- INIT_CK(NULL, "pll2", &clk_pll2),
- INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
- INIT_CK(NULL, "m2p0", &clk_m2p0),
- INIT_CK(NULL, "m2p1", &clk_m2p1),
- INIT_CK(NULL, "m2p2", &clk_m2p2),
- INIT_CK(NULL, "m2p3", &clk_m2p3),
- INIT_CK(NULL, "m2p4", &clk_m2p4),
- INIT_CK(NULL, "m2p5", &clk_m2p5),
- INIT_CK(NULL, "m2p6", &clk_m2p6),
- INIT_CK(NULL, "m2p7", &clk_m2p7),
- INIT_CK(NULL, "m2p8", &clk_m2p8),
- INIT_CK(NULL, "m2p9", &clk_m2p9),
- INIT_CK(NULL, "m2m0", &clk_m2m0),
- INIT_CK(NULL, "m2m1", &clk_m2m1),
+ INIT_CK("apb:uart1", NULL, &clk_uart1),
+ INIT_CK("apb:uart2", NULL, &clk_uart2),
+ INIT_CK("apb:uart3", NULL, &clk_uart3),
+ INIT_CK(NULL, "pll1", &clk_pll1),
+ INIT_CK(NULL, "fclk", &clk_f),
+ INIT_CK(NULL, "hclk", &clk_h),
+ INIT_CK(NULL, "pclk", &clk_p),
+ INIT_CK(NULL, "pll2", &clk_pll2),
+ INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
+ INIT_CK("ep93xx-keypad", NULL, &clk_keypad),
+ INIT_CK(NULL, "pwm_clk", &clk_pwm),
+ INIT_CK(NULL, "m2p0", &clk_m2p0),
+ INIT_CK(NULL, "m2p1", &clk_m2p1),
+ INIT_CK(NULL, "m2p2", &clk_m2p2),
+ INIT_CK(NULL, "m2p3", &clk_m2p3),
+ INIT_CK(NULL, "m2p4", &clk_m2p4),
+ INIT_CK(NULL, "m2p5", &clk_m2p5),
+ INIT_CK(NULL, "m2p6", &clk_m2p6),
+ INIT_CK(NULL, "m2p7", &clk_m2p7),
+ INIT_CK(NULL, "m2p8", &clk_m2p8),
+ INIT_CK(NULL, "m2p9", &clk_m2p9),
+ INIT_CK(NULL, "m2m0", &clk_m2m0),
+ INIT_CK(NULL, "m2m1", &clk_m2m1),
};
@@ -160,9 +162,11 @@ int clk_enable(struct clk *clk)
u32 value;
value = __raw_readl(clk->enable_reg);
+ value |= clk->enable_mask;
if (clk->sw_locked)
- __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(value | clk->enable_mask, clk->enable_reg);
+ ep93xx_syscon_swlocked_write(value, clk->enable_reg);
+ else
+ __raw_writel(value, clk->enable_reg);
}
return 0;
@@ -175,9 +179,11 @@ void clk_disable(struct clk *clk)
u32 value;
value = __raw_readl(clk->enable_reg);
+ value &= ~clk->enable_mask;
if (clk->sw_locked)
- __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(value & ~clk->enable_mask, clk->enable_reg);
+ ep93xx_syscon_swlocked_write(value, clk->enable_reg);
+ else
+ __raw_writel(value, clk->enable_reg);
}
}
EXPORT_SYMBOL(clk_disable);
@@ -202,6 +208,43 @@ unsigned long clk_get_rate(struct clk *clk)
}
EXPORT_SYMBOL(clk_get_rate);
+static int set_keytchclk_rate(struct clk *clk, unsigned long rate)
+{
+ u32 val;
+ u32 div_bit;
+
+ val = __raw_readl(clk->enable_reg);
+
+ /*
+ * The Key Matrix and ADC clocks are configured using the same
+ * System Controller register. The clock used will be either
+ * 1/4 or 1/16 the external clock rate depending on the
+ * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV
+ * bit being set or cleared.
+ */
+ div_bit = clk->enable_mask >> 15;
+
+ if (rate == EP93XX_KEYTCHCLK_DIV4)
+ val |= div_bit;
+ else if (rate == EP93XX_KEYTCHCLK_DIV16)
+ val &= ~div_bit;
+ else
+ return -EINVAL;
+
+ ep93xx_syscon_swlocked_write(val, clk->enable_reg);
+ clk->rate = rate;
+ return 0;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->set_rate)
+ return clk->set_rate(clk, rate);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 204dc5cbd0b8..40755298fa33 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -16,40 +16,24 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
+#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
#include <linux/dma-mapping.h>
-#include <linux/time.h>
#include <linux/timex.h>
-#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
#include <linux/termios.h>
#include <linux/amba/bus.h>
#include <linux/amba/serial.h>
-#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
-#include <mach/gpio.h>
#include <asm/hardware/vic.h>
@@ -362,8 +346,8 @@ void __init ep93xx_init_irq(void)
{
int gpio_irq;
- vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
- vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
+ vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
+ vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
for (gpio_irq = gpio_to_irq(0);
gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
@@ -385,6 +369,47 @@ void __init ep93xx_init_irq(void)
/*************************************************************************
+ * EP93xx System Controller Software Locked register handling
+ *************************************************************************/
+
+/*
+ * syscon_swlock prevents anything else from writing to the syscon
+ * block while a software locked register is being written.
+ */
+static DEFINE_SPINLOCK(syscon_swlock);
+
+void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&syscon_swlock, flags);
+
+ __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+ __raw_writel(val, reg);
+
+ spin_unlock_irqrestore(&syscon_swlock, flags);
+}
+EXPORT_SYMBOL(ep93xx_syscon_swlocked_write);
+
+void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
+{
+ unsigned long flags;
+ unsigned int val;
+
+ spin_lock_irqsave(&syscon_swlock, flags);
+
+ val = __raw_readl(EP93XX_SYSCON_DEVCFG);
+ val |= set_bits;
+ val &= ~clear_bits;
+ __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+ __raw_writel(val, EP93XX_SYSCON_DEVCFG);
+
+ spin_unlock_irqrestore(&syscon_swlock, flags);
+}
+EXPORT_SYMBOL(ep93xx_devcfg_set_clear);
+
+
+/*************************************************************************
* EP93xx peripheral handling
*************************************************************************/
#define EP93XX_UART_MCR_OFFSET (0x0100)
@@ -517,10 +542,8 @@ static struct platform_device ep93xx_eth_device = {
void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
{
- if (copy_addr) {
- memcpy(data->dev_addr,
- (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
- }
+ if (copy_addr)
+ memcpy_fromio(data->dev_addr, EP93XX_ETHERNET_BASE + 0x50, 6);
ep93xx_eth_data = *data;
platform_device_register(&ep93xx_eth_device);
@@ -546,19 +569,125 @@ void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num)
platform_device_register(&ep93xx_i2c_device);
}
+
+/*************************************************************************
+ * EP93xx LEDs
+ *************************************************************************/
+static struct gpio_led ep93xx_led_pins[] = {
+ {
+ .name = "platform:grled",
+ .gpio = EP93XX_GPIO_LINE_GRLED,
+ }, {
+ .name = "platform:rdled",
+ .gpio = EP93XX_GPIO_LINE_RDLED,
+ },
+};
+
+static struct gpio_led_platform_data ep93xx_led_data = {
+ .num_leds = ARRAY_SIZE(ep93xx_led_pins),
+ .leds = ep93xx_led_pins,
+};
+
+static struct platform_device ep93xx_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &ep93xx_led_data,
+ },
+};
+
+
+/*************************************************************************
+ * EP93xx pwm peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_pwm0_resource[] = {
+ {
+ .start = EP93XX_PWM_PHYS_BASE,
+ .end = EP93XX_PWM_PHYS_BASE + 0x10 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ep93xx_pwm0_device = {
+ .name = "ep93xx-pwm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(ep93xx_pwm0_resource),
+ .resource = ep93xx_pwm0_resource,
+};
+
+static struct resource ep93xx_pwm1_resource[] = {
+ {
+ .start = EP93XX_PWM_PHYS_BASE + 0x20,
+ .end = EP93XX_PWM_PHYS_BASE + 0x30 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ep93xx_pwm1_device = {
+ .name = "ep93xx-pwm",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(ep93xx_pwm1_resource),
+ .resource = ep93xx_pwm1_resource,
+};
+
+void __init ep93xx_register_pwm(int pwm0, int pwm1)
+{
+ if (pwm0)
+ platform_device_register(&ep93xx_pwm0_device);
+
+ /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */
+ if (pwm1)
+ platform_device_register(&ep93xx_pwm1_device);
+}
+
+int ep93xx_pwm_acquire_gpio(struct platform_device *pdev)
+{
+ int err;
+
+ if (pdev->id == 0) {
+ err = 0;
+ } else if (pdev->id == 1) {
+ err = gpio_request(EP93XX_GPIO_LINE_EGPIO14,
+ dev_name(&pdev->dev));
+ if (err)
+ return err;
+ err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0);
+ if (err)
+ goto fail;
+
+ /* PWM 1 output on EGPIO[14] */
+ ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG);
+ } else {
+ err = -ENODEV;
+ }
+
+ return err;
+
+fail:
+ gpio_free(EP93XX_GPIO_LINE_EGPIO14);
+ return err;
+}
+EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio);
+
+void ep93xx_pwm_release_gpio(struct platform_device *pdev)
+{
+ if (pdev->id == 1) {
+ gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14);
+ gpio_free(EP93XX_GPIO_LINE_EGPIO14);
+
+ /* EGPIO[14] used for GPIO */
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG);
+ }
+}
+EXPORT_SYMBOL(ep93xx_pwm_release_gpio);
+
+
extern void ep93xx_gpio_init(void);
void __init ep93xx_init_devices(void)
{
- unsigned int v;
-
- /*
- * Disallow access to MaverickCrunch initially.
- */
- v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
- v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
- __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
+ /* Disallow access to MaverickCrunch initially */
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA);
ep93xx_gpio_init();
@@ -568,4 +697,5 @@ void __init ep93xx_init_devices(void)
platform_device_register(&ep93xx_rtc_device);
platform_device_register(&ep93xx_ohci_device);
+ platform_device_register(&ep93xx_leds);
}
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index e9e45b92457e..73145ae5d3fa 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -26,18 +26,16 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
#include <linux/i2c.h>
+#include <linux/mtd/physmap.h>
+
#include <mach/hardware.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+
static struct physmap_flash_data edb93xx_flash_data;
static struct resource edb93xx_flash_resource = {
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index 3bad500b71b6..3da7ca816d19 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -12,18 +12,15 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
+#include <linux/mtd/physmap.h>
+
#include <mach/hardware.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+
static struct physmap_flash_data gesbc9312_flash_data = {
.width = 4,
};
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index 482cf3d2fbcd..1ea8871e03a9 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -17,15 +17,16 @@
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
-#include <mach/ep93xx-regs.h>
-#include <asm/gpio.h>
+#include <mach/hardware.h>
struct ep93xx_gpio_chip {
struct gpio_chip chip;
- unsigned int data_reg;
- unsigned int data_dir_reg;
+ void __iomem *data_reg;
+ void __iomem *data_dir_reg;
};
#define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip)
@@ -111,15 +112,61 @@ static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
u8 data_reg, data_dir_reg;
- int i;
+ int gpio, i;
data_reg = __raw_readb(ep93xx_chip->data_reg);
data_dir_reg = __raw_readb(ep93xx_chip->data_dir_reg);
- for (i = 0; i < chip->ngpio; i++)
- seq_printf(s, "GPIO %s%d: %s %s\n", chip->label, i,
- (data_reg & (1 << i)) ? "set" : "clear",
- (data_dir_reg & (1 << i)) ? "out" : "in");
+ gpio = ep93xx_chip->chip.base;
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ int is_out = data_dir_reg & (1 << i);
+
+ seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s",
+ chip->label, i, gpio,
+ gpiochip_is_requested(chip, i) ? : "",
+ is_out ? "out" : "in ",
+ (data_reg & (1 << i)) ? "hi" : "lo");
+
+ if (!is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+
+ switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ trigger = "(default)";
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "edge-falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "edge-rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "edge-both";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "level-high";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "level-low";
+ break;
+ default:
+ trigger = "?trigger?";
+ break;
+ }
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ (desc->status & IRQ_WAKEUP)
+ ? " wakeup" : "");
+ }
+ }
+
+ seq_printf(s, "\n");
+ }
}
#define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio) \
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 967c079180db..ea78e908fc82 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -52,40 +52,43 @@
#define EP93XX_AHB_VIRT_BASE 0xfef00000
#define EP93XX_AHB_SIZE 0x00100000
+#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_IOMEM(x) IOMEM(EP93XX_APB_VIRT_BASE + (x))
+
/* AHB peripherals */
-#define EP93XX_DMA_BASE ((void __iomem *) \
- (EP93XX_AHB_VIRT_BASE + 0x00000000))
+#define EP93XX_DMA_BASE EP93XX_AHB_IOMEM(0x00000000)
-#define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000)
#define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000)
+#define EP93XX_ETHERNET_BASE EP93XX_AHB_IOMEM(0x00010000)
-#define EP93XX_USB_BASE (EP93XX_AHB_VIRT_BASE + 0x00020000)
#define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000)
+#define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000)
-#define EP93XX_RASTER_BASE (EP93XX_AHB_VIRT_BASE + 0x00030000)
+#define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000)
-#define EP93XX_GRAPHICS_ACCEL_BASE (EP93XX_AHB_VIRT_BASE + 0x00040000)
+#define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000)
-#define EP93XX_SDRAM_CONTROLLER_BASE (EP93XX_AHB_VIRT_BASE + 0x00060000)
+#define EP93XX_SDRAM_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00060000)
-#define EP93XX_PCMCIA_CONTROLLER_BASE (EP93XX_AHB_VIRT_BASE + 0x00080000)
+#define EP93XX_PCMCIA_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00080000)
-#define EP93XX_BOOT_ROM_BASE (EP93XX_AHB_VIRT_BASE + 0x00090000)
+#define EP93XX_BOOT_ROM_BASE EP93XX_AHB_IOMEM(0x00090000)
-#define EP93XX_IDE_BASE (EP93XX_AHB_VIRT_BASE + 0x000a0000)
+#define EP93XX_IDE_BASE EP93XX_AHB_IOMEM(0x000a0000)
-#define EP93XX_VIC1_BASE (EP93XX_AHB_VIRT_BASE + 0x000b0000)
+#define EP93XX_VIC1_BASE EP93XX_AHB_IOMEM(0x000b0000)
-#define EP93XX_VIC2_BASE (EP93XX_AHB_VIRT_BASE + 0x000c0000)
+#define EP93XX_VIC2_BASE EP93XX_AHB_IOMEM(0x000c0000)
/* APB peripherals */
-#define EP93XX_TIMER_BASE (EP93XX_APB_VIRT_BASE + 0x00010000)
+#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000)
#define EP93XX_TIMER_REG(x) (EP93XX_TIMER_BASE + (x))
#define EP93XX_TIMER1_LOAD EP93XX_TIMER_REG(0x00)
#define EP93XX_TIMER1_VALUE EP93XX_TIMER_REG(0x04)
@@ -102,11 +105,11 @@
#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88)
#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c)
-#define EP93XX_I2S_BASE (EP93XX_APB_VIRT_BASE + 0x00020000)
+#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000)
-#define EP93XX_SECURITY_BASE (EP93XX_APB_VIRT_BASE + 0x00030000)
+#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000)
-#define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000)
+#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)
@@ -124,32 +127,33 @@
#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8)
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
-#define EP93XX_AAC_BASE (EP93XX_APB_VIRT_BASE + 0x00080000)
+#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
-#define EP93XX_SPI_BASE (EP93XX_APB_VIRT_BASE + 0x000a0000)
+#define EP93XX_SPI_BASE EP93XX_APB_IOMEM(0x000a0000)
-#define EP93XX_IRDA_BASE (EP93XX_APB_VIRT_BASE + 0x000b0000)
+#define EP93XX_IRDA_BASE EP93XX_APB_IOMEM(0x000b0000)
-#define EP93XX_UART1_BASE (EP93XX_APB_VIRT_BASE + 0x000c0000)
#define EP93XX_UART1_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000c0000)
+#define EP93XX_UART1_BASE EP93XX_APB_IOMEM(0x000c0000)
-#define EP93XX_UART2_BASE (EP93XX_APB_VIRT_BASE + 0x000d0000)
#define EP93XX_UART2_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000d0000)
+#define EP93XX_UART2_BASE EP93XX_APB_IOMEM(0x000d0000)
-#define EP93XX_UART3_BASE (EP93XX_APB_VIRT_BASE + 0x000e0000)
#define EP93XX_UART3_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000e0000)
+#define EP93XX_UART3_BASE EP93XX_APB_IOMEM(0x000e0000)
-#define EP93XX_KEY_MATRIX_BASE (EP93XX_APB_VIRT_BASE + 0x000f0000)
+#define EP93XX_KEY_MATRIX_BASE EP93XX_APB_IOMEM(0x000f0000)
-#define EP93XX_ADC_BASE (EP93XX_APB_VIRT_BASE + 0x00100000)
-#define EP93XX_TOUCHSCREEN_BASE (EP93XX_APB_VIRT_BASE + 0x00100000)
+#define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000)
+#define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000)
-#define EP93XX_PWM_BASE (EP93XX_APB_VIRT_BASE + 0x00110000)
+#define EP93XX_PWM_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00110000)
+#define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000)
-#define EP93XX_RTC_BASE (EP93XX_APB_VIRT_BASE + 0x00120000)
#define EP93XX_RTC_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00120000)
+#define EP93XX_RTC_BASE EP93XX_APB_IOMEM(0x00120000)
-#define EP93XX_SYSCON_BASE (EP93XX_APB_VIRT_BASE + 0x00130000)
+#define EP93XX_SYSCON_BASE EP93XX_APB_IOMEM(0x00130000)
#define EP93XX_SYSCON_REG(x) (EP93XX_SYSCON_BASE + (x))
#define EP93XX_SYSCON_POWER_STATE EP93XX_SYSCON_REG(0x00)
#define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04)
@@ -172,14 +176,45 @@
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20)
#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24)
-#define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80)
-#define EP93XX_SYSCON_DEVICE_CONFIG_U3EN (1<<24)
-#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE (1<<23)
-#define EP93XX_SYSCON_DEVICE_CONFIG_U2EN (1<<20)
-#define EP93XX_SYSCON_DEVICE_CONFIG_U1EN (1<<18)
+#define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80)
+#define EP93XX_SYSCON_DEVCFG_SWRST (1<<31)
+#define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30)
+#define EP93XX_SYSCON_DEVCFG_D0ONG (1<<29)
+#define EP93XX_SYSCON_DEVCFG_IONU2 (1<<28)
+#define EP93XX_SYSCON_DEVCFG_GONK (1<<27)
+#define EP93XX_SYSCON_DEVCFG_TONG (1<<26)
+#define EP93XX_SYSCON_DEVCFG_MONG (1<<25)
+#define EP93XX_SYSCON_DEVCFG_U3EN (1<<24)
+#define EP93XX_SYSCON_DEVCFG_CPENA (1<<23)
+#define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22)
+#define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21)
+#define EP93XX_SYSCON_DEVCFG_U2EN (1<<20)
+#define EP93XX_SYSCON_DEVCFG_EXVC (1<<19)
+#define EP93XX_SYSCON_DEVCFG_U1EN (1<<18)
+#define EP93XX_SYSCON_DEVCFG_TIN (1<<17)
+#define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15)
+#define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14)
+#define EP93XX_SYSCON_DEVCFG_HC1IN (1<<13)
+#define EP93XX_SYSCON_DEVCFG_HC1EN (1<<12)
+#define EP93XX_SYSCON_DEVCFG_HONIDE (1<<11)
+#define EP93XX_SYSCON_DEVCFG_GONIDE (1<<10)
+#define EP93XX_SYSCON_DEVCFG_PONG (1<<9)
+#define EP93XX_SYSCON_DEVCFG_EONIDE (1<<8)
+#define EP93XX_SYSCON_DEVCFG_I2SONSSP (1<<7)
+#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6)
+#define EP93XX_SYSCON_DEVCFG_RASONP3 (1<<4)
+#define EP93XX_SYSCON_DEVCFG_RAS (1<<3)
+#define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2)
+#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1)
+#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0)
+#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0)
#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0)
-#define EP93XX_WATCHDOG_BASE (EP93XX_APB_VIRT_BASE + 0x00140000)
+#define EP93XX_WATCHDOG_BASE EP93XX_APB_IOMEM(0x00140000)
#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/hardware.h b/arch/arm/mach-ep93xx/include/mach/hardware.h
index 2866297310b7..349fa7cb72d5 100644
--- a/arch/arm/mach-ep93xx/include/mach/hardware.h
+++ b/arch/arm/mach-ep93xx/include/mach/hardware.h
@@ -4,12 +4,23 @@
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
-#include "ep93xx-regs.h"
+#include <mach/ep93xx-regs.h>
+#include <mach/platform.h>
#define pcibios_assign_all_busses() 0
-#include "platform.h"
+/*
+ * The EP93xx has two external crystal oscillators. To generate the
+ * required high-frequency clocks, the processor uses two phase-locked-
+ * loops (PLLs) to multiply the incoming external clock signal to much
+ * higher frequencies that are then divided down by programmable dividers
+ * to produce the needed clocks. The PLLs operate independently of one
+ * another.
+ */
+#define EP93XX_EXT_CLK_RATE 14745600
+#define EP93XX_EXT_RTC_RATE 32768
-#include "ts72xx.h"
+#define EP93XX_KEYTCHCLK_DIV4 (EP93XX_EXT_CLK_RATE / 4)
+#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16)
#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/io.h b/arch/arm/mach-ep93xx/include/mach/io.h
index fd5f081cc8b7..cebcc1c53d63 100644
--- a/arch/arm/mach-ep93xx/include/mach/io.h
+++ b/arch/arm/mach-ep93xx/include/mach/io.h
@@ -1,8 +1,21 @@
/*
* arch/arm/mach-ep93xx/include/mach/io.h
*/
+#ifndef __ASM_MACH_IO_H
+#define __ASM_MACH_IO_H
#define IO_SPACE_LIMIT 0xffffffff
-#define __io(p) __typesafe_io(p)
-#define __mem_pci(p) (p)
+#define __io(p) __typesafe_io(p)
+#define __mem_pci(p) (p)
+
+/*
+ * A typesafe __io() variation for variable initialisers
+ */
+#ifdef __ASSEMBLER__
+#define IOMEM(p) p
+#else
+#define IOMEM(p) ((void __iomem __force *)(p))
+#endif
+
+#endif /* __ASM_MACH_IO_H */
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 05f0f4f2f3ce..5f5fa6574d34 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
struct i2c_board_info;
+struct platform_device;
struct ep93xx_eth_data
{
@@ -15,8 +16,27 @@ struct ep93xx_eth_data
void ep93xx_map_io(void);
void ep93xx_init_irq(void);
void ep93xx_init_time(unsigned long);
+
+/* EP93xx System Controller software locked register write */
+void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
+void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
+
+static inline void ep93xx_devcfg_set_bits(unsigned int bits)
+{
+ ep93xx_devcfg_set_clear(bits, 0x00);
+}
+
+static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
+{
+ ep93xx_devcfg_set_clear(0x00, 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_pwm(int pwm0, int pwm1);
+int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
+void ep93xx_pwm_release_gpio(struct platform_device *pdev);
+
void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;
diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h
index ed8f35e4f068..6d661fe9d66c 100644
--- a/arch/arm/mach-ep93xx/include/mach/system.h
+++ b/arch/arm/mach-ep93xx/include/mach/system.h
@@ -11,15 +11,13 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode, const char *cmd)
{
- u32 devicecfg;
-
local_irq_disable();
- devicecfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
- __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(devicecfg | 0x80000000, EP93XX_SYSCON_DEVICE_CONFIG);
- __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
- __raw_writel(devicecfg & ~0x80000000, EP93XX_SYSCON_DEVICE_CONFIG);
+ /*
+ * Set then clear the SWRST bit to initiate a software reset
+ */
+ ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_SWRST);
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_SWRST);
while (1)
;
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
index 34ddec081c40..3bd934e9a7f1 100644
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
@@ -41,9 +41,6 @@
#define TS72XX_OPTIONS2_TS9420_BOOT 0x02
-#define TS72XX_NOR_PHYS_BASE 0x60000000
-#define TS72XX_NOR2_PHYS_BASE 0x62000000
-
#define TS72XX_NAND1_DATA_PHYS_BASE 0x60000000
#define TS72XX_NAND2_DATA_PHYS_BASE 0x70000000
#define TS72XX_NAND_DATA_VIRT_BASE 0xfebfc000
@@ -70,7 +67,6 @@
#ifndef __ASSEMBLY__
-#include <linux/io.h>
static inline int board_is_ts7200(void)
{
diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c
index 15d6815d78c4..0a313e82fb74 100644
--- a/arch/arm/mach-ep93xx/micro9.c
+++ b/arch/arm/mach-ep93xx/micro9.c
@@ -9,21 +9,16 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
#include <linux/mtd/physmap.h>
#include <mach/hardware.h>
-#include <asm/mach/arch.h>
#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
static struct ep93xx_eth_data micro9_eth_data = {
.phy_id = 0x1f,
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 7ee024d34829..259f7822ba52 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -12,19 +12,18 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
-#include <linux/m48t86.h>
#include <linux/io.h>
-#include <linux/i2c.h>
+#include <linux/m48t86.h>
+#include <linux/mtd/physmap.h>
+
#include <mach/hardware.h>
+#include <mach/ts72xx.h>
+
#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
static struct map_desc ts72xx_io_desc[] __initdata = {
{
@@ -112,13 +111,16 @@ static void __init ts72xx_map_io(void)
}
}
+/*************************************************************************
+ * NOR flash (TS-7200 only)
+ *************************************************************************/
static struct physmap_flash_data ts72xx_flash_data = {
- .width = 1,
+ .width = 2,
};
static struct resource ts72xx_flash_resource = {
- .start = TS72XX_NOR_PHYS_BASE,
- .end = TS72XX_NOR_PHYS_BASE + SZ_16M - 1,
+ .start = EP93XX_CS6_PHYS_BASE,
+ .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
.flags = IORESOURCE_MEM,
};
@@ -132,6 +134,12 @@ static struct platform_device ts72xx_flash = {
.resource = &ts72xx_flash_resource,
};
+static void __init ts72xx_register_flash(void)
+{
+ if (board_is_ts7200())
+ platform_device_register(&ts72xx_flash);
+}
+
static unsigned char ts72xx_rtc_readbyte(unsigned long addr)
{
__raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
@@ -165,8 +173,7 @@ static struct ep93xx_eth_data ts72xx_eth_data = {
static void __init ts72xx_init_machine(void)
{
ep93xx_init_devices();
- if (board_is_ts7200())
- platform_device_register(&ts72xx_flash);
+ ts72xx_register_flash();
platform_device_register(&ts72xx_rtc_device);
ep93xx_register_eth(&ts72xx_eth_data, 1);
diff --git a/arch/arm/mach-integrator/include/mach/hardware.h b/arch/arm/mach-integrator/include/mach/hardware.h
index 1251319ef9ae..d795642fad22 100644
--- a/arch/arm/mach-integrator/include/mach/hardware.h
+++ b/arch/arm/mach-integrator/include/mach/hardware.h
@@ -36,8 +36,12 @@
#define PCIO_BASE PCI_IO_VADDR
#define PCIMEM_BASE PCI_MEMORY_VADDR
+#ifdef CONFIG_MMU
/* macro to get at IO space when running virtually */
#define IO_ADDRESS(x) (((x) >> 4) + IO_BASE)
+#else
+#define IO_ADDRESS(x) (x)
+#endif
#define pcibios_assign_all_busses() 1
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 4ac04055c2ea..2a318eba1b07 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -49,14 +49,14 @@
#define INTCP_PA_CLCD_BASE 0xc0000000
-#define INTCP_VA_CIC_BASE 0xf1000040
-#define INTCP_VA_PIC_BASE 0xf1400000
-#define INTCP_VA_SIC_BASE 0xfca00000
+#define INTCP_VA_CIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + 0x40
+#define INTCP_VA_PIC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE)
+#define INTCP_VA_SIC_BASE IO_ADDRESS(0xca000000)
#define INTCP_PA_ETH_BASE 0xc8000000
#define INTCP_ETH_SIZE 0x10
-#define INTCP_VA_CTRL_BASE 0xfcb00000
+#define INTCP_VA_CTRL_BASE IO_ADDRESS(0xcb000000)
#define INTCP_FLASHPROG 0x04
#define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0)
#define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1)
@@ -121,12 +121,12 @@ static struct map_desc intcp_io_desc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = 0xfca00000,
+ .virtual = IO_ADDRESS(0xca000000),
.pfn = __phys_to_pfn(0xca000000),
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = 0xfcb00000,
+ .virtual = IO_ADDRESS(0xcb000000),
.pfn = __phys_to_pfn(0xcb000000),
.length = SZ_4K,
.type = MT_DEVICE
@@ -394,8 +394,8 @@ static struct platform_device *intcp_devs[] __initdata = {
*/
static unsigned int mmc_status(struct device *dev)
{
- unsigned int status = readl(0xfca00004);
- writel(8, 0xfcb00008);
+ unsigned int status = readl(IO_ADDRESS(0xca000000) + 4);
+ writel(8, IO_ADDRESS(0xcb000000) + 8);
return status & 8;
}
@@ -403,6 +403,8 @@ static unsigned int mmc_status(struct device *dev)
static struct mmc_platform_data mmc_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
+ .gpio_wp = -1,
+ .gpio_cd = -1,
};
static struct amba_device mmc_device = {
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
index f5ebcc0fcab9..78499667eb7b 100644
--- a/arch/arm/mach-ks8695/pci.c
+++ b/arch/arm/mach-ks8695/pci.c
@@ -245,6 +245,9 @@ static int ks8695_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs
static void __init ks8695_pci_preinit(void)
{
+ /* make software reset to avoid freeze if PCI bus was messed up */
+ __raw_writel(0x80000000, KS8695_PCI_VA + KS8695_PBCS);
+
/* stage 1 initialization, subid, subdevice = 0x0001 */
__raw_writel(0x00010001, KS8695_PCI_VA + KS8695_CRCSID);
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
new file mode 100644
index 000000000000..2a02b49c40f0
--- /dev/null
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -0,0 +1,21 @@
+if ARCH_NOMADIK
+
+menu "Nomadik boards"
+
+config MACH_NOMADIK_8815NHK
+ bool "ST 8815 Nomadik Hardware Kit (evaluation board)"
+ select NOMADIK_8815
+
+endmenu
+
+config NOMADIK_8815
+ bool
+
+
+config I2C_BITBANG_8815NHK
+ tristate "Driver for bit-bang busses found on the 8815 NHK"
+ depends on I2C && MACH_NOMADIK_8815NHK
+ select I2C_ALGOBIT
+ default y
+
+endif
diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile
new file mode 100644
index 000000000000..412040982a40
--- /dev/null
+++ b/arch/arm/mach-nomadik/Makefile
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+
+# Object file lists.
+
+obj-y += clock.o timer.o gpio.o
+
+# Cpu revision
+obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o
+
+# Specific board support
+obj-$(CONFIG_MACH_NOMADIK_8815NHK) += board-nhk8815.o
+
+# Nomadik extra devices
+obj-$(CONFIG_I2C_BITBANG_8815NHK) += i2c-8815nhk.o
diff --git a/arch/arm/mach-nomadik/Makefile.boot b/arch/arm/mach-nomadik/Makefile.boot
new file mode 100644
index 000000000000..c7e75acfe6c9
--- /dev/null
+++ b/arch/arm/mach-nomadik/Makefile.boot
@@ -0,0 +1,4 @@
+ zreladdr-y := 0x00008000
+params_phys-y := 0x00000100
+initrd_phys-y := 0x00800000
+
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
new file mode 100644
index 000000000000..79bdea943eb4
--- /dev/null
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -0,0 +1,111 @@
+/*
+ * linux/arch/arm/mach-nomadik/board-8815nhk.c
+ *
+ * Copyright (C) STMicroelectronics
+ *
+ * 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.
+ *
+ * NHK15 board specifc driver definition
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/setup.h>
+#include "clock.h"
+
+#define __MEM_4K_RESOURCE(x) \
+ .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+
+static struct amba_device uart0_device = {
+ .dev = { .init_name = "uart0" },
+ __MEM_4K_RESOURCE(NOMADIK_UART0_BASE),
+ .irq = {IRQ_UART0, NO_IRQ},
+};
+
+static struct amba_device uart1_device = {
+ .dev = { .init_name = "uart1" },
+ __MEM_4K_RESOURCE(NOMADIK_UART1_BASE),
+ .irq = {IRQ_UART1, NO_IRQ},
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+ &uart0_device,
+ &uart1_device,
+};
+
+/* We have a fixed clock alone, by now */
+static struct clk nhk8815_clk_48 = {
+ .rate = 48*1000*1000,
+};
+
+static struct resource nhk8815_eth_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x34000000 + 0x300,
+ .end = 0x34000000 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = NOMADIK_GPIO_TO_IRQ(115),
+ .end = NOMADIK_GPIO_TO_IRQ(115),
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+ }
+};
+
+static struct platform_device nhk8815_eth_device = {
+ .name = "smc91x",
+ .resource = nhk8815_eth_resources,
+ .num_resources = ARRAY_SIZE(nhk8815_eth_resources),
+};
+
+static int __init nhk8815_eth_init(void)
+{
+ int gpio_nr = 115; /* hardwired in the board */
+ int err;
+
+ err = gpio_request(gpio_nr, "eth_irq");
+ if (!err) err = nmk_gpio_set_mode(gpio_nr, NMK_GPIO_ALT_GPIO);
+ if (!err) err = gpio_direction_input(gpio_nr);
+ if (err)
+ pr_err("Error %i in %s\n", err, __func__);
+ return err;
+}
+device_initcall(nhk8815_eth_init);
+
+static struct platform_device *nhk8815_platform_devices[] __initdata = {
+ &nhk8815_eth_device,
+ /* will add more devices */
+};
+
+static void __init nhk8815_platform_init(void)
+{
+ int i;
+
+ cpu8815_platform_init();
+ platform_add_devices(nhk8815_platform_devices,
+ ARRAY_SIZE(nhk8815_platform_devices));
+
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+ nmdk_clk_create(&nhk8815_clk_48, amba_devs[i]->dev.init_name);
+ amba_device_register(amba_devs[i], &iomem_resource);
+ }
+}
+
+MACHINE_START(NOMADIK, "NHK8815")
+ /* Maintainer: ST MicroElectronics */
+ .phys_io = NOMADIK_UART0_BASE,
+ .io_pg_offst = (IO_ADDRESS(NOMADIK_UART0_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x100,
+ .map_io = cpu8815_map_io,
+ .init_irq = cpu8815_init_irq,
+ .timer = &nomadik_timer,
+ .init_machine = nhk8815_platform_init,
+MACHINE_END
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c
new file mode 100644
index 000000000000..9f92502a0083
--- /dev/null
+++ b/arch/arm/mach-nomadik/clock.c
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/arm/mach-nomadik/clock.c
+ *
+ * Copyright (C) 2009 Alessandro Rubini
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <asm/clkdev.h>
+#include "clock.h"
+
+/*
+ * The nomadik board uses generic clocks, but the serial pl011 file
+ * calls clk_enable(), clk_disable(), clk_get_rate(), so we provide them
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/* enable and disable do nothing */
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+/* Create a clock structure with the given name */
+int nmdk_clk_create(struct clk *clk, const char *dev_id)
+{
+ struct clk_lookup *clkdev;
+
+ clkdev = clkdev_alloc(clk, NULL, dev_id);
+ if (!clkdev)
+ return -ENOMEM;
+ clkdev_add(clkdev);
+ return 0;
+}
diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h
new file mode 100644
index 000000000000..235faec7f627
--- /dev/null
+++ b/arch/arm/mach-nomadik/clock.h
@@ -0,0 +1,14 @@
+
+/*
+ * linux/arch/arm/mach-nomadik/clock.h
+ *
+ * Copyright (C) 2009 Alessandro Rubini
+ *
+ * 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.
+ */
+struct clk {
+ unsigned long rate;
+};
+extern int nmdk_clk_create(struct clk *clk, const char *dev_id);
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
new file mode 100644
index 000000000000..f93c59634191
--- /dev/null
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright STMicroelectronics, 2007.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/vic.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+
+/* The 8815 has 4 GPIO blocks, let's register them immediately */
+static struct nmk_gpio_platform_data cpu8815_gpio[] = {
+ {
+ .name = "GPIO-0-31",
+ .first_gpio = 0,
+ .first_irq = NOMADIK_GPIO_TO_IRQ(0),
+ .parent_irq = IRQ_GPIO0,
+ }, {
+ .name = "GPIO-32-63",
+ .first_gpio = 32,
+ .first_irq = NOMADIK_GPIO_TO_IRQ(32),
+ .parent_irq = IRQ_GPIO1,
+ }, {
+ .name = "GPIO-64-95",
+ .first_gpio = 64,
+ .first_irq = NOMADIK_GPIO_TO_IRQ(64),
+ .parent_irq = IRQ_GPIO2,
+ }, {
+ .name = "GPIO-96-127", /* 124..127 not routed to pin */
+ .first_gpio = 96,
+ .first_irq = NOMADIK_GPIO_TO_IRQ(96),
+ .parent_irq = IRQ_GPIO3,
+ }
+};
+
+#define __MEM_4K_RESOURCE(x) \
+ .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+
+static struct amba_device cpu8815_amba_gpio[] = {
+ {
+ .dev = {
+ .init_name = "gpio0",
+ .platform_data = cpu8815_gpio + 0,
+ },
+ __MEM_4K_RESOURCE(NOMADIK_GPIO0_BASE),
+ }, {
+ .dev = {
+ .init_name = "gpio1",
+ .platform_data = cpu8815_gpio + 1,
+ },
+ __MEM_4K_RESOURCE(NOMADIK_GPIO1_BASE),
+ }, {
+ .dev = {
+ .init_name = "gpio2",
+ .platform_data = cpu8815_gpio + 2,
+ },
+ __MEM_4K_RESOURCE(NOMADIK_GPIO2_BASE),
+ }, {
+ .dev = {
+ .init_name = "gpio3",
+ .platform_data = cpu8815_gpio + 3,
+ },
+ __MEM_4K_RESOURCE(NOMADIK_GPIO3_BASE),
+ },
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+ cpu8815_amba_gpio + 0,
+ cpu8815_amba_gpio + 1,
+ cpu8815_amba_gpio + 2,
+ cpu8815_amba_gpio + 3,
+};
+
+static int __init cpu8815_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
+ amba_device_register(amba_devs[i], &iomem_resource);
+ return 0;
+}
+arch_initcall(cpu8815_init);
+
+/* All SoC devices live in the same area (see hardware.h) */
+static struct map_desc nomadik_io_desc[] __initdata = {
+ {
+ .virtual = NOMADIK_IO_VIRTUAL,
+ .pfn = __phys_to_pfn(NOMADIK_IO_PHYSICAL),
+ .length = NOMADIK_IO_SIZE,
+ .type = MT_DEVICE,
+ }
+ /* static ram and secured ram may be added later */
+};
+
+void __init cpu8815_map_io(void)
+{
+ iotable_init(nomadik_io_desc, ARRAY_SIZE(nomadik_io_desc));
+}
+
+void __init cpu8815_init_irq(void)
+{
+ /* This modified VIC cell has two register blocks, at 0 and 0x20 */
+ vic_init(io_p2v(NOMADIK_IC_BASE + 0x00), IRQ_VIC_START + 0, ~0, 0);
+ vic_init(io_p2v(NOMADIK_IC_BASE + 0x20), IRQ_VIC_START + 32, ~0, 0);
+}
+
+/*
+ * This function is called from the board init ("init_machine").
+ */
+ void __init cpu8815_platform_init(void)
+{
+#ifdef CONFIG_CACHE_L2X0
+ /* At full speed latency must be >=2, so 0x249 in low bits */
+ l2x0_init(io_p2v(NOMADIK_L2CC_BASE), 0x00730249, 0xfe000fff);
+#endif
+ return;
+}
diff --git a/arch/arm/mach-nomadik/gpio.c b/arch/arm/mach-nomadik/gpio.c
new file mode 100644
index 000000000000..9a09b2791e03
--- /dev/null
+++ b/arch/arm/mach-nomadik/gpio.c
@@ -0,0 +1,396 @@
+/*
+ * Generic GPIO driver for logic cells found in the Nomadik SoC
+ *
+ * Copyright (C) 2008,2009 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
+ * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+
+/*
+ * The GPIO module in the Nomadik family of Systems-on-Chip is an
+ * AMBA device, managing 32 pins and alternate functions. The logic block
+ * is currently only used in the Nomadik.
+ *
+ * Symbols in this file are called "nmk_gpio" for "nomadik gpio"
+ */
+
+#define NMK_GPIO_PER_CHIP 32
+struct nmk_gpio_chip {
+ struct gpio_chip chip;
+ void __iomem *addr;
+ unsigned int parent_irq;
+ spinlock_t *lock;
+ /* Keep track of configured edges */
+ u32 edge_rising;
+ u32 edge_falling;
+};
+
+/* Mode functions */
+int nmk_gpio_set_mode(int gpio, int gpio_mode)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+ u32 afunc, bfunc, bit;
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ if (!nmk_chip)
+ return -EINVAL;
+
+ bit = 1 << (gpio - nmk_chip->chip.base);
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
+ bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
+ if (gpio_mode & NMK_GPIO_ALT_A)
+ afunc |= bit;
+ if (gpio_mode & NMK_GPIO_ALT_B)
+ bfunc |= bit;
+ writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
+ writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(nmk_gpio_set_mode);
+
+int nmk_gpio_get_mode(int gpio)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ u32 afunc, bfunc, bit;
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ if (!nmk_chip)
+ return -EINVAL;
+
+ bit = 1 << (gpio - nmk_chip->chip.base);
+
+ afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
+ bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
+
+ return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
+}
+EXPORT_SYMBOL(nmk_gpio_get_mode);
+
+
+/* IRQ functions */
+static inline int nmk_gpio_get_bitmask(int gpio)
+{
+ return 1 << (gpio % 32);
+}
+
+static void nmk_gpio_irq_ack(unsigned int irq)
+{
+ int gpio;
+ struct nmk_gpio_chip *nmk_chip;
+
+ gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ nmk_chip = get_irq_chip_data(irq);
+ if (!nmk_chip)
+ return;
+ writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
+}
+
+static void nmk_gpio_irq_mask(unsigned int irq)
+{
+ int gpio;
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+ u32 bitmask, reg;
+
+ gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ nmk_chip = get_irq_chip_data(irq);
+ bitmask = nmk_gpio_get_bitmask(gpio);
+ if (!nmk_chip)
+ return;
+
+ /* we must individually clear the two edges */
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ if (nmk_chip->edge_rising & bitmask) {
+ reg = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
+ reg &= ~bitmask;
+ writel(reg, nmk_chip->addr + NMK_GPIO_RWIMSC);
+ }
+ if (nmk_chip->edge_falling & bitmask) {
+ reg = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
+ reg &= ~bitmask;
+ writel(reg, nmk_chip->addr + NMK_GPIO_FWIMSC);
+ }
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+};
+
+static void nmk_gpio_irq_unmask(unsigned int irq)
+{
+ int gpio;
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+ u32 bitmask, reg;
+
+ gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ nmk_chip = get_irq_chip_data(irq);
+ bitmask = nmk_gpio_get_bitmask(gpio);
+ if (!nmk_chip)
+ return;
+
+ /* we must individually set the two edges */
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+ if (nmk_chip->edge_rising & bitmask) {
+ reg = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
+ reg |= bitmask;
+ writel(reg, nmk_chip->addr + NMK_GPIO_RWIMSC);
+ }
+ if (nmk_chip->edge_falling & bitmask) {
+ reg = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
+ reg |= bitmask;
+ writel(reg, nmk_chip->addr + NMK_GPIO_FWIMSC);
+ }
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+}
+
+static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+ int gpio;
+ struct nmk_gpio_chip *nmk_chip;
+ unsigned long flags;
+ u32 bitmask;
+
+ gpio = NOMADIK_IRQ_TO_GPIO(irq);
+ nmk_chip = get_irq_chip_data(irq);
+ bitmask = nmk_gpio_get_bitmask(gpio);
+ if (!nmk_chip)
+ return -EINVAL;
+
+ if (type & IRQ_TYPE_LEVEL_HIGH)
+ return -EINVAL;
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nmk_chip->lock, flags);
+
+ nmk_chip->edge_rising &= ~bitmask;
+ if (type & IRQ_TYPE_EDGE_RISING)
+ nmk_chip->edge_rising |= bitmask;
+ writel(nmk_chip->edge_rising, nmk_chip->addr + NMK_GPIO_RIMSC);
+
+ nmk_chip->edge_falling &= ~bitmask;
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ nmk_chip->edge_falling |= bitmask;
+ writel(nmk_chip->edge_falling, nmk_chip->addr + NMK_GPIO_FIMSC);
+
+ spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ nmk_gpio_irq_unmask(irq);
+
+ return 0;
+}
+
+static struct irq_chip nmk_gpio_irq_chip = {
+ .name = "Nomadik-GPIO",
+ .ack = nmk_gpio_irq_ack,
+ .mask = nmk_gpio_irq_mask,
+ .unmask = nmk_gpio_irq_unmask,
+ .set_type = nmk_gpio_irq_set_type,
+};
+
+static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct nmk_gpio_chip *nmk_chip;
+ struct irq_chip *host_chip;
+ unsigned int gpio_irq;
+ u32 pending;
+ unsigned int first_irq;
+
+ nmk_chip = get_irq_data(irq);
+ first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
+ while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) {
+ gpio_irq = first_irq + __ffs(pending);
+ generic_handle_irq(gpio_irq);
+ }
+ if (0) {/* don't ack parent irq, as ack == disable */
+ host_chip = get_irq_chip(irq);
+ host_chip->ack(irq);
+ }
+}
+
+static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
+{
+ unsigned int first_irq;
+ int i;
+
+ first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
+ for (i = first_irq; i < first_irq + NMK_GPIO_PER_CHIP; i++) {
+ set_irq_chip(i, &nmk_gpio_irq_chip);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ set_irq_chip_data(i, nmk_chip);
+ }
+ set_irq_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
+ set_irq_data(nmk_chip->parent_irq, nmk_chip);
+ return 0;
+}
+
+/* I/O Functions */
+static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+ return 0;
+}
+
+static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+
+ writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+ return 0;
+}
+
+static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+ u32 bit = 1 << offset;
+
+ return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+}
+
+static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+ u32 bit = 1 << offset;
+
+ if (val)
+ writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
+ else
+ writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+/* This structure is replicated for each GPIO block allocated at probe time */
+static struct gpio_chip nmk_gpio_template = {
+ .direction_input = nmk_gpio_make_input,
+ .get = nmk_gpio_get_input,
+ .direction_output = nmk_gpio_make_output,
+ .set = nmk_gpio_set_output,
+ .ngpio = NMK_GPIO_PER_CHIP,
+ .can_sleep = 0,
+};
+
+static int __init nmk_gpio_probe(struct amba_device *dev, struct amba_id *id)
+{
+ struct nmk_gpio_platform_data *pdata;
+ struct nmk_gpio_chip *nmk_chip;
+ struct gpio_chip *chip;
+ int ret;
+
+ pdata = dev->dev.platform_data;
+ ret = amba_request_regions(dev, pdata->name);
+ if (ret)
+ return ret;
+
+ nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
+ if (!nmk_chip) {
+ ret = -ENOMEM;
+ goto out_amba;
+ }
+ /*
+ * The virt address in nmk_chip->addr is in the nomadik register space,
+ * so we can simply convert the resource address, without remapping
+ */
+ nmk_chip->addr = io_p2v(dev->res.start);
+ nmk_chip->chip = nmk_gpio_template;
+ nmk_chip->parent_irq = pdata->parent_irq;
+
+ chip = &nmk_chip->chip;
+ chip->base = pdata->first_gpio;
+ chip->label = pdata->name;
+ chip->dev = &dev->dev;
+ chip->owner = THIS_MODULE;
+
+ ret = gpiochip_add(&nmk_chip->chip);
+ if (ret)
+ goto out_free;
+
+ amba_set_drvdata(dev, nmk_chip);
+
+ nmk_gpio_init_irq(nmk_chip);
+
+ dev_info(&dev->dev, "Bits %i-%i at address %p\n",
+ nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr);
+ return 0;
+
+ out_free:
+ kfree(nmk_chip);
+ out_amba:
+ amba_release_regions(dev);
+ dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
+ pdata->first_gpio, pdata->first_gpio+31);
+ return ret;
+}
+
+static int nmk_gpio_remove(struct amba_device *dev)
+{
+ struct nmk_gpio_chip *nmk_chip;
+
+ nmk_chip = amba_get_drvdata(dev);
+ gpiochip_remove(&nmk_chip->chip);
+ kfree(nmk_chip);
+ amba_release_regions(dev);
+ return 0;
+}
+
+
+/* We have 0x1f080060 and 0x1f180060, accept both using the mask */
+static struct amba_id nmk_gpio_ids[] = {
+ {
+ .id = 0x1f080060,
+ .mask = 0xffefffff,
+ },
+ {0, 0},
+};
+
+static struct amba_driver nmk_gpio_driver = {
+ .drv = {
+ .owner = THIS_MODULE,
+ .name = "gpio",
+ },
+ .probe = nmk_gpio_probe,
+ .remove = nmk_gpio_remove,
+ .suspend = NULL, /* to be done */
+ .resume = NULL,
+ .id_table = nmk_gpio_ids,
+};
+
+static int __init nmk_gpio_init(void)
+{
+ return amba_driver_register(&nmk_gpio_driver);
+}
+
+arch_initcall(nmk_gpio_init);
+
+MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
+MODULE_DESCRIPTION("Nomadik GPIO Driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/arch/arm/mach-nomadik/i2c-8815nhk.c b/arch/arm/mach-nomadik/i2c-8815nhk.c
new file mode 100644
index 000000000000..abfe25a08d6b
--- /dev/null
+++ b/arch/arm/mach-nomadik/i2c-8815nhk.c
@@ -0,0 +1,65 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+/*
+ * There are two busses in the 8815NHK.
+ * They could, in theory, be driven by the hardware component, but we
+ * use bit-bang through GPIO by now, to keep things simple
+ */
+
+static struct i2c_gpio_platform_data nhk8815_i2c_data0 = {
+ /* keep defaults for timeouts; pins are push-pull bidirectional */
+ .scl_pin = 62,
+ .sda_pin = 63,
+};
+
+static struct i2c_gpio_platform_data nhk8815_i2c_data1 = {
+ /* keep defaults for timeouts; pins are push-pull bidirectional */
+ .scl_pin = 53,
+ .sda_pin = 54,
+};
+
+/* first bus: GPIO XX and YY */
+static struct platform_device nhk8815_i2c_dev0 = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &nhk8815_i2c_data0,
+ },
+};
+/* second bus: GPIO XX and YY */
+static struct platform_device nhk8815_i2c_dev1 = {
+ .name = "i2c-gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &nhk8815_i2c_data1,
+ },
+};
+
+static int __init nhk8815_i2c_init(void)
+{
+ nmk_gpio_set_mode(nhk8815_i2c_data0.scl_pin, NMK_GPIO_ALT_GPIO);
+ nmk_gpio_set_mode(nhk8815_i2c_data0.sda_pin, NMK_GPIO_ALT_GPIO);
+ platform_device_register(&nhk8815_i2c_dev0);
+
+ nmk_gpio_set_mode(nhk8815_i2c_data1.scl_pin, NMK_GPIO_ALT_GPIO);
+ nmk_gpio_set_mode(nhk8815_i2c_data1.sda_pin, NMK_GPIO_ALT_GPIO);
+ platform_device_register(&nhk8815_i2c_dev1);
+
+ return 0;
+}
+
+static void __exit nhk8815_i2c_exit(void)
+{
+ platform_device_unregister(&nhk8815_i2c_dev0);
+ platform_device_unregister(&nhk8815_i2c_dev1);
+ return;
+}
+
+module_init(nhk8815_i2c_init);
+module_exit(nhk8815_i2c_exit);
diff --git a/arch/arm/mach-nomadik/include/mach/clkdev.h b/arch/arm/mach-nomadik/include/mach/clkdev.h
new file mode 100644
index 000000000000..04b37a89801c
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/clkdev.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-nomadik/include/mach/debug-macro.S b/arch/arm/mach-nomadik/include/mach/debug-macro.S
new file mode 100644
index 000000000000..e876990e1569
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/debug-macro.S
@@ -0,0 +1,22 @@
+/*
+ * Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+ .macro addruart,rx
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ moveq \rx, #0x10000000 @ physical base address
+ movne \rx, #0xf0000000 @ virtual base
+ add \rx, \rx, #0x00100000
+ add \rx, \rx, #0x000fb000
+ .endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-nomadik/include/mach/entry-macro.S b/arch/arm/mach-nomadik/include/mach/entry-macro.S
new file mode 100644
index 000000000000..49f1aa3bb420
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/entry-macro.S
@@ -0,0 +1,43 @@
+/*
+ * Low-level IRQ helper macros for Nomadik platforms
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ ldr \base, =IO_ADDRESS(NOMADIK_IC_BASE)
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+ /* This stanza gets the irq mask from one of two status registers */
+ mov \irqnr, #0
+ ldr \irqstat, [\base, #VIC_REG_IRQSR0] @ get masked status
+ cmp \irqstat, #0
+ bne 1001f
+ add \irqnr, \irqnr, #32
+ ldr \irqstat, [\base, #VIC_REG_IRQSR1] @ get masked status
+
+1001: tst \irqstat, #15
+ bne 1002f
+ add \irqnr, \irqnr, #4
+ movs \irqstat, \irqstat, lsr #4
+ bne 1001b
+1002: tst \irqstat, #1
+ bne 1003f
+ add \irqnr, \irqnr, #1
+ movs \irqstat, \irqstat, lsr #1
+ bne 1002b
+1003: /* EQ will be set if no irqs pending */
+ .endm
diff --git a/arch/arm/mach-nomadik/include/mach/gpio.h b/arch/arm/mach-nomadik/include/mach/gpio.h
new file mode 100644
index 000000000000..61577c9f9a7d
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/gpio.h
@@ -0,0 +1,71 @@
+/*
+ * Structures and registers for GPIO access in the Nomadik SoC
+ *
+ * Copyright (C) 2008 STMicroelectronics
+ * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+/*
+ * These currently cause a function call to happen, they may be optimized
+ * if needed by adding cpu-specific defines to identify blocks
+ * (see mach-pxa/include/mach/gpio.h as an example using GPLR etc)
+ */
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
+
+/*
+ * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving
+ * the "gpio" namespace for generic and cross-machine functions
+ */
+
+/* Register in the logic block */
+#define NMK_GPIO_DAT 0x00
+#define NMK_GPIO_DATS 0x04
+#define NMK_GPIO_DATC 0x08
+#define NMK_GPIO_PDIS 0x0c
+#define NMK_GPIO_DIR 0x10
+#define NMK_GPIO_DIRS 0x14
+#define NMK_GPIO_DIRC 0x18
+#define NMK_GPIO_SLPC 0x1c
+#define NMK_GPIO_AFSLA 0x20
+#define NMK_GPIO_AFSLB 0x24
+
+#define NMK_GPIO_RIMSC 0x40
+#define NMK_GPIO_FIMSC 0x44
+#define NMK_GPIO_IS 0x48
+#define NMK_GPIO_IC 0x4c
+#define NMK_GPIO_RWIMSC 0x50
+#define NMK_GPIO_FWIMSC 0x54
+#define NMK_GPIO_WKS 0x58
+
+/* Alternate functions: function C is set in hw by setting both A and B */
+#define NMK_GPIO_ALT_GPIO 0
+#define NMK_GPIO_ALT_A 1
+#define NMK_GPIO_ALT_B 2
+#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
+
+extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
+extern int nmk_gpio_get_mode(int gpio);
+
+/*
+ * Platform data to register a block: only the initial gpio/irq number.
+ */
+struct nmk_gpio_platform_data {
+ char *name;
+ int first_gpio;
+ int first_irq;
+ int parent_irq;
+};
+
+#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-nomadik/include/mach/hardware.h b/arch/arm/mach-nomadik/include/mach/hardware.h
new file mode 100644
index 000000000000..6316dba3bfc8
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/hardware.h
@@ -0,0 +1,90 @@
+/*
+ * This file contains the hardware definitions of the Nomadik.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/* Nomadik registers live from 0x1000.0000 to 0x1023.0000 -- currently */
+#define NOMADIK_IO_VIRTUAL 0xF0000000 /* VA of IO */
+#define NOMADIK_IO_PHYSICAL 0x10000000 /* PA of IO */
+#define NOMADIK_IO_SIZE 0x00300000 /* 3MB for all regs */
+
+/* used in C code, so cast to proper type */
+#define io_p2v(x) ((void __iomem *)(x) \
+ - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
+#define io_v2p(x) ((unsigned long)(x) \
+ - NOMADIK_IO_VIRTUAL + NOMADIK_IO_PHYSICAL)
+
+/* used in asm code, so no casts */
+#define IO_ADDRESS(x) ((x) - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
+
+/*
+ * Base address defination for Nomadik Onchip Logic Block
+ */
+#define NOMADIK_FSMC_BASE 0x10100000 /* FSMC registers */
+#define NOMADIK_SDRAMC_BASE 0x10110000 /* SDRAM Controller */
+#define NOMADIK_CLCDC_BASE 0x10120000 /* CLCD Controller */
+#define NOMADIK_MDIF_BASE 0x10120000 /* MDIF */
+#define NOMADIK_DMA0_BASE 0x10130000 /* DMA0 Controller */
+#define NOMADIK_IC_BASE 0x10140000 /* Vectored Irq Controller */
+#define NOMADIK_DMA1_BASE 0x10150000 /* DMA1 Controller */
+#define NOMADIK_USB_BASE 0x10170000 /* USB-OTG conf reg base */
+#define NOMADIK_CRYP_BASE 0x10180000 /* Crypto processor */
+#define NOMADIK_SHA1_BASE 0x10190000 /* SHA-1 Processor */
+#define NOMADIK_XTI_BASE 0x101A0000 /* XTI */
+#define NOMADIK_RNG_BASE 0x101B0000 /* Random number generator */
+#define NOMADIK_SRC_BASE 0x101E0000 /* SRC base */
+#define NOMADIK_WDOG_BASE 0x101E1000 /* Watchdog */
+#define NOMADIK_MTU0_BASE 0x101E2000 /* Multiple Timer 0 */
+#define NOMADIK_MTU1_BASE 0x101E3000 /* Multiple Timer 1 */
+#define NOMADIK_GPIO0_BASE 0x101E4000 /* GPIO0 */
+#define NOMADIK_GPIO1_BASE 0x101E5000 /* GPIO1 */
+#define NOMADIK_GPIO2_BASE 0x101E6000 /* GPIO2 */
+#define NOMADIK_GPIO3_BASE 0x101E7000 /* GPIO3 */
+#define NOMADIK_RTC_BASE 0x101E8000 /* Real Time Clock base */
+#define NOMADIK_PMU_BASE 0x101E9000 /* Power Management Unit */
+#define NOMADIK_OWM_BASE 0x101EA000 /* One wire master */
+#define NOMADIK_SCR_BASE 0x101EF000 /* Secure Control registers */
+#define NOMADIK_MSP2_BASE 0x101F0000 /* MSP 2 interface */
+#define NOMADIK_MSP1_BASE 0x101F1000 /* MSP 1 interface */
+#define NOMADIK_UART2_BASE 0x101F2000 /* UART 2 interface */
+#define NOMADIK_SSIRx_BASE 0x101F3000 /* SSI 8-ch rx interface */
+#define NOMADIK_SSITx_BASE 0x101F4000 /* SSI 8-ch tx interface */
+#define NOMADIK_MSHC_BASE 0x101F5000 /* Memory Stick(Pro) Host */
+#define NOMADIK_SDI_BASE 0x101F6000 /* SD-card/MM-Card */
+#define NOMADIK_I2C1_BASE 0x101F7000 /* I2C1 interface */
+#define NOMADIK_I2C0_BASE 0x101F8000 /* I2C0 interface */
+#define NOMADIK_MSP0_BASE 0x101F9000 /* MSP 0 interface */
+#define NOMADIK_FIRDA_BASE 0x101FA000 /* FIrDA interface */
+#define NOMADIK_UART1_BASE 0x101FB000 /* UART 1 interface */
+#define NOMADIK_SSP_BASE 0x101FC000 /* SSP interface */
+#define NOMADIK_UART0_BASE 0x101FD000 /* UART 0 interface */
+#define NOMADIK_SGA_BASE 0x101FE000 /* SGA interface */
+#define NOMADIK_L2CC_BASE 0x10210000 /* L2 Cache controller */
+
+/* Other ranges, not for p2v/v2p */
+#define NOMADIK_BACKUP_RAM 0x80010000
+#define NOMADIK_EBROM 0x80000000 /* Embedded boot ROM */
+#define NOMADIK_HAMACV_DMEM_BASE 0xA0100000 /* HAMACV Data Memory Start */
+#define NOMADIK_HAMACV_DMEM_END 0xA01FFFFF /* HAMACV Data Memory End */
+#define NOMADIK_HAMACA_DMEM 0xA0200000 /* HAMACA Data Memory Space */
+
+#define NOMADIK_FSMC_VA IO_ADDRESS(NOMADIK_FSMC_BASE)
+#define NOMADIK_MTU0_VA IO_ADDRESS(NOMADIK_MTU0_BASE)
+#define NOMADIK_MTU1_VA IO_ADDRESS(NOMADIK_MTU1_BASE)
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-nomadik/include/mach/io.h b/arch/arm/mach-nomadik/include/mach/io.h
new file mode 100644
index 000000000000..2e1eca1b8243
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/io.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-nomadik/include/mach/io.h (copied from mach-sa1100)
+ *
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * Modifications:
+ * 06-12-1997 RMK Created.
+ * 07-04-1999 RMK Major cleanup
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a) __typesafe_io(a)
+#define __mem_pci(a) (a)
+
+#endif
diff --git a/arch/arm/mach-nomadik/include/mach/irqs.h b/arch/arm/mach-nomadik/include/mach/irqs.h
new file mode 100644
index 000000000000..8faabc560398
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/irqs.h
@@ -0,0 +1,82 @@
+/*
+ * mach-nomadik/include/mach/irqs.h
+ *
+ * Copyright (C) ST Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#include <mach/hardware.h>
+
+#define IRQ_VIC_START 0 /* first VIC interrupt is 0 */
+
+/*
+ * Interrupt numbers generic for all Nomadik Chip cuts
+ */
+#define IRQ_WATCHDOG 0
+#define IRQ_SOFTINT 1
+#define IRQ_CRYPTO 2
+#define IRQ_OWM 3
+#define IRQ_MTU0 4
+#define IRQ_MTU1 5
+#define IRQ_GPIO0 6
+#define IRQ_GPIO1 7
+#define IRQ_GPIO2 8
+#define IRQ_GPIO3 9
+#define IRQ_RTC_RTT 10
+#define IRQ_SSP 11
+#define IRQ_UART0 12
+#define IRQ_DMA1 13
+#define IRQ_CLCD_MDIF 14
+#define IRQ_DMA0 15
+#define IRQ_PWRFAIL 16
+#define IRQ_UART1 17
+#define IRQ_FIRDA 18
+#define IRQ_MSP0 19
+#define IRQ_I2C0 20
+#define IRQ_I2C1 21
+#define IRQ_SDMMC 22
+#define IRQ_USBOTG 23
+#define IRQ_SVA_IT0 24
+#define IRQ_SVA_IT1 25
+#define IRQ_SAA_IT0 26
+#define IRQ_SAA_IT1 27
+#define IRQ_UART2 28
+#define IRQ_MSP2 31
+#define IRQ_L2CC 48
+#define IRQ_HPI 49
+#define IRQ_SKE 50
+#define IRQ_KP 51
+#define IRQ_MEMST 54
+#define IRQ_SGA_IT 58
+#define IRQ_USBM 60
+#define IRQ_MSP1 62
+
+#define NOMADIK_SOC_NR_IRQS 64
+
+/* After chip-specific IRQ numbers we have the GPIO ones */
+#define NOMADIK_NR_GPIO 128 /* last 4 not wired to pins */
+#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + NOMADIK_SOC_NR_IRQS)
+#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - NOMADIK_SOC_NR_IRQS)
+#define NR_IRQS NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+
+/* Following two are used by entry_macro.S, to access our dual-vic */
+#define VIC_REG_IRQSR0 0
+#define VIC_REG_IRQSR1 0x20
+
+#endif /* __ASM_ARCH_IRQS_H */
+
diff --git a/arch/arm/mach-nomadik/include/mach/memory.h b/arch/arm/mach-nomadik/include/mach/memory.h
new file mode 100644
index 000000000000..1e5689d98ecd
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/memory.h
@@ -0,0 +1,28 @@
+/*
+ * mach-nomadik/include/mach/memory.h
+ *
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-nomadik/include/mach/mtu.h b/arch/arm/mach-nomadik/include/mach/mtu.h
new file mode 100644
index 000000000000..76da7f085330
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/mtu.h
@@ -0,0 +1,45 @@
+#ifndef __ASM_ARCH_MTU_H
+#define __ASM_ARCH_MTU_H
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
+#define MTU_RIS 0x04 /* Raw interrupt status */
+#define MTU_MIS 0x08 /* Masked interrupt status */
+#define MTU_ICR 0x0C /* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
+#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
+#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
+#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA 0x80
+#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK 0x0c
+#define MTU_CRn_PRESCALE_1 0x00
+#define MTU_CRn_PRESCALE_16 0x04
+#define MTU_CRn_PRESCALE_256 0x08
+#define MTU_CRn_32BITS 0x02
+#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR 0xff0
+#define MTU_ITOP 0xff4
+
+#define MTU_PERIPH_ID0 0xfe0
+#define MTU_PERIPH_ID1 0xfe4
+#define MTU_PERIPH_ID2 0xfe8
+#define MTU_PERIPH_ID3 0xfeC
+
+#define MTU_PCELL0 0xff0
+#define MTU_PCELL1 0xff4
+#define MTU_PCELL2 0xff8
+#define MTU_PCELL3 0xffC
+
+#endif /* __ASM_ARCH_MTU_H */
+
diff --git a/arch/arm/mach-nomadik/include/mach/setup.h b/arch/arm/mach-nomadik/include/mach/setup.h
new file mode 100644
index 000000000000..a4e468cf63da
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/setup.h
@@ -0,0 +1,22 @@
+
+/*
+ * These symbols are needed for board-specific files to call their
+ * own cpu-specific files
+ */
+
+#ifndef __ASM_ARCH_SETUP_H
+#define __ASM_ARCH_SETUP_H
+
+#include <asm/mach/time.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_NOMADIK_8815
+
+extern void cpu8815_map_io(void);
+extern void cpu8815_platform_init(void);
+extern void cpu8815_init_irq(void);
+extern struct sys_timer nomadik_timer;
+
+#endif /* NOMADIK_8815 */
+
+#endif /* __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-nomadik/include/mach/system.h b/arch/arm/mach-nomadik/include/mach/system.h
new file mode 100644
index 000000000000..7119f688116e
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/system.h
@@ -0,0 +1,45 @@
+/*
+ * mach-nomadik/include/mach/system.h
+ *
+ * Copyright (C) 2008 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+static inline void arch_idle(void)
+{
+ /*
+ * This should do all the clock switching
+ * and wait for interrupt tricks
+ */
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+ void __iomem *src_rstsr = io_p2v(NOMADIK_SRC_BASE + 0x18);
+
+ /* FIXME: use egpio when implemented */
+
+ /* Write anything to Reset status register */
+ writel(1, src_rstsr);
+}
+
+#endif
diff --git a/arch/arm/mach-nomadik/include/mach/timex.h b/arch/arm/mach-nomadik/include/mach/timex.h
new file mode 100644
index 000000000000..318b8896ce96
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/timex.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+#define CLOCK_TICK_RATE 2400000
+
+#endif
diff --git a/arch/arm/mach-nomadik/include/mach/uncompress.h b/arch/arm/mach-nomadik/include/mach/uncompress.h
new file mode 100644
index 000000000000..071003bc8456
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/uncompress.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+
+/* we need the constants in amba/serial.h, but it refers to amba_device */
+struct amba_device;
+#include <linux/amba/serial.h>
+
+#define NOMADIK_UART_DR 0x101FB000
+#define NOMADIK_UART_LCRH 0x101FB02c
+#define NOMADIK_UART_CR 0x101FB030
+#define NOMADIK_UART_FR 0x101FB018
+
+static void putc(const char c)
+{
+ /* Do nothing if the UART is not enabled. */
+ if (!(readb(NOMADIK_UART_CR) & UART01x_CR_UARTEN))
+ return;
+
+ if (c == '\n')
+ putc('\r');
+
+ while (readb(NOMADIK_UART_FR) & UART01x_FR_TXFF)
+ barrier();
+ writeb(c, NOMADIK_UART_DR);
+}
+
+static void flush(void)
+{
+ if (!(readb(NOMADIK_UART_CR) & UART01x_CR_UARTEN))
+ return;
+ while (readb(NOMADIK_UART_FR) & UART01x_FR_BUSY)
+ barrier();
+}
+
+static inline void arch_decomp_setup(void)
+{
+}
+
+#define arch_decomp_wdog() /* nothing to do here */
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-nomadik/include/mach/vmalloc.h b/arch/arm/mach-nomadik/include/mach/vmalloc.h
new file mode 100644
index 000000000000..be12e31ea528
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/vmalloc.h
@@ -0,0 +1,2 @@
+
+#define VMALLOC_END 0xe8000000
diff --git a/arch/arm/mach-nomadik/timer.c b/arch/arm/mach-nomadik/timer.c
new file mode 100644
index 000000000000..d1738e7061d4
--- /dev/null
+++ b/arch/arm/mach-nomadik/timer.c
@@ -0,0 +1,164 @@
+/*
+ * linux/arch/arm/mach-nomadik/timer.c
+ *
+ * Copyright (C) 2008 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/clockchips.h>
+#include <linux/jiffies.h>
+#include <asm/mach/time.h>
+#include <mach/mtu.h>
+
+#define TIMER_CTRL 0x80 /* No divisor */
+#define TIMER_PERIODIC 0x40
+#define TIMER_SZ32BIT 0x02
+
+/* Initial value for SRC control register: all timers use MXTAL/8 source */
+#define SRC_CR_INIT_MASK 0x00007fff
+#define SRC_CR_INIT_VAL 0x2aaa8000
+
+static u32 nmdk_count; /* accumulated count */
+static u32 nmdk_cycle; /* write-once */
+static __iomem void *mtu_base;
+
+/*
+ * clocksource: the MTU device is a decrementing counters, so we negate
+ * the value being read.
+ */
+static cycle_t nmdk_read_timer(struct clocksource *cs)
+{
+ u32 count = readl(mtu_base + MTU_VAL(0));
+ return nmdk_count + nmdk_cycle - count;
+
+}
+
+static struct clocksource nmdk_clksrc = {
+ .name = "mtu_0",
+ .rating = 120,
+ .read = nmdk_read_timer,
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * Clockevent device: currently only periodic mode is supported
+ */
+static void nmdk_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ unsigned long flags;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* enable interrupts -- and count current value? */
+ raw_local_irq_save(flags);
+ writel(readl(mtu_base + MTU_IMSC) | 1, mtu_base + MTU_IMSC);
+ raw_local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ BUG(); /* Not supported, yet */
+ /* FALLTHROUGH */
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* disable irq */
+ raw_local_irq_save(flags);
+ writel(readl(mtu_base + MTU_IMSC) & ~1, mtu_base + MTU_IMSC);
+ raw_local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device nmdk_clkevt = {
+ .name = "mtu_0",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 100,
+ .set_mode = nmdk_clkevt_mode,
+};
+
+/*
+ * IRQ Handler for the timer 0 of the MTU block. The irq is not shared
+ * as we are the only users of mtu0 by now.
+ */
+static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
+{
+ /* ack: "interrupt clear register" */
+ writel( 1 << 0, mtu_base + MTU_ICR);
+
+ /* we can't count lost ticks, unfortunately */
+ nmdk_count += nmdk_cycle;
+ nmdk_clkevt.event_handler(&nmdk_clkevt);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static struct irqaction nmdk_timer_irq = {
+ .name = "Nomadik Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = nmdk_timer_interrupt,
+};
+
+static void nmdk_timer_reset(void)
+{
+ u32 cr;
+
+ writel(0, mtu_base + MTU_CR(0)); /* off */
+
+ /* configure load and background-load, and fire it up */
+ writel(nmdk_cycle, mtu_base + MTU_LR(0));
+ writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
+ cr = MTU_CRn_PERIODIC | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS;
+ writel(cr, mtu_base + MTU_CR(0));
+ writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
+}
+
+static void __init nmdk_timer_init(void)
+{
+ u32 src_cr;
+ unsigned long rate;
+ int bits;
+
+ rate = CLOCK_TICK_RATE; /* 2.4MHz */
+ nmdk_cycle = (rate + HZ/2) / HZ;
+
+ /* Configure timer sources in "system reset controller" ctrl reg */
+ src_cr = readl(io_p2v(NOMADIK_SRC_BASE));
+ src_cr &= SRC_CR_INIT_MASK;
+ src_cr |= SRC_CR_INIT_VAL;
+ writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
+
+ /* Save global pointer to mtu, used by functions above */
+ mtu_base = io_p2v(NOMADIK_MTU0_BASE);
+
+ /* Init the timer and register clocksource */
+ nmdk_timer_reset();
+
+ nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
+ bits = 8*sizeof(nmdk_count);
+ nmdk_clksrc.mask = CLOCKSOURCE_MASK(bits);
+
+ clocksource_register(&nmdk_clksrc);
+
+ /* Register irq and clockevents */
+ setup_irq(IRQ_MTU0, &nmdk_timer_irq);
+ nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
+ nmdk_clkevt.cpumask = cpumask_of(0);
+ clockevents_register_device(&nmdk_clkevt);
+}
+
+struct sys_timer nomadik_timer = {
+ .init = nmdk_timer_init,
+};
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index a2d7814896be..505d98cfe508 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -19,7 +19,6 @@
#include <mach/irqs.h>
#include <mach/dma.h>
-#include <mach/irqs.h>
#include <mach/mux.h>
#include <mach/cpu.h>
#include <mach/mcbsp.h>
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index d3cc145814d0..cf3dd771a678 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -25,6 +25,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl4030.h>
+#include <linux/usb/otg.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -307,6 +308,10 @@ static void __init omap3_evm_init(void)
ARRAY_SIZE(omap3evm_spi_board_info));
omap_serial_init();
+#ifdef CONFIG_NOP_USB_XCEIV
+ /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */
+ usb_nop_xceiv_register();
+#endif
usb_musb_init();
ads7846_dev_init();
}
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index a5c0f0435cd6..99b6e1546311 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -19,7 +19,6 @@
#include <mach/irqs.h>
#include <mach/dma.h>
-#include <mach/irqs.h>
#include <mach/mux.h>
#include <mach/cpu.h>
#include <mach/mcbsp.h>
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index d85296dc896c..739e59e8025c 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -155,20 +155,6 @@ static struct platform_device musb_device = {
.resource = musb_resources,
};
-#ifdef CONFIG_NOP_USB_XCEIV
-static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device nop_xceiv_device = {
- .name = "nop_usb_xceiv",
- .id = -1,
- .dev = {
- .dma_mask = &nop_xceiv_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = NULL,
- },
-};
-#endif
-
void __init usb_musb_init(void)
{
if (cpu_is_omap243x())
@@ -183,13 +169,6 @@ void __init usb_musb_init(void)
*/
musb_plat.clock = "ick";
-#ifdef CONFIG_NOP_USB_XCEIV
- if (platform_device_register(&nop_xceiv_device) < 0) {
- printk(KERN_ERR "Unable to register NOP-XCEIV device\n");
- return;
- }
-#endif
-
if (platform_device_register(&musb_device) < 0) {
printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
return;
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 89c992b8f75b..6ebea5e1b304 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -371,6 +371,15 @@ config MACH_PALMTE2
Say Y here if you intend to run this kernel on a Palm Tungsten|E2
handheld computer.
+config MACH_PALMTC
+ bool "Palm Tungsten|C"
+ default y
+ depends on ARCH_PXA_PALM
+ select PXA25x
+ help
+ Say Y here if you intend to run this kernel on a Palm Tungsten|C
+ handheld computer.
+
config MACH_PALMT5
bool "Palm Tungsten|T5"
default y
@@ -458,6 +467,7 @@ config PXA_EZX
select PXA27x
select IWMMXT
select HAVE_PWM
+ select PXA_HAVE_BOARD_IRQS
config MACH_EZX_A780
bool "Motorola EZX A780"
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index d4c6122a342f..aa8f83e9421e 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -58,6 +58,7 @@ 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
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index 1d2cec25391d..59292181088c 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -271,56 +271,12 @@ static inline void cmx270_init_ohci(void) {}
#endif
#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
-static int cmx270_mci_init(struct device *dev,
- irq_handler_t cmx270_detect_int,
- void *data)
-{
- int err;
-
- err = gpio_request(GPIO105_MMC_POWER, "MMC/SD power");
- if (err) {
- dev_warn(dev, "power gpio unavailable\n");
- return err;
- }
-
- gpio_direction_output(GPIO105_MMC_POWER, 0);
-
- err = request_irq(CMX270_MMC_IRQ, cmx270_detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- gpio_free(GPIO105_MMC_POWER);
- dev_err(dev, "cmx270_mci_init: MMC/SD: can't"
- " request MMC card detect IRQ\n");
- }
-
- return err;
-}
-
-static void cmx270_mci_setpower(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
-
- if ((1 << vdd) & p_d->ocr_mask) {
- dev_dbg(dev, "power on\n");
- gpio_set_value(GPIO105_MMC_POWER, 0);
- } else {
- gpio_set_value(GPIO105_MMC_POWER, 1);
- dev_dbg(dev, "power off\n");
- }
-}
-
-static void cmx270_mci_exit(struct device *dev, void *data)
-{
- free_irq(CMX270_MMC_IRQ, data);
- gpio_free(GPIO105_MMC_POWER);
-}
-
static struct pxamci_platform_data cmx270_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = cmx270_mci_init,
- .setpower = cmx270_mci_setpower,
- .exit = cmx270_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = GPIO83_MMC_IRQ,
+ .gpio_card_ro = -1,
+ .gpio_power = GPIO105_MMC_POWER,
+ .gpio_power_invert = 1,
};
static void __init cmx270_init_mmc(void)
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 465da26591bd..aac2cda60e09 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -306,68 +306,21 @@ static void cm_x300_mci_exit(struct device *dev, void *data)
}
static struct pxamci_platform_data cm_x300_mci_platform_data = {
- .detect_delay = 20,
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = cm_x300_mci_init,
- .exit = cm_x300_mci_exit,
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = cm_x300_mci_init,
+ .exit = cm_x300_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
-static int cm_x300_mci2_ro(struct device *dev)
-{
- return gpio_get_value(GPIO85_MMC2_WP);
-}
-
-static int cm_x300_mci2_init(struct device *dev,
- irq_handler_t cm_x300_detect_int,
- void *data)
-{
- int err;
-
- /*
- * setup GPIO for CM-X300 MMC controller
- */
- err = gpio_request(GPIO82_MMC2_IRQ, "mmc card detect");
- if (err)
- goto err_request_cd;
- gpio_direction_input(GPIO82_MMC2_IRQ);
-
- err = gpio_request(GPIO85_MMC2_WP, "mmc write protect");
- if (err)
- goto err_request_wp;
- gpio_direction_input(GPIO85_MMC2_WP);
-
- err = request_irq(CM_X300_MMC2_IRQ, cm_x300_detect_int,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: MMC/SD/SDIO: "
- "can't request card detect IRQ\n", __func__);
- goto err_request_irq;
- }
-
- return 0;
-
-err_request_irq:
- gpio_free(GPIO85_MMC2_WP);
-err_request_wp:
- gpio_free(GPIO82_MMC2_IRQ);
-err_request_cd:
- return err;
-}
-
-static void cm_x300_mci2_exit(struct device *dev, void *data)
-{
- free_irq(CM_X300_MMC2_IRQ, data);
- gpio_free(GPIO82_MMC2_IRQ);
- gpio_free(GPIO85_MMC2_WP);
-}
-
static struct pxamci_platform_data cm_x300_mci2_platform_data = {
- .detect_delay = 20,
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = cm_x300_mci2_init,
- .exit = cm_x300_mci2_exit,
- .get_ro = cm_x300_mci2_ro,
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = GPIO82_MMC2_IRQ,
+ .gpio_card_ro = GPIO85_MMC2_WP,
+ .gpio_power = -1,
};
static void __init cm_x300_init_mmc(void)
diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c
index 7c9c34c19ae2..37c239c56568 100644
--- a/arch/arm/mach-pxa/colibri-pxa300.c
+++ b/arch/arm/mach-pxa/colibri-pxa300.c
@@ -172,6 +172,7 @@ void __init colibri_pxa300_init(void)
{
colibri_pxa300_init_eth();
colibri_pxa300_init_ohci();
+ colibri_pxa3xx_init_nand();
colibri_pxa300_init_lcd();
colibri_pxa3xx_init_lcd(mfp_to_gpio(GPIO39_GPIO));
colibri_pxa310_init_ac97();
diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c
index a18d37b3c5e6..494572825c7d 100644
--- a/arch/arm/mach-pxa/colibri-pxa320.c
+++ b/arch/arm/mach-pxa/colibri-pxa320.c
@@ -164,15 +164,48 @@ static inline void __init colibri_pxa320_init_ac97(void)
static inline void colibri_pxa320_init_ac97(void) {}
#endif
+/*
+ * The following configuration is verified to work with the Toradex Orchid
+ * carrier board
+ */
+static mfp_cfg_t colibri_pxa320_uart_pin_config[] __initdata = {
+ /* UART 1 configuration (may be set by bootloader) */
+ GPIO99_UART1_CTS,
+ GPIO104_UART1_RTS,
+ GPIO97_UART1_RXD,
+ GPIO98_UART1_TXD,
+ GPIO101_UART1_DTR,
+ GPIO103_UART1_DSR,
+ GPIO100_UART1_DCD,
+ GPIO102_UART1_RI,
+
+ /* UART 2 configuration */
+ GPIO109_UART2_CTS,
+ GPIO112_UART2_RTS,
+ GPIO110_UART2_RXD,
+ GPIO111_UART2_TXD,
+
+ /* UART 3 configuration */
+ GPIO30_UART3_RXD,
+ GPIO31_UART3_TXD,
+};
+
+static void __init colibri_pxa320_init_uart(void)
+{
+ pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa320_uart_pin_config));
+}
+
void __init colibri_pxa320_init(void)
{
colibri_pxa320_init_eth();
colibri_pxa320_init_ohci();
+ colibri_pxa3xx_init_nand();
colibri_pxa320_init_lcd();
colibri_pxa3xx_init_lcd(mfp_to_gpio(GPIO49_GPIO));
colibri_pxa320_init_ac97();
colibri_pxa3xx_init_mmc(ARRAY_AND_SIZE(colibri_pxa320_mmc_pin_config),
mfp_to_gpio(MFP_PIN_GPIO28));
+ colibri_pxa320_init_uart();
}
MACHINE_START(COLIBRI320, "Toradex Colibri PXA320")
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index ea34e34f8cd8..efebaf4d734d 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -25,6 +25,7 @@
#include <mach/colibri.h>
#include <mach/mmc.h>
#include <mach/pxafb.h>
+#include <mach/pxa3xx_nand.h>
#include "generic.h"
#include "devices.h"
@@ -95,10 +96,13 @@ static void colibri_pxa3xx_mci_exit(struct device *dev, void *data)
}
static struct pxamci_platform_data colibri_pxa3xx_mci_platform_data = {
- .detect_delay = 20,
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .init = colibri_pxa3xx_mci_init,
- .exit = colibri_pxa3xx_mci_exit,
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .init = colibri_pxa3xx_mci_init,
+ .exit = colibri_pxa3xx_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
void __init colibri_pxa3xx_init_mmc(mfp_cfg_t *pins, int len, int detect_pin)
@@ -154,3 +158,43 @@ void __init colibri_pxa3xx_init_lcd(int bl_pin)
}
#endif
+#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+static struct mtd_partition colibri_nand_partitions[] = {
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_512K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_1M,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "fs",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct pxa3xx_nand_platform_data colibri_nand_info = {
+ .enable_arbiter = 1,
+ .keep_config = 1,
+ .parts = colibri_nand_partitions,
+ .nr_parts = ARRAY_SIZE(colibri_nand_partitions),
+};
+
+void __init colibri_pxa3xx_init_nand(void)
+{
+ pxa3xx_set_nand_info(&colibri_nand_info);
+}
+#endif
+
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 5363e1aea3fb..39a94585f97b 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -307,77 +307,11 @@ static struct platform_device corgiled_device = {
* The card detect interrupt isn't debounced so we delay it by 250ms
* to give the card a chance to fully insert/eject.
*/
-static struct pxamci_platform_data corgi_mci_platform_data;
-
-static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, void *data)
-{
- int err;
-
- err = gpio_request(CORGI_GPIO_nSD_DETECT, "nSD_DETECT");
- if (err)
- goto err_out;
-
- err = gpio_request(CORGI_GPIO_nSD_WP, "nSD_WP");
- if (err)
- goto err_free_1;
-
- err = gpio_request(CORGI_GPIO_SD_PWR, "SD_PWR");
- if (err)
- goto err_free_2;
-
- gpio_direction_input(CORGI_GPIO_nSD_DETECT);
- gpio_direction_input(CORGI_GPIO_nSD_WP);
- gpio_direction_output(CORGI_GPIO_SD_PWR, 0);
-
- corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
-
- err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
- __func__);
- goto err_free_3;
- }
- return 0;
-
-err_free_3:
- gpio_free(CORGI_GPIO_SD_PWR);
-err_free_2:
- gpio_free(CORGI_GPIO_nSD_WP);
-err_free_1:
- gpio_free(CORGI_GPIO_nSD_DETECT);
-err_out:
- return err;
-}
-
-static void corgi_mci_setpower(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data* p_d = dev->platform_data;
-
- gpio_set_value(CORGI_GPIO_SD_PWR, ((1 << vdd) & p_d->ocr_mask));
-}
-
-static int corgi_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(CORGI_GPIO_nSD_WP);
-}
-
-static void corgi_mci_exit(struct device *dev, void *data)
-{
- free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
- gpio_free(CORGI_GPIO_SD_PWR);
- gpio_free(CORGI_GPIO_nSD_WP);
- gpio_free(CORGI_GPIO_nSD_DETECT);
-}
-
static struct pxamci_platform_data corgi_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = corgi_mci_init,
- .get_ro = corgi_mci_get_ro,
- .setpower = corgi_mci_setpower,
- .exit = corgi_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = CORGI_GPIO_nSD_WP,
+ .gpio_power = CORGI_GPIO_SD_PWR,
};
@@ -636,6 +570,7 @@ static void __init corgi_init(void)
corgi_init_spi();
pxa_set_udc_info(&udc_info);
+ corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
pxa_set_mci_info(&corgi_mci_platform_data);
pxa_set_ficp_info(&corgi_ficp_platform_data);
pxa_set_i2c_info(NULL);
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index 7d3e1b46e550..79141f862728 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -130,61 +130,17 @@ static struct pxamci_platform_data csb726_mci_data;
static int csb726_mci_init(struct device *dev,
irq_handler_t detect, void *data)
{
- int err;
-
csb726_mci_data.detect_delay = msecs_to_jiffies(500);
-
- err = gpio_request(CSB726_GPIO_MMC_DETECT, "MMC detect");
- if (err)
- goto err_det_req;
-
- err = gpio_direction_input(CSB726_GPIO_MMC_DETECT);
- if (err)
- goto err_det_dir;
-
- err = gpio_request(CSB726_GPIO_MMC_RO, "MMC ro");
- if (err)
- goto err_ro_req;
-
- err = gpio_direction_input(CSB726_GPIO_MMC_RO);
- if (err)
- goto err_ro_dir;
-
- err = request_irq(gpio_to_irq(CSB726_GPIO_MMC_DETECT), detect,
- IRQF_DISABLED, "MMC card detect", data);
- if (err)
- goto err_irq;
-
return 0;
-
-err_irq:
-err_ro_dir:
- gpio_free(CSB726_GPIO_MMC_RO);
-err_ro_req:
-err_det_dir:
- gpio_free(CSB726_GPIO_MMC_DETECT);
-err_det_req:
- return err;
-}
-
-static int csb726_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(CSB726_GPIO_MMC_RO);
-}
-
-static void csb726_mci_exit(struct device *dev, void *data)
-{
- free_irq(gpio_to_irq(CSB726_GPIO_MMC_DETECT), data);
- gpio_free(CSB726_GPIO_MMC_RO);
- gpio_free(CSB726_GPIO_MMC_DETECT);
}
static struct pxamci_platform_data csb726_mci = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = csb726_mci_init,
- .get_ro = csb726_mci_get_ro,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = csb726_mci_init,
/* FIXME setpower */
- .exit = csb726_mci_exit,
+ .gpio_card_detect = CSB726_GPIO_MMC_DETECT,
+ .gpio_card_ro = CSB726_GPIO_MMC_RO,
+ .gpio_power = -1,
};
static struct pxaohci_platform_data csb726_ohci_platform_data = {
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index ecc08f360b68..46fabe1cca11 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -935,6 +935,33 @@ void __init pxa3xx_set_nand_info(struct pxa3xx_nand_platform_data *info)
{
pxa_register_device(&pxa3xx_device_nand, info);
}
+
+static struct resource pxa3xx_resources_gcu[] = {
+ {
+ .start = 0x54000000,
+ .end = 0x54000fff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_GCU,
+ .end = IRQ_GCU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 pxa3xx_gcu_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device pxa3xx_device_gcu = {
+ .name = "pxa3xx-gcu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(pxa3xx_resources_gcu),
+ .resource = pxa3xx_resources_gcu,
+ .dev = {
+ .dma_mask = &pxa3xx_gcu_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
#endif /* CONFIG_PXA3xx */
/* pxa2xx-spi platform-device ID equals respective SSP platform-device ID + 1.
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index ecc24a4dca6d..93817d99761e 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -35,4 +35,6 @@ extern struct platform_device pxa27x_device_pwm1;
extern struct platform_device pxa3xx_device_nand;
extern struct platform_device pxa3xx_device_i2c_power;
+extern struct platform_device pxa3xx_device_gcu;
+
void __init pxa_register_device(struct platform_device *dev, void *data);
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 63b10d9bb1d3..aec7f4214b14 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -646,13 +646,16 @@ static int em_x270_mci_get_ro(struct device *dev)
}
static struct pxamci_platform_data em_x270_mci_platform_data = {
- .ocr_mask = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23|
- MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27|
- MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|
- MMC_VDD_30_31|MMC_VDD_31_32,
- .init = em_x270_mci_init,
- .setpower = em_x270_mci_setpower,
- .exit = em_x270_mci_exit,
+ .ocr_mask = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23|
+ MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27|
+ MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|
+ MMC_VDD_30_31|MMC_VDD_31_32,
+ .init = em_x270_mci_init,
+ .setpower = em_x270_mci_setpower,
+ .exit = em_x270_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void __init em_x270_init_mmc(void)
@@ -1022,22 +1025,32 @@ static int em_x270_sensor_power(struct device *dev, int on)
return 0;
}
-static struct soc_camera_link iclink = {
- .bus_id = 0,
- .power = em_x270_sensor_power,
-};
-
static struct i2c_board_info em_x270_i2c_cam_info[] = {
{
I2C_BOARD_INFO("mt9m111", 0x48),
+ },
+};
+
+static struct soc_camera_link iclink = {
+ .bus_id = 0,
+ .power = em_x270_sensor_power,
+ .board_info = &em_x270_i2c_cam_info[0],
+ .i2c_adapter_id = 0,
+ .module_name = "mt9m111",
+};
+
+static struct platform_device em_x270_camera = {
+ .name = "soc-camera-pdrv",
+ .id = -1,
+ .dev = {
.platform_data = &iclink,
},
};
static void __init em_x270_init_camera(void)
{
- i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info));
pxa_set_camera_info(&em_x270_camera_platform_data);
+ platform_device_register(&em_x270_camera);
}
#else
static inline void em_x270_init_camera(void) {}
@@ -1103,6 +1116,7 @@ REGULATOR_CONSUMER(ldo5, NULL, "vcc cam");
REGULATOR_CONSUMER(ldo10, &pxa_device_mci.dev, "vcc sdio");
REGULATOR_CONSUMER(ldo12, NULL, "vcc usb");
REGULATOR_CONSUMER(ldo19, &em_x270_gprs_userspace_consumer.dev, "vcc gprs");
+REGULATOR_CONSUMER(buck2, NULL, "vcc_core");
#define REGULATOR_INIT(_ldo, _min_uV, _max_uV, _ops_mask) \
static struct regulator_init_data _ldo##_data = { \
@@ -1125,6 +1139,7 @@ REGULATOR_INIT(ldo10, 2000000, 3200000,
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE);
REGULATOR_INIT(ldo12, 3000000, 3000000, REGULATOR_CHANGE_STATUS);
REGULATOR_INIT(ldo19, 3200000, 3200000, REGULATOR_CHANGE_STATUS);
+REGULATOR_INIT(buck2, 1000000, 1650000, REGULATOR_CHANGE_VOLTAGE);
struct led_info em_x270_led_info = {
.name = "em-x270:orange",
@@ -1141,12 +1156,16 @@ struct power_supply_info em_x270_psy_info = {
static void em_x270_battery_low(void)
{
+#if defined(CONFIG_APM_EMULATION)
apm_queue_event(APM_LOW_BATTERY);
+#endif
}
static void em_x270_battery_critical(void)
{
+#if defined(CONFIG_APM_EMULATION)
apm_queue_event(APM_CRITICAL_SUSPEND);
+#endif
}
struct da9030_battery_info em_x270_batterty_info = {
@@ -1190,6 +1209,8 @@ struct da903x_subdev_info em_x270_da9030_subdevs[] = {
DA9030_LDO(12),
DA9030_LDO(19),
+ DA9030_SUBDEV(regulator, BUCK2, &buck2_data),
+
DA9030_SUBDEV(led, LED_PC, &em_x270_led_info),
DA9030_SUBDEV(backlight, WLED, &em_x270_led_info),
DA9030_SUBDEV(battery, BAT, &em_x270_batterty_info),
@@ -1241,7 +1262,6 @@ static void __init em_x270_init_i2c(void)
static void __init em_x270_module_init(void)
{
- pr_info("%s\n", __func__);
pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_pin_config));
mmc_cd = GPIO13_MMC_CD;
@@ -1253,7 +1273,6 @@ static void __init em_x270_module_init(void)
static void __init em_x270_exeda_init(void)
{
- pr_info("%s\n", __func__);
pxa2xx_mfp_config(ARRAY_AND_SIZE(exeda_pin_config));
mmc_cd = GPIO114_MMC_CD;
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index ca9912ea78d9..1708c0109844 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -88,7 +88,10 @@ static struct platform_device *devices[] __initdata = {
#ifdef CONFIG_MMC_PXA
static struct pxamci_platform_data gumstix_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void __init gumstix_mmc_init(void)
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index b6243b59d9be..b6486ef20b17 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -168,7 +168,10 @@ static struct pxafb_mach_info sharp_lm8v31 = {
};
static struct pxamci_platform_data idp_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void __init idp_init(void)
diff --git a/arch/arm/mach-pxa/imote2.c b/arch/arm/mach-pxa/imote2.c
index 961807dc6467..2a4945db31c5 100644
--- a/arch/arm/mach-pxa/imote2.c
+++ b/arch/arm/mach-pxa/imote2.c
@@ -389,6 +389,9 @@ static int imote2_mci_get_ro(struct device *dev)
static struct pxamci_platform_data imote2_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* default anyway */
.get_ro = imote2_mci_get_ro,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static struct mtd_partition imote2flash_partitions[] = {
diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h
index a88d7caff0d1..811743c56147 100644
--- a/arch/arm/mach-pxa/include/mach/colibri.h
+++ b/arch/arm/mach-pxa/include/mach/colibri.h
@@ -23,6 +23,12 @@ static inline void colibri_pxa3xx_init_lcd(int bl_pin) {}
extern void colibri_pxa3xx_init_eth(struct ax_plat_data *plat_data);
#endif
+#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
+extern void colibri_pxa3xx_init_nand(void);
+#else
+static inline void colibri_pxa3xx_init_nand(void) {}
+#endif
+
/* physical memory regions */
#define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */
diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 6a1d95993342..3fad82d3bf11 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -70,7 +70,7 @@
#define IRQ_CIR PXA_IRQ(34) /* Consumer IR */
#define IRQ_TSI PXA_IRQ(36) /* Touch Screen Interface (PXA320) */
#define IRQ_USIM2 PXA_IRQ(38) /* USIM2 Controller */
-#define IRQ_GRPHICS PXA_IRQ(39) /* Graphics Controller */
+#define IRQ_GCU PXA_IRQ(39) /* Graphics Controller */
#define IRQ_MMC2 PXA_IRQ(41) /* MMC2 Controller */
#define IRQ_1WIRE PXA_IRQ(44) /* 1-Wire Controller */
#define IRQ_NAND PXA_IRQ(45) /* NAND Controller */
@@ -105,6 +105,8 @@
#define IRQ_BOARD_END (IRQ_BOARD_START + 70)
#elif defined(CONFIG_MACH_ZYLONITE)
#define IRQ_BOARD_END (IRQ_BOARD_START + 32)
+#elif defined(CONFIG_PXA_EZX)
+#define IRQ_BOARD_END (IRQ_BOARD_START + 23)
#else
#define IRQ_BOARD_END (IRQ_BOARD_START + 16)
#endif
diff --git a/arch/arm/mach-pxa/include/mach/mmc.h b/arch/arm/mach-pxa/include/mach/mmc.h
index 6d1304c9270f..02a69dc2ee63 100644
--- a/arch/arm/mach-pxa/include/mach/mmc.h
+++ b/arch/arm/mach-pxa/include/mach/mmc.h
@@ -14,6 +14,11 @@ struct pxamci_platform_data {
int (*get_ro)(struct device *);
void (*setpower)(struct device *, unsigned int);
void (*exit)(struct device *, void *);
+ int gpio_card_detect; /* gpio detecting card insertion */
+ int gpio_card_ro; /* gpio detecting read only toggle */
+ bool gpio_card_ro_invert; /* gpio ro is inverted */
+ int gpio_power; /* gpio powering up MMC bus */
+ bool gpio_power_invert; /* gpio power is inverted */
};
extern void pxa_set_mci_info(struct pxamci_platform_data *info);
diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/include/mach/palmtc.h
new file mode 100644
index 000000000000..3dc9b074ab46
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/palmtc.h
@@ -0,0 +1,86 @@
+/*
+ * linux/include/asm-arm/arch-pxa/palmtc-gpio.h
+ *
+ * GPIOs and interrupts for Palm Tungsten|C Handheld Computer
+ *
+ * Authors: Alex Osborne <bobofdoom@gmail.com>
+ * Marek Vasut <marek.vasut@gmail.com>
+ * Holger Bocklet <bitz.email@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _INCLUDE_PALMTC_H_
+#define _INCLUDE_PALMTC_H_
+
+/** HERE ARE GPIOs **/
+
+/* GPIOs */
+#define GPIO_NR_PALMTC_EARPHONE_DETECT 2
+#define GPIO_NR_PALMTC_CRADLE_DETECT 5
+#define GPIO_NR_PALMTC_HOTSYNC_BUTTON 7
+
+/* SD/MMC */
+#define GPIO_NR_PALMTC_SD_DETECT_N 12
+#define GPIO_NR_PALMTC_SD_POWER 32
+#define GPIO_NR_PALMTC_SD_READONLY 54
+
+/* WLAN */
+#define GPIO_NR_PALMTC_PCMCIA_READY 13
+#define GPIO_NR_PALMTC_PCMCIA_PWRREADY 14
+#define GPIO_NR_PALMTC_PCMCIA_POWER1 15
+#define GPIO_NR_PALMTC_PCMCIA_POWER2 33
+#define GPIO_NR_PALMTC_PCMCIA_POWER3 55
+#define GPIO_NR_PALMTC_PCMCIA_RESET 78
+
+/* UDC */
+#define GPIO_NR_PALMTC_USB_DETECT_N 4
+#define GPIO_NR_PALMTC_USB_POWER 36
+
+/* LCD/BACKLIGHT */
+#define GPIO_NR_PALMTC_BL_POWER 16
+#define GPIO_NR_PALMTC_LCD_POWER 44
+#define GPIO_NR_PALMTC_LCD_BLANK 38
+
+/* UART */
+#define GPIO_NR_PALMTC_RS232_POWER 37
+
+/* IRDA */
+#define GPIO_NR_PALMTC_IR_DISABLE 45
+
+/* IRQs */
+#define IRQ_GPIO_PALMTC_SD_DETECT_N IRQ_GPIO(GPIO_NR_PALMTC_SD_DETECT_N)
+#define IRQ_GPIO_PALMTC_WLAN_READY IRQ_GPIO(GPIO_NR_PALMTC_WLAN_READY)
+
+/* UCB1400 GPIOs */
+#define GPIO_NR_PALMTC_POWER_DETECT (0x80 | 0x00)
+#define GPIO_NR_PALMTC_HEADPHONE_DETECT (0x80 | 0x01)
+#define GPIO_NR_PALMTC_SPEAKER_ENABLE (0x80 | 0x03)
+#define GPIO_NR_PALMTC_VIBRA_POWER (0x80 | 0x05)
+#define GPIO_NR_PALMTC_LED_POWER (0x80 | 0x07)
+
+/** HERE ARE INIT VALUES **/
+#define PALMTC_UCB1400_GPIO_OFFSET 0x80
+
+/* BATTERY */
+#define PALMTC_BAT_MAX_VOLTAGE 4000 /* 4.00V maximum voltage */
+#define PALMTC_BAT_MIN_VOLTAGE 3550 /* 3.55V critical voltage */
+#define PALMTC_BAT_MAX_CURRENT 0 /* unknokn */
+#define PALMTC_BAT_MIN_CURRENT 0 /* unknown */
+#define PALMTC_BAT_MAX_CHARGE 1 /* unknown */
+#define PALMTC_BAT_MIN_CHARGE 1 /* unknown */
+#define PALMTC_MAX_LIFE_MINS 240 /* on-life in minutes */
+
+#define PALMTC_BAT_MEASURE_DELAY (HZ * 1)
+
+/* BACKLIGHT */
+#define PALMTC_MAX_INTENSITY 0xFE
+#define PALMTC_DEFAULT_INTENSITY 0x7E
+#define PALMTC_LIMIT_MASK 0x7F
+#define PALMTC_PRESCALER 0x3F
+#define PALMTC_PERIOD_NS 3500
+
+#endif
diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h
index e74082c872e1..1be0db6ed55e 100644
--- a/arch/arm/mach-pxa/include/mach/palmtx.h
+++ b/arch/arm/mach-pxa/include/mach/palmtx.h
@@ -82,6 +82,11 @@
#define PALMTX_PHYS_FLASH_START PXA_CS0_PHYS /* ChipSelect 0 */
#define PALMTX_PHYS_NAND_START PXA_CS1_PHYS /* ChipSelect 1 */
+#define PALMTX_NAND_ALE_PHYS (PALMTX_PHYS_NAND_START | (1 << 24))
+#define PALMTX_NAND_CLE_PHYS (PALMTX_PHYS_NAND_START | (1 << 25))
+#define PALMTX_NAND_ALE_VIRT 0xff100000
+#define PALMTX_NAND_CLE_VIRT 0xff200000
+
/* TOUCHSCREEN */
#define AC97_LINK_FRAME 21
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h b/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
index d5a48a96dea7..63e8965ad85d 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
@@ -2,6 +2,7 @@
#define __ASM_ARCH_PXA27x_KEYPAD_H
#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
#define MAX_MATRIX_KEY_ROWS (8)
#define MAX_MATRIX_KEY_COLS (8)
@@ -51,8 +52,6 @@ struct pxa27x_keypad_platform_data {
unsigned int debounce_interval;
};
-#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
-
extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h b/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
index 7d1a059b3d43..e91d63cfe811 100644
--- a/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
+++ b/arch/arm/mach-pxa/include/mach/pxa3xx-regs.h
@@ -208,7 +208,7 @@
#define CKEN_MVED 43 /* < MVED clock enable */
/* Note: GCU clock enable bit differs on PXA300/PXA310 and PXA320 */
-#define PXA300_CKEN_GRAPHICS 42 /* Graphics controller clock enable */
-#define PXA320_CKEN_GRAPHICS 7 /* Graphics controller clock enable */
+#define CKEN_PXA300_GCU 42 /* Graphics controller clock enable */
+#define CKEN_PXA320_GCU 7 /* Graphics controller clock enable */
#endif /* __ASM_ARCH_PXA3XX_REGS_H */
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 55b3788fd1ae..13848955d133 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -265,45 +265,12 @@ static inline void littleton_init_keypad(void) {}
#endif
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
-static int littleton_mci_init(struct device *dev,
- irq_handler_t littleton_detect_int, void *data)
-{
- int err, gpio_cd = GPIO_MMC1_CARD_DETECT;
-
- err = gpio_request(gpio_cd, "mmc card detect");
- if (err)
- goto err_request_cd;
-
- gpio_direction_input(gpio_cd);
-
- err = request_irq(gpio_to_irq(gpio_cd), littleton_detect_int,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "mmc card detect", data);
- if (err) {
- dev_err(dev, "failed to request card detect IRQ\n");
- goto err_request_irq;
- }
- return 0;
-
-err_request_irq:
- gpio_free(gpio_cd);
-err_request_cd:
- return err;
-}
-
-static void littleton_mci_exit(struct device *dev, void *data)
-{
- int gpio_cd = GPIO_MMC1_CARD_DETECT;
-
- free_irq(gpio_to_irq(gpio_cd), data);
- gpio_free(gpio_cd);
-}
-
static struct pxamci_platform_data littleton_mci_platform_data = {
- .detect_delay = 20,
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .init = littleton_mci_init,
- .exit = littleton_mci_exit,
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_MMC1_CARD_DETECT,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void __init littleton_init_mmc(void)
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index f04c8333dff7..1785cc9494d9 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -482,11 +482,14 @@ static void lubbock_mci_exit(struct device *dev, void *data)
}
static struct pxamci_platform_data lubbock_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .detect_delay = 1,
- .init = lubbock_mci_init,
- .get_ro = lubbock_mci_get_ro,
- .exit = lubbock_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .detect_delay = 1,
+ .init = lubbock_mci_init,
+ .get_ro = lubbock_mci_get_ro,
+ .exit = lubbock_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void lubbock_irda_transceiver_mode(struct device *dev, int mode)
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index ca39669cffc5..0daba43d7ca1 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -651,55 +651,24 @@ static struct platform_device bq24022 = {
static int magician_mci_init(struct device *dev,
irq_handler_t detect_irq, void *data)
{
- int err;
-
- err = request_irq(IRQ_MAGICIAN_SD, detect_irq,
+ return request_irq(IRQ_MAGICIAN_SD, detect_irq,
IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
- "MMC card detect", data);
- if (err)
- goto err_request_irq;
- err = gpio_request(EGPIO_MAGICIAN_SD_POWER, "SD_POWER");
- if (err)
- goto err_request_power;
- err = gpio_request(EGPIO_MAGICIAN_nSD_READONLY, "nSD_READONLY");
- if (err)
- goto err_request_readonly;
-
- return 0;
-
-err_request_readonly:
- gpio_free(EGPIO_MAGICIAN_SD_POWER);
-err_request_power:
- free_irq(IRQ_MAGICIAN_SD, data);
-err_request_irq:
- return err;
-}
-
-static void magician_mci_setpower(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *pdata = dev->platform_data;
-
- gpio_set_value(EGPIO_MAGICIAN_SD_POWER, (1 << vdd) & pdata->ocr_mask);
-}
-
-static int magician_mci_get_ro(struct device *dev)
-{
- return (!gpio_get_value(EGPIO_MAGICIAN_nSD_READONLY));
+ "mmc card detect", data);
}
static void magician_mci_exit(struct device *dev, void *data)
{
- gpio_free(EGPIO_MAGICIAN_nSD_READONLY);
- gpio_free(EGPIO_MAGICIAN_SD_POWER);
free_irq(IRQ_MAGICIAN_SD, data);
}
static struct pxamci_platform_data magician_mci_info = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = magician_mci_init,
- .get_ro = magician_mci_get_ro,
- .setpower = magician_mci_setpower,
- .exit = magician_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = magician_mci_init,
+ .exit = magician_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = EGPIO_MAGICIAN_nSD_READONLY,
+ .gpio_card_ro_invert = 1,
+ .gpio_power = EGPIO_MAGICIAN_SD_POWER,
};
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index f4dabf0273ca..f7dc23078ce3 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -450,10 +450,13 @@ static void mainstone_mci_exit(struct device *dev, void *data)
}
static struct pxamci_platform_data mainstone_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = mainstone_mci_init,
- .setpower = mainstone_mci_setpower,
- .exit = mainstone_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = mainstone_mci_init,
+ .setpower = mainstone_mci_setpower,
+ .exit = mainstone_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static void mainstone_irda_transceiver_mode(struct device *dev, int mode)
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 2d28132c725b..3cab452e5567 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -434,72 +434,15 @@ struct gpio_vbus_mach_info gpio_vbus_data = {
/*
* SDIO/MMC Card controller
*/
-static void mci_setpower(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
-
- if ((1 << vdd) & p_d->ocr_mask)
- gpio_set_value(GPIO91_SDIO_EN, 1); /* enable SDIO power */
- else
- gpio_set_value(GPIO91_SDIO_EN, 0); /* disable SDIO power */
-}
-
-static int mci_get_ro(struct device *dev)
-{
- return gpio_get_value(GPIO78_SDIO_RO);
-}
-
-struct gpio_ress mci_gpios[] = {
- MIO_GPIO_IN(GPIO78_SDIO_RO, "SDIO readonly detect"),
- MIO_GPIO_IN(GPIO15_SDIO_INSERT, "SDIO insertion detect"),
- MIO_GPIO_OUT(GPIO91_SDIO_EN, 0, "SDIO power enable")
-};
-
-static void mci_exit(struct device *dev, void *data)
-{
- mio_gpio_free(ARRAY_AND_SIZE(mci_gpios));
- free_irq(gpio_to_irq(GPIO15_SDIO_INSERT), data);
-}
-
-static struct pxamci_platform_data mioa701_mci_info;
-
/**
* The card detect interrupt isn't debounced so we delay it by 250ms
* to give the card a chance to fully insert/eject.
*/
-static int mci_init(struct device *dev, irq_handler_t detect_int, void *data)
-{
- int rc;
- int irq = gpio_to_irq(GPIO15_SDIO_INSERT);
-
- rc = mio_gpio_request(ARRAY_AND_SIZE(mci_gpios));
- if (rc)
- goto err_gpio;
- /* enable RE/FE interrupt on card insertion and removal */
- rc = request_irq(irq, detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (rc)
- goto err_irq;
-
- mioa701_mci_info.detect_delay = msecs_to_jiffies(250);
- return 0;
-
-err_irq:
- dev_err(dev, "mioa701_mci_init: MMC/SD:"
- " can't request MMC card detect IRQ\n");
- mio_gpio_free(ARRAY_AND_SIZE(mci_gpios));
-err_gpio:
- return rc;
-}
-
static struct pxamci_platform_data mioa701_mci_info = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .init = mci_init,
- .get_ro = mci_get_ro,
- .setpower = mci_setpower,
- .exit = mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO15_SDIO_INSERT,
+ .gpio_card_ro = GPIO78_SDIO_RO,
+ .gpio_power = GPIO91_SDIO_EN,
};
/* FlashRAM */
@@ -765,19 +708,20 @@ static struct i2c_board_info __initdata mioa701_pi2c_devices[] = {
},
};
-static struct soc_camera_link iclink = {
- .bus_id = 0, /* Must match id in pxa27x_device_camera in device.c */
-};
-
/* Board I2C devices. */
static struct i2c_board_info __initdata mioa701_i2c_devices[] = {
{
- /* Must initialize before the camera(s) */
I2C_BOARD_INFO("mt9m111", 0x5d),
- .platform_data = &iclink,
},
};
+static struct soc_camera_link iclink = {
+ .bus_id = 0, /* Match id in pxa27x_device_camera in device.c */
+ .board_info = &mioa701_i2c_devices[0],
+ .i2c_adapter_id = 0,
+ .module_name = "mt9m111",
+};
+
struct i2c_pxa_platform_data i2c_pdata = {
.fast_mode = 1,
};
@@ -811,6 +755,7 @@ MIO_SIMPLE_DEV(pxa2xx_pcm, "pxa2xx-pcm", NULL)
MIO_SIMPLE_DEV(mioa701_sound, "mioa701-wm9713", NULL)
MIO_SIMPLE_DEV(mioa701_board, "mioa701-board", NULL)
MIO_SIMPLE_DEV(gpio_vbus, "gpio-vbus", &gpio_vbus_data);
+MIO_SIMPLE_DEV(mioa701_camera, "soc-camera-pdrv",&iclink);
static struct platform_device *devices[] __initdata = {
&mioa701_gpio_keys,
@@ -821,6 +766,7 @@ static struct platform_device *devices[] __initdata = {
&power_dev,
&strataflash,
&gpio_vbus,
+ &mioa701_camera,
&mioa701_board,
};
@@ -841,7 +787,7 @@ static void mioa701_restart(char c, const char *cmd)
static struct gpio_ress global_gpios[] = {
MIO_GPIO_OUT(GPIO9_CHARGE_EN, 1, "Charger enable"),
MIO_GPIO_OUT(GPIO18_POWEROFF, 0, "Power Off"),
- MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power")
+ MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power"),
};
static void __init mioa701_machine_init(void)
@@ -855,6 +801,7 @@ static void __init mioa701_machine_init(void)
mio_gpio_request(ARRAY_AND_SIZE(global_gpios));
bootstrap_init();
set_pxa_fb_info(&mioa701_pxafb_info);
+ mioa701_mci_info.detect_delay = msecs_to_jiffies(250);
pxa_set_mci_info(&mioa701_mci_info);
pxa_set_keypad_info(&mioa701_keypad_info);
wm97xx_bat_set_pdata(&mioa701_battery_data);
@@ -869,7 +816,6 @@ static void __init mioa701_machine_init(void)
pxa_set_i2c_info(&i2c_pdata);
pxa27x_set_i2c_power_info(NULL);
pxa_set_camera_info(&mioa701_pxacamera_platform_data);
- i2c_register_board_info(0, ARRAY_AND_SIZE(mioa701_i2c_devices));
}
static void mioa701_machine_exit(void)
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index ed70f281dd09..b3ae8b958ad6 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -25,6 +25,9 @@
#include <linux/wm97xx_batt.h>
#include <linux/power_supply.h>
#include <linux/sysdev.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -128,6 +131,10 @@ static unsigned long palmld_pin_config[] __initdata = {
GPIO38_GPIO, /* wifi ready */
GPIO81_GPIO, /* wifi reset */
+ /* FFUART */
+ GPIO34_FFUART_RXD,
+ GPIO39_FFUART_TXD,
+
/* HDD */
GPIO98_GPIO, /* HDD reset */
GPIO115_GPIO, /* HDD power */
@@ -137,85 +144,50 @@ static unsigned long palmld_pin_config[] __initdata = {
};
/******************************************************************************
- * SD/MMC card controller
+ * NOR Flash
******************************************************************************/
-static int palmld_mci_init(struct device *dev, irq_handler_t palmld_detect_int,
- void *data)
-{
- int err = 0;
-
- /* Setup an interrupt for detecting card insert/remove events */
- err = gpio_request(GPIO_NR_PALMLD_SD_DETECT_N, "SD IRQ");
- if (err)
- goto err;
- err = gpio_direction_input(GPIO_NR_PALMLD_SD_DETECT_N);
- if (err)
- goto err2;
- err = request_irq(gpio_to_irq(GPIO_NR_PALMLD_SD_DETECT_N),
- palmld_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "SD/MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
- __func__);
- goto err2;
+static struct mtd_partition palmld_partitions[] = {
+ {
+ .name = "Flash",
+ .offset = 0x00000000,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0
}
+};
- err = gpio_request(GPIO_NR_PALMLD_SD_POWER, "SD_POWER");
- if (err)
- goto err3;
- err = gpio_direction_output(GPIO_NR_PALMLD_SD_POWER, 0);
- if (err)
- goto err4;
-
- err = gpio_request(GPIO_NR_PALMLD_SD_READONLY, "SD_READONLY");
- if (err)
- goto err4;
- err = gpio_direction_input(GPIO_NR_PALMLD_SD_READONLY);
- if (err)
- goto err5;
-
- printk(KERN_DEBUG "%s: irq registered\n", __func__);
-
- return 0;
-
-err5:
- gpio_free(GPIO_NR_PALMLD_SD_READONLY);
-err4:
- gpio_free(GPIO_NR_PALMLD_SD_POWER);
-err3:
- free_irq(gpio_to_irq(GPIO_NR_PALMLD_SD_DETECT_N), data);
-err2:
- gpio_free(GPIO_NR_PALMLD_SD_DETECT_N);
-err:
- return err;
-}
-
-static void palmld_mci_exit(struct device *dev, void *data)
-{
- gpio_free(GPIO_NR_PALMLD_SD_READONLY);
- gpio_free(GPIO_NR_PALMLD_SD_POWER);
- free_irq(gpio_to_irq(GPIO_NR_PALMLD_SD_DETECT_N), data);
- gpio_free(GPIO_NR_PALMLD_SD_DETECT_N);
-}
+static struct physmap_flash_data palmld_flash_data[] = {
+ {
+ .width = 2, /* bankwidth in bytes */
+ .parts = palmld_partitions,
+ .nr_parts = ARRAY_SIZE(palmld_partitions)
+ }
+};
-static void palmld_mci_power(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
- gpio_set_value(GPIO_NR_PALMLD_SD_POWER, p_d->ocr_mask & (1 << vdd));
-}
+static struct resource palmld_flash_resource = {
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_4M - 1,
+ .flags = IORESOURCE_MEM,
+};
-static int palmld_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(GPIO_NR_PALMLD_SD_READONLY);
-}
+static struct platform_device palmld_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .resource = &palmld_flash_resource,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = palmld_flash_data,
+ },
+};
+/******************************************************************************
+ * SD/MMC card controller
+ ******************************************************************************/
static struct pxamci_platform_data palmld_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .setpower = palmld_mci_power,
- .get_ro = palmld_mci_get_ro,
- .init = palmld_mci_init,
- .exit = palmld_mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_PALMLD_SD_DETECT_N,
+ .gpio_card_ro = GPIO_NR_PALMLD_SD_READONLY,
+ .gpio_power = GPIO_NR_PALMLD_SD_POWER,
+ .detect_delay = 20,
};
/******************************************************************************
@@ -556,6 +528,7 @@ static struct platform_device *devices[] __initdata = {
&power_supply,
&palmld_asoc,
&palmld_hdd,
+ &palmld_flash,
};
static struct map_desc palmld_io_desc[] __initdata = {
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index aae64a12a734..88dcaac358a2 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -111,6 +111,10 @@ static unsigned long palmt5_pin_config[] __initdata = {
/* PWM */
GPIO16_PWM0_OUT,
+ /* FFUART */
+ GPIO34_FFUART_RXD,
+ GPIO39_FFUART_TXD,
+
/* MISC */
GPIO10_GPIO, /* hotsync button */
GPIO90_GPIO, /* power detect */
@@ -120,83 +124,12 @@ static unsigned long palmt5_pin_config[] __initdata = {
/******************************************************************************
* SD/MMC card controller
******************************************************************************/
-static int palmt5_mci_init(struct device *dev, irq_handler_t palmt5_detect_int,
- void *data)
-{
- int err = 0;
-
- /* Setup an interrupt for detecting card insert/remove events */
- err = gpio_request(GPIO_NR_PALMT5_SD_DETECT_N, "SD IRQ");
- if (err)
- goto err;
- err = gpio_direction_input(GPIO_NR_PALMT5_SD_DETECT_N);
- if (err)
- goto err2;
- err = request_irq(gpio_to_irq(GPIO_NR_PALMT5_SD_DETECT_N),
- palmt5_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "SD/MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
- __func__);
- goto err2;
- }
-
- err = gpio_request(GPIO_NR_PALMT5_SD_POWER, "SD_POWER");
- if (err)
- goto err3;
- err = gpio_direction_output(GPIO_NR_PALMT5_SD_POWER, 0);
- if (err)
- goto err4;
-
- err = gpio_request(GPIO_NR_PALMT5_SD_READONLY, "SD_READONLY");
- if (err)
- goto err4;
- err = gpio_direction_input(GPIO_NR_PALMT5_SD_READONLY);
- if (err)
- goto err5;
-
- printk(KERN_DEBUG "%s: irq registered\n", __func__);
-
- return 0;
-
-err5:
- gpio_free(GPIO_NR_PALMT5_SD_READONLY);
-err4:
- gpio_free(GPIO_NR_PALMT5_SD_POWER);
-err3:
- free_irq(gpio_to_irq(GPIO_NR_PALMT5_SD_DETECT_N), data);
-err2:
- gpio_free(GPIO_NR_PALMT5_SD_DETECT_N);
-err:
- return err;
-}
-
-static void palmt5_mci_exit(struct device *dev, void *data)
-{
- gpio_free(GPIO_NR_PALMT5_SD_READONLY);
- gpio_free(GPIO_NR_PALMT5_SD_POWER);
- free_irq(IRQ_GPIO_PALMT5_SD_DETECT_N, data);
- gpio_free(GPIO_NR_PALMT5_SD_DETECT_N);
-}
-
-static void palmt5_mci_power(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
- gpio_set_value(GPIO_NR_PALMT5_SD_POWER, p_d->ocr_mask & (1 << vdd));
-}
-
-static int palmt5_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(GPIO_NR_PALMT5_SD_READONLY);
-}
-
static struct pxamci_platform_data palmt5_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .setpower = palmt5_mci_power,
- .get_ro = palmt5_mci_get_ro,
- .init = palmt5_mci_init,
- .exit = palmt5_mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_PALMT5_SD_DETECT_N,
+ .gpio_card_ro = GPIO_NR_PALMT5_SD_READONLY,
+ .gpio_power = GPIO_NR_PALMT5_SD_POWER,
+ .detect_delay = 20,
};
/******************************************************************************
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
new file mode 100644
index 000000000000..f4ab6d5b3feb
--- /dev/null
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -0,0 +1,455 @@
+/*
+ * linux/arch/arm/mach-pxa/palmtc.c
+ *
+ * Support for the Palm Tungsten|C
+ *
+ * Author: Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on work of:
+ * Petr Blaha <p3t3@centrum.cz>
+ * Chetan S. Kumar <shivakumar.chetan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/input.h>
+#include <linux/pwm_backlight.h>
+#include <linux/gpio.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/ucb1400.h>
+#include <linux/power_supply.h>
+#include <linux/gpio_keys.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/audio.h>
+#include <mach/palmtc.h>
+#include <mach/mmc.h>
+#include <mach/pxafb.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/irda.h>
+#include <mach/udc.h>
+#include <mach/pxa2xx-regs.h>
+
+#include "generic.h"
+#include "devices.h"
+
+/******************************************************************************
+ * Pin configuration
+ ******************************************************************************/
+static unsigned long palmtc_pin_config[] __initdata = {
+ /* MMC */
+ GPIO6_MMC_CLK,
+ GPIO8_MMC_CS0,
+ GPIO12_GPIO, /* detect */
+ GPIO32_GPIO, /* power */
+ GPIO54_GPIO, /* r/o switch */
+
+ /* PCMCIA */
+ GPIO52_nPCE_1,
+ GPIO53_nPCE_2,
+ GPIO50_nPIOR,
+ GPIO51_nPIOW,
+ GPIO49_nPWE,
+ GPIO48_nPOE,
+ GPIO52_nPCE_1,
+ GPIO53_nPCE_2,
+ GPIO57_nIOIS16,
+ GPIO56_nPWAIT,
+
+ /* AC97 */
+ GPIO28_AC97_BITCLK,
+ GPIO29_AC97_SDATA_IN_0,
+ GPIO30_AC97_SDATA_OUT,
+ GPIO31_AC97_SYNC,
+
+ /* IrDA */
+ GPIO45_GPIO, /* ir disable */
+ GPIO46_FICP_RXD,
+ GPIO47_FICP_TXD,
+
+ /* PWM */
+ GPIO17_PWM1_OUT,
+
+ /* USB */
+ GPIO4_GPIO, /* detect */
+ GPIO36_GPIO, /* pullup */
+
+ /* LCD */
+ GPIO58_LCD_LDD_0,
+ GPIO59_LCD_LDD_1,
+ GPIO60_LCD_LDD_2,
+ GPIO61_LCD_LDD_3,
+ GPIO62_LCD_LDD_4,
+ GPIO63_LCD_LDD_5,
+ GPIO64_LCD_LDD_6,
+ GPIO65_LCD_LDD_7,
+ GPIO66_LCD_LDD_8,
+ GPIO67_LCD_LDD_9,
+ GPIO68_LCD_LDD_10,
+ GPIO69_LCD_LDD_11,
+ GPIO70_LCD_LDD_12,
+ GPIO71_LCD_LDD_13,
+ GPIO72_LCD_LDD_14,
+ GPIO73_LCD_LDD_15,
+ GPIO74_LCD_FCLK,
+ GPIO75_LCD_LCLK,
+ GPIO76_LCD_PCLK,
+ GPIO77_LCD_BIAS,
+
+ /* MATRIX KEYPAD */
+ GPIO0_GPIO | WAKEUP_ON_EDGE_BOTH, /* in 0 */
+ GPIO9_GPIO | WAKEUP_ON_EDGE_BOTH, /* in 1 */
+ GPIO10_GPIO | WAKEUP_ON_EDGE_BOTH, /* in 2 */
+ GPIO11_GPIO | WAKEUP_ON_EDGE_BOTH, /* in 3 */
+ GPIO18_GPIO | MFP_LPM_DRIVE_LOW, /* out 0 */
+ GPIO19_GPIO | MFP_LPM_DRIVE_LOW, /* out 1 */
+ GPIO20_GPIO | MFP_LPM_DRIVE_LOW, /* out 2 */
+ GPIO21_GPIO | MFP_LPM_DRIVE_LOW, /* out 3 */
+ GPIO22_GPIO | MFP_LPM_DRIVE_LOW, /* out 4 */
+ GPIO23_GPIO | MFP_LPM_DRIVE_LOW, /* out 5 */
+ GPIO24_GPIO | MFP_LPM_DRIVE_LOW, /* out 6 */
+ GPIO25_GPIO | MFP_LPM_DRIVE_LOW, /* out 7 */
+ GPIO26_GPIO | MFP_LPM_DRIVE_LOW, /* out 8 */
+ GPIO27_GPIO | MFP_LPM_DRIVE_LOW, /* out 9 */
+ GPIO79_GPIO | MFP_LPM_DRIVE_LOW, /* out 10 */
+ GPIO80_GPIO | MFP_LPM_DRIVE_LOW, /* out 11 */
+
+ /* PXA GPIO KEYS */
+ GPIO7_GPIO | WAKEUP_ON_EDGE_BOTH, /* hotsync button on cradle */
+
+ /* MISC */
+ GPIO1_RST, /* reset */
+ GPIO2_GPIO, /* earphone detect */
+ GPIO16_GPIO, /* backlight switch */
+};
+
+/******************************************************************************
+ * SD/MMC card controller
+ ******************************************************************************/
+static struct pxamci_platform_data palmtc_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_power = GPIO_NR_PALMTC_SD_POWER,
+ .gpio_card_ro = GPIO_NR_PALMTC_SD_READONLY,
+ .gpio_card_detect = GPIO_NR_PALMTC_SD_DETECT_N,
+ .detect_delay = 20,
+};
+
+/******************************************************************************
+ * GPIO keys
+ ******************************************************************************/
+static struct gpio_keys_button palmtc_pxa_buttons[] = {
+ {KEY_F8, GPIO_NR_PALMTC_HOTSYNC_BUTTON, 1, "HotSync Button", EV_KEY, 1},
+};
+
+static struct gpio_keys_platform_data palmtc_pxa_keys_data = {
+ .buttons = palmtc_pxa_buttons,
+ .nbuttons = ARRAY_SIZE(palmtc_pxa_buttons),
+};
+
+static struct platform_device palmtc_pxa_keys = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &palmtc_pxa_keys_data,
+ },
+};
+
+/******************************************************************************
+ * Backlight
+ ******************************************************************************/
+static int palmtc_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(GPIO_NR_PALMTC_BL_POWER, "BL POWER");
+ if (ret)
+ goto err;
+ ret = gpio_direction_output(GPIO_NR_PALMTC_BL_POWER, 1);
+ if (ret)
+ goto err2;
+
+ return 0;
+
+err2:
+ gpio_free(GPIO_NR_PALMTC_BL_POWER);
+err:
+ return ret;
+}
+
+static int palmtc_backlight_notify(int brightness)
+{
+ /* backlight is on when GPIO16 AF0 is high */
+ gpio_set_value(GPIO_NR_PALMTC_BL_POWER, brightness);
+ return brightness;
+}
+
+static void palmtc_backlight_exit(struct device *dev)
+{
+ gpio_free(GPIO_NR_PALMTC_BL_POWER);
+}
+
+static struct platform_pwm_backlight_data palmtc_backlight_data = {
+ .pwm_id = 1,
+ .max_brightness = PALMTC_MAX_INTENSITY,
+ .dft_brightness = PALMTC_MAX_INTENSITY,
+ .pwm_period_ns = PALMTC_PERIOD_NS,
+ .init = palmtc_backlight_init,
+ .notify = palmtc_backlight_notify,
+ .exit = palmtc_backlight_exit,
+};
+
+static struct platform_device palmtc_backlight = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &pxa25x_device_pwm1.dev,
+ .platform_data = &palmtc_backlight_data,
+ },
+};
+
+/******************************************************************************
+ * IrDA
+ ******************************************************************************/
+static int palmtc_irda_startup(struct device *dev)
+{
+ int err;
+ err = gpio_request(GPIO_NR_PALMTC_IR_DISABLE, "IR DISABLE");
+ if (err)
+ goto err;
+ err = gpio_direction_output(GPIO_NR_PALMTC_IR_DISABLE, 1);
+ if (err)
+ gpio_free(GPIO_NR_PALMTC_IR_DISABLE);
+err:
+ return err;
+}
+
+static void palmtc_irda_shutdown(struct device *dev)
+{
+ gpio_free(GPIO_NR_PALMTC_IR_DISABLE);
+}
+
+static void palmtc_irda_transceiver_mode(struct device *dev, int mode)
+{
+ gpio_set_value(GPIO_NR_PALMTC_IR_DISABLE, mode & IR_OFF);
+ pxa2xx_transceiver_mode(dev, mode);
+}
+
+static struct pxaficp_platform_data palmtc_ficp_platform_data = {
+ .startup = palmtc_irda_startup,
+ .shutdown = palmtc_irda_shutdown,
+ .transceiver_cap = IR_SIRMODE | IR_FIRMODE | IR_OFF,
+ .transceiver_mode = palmtc_irda_transceiver_mode,
+};
+
+/******************************************************************************
+ * Keyboard
+ ******************************************************************************/
+static const uint32_t palmtc_matrix_keys[] = {
+ KEY(0, 0, KEY_F1),
+ KEY(0, 1, KEY_X),
+ KEY(0, 2, KEY_POWER),
+ KEY(0, 3, KEY_TAB),
+ KEY(0, 4, KEY_A),
+ KEY(0, 5, KEY_Q),
+ KEY(0, 6, KEY_LEFTSHIFT),
+ KEY(0, 7, KEY_Z),
+ KEY(0, 8, KEY_S),
+ KEY(0, 9, KEY_W),
+ KEY(0, 10, KEY_E),
+ KEY(0, 11, KEY_UP),
+
+ KEY(1, 0, KEY_F2),
+ KEY(1, 1, KEY_DOWN),
+ KEY(1, 3, KEY_D),
+ KEY(1, 4, KEY_C),
+ KEY(1, 5, KEY_F),
+ KEY(1, 6, KEY_R),
+ KEY(1, 7, KEY_SPACE),
+ KEY(1, 8, KEY_V),
+ KEY(1, 9, KEY_G),
+ KEY(1, 10, KEY_T),
+ KEY(1, 11, KEY_LEFT),
+
+ KEY(2, 0, KEY_F3),
+ KEY(2, 1, KEY_LEFTCTRL),
+ KEY(2, 3, KEY_H),
+ KEY(2, 4, KEY_Y),
+ KEY(2, 5, KEY_N),
+ KEY(2, 6, KEY_J),
+ KEY(2, 7, KEY_U),
+ KEY(2, 8, KEY_M),
+ KEY(2, 9, KEY_K),
+ KEY(2, 10, KEY_I),
+ KEY(2, 11, KEY_RIGHT),
+
+ KEY(3, 0, KEY_F4),
+ KEY(3, 1, KEY_ENTER),
+ KEY(3, 3, KEY_DOT),
+ KEY(3, 4, KEY_L),
+ KEY(3, 5, KEY_O),
+ KEY(3, 6, KEY_LEFTALT),
+ KEY(3, 7, KEY_ENTER),
+ KEY(3, 8, KEY_BACKSPACE),
+ KEY(3, 9, KEY_P),
+ KEY(3, 10, KEY_B),
+ KEY(3, 11, KEY_FN),
+};
+
+const struct matrix_keymap_data palmtc_keymap_data = {
+ .keymap = palmtc_matrix_keys,
+ .keymap_size = ARRAY_SIZE(palmtc_matrix_keys),
+ .max_keymap_size = ARRAY_SIZE(palmtc_matrix_keys),
+};
+
+static struct matrix_keypad_platform_data palmtc_keypad_platform_data = {
+ .keymap_data = &palmtc_keymap_data,
+ .col_gpios = {18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 79, 80},
+ .num_col_gpios = 12,
+ .row_gpios = {0, 9, 10, 11},
+ .num_row_gpios = 4,
+ .active_low = 1,
+
+ .debounce_ms = 20,
+ .col_scan_delay_us = 5,
+};
+
+static struct platform_device palmtc_keyboard = {
+ .name = "matrix-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &palmtc_keypad_platform_data,
+ },
+};
+
+/******************************************************************************
+ * UDC
+ ******************************************************************************/
+static struct pxa2xx_udc_mach_info palmtc_udc_info __initdata = {
+ .gpio_vbus = GPIO_NR_PALMTC_USB_DETECT_N,
+ .gpio_vbus_inverted = 1,
+ .gpio_pullup = GPIO_NR_PALMTC_USB_POWER,
+};
+
+/******************************************************************************
+ * Touchscreen / Battery / GPIO-extender
+ ******************************************************************************/
+static struct platform_device palmtc_ucb1400_core = {
+ .name = "ucb1400_core",
+ .id = -1,
+};
+
+/******************************************************************************
+ * NOR Flash
+ ******************************************************************************/
+static struct resource palmtc_flash_resource = {
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_16M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct mtd_partition palmtc_flash_parts[] = {
+ {
+ .name = "U-Boot Bootloader",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "Linux Kernel",
+ .offset = 0x40000,
+ .size = 0x2c0000,
+ },
+ {
+ .name = "Filesystem",
+ .offset = 0x300000,
+ .size = 0xcc0000,
+ },
+ {
+ .name = "U-Boot Environment",
+ .offset = 0xfc0000,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct physmap_flash_data palmtc_flash_data = {
+ .width = 4,
+ .parts = palmtc_flash_parts,
+ .nr_parts = ARRAY_SIZE(palmtc_flash_parts),
+};
+
+static struct platform_device palmtc_flash = {
+ .name = "physmap-flash",
+ .id = -1,
+ .resource = &palmtc_flash_resource,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &palmtc_flash_data,
+ },
+};
+
+/******************************************************************************
+ * Framebuffer
+ ******************************************************************************/
+static struct pxafb_mode_info palmtc_lcd_modes[] = {
+{
+ .pixclock = 115384,
+ .xres = 320,
+ .yres = 320,
+ .bpp = 16,
+
+ .left_margin = 27,
+ .right_margin = 7,
+ .upper_margin = 7,
+ .lower_margin = 8,
+
+ .hsync_len = 6,
+ .vsync_len = 1,
+},
+};
+
+static struct pxafb_mach_info palmtc_lcd_screen = {
+ .modes = palmtc_lcd_modes,
+ .num_modes = ARRAY_SIZE(palmtc_lcd_modes),
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+};
+
+/******************************************************************************
+ * Machine init
+ ******************************************************************************/
+static struct platform_device *devices[] __initdata = {
+ &palmtc_backlight,
+ &palmtc_ucb1400_core,
+ &palmtc_keyboard,
+ &palmtc_pxa_keys,
+ &palmtc_flash,
+};
+
+static void __init palmtc_init(void)
+{
+ pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtc_pin_config));
+
+ set_pxa_fb_info(&palmtc_lcd_screen);
+ pxa_set_mci_info(&palmtc_mci_platform_data);
+ pxa_set_udc_info(&palmtc_udc_info);
+ pxa_set_ac97_info(NULL);
+ pxa_set_ficp_info(&palmtc_ficp_platform_data);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+};
+
+MACHINE_START(PALMTC, "Palm Tungsten|C")
+ .phys_io = 0x40000000,
+ .boot_params = 0xa0000100,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .map_io = pxa_map_io,
+ .init_irq = pxa25x_init_irq,
+ .timer = &pxa_timer,
+ .init_machine = palmtc_init
+MACHINE_END
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index d823b09801df..d9ef76c9278f 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -117,83 +117,11 @@ static unsigned long palmte2_pin_config[] __initdata = {
/******************************************************************************
* SD/MMC card controller
******************************************************************************/
-static int palmte2_mci_init(struct device *dev,
- irq_handler_t palmte2_detect_int, void *data)
-{
- int err = 0;
-
- /* Setup an interrupt for detecting card insert/remove events */
- err = gpio_request(GPIO_NR_PALMTE2_SD_DETECT_N, "SD IRQ");
- if (err)
- goto err;
- err = gpio_direction_input(GPIO_NR_PALMTE2_SD_DETECT_N);
- if (err)
- goto err2;
- err = request_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N),
- palmte2_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "SD/MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
- __func__);
- goto err2;
- }
-
- err = gpio_request(GPIO_NR_PALMTE2_SD_POWER, "SD_POWER");
- if (err)
- goto err3;
- err = gpio_direction_output(GPIO_NR_PALMTE2_SD_POWER, 0);
- if (err)
- goto err4;
-
- err = gpio_request(GPIO_NR_PALMTE2_SD_READONLY, "SD_READONLY");
- if (err)
- goto err4;
- err = gpio_direction_input(GPIO_NR_PALMTE2_SD_READONLY);
- if (err)
- goto err5;
-
- printk(KERN_DEBUG "%s: irq registered\n", __func__);
-
- return 0;
-
-err5:
- gpio_free(GPIO_NR_PALMTE2_SD_READONLY);
-err4:
- gpio_free(GPIO_NR_PALMTE2_SD_POWER);
-err3:
- free_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N), data);
-err2:
- gpio_free(GPIO_NR_PALMTE2_SD_DETECT_N);
-err:
- return err;
-}
-
-static void palmte2_mci_exit(struct device *dev, void *data)
-{
- gpio_free(GPIO_NR_PALMTE2_SD_READONLY);
- gpio_free(GPIO_NR_PALMTE2_SD_POWER);
- free_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N), data);
- gpio_free(GPIO_NR_PALMTE2_SD_DETECT_N);
-}
-
-static void palmte2_mci_power(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
- gpio_set_value(GPIO_NR_PALMTE2_SD_POWER, p_d->ocr_mask & (1 << vdd));
-}
-
-static int palmte2_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(GPIO_NR_PALMTE2_SD_READONLY);
-}
-
static struct pxamci_platform_data palmte2_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .setpower = palmte2_mci_power,
- .get_ro = palmte2_mci_get_ro,
- .init = palmte2_mci_init,
- .exit = palmte2_mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_PALMTE2_SD_DETECT_N,
+ .gpio_card_ro = GPIO_NR_PALMTE2_SD_READONLY,
+ .gpio_power = GPIO_NR_PALMTE2_SD_POWER,
};
/******************************************************************************
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 6c15d84bde53..c0aca18b71bb 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -28,6 +28,10 @@
#include <linux/wm97xx_batt.h>
#include <linux/power_supply.h>
#include <linux/usb/gpio_vbus.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/physmap.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -127,6 +131,14 @@ static unsigned long palmtx_pin_config[] __initdata = {
GPIO76_LCD_PCLK,
GPIO77_LCD_BIAS,
+ /* FFUART */
+ GPIO34_FFUART_RXD,
+ GPIO39_FFUART_TXD,
+
+ /* NAND */
+ GPIO15_nCS_1,
+ GPIO18_RDY,
+
/* MISC. */
GPIO10_GPIO, /* hotsync button */
GPIO12_GPIO, /* power detect */
@@ -134,85 +146,50 @@ static unsigned long palmtx_pin_config[] __initdata = {
};
/******************************************************************************
- * SD/MMC card controller
+ * NOR Flash
******************************************************************************/
-static int palmtx_mci_init(struct device *dev, irq_handler_t palmtx_detect_int,
- void *data)
-{
- int err = 0;
-
- /* Setup an interrupt for detecting card insert/remove events */
- err = gpio_request(GPIO_NR_PALMTX_SD_DETECT_N, "SD IRQ");
- if (err)
- goto err;
- err = gpio_direction_input(GPIO_NR_PALMTX_SD_DETECT_N);
- if (err)
- goto err2;
- err = request_irq(gpio_to_irq(GPIO_NR_PALMTX_SD_DETECT_N),
- palmtx_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "SD/MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
- __func__);
- goto err2;
+static struct mtd_partition palmtx_partitions[] = {
+ {
+ .name = "Flash",
+ .offset = 0x00000000,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0
}
+};
- err = gpio_request(GPIO_NR_PALMTX_SD_POWER, "SD_POWER");
- if (err)
- goto err3;
- err = gpio_direction_output(GPIO_NR_PALMTX_SD_POWER, 0);
- if (err)
- goto err4;
-
- err = gpio_request(GPIO_NR_PALMTX_SD_READONLY, "SD_READONLY");
- if (err)
- goto err4;
- err = gpio_direction_input(GPIO_NR_PALMTX_SD_READONLY);
- if (err)
- goto err5;
-
- printk(KERN_DEBUG "%s: irq registered\n", __func__);
-
- return 0;
-
-err5:
- gpio_free(GPIO_NR_PALMTX_SD_READONLY);
-err4:
- gpio_free(GPIO_NR_PALMTX_SD_POWER);
-err3:
- free_irq(gpio_to_irq(GPIO_NR_PALMTX_SD_DETECT_N), data);
-err2:
- gpio_free(GPIO_NR_PALMTX_SD_DETECT_N);
-err:
- return err;
-}
-
-static void palmtx_mci_exit(struct device *dev, void *data)
-{
- gpio_free(GPIO_NR_PALMTX_SD_READONLY);
- gpio_free(GPIO_NR_PALMTX_SD_POWER);
- free_irq(gpio_to_irq(GPIO_NR_PALMTX_SD_DETECT_N), data);
- gpio_free(GPIO_NR_PALMTX_SD_DETECT_N);
-}
+static struct physmap_flash_data palmtx_flash_data[] = {
+ {
+ .width = 2, /* bankwidth in bytes */
+ .parts = palmtx_partitions,
+ .nr_parts = ARRAY_SIZE(palmtx_partitions)
+ }
+};
-static void palmtx_mci_power(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
- gpio_set_value(GPIO_NR_PALMTX_SD_POWER, p_d->ocr_mask & (1 << vdd));
-}
+static struct resource palmtx_flash_resource = {
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_8M - 1,
+ .flags = IORESOURCE_MEM,
+};
-static int palmtx_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(GPIO_NR_PALMTX_SD_READONLY);
-}
+static struct platform_device palmtx_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .resource = &palmtx_flash_resource,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = palmtx_flash_data,
+ },
+};
+/******************************************************************************
+ * SD/MMC card controller
+ ******************************************************************************/
static struct pxamci_platform_data palmtx_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .setpower = palmtx_mci_power,
- .get_ro = palmtx_mci_get_ro,
- .init = palmtx_mci_init,
- .exit = palmtx_mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_PALMTX_SD_DETECT_N,
+ .gpio_card_ro = GPIO_NR_PALMTX_SD_READONLY,
+ .gpio_power = GPIO_NR_PALMTX_SD_POWER,
+ .detect_delay = 20,
};
/******************************************************************************
@@ -489,6 +466,68 @@ static struct pxafb_mach_info palmtx_lcd_screen = {
};
/******************************************************************************
+ * NAND Flash
+ ******************************************************************************/
+static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd, PALMTX_NAND_CLE_VIRT);
+ else if (ctrl & NAND_ALE)
+ writeb(cmd, PALMTX_NAND_ALE_VIRT);
+ else
+ writeb(cmd, nandaddr);
+}
+
+static struct mtd_partition palmtx_partition_info[] = {
+ [0] = {
+ .name = "palmtx-0",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL
+ },
+};
+
+static const char *palmtx_part_probes[] = { "cmdlinepart", NULL };
+
+struct platform_nand_data palmtx_nand_platdata = {
+ .chip = {
+ .nr_chips = 1,
+ .chip_offset = 0,
+ .nr_partitions = ARRAY_SIZE(palmtx_partition_info),
+ .partitions = palmtx_partition_info,
+ .chip_delay = 20,
+ .part_probe_types = palmtx_part_probes,
+ },
+ .ctrl = {
+ .cmd_ctrl = palmtx_nand_cmd_ctl,
+ },
+};
+
+static struct resource palmtx_nand_resource[] = {
+ [0] = {
+ .start = PXA_CS1_PHYS,
+ .end = PXA_CS1_PHYS + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device palmtx_nand = {
+ .name = "gen_nand",
+ .num_resources = ARRAY_SIZE(palmtx_nand_resource),
+ .resource = palmtx_nand_resource,
+ .id = -1,
+ .dev = {
+ .platform_data = &palmtx_nand_platdata,
+ }
+};
+
+/******************************************************************************
* Power management - standby
******************************************************************************/
static void __init palmtx_pm_init(void)
@@ -514,6 +553,8 @@ static struct platform_device *devices[] __initdata = {
&power_supply,
&palmtx_asoc,
&palmtx_gpio_vbus,
+ &palmtx_flash,
+ &palmtx_nand,
};
static struct map_desc palmtx_io_desc[] __initdata = {
@@ -521,8 +562,18 @@ static struct map_desc palmtx_io_desc[] __initdata = {
.virtual = PALMTX_PCMCIA_VIRT,
.pfn = __phys_to_pfn(PALMTX_PCMCIA_PHYS),
.length = PALMTX_PCMCIA_SIZE,
- .type = MT_DEVICE
-},
+ .type = MT_DEVICE,
+}, {
+ .virtual = PALMTX_NAND_ALE_VIRT,
+ .pfn = __phys_to_pfn(PALMTX_NAND_ALE_PHYS),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+}, {
+ .virtual = PALMTX_NAND_CLE_VIRT,
+ .pfn = __phys_to_pfn(PALMTX_NAND_CLE_PHYS),
+ .length = SZ_1M,
+ .type = MT_DEVICE,
+}
};
static void __init palmtx_map_io(void)
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index c3645aa3fa3d..d8fa53c19178 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -129,88 +129,14 @@ static unsigned long palmz72_pin_config[] __initdata = {
/******************************************************************************
* SD/MMC card controller
******************************************************************************/
-static int palmz72_mci_init(struct device *dev,
- irq_handler_t palmz72_detect_int, void *data)
-{
- int err = 0;
-
- /* Setup an interrupt for detecting card insert/remove events */
- err = gpio_request(GPIO_NR_PALMZ72_SD_DETECT_N, "SD IRQ");
- if (err)
- goto err;
- err = gpio_direction_input(GPIO_NR_PALMZ72_SD_DETECT_N);
- if (err)
- goto err2;
- err = request_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N),
- palmz72_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "SD/MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n",
- __func__);
- goto err2;
- }
-
- /* SD_POWER is not actually power, but it is more like chip
- * select, i.e. it is inverted */
-
- err = gpio_request(GPIO_NR_PALMZ72_SD_POWER_N, "SD_POWER");
- if (err)
- goto err3;
- err = gpio_direction_output(GPIO_NR_PALMZ72_SD_POWER_N, 0);
- if (err)
- goto err4;
- err = gpio_request(GPIO_NR_PALMZ72_SD_RO, "SD_RO");
- if (err)
- goto err4;
- err = gpio_direction_input(GPIO_NR_PALMZ72_SD_RO);
- if (err)
- goto err5;
-
- printk(KERN_DEBUG "%s: irq registered\n", __func__);
-
- return 0;
-
-err5:
- gpio_free(GPIO_NR_PALMZ72_SD_RO);
-err4:
- gpio_free(GPIO_NR_PALMZ72_SD_POWER_N);
-err3:
- free_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N), data);
-err2:
- gpio_free(GPIO_NR_PALMZ72_SD_DETECT_N);
-err:
- return err;
-}
-
-static void palmz72_mci_exit(struct device *dev, void *data)
-{
- gpio_free(GPIO_NR_PALMZ72_SD_POWER_N);
- free_irq(gpio_to_irq(GPIO_NR_PALMZ72_SD_DETECT_N), data);
- gpio_free(GPIO_NR_PALMZ72_SD_DETECT_N);
- gpio_free(GPIO_NR_PALMZ72_SD_RO);
-}
-
-static void palmz72_mci_power(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data *p_d = dev->platform_data;
- if (p_d->ocr_mask & (1 << vdd))
- gpio_set_value(GPIO_NR_PALMZ72_SD_POWER_N, 0);
- else
- gpio_set_value(GPIO_NR_PALMZ72_SD_POWER_N, 1);
-}
-
-static int palmz72_mci_ro(struct device *dev)
-{
- return gpio_get_value(GPIO_NR_PALMZ72_SD_RO);
-}
-
+/* SD_POWER is not actually power, but it is more like chip
+ * select, i.e. it is inverted */
static struct pxamci_platform_data palmz72_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .setpower = palmz72_mci_power,
- .get_ro = palmz72_mci_ro,
- .init = palmz72_mci_init,
- .exit = palmz72_mci_exit,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_PALMZ72_SD_DETECT_N,
+ .gpio_card_ro = GPIO_NR_PALMZ72_SD_RO,
+ .gpio_power = GPIO_NR_PALMZ72_SD_POWER_N,
+ .gpio_power_invert = 1,
};
/******************************************************************************
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 01791d74e08e..bbda57078e0f 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -321,11 +321,14 @@ static void pcm990_mci_exit(struct device *dev, void *data)
#define MSECS_PER_JIFFY (1000/HZ)
static struct pxamci_platform_data pcm990_mci_platform_data = {
- .detect_delay = 250 / MSECS_PER_JIFFY,
- .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .init = pcm990_mci_init,
- .setpower = pcm990_mci_setpower,
- .exit = pcm990_mci_exit,
+ .detect_delay = 250 / MSECS_PER_JIFFY,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .init = pcm990_mci_init,
+ .setpower = pcm990_mci_setpower,
+ .exit = pcm990_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static struct pxaohci_platform_data pcm990_ohci_platform_data = {
@@ -427,25 +430,56 @@ static void pcm990_camera_free_bus(struct soc_camera_link *link)
gpio_bus_switch = -EINVAL;
}
-static struct soc_camera_link iclink = {
- .bus_id = 0, /* Must match with the camera ID above */
- .query_bus_param = pcm990_camera_query_bus_param,
- .set_bus_param = pcm990_camera_set_bus_param,
- .free_bus = pcm990_camera_free_bus,
-};
-
/* Board I2C devices. */
static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
{
/* Must initialize before the camera(s) */
I2C_BOARD_INFO("pca9536", 0x41),
.platform_data = &pca9536_data,
- }, {
+ },
+};
+
+static struct i2c_board_info pcm990_camera_i2c[] = {
+ {
I2C_BOARD_INFO("mt9v022", 0x48),
- .platform_data = &iclink, /* With extender */
}, {
I2C_BOARD_INFO("mt9m001", 0x5d),
- .platform_data = &iclink, /* With extender */
+ },
+};
+
+static struct soc_camera_link iclink[] = {
+ {
+ .bus_id = 0, /* Must match with the camera ID */
+ .board_info = &pcm990_camera_i2c[0],
+ .i2c_adapter_id = 0,
+ .query_bus_param = pcm990_camera_query_bus_param,
+ .set_bus_param = pcm990_camera_set_bus_param,
+ .free_bus = pcm990_camera_free_bus,
+ .module_name = "mt9v022",
+ }, {
+ .bus_id = 0, /* Must match with the camera ID */
+ .board_info = &pcm990_camera_i2c[1],
+ .i2c_adapter_id = 0,
+ .query_bus_param = pcm990_camera_query_bus_param,
+ .set_bus_param = pcm990_camera_set_bus_param,
+ .free_bus = pcm990_camera_free_bus,
+ .module_name = "mt9m001",
+ },
+};
+
+static struct platform_device pcm990_camera[] = {
+ {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink[0],
+ },
+ }, {
+ .name = "soc-camera-pdrv",
+ .id = 1,
+ .dev = {
+ .platform_data = &iclink[1],
+ },
},
};
#endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
@@ -501,6 +535,9 @@ void __init pcm990_baseboard_init(void)
pxa_set_camera_info(&pcm990_pxacamera_platform_data);
i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices));
+
+ platform_device_register(&pcm990_camera[0]);
+ platform_device_register(&pcm990_camera[1]);
#endif
printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n");
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 9352d4a34837..333b1dc2dd3e 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -245,20 +245,10 @@ static inline void poodle_init_spi(void) {}
* The card detect interrupt isn't debounced so we delay it by 250ms
* to give the card a chance to fully insert/eject.
*/
-static struct pxamci_platform_data poodle_mci_platform_data;
-
static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int, void *data)
{
int err;
- err = gpio_request(POODLE_GPIO_nSD_DETECT, "nSD_DETECT");
- if (err)
- goto err_out;
-
- err = gpio_request(POODLE_GPIO_nSD_WP, "nSD_WP");
- if (err)
- goto err_free_1;
-
err = gpio_request(POODLE_GPIO_SD_PWR, "SD_PWR");
if (err)
goto err_free_2;
@@ -267,34 +257,14 @@ static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int,
if (err)
goto err_free_3;
- gpio_direction_input(POODLE_GPIO_nSD_DETECT);
- gpio_direction_input(POODLE_GPIO_nSD_WP);
-
gpio_direction_output(POODLE_GPIO_SD_PWR, 0);
gpio_direction_output(POODLE_GPIO_SD_PWR1, 0);
- poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250);
-
- err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
- __func__);
- goto err_free_4;
- }
-
return 0;
-err_free_4:
- gpio_free(POODLE_GPIO_SD_PWR1);
err_free_3:
gpio_free(POODLE_GPIO_SD_PWR);
err_free_2:
- gpio_free(POODLE_GPIO_nSD_WP);
-err_free_1:
- gpio_free(POODLE_GPIO_nSD_DETECT);
-err_out:
return err;
}
@@ -312,28 +282,20 @@ static void poodle_mci_setpower(struct device *dev, unsigned int vdd)
}
}
-static int poodle_mci_get_ro(struct device *dev)
-{
- return !!gpio_get_value(POODLE_GPIO_nSD_WP);
- return GPLR(POODLE_GPIO_nSD_WP) & GPIO_bit(POODLE_GPIO_nSD_WP);
-}
-
-
static void poodle_mci_exit(struct device *dev, void *data)
{
- free_irq(POODLE_IRQ_GPIO_nSD_DETECT, data);
gpio_free(POODLE_GPIO_SD_PWR1);
gpio_free(POODLE_GPIO_SD_PWR);
- gpio_free(POODLE_GPIO_nSD_WP);
- gpio_free(POODLE_GPIO_nSD_DETECT);
}
static struct pxamci_platform_data poodle_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = poodle_mci_init,
- .get_ro = poodle_mci_get_ro,
- .setpower = poodle_mci_setpower,
- .exit = poodle_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = poodle_mci_init,
+ .setpower = poodle_mci_setpower,
+ .exit = poodle_mci_exit,
+ .gpio_card_detect = POODLE_IRQ_GPIO_nSD_DETECT,
+ .gpio_card_ro = POODLE_GPIO_nSD_WP,
+ .gpio_power = -1,
};
@@ -521,6 +483,7 @@ static void __init poodle_init(void)
set_pxa_fb_parent(&poodle_locomo_device.dev);
set_pxa_fb_info(&poodle_fb_info);
pxa_set_udc_info(&udc_info);
+ poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250);
pxa_set_mci_info(&poodle_mci_platform_data);
pxa_set_ficp_info(&poodle_ficp_platform_data);
pxa_set_i2c_info(NULL);
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
index 4ba6d21f851c..f4af6e2bef89 100644
--- a/arch/arm/mach-pxa/pxa300.c
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -84,9 +84,11 @@ static struct mfp_addr_map pxa310_mfp_addr_map[] __initdata = {
};
static DEFINE_PXA3_CKEN(common_nand, NAND, 156000000, 0);
+static DEFINE_PXA3_CKEN(gcu, PXA300_GCU, 0, 0);
static struct clk_lookup common_clkregs[] = {
INIT_CLKREG(&clk_common_nand, "pxa3xx-nand", NULL),
+ INIT_CLKREG(&clk_gcu, "pxa3xx-gcu", NULL),
};
static DEFINE_PXA3_CKEN(pxa310_mmc3, MMC3, 19500000, 0);
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index 8b3d97efadab..c7373e74a109 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -78,9 +78,11 @@ static struct mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
};
static DEFINE_PXA3_CKEN(pxa320_nand, NAND, 104000000, 0);
+static DEFINE_PXA3_CKEN(gcu, PXA320_GCU, 0, 0);
static struct clk_lookup pxa320_clkregs[] = {
INIT_CLKREG(&clk_pxa320_nand, "pxa3xx-nand", NULL),
+ INIT_CLKREG(&clk_gcu, "pxa3xx-gcu", NULL),
};
static int __init pxa320_init(void)
diff --git a/arch/arm/mach-pxa/pxa930.c b/arch/arm/mach-pxa/pxa930.c
index 71131742fffd..064292008288 100644
--- a/arch/arm/mach-pxa/pxa930.c
+++ b/arch/arm/mach-pxa/pxa930.c
@@ -176,13 +176,30 @@ static struct mfp_addr_map pxa930_mfp_addr_map[] __initdata = {
MFP_ADDR_END,
};
+static struct mfp_addr_map pxa935_mfp_addr_map[] __initdata = {
+ MFP_ADDR(GPIO159, 0x0524),
+ MFP_ADDR(GPIO163, 0x0534),
+ MFP_ADDR(GPIO167, 0x0544),
+ MFP_ADDR(GPIO168, 0x0548),
+ MFP_ADDR(GPIO169, 0x054c),
+ MFP_ADDR(GPIO170, 0x0550),
+ MFP_ADDR(GPIO171, 0x0554),
+ MFP_ADDR(GPIO172, 0x0558),
+ MFP_ADDR(GPIO173, 0x055c),
+
+ MFP_ADDR_END,
+};
+
static int __init pxa930_init(void)
{
- if (cpu_is_pxa930()) {
+ if (cpu_is_pxa930() || cpu_is_pxa935()) {
mfp_init_base(io_p2v(MFPR_BASE));
mfp_init_addr(pxa930_mfp_addr_map);
}
+ if (cpu_is_pxa935())
+ mfp_init_addr(pxa935_mfp_addr_map);
+
return 0;
}
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index dda310fe71c8..da85327e630c 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -378,45 +378,6 @@ static inline void spitz_init_spi(void) {}
* The card detect interrupt isn't debounced so we delay it by 250ms
* to give the card a chance to fully insert/eject.
*/
-
-static struct pxamci_platform_data spitz_mci_platform_data;
-
-static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, void *data)
-{
- int err;
-
- err = gpio_request(SPITZ_GPIO_nSD_DETECT, "nSD_DETECT");
- if (err)
- goto err_out;
-
- err = gpio_request(SPITZ_GPIO_nSD_WP, "nSD_WP");
- if (err)
- goto err_free_1;
-
- gpio_direction_input(SPITZ_GPIO_nSD_DETECT);
- gpio_direction_input(SPITZ_GPIO_nSD_WP);
-
- spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
-
- err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
- __func__);
- goto err_free_2;
- }
- return 0;
-
-err_free_2:
- gpio_free(SPITZ_GPIO_nSD_WP);
-err_free_1:
- gpio_free(SPITZ_GPIO_nSD_DETECT);
-err_out:
- return err;
-}
-
static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
{
struct pxamci_platform_data* p_d = dev->platform_data;
@@ -427,24 +388,12 @@ static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0000);
}
-static int spitz_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(SPITZ_GPIO_nSD_WP);
-}
-
-static void spitz_mci_exit(struct device *dev, void *data)
-{
- free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data);
- gpio_free(SPITZ_GPIO_nSD_WP);
- gpio_free(SPITZ_GPIO_nSD_DETECT);
-}
-
static struct pxamci_platform_data spitz_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = spitz_mci_init,
- .get_ro = spitz_mci_get_ro,
- .setpower = spitz_mci_setpower,
- .exit = spitz_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .setpower = spitz_mci_setpower,
+ .gpio_card_detect = SPITZ_GPIO_nSD_DETECT,
+ .gpio_card_ro = SPITZ_GPIO_nSD_WP,
+ .gpio_power = -1,
};
@@ -695,6 +644,7 @@ static void __init common_init(void)
spitz_init_spi();
platform_add_devices(devices, ARRAY_SIZE(devices));
+ spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
pxa_set_mci_info(&spitz_mci_platform_data);
pxa_set_ohci_info(&spitz_ohci_platform_data);
pxa_set_ficp_info(&spitz_ficp_platform_data);
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 117ad5920e53..b56cc5667bb4 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -247,49 +247,10 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
/*
* MMC/SD Device
*/
-static struct pxamci_platform_data tosa_mci_platform_data;
-
static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void *data)
{
int err;
- tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
-
- err = gpio_request(TOSA_GPIO_nSD_DETECT, "MMC/SD card detect");
- if (err) {
- printk(KERN_ERR "tosa_mci_init: can't request nSD_DETECT gpio\n");
- goto err_gpio_detect;
- }
- err = gpio_direction_input(TOSA_GPIO_nSD_DETECT);
- if (err)
- goto err_gpio_detect_dir;
-
- err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "MMC/SD card detect", data);
- if (err) {
- printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
- goto err_irq;
- }
-
- err = gpio_request(TOSA_GPIO_SD_WP, "SD Write Protect");
- if (err) {
- printk(KERN_ERR "tosa_mci_init: can't request SD_WP gpio\n");
- goto err_gpio_wp;
- }
- err = gpio_direction_input(TOSA_GPIO_SD_WP);
- if (err)
- goto err_gpio_wp_dir;
-
- err = gpio_request(TOSA_GPIO_PWR_ON, "SD Power");
- if (err) {
- printk(KERN_ERR "tosa_mci_init: can't request SD_PWR gpio\n");
- goto err_gpio_pwr;
- }
- err = gpio_direction_output(TOSA_GPIO_PWR_ON, 0);
- if (err)
- goto err_gpio_pwr_dir;
-
err = gpio_request(TOSA_GPIO_nSD_INT, "SD Int");
if (err) {
printk(KERN_ERR "tosa_mci_init: can't request SD_PWR gpio\n");
@@ -304,51 +265,21 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
err_gpio_int_dir:
gpio_free(TOSA_GPIO_nSD_INT);
err_gpio_int:
-err_gpio_pwr_dir:
- gpio_free(TOSA_GPIO_PWR_ON);
-err_gpio_pwr:
-err_gpio_wp_dir:
- gpio_free(TOSA_GPIO_SD_WP);
-err_gpio_wp:
- free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
-err_irq:
-err_gpio_detect_dir:
- gpio_free(TOSA_GPIO_nSD_DETECT);
-err_gpio_detect:
return err;
}
-static void tosa_mci_setpower(struct device *dev, unsigned int vdd)
-{
- struct pxamci_platform_data* p_d = dev->platform_data;
-
- if (( 1 << vdd) & p_d->ocr_mask) {
- gpio_set_value(TOSA_GPIO_PWR_ON, 1);
- } else {
- gpio_set_value(TOSA_GPIO_PWR_ON, 0);
- }
-}
-
-static int tosa_mci_get_ro(struct device *dev)
-{
- return gpio_get_value(TOSA_GPIO_SD_WP);
-}
-
static void tosa_mci_exit(struct device *dev, void *data)
{
gpio_free(TOSA_GPIO_nSD_INT);
- gpio_free(TOSA_GPIO_PWR_ON);
- gpio_free(TOSA_GPIO_SD_WP);
- free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
- gpio_free(TOSA_GPIO_nSD_DETECT);
}
static struct pxamci_platform_data tosa_mci_platform_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = tosa_mci_init,
- .get_ro = tosa_mci_get_ro,
- .setpower = tosa_mci_setpower,
- .exit = tosa_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = tosa_mci_init,
+ .exit = tosa_mci_exit,
+ .gpio_card_detect = TOSA_GPIO_nSD_DETECT,
+ .gpio_card_ro = TOSA_GPIO_SD_WP,
+ .gpio_power = TOSA_GPIO_PWR_ON,
};
/*
@@ -910,6 +841,7 @@ static void __init tosa_init(void)
dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12);
dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16);
+ tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
pxa_set_mci_info(&tosa_mci_platform_data);
pxa_set_udc_info(&udc_info);
pxa_set_ficp_info(&tosa_ficp_platform_data);
diff --git a/arch/arm/mach-pxa/treo680.c b/arch/arm/mach-pxa/treo680.c
index a06f19edebb3..753ec4df17b9 100644
--- a/arch/arm/mach-pxa/treo680.c
+++ b/arch/arm/mach-pxa/treo680.c
@@ -409,7 +409,7 @@ err1:
static void treo680_irda_shutdown(struct device *dev)
{
- gpio_free(GPIO_NR_TREO680_AMP_EN);
+ gpio_free(GPIO_NR_TREO680_IR_EN);
}
static struct pxaficp_platform_data treo680_ficp_info = {
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 825f540176d2..32299869b352 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -367,6 +367,9 @@ static struct pxamci_platform_data trizeps4_mci_platform_data = {
.exit = trizeps4_mci_exit,
.get_ro = NULL, /* write-protection not supported */
.setpower = NULL, /* power-switching not supported */
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
/****************************************************************************
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 218d2001f1df..09784d3954e4 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -290,6 +290,9 @@ static struct pxamci_platform_data zylonite_mci_platform_data = {
.init = zylonite_mci_init,
.exit = zylonite_mci_exit,
.get_ro = zylonite_mci_ro,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
};
static struct pxamci_platform_data zylonite_mci2_platform_data = {
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
index cefd1c0a854a..84095440a878 100644
--- a/arch/arm/mach-pxa/zylonite_pxa300.c
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -197,10 +197,12 @@ static void __init zylonite_detect_lcd_panel(void)
for (i = 0; i < NUM_LCD_DETECT_PINS; i++) {
id = id << 1;
gpio = mfp_to_gpio(lcd_detect_pins[i]);
+ gpio_request(gpio, "LCD_ID_PINS");
gpio_direction_input(gpio);
if (gpio_get_value(gpio))
id = id | 0x1;
+ gpio_free(gpio);
}
/* lcd id, flush out bit 1 */
diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
index cc5a22833605..60d08f23f5e4 100644
--- a/arch/arm/mach-pxa/zylonite_pxa320.c
+++ b/arch/arm/mach-pxa/zylonite_pxa320.c
@@ -176,10 +176,12 @@ static void __init zylonite_detect_lcd_panel(void)
for (i = 0; i < NUM_LCD_DETECT_PINS; i++) {
id = id << 1;
gpio = mfp_to_gpio(lcd_detect_pins[i]);
+ gpio_request(gpio, "LCD_ID_PINS");
gpio_direction_input(gpio);
if (gpio_get_value(gpio))
id = id | 0x1;
+ gpio_free(gpio);
}
/* lcd id, flush out bit 1 */
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index d4cfa2145386..dfc9b0bc6eb2 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -75,7 +75,7 @@ config MACH_REALVIEW_PBX
config REALVIEW_HIGH_PHYS_OFFSET
bool "High physical base address for the RealView platform"
- depends on !MACH_REALVIEW_PB1176
+ depends on MMU && !MACH_REALVIEW_PB1176
default y
help
RealView boards other than PB1176 have the RAM available at
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index facbd49eec67..dc3519c50ab2 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -221,6 +221,9 @@ arch_initcall(realview_i2c_init);
#define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)
+/*
+ * This is only used if GPIOLIB support is disabled
+ */
static unsigned int realview_mmc_status(struct device *dev)
{
struct amba_device *adev = container_of(dev, struct amba_device, dev);
@@ -237,11 +240,15 @@ static unsigned int realview_mmc_status(struct device *dev)
struct mmc_platform_data realview_mmc0_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = realview_mmc_status,
+ .gpio_wp = 17,
+ .gpio_cd = 16,
};
struct mmc_platform_data realview_mmc1_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = realview_mmc_status,
+ .gpio_wp = 19,
+ .gpio_cd = 18,
};
/*
diff --git a/arch/arm/mach-realview/include/mach/gpio.h b/arch/arm/mach-realview/include/mach/gpio.h
new file mode 100644
index 000000000000..94ff27678a46
--- /dev/null
+++ b/arch/arm/mach-realview/include/mach/gpio.h
@@ -0,0 +1,6 @@
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
diff --git a/arch/arm/mach-realview/include/mach/hardware.h b/arch/arm/mach-realview/include/mach/hardware.h
index b42c14f89acb..8a638d15797f 100644
--- a/arch/arm/mach-realview/include/mach/hardware.h
+++ b/arch/arm/mach-realview/include/mach/hardware.h
@@ -25,6 +25,7 @@
#include <asm/sizes.h>
/* macro to get at IO space when running virtually */
+#ifdef CONFIG_MMU
/*
* Statically mapped addresses:
*
@@ -33,6 +34,9 @@
* 1fxx xxxx -> fexx xxxx
*/
#define IO_ADDRESS(x) (((x) & 0x03ffffff) + 0xfb000000)
+#else
+#define IO_ADDRESS(x) (x)
+#endif
#define __io_address(n) __io(IO_ADDRESS(n))
#endif
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index ac0e83f1cc3a..a88458b4799d 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -20,6 +20,7 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/localtimer.h>
+#include <asm/unified.h>
#include <mach/board-eb.h>
#include <mach/board-pb11mp.h>
@@ -137,26 +138,19 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
static void __init poke_milo(void)
{
- extern void secondary_startup(void);
-
/* nobody is to be released from the pen yet */
pen_release = -1;
/*
- * write the address of secondary startup into the system-wide
- * flags register, then clear the bottom two bits, which is what
- * BootMonitor is waiting for
+ * Write the address of secondary startup into the system-wide flags
+ * register. The BootMonitor waits for this register to become
+ * non-zero.
*/
-#if 1
#define REALVIEW_SYS_FLAGSS_OFFSET 0x30
- __raw_writel(virt_to_phys(realview_secondary_startup),
- __io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_FLAGSS_OFFSET);
#define REALVIEW_SYS_FLAGSC_OFFSET 0x34
- __raw_writel(3,
+ __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)),
__io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_FLAGSC_OFFSET);
-#endif
+ REALVIEW_SYS_FLAGSS_OFFSET);
mb();
}
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 8dfa44e08a94..abd13b448671 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -113,6 +114,21 @@ static void __init realview_eb_map_io(void)
iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
}
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = -1,
+};
+
/*
* RealView EB AMBA devices
*/
@@ -189,9 +205,9 @@ AMBA_DEVICE(clcd, "dev:20", EB_CLCD, &clcd_plat_data);
AMBA_DEVICE(dmac, "dev:30", DMAC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", EB_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", EB_GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", EB_GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
AMBA_DEVICE(rtc, "dev:e8", EB_RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", EB_UART0, NULL);
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 25efe71a67c7..17fbb0e889b6 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -107,6 +108,21 @@ static void __init realview_pb1176_map_io(void)
iotable_init(realview_pb1176_io_desc, ARRAY_SIZE(realview_pb1176_io_desc));
}
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = -1,
+};
+
/*
* RealView PB1176 AMBA devices
*/
@@ -164,9 +180,9 @@ AMBA_DEVICE(uart3, "fpga:09", PB1176_UART3, NULL);
AMBA_DEVICE(smc, "dev:00", PB1176_SMC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", PB1176_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", PB1176_GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", PB1176_GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
AMBA_DEVICE(rtc, "dev:e8", PB1176_RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", PB1176_UART0, NULL);
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index dc4b16943907..fdd042b85f40 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -108,6 +109,21 @@ static void __init realview_pb11mp_map_io(void)
iotable_init(realview_pb11mp_io_desc, ARRAY_SIZE(realview_pb11mp_io_desc));
}
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = -1,
+};
+
/*
* RealView PB11MPCore AMBA devices
*/
@@ -166,9 +182,9 @@ AMBA_DEVICE(uart3, "fpga:09", PB11MP_UART3, NULL);
AMBA_DEVICE(smc, "dev:00", PB11MP_SMC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", PB11MP_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", PB11MP_GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", PB11MP_GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
AMBA_DEVICE(rtc, "dev:e8", PB11MP_RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", PB11MP_UART0, NULL);
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index d6ac1eb86576..70bba9900d97 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -98,6 +99,21 @@ static void __init realview_pba8_map_io(void)
iotable_init(realview_pba8_io_desc, ARRAY_SIZE(realview_pba8_io_desc));
}
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = -1,
+};
+
/*
* RealView PBA8Core AMBA devices
*/
@@ -156,9 +172,9 @@ AMBA_DEVICE(uart3, "fpga:09", PBA8_UART3, NULL);
AMBA_DEVICE(smc, "dev:00", PBA8_SMC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", PBA8_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", PBA8_GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", PBA8_GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
AMBA_DEVICE(rtc, "dev:e8", PBA8_RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", PBA8_UART0, NULL);
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index ede2a57240a3..ce6c5d25fbef 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -118,6 +119,21 @@ static void __init realview_pbx_map_io(void)
iotable_init(realview_local_io_desc, ARRAY_SIZE(realview_local_io_desc));
}
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = -1,
+};
+
/*
* RealView PBXCore AMBA devices
*/
@@ -176,9 +192,9 @@ AMBA_DEVICE(uart3, "fpga:09", PBX_UART3, NULL);
AMBA_DEVICE(smc, "dev:00", PBX_SMC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", PBX_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", PBX_GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", PBX_GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
AMBA_DEVICE(rtc, "dev:e8", PBX_RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", PBX_UART0, NULL);
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-core.h b/arch/arm/mach-s3c2410/include/mach/gpio-core.h
index 8fe192081d3a..f8b879a7973c 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio-core.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio-core.h
@@ -28,7 +28,7 @@ static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin)
return NULL;
chip = &s3c24xx_gpios[pin/32];
- return (S3C2410_GPIO_OFFSET(pin) > chip->chip.ngpio) ? chip : NULL;
+ return (S3C2410_GPIO_OFFSET(pin) < chip->chip.ngpio) ? chip : NULL;
}
#endif /* __ASM_ARCH_GPIO_CORE_H */
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index 3138d3955c9e..585cc013639d 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -156,6 +156,8 @@ int __devinit mmc_init(struct amba_device *adev)
mmci_card->mmc0_plat_data.ocr_mask = MMC_VDD_28_29;
mmci_card->mmc0_plat_data.translate_vdd = mmc_translate_vdd;
mmci_card->mmc0_plat_data.status = mmc_status;
+ mmci_card->mmc0_plat_data.gpio_wp = -1;
+ mmci_card->mmc0_plat_data.gpio_cd = -1;
mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data;
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 31093af7d052..975eae41ee66 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
+#include <linux/amba/pl061.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cnt32_to_63.h>
@@ -371,6 +372,8 @@ unsigned int mmc_status(struct device *dev)
static struct mmc_platform_data mmc0_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
+ .gpio_wp = -1,
+ .gpio_cd = -1,
};
/*
@@ -705,6 +708,16 @@ static struct clcd_board clcd_plat_data = {
.remove = versatile_clcd_remove,
};
+static struct pl061_platform_data gpio0_plat_data = {
+ .gpio_base = 0,
+ .irq_base = IRQ_GPIO0_START,
+};
+
+static struct pl061_platform_data gpio1_plat_data = {
+ .gpio_base = 8,
+ .irq_base = IRQ_GPIO1_START,
+};
+
#define AACI_IRQ { IRQ_AACI, NO_IRQ }
#define AACI_DMA { 0x80, 0x81 }
#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
@@ -767,8 +780,8 @@ AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
AMBA_DEVICE(dmac, "dev:30", DMAC, NULL);
AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL);
+AMBA_DEVICE(gpio0, "dev:e4", GPIO0, &gpio0_plat_data);
+AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
AMBA_DEVICE(rtc, "dev:e8", RTC, NULL);
AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
diff --git a/arch/arm/mach-versatile/include/mach/gpio.h b/arch/arm/mach-versatile/include/mach/gpio.h
new file mode 100644
index 000000000000..94ff27678a46
--- /dev/null
+++ b/arch/arm/mach-versatile/include/mach/gpio.h
@@ -0,0 +1,6 @@
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
diff --git a/arch/arm/mach-versatile/include/mach/irqs.h b/arch/arm/mach-versatile/include/mach/irqs.h
index 9bfdb30e1f3f..bf44c61bd1f6 100644
--- a/arch/arm/mach-versatile/include/mach/irqs.h
+++ b/arch/arm/mach-versatile/include/mach/irqs.h
@@ -122,4 +122,13 @@
#define IRQ_SIC_PCI3 (IRQ_SIC_START + SIC_INT_PCI3)
#define IRQ_SIC_END 63
-#define NR_IRQS 64
+#define IRQ_GPIO0_START (IRQ_SIC_END + 1)
+#define IRQ_GPIO0_END (IRQ_GPIO0_START + 31)
+#define IRQ_GPIO1_START (IRQ_GPIO0_END + 1)
+#define IRQ_GPIO1_END (IRQ_GPIO1_START + 31)
+#define IRQ_GPIO2_START (IRQ_GPIO1_END + 1)
+#define IRQ_GPIO2_END (IRQ_GPIO2_START + 31)
+#define IRQ_GPIO3_START (IRQ_GPIO2_END + 1)
+#define IRQ_GPIO3_END (IRQ_GPIO3_START + 31)
+
+#define NR_IRQS (IRQ_GPIO3_END + 1)
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index aa051c0884f8..9af8d8154df5 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -23,6 +23,7 @@
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl061.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -43,6 +44,18 @@
static struct mmc_platform_data mmc1_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
+ .gpio_wp = -1,
+ .gpio_cd = -1,
+};
+
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = IRQ_GPIO2_START,
+};
+
+static struct pl061_platform_data gpio3_plat_data = {
+ .gpio_base = 24,
+ .irq_base = IRQ_GPIO3_START,
};
#define UART3_IRQ { IRQ_SIC_UART3, NO_IRQ }
@@ -70,8 +83,8 @@ AMBA_DEVICE(sci1, "fpga:0a", SCI1, NULL);
AMBA_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data);
/* DevChip Primecells */
-AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL);
-AMBA_DEVICE(gpio3, "dev:e7", GPIO3, NULL);
+AMBA_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
+AMBA_DEVICE(gpio3, "dev:e7", GPIO3, &gpio3_plat_data);
static struct amba_device *amba_devs[] __initdata = {
&uart3_device,
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
index d50c94f4dbdf..3ccd625455cf 100644
--- a/arch/arm/mach-w90x900/Makefile
+++ b/arch/arm/mach-w90x900/Makefile
@@ -5,7 +5,7 @@
# Object file lists.
obj-y := irq.o time.o mfp-w90p910.o gpio.o clock.o
-
+obj-y += clksel.o
# W90X900 CPU support files
obj-$(CONFIG_CPU_W90P910) += w90p910.o
diff --git a/arch/arm/mach-w90x900/clksel.c b/arch/arm/mach-w90x900/clksel.c
new file mode 100644
index 000000000000..5a77eb91cb16
--- /dev/null
+++ b/arch/arm/mach-w90x900/clksel.c
@@ -0,0 +1,91 @@
+/*
+ * linux/arch/arm/mach-w90x900/clksel.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-clock.h>
+
+#define PLL0 0x00
+#define PLL1 0x01
+#define OTHER 0x02
+#define EXT 0x03
+#define MSOFFSET 0x0C
+#define ATAOFFSET 0x0a
+#define LCDOFFSET 0x06
+#define AUDOFFSET 0x04
+#define CPUOFFSET 0x00
+
+static DEFINE_MUTEX(clksel_sem);
+
+static void clock_source_select(const char *dev_id, unsigned int clkval)
+{
+ unsigned int clksel, offset;
+
+ clksel = __raw_readl(REG_CLKSEL);
+
+ if (strcmp(dev_id, "w90p910-ms") == 0)
+ offset = MSOFFSET;
+ else if (strcmp(dev_id, "w90p910-atapi") == 0)
+ offset = ATAOFFSET;
+ else if (strcmp(dev_id, "w90p910-lcd") == 0)
+ offset = LCDOFFSET;
+ else if (strcmp(dev_id, "w90p910-audio") == 0)
+ offset = AUDOFFSET;
+ else
+ offset = CPUOFFSET;
+
+ clksel &= ~(0x03 << offset);
+ clksel |= (clkval << offset);
+
+ __raw_writel(clksel, REG_CLKSEL);
+}
+
+void w90p910_clock_source(struct device *dev, unsigned char *src)
+{
+ unsigned int clkval;
+ const char *dev_id;
+
+ BUG_ON(!src);
+ clkval = 0;
+
+ mutex_lock(&clksel_sem);
+
+ if (dev)
+ dev_id = dev_name(dev);
+ else
+ dev_id = "cpufreq";
+
+ if (strcmp(src, "pll0") == 0)
+ clkval = PLL0;
+ else if (strcmp(src, "pll1") == 0)
+ clkval = PLL1;
+ else if (strcmp(src, "ext") == 0)
+ clkval = EXT;
+ else if (strcmp(src, "oth") == 0)
+ clkval = OTHER;
+
+ clock_source_select(dev_id, clkval);
+
+ mutex_unlock(&clksel_sem);
+}
+EXPORT_SYMBOL(w90p910_clock_source);
+
diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
index f420613cd395..49cf1fbc14eb 100644
--- a/arch/arm/mach-w90x900/clock.c
+++ b/arch/arm/mach-w90x900/clock.c
@@ -25,6 +25,8 @@
#include "clock.h"
+#define SUBCLK 0x24
+
static DEFINE_SPINLOCK(clocks_lock);
int clk_enable(struct clk *clk)
@@ -68,6 +70,22 @@ void w90x900_clk_enable(struct clk *clk, int enable)
__raw_writel(clken, W90X900_VA_CLKPWR);
}
+void w90x900_subclk_enable(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->cken;
+ unsigned long clken;
+
+ clken = __raw_readl(W90X900_VA_CLKPWR + SUBCLK);
+
+ if (enable)
+ clken |= clocks;
+ else
+ clken &= ~clocks;
+
+ __raw_writel(clken, W90X900_VA_CLKPWR + SUBCLK);
+}
+
+
void clks_register(struct clk_lookup *clks, size_t num)
{
int i;
diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h
index 4f27bda76d56..d2f0e50a70bf 100644
--- a/arch/arm/mach-w90x900/clock.h
+++ b/arch/arm/mach-w90x900/clock.h
@@ -13,6 +13,7 @@
#include <asm/clkdev.h>
void w90x900_clk_enable(struct clk *clk, int enable);
+void w90x900_subclk_enable(struct clk *clk, int enable);
void clks_register(struct clk_lookup *clks, size_t num);
struct clk {
@@ -27,6 +28,13 @@ struct clk clk_##_name = { \
.cken = (1 << _ctrlbit), \
}
+#define DEFINE_SUBCLK(_name, _ctrlbit) \
+struct clk clk_##_name = { \
+ .enable = w90x900_subclk_enable, \
+ .cken = (1 << _ctrlbit), \
+ }
+
+
#define DEF_CLKLOOK(_clk, _devname, _conname) \
{ \
.clk = _clk, \
diff --git a/arch/arm/mach-w90x900/cpu.h b/arch/arm/mach-w90x900/cpu.h
index 57b5dbabeb41..ddde959d8987 100644
--- a/arch/arm/mach-w90x900/cpu.h
+++ b/arch/arm/mach-w90x900/cpu.h
@@ -45,6 +45,7 @@ extern void w90p910_init_clocks(void);
extern void w90p910_map_io(struct map_desc *mach_desc, int size);
extern struct platform_device w90p910_serial_device;
extern struct sys_timer w90x900_timer;
+extern void w90p910_clock_source(struct device *dev, unsigned char *src);
#define W90X900_8250PORT(name) \
{ \
diff --git a/arch/arm/mach-w90x900/include/mach/regs-clock.h b/arch/arm/mach-w90x900/include/mach/regs-clock.h
index f10b6a8dc069..516d6b477b61 100644
--- a/arch/arm/mach-w90x900/include/mach/regs-clock.h
+++ b/arch/arm/mach-w90x900/include/mach/regs-clock.h
@@ -28,4 +28,26 @@
#define REG_CLKEN1 (CLK_BA + 0x24)
#define REG_CLKDIV1 (CLK_BA + 0x28)
+/* Define PLL freq setting */
+#define PLL_DISABLE 0x12B63
+#define PLL_66MHZ 0x2B63
+#define PLL_100MHZ 0x4F64
+#define PLL_120MHZ 0x4F63
+#define PLL_166MHZ 0x4124
+#define PLL_200MHZ 0x4F24
+
+/* Define AHB:CPUFREQ ratio */
+#define AHB_CPUCLK_1_1 0x00
+#define AHB_CPUCLK_1_2 0x01
+#define AHB_CPUCLK_1_4 0x02
+#define AHB_CPUCLK_1_8 0x03
+
+/* Define APB:AHB ratio */
+#define APB_AHB_1_2 0x01
+#define APB_AHB_1_4 0x02
+#define APB_AHB_1_8 0x03
+
+/* Define clock skew */
+#define DEFAULTSKEW 0x48
+
#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-ebi.h b/arch/arm/mach-w90x900/include/mach/regs-ebi.h
new file mode 100644
index 000000000000..b68455e7f88b
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/regs-ebi.h
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-ebi.h
+ *
+ * Copyright (c) 2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@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 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_EBI_H
+#define __ASM_ARCH_REGS_EBI_H
+
+/* EBI Control Registers */
+
+#define EBI_BA W90X900_VA_EBI
+#define REG_EBICON (EBI_BA + 0x00)
+#define REG_ROMCON (EBI_BA + 0x04)
+#define REG_SDCONF0 (EBI_BA + 0x08)
+#define REG_SDCONF1 (EBI_BA + 0x0C)
+#define REG_SDTIME0 (EBI_BA + 0x10)
+#define REG_SDTIME1 (EBI_BA + 0x14)
+#define REG_EXT0CON (EBI_BA + 0x18)
+#define REG_EXT1CON (EBI_BA + 0x1C)
+#define REG_EXT2CON (EBI_BA + 0x20)
+#define REG_EXT3CON (EBI_BA + 0x24)
+#define REG_EXT4CON (EBI_BA + 0x28)
+#define REG_CKSKEW (EBI_BA + 0x2C)
+
+#endif /* __ASM_ARCH_REGS_EBI_H */
diff --git a/arch/arm/mach-w90x900/irq.c b/arch/arm/mach-w90x900/irq.c
index 0b4fc194729c..a296c9b81d24 100644
--- a/arch/arm/mach-w90x900/irq.c
+++ b/arch/arm/mach-w90x900/irq.c
@@ -10,8 +10,7 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation;version 2 of the License.
*
*/
@@ -29,9 +28,114 @@
#include <mach/hardware.h>
#include <mach/regs-irq.h>
+struct group_irq {
+ unsigned long gpen;
+ unsigned int enabled;
+ void (*enable)(struct group_irq *, int enable);
+};
+
+static DEFINE_SPINLOCK(groupirq_lock);
+
+#define DEFINE_GROUP(_name, _ctrlbit, _num) \
+struct group_irq group_##_name = { \
+ .enable = w90x900_group_enable, \
+ .gpen = ((2 ^ _num) - 1) << _ctrlbit, \
+ }
+
+static void w90x900_group_enable(struct group_irq *gpirq, int enable);
+
+static DEFINE_GROUP(nirq0, 0, 4);
+static DEFINE_GROUP(nirq1, 4, 4);
+static DEFINE_GROUP(usbh, 8, 2);
+static DEFINE_GROUP(ottimer, 16, 3);
+static DEFINE_GROUP(gdma, 20, 2);
+static DEFINE_GROUP(sc, 24, 2);
+static DEFINE_GROUP(i2c, 26, 2);
+static DEFINE_GROUP(ps2, 28, 2);
+
+static int group_irq_enable(struct group_irq *group_irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&groupirq_lock, flags);
+ if (group_irq->enabled++ == 0)
+ (group_irq->enable)(group_irq, 1);
+ spin_unlock_irqrestore(&groupirq_lock, flags);
+
+ return 0;
+}
+
+static void group_irq_disable(struct group_irq *group_irq)
+{
+ unsigned long flags;
+
+ WARN_ON(group_irq->enabled == 0);
+
+ spin_lock_irqsave(&groupirq_lock, flags);
+ if (--group_irq->enabled == 0)
+ (group_irq->enable)(group_irq, 0);
+ spin_unlock_irqrestore(&groupirq_lock, flags);
+}
+
+static void w90x900_group_enable(struct group_irq *gpirq, int enable)
+{
+ unsigned int groupen = gpirq->gpen;
+ unsigned long regval;
+
+ regval = __raw_readl(REG_AIC_GEN);
+
+ if (enable)
+ regval |= groupen;
+ else
+ regval &= ~groupen;
+
+ __raw_writel(regval, REG_AIC_GEN);
+}
+
static void w90x900_irq_mask(unsigned int irq)
{
+ struct group_irq *group_irq;
+
+ group_irq = NULL;
+
__raw_writel(1 << irq, REG_AIC_MDCR);
+
+ switch (irq) {
+ case IRQ_GROUP0:
+ group_irq = &group_nirq0;
+ break;
+
+ case IRQ_GROUP1:
+ group_irq = &group_nirq1;
+ break;
+
+ case IRQ_USBH:
+ group_irq = &group_usbh;
+ break;
+
+ case IRQ_T_INT_GROUP:
+ group_irq = &group_ottimer;
+ break;
+
+ case IRQ_GDMAGROUP:
+ group_irq = &group_gdma;
+ break;
+
+ case IRQ_SCGROUP:
+ group_irq = &group_sc;
+ break;
+
+ case IRQ_I2CGROUP:
+ group_irq = &group_i2c;
+ break;
+
+ case IRQ_P2SGROUP:
+ group_irq = &group_ps2;
+ break;
+ }
+
+ if (group_irq)
+ group_irq_disable(group_irq);
}
/*
@@ -46,14 +150,48 @@ static void w90x900_irq_ack(unsigned int irq)
static void w90x900_irq_unmask(unsigned int irq)
{
- unsigned long mask;
+ struct group_irq *group_irq;
+
+ group_irq = NULL;
- if (irq == IRQ_T_INT_GROUP) {
- mask = __raw_readl(REG_AIC_GEN);
- __raw_writel(TIME_GROUP_IRQ | mask, REG_AIC_GEN);
- __raw_writel(1 << IRQ_T_INT_GROUP, REG_AIC_MECR);
- }
__raw_writel(1 << irq, REG_AIC_MECR);
+
+ switch (irq) {
+ case IRQ_GROUP0:
+ group_irq = &group_nirq0;
+ break;
+
+ case IRQ_GROUP1:
+ group_irq = &group_nirq1;
+ break;
+
+ case IRQ_USBH:
+ group_irq = &group_usbh;
+ break;
+
+ case IRQ_T_INT_GROUP:
+ group_irq = &group_ottimer;
+ break;
+
+ case IRQ_GDMAGROUP:
+ group_irq = &group_gdma;
+ break;
+
+ case IRQ_SCGROUP:
+ group_irq = &group_sc;
+ break;
+
+ case IRQ_I2CGROUP:
+ group_irq = &group_i2c;
+ break;
+
+ case IRQ_P2SGROUP:
+ group_irq = &group_ps2;
+ break;
+ }
+
+ if (group_irq)
+ group_irq_enable(group_irq);
}
static struct irq_chip w90x900_irq_chip = {
diff --git a/arch/arm/mach-w90x900/mach-w90p910evb.c b/arch/arm/mach-w90x900/mach-w90p910evb.c
index 7a62bd348e80..117578aed681 100644
--- a/arch/arm/mach-w90x900/mach-w90p910evb.c
+++ b/arch/arm/mach-w90x900/mach-w90p910evb.c
@@ -20,7 +20,13 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+
#include <linux/mtd/physmap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -35,6 +41,8 @@
#define W90P910_FLASH_BASE 0xA0000000
#define W90P910_FLASH_SIZE 0x400000
+#define SPIOFFSET 0x200
+#define SPIOREG_SIZE 0x100
static struct mtd_partition w90p910_flash_partitions[] = {
{
@@ -228,6 +236,132 @@ struct platform_device w90x900_device_usbgadget = {
};
EXPORT_SYMBOL(w90x900_device_usbgadget);
+/* FMI Device */
+
+static struct resource w90p910_fmi_resource[] = {
+ [0] = {
+ .start = W90X900_PA_FMI,
+ .end = W90X900_PA_FMI + W90X900_SZ_FMI - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FMI,
+ .end = IRQ_FMI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device w90p910_device_fmi = {
+ .name = "w90p910-fmi",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(w90p910_fmi_resource),
+ .resource = w90p910_fmi_resource,
+};
+
+/* MAC device */
+
+static struct resource w90x900_emc_resource[] = {
+ [0] = {
+ .start = W90X900_PA_EMC,
+ .end = W90X900_PA_EMC + W90X900_SZ_EMC - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_EMCTX,
+ .end = IRQ_EMCTX,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_EMCRX,
+ .end = IRQ_EMCRX,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 w90x900_device_emc_dmamask = 0xffffffffUL;
+static struct platform_device w90p910_device_emc = {
+ .name = "w90p910-emc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(w90x900_emc_resource),
+ .resource = w90x900_emc_resource,
+ .dev = {
+ .dma_mask = &w90x900_device_emc_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+/* SPI device */
+
+static struct resource w90p910_spi_resource[] = {
+ [0] = {
+ .start = W90X900_PA_I2C + SPIOFFSET,
+ .end = W90X900_PA_I2C + SPIOFFSET + SPIOREG_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SSP,
+ .end = IRQ_SSP,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device w90p910_device_spi = {
+ .name = "w90p910-spi",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(w90p910_spi_resource),
+ .resource = w90p910_spi_resource,
+};
+
+/* spi device, spi flash info */
+
+static struct mtd_partition w90p910_spi_flash_partitions[] = {
+ {
+ .name = "bootloader(spi)",
+ .size = 0x0100000,
+ .offset = 0,
+ },
+};
+
+static struct flash_platform_data w90p910_spi_flash_data = {
+ .name = "m25p80",
+ .parts = w90p910_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(w90p910_spi_flash_partitions),
+ .type = "w25x16",
+};
+
+static struct spi_board_info w90p910_spi_board_info[] __initdata = {
+ {
+ .modalias = "m25p80",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .platform_data = &w90p910_spi_flash_data,
+ .mode = SPI_MODE_0,
+ },
+};
+
+/* WDT Device */
+
+static struct resource w90p910_wdt_resource[] = {
+ [0] = {
+ .start = W90X900_PA_TIMER,
+ .end = W90X900_PA_TIMER + W90X900_SZ_TIMER - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_WDT,
+ .end = IRQ_WDT,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device w90p910_device_wdt = {
+ .name = "w90p910-wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(w90p910_wdt_resource),
+ .resource = w90p910_wdt_resource,
+};
+
static struct map_desc w90p910_iodesc[] __initdata = {
};
@@ -242,6 +376,10 @@ static struct platform_device *w90p910evb_dev[] __initdata = {
&w90x900_device_rtc,
&w90x900_device_kpi,
&w90x900_device_usbgadget,
+ &w90p910_device_fmi,
+ &w90p910_device_emc,
+ &w90p910_device_spi,
+ &w90p910_device_wdt,
};
static void __init w90p910evb_map_io(void)
@@ -253,6 +391,8 @@ static void __init w90p910evb_map_io(void)
static void __init w90p910evb_init(void)
{
platform_add_devices(w90p910evb_dev, ARRAY_SIZE(w90p910evb_dev));
+ spi_register_board_info(w90p910_spi_board_info,
+ ARRAY_SIZE(w90p910_spi_board_info));
}
MACHINE_START(W90P910EVB, "W90P910EVB")
diff --git a/arch/arm/mach-w90x900/mfp-w90p910.c b/arch/arm/mach-w90x900/mfp-w90p910.c
index a3520fefb5e7..e11a32b6856d 100644
--- a/arch/arm/mach-w90x900/mfp-w90p910.c
+++ b/arch/arm/mach-w90x900/mfp-w90p910.c
@@ -34,6 +34,12 @@
#define GPSELEI0 (0x01 << 26)
#define GPSELEI1 (0x01 << 27)
+#define GPIOG0TO1 (0x03 << 14)
+#define GPIOG2TO3 (0x03 << 16)
+#define ENSPI (0x0a << 14)
+#define ENI2C0 (0x01 << 14)
+#define ENI2C1 (0x01 << 16)
+
static DECLARE_MUTEX(mfp_sem);
void mfp_set_groupf(struct device *dev)
@@ -90,7 +96,7 @@ void mfp_set_groupc(struct device *dev)
}
EXPORT_SYMBOL(mfp_set_groupc);
-void mfp_set_groupi(struct device *dev, int gpio)
+void mfp_set_groupi(struct device *dev)
{
unsigned long mfpen;
const char *dev_id;
@@ -103,10 +109,14 @@ void mfp_set_groupi(struct device *dev, int gpio)
mfpen = __raw_readl(REG_MFSEL);
+ mfpen &= ~GPSELEI1;/*default gpio16*/
+
if (strcmp(dev_id, "w90p910-wdog") == 0)
mfpen |= GPSELEI1;/*enable wdog*/
else if (strcmp(dev_id, "w90p910-atapi") == 0)
mfpen |= GPSELEI0;/*enable atapi*/
+ else if (strcmp(dev_id, "w90p910-keypad") == 0)
+ mfpen &= ~GPSELEI0;/*enable keypad*/
__raw_writel(mfpen, REG_MFSEL);
@@ -114,3 +124,35 @@ void mfp_set_groupi(struct device *dev, int gpio)
}
EXPORT_SYMBOL(mfp_set_groupi);
+void mfp_set_groupg(struct device *dev)
+{
+ unsigned long mfpen;
+ const char *dev_id;
+
+ BUG_ON(!dev);
+
+ down(&mfp_sem);
+
+ dev_id = dev_name(dev);
+
+ mfpen = __raw_readl(REG_MFSEL);
+
+ if (strcmp(dev_id, "w90p910-spi") == 0) {
+ mfpen &= ~(GPIOG0TO1 | GPIOG2TO3);
+ mfpen |= ENSPI;/*enable spi*/
+ } else if (strcmp(dev_id, "w90p910-i2c0") == 0) {
+ mfpen &= ~(GPIOG0TO1);
+ mfpen |= ENI2C0;/*enable i2c0*/
+ } else if (strcmp(dev_id, "w90p910-i2c1") == 0) {
+ mfpen &= ~(GPIOG2TO3);
+ mfpen |= ENI2C1;/*enable i2c1*/
+ } else {
+ mfpen &= ~(GPIOG0TO1 | GPIOG2TO3);/*GPIOG[3:0]*/
+ }
+
+ __raw_writel(mfpen, REG_MFSEL);
+
+ up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupg);
+
diff --git a/arch/arm/mach-w90x900/w90p910.c b/arch/arm/mach-w90x900/w90p910.c
index 1c97e4930b7a..8444eababaab 100644
--- a/arch/arm/mach-w90x900/w90p910.c
+++ b/arch/arm/mach-w90x900/w90p910.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/serial_8250.h>
+#include <linux/delay.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -32,6 +33,8 @@
#include <mach/hardware.h>
#include <mach/regs-serial.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-ebi.h>
#include "cpu.h"
#include "clock.h"
@@ -57,9 +60,12 @@ static struct map_desc w90p910_iodesc[] __initdata = {
static DEFINE_CLK(lcd, 0);
static DEFINE_CLK(audio, 1);
static DEFINE_CLK(fmi, 4);
+static DEFINE_SUBCLK(ms, 0);
+static DEFINE_SUBCLK(sd, 1);
static DEFINE_CLK(dmac, 5);
static DEFINE_CLK(atapi, 6);
static DEFINE_CLK(emc, 7);
+static DEFINE_SUBCLK(rmii, 2);
static DEFINE_CLK(usbd, 8);
static DEFINE_CLK(usbh, 9);
static DEFINE_CLK(g2d, 10);;
@@ -75,9 +81,12 @@ static struct clk_lookup w90p910_clkregs[] = {
DEF_CLKLOOK(&clk_lcd, "w90p910-lcd", NULL),
DEF_CLKLOOK(&clk_audio, "w90p910-audio", NULL),
DEF_CLKLOOK(&clk_fmi, "w90p910-fmi", NULL),
+ DEF_CLKLOOK(&clk_ms, "w90p910-fmi", "MS"),
+ DEF_CLKLOOK(&clk_sd, "w90p910-fmi", "SD"),
DEF_CLKLOOK(&clk_dmac, "w90p910-dmac", NULL),
DEF_CLKLOOK(&clk_atapi, "w90p910-atapi", NULL),
DEF_CLKLOOK(&clk_emc, "w90p910-emc", NULL),
+ DEF_CLKLOOK(&clk_rmii, "w90p910-emc", "RMII"),
DEF_CLKLOOK(&clk_usbd, "w90p910-usbd", NULL),
DEF_CLKLOOK(&clk_usbh, "w90p910-usbh", NULL),
DEF_CLKLOOK(&clk_g2d, "w90p910-g2d", NULL),
@@ -87,7 +96,7 @@ static struct clk_lookup w90p910_clkregs[] = {
DEF_CLKLOOK(&clk_wdt, "w90p910-wdt", NULL),
DEF_CLKLOOK(&clk_gdma, "w90p910-gdma", NULL),
DEF_CLKLOOK(&clk_adc, "w90p910-adc", NULL),
- DEF_CLKLOOK(&clk_usi, "w90p910-usi", NULL),
+ DEF_CLKLOOK(&clk_usi, "w90p910-spi", NULL),
};
/* Initial serial platform data */
@@ -117,6 +126,83 @@ void __init w90p910_map_io(struct map_desc *mach_desc, int mach_size)
printk(KERN_ERR "CPU type 0x%08lx is not W90P910\n", idcode);
}
+/*Set W90P910 cpu frequence*/
+static int __init w90p910_set_clkval(unsigned int cpufreq)
+{
+ unsigned int pllclk, ahbclk, apbclk, val;
+
+ pllclk = 0;
+ ahbclk = 0;
+ apbclk = 0;
+
+ switch (cpufreq) {
+ case 66:
+ pllclk = PLL_66MHZ;
+ ahbclk = AHB_CPUCLK_1_1;
+ apbclk = APB_AHB_1_2;
+ break;
+
+ case 100:
+ pllclk = PLL_100MHZ;
+ ahbclk = AHB_CPUCLK_1_1;
+ apbclk = APB_AHB_1_2;
+ break;
+
+ case 120:
+ pllclk = PLL_120MHZ;
+ ahbclk = AHB_CPUCLK_1_2;
+ apbclk = APB_AHB_1_2;
+ break;
+
+ case 166:
+ pllclk = PLL_166MHZ;
+ ahbclk = AHB_CPUCLK_1_2;
+ apbclk = APB_AHB_1_2;
+ break;
+
+ case 200:
+ pllclk = PLL_200MHZ;
+ ahbclk = AHB_CPUCLK_1_2;
+ apbclk = APB_AHB_1_2;
+ break;
+ }
+
+ __raw_writel(pllclk, REG_PLLCON0);
+
+ val = __raw_readl(REG_CLKDIV);
+ val &= ~(0x03 << 24 | 0x03 << 26);
+ val |= (ahbclk << 24 | apbclk << 26);
+ __raw_writel(val, REG_CLKDIV);
+
+ return 0;
+}
+static int __init w90p910_set_cpufreq(char *str)
+{
+ unsigned long cpufreq, val;
+
+ if (!*str)
+ return 0;
+
+ strict_strtoul(str, 0, &cpufreq);
+
+ w90p910_clock_source(NULL, "ext");
+
+ w90p910_set_clkval(cpufreq);
+
+ mdelay(1);
+
+ val = __raw_readl(REG_CKSKEW);
+ val &= ~0xff;
+ val |= DEFAULTSKEW;
+ __raw_writel(val, REG_CKSKEW);
+
+ w90p910_clock_source(NULL, "pll0");
+
+ return 1;
+}
+
+__setup("cpufreq=", w90p910_set_cpufreq);
+
/*Init W90P910 clock*/
void __init w90p910_init_clocks(void)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 83c025e72ceb..5fe595aeba69 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -758,7 +758,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
config CACHE_L2X0
bool "Enable the L2x0 outer cache controller"
depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
- REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX
+ REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK
default y
select OUTER_CACHE
help
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 03cd27d917b9..b270d6228fe2 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -159,7 +159,9 @@ union offset_union {
#define __get8_unaligned_check(ins,val,addr,err) \
__asm__( \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
@@ -215,7 +217,9 @@ union offset_union {
do { \
unsigned int err = 0, v = val, a = addr; \
__asm__( FIRST_BYTE_16 \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
"2: "ins" %1, [%2]\n" \
"3:\n" \
@@ -245,11 +249,17 @@ union offset_union {
do { \
unsigned int err = 0, v = val, a = addr; \
__asm__( FIRST_BYTE_32 \
- "1: "ins" %1, [%2], #1\n" \
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
+ THUMB( "1: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
- "2: "ins" %1, [%2], #1\n" \
+ ARM( "2: "ins" %1, [%2], #1\n" ) \
+ THUMB( "2: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
- "3: "ins" %1, [%2], #1\n" \
+ ARM( "3: "ins" %1, [%2], #1\n" ) \
+ THUMB( "3: "ins" %1, [%2]\n" ) \
+ THUMB( " add %2, %2, #1\n" ) \
" mov %1, %1, "NEXT_BYTE"\n" \
"4: "ins" %1, [%2]\n" \
"5:\n" \
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index be93ff02a98d..bda0ec31a4e2 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -21,7 +21,7 @@
*
* Flush the whole D-cache.
*
- * Corrupted registers: r0-r5, r7, r9-r11
+ * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
*
* - mm - mm_struct describing address space
*/
@@ -51,8 +51,12 @@ loop1:
loop2:
mov r9, r4 @ create working copy of max way size
loop3:
- orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
- orr r11, r11, r7, lsl r2 @ factor index number into r11
+ ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11
+ THUMB( lsl r6, r9, r5 )
+ THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
+ ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11
+ THUMB( lsl r6, r7, r2 )
+ THUMB( orr r11, r11, r6 ) @ factor index number into r11
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge loop3
@@ -82,11 +86,13 @@ ENDPROC(v7_flush_dcache_all)
*
*/
ENTRY(v7_flush_kern_cache_all)
- stmfd sp!, {r4-r5, r7, r9-r11, lr}
+ ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
bl v7_flush_dcache_all
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
- ldmfd sp!, {r4-r5, r7, r9-r11, lr}
+ ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
+ THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
mov pc, lr
ENDPROC(v7_flush_kern_cache_all)
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index fc84fcc74380..6bda76a43199 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -59,6 +59,6 @@ void __new_context(struct mm_struct *mm)
}
spin_unlock(&cpu_asid_lock);
- mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
+ cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id()));
mm->context.id = asid;
}
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 510c179b0ac8..b30925fcbcdc 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -36,7 +36,34 @@
#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+static u64 get_coherent_dma_mask(struct device *dev)
+{
+ u64 mask = ISA_DMA_THRESHOLD;
+
+ if (dev) {
+ mask = dev->coherent_dma_mask;
+
+ /*
+ * Sanity check the DMA mask - it must be non-zero, and
+ * must be able to be satisfied by a DMA allocation.
+ */
+ if (mask == 0) {
+ dev_warn(dev, "coherent DMA mask is unset\n");
+ return 0;
+ }
+
+ if ((~mask) & ISA_DMA_THRESHOLD) {
+ dev_warn(dev, "coherent DMA mask %#llx is smaller "
+ "than system GFP_DMA mask %#llx\n",
+ mask, (unsigned long long)ISA_DMA_THRESHOLD);
+ return 0;
+ }
+ }
+ return mask;
+}
+
+#ifdef CONFIG_MMU
/*
* These are the page tables (2MB each) covering uncached, DMA consistent allocations
*/
@@ -152,7 +179,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
struct page *page;
struct arm_vm_region *c;
unsigned long order;
- u64 mask = ISA_DMA_THRESHOLD, limit;
+ u64 mask = get_coherent_dma_mask(dev);
+ u64 limit;
if (!consistent_pte[0]) {
printk(KERN_ERR "%s: not initialised\n", __func__);
@@ -160,25 +188,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
return NULL;
}
- if (dev) {
- mask = dev->coherent_dma_mask;
-
- /*
- * Sanity check the DMA mask - it must be non-zero, and
- * must be able to be satisfied by a DMA allocation.
- */
- if (mask == 0) {
- dev_warn(dev, "coherent DMA mask is unset\n");
- goto no_page;
- }
-
- if ((~mask) & ISA_DMA_THRESHOLD) {
- dev_warn(dev, "coherent DMA mask %#llx is smaller "
- "than system GFP_DMA mask %#llx\n",
- mask, (unsigned long long)ISA_DMA_THRESHOLD);
- goto no_page;
- }
- }
+ if (!mask)
+ goto no_page;
/*
* Sanity check the allocation size.
@@ -267,6 +278,31 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
*handle = ~0;
return NULL;
}
+#else /* !CONFIG_MMU */
+static void *
+__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+ pgprot_t prot)
+{
+ void *virt;
+ u64 mask = get_coherent_dma_mask(dev);
+
+ if (!mask)
+ goto error;
+
+ if (mask != 0xffffffff)
+ gfp |= GFP_DMA;
+ virt = kmalloc(size, gfp);
+ if (!virt)
+ goto error;
+
+ *handle = virt_to_dma(dev, virt);
+ return virt;
+
+error:
+ *handle = ~0;
+ return NULL;
+}
+#endif /* CONFIG_MMU */
/*
* Allocate DMA-coherent memory space and return both the kernel remapped
@@ -311,9 +347,10 @@ EXPORT_SYMBOL(dma_alloc_writecombine);
static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
+ int ret = -ENXIO;
+#ifdef CONFIG_MMU
unsigned long flags, user_size, kern_size;
struct arm_vm_region *c;
- int ret = -ENXIO;
user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
@@ -334,6 +371,7 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
vma->vm_page_prot);
}
}
+#endif /* CONFIG_MMU */
return ret;
}
@@ -358,6 +396,7 @@ EXPORT_SYMBOL(dma_mmap_writecombine);
* free a page as defined by the above mapping.
* Must not be called with IRQs disabled.
*/
+#ifdef CONFIG_MMU
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{
struct arm_vm_region *c;
@@ -444,6 +483,14 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
__func__, cpu_addr);
dump_stack();
}
+#else /* !CONFIG_MMU */
+void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
+{
+ if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
+ return;
+ kfree(cpu_addr);
+}
+#endif /* CONFIG_MMU */
EXPORT_SYMBOL(dma_free_coherent);
/*
@@ -451,10 +498,12 @@ EXPORT_SYMBOL(dma_free_coherent);
*/
static int __init consistent_init(void)
{
+ int ret = 0;
+#ifdef CONFIG_MMU
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
- int ret = 0, i = 0;
+ int i = 0;
u32 base = CONSISTENT_BASE;
do {
@@ -477,6 +526,7 @@ static int __init consistent_init(void)
consistent_pte[i++] = pte;
base += (1 << PGDIR_SHIFT);
} while (base < CONSISTENT_END);
+#endif /* !CONFIG_MMU */
return ret;
}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 6fdcbb709827..556c8daf087d 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -16,6 +16,7 @@
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/page-flags.h>
+#include <linux/sched.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -23,6 +24,7 @@
#include "fault.h"
+#ifdef CONFIG_MMU
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
@@ -97,6 +99,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
printk("\n");
}
+#else /* CONFIG_MMU */
+void show_pte(struct mm_struct *mm, unsigned long addr)
+{ }
+#endif /* CONFIG_MMU */
/*
* Oops. The kernel tried to access some page that wasn't present.
@@ -171,6 +177,7 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
__do_kernel_fault(mm, addr, fsr, regs);
}
+#ifdef CONFIG_MMU
#define VM_FAULT_BADMAP 0x010000
#define VM_FAULT_BADACCESS 0x020000
@@ -322,6 +329,13 @@ no_context:
__do_kernel_fault(mm, addr, fsr, regs);
return 0;
}
+#else /* CONFIG_MMU */
+static int
+do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+ return 0;
+}
+#endif /* CONFIG_MMU */
/*
* First Level Translation Fault Handler
@@ -340,6 +354,7 @@ no_context:
* interrupt or a critical region, and should only copy the information
* from the master page table, nothing more.
*/
+#ifdef CONFIG_MMU
static int __kprobes
do_translation_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
@@ -378,6 +393,14 @@ bad_area:
do_bad_area(addr, fsr, regs);
return 0;
}
+#else /* CONFIG_MMU */
+static int
+do_translation_fault(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+{
+ return 0;
+}
+#endif /* CONFIG_MMU */
/*
* Some section permission faults need to be handled gracefully.
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index c07222eb5ce0..d9773a63e151 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -50,7 +50,7 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
void flush_cache_mm(struct mm_struct *mm)
{
if (cache_is_vivt()) {
- if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
__cpuc_flush_user_all();
return;
}
@@ -73,7 +73,7 @@ void flush_cache_mm(struct mm_struct *mm)
void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
{
if (cache_is_vivt()) {
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask))
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
vma->vm_flags);
return;
@@ -97,7 +97,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned
void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
{
if (cache_is_vivt()) {
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
unsigned long addr = user_addr & PAGE_MASK;
__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
}
@@ -113,7 +113,7 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
unsigned long len, int write)
{
if (cache_is_vivt()) {
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
unsigned long addr = (unsigned long)kaddr;
__cpuc_coherent_kern_range(addr, addr + len);
}
@@ -126,7 +126,7 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
}
/* VIPT non-aliasing cache */
- if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask) &&
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)) &&
vma->vm_flags & VM_EXEC) {
unsigned long addr = (unsigned long)kaddr;
/* only flushing the kernel mapping on non-aliasing VIPT */
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index ad7bacc693b2..900811cc9130 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -12,6 +12,7 @@
#include <asm/cacheflush.h>
#include <asm/sections.h>
#include <asm/page.h>
+#include <asm/setup.h>
#include <asm/mach/arch.h>
#include "mm.h"
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 54b1f721dec8..7d63beaf9745 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -77,19 +77,15 @@
* Sanity check the PTE configuration for the code below - which makes
* certain assumptions about how these bits are layed out.
*/
+#ifdef CONFIG_MMU
#if L_PTE_SHARED != PTE_EXT_SHARED
#error PTE shared bit mismatch
#endif
-#if L_PTE_BUFFERABLE != PTE_BUFFERABLE
-#error PTE bufferable bit mismatch
-#endif
-#if L_PTE_CACHEABLE != PTE_CACHEABLE
-#error PTE cacheable bit mismatch
-#endif
#if (L_PTE_EXEC+L_PTE_USER+L_PTE_WRITE+L_PTE_DIRTY+L_PTE_YOUNG+\
L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED
#error Invalid Linux PTE bit settings
#endif
+#endif /* CONFIG_MMU */
/*
* The ARMv6 and ARMv7 set_pte_ext translation function.
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 180a08d03a03..f3fa1c32fe92 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -127,7 +127,9 @@ ENDPROC(cpu_v7_switch_mm)
*/
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
- str r1, [r0], #-2048 @ linux version
+ ARM( str r1, [r0], #-2048 ) @ linux version
+ THUMB( str r1, [r0] ) @ linux version
+ THUMB( sub r0, r0, #2048 )
bic r3, r1, #0x000003f0
bic r3, r3, #PTE_TYPE_MASK
@@ -232,7 +234,6 @@ __v7_setup:
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
mov r10, #0x1f @ domains 0, 1 = manager
mcr p15, 0, r10, c3, c0, 0 @ load domain access register
-#endif
/*
* Memory region attributes with SCTLR.TRE=1
*
@@ -265,6 +266,7 @@ __v7_setup:
ldr r6, =0x40e040e0 @ NMRR
mcr p15, 0, r5, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
+#endif
adr r5, v7_crval
ldmia r5, {r5, r6}
#ifdef CONFIG_CPU_ENDIAN_BE8
@@ -273,6 +275,7 @@ __v7_setup:
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, r5 @ clear bits them
orr r0, r0, r6 @ set them
+ THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions
mov pc, lr @ return to head.S:__ret
ENDPROC(__v7_setup)
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index be4eefda4767..9395898dd49a 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -281,24 +281,27 @@ static int /* __init */ fpga_probe(struct platform_device *pdev)
return 0;
}
-static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+static int fpga_suspend_noirq(struct device *dev)
{
__raw_writew(~0, &fpga->leds);
return 0;
}
-static int fpga_resume_early(struct platform_device *pdev)
+static int fpga_resume_noirq(struct device *dev)
{
__raw_writew(~hw_led_state, &fpga->leds);
return 0;
}
+static struct dev_pm_ops fpga_dev_pm_ops = {
+ .suspend_noirq = fpga_suspend_noirq,
+ .resume_noirq = fpga_resume_noirq,
+};
static struct platform_driver led_driver = {
.driver.name = "omap_dbg_led",
+ .driver.pm = &fpga_dev_pm_ops,
.probe = fpga_probe,
- .suspend_late = fpga_suspend_late,
- .resume_early = fpga_resume_early,
};
static int __init fpga_init(void)
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 26b387c12423..3d03337ad422 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -1264,8 +1264,9 @@ static struct irq_chip mpuio_irq_chip = {
#include <linux/platform_device.h>
-static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+static int omap_mpuio_suspend_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
unsigned long flags;
@@ -1278,8 +1279,9 @@ static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t me
return 0;
}
-static int omap_mpuio_resume_early(struct platform_device *pdev)
+static int omap_mpuio_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
unsigned long flags;
@@ -1291,14 +1293,18 @@ static int omap_mpuio_resume_early(struct platform_device *pdev)
return 0;
}
+static struct dev_pm_ops omap_mpuio_dev_pm_ops = {
+ .suspend_noirq = omap_mpuio_suspend_noirq,
+ .resume_noirq = omap_mpuio_resume_noirq,
+};
+
/* use platform_driver for this, now that there's no longer any
* point to sys_device (other than not disturbing old code).
*/
static struct platform_driver omap_mpuio_driver = {
- .suspend_late = omap_mpuio_suspend_late,
- .resume_early = omap_mpuio_resume_early,
.driver = {
.name = "mpuio",
+ .pm = &omap_mpuio_dev_pm_ops,
},
};
diff --git a/arch/arm/plat-pxa/include/plat/mfp.h b/arch/arm/plat-pxa/include/plat/mfp.h
index 64019464c8db..1528dc27c859 100644
--- a/arch/arm/plat-pxa/include/plat/mfp.h
+++ b/arch/arm/plat-pxa/include/plat/mfp.h
@@ -150,6 +150,74 @@ enum {
MFP_PIN_GPIO125,
MFP_PIN_GPIO126,
MFP_PIN_GPIO127,
+
+ MFP_PIN_GPIO128,
+ MFP_PIN_GPIO129,
+ MFP_PIN_GPIO130,
+ MFP_PIN_GPIO131,
+ MFP_PIN_GPIO132,
+ MFP_PIN_GPIO133,
+ MFP_PIN_GPIO134,
+ MFP_PIN_GPIO135,
+ MFP_PIN_GPIO136,
+ MFP_PIN_GPIO137,
+ MFP_PIN_GPIO138,
+ MFP_PIN_GPIO139,
+ MFP_PIN_GPIO140,
+ MFP_PIN_GPIO141,
+ MFP_PIN_GPIO142,
+ MFP_PIN_GPIO143,
+ MFP_PIN_GPIO144,
+ MFP_PIN_GPIO145,
+ MFP_PIN_GPIO146,
+ MFP_PIN_GPIO147,
+ MFP_PIN_GPIO148,
+ MFP_PIN_GPIO149,
+ MFP_PIN_GPIO150,
+ MFP_PIN_GPIO151,
+ MFP_PIN_GPIO152,
+ MFP_PIN_GPIO153,
+ MFP_PIN_GPIO154,
+ MFP_PIN_GPIO155,
+ MFP_PIN_GPIO156,
+ MFP_PIN_GPIO157,
+ MFP_PIN_GPIO158,
+ MFP_PIN_GPIO159,
+ MFP_PIN_GPIO160,
+ MFP_PIN_GPIO161,
+ MFP_PIN_GPIO162,
+ MFP_PIN_GPIO163,
+ MFP_PIN_GPIO164,
+ MFP_PIN_GPIO165,
+ MFP_PIN_GPIO166,
+ MFP_PIN_GPIO167,
+ MFP_PIN_GPIO168,
+ MFP_PIN_GPIO169,
+ MFP_PIN_GPIO170,
+ MFP_PIN_GPIO171,
+ MFP_PIN_GPIO172,
+ MFP_PIN_GPIO173,
+ MFP_PIN_GPIO174,
+ MFP_PIN_GPIO175,
+ MFP_PIN_GPIO176,
+ MFP_PIN_GPIO177,
+ MFP_PIN_GPIO178,
+ MFP_PIN_GPIO179,
+ MFP_PIN_GPIO180,
+ MFP_PIN_GPIO181,
+ MFP_PIN_GPIO182,
+ MFP_PIN_GPIO183,
+ MFP_PIN_GPIO184,
+ MFP_PIN_GPIO185,
+ MFP_PIN_GPIO186,
+ MFP_PIN_GPIO187,
+ MFP_PIN_GPIO188,
+ MFP_PIN_GPIO189,
+ MFP_PIN_GPIO190,
+ MFP_PIN_GPIO191,
+
+ MFP_PIN_GPIO255 = 255,
+
MFP_PIN_GPIO0_2,
MFP_PIN_GPIO1_2,
MFP_PIN_GPIO2_2,
diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c
index 07a6516a4f3c..47632fc7eb66 100644
--- a/arch/arm/plat-s3c64xx/pm.c
+++ b/arch/arm/plat-s3c64xx/pm.c
@@ -117,8 +117,6 @@ void s3c_pm_save_core(void)
* this.
*/
-#include <plat/regs-gpio.h>
-
static void s3c64xx_cpu_suspend(void)
{
unsigned long tmp;
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
index 1debc1f9f987..febac1950d8e 100644
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c
@@ -153,7 +153,7 @@ static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
u32 div;
if (parent < rate)
- return rate;
+ return parent;
div = (parent / rate) - 1;
if (div > armclk_mask)
@@ -175,7 +175,7 @@ static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
div = clk_get_rate(clk->parent) / rate;
val = __raw_readl(S3C_CLK_DIV0);
- val &= armclk_mask;
+ val &= ~armclk_mask;
val |= (div - 1);
__raw_writel(val, S3C_CLK_DIV0);
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
index d41200382208..6d6b1a468eda 100644
--- a/arch/arm/plat-stmp3xxx/pinmux.c
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -22,7 +22,6 @@
#include <linux/sysdev.h>
#include <linux/string.h>
#include <linux/bitops.h>
-#include <linux/sysdev.h>
#include <linux/irq.h>
#include <mach/hardware.h>
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 33026eff2aa4..200d83a98286 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# Last update: Sat Jun 20 22:28:39 2009
+# Last update: Sat Aug 1 16:26:02 2009
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -1769,7 +1769,7 @@ mx31cicada MACH_MX31CICADA MX31CICADA 1777
mi424wr MACH_MI424WR MI424WR 1778
axs_ultrax MACH_AXS_ULTRAX AXS_ULTRAX 1779
at572d940deb MACH_AT572D940DEB AT572D940DEB 1780
-davinci_da8xx_evm MACH_DAVINCI_DA8XX_EVM DAVINCI_DA8XX_EVM 1781
+davinci_da830_evm MACH_DAVINCI_DA830_EVM DAVINCI_DA830_EVM 1781
ep9302 MACH_EP9302 EP9302 1782
at572d940hfek MACH_AT572D940HFEB AT572D940HFEB 1783
cybook3 MACH_CYBOOK3 CYBOOK3 1784
@@ -2280,3 +2280,72 @@ htcrhodium MACH_HTCRHODIUM HTCRHODIUM 2292
htctopaz MACH_HTCTOPAZ HTCTOPAZ 2293
matrix504 MACH_MATRIX504 MATRIX504 2294
mrfsa MACH_MRFSA MRFSA 2295
+sc_p270 MACH_SC_P270 SC_P270 2296
+atlas5_evb MACH_ATLAS5_EVB ATLAS5_EVB 2297
+pelco_lobox MACH_PELCO_LOBOX PELCO_LOBOX 2298
+dilax_pcu200 MACH_DILAX_PCU200 DILAX_PCU200 2299
+leonardo MACH_LEONARDO LEONARDO 2300
+zoran_approach7 MACH_ZORAN_APPROACH7 ZORAN_APPROACH7 2301
+dp6xx MACH_DP6XX DP6XX 2302
+bcm2153_vesper MACH_BCM2153_VESPER BCM2153_VESPER 2303
+mahimahi MACH_MAHIMAHI MAHIMAHI 2304
+clickc MACH_CLICKC CLICKC 2305
+zb_gateway MACH_ZB_GATEWAY ZB_GATEWAY 2306
+tazcard MACH_TAZCARD TAZCARD 2307
+tazdev MACH_TAZDEV TAZDEV 2308
+annax_cb_arm MACH_ANNAX_CB_ARM ANNAX_CB_ARM 2309
+annax_dm3 MACH_ANNAX_DM3 ANNAX_DM3 2310
+cerebric MACH_CEREBRIC CEREBRIC 2311
+orca MACH_ORCA ORCA 2312
+pc9260 MACH_PC9260 PC9260 2313
+ems285a MACH_EMS285A EMS285A 2314
+gec2410 MACH_GEC2410 GEC2410 2315
+gec2440 MACH_GEC2440 GEC2440 2316
+mw903 MACH_ARCH_MW903 ARCH_MW903 2317
+mw2440 MACH_MW2440 MW2440 2318
+ecac2378 MACH_ECAC2378 ECAC2378 2319
+tazkiosk MACH_TAZKIOSK TAZKIOSK 2320
+whiterabbit_mch MACH_WHITERABBIT_MCH WHITERABBIT_MCH 2321
+sbox9263 MACH_SBOX9263 SBOX9263 2322
+oreo MACH_OREO OREO 2323
+smdk6442 MACH_SMDK6442 SMDK6442 2324
+openrd_base MACH_OPENRD_BASE OPENRD_BASE 2325
+incredible MACH_INCREDIBLE INCREDIBLE 2326
+incrediblec MACH_INCREDIBLEC INCREDIBLEC 2327
+heroct MACH_HEROCT HEROCT 2328
+mmnet1000 MACH_MMNET1000 MMNET1000 2329
+devkit8000 MACH_DEVKIT8000 DEVKIT8000 2330
+devkit9000 MACH_DEVKIT9000 DEVKIT9000 2331
+mx31txtr MACH_MX31TXTR MX31TXTR 2332
+u380 MACH_U380 U380 2333
+oamp3_hualu MACH_HUALU_BOARD HUALU_BOARD 2334
+npcmx50 MACH_NPCMX50 NPCMX50 2335
+mx51_lange51 MACH_MX51_LANGE51 MX51_LANGE51 2336
+mx51_lange52 MACH_MX51_LANGE52 MX51_LANGE52 2337
+riom MACH_RIOM RIOM 2338
+comcas MACH_COMCAS COMCAS 2339
+wsi_mx27 MACH_WSI_MX27 WSI_MX27 2340
+cm_t35 MACH_CM_T35 CM_T35 2341
+net2big MACH_NET2BIG NET2BIG 2342
+motorola_a1600 MACH_MOTOROLA_A1600 MOTOROLA_A1600 2343
+igep0020 MACH_IGEP0020 IGEP0020 2344
+igep0010 MACH_IGEP0010 IGEP0010 2345
+mv6281gtwge2 MACH_MV6281GTWGE2 MV6281GTWGE2 2346
+scat100 MACH_SCAT100 SCAT100 2347
+sanmina MACH_SANMINA SANMINA 2348
+momento MACH_MOMENTO MOMENTO 2349
+nuc9xx MACH_NUC9XX NUC9XX 2350
+nuc910evb MACH_NUC910EVB NUC910EVB 2351
+nuc920evb MACH_NUC920EVB NUC920EVB 2352
+nuc950evb MACH_NUC950EVB NUC950EVB 2353
+nuc945evb MACH_NUC945EVB NUC945EVB 2354
+nuc960evb MACH_NUC960EVB NUC960EVB 2355
+nuc932evb MACH_NUC932EVB NUC932EVB 2356
+nuc900 MACH_NUC900 NUC900 2357
+sd1soc MACH_SD1SOC SD1SOC 2358
+ln2440bc MACH_LN2440BC LN2440BC 2359
+rsbc MACH_RSBC RSBC 2360
+openrd_client MACH_OPENRD_CLIENT OPENRD_CLIENT 2361
+hpipaq11x MACH_HPIPAQ11X HPIPAQ11X 2362
+wayland MACH_WAYLAND WAYLAND 2363
+acnbsx102 MACH_ACNBSX102 ACNBSX102 2364
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index a2bed62aec21..4fa9903b83cf 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -42,6 +42,7 @@ ENTRY(vfp_null_entry)
mov pc, lr
ENDPROC(vfp_null_entry)
+ .align 2
.LCvfp:
.word vfp_vector
@@ -61,6 +62,7 @@ ENTRY(vfp_testing_entry)
mov pc, r9 @ we have handled the fault
ENDPROC(vfp_testing_entry)
+ .align 2
VFP_arch_address:
.word VFP_arch
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 1aeae38725dd..66dc2d03b7fc 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -209,40 +209,55 @@ ENDPROC(vfp_save_state)
last_VFP_context_address:
.word last_VFP_context
-ENTRY(vfp_get_float)
- add pc, pc, r0, lsl #3
+ .macro tbl_branch, base, tmp, shift
+#ifdef CONFIG_THUMB2_KERNEL
+ adr \tmp, 1f
+ add \tmp, \tmp, \base, lsl \shift
+ mov pc, \tmp
+#else
+ add pc, pc, \base, lsl \shift
mov r0, r0
+#endif
+1:
+ .endm
+
+ENTRY(vfp_get_float)
+ tbl_branch r0, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0
+1: mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0
mov pc, lr
- mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1
+ .org 1b + 8
+1: mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1
mov pc, lr
+ .org 1b + 8
.endr
ENDPROC(vfp_get_float)
ENTRY(vfp_put_float)
- add pc, pc, r1, lsl #3
- mov r0, r0
+ tbl_branch r1, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0
+1: mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0
mov pc, lr
- mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1
+ .org 1b + 8
+1: mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1
mov pc, lr
+ .org 1b + 8
.endr
ENDPROC(vfp_put_float)
ENTRY(vfp_get_double)
- add pc, pc, r0, lsl #3
- mov r0, r0
+ tbl_branch r0, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- fmrrd r0, r1, d\dr
+1: fmrrd r0, r1, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#ifdef CONFIG_VFPv3
@ d16 - d31 registers
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr
+1: mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#endif
@@ -253,17 +268,18 @@ ENTRY(vfp_get_double)
ENDPROC(vfp_get_double)
ENTRY(vfp_put_double)
- add pc, pc, r2, lsl #3
- mov r0, r0
+ tbl_branch r2, r3, #3
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- fmdrr d\dr, r0, r1
+1: fmdrr d\dr, r0, r1
mov pc, lr
+ .org 1b + 8
.endr
#ifdef CONFIG_VFPv3
@ d16 - d31 registers
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
- mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr
+1: mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr
mov pc, lr
+ .org 1b + 8
.endr
#endif
ENDPROC(vfp_put_double)
diff --git a/arch/avr32/boards/favr-32/setup.c b/arch/avr32/boards/favr-32/setup.c
index 46c9b0a224cf..75f19f47fb2f 100644
--- a/arch/avr32/boards/favr-32/setup.c
+++ b/arch/avr32/boards/favr-32/setup.c
@@ -72,6 +72,10 @@ static struct ads7846_platform_data ads7843_data = {
.debounce_max = 20,
.debounce_rep = 4,
.debounce_tol = 5,
+
+ .keep_vref_on = true,
+ .settle_delay_usecs = 500,
+ .penirq_recheck_delay_usecs = 100,
};
static struct spi_board_info __initdata spi1_board_info[] = {
diff --git a/arch/avr32/include/asm/pgalloc.h b/arch/avr32/include/asm/pgalloc.h
index 640821323943..92ecd8446ef8 100644
--- a/arch/avr32/include/asm/pgalloc.h
+++ b/arch/avr32/include/asm/pgalloc.h
@@ -83,7 +83,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
quicklist_free_page(QUICK_PT, NULL, pte);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,addr) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb), pte); \
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 7910d41eb886..c4b56654349a 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -124,14 +124,11 @@ SECTIONS
_end = .;
}
+ DWARF_DEBUG
+
/* When something in the kernel is NOT compiled as a module, the module
* cleanup code and data are put into these segments. Both can then be
* thrown away, as cleanup code is never called unless it's a module.
*/
- /DISCARD/ : {
- EXIT_DATA
- *(.exitcall.exit)
- }
-
- DWARF_DEBUG
+ DISCARDS
}
diff --git a/arch/avr32/lib/memcpy.S b/arch/avr32/lib/memcpy.S
index 0abb26142b64..c2ca49d705af 100644
--- a/arch/avr32/lib/memcpy.S
+++ b/arch/avr32/lib/memcpy.S
@@ -24,8 +24,8 @@ memcpy:
brne 1f
/* At this point, "from" is word-aligned */
-2: sub r10, 4
- mov r9, r12
+2: mov r9, r12
+5: sub r10, 4
brlt 4f
3: ld.w r8, r11++
@@ -49,6 +49,7 @@ memcpy:
/* Handle unaligned "from" pointer */
1: sub r10, 4
+ movlt r9, r12
brlt 4b
add r10, r9
lsl r9, 2
@@ -59,4 +60,13 @@ memcpy:
st.b r12++, r8
ld.ub r8, r11++
st.b r12++, r8
- rjmp 2b
+ mov r8, r12
+ add pc, pc, r9
+ sub r8, 1
+ nop
+ sub r8, 1
+ nop
+ sub r8, 1
+ nop
+ mov r9, r8
+ rjmp 5b
diff --git a/arch/blackfin/include/asm/bfin_rotary.h b/arch/blackfin/include/asm/bfin_rotary.h
new file mode 100644
index 000000000000..425ece64fd5e
--- /dev/null
+++ b/arch/blackfin/include/asm/bfin_rotary.h
@@ -0,0 +1,39 @@
+/*
+ * board initialization should put one of these structures into platform_data
+ * and place the bfin-rotary onto platform_bus named "bfin-rotary".
+ */
+
+#ifndef _BFIN_ROTARY_H
+#define _BFIN_ROTARY_H
+
+/* mode bitmasks */
+#define ROT_QUAD_ENC CNTMODE_QUADENC /* quadrature/grey code encoder mode */
+#define ROT_BIN_ENC CNTMODE_BINENC /* binary encoder mode */
+#define ROT_UD_CNT CNTMODE_UDCNT /* rotary counter mode */
+#define ROT_DIR_CNT CNTMODE_DIRCNT /* direction counter mode */
+
+#define ROT_DEBE DEBE /* Debounce Enable */
+
+#define ROT_CDGINV CDGINV /* CDG Pin Polarity Invert */
+#define ROT_CUDINV CUDINV /* CUD Pin Polarity Invert */
+#define ROT_CZMINV CZMINV /* CZM Pin Polarity Invert */
+
+struct bfin_rotary_platform_data {
+ /* set rotary UP KEY_### or BTN_### in case you prefer
+ * bfin-rotary to send EV_KEY otherwise set 0
+ */
+ unsigned int rotary_up_key;
+ /* set rotary DOWN KEY_### or BTN_### in case you prefer
+ * bfin-rotary to send EV_KEY otherwise set 0
+ */
+ unsigned int rotary_down_key;
+ /* set rotary BUTTON KEY_### or BTN_### */
+ unsigned int rotary_button_key;
+ /* set rotary Relative Axis REL_### in case you prefer
+ * bfin-rotary to send EV_REL otherwise set 0
+ */
+ unsigned int rotary_rel_code;
+ unsigned short debounce; /* 0..17 */
+ unsigned short mode;
+};
+#endif
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index 6ac307ca0d80..d7ffe299b979 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -277,8 +277,5 @@ SECTIONS
DWARF_DEBUG
- /DISCARD/ :
- {
- *(.exitcall.exit)
- }
+ DISCARDS
}
diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h
index bdc330cd0e1c..1c58914a8740 100644
--- a/arch/blackfin/mach-bf538/include/mach/defBF539.h
+++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h
@@ -2325,7 +2325,7 @@
#define AMBEN_B0_B1 0x0004 /* Enable Asynchronous Memory Banks 0 & 1 only */
#define AMBEN_B0_B1_B2 0x0006 /* Enable Asynchronous Memory Banks 0, 1, and 2 */
#define AMBEN_ALL 0x0008 /* Enable Asynchronous Memory Banks (all) 0, 1, 2, and 3 */
-#define CDPRIO 0x0100 /* DMA has priority over core for for external accesses */
+#define CDPRIO 0x0100 /* DMA has priority over core for external accesses */
/* EBIU_AMGCTL Bit Positions */
#define AMCKEN_P 0x0000 /* Enable CLKOUT */
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
index 0bc3c4ef0aad..99e4dbb1dfd1 100644
--- a/arch/blackfin/mm/sram-alloc.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -42,9 +42,9 @@
#include <asm/mem_map.h>
#include "blackfin_sram.h"
-static DEFINE_PER_CPU(spinlock_t, l1sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_data_sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_inst_sram_lock) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_data_sram_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock);
static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
/* the data structure for L1 scratchpad and DATA SRAM */
diff --git a/arch/cris/include/arch-v10/arch/mmu.h b/arch/cris/include/arch-v10/arch/mmu.h
index df84f1716e6b..e829e5a37bbe 100644
--- a/arch/cris/include/arch-v10/arch/mmu.h
+++ b/arch/cris/include/arch-v10/arch/mmu.h
@@ -33,10 +33,10 @@ typedef struct
/* CRIS PTE bits (see R_TLB_LO in the register description)
*
- * Bit: 31-13 12-------4 3 2 1 0
- * ________________________________________________
- * | pfn | reserved | global | valid | kernel | we |
- * |_____|__________|________|_______|________|_____|
+ * Bit: 31 30-13 12-------4 3 2 1 0
+ * _______________________________________________________
+ * | cache |pfn | reserved | global | valid | kernel | we |
+ * |_______|____|__________|________|_______|________|_____|
*
* (pfn = physical frame number)
*/
@@ -53,6 +53,7 @@ typedef struct
#define _PAGE_VALID (1<<2) /* page is valid */
#define _PAGE_SILENT_READ (1<<2) /* synonym */
#define _PAGE_GLOBAL (1<<3) /* global page - context is ignored */
+#define _PAGE_NO_CACHE (1<<31) /* part of the uncached memory map */
/* Bits the HW doesn't care about but the kernel uses them in SW */
diff --git a/arch/cris/include/arch-v32/arch/mmu.h b/arch/cris/include/arch-v32/arch/mmu.h
index 6bcdc3fdf7dc..a05b033c5c42 100644
--- a/arch/cris/include/arch-v32/arch/mmu.h
+++ b/arch/cris/include/arch-v32/arch/mmu.h
@@ -28,10 +28,10 @@ typedef struct
/*
* CRISv32 PTE bits:
*
- * Bit: 31-13 12-5 4 3 2 1 0
- * +-----+------+--------+-------+--------+-------+---------+
- * | pfn | zero | global | valid | kernel | write | execute |
- * +-----+------+--------+-------+--------+-------+---------+
+ * Bit: 31 30-13 12-5 4 3 2 1 0
+ * +-------+-----+------+--------+-------+--------+-------+---------+
+ * | cache | pfn | zero | global | valid | kernel | write | execute |
+ * +-------+-----+------+--------+-------+--------+-------+---------+
*/
/*
@@ -45,6 +45,8 @@ typedef struct
#define _PAGE_VALID (1 << 3) /* Page is valid. */
#define _PAGE_SILENT_READ (1 << 3) /* Same as above. */
#define _PAGE_GLOBAL (1 << 4) /* Global page. */
+#define _PAGE_NO_CACHE (1 <<31) /* part of the uncached memory map */
+
/*
* The hardware doesn't care about these bits, but the kernel uses them in
diff --git a/arch/cris/include/asm/mmu_context.h b/arch/cris/include/asm/mmu_context.h
index 72ba08dcfd18..1d45fd6365b7 100644
--- a/arch/cris/include/asm/mmu_context.h
+++ b/arch/cris/include/asm/mmu_context.h
@@ -17,7 +17,8 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* registers like cr3 on the i386
*/
-extern volatile DEFINE_PER_CPU(pgd_t *,current_pgd); /* defined in arch/cris/mm/fault.c */
+/* defined in arch/cris/mm/fault.c */
+DECLARE_PER_CPU(pgd_t *, current_pgd);
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/arch/cris/include/asm/pgalloc.h b/arch/cris/include/asm/pgalloc.h
index a1ba761d0573..6da975db112f 100644
--- a/arch/cris/include/asm/pgalloc.h
+++ b/arch/cris/include/asm/pgalloc.h
@@ -47,7 +47,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
__free_page(pte);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,address) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb), pte); \
diff --git a/arch/cris/include/asm/pgtable.h b/arch/cris/include/asm/pgtable.h
index 50aa974aa834..1fcce00f01f4 100644
--- a/arch/cris/include/asm/pgtable.h
+++ b/arch/cris/include/asm/pgtable.h
@@ -197,6 +197,8 @@ static inline pte_t __mk_pte(void * page, pgprot_t pgprot)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE))
+
/* pte_val refers to a page in the 0x4xxxxxxx physical DRAM interval
* __pte_page(pte_val) refers to the "virtual" DRAM interval
diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S
index 0d2adfc794d4..6c81836b9229 100644
--- a/arch/cris/kernel/vmlinux.lds.S
+++ b/arch/cris/kernel/vmlinux.lds.S
@@ -140,12 +140,7 @@ SECTIONS
_end = .;
__end = .;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
dram_end = dram_start + (CONFIG_ETRAX_DRAM_SIZE - __CONFIG_ETRAX_VMEM_SIZE)*1024*1024;
+
+ DISCARDS
}
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index f925115e3250..4a7cdd9ea1ee 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -29,7 +29,7 @@ extern void die_if_kernel(const char *, struct pt_regs *, long);
/* current active page directory */
-volatile DEFINE_PER_CPU(pgd_t *,current_pgd);
+DEFINE_PER_CPU(pgd_t *, current_pgd);
unsigned long cris_signal_return_page;
/*
diff --git a/arch/frv/include/asm/gdb-stub.h b/arch/frv/include/asm/gdb-stub.h
index 24f9738670bd..2da716407ff2 100644
--- a/arch/frv/include/asm/gdb-stub.h
+++ b/arch/frv/include/asm/gdb-stub.h
@@ -90,7 +90,6 @@ extern void gdbstub_do_rx(void);
extern asmlinkage void __debug_stub_init_break(void);
extern asmlinkage void __break_hijack_kernel_event(void);
extern asmlinkage void __break_hijack_kernel_event_breaks_here(void);
-extern asmlinkage void start_kernel(void);
extern asmlinkage void gdbstub_rx_handler(void);
extern asmlinkage void gdbstub_rx_irq(void);
diff --git a/arch/frv/include/asm/pgalloc.h b/arch/frv/include/asm/pgalloc.h
index 971e6addb009..416d19a632f2 100644
--- a/arch/frv/include/asm/pgalloc.h
+++ b/arch/frv/include/asm/pgalloc.h
@@ -49,7 +49,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
__free_page(pte);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,address) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb),(pte)); \
@@ -62,7 +62,7 @@ do { \
*/
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *) 2); })
#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb,x) do { } while (0)
+#define __pmd_free_tlb(tlb,x,a) do { } while (0)
#endif /* CONFIG_MMU */
diff --git a/arch/frv/include/asm/pgtable.h b/arch/frv/include/asm/pgtable.h
index 33233011b1c1..22c60692b551 100644
--- a/arch/frv/include/asm/pgtable.h
+++ b/arch/frv/include/asm/pgtable.h
@@ -225,7 +225,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
*/
#define pud_alloc_one(mm, address) NULL
#define pud_free(mm, x) do { } while (0)
-#define __pud_free_tlb(tlb, x) do { } while (0)
+#define __pud_free_tlb(tlb, x, address) do { } while (0)
/*
* The "pud_xxx()" functions here are trivial for a folded two-level
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 22d9787406ed..7dbf41f68b52 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -177,6 +177,8 @@ SECTIONS
.debug_ranges 0 : { *(.debug_ranges) }
.comment 0 : { *(.comment) }
+
+ DISCARDS
}
__kernel_image_size_no_bss = __bss_start - __kernel_image_start;
diff --git a/arch/frv/lib/cache.S b/arch/frv/lib/cache.S
index 0e10ad8dc462..0c4fb204911b 100644
--- a/arch/frv/lib/cache.S
+++ b/arch/frv/lib/cache.S
@@ -1,4 +1,4 @@
-/* cache.S: cache managment routines
+/* cache.S: cache management routines
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c
index 43d67534c712..566bdeb499d1 100644
--- a/arch/frv/mb93090-mb00/pci-frv.c
+++ b/arch/frv/mb93090-mb00/pci-frv.c
@@ -86,7 +86,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
struct pci_bus *bus;
struct pci_dev *dev;
int idx;
- struct resource *r, *pr;
+ struct resource *r;
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
@@ -96,8 +96,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
r = &dev->resource[idx];
if (!r->start)
continue;
- pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0)
+ if (pci_claim_resource(dev, idx) < 0)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
}
}
@@ -110,7 +109,7 @@ static void __init pcibios_allocate_resources(int pass)
struct pci_dev *dev = NULL;
int idx, disabled;
u16 command;
- struct resource *r, *pr;
+ struct resource *r;
for_each_pci_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command);
@@ -127,8 +126,7 @@ static void __init pcibios_allocate_resources(int pass)
if (pass == disabled) {
DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
- pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0) {
+ if (pci_claim_resource(dev, idx) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
/* We'll assign a new address later */
r->end -= r->start;
diff --git a/arch/h8300/include/asm/pci.h b/arch/h8300/include/asm/pci.h
index 97389b35aa35..cc9762091c0a 100644
--- a/arch/h8300/include/asm/pci.h
+++ b/arch/h8300/include/asm/pci.h
@@ -8,7 +8,6 @@
*/
#define pcibios_assign_all_busses() 0
-#define pcibios_scan_all_fns(a, b) 0
static inline void pcibios_set_master(struct pci_dev *dev)
{
diff --git a/arch/h8300/kernel/timer/tpu.c b/arch/h8300/kernel/timer/tpu.c
index e7c6e614a758..2193a2e2859a 100644
--- a/arch/h8300/kernel/timer/tpu.c
+++ b/arch/h8300/kernel/timer/tpu.c
@@ -7,7 +7,6 @@
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index 43a87b9085b6..662b02ecb86e 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -152,9 +152,6 @@ SECTIONS
__end = . ;
__ramstart = .;
}
- /DISCARD/ : {
- *(.exitcall.exit)
- }
.romfs :
{
*(.romfs*)
@@ -165,4 +162,6 @@ SECTIONS
COMMAND_START = . - 0x200 ;
__ramend = . ;
}
+
+ DISCARDS
}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 170042b420d4..328d2f8b8c3f 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -89,6 +89,9 @@ config GENERIC_TIME_VSYSCALL
bool
default y
+config HAVE_LEGACY_PER_CPU_AREA
+ def_bool y
+
config HAVE_SETUP_PER_CPU_AREA
def_bool y
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 8cfb001092ab..674a8374c6d9 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -2026,24 +2026,21 @@ acpi_sba_ioc_add(struct acpi_device *device)
struct ioc *ioc;
acpi_status status;
u64 hpa, length;
- struct acpi_buffer buffer;
struct acpi_device_info *dev_info;
status = hp_acpi_csr_space(device->handle, &hpa, &length);
if (ACPI_FAILURE(status))
return 1;
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_get_object_info(device->handle, &buffer);
+ status = acpi_get_object_info(device->handle, &dev_info);
if (ACPI_FAILURE(status))
return 1;
- dev_info = buffer.pointer;
/*
* For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI
* root bridges, and its CSR space includes the IOC function.
*/
- if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) {
+ if (strncmp("HWP0001", dev_info->hardware_id.string, 7) == 0) {
hpa += ZX1_IOC_OFFSET;
/* zx1 based systems default to kernel page size iommu pages */
if (!iovp_shift)
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index e4d8fde68103..7e81966ce481 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -412,7 +412,7 @@ simeth_tx(struct sk_buff *skb, struct net_device *dev)
*/
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline struct sk_buff *
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 16ef61a91d95..625ed8f76fce 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -1270,7 +1270,7 @@ putreg (struct task_struct *child, int regno, unsigned int value)
case PT_CS:
if (value != __USER_CS)
printk(KERN_ERR
- "ia32.putreg: attempt to to set invalid segment register %d = %x\n",
+ "ia32.putreg: attempt to set invalid segment register %d = %x\n",
regno, value);
break;
default:
diff --git a/arch/ia64/include/asm/device.h b/arch/ia64/include/asm/device.h
index 41ab85d66f33..d66d446b127c 100644
--- a/arch/ia64/include/asm/device.h
+++ b/arch/ia64/include/asm/device.h
@@ -15,4 +15,7 @@ struct dev_archdata {
#endif
};
+struct pdev_archdata {
+};
+
#endif /* _ASM_IA64_DEVICE_H */
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 5f43697aed30..d9b6325a9328 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -235,7 +235,8 @@ struct kvm_vm_data {
#define KVM_REQ_PTC_G 32
#define KVM_REQ_RESUME 33
-#define KVM_PAGES_PER_HPAGE 1
+#define KVM_NR_PAGE_SIZES 1
+#define KVM_PAGES_PER_HPAGE(x) 1
struct kvm;
struct kvm_vcpu;
@@ -465,7 +466,6 @@ struct kvm_arch {
unsigned long metaphysical_rr4;
unsigned long vmm_init_rr;
- int online_vcpus;
int is_sn2;
struct kvm_ioapic *vioapic;
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index fcfca56bb850..55281aabe5f2 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -17,7 +17,6 @@
* loader.
*/
#define pcibios_assign_all_busses() 0
-#define pcibios_scan_all_fns(a, b) 0
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0x10000000
@@ -135,7 +134,18 @@ extern void pcibios_resource_to_bus(struct pci_dev *dev,
extern void pcibios_bus_to_resource(struct pci_dev *dev,
struct resource *res, struct pci_bus_region *region);
-#define pcibios_scan_all_fns(a, b) 0
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+ struct resource *root = NULL;
+
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ if (res->flags & IORESOURCE_MEM)
+ root = &iomem_resource;
+
+ return root;
+}
#define HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
diff --git a/arch/ia64/include/asm/pgalloc.h b/arch/ia64/include/asm/pgalloc.h
index b9ac1a6fc216..96a8d927db28 100644
--- a/arch/ia64/include/asm/pgalloc.h
+++ b/arch/ia64/include/asm/pgalloc.h
@@ -48,7 +48,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
quicklist_free(0, NULL, pud);
}
-#define __pud_free_tlb(tlb, pud) pud_free((tlb)->mm, pud)
+#define __pud_free_tlb(tlb, pud, address) pud_free((tlb)->mm, pud)
#endif /* CONFIG_PGTABLE_4 */
static inline void
@@ -67,7 +67,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
quicklist_free(0, NULL, pmd);
}
-#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
+#define __pmd_free_tlb(tlb, pmd, address) pmd_free((tlb)->mm, pmd)
static inline void
pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, pgtable_t pte)
@@ -117,6 +117,6 @@ static inline void check_pgt_cache(void)
quicklist_trim(0, NULL, 25, 16);
}
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, address) pte_free((tlb)->mm, pte)
#endif /* _ASM_IA64_PGALLOC_H */
diff --git a/arch/ia64/include/asm/smp.h b/arch/ia64/include/asm/smp.h
index d217d1d4e051..0b3b3997decd 100644
--- a/arch/ia64/include/asm/smp.h
+++ b/arch/ia64/include/asm/smp.h
@@ -127,7 +127,6 @@ extern int is_multithreading_enabled(void);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
#else /* CONFIG_SMP */
diff --git a/arch/ia64/include/asm/tlb.h b/arch/ia64/include/asm/tlb.h
index 20d8a39680c2..85d965cb19a0 100644
--- a/arch/ia64/include/asm/tlb.h
+++ b/arch/ia64/include/asm/tlb.h
@@ -236,22 +236,22 @@ do { \
__tlb_remove_tlb_entry(tlb, ptep, addr); \
} while (0)
-#define pte_free_tlb(tlb, ptep) \
+#define pte_free_tlb(tlb, ptep, address) \
do { \
tlb->need_flush = 1; \
- __pte_free_tlb(tlb, ptep); \
+ __pte_free_tlb(tlb, ptep, address); \
} while (0)
-#define pmd_free_tlb(tlb, ptep) \
+#define pmd_free_tlb(tlb, ptep, address) \
do { \
tlb->need_flush = 1; \
- __pmd_free_tlb(tlb, ptep); \
+ __pmd_free_tlb(tlb, ptep, address); \
} while (0)
-#define pud_free_tlb(tlb, pudp) \
+#define pud_free_tlb(tlb, pudp, address) \
do { \
tlb->need_flush = 1; \
- __pud_free_tlb(tlb, pudp); \
+ __pud_free_tlb(tlb, pudp, address); \
} while (0)
#endif /* _ASM_IA64_TLB_H */
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index 7b4c8c70b2d1..9ac48c34daac 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -33,7 +33,6 @@
/*
* Returns a bitmask of CPUs on Node 'node'.
*/
-#define node_to_cpumask(node) (node_to_cpu_mask[node])
#define cpumask_of_node(node) (&node_to_cpu_mask[node])
/*
@@ -103,8 +102,6 @@ void build_cpu_to_node_map(void);
#ifdef CONFIG_SMP
#define topology_physical_package_id(cpu) (cpu_data(cpu)->socket_id)
#define topology_core_id(cpu) (cpu_data(cpu)->core_id)
-#define topology_core_siblings(cpu) (cpu_core_map[cpu])
-#define topology_thread_siblings(cpu) (per_cpu(cpu_sibling_map, cpu))
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
#define smt_capable() (smp_num_siblings > 1)
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 1b23ec126b63..1de86c96801d 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -855,11 +855,17 @@ identify_cpu (struct cpuinfo_ia64 *c)
c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
}
+/*
+ * In UP configuration, setup_per_cpu_areas() is defined in
+ * include/linux/percpu.h
+ */
+#ifdef CONFIG_SMP
void __init
setup_per_cpu_areas (void)
{
/* start_kernel() requires this... */
}
+#endif
/*
* Do the following calculations:
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index f0c521b0ba4c..dabeefe21134 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -58,7 +58,8 @@ static struct local_tlb_flush_counts {
unsigned int count;
} __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS];
-static DEFINE_PER_CPU(unsigned short, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
+static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned short [NR_CPUS],
+ shadow_flush_counts);
#define IPI_CALL_FUNC 0
#define IPI_CPU_STOP 1
@@ -301,7 +302,7 @@ smp_flush_tlb_mm (struct mm_struct *mm)
return;
}
- smp_call_function_mask(mm->cpu_vm_mask,
+ smp_call_function_many(mm_cpumask(mm),
(void (*)(void *))local_finish_flush_tlb_mm, mm, 1);
local_irq_disable();
local_finish_flush_tlb_mm(mm);
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 4a95e86b9ac2..eb4214d1c5af 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -24,14 +24,14 @@ PHDRS {
}
SECTIONS
{
- /* Sections to be discarded */
+ /* unwind exit sections must be discarded before the rest of the
+ sections get included. */
/DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
*(.IA_64.unwind.exit.text)
*(.IA_64.unwind_info.exit.text)
- }
+ *(.comment)
+ *(.note)
+ }
v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */
phys_start = _start - LOAD_OFFSET;
@@ -316,7 +316,7 @@ SECTIONS
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
- /DISCARD/ : { *(.comment) }
- /DISCARD/ : { *(.note) }
+
+ /* Default discards */
+ DISCARDS
}
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig
index 64d520937874..ef3e7be29caf 100644
--- a/arch/ia64/kvm/Kconfig
+++ b/arch/ia64/kvm/Kconfig
@@ -1,12 +1,8 @@
#
# KVM configuration
#
-config HAVE_KVM
- bool
-config HAVE_KVM_IRQCHIP
- bool
- default y
+source "virt/kvm/Kconfig"
menuconfig VIRTUALIZATION
bool "Virtualization"
@@ -28,6 +24,8 @@ config KVM
depends on PCI
select PREEMPT_NOTIFIERS
select ANON_INODES
+ select HAVE_KVM_IRQCHIP
+ select KVM_APIC_ARCHITECTURE
---help---
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
@@ -49,9 +47,6 @@ config KVM_INTEL
Provides support for KVM on Itanium 2 processors equipped with the VT
extensions.
-config KVM_TRACE
- bool
-
source drivers/virtio/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 80c57b0a21c4..0ad09f05efa9 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -210,16 +210,6 @@ int kvm_dev_ioctl_check_extension(long ext)
}
-static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
- gpa_t addr, int len, int is_write)
-{
- struct kvm_io_device *dev;
-
- dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write);
-
- return dev;
-}
-
static int handle_vm_error(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
@@ -231,6 +221,7 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
struct kvm_mmio_req *p;
struct kvm_io_device *mmio_dev;
+ int r;
p = kvm_get_vcpu_ioreq(vcpu);
@@ -247,16 +238,13 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_run->exit_reason = KVM_EXIT_MMIO;
return 0;
mmio:
- mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir);
- if (mmio_dev) {
- if (!p->dir)
- kvm_iodevice_write(mmio_dev, p->addr, p->size,
- &p->data);
- else
- kvm_iodevice_read(mmio_dev, p->addr, p->size,
- &p->data);
-
- } else
+ if (p->dir)
+ r = kvm_io_bus_read(&vcpu->kvm->mmio_bus, p->addr,
+ p->size, &p->data);
+ else
+ r = kvm_io_bus_write(&vcpu->kvm->mmio_bus, p->addr,
+ p->size, &p->data);
+ if (r)
printk(KERN_ERR"kvm: No iodevice found! addr:%lx\n", p->addr);
p->state = STATE_IORESP_READY;
@@ -337,13 +325,12 @@ static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id,
{
union ia64_lid lid;
int i;
+ struct kvm_vcpu *vcpu;
- for (i = 0; i < kvm->arch.online_vcpus; i++) {
- if (kvm->vcpus[i]) {
- lid.val = VCPU_LID(kvm->vcpus[i]);
- if (lid.id == id && lid.eid == eid)
- return kvm->vcpus[i];
- }
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ lid.val = VCPU_LID(vcpu);
+ if (lid.id == id && lid.eid == eid)
+ return vcpu;
}
return NULL;
@@ -409,21 +396,21 @@ static int handle_global_purge(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
struct kvm *kvm = vcpu->kvm;
struct call_data call_data;
int i;
+ struct kvm_vcpu *vcpui;
call_data.ptc_g_data = p->u.ptc_g_data;
- for (i = 0; i < kvm->arch.online_vcpus; i++) {
- if (!kvm->vcpus[i] || kvm->vcpus[i]->arch.mp_state ==
- KVM_MP_STATE_UNINITIALIZED ||
- vcpu == kvm->vcpus[i])
+ kvm_for_each_vcpu(i, vcpui, kvm) {
+ if (vcpui->arch.mp_state == KVM_MP_STATE_UNINITIALIZED ||
+ vcpu == vcpui)
continue;
- if (waitqueue_active(&kvm->vcpus[i]->wq))
- wake_up_interruptible(&kvm->vcpus[i]->wq);
+ if (waitqueue_active(&vcpui->wq))
+ wake_up_interruptible(&vcpui->wq);
- if (kvm->vcpus[i]->cpu != -1) {
- call_data.vcpu = kvm->vcpus[i];
- smp_call_function_single(kvm->vcpus[i]->cpu,
+ if (vcpui->cpu != -1) {
+ call_data.vcpu = vcpui;
+ smp_call_function_single(vcpui->cpu,
vcpu_global_purge, &call_data, 1);
} else
printk(KERN_WARNING"kvm: Uninit vcpu received ipi!\n");
@@ -852,8 +839,6 @@ struct kvm *kvm_arch_create_vm(void)
kvm_init_vm(kvm);
- kvm->arch.online_vcpus = 0;
-
return kvm;
}
@@ -1000,10 +985,10 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
if (irqchip_in_kernel(kvm)) {
__s32 status;
- mutex_lock(&kvm->lock);
+ mutex_lock(&kvm->irq_lock);
status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
irq_event.irq, irq_event.level);
- mutex_unlock(&kvm->lock);
+ mutex_unlock(&kvm->irq_lock);
if (ioctl == KVM_IRQ_LINE_STATUS) {
irq_event.status = status;
if (copy_to_user(argp, &irq_event,
@@ -1216,7 +1201,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
if (IS_ERR(vmm_vcpu))
return PTR_ERR(vmm_vcpu);
- if (vcpu->vcpu_id == 0) {
+ if (kvm_vcpu_is_bsp(vcpu)) {
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
/*Set entry address for first run.*/
@@ -1224,7 +1209,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
/*Initialize itc offset for vcpus*/
itc_offset = 0UL - kvm_get_itc(vcpu);
- for (i = 0; i < kvm->arch.online_vcpus; i++) {
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
v = (struct kvm_vcpu *)((char *)vcpu +
sizeof(struct kvm_vcpu_data) * i);
v->arch.itc_offset = itc_offset;
@@ -1356,8 +1341,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
goto fail;
}
- kvm->arch.online_vcpus++;
-
return vcpu;
fail:
return ERR_PTR(r);
@@ -1952,19 +1935,6 @@ int kvm_highest_pending_irq(struct kvm_vcpu *vcpu)
return find_highest_bits((int *)&vpd->irr[0]);
}
-int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
-{
- if (kvm_highest_pending_irq(vcpu) != -1)
- return 1;
- return 0;
-}
-
-int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
-{
- /* do real check here */
- return 1;
-}
-
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
return vcpu->arch.timer_fired;
@@ -1977,7 +1947,8 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
- return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE;
+ return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) ||
+ (kvm_highest_pending_irq(vcpu) != -1);
}
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c
index 21f63fffc379..9bf55afd08d0 100644
--- a/arch/ia64/kvm/mmio.c
+++ b/arch/ia64/kvm/mmio.c
@@ -247,7 +247,8 @@ void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma)
vcpu_get_fpreg(vcpu, inst.M9.f2, &v);
/* Write high word. FIXME: this is a kludge! */
v.u.bits[1] &= 0x3ffff;
- mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
+ mmio_access(vcpu, padr + 8, (u64 *)&v.u.bits[1], 8,
+ ma, IOREQ_WRITE);
data = v.u.bits[0];
size = 3;
} else if (inst.M10.major == 7 && inst.M10.x6 == 0x3B) {
@@ -265,7 +266,8 @@ void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma)
/* Write high word.FIXME: this is a kludge! */
v.u.bits[1] &= 0x3ffff;
- mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
+ mmio_access(vcpu, padr + 8, (u64 *)&v.u.bits[1],
+ 8, ma, IOREQ_WRITE);
data = v.u.bits[0];
size = 3;
} else if (inst.M10.major == 7 && inst.M10.x6 == 0x31) {
diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c
index 46b02cbcc874..dce75b70cdd5 100644
--- a/arch/ia64/kvm/vcpu.c
+++ b/arch/ia64/kvm/vcpu.c
@@ -461,7 +461,7 @@ void setreg(unsigned long regnum, unsigned long val,
u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg)
{
struct kvm_pt_regs *regs = vcpu_regs(vcpu);
- u64 val;
+ unsigned long val;
if (!reg)
return 0;
@@ -469,7 +469,7 @@ u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg)
return val;
}
-void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 value, int nat)
+void vcpu_set_gr(struct kvm_vcpu *vcpu, unsigned long reg, u64 value, int nat)
{
struct kvm_pt_regs *regs = vcpu_regs(vcpu);
long sof = (regs->cr_ifs) & 0x7f;
@@ -830,8 +830,8 @@ static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val)
kvm = (struct kvm *)KVM_VM_BASE;
- if (vcpu->vcpu_id == 0) {
- for (i = 0; i < kvm->arch.online_vcpus; i++) {
+ if (kvm_vcpu_is_bsp(vcpu)) {
+ for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) {
v = (struct kvm_vcpu *)((char *)vcpu +
sizeof(struct kvm_vcpu_data) * i);
VMX(v, itc_offset) = itc_offset;
@@ -1072,7 +1072,7 @@ void kvm_ttag(struct kvm_vcpu *vcpu, INST64 inst)
vcpu_set_gr(vcpu, inst.M46.r1, tag, 0);
}
-int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, u64 *padr)
+int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, unsigned long *padr)
{
struct thash_data *data;
union ia64_isr visr, pt_isr;
diff --git a/arch/ia64/kvm/vcpu.h b/arch/ia64/kvm/vcpu.h
index 042af92ced83..360724d3ae69 100644
--- a/arch/ia64/kvm/vcpu.h
+++ b/arch/ia64/kvm/vcpu.h
@@ -686,14 +686,15 @@ static inline int highest_inservice_irq(struct kvm_vcpu *vcpu)
return highest_bits((int *)&(VMX(vcpu, insvc[0])));
}
-extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, u64 reg,
+extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
struct ia64_fpreg *val);
-extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, u64 reg,
+extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
struct ia64_fpreg *val);
-extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, u64 reg);
-extern void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 val, int nat);
-extern u64 vcpu_get_psr(struct kvm_vcpu *vcpu);
-extern void vcpu_set_psr(struct kvm_vcpu *vcpu, u64 val);
+extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg);
+extern void vcpu_set_gr(struct kvm_vcpu *vcpu, unsigned long reg,
+ u64 val, int nat);
+extern unsigned long vcpu_get_psr(struct kvm_vcpu *vcpu);
+extern void vcpu_set_psr(struct kvm_vcpu *vcpu, unsigned long val);
extern u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr);
extern void vcpu_bsw0(struct kvm_vcpu *vcpu);
extern void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte,
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index e456f062f241..ece1bf994499 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second);
DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
EXPORT_PER_CPU_SYMBOL(__sn_hub_info);
-DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
+DEFINE_PER_CPU(short [MAX_COMPACT_NODES], __sn_cnodeid_to_nasid);
EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
diff --git a/arch/m32r/include/asm/mmu_context.h b/arch/m32r/include/asm/mmu_context.h
index 91909e5dd9d0..a735cc567931 100644
--- a/arch/m32r/include/asm/mmu_context.h
+++ b/arch/m32r/include/asm/mmu_context.h
@@ -127,7 +127,7 @@ static inline void switch_mm(struct mm_struct *prev,
if (prev != next) {
#ifdef CONFIG_SMP
- cpu_set(cpu, next->cpu_vm_mask);
+ cpumask_set_cpu(cpu, mm_cpumask(next));
#endif /* CONFIG_SMP */
/* Set MPTB = next->pgd */
*(volatile unsigned long *)MPTB = (unsigned long)next->pgd;
@@ -135,7 +135,7 @@ static inline void switch_mm(struct mm_struct *prev,
}
#ifdef CONFIG_SMP
else
- if (!cpu_test_and_set(cpu, next->cpu_vm_mask))
+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))
activate_context(next);
#endif /* CONFIG_SMP */
}
diff --git a/arch/m32r/include/asm/pgalloc.h b/arch/m32r/include/asm/pgalloc.h
index f11a2b909cdb..0fc736198979 100644
--- a/arch/m32r/include/asm/pgalloc.h
+++ b/arch/m32r/include/asm/pgalloc.h
@@ -58,7 +58,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
__free_page(pte);
}
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -68,7 +68,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb, x) do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
#define check_pgt_cache() do { } while (0)
diff --git a/arch/m32r/include/asm/smp.h b/arch/m32r/include/asm/smp.h
index b96a6d2ffbc3..e67ded1aab91 100644
--- a/arch/m32r/include/asm/smp.h
+++ b/arch/m32r/include/asm/smp.h
@@ -88,7 +88,7 @@ extern void smp_send_timer(void);
extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#endif /* not __ASSEMBLY__ */
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index 929e5c9d3ad9..e6ec3cc12854 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -85,7 +85,7 @@ void smp_ipi_timer_interrupt(struct pt_regs *);
void smp_local_timer_interrupt(void);
static void send_IPI_allbutself(int, int);
-static void send_IPI_mask(cpumask_t, int, int);
+static void send_IPI_mask(const struct cpumask *, int, int);
unsigned long send_IPI_mask_phys(cpumask_t, int, int);
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
@@ -113,7 +113,7 @@ unsigned long send_IPI_mask_phys(cpumask_t, int, int);
void smp_send_reschedule(int cpu_id)
{
WARN_ON(cpu_is_offline(cpu_id));
- send_IPI_mask(cpumask_of_cpu(cpu_id), RESCHEDULE_IPI, 1);
+ send_IPI_mask(cpumask_of(cpu_id), RESCHEDULE_IPI, 1);
}
/*==========================================================================*
@@ -168,7 +168,7 @@ void smp_flush_cache_all(void)
spin_lock(&flushcache_lock);
mask=cpus_addr(cpumask);
atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);
- send_IPI_mask(cpumask, INVALIDATE_CACHE_IPI, 0);
+ send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);
_flush_cache_copyback_all();
while (flushcache_cpumask)
mb();
@@ -264,7 +264,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
preempt_disable();
cpu_id = smp_processor_id();
mmc = &mm->context[cpu_id];
- cpu_mask = mm->cpu_vm_mask;
+ cpu_mask = *mm_cpumask(mm);
cpu_clear(cpu_id, cpu_mask);
if (*mmc != NO_CONTEXT) {
@@ -273,7 +273,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
if (mm == current->mm)
activate_context(mm);
else
- cpu_clear(cpu_id, mm->cpu_vm_mask);
+ cpumask_clear_cpu(cpu_id, mm_cpumask(mm));
local_irq_restore(flags);
}
if (!cpus_empty(cpu_mask))
@@ -334,7 +334,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
preempt_disable();
cpu_id = smp_processor_id();
mmc = &mm->context[cpu_id];
- cpu_mask = mm->cpu_vm_mask;
+ cpu_mask = *mm_cpumask(mm);
cpu_clear(cpu_id, cpu_mask);
#ifdef DEBUG_SMP
@@ -424,7 +424,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
* We have to send the IPI only to
* CPUs affected.
*/
- send_IPI_mask(cpumask, INVALIDATE_TLB_IPI, 0);
+ send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
while (!cpus_empty(flush_cpumask)) {
/* nothing. lockup detection does not belong here */
@@ -469,7 +469,7 @@ void smp_invalidate_interrupt(void)
if (flush_mm == current->active_mm)
activate_context(flush_mm);
else
- cpu_clear(cpu_id, flush_mm->cpu_vm_mask);
+ cpumask_clear(cpu_id, mm_cpumask(flush_mm));
} else {
unsigned long va = flush_va;
@@ -546,14 +546,14 @@ static void stop_this_cpu(void *dummy)
for ( ; ; );
}
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
send_IPI_mask(mask, CALL_FUNCTION_IPI, 0);
}
void arch_send_call_function_single_ipi(int cpu)
{
- send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNC_SINGLE_IPI, 0);
+ send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI, 0);
}
/*==========================================================================*
@@ -729,7 +729,7 @@ static void send_IPI_allbutself(int ipi_num, int try)
cpumask = cpu_online_map;
cpu_clear(smp_processor_id(), cpumask);
- send_IPI_mask(cpumask, ipi_num, try);
+ send_IPI_mask(&cpumask, ipi_num, try);
}
/*==========================================================================*
@@ -752,7 +752,7 @@ static void send_IPI_allbutself(int ipi_num, int try)
* ---------- --- --------------------------------------------------------
*
*==========================================================================*/
-static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try)
+static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
{
cpumask_t physid_mask, tmp;
int cpu_id, phys_id;
@@ -761,11 +761,11 @@ static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try)
if (num_cpus <= 1) /* NO MP */
return;
- cpus_and(tmp, cpumask, cpu_online_map);
- BUG_ON(!cpus_equal(cpumask, tmp));
+ cpumask_and(&tmp, cpumask, cpu_online_mask);
+ BUG_ON(!cpumask_equal(cpumask, &tmp));
physid_mask = CPU_MASK_NONE;
- for_each_cpu_mask(cpu_id, cpumask){
+ for_each_cpu(cpu_id, cpumask) {
if ((phys_id = cpu_to_physid(cpu_id)) != -1)
cpu_set(phys_id, physid_mask);
}
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 2547d6c4a827..ffc3bbcfd3bb 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -178,7 +178,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++)
physid_set(phys_id, phys_cpu_present_map);
#ifndef CONFIG_HOTPLUG_CPU
- cpu_present_map = cpu_possible_map;
+ init_cpu_present(&cpu_possible_map);
#endif
show_mp_info(nr_cpu);
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 4179adf6c624..de5e21cca6a5 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -120,13 +120,6 @@ SECTIONS
_end = . ;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
@@ -135,4 +128,7 @@ SECTIONS
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
+
+ /* Sections to be discarded */
+ DISCARDS
}
diff --git a/arch/m68k/include/asm/checksum.h b/arch/m68k/include/asm/checksum.h
index 1cf544767453..ec514485c8b6 100644
--- a/arch/m68k/include/asm/checksum.h
+++ b/arch/m68k/include/asm/checksum.h
@@ -1,5 +1,170 @@
-#ifdef __uClinux__
-#include "checksum_no.h"
+#ifndef _M68K_CHECKSUM_H
+#define _M68K_CHECKSUM_H
+
+#include <linux/in6.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern __wsum csum_partial_copy_from_user(const void __user *src,
+ void *dst,
+ int len, __wsum sum,
+ int *csum_err);
+
+extern __wsum csum_partial_copy_nocheck(const void *src,
+ void *dst, int len,
+ __wsum sum);
+
+
+#ifdef CONFIG_COLDFIRE
+
+/*
+ * The ColdFire cores don't support all the 68k instructions used
+ * in the optimized checksum code below. So it reverts back to using
+ * more standard C coded checksums. The fast checksum code is
+ * significantly larger than the optimized version, so it is not
+ * inlined here.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
+
+static inline __sum16 csum_fold(__wsum sum)
+{
+ unsigned int tmp = (__force u32)sum;
+
+ tmp = (tmp & 0xffff) + (tmp >> 16);
+ tmp = (tmp & 0xffff) + (tmp >> 16);
+
+ return (__force __sum16)~tmp;
+}
+
#else
-#include "checksum_mm.h"
-#endif
+
+/*
+ * This is a version of ip_fast_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ unsigned int sum = 0;
+ unsigned long tmp;
+
+ __asm__ ("subqw #1,%2\n"
+ "1:\t"
+ "movel %1@+,%3\n\t"
+ "addxl %3,%0\n\t"
+ "dbra %2,1b\n\t"
+ "movel %0,%3\n\t"
+ "swap %3\n\t"
+ "addxw %3,%0\n\t"
+ "clrw %3\n\t"
+ "addxw %3,%0\n\t"
+ : "=d" (sum), "=&a" (iph), "=&d" (ihl), "=&d" (tmp)
+ : "0" (sum), "1" (iph), "2" (ihl)
+ : "memory");
+ return (__force __sum16)~sum;
+}
+
+static inline __sum16 csum_fold(__wsum sum)
+{
+ unsigned int tmp = (__force u32)sum;
+
+ __asm__("swap %1\n\t"
+ "addw %1, %0\n\t"
+ "clrw %1\n\t"
+ "addxw %1, %0"
+ : "=&d" (sum), "=&d" (tmp)
+ : "0" (sum), "1" (tmp));
+
+ return (__force __sum16)~sum;
+}
+
+#endif /* CONFIG_COLDFIRE */
+
+static inline __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+ unsigned short proto, __wsum sum)
+{
+ __asm__ ("addl %2,%0\n\t"
+ "addxl %3,%0\n\t"
+ "addxl %4,%0\n\t"
+ "clrl %1\n\t"
+ "addxl %1,%0"
+ : "=&d" (sum), "=d" (saddr)
+ : "g" (daddr), "1" (saddr), "d" (len + proto),
+ "0" (sum));
+ return sum;
+}
+
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline __sum16
+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
+ unsigned short proto, __wsum sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static inline __sum16 ip_compute_csum(const void *buff, int len)
+{
+ return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ __sum16
+csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
+ __u32 len, unsigned short proto, __wsum sum)
+{
+ register unsigned long tmp;
+ __asm__("addl %2@,%0\n\t"
+ "movel %2@(4),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %2@(8),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %2@(12),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@,%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(4),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(8),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(12),%1\n\t"
+ "addxl %1,%0\n\t"
+ "addxl %4,%0\n\t"
+ "clrl %1\n\t"
+ "addxl %1,%0"
+ : "=&d" (sum), "=&d" (tmp)
+ : "a" (saddr), "a" (daddr), "d" (len + proto),
+ "0" (sum));
+
+ return csum_fold(sum);
+}
+
+#endif /* _M68K_CHECKSUM_H */
diff --git a/arch/m68k/include/asm/checksum_mm.h b/arch/m68k/include/asm/checksum_mm.h
deleted file mode 100644
index 494f9aec37ea..000000000000
--- a/arch/m68k/include/asm/checksum_mm.h
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef _M68K_CHECKSUM_H
-#define _M68K_CHECKSUM_H
-
-#include <linux/in6.h>
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-extern __wsum csum_partial_copy_from_user(const void __user *src,
- void *dst,
- int len, __wsum sum,
- int *csum_err);
-
-extern __wsum csum_partial_copy_nocheck(const void *src,
- void *dst, int len,
- __wsum sum);
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- *
- */
-static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
- unsigned int sum = 0;
- unsigned long tmp;
-
- __asm__ ("subqw #1,%2\n"
- "1:\t"
- "movel %1@+,%3\n\t"
- "addxl %3,%0\n\t"
- "dbra %2,1b\n\t"
- "movel %0,%3\n\t"
- "swap %3\n\t"
- "addxw %3,%0\n\t"
- "clrw %3\n\t"
- "addxw %3,%0\n\t"
- : "=d" (sum), "=&a" (iph), "=&d" (ihl), "=&d" (tmp)
- : "0" (sum), "1" (iph), "2" (ihl)
- : "memory");
- return (__force __sum16)~sum;
-}
-
-/*
- * Fold a partial checksum
- */
-
-static inline __sum16 csum_fold(__wsum sum)
-{
- unsigned int tmp = (__force u32)sum;
- __asm__("swap %1\n\t"
- "addw %1, %0\n\t"
- "clrw %1\n\t"
- "addxw %1, %0"
- : "=&d" (sum), "=&d" (tmp)
- : "0" (sum), "1" (tmp));
- return (__force __sum16)~sum;
-}
-
-
-static inline __wsum
-csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
- unsigned short proto, __wsum sum)
-{
- __asm__ ("addl %2,%0\n\t"
- "addxl %3,%0\n\t"
- "addxl %4,%0\n\t"
- "clrl %1\n\t"
- "addxl %1,%0"
- : "=&d" (sum), "=d" (saddr)
- : "g" (daddr), "1" (saddr), "d" (len + proto),
- "0" (sum));
- return sum;
-}
-
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-static inline __sum16
-csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
- unsigned short proto, __wsum sum)
-{
- return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-
-static inline __sum16 ip_compute_csum(const void *buff, int len)
-{
- return csum_fold (csum_partial(buff, len, 0));
-}
-
-#define _HAVE_ARCH_IPV6_CSUM
-static __inline__ __sum16
-csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
- __u32 len, unsigned short proto, __wsum sum)
-{
- register unsigned long tmp;
- __asm__("addl %2@,%0\n\t"
- "movel %2@(4),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %2@(8),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %2@(12),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@,%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(4),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(8),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(12),%1\n\t"
- "addxl %1,%0\n\t"
- "addxl %4,%0\n\t"
- "clrl %1\n\t"
- "addxl %1,%0"
- : "=&d" (sum), "=&d" (tmp)
- : "a" (saddr), "a" (daddr), "d" (len + proto),
- "0" (sum));
-
- return csum_fold(sum);
-}
-
-#endif /* _M68K_CHECKSUM_H */
diff --git a/arch/m68k/include/asm/checksum_no.h b/arch/m68k/include/asm/checksum_no.h
deleted file mode 100644
index 81883482ffb1..000000000000
--- a/arch/m68k/include/asm/checksum_no.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _M68K_CHECKSUM_H
-#define _M68K_CHECKSUM_H
-
-#include <linux/in6.h>
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
- int len, __wsum sum);
-
-
-/*
- * the same as csum_partial_copy, but copies from user space.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-extern __wsum csum_partial_copy_from_user(const void __user *src,
- void *dst, int len, __wsum sum, int *csum_err);
-
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
-
-/*
- * Fold a partial checksum
- */
-
-static inline __sum16 csum_fold(__wsum sum)
-{
- unsigned int tmp = (__force u32)sum;
-#ifdef CONFIG_COLDFIRE
- tmp = (tmp & 0xffff) + (tmp >> 16);
- tmp = (tmp & 0xffff) + (tmp >> 16);
- return (__force __sum16)~tmp;
-#else
- __asm__("swap %1\n\t"
- "addw %1, %0\n\t"
- "clrw %1\n\t"
- "addxw %1, %0"
- : "=&d" (sum), "=&d" (tmp)
- : "0" (sum), "1" (sum));
- return (__force __sum16)~sum;
-#endif
-}
-
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-
-static inline __wsum
-csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
- unsigned short proto, __wsum sum)
-{
- __asm__ ("addl %1,%0\n\t"
- "addxl %4,%0\n\t"
- "addxl %5,%0\n\t"
- "clrl %1\n\t"
- "addxl %1,%0"
- : "=&d" (sum), "=&d" (saddr)
- : "0" (daddr), "1" (saddr), "d" (len + proto),
- "d"(sum));
- return sum;
-}
-
-static inline __sum16
-csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
- unsigned short proto, __wsum sum)
-{
- return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-
-extern __sum16 ip_compute_csum(const void *buff, int len);
-
-#define _HAVE_ARCH_IPV6_CSUM
-static __inline__ __sum16
-csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
- __u32 len, unsigned short proto, __wsum sum)
-{
- register unsigned long tmp;
- __asm__("addl %2@,%0\n\t"
- "movel %2@(4),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %2@(8),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %2@(12),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@,%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(4),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(8),%1\n\t"
- "addxl %1,%0\n\t"
- "movel %3@(12),%1\n\t"
- "addxl %1,%0\n\t"
- "addxl %4,%0\n\t"
- "clrl %1\n\t"
- "addxl %1,%0"
- : "=&d" (sum), "=&d" (tmp)
- : "a" (saddr), "a" (daddr), "d" (len + proto),
- "0" (sum));
-
- return csum_fold(sum);
-}
-
-#endif /* _M68K_CHECKSUM_H */
diff --git a/arch/m68k/include/asm/dma.h b/arch/m68k/include/asm/dma.h
index b82e660cf1c2..3b85f6e6c098 100644
--- a/arch/m68k/include/asm/dma.h
+++ b/arch/m68k/include/asm/dma.h
@@ -1,5 +1,491 @@
-#ifdef __uClinux__
-#include "dma_no.h"
+#ifndef _M68K_DMA_H
+#define _M68K_DMA_H 1
+
+#ifdef CONFIG_COLDFIRE
+/*
+ * ColdFire DMA Model:
+ * ColdFire DMA supports two forms of DMA: Single and Dual address. Single
+ * address mode emits a source address, and expects that the device will either
+ * pick up the data (DMA READ) or source data (DMA WRITE). This implies that
+ * the device will place data on the correct byte(s) of the data bus, as the
+ * memory transactions are always 32 bits. This implies that only 32 bit
+ * devices will find single mode transfers useful. Dual address DMA mode
+ * performs two cycles: source read and destination write. ColdFire will
+ * align the data so that the device will always get the correct bytes, thus
+ * is useful for 8 and 16 bit devices. This is the mode that is supported
+ * below.
+ *
+ * AUG/22/2000 : added support for 32-bit Dual-Address-Mode (K) 2000
+ * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de)
+ *
+ * AUG/25/2000 : addad support for 8, 16 and 32-bit Single-Address-Mode (K)2000
+ * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de)
+ *
+ * APR/18/2002 : added proper support for MCF5272 DMA controller.
+ * Arthur Shipkowski (art@videon-central.com)
+ */
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/*
+ * Set number of channels of DMA on ColdFire for different implementations.
+ */
+#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
+ defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define MAX_M68K_DMA_CHANNELS 4
+#elif defined(CONFIG_M5272)
+#define MAX_M68K_DMA_CHANNELS 1
+#elif defined(CONFIG_M532x)
+#define MAX_M68K_DMA_CHANNELS 0
#else
-#include "dma_mm.h"
+#define MAX_M68K_DMA_CHANNELS 2
#endif
+
+extern unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS];
+extern unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+#if !defined(CONFIG_M5272)
+#define DMA_MODE_WRITE_BIT 0x01 /* Memory/IO to IO/Memory select */
+#define DMA_MODE_WORD_BIT 0x02 /* 8 or 16 bit transfers */
+#define DMA_MODE_LONG_BIT 0x04 /* or 32 bit transfers */
+#define DMA_MODE_SINGLE_BIT 0x08 /* single-address-mode */
+
+/* I/O to memory, 8 bits, mode */
+#define DMA_MODE_READ 0
+/* memory to I/O, 8 bits, mode */
+#define DMA_MODE_WRITE 1
+/* I/O to memory, 16 bits, mode */
+#define DMA_MODE_READ_WORD 2
+/* memory to I/O, 16 bits, mode */
+#define DMA_MODE_WRITE_WORD 3
+/* I/O to memory, 32 bits, mode */
+#define DMA_MODE_READ_LONG 4
+/* memory to I/O, 32 bits, mode */
+#define DMA_MODE_WRITE_LONG 5
+/* I/O to memory, 8 bits, single-address-mode */
+#define DMA_MODE_READ_SINGLE 8
+/* memory to I/O, 8 bits, single-address-mode */
+#define DMA_MODE_WRITE_SINGLE 9
+/* I/O to memory, 16 bits, single-address-mode */
+#define DMA_MODE_READ_WORD_SINGLE 10
+/* memory to I/O, 16 bits, single-address-mode */
+#define DMA_MODE_WRITE_WORD_SINGLE 11
+/* I/O to memory, 32 bits, single-address-mode */
+#define DMA_MODE_READ_LONG_SINGLE 12
+/* memory to I/O, 32 bits, single-address-mode */
+#define DMA_MODE_WRITE_LONG_SINGLE 13
+
+#else /* CONFIG_M5272 is defined */
+
+/* Source static-address mode */
+#define DMA_MODE_SRC_SA_BIT 0x01
+/* Two bits to select between all four modes */
+#define DMA_MODE_SSIZE_MASK 0x06
+/* Offset to shift bits in */
+#define DMA_MODE_SSIZE_OFF 0x01
+/* Destination static-address mode */
+#define DMA_MODE_DES_SA_BIT 0x10
+/* Two bits to select between all four modes */
+#define DMA_MODE_DSIZE_MASK 0x60
+/* Offset to shift bits in */
+#define DMA_MODE_DSIZE_OFF 0x05
+/* Size modifiers */
+#define DMA_MODE_SIZE_LONG 0x00
+#define DMA_MODE_SIZE_BYTE 0x01
+#define DMA_MODE_SIZE_WORD 0x02
+#define DMA_MODE_SIZE_LINE 0x03
+
+/*
+ * Aliases to help speed quick ports; these may be suboptimal, however. They
+ * do not include the SINGLE mode modifiers since the MCF5272 does not have a
+ * mode where the device is in control of its addressing.
+ */
+
+/* I/O to memory, 8 bits, mode */
+#define DMA_MODE_READ ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
+/* memory to I/O, 8 bits, mode */
+#define DMA_MODE_WRITE ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
+/* I/O to memory, 16 bits, mode */
+#define DMA_MODE_READ_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
+/* memory to I/O, 16 bits, mode */
+#define DMA_MODE_WRITE_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
+/* I/O to memory, 32 bits, mode */
+#define DMA_MODE_READ_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
+/* memory to I/O, 32 bits, mode */
+#define DMA_MODE_WRITE_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
+
+#endif /* !defined(CONFIG_M5272) */
+
+#if !defined(CONFIG_M5272)
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+ volatile unsigned short *dmawp;
+
+#ifdef DMA_DEBUG
+ printk("enable_dma(dmanr=%d)\n", dmanr);
+#endif
+
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+ dmawp[MCFDMA_DCR] |= MCFDMA_DCR_EEXT;
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+ volatile unsigned short *dmawp;
+ volatile unsigned char *dmapb;
+
+#ifdef DMA_DEBUG
+ printk("disable_dma(dmanr=%d)\n", dmanr);
+#endif
+
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+ dmapb = (unsigned char *) dma_base_addr[dmanr];
+
+ /* Turn off external requests, and stop any DMA in progress */
+ dmawp[MCFDMA_DCR] &= ~MCFDMA_DCR_EEXT;
+ dmapb[MCFDMA_DSR] = MCFDMA_DSR_DONE;
+}
+
+/*
+ * Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while interrupts are disabled! ---
+ *
+ * This is a NOP for ColdFire. Provide a stub for compatibility.
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+
+ volatile unsigned char *dmabp;
+ volatile unsigned short *dmawp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode);
+#endif
+
+ dmabp = (unsigned char *) dma_base_addr[dmanr];
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+
+ // Clear config errors
+ dmabp[MCFDMA_DSR] = MCFDMA_DSR_DONE;
+
+ // Set command register
+ dmawp[MCFDMA_DCR] =
+ MCFDMA_DCR_INT | // Enable completion irq
+ MCFDMA_DCR_CS | // Force one xfer per request
+ MCFDMA_DCR_AA | // Enable auto alignment
+ // single-address-mode
+ ((mode & DMA_MODE_SINGLE_BIT) ? MCFDMA_DCR_SAA : 0) |
+ // sets s_rw (-> r/w) high if Memory to I/0
+ ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_S_RW : 0) |
+ // Memory to I/O or I/O to Memory
+ ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_SINC : MCFDMA_DCR_DINC) |
+ // 32 bit, 16 bit or 8 bit transfers
+ ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_SSIZE_WORD :
+ ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_SSIZE_LONG :
+ MCFDMA_DCR_SSIZE_BYTE)) |
+ ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_DSIZE_WORD :
+ ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_DSIZE_LONG :
+ MCFDMA_DCR_DSIZE_BYTE));
+
+#ifdef DEBUG_DMA
+ printk("%s(%d): dmanr=%d DSR[%x]=%x DCR[%x]=%x\n", __FILE__, __LINE__,
+ dmanr, (int) &dmabp[MCFDMA_DSR], dmabp[MCFDMA_DSR],
+ (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR]);
+#endif
+}
+
+/* Set transfer address for specific DMA channel */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ volatile unsigned short *dmawp;
+ volatile unsigned int *dmalp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a);
+#endif
+
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+
+ // Determine which address registers are used for memory/device accesses
+ if (dmawp[MCFDMA_DCR] & MCFDMA_DCR_SINC) {
+ // Source incrementing, must be memory
+ dmalp[MCFDMA_SAR] = a;
+ // Set dest address, must be device
+ dmalp[MCFDMA_DAR] = dma_device_address[dmanr];
+ } else {
+ // Destination incrementing, must be memory
+ dmalp[MCFDMA_DAR] = a;
+ // Set source address, must be device
+ dmalp[MCFDMA_SAR] = dma_device_address[dmanr];
+ }
+
+#ifdef DEBUG_DMA
+ printk("%s(%d): dmanr=%d DCR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n",
+ __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR],
+ (int) &dmalp[MCFDMA_SAR], dmalp[MCFDMA_SAR],
+ (int) &dmalp[MCFDMA_DAR], dmalp[MCFDMA_DAR]);
+#endif
+}
+
+/*
+ * Specific for Coldfire - sets device address.
+ * Should be called after the mode set call, and before set DMA address.
+ */
+static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a)
+{
+#ifdef DMA_DEBUG
+ printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a);
+#endif
+
+ dma_device_address[dmanr] = a;
+}
+
+/*
+ * NOTE 2: "count" represents _bytes_.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ volatile unsigned short *dmawp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count);
+#endif
+
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+ dmawp[MCFDMA_BCR] = (unsigned short)count;
+}
+
+/*
+ * Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+ volatile unsigned short *dmawp;
+ unsigned short count;
+
+#ifdef DMA_DEBUG
+ printk("get_dma_residue(dmanr=%d)\n", dmanr);
+#endif
+
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+ count = dmawp[MCFDMA_BCR];
+ return((int) count);
+}
+#else /* CONFIG_M5272 is defined */
+
+/*
+ * The MCF5272 DMA controller is very different than the controller defined above
+ * in terms of register mapping. For instance, with the exception of the 16-bit
+ * interrupt register (IRQ#85, for reference), all of the registers are 32-bit.
+ *
+ * The big difference, however, is the lack of device-requested DMA. All modes
+ * are dual address transfer, and there is no 'device' setup or direction bit.
+ * You can DMA between a device and memory, between memory and memory, or even between
+ * two devices directly, with any combination of incrementing and non-incrementing
+ * addresses you choose. This puts a crimp in distinguishing between the 'device
+ * address' set up by set_dma_device_addr.
+ *
+ * Therefore, there are two options. One is to use set_dma_addr and set_dma_device_addr,
+ * which will act exactly as above in -- it will look to see if the source is set to
+ * autoincrement, and if so it will make the source use the set_dma_addr value and the
+ * destination the set_dma_device_addr value. Otherwise the source will be set to the
+ * set_dma_device_addr value and the destination will get the set_dma_addr value.
+ *
+ * The other is to use the provided set_dma_src_addr and set_dma_dest_addr functions
+ * and make it explicit. Depending on what you're doing, one of these two should work
+ * for you, but don't mix them in the same transfer setup.
+ */
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+ volatile unsigned int *dmalp;
+
+#ifdef DMA_DEBUG
+ printk("enable_dma(dmanr=%d)\n", dmanr);
+#endif
+
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+ dmalp[MCFDMA_DMR] |= MCFDMA_DMR_EN;
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+ volatile unsigned int *dmalp;
+
+#ifdef DMA_DEBUG
+ printk("disable_dma(dmanr=%d)\n", dmanr);
+#endif
+
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+
+ /* Turn off external requests, and stop any DMA in progress */
+ dmalp[MCFDMA_DMR] &= ~MCFDMA_DMR_EN;
+ dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET;
+}
+
+/*
+ * Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while interrupts are disabled! ---
+ *
+ * This is a NOP for ColdFire. Provide a stub for compatibility.
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+
+ volatile unsigned int *dmalp;
+ volatile unsigned short *dmawp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode);
+#endif
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+ dmawp = (unsigned short *) dma_base_addr[dmanr];
+
+ // Clear config errors
+ dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET;
+
+ // Set command register
+ dmalp[MCFDMA_DMR] =
+ MCFDMA_DMR_RQM_DUAL | // Mandatory Request Mode setting
+ MCFDMA_DMR_DSTT_SD | // Set up addressing types; set to supervisor-data.
+ MCFDMA_DMR_SRCT_SD | // Set up addressing types; set to supervisor-data.
+ // source static-address-mode
+ ((mode & DMA_MODE_SRC_SA_BIT) ? MCFDMA_DMR_SRCM_SA : MCFDMA_DMR_SRCM_IA) |
+ // dest static-address-mode
+ ((mode & DMA_MODE_DES_SA_BIT) ? MCFDMA_DMR_DSTM_SA : MCFDMA_DMR_DSTM_IA) |
+ // burst, 32 bit, 16 bit or 8 bit transfers are separately configurable on the MCF5272
+ (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_DSTS_OFF) |
+ (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_SRCS_OFF);
+
+ dmawp[MCFDMA_DIR] |= MCFDMA_DIR_ASCEN; /* Enable completion interrupts */
+
+#ifdef DEBUG_DMA
+ printk("%s(%d): dmanr=%d DMR[%x]=%x DIR[%x]=%x\n", __FILE__, __LINE__,
+ dmanr, (int) &dmalp[MCFDMA_DMR], dmabp[MCFDMA_DMR],
+ (int) &dmawp[MCFDMA_DIR], dmawp[MCFDMA_DIR]);
+#endif
+}
+
+/* Set transfer address for specific DMA channel */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ volatile unsigned int *dmalp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a);
+#endif
+
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+
+ // Determine which address registers are used for memory/device accesses
+ if (dmalp[MCFDMA_DMR] & MCFDMA_DMR_SRCM) {
+ // Source incrementing, must be memory
+ dmalp[MCFDMA_DSAR] = a;
+ // Set dest address, must be device
+ dmalp[MCFDMA_DDAR] = dma_device_address[dmanr];
+ } else {
+ // Destination incrementing, must be memory
+ dmalp[MCFDMA_DDAR] = a;
+ // Set source address, must be device
+ dmalp[MCFDMA_DSAR] = dma_device_address[dmanr];
+ }
+
+#ifdef DEBUG_DMA
+ printk("%s(%d): dmanr=%d DMR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n",
+ __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DMR], dmawp[MCFDMA_DMR],
+ (int) &dmalp[MCFDMA_DSAR], dmalp[MCFDMA_DSAR],
+ (int) &dmalp[MCFDMA_DDAR], dmalp[MCFDMA_DDAR]);
+#endif
+}
+
+/*
+ * Specific for Coldfire - sets device address.
+ * Should be called after the mode set call, and before set DMA address.
+ */
+static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a)
+{
+#ifdef DMA_DEBUG
+ printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a);
+#endif
+
+ dma_device_address[dmanr] = a;
+}
+
+/*
+ * NOTE 2: "count" represents _bytes_.
+ *
+ * NOTE 3: While a 32-bit register, "count" is only a maximum 24-bit value.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ volatile unsigned int *dmalp;
+
+#ifdef DMA_DEBUG
+ printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count);
+#endif
+
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+ dmalp[MCFDMA_DBCR] = count;
+}
+
+/*
+ * Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+ volatile unsigned int *dmalp;
+ unsigned int count;
+
+#ifdef DMA_DEBUG
+ printk("get_dma_residue(dmanr=%d)\n", dmanr);
+#endif
+
+ dmalp = (unsigned int *) dma_base_addr[dmanr];
+ count = dmalp[MCFDMA_DBCR];
+ return(count);
+}
+
+#endif /* !defined(CONFIG_M5272) */
+#endif /* CONFIG_COLDFIRE */
+
+/* it's useless on the m68k, but unfortunately needed by the new
+ bootmem allocator (but this should do it for this) */
+#define MAX_DMA_ADDRESS PAGE_OFFSET
+
+#define MAX_DMA_CHANNELS 8
+
+extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr); /* release it again */
+
+#define isa_dma_bridge_buggy (0)
+
+#endif /* _M68K_DMA_H */
diff --git a/arch/m68k/include/asm/dma_mm.h b/arch/m68k/include/asm/dma_mm.h
deleted file mode 100644
index 4240fbc946f8..000000000000
--- a/arch/m68k/include/asm/dma_mm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _M68K_DMA_H
-#define _M68K_DMA_H 1
-
-
-/* it's useless on the m68k, but unfortunately needed by the new
- bootmem allocator (but this should do it for this) */
-#define MAX_DMA_ADDRESS PAGE_OFFSET
-
-#define MAX_DMA_CHANNELS 8
-
-extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr); /* release it again */
-
-#define isa_dma_bridge_buggy (0)
-
-#endif /* _M68K_DMA_H */
diff --git a/arch/m68k/include/asm/dma_no.h b/arch/m68k/include/asm/dma_no.h
deleted file mode 100644
index 939a02056217..000000000000
--- a/arch/m68k/include/asm/dma_no.h
+++ /dev/null
@@ -1,494 +0,0 @@
-#ifndef _M68K_DMA_H
-#define _M68K_DMA_H 1
-
-//#define DMA_DEBUG 1
-
-
-#ifdef CONFIG_COLDFIRE
-/*
- * ColdFire DMA Model:
- * ColdFire DMA supports two forms of DMA: Single and Dual address. Single
- * address mode emits a source address, and expects that the device will either
- * pick up the data (DMA READ) or source data (DMA WRITE). This implies that
- * the device will place data on the correct byte(s) of the data bus, as the
- * memory transactions are always 32 bits. This implies that only 32 bit
- * devices will find single mode transfers useful. Dual address DMA mode
- * performs two cycles: source read and destination write. ColdFire will
- * align the data so that the device will always get the correct bytes, thus
- * is useful for 8 and 16 bit devices. This is the mode that is supported
- * below.
- *
- * AUG/22/2000 : added support for 32-bit Dual-Address-Mode (K) 2000
- * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de)
- *
- * AUG/25/2000 : addad support for 8, 16 and 32-bit Single-Address-Mode (K)2000
- * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de)
- *
- * APR/18/2002 : added proper support for MCF5272 DMA controller.
- * Arthur Shipkowski (art@videon-central.com)
- */
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
-
-/*
- * Set number of channels of DMA on ColdFire for different implementations.
- */
-#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
- defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-#define MAX_M68K_DMA_CHANNELS 4
-#elif defined(CONFIG_M5272)
-#define MAX_M68K_DMA_CHANNELS 1
-#elif defined(CONFIG_M532x)
-#define MAX_M68K_DMA_CHANNELS 0
-#else
-#define MAX_M68K_DMA_CHANNELS 2
-#endif
-
-extern unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS];
-extern unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
-
-#if !defined(CONFIG_M5272)
-#define DMA_MODE_WRITE_BIT 0x01 /* Memory/IO to IO/Memory select */
-#define DMA_MODE_WORD_BIT 0x02 /* 8 or 16 bit transfers */
-#define DMA_MODE_LONG_BIT 0x04 /* or 32 bit transfers */
-#define DMA_MODE_SINGLE_BIT 0x08 /* single-address-mode */
-
-/* I/O to memory, 8 bits, mode */
-#define DMA_MODE_READ 0
-/* memory to I/O, 8 bits, mode */
-#define DMA_MODE_WRITE 1
-/* I/O to memory, 16 bits, mode */
-#define DMA_MODE_READ_WORD 2
-/* memory to I/O, 16 bits, mode */
-#define DMA_MODE_WRITE_WORD 3
-/* I/O to memory, 32 bits, mode */
-#define DMA_MODE_READ_LONG 4
-/* memory to I/O, 32 bits, mode */
-#define DMA_MODE_WRITE_LONG 5
-/* I/O to memory, 8 bits, single-address-mode */
-#define DMA_MODE_READ_SINGLE 8
-/* memory to I/O, 8 bits, single-address-mode */
-#define DMA_MODE_WRITE_SINGLE 9
-/* I/O to memory, 16 bits, single-address-mode */
-#define DMA_MODE_READ_WORD_SINGLE 10
-/* memory to I/O, 16 bits, single-address-mode */
-#define DMA_MODE_WRITE_WORD_SINGLE 11
-/* I/O to memory, 32 bits, single-address-mode */
-#define DMA_MODE_READ_LONG_SINGLE 12
-/* memory to I/O, 32 bits, single-address-mode */
-#define DMA_MODE_WRITE_LONG_SINGLE 13
-
-#else /* CONFIG_M5272 is defined */
-
-/* Source static-address mode */
-#define DMA_MODE_SRC_SA_BIT 0x01
-/* Two bits to select between all four modes */
-#define DMA_MODE_SSIZE_MASK 0x06
-/* Offset to shift bits in */
-#define DMA_MODE_SSIZE_OFF 0x01
-/* Destination static-address mode */
-#define DMA_MODE_DES_SA_BIT 0x10
-/* Two bits to select between all four modes */
-#define DMA_MODE_DSIZE_MASK 0x60
-/* Offset to shift bits in */
-#define DMA_MODE_DSIZE_OFF 0x05
-/* Size modifiers */
-#define DMA_MODE_SIZE_LONG 0x00
-#define DMA_MODE_SIZE_BYTE 0x01
-#define DMA_MODE_SIZE_WORD 0x02
-#define DMA_MODE_SIZE_LINE 0x03
-
-/*
- * Aliases to help speed quick ports; these may be suboptimal, however. They
- * do not include the SINGLE mode modifiers since the MCF5272 does not have a
- * mode where the device is in control of its addressing.
- */
-
-/* I/O to memory, 8 bits, mode */
-#define DMA_MODE_READ ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
-/* memory to I/O, 8 bits, mode */
-#define DMA_MODE_WRITE ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
-/* I/O to memory, 16 bits, mode */
-#define DMA_MODE_READ_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
-/* memory to I/O, 16 bits, mode */
-#define DMA_MODE_WRITE_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
-/* I/O to memory, 32 bits, mode */
-#define DMA_MODE_READ_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT)
-/* memory to I/O, 32 bits, mode */
-#define DMA_MODE_WRITE_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT)
-
-#endif /* !defined(CONFIG_M5272) */
-
-#if !defined(CONFIG_M5272)
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
-{
- volatile unsigned short *dmawp;
-
-#ifdef DMA_DEBUG
- printk("enable_dma(dmanr=%d)\n", dmanr);
-#endif
-
- dmawp = (unsigned short *) dma_base_addr[dmanr];
- dmawp[MCFDMA_DCR] |= MCFDMA_DCR_EEXT;
-}
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
- volatile unsigned short *dmawp;
- volatile unsigned char *dmapb;
-
-#ifdef DMA_DEBUG
- printk("disable_dma(dmanr=%d)\n", dmanr);
-#endif
-
- dmawp = (unsigned short *) dma_base_addr[dmanr];
- dmapb = (unsigned char *) dma_base_addr[dmanr];
-
- /* Turn off external requests, and stop any DMA in progress */
- dmawp[MCFDMA_DCR] &= ~MCFDMA_DCR_EEXT;
- dmapb[MCFDMA_DSR] = MCFDMA_DSR_DONE;
-}
-
-/*
- * Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- *
- * This is a NOP for ColdFire. Provide a stub for compatibility.
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-}
-
-/* set mode (above) for a specific DMA channel */
-static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
-{
-
- volatile unsigned char *dmabp;
- volatile unsigned short *dmawp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode);
-#endif
-
- dmabp = (unsigned char *) dma_base_addr[dmanr];
- dmawp = (unsigned short *) dma_base_addr[dmanr];
-
- // Clear config errors
- dmabp[MCFDMA_DSR] = MCFDMA_DSR_DONE;
-
- // Set command register
- dmawp[MCFDMA_DCR] =
- MCFDMA_DCR_INT | // Enable completion irq
- MCFDMA_DCR_CS | // Force one xfer per request
- MCFDMA_DCR_AA | // Enable auto alignment
- // single-address-mode
- ((mode & DMA_MODE_SINGLE_BIT) ? MCFDMA_DCR_SAA : 0) |
- // sets s_rw (-> r/w) high if Memory to I/0
- ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_S_RW : 0) |
- // Memory to I/O or I/O to Memory
- ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_SINC : MCFDMA_DCR_DINC) |
- // 32 bit, 16 bit or 8 bit transfers
- ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_SSIZE_WORD :
- ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_SSIZE_LONG :
- MCFDMA_DCR_SSIZE_BYTE)) |
- ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_DSIZE_WORD :
- ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_DSIZE_LONG :
- MCFDMA_DCR_DSIZE_BYTE));
-
-#ifdef DEBUG_DMA
- printk("%s(%d): dmanr=%d DSR[%x]=%x DCR[%x]=%x\n", __FILE__, __LINE__,
- dmanr, (int) &dmabp[MCFDMA_DSR], dmabp[MCFDMA_DSR],
- (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR]);
-#endif
-}
-
-/* Set transfer address for specific DMA channel */
-static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
-{
- volatile unsigned short *dmawp;
- volatile unsigned int *dmalp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a);
-#endif
-
- dmawp = (unsigned short *) dma_base_addr[dmanr];
- dmalp = (unsigned int *) dma_base_addr[dmanr];
-
- // Determine which address registers are used for memory/device accesses
- if (dmawp[MCFDMA_DCR] & MCFDMA_DCR_SINC) {
- // Source incrementing, must be memory
- dmalp[MCFDMA_SAR] = a;
- // Set dest address, must be device
- dmalp[MCFDMA_DAR] = dma_device_address[dmanr];
- } else {
- // Destination incrementing, must be memory
- dmalp[MCFDMA_DAR] = a;
- // Set source address, must be device
- dmalp[MCFDMA_SAR] = dma_device_address[dmanr];
- }
-
-#ifdef DEBUG_DMA
- printk("%s(%d): dmanr=%d DCR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n",
- __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR],
- (int) &dmalp[MCFDMA_SAR], dmalp[MCFDMA_SAR],
- (int) &dmalp[MCFDMA_DAR], dmalp[MCFDMA_DAR]);
-#endif
-}
-
-/*
- * Specific for Coldfire - sets device address.
- * Should be called after the mode set call, and before set DMA address.
- */
-static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a)
-{
-#ifdef DMA_DEBUG
- printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a);
-#endif
-
- dma_device_address[dmanr] = a;
-}
-
-/*
- * NOTE 2: "count" represents _bytes_.
- */
-static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
-{
- volatile unsigned short *dmawp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count);
-#endif
-
- dmawp = (unsigned short *) dma_base_addr[dmanr];
- dmawp[MCFDMA_BCR] = (unsigned short)count;
-}
-
-/*
- * Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- */
-static __inline__ int get_dma_residue(unsigned int dmanr)
-{
- volatile unsigned short *dmawp;
- unsigned short count;
-
-#ifdef DMA_DEBUG
- printk("get_dma_residue(dmanr=%d)\n", dmanr);
-#endif
-
- dmawp = (unsigned short *) dma_base_addr[dmanr];
- count = dmawp[MCFDMA_BCR];
- return((int) count);
-}
-#else /* CONFIG_M5272 is defined */
-
-/*
- * The MCF5272 DMA controller is very different than the controller defined above
- * in terms of register mapping. For instance, with the exception of the 16-bit
- * interrupt register (IRQ#85, for reference), all of the registers are 32-bit.
- *
- * The big difference, however, is the lack of device-requested DMA. All modes
- * are dual address transfer, and there is no 'device' setup or direction bit.
- * You can DMA between a device and memory, between memory and memory, or even between
- * two devices directly, with any combination of incrementing and non-incrementing
- * addresses you choose. This puts a crimp in distinguishing between the 'device
- * address' set up by set_dma_device_addr.
- *
- * Therefore, there are two options. One is to use set_dma_addr and set_dma_device_addr,
- * which will act exactly as above in -- it will look to see if the source is set to
- * autoincrement, and if so it will make the source use the set_dma_addr value and the
- * destination the set_dma_device_addr value. Otherwise the source will be set to the
- * set_dma_device_addr value and the destination will get the set_dma_addr value.
- *
- * The other is to use the provided set_dma_src_addr and set_dma_dest_addr functions
- * and make it explicit. Depending on what you're doing, one of these two should work
- * for you, but don't mix them in the same transfer setup.
- */
-
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
-{
- volatile unsigned int *dmalp;
-
-#ifdef DMA_DEBUG
- printk("enable_dma(dmanr=%d)\n", dmanr);
-#endif
-
- dmalp = (unsigned int *) dma_base_addr[dmanr];
- dmalp[MCFDMA_DMR] |= MCFDMA_DMR_EN;
-}
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
- volatile unsigned int *dmalp;
-
-#ifdef DMA_DEBUG
- printk("disable_dma(dmanr=%d)\n", dmanr);
-#endif
-
- dmalp = (unsigned int *) dma_base_addr[dmanr];
-
- /* Turn off external requests, and stop any DMA in progress */
- dmalp[MCFDMA_DMR] &= ~MCFDMA_DMR_EN;
- dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET;
-}
-
-/*
- * Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- *
- * This is a NOP for ColdFire. Provide a stub for compatibility.
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-}
-
-/* set mode (above) for a specific DMA channel */
-static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
-{
-
- volatile unsigned int *dmalp;
- volatile unsigned short *dmawp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode);
-#endif
- dmalp = (unsigned int *) dma_base_addr[dmanr];
- dmawp = (unsigned short *) dma_base_addr[dmanr];
-
- // Clear config errors
- dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET;
-
- // Set command register
- dmalp[MCFDMA_DMR] =
- MCFDMA_DMR_RQM_DUAL | // Mandatory Request Mode setting
- MCFDMA_DMR_DSTT_SD | // Set up addressing types; set to supervisor-data.
- MCFDMA_DMR_SRCT_SD | // Set up addressing types; set to supervisor-data.
- // source static-address-mode
- ((mode & DMA_MODE_SRC_SA_BIT) ? MCFDMA_DMR_SRCM_SA : MCFDMA_DMR_SRCM_IA) |
- // dest static-address-mode
- ((mode & DMA_MODE_DES_SA_BIT) ? MCFDMA_DMR_DSTM_SA : MCFDMA_DMR_DSTM_IA) |
- // burst, 32 bit, 16 bit or 8 bit transfers are separately configurable on the MCF5272
- (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_DSTS_OFF) |
- (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_SRCS_OFF);
-
- dmawp[MCFDMA_DIR] |= MCFDMA_DIR_ASCEN; /* Enable completion interrupts */
-
-#ifdef DEBUG_DMA
- printk("%s(%d): dmanr=%d DMR[%x]=%x DIR[%x]=%x\n", __FILE__, __LINE__,
- dmanr, (int) &dmalp[MCFDMA_DMR], dmabp[MCFDMA_DMR],
- (int) &dmawp[MCFDMA_DIR], dmawp[MCFDMA_DIR]);
-#endif
-}
-
-/* Set transfer address for specific DMA channel */
-static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
-{
- volatile unsigned int *dmalp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a);
-#endif
-
- dmalp = (unsigned int *) dma_base_addr[dmanr];
-
- // Determine which address registers are used for memory/device accesses
- if (dmalp[MCFDMA_DMR] & MCFDMA_DMR_SRCM) {
- // Source incrementing, must be memory
- dmalp[MCFDMA_DSAR] = a;
- // Set dest address, must be device
- dmalp[MCFDMA_DDAR] = dma_device_address[dmanr];
- } else {
- // Destination incrementing, must be memory
- dmalp[MCFDMA_DDAR] = a;
- // Set source address, must be device
- dmalp[MCFDMA_DSAR] = dma_device_address[dmanr];
- }
-
-#ifdef DEBUG_DMA
- printk("%s(%d): dmanr=%d DMR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n",
- __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DMR], dmawp[MCFDMA_DMR],
- (int) &dmalp[MCFDMA_DSAR], dmalp[MCFDMA_DSAR],
- (int) &dmalp[MCFDMA_DDAR], dmalp[MCFDMA_DDAR]);
-#endif
-}
-
-/*
- * Specific for Coldfire - sets device address.
- * Should be called after the mode set call, and before set DMA address.
- */
-static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a)
-{
-#ifdef DMA_DEBUG
- printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a);
-#endif
-
- dma_device_address[dmanr] = a;
-}
-
-/*
- * NOTE 2: "count" represents _bytes_.
- *
- * NOTE 3: While a 32-bit register, "count" is only a maximum 24-bit value.
- */
-static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
-{
- volatile unsigned int *dmalp;
-
-#ifdef DMA_DEBUG
- printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count);
-#endif
-
- dmalp = (unsigned int *) dma_base_addr[dmanr];
- dmalp[MCFDMA_DBCR] = count;
-}
-
-/*
- * Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- */
-static __inline__ int get_dma_residue(unsigned int dmanr)
-{
- volatile unsigned int *dmalp;
- unsigned int count;
-
-#ifdef DMA_DEBUG
- printk("get_dma_residue(dmanr=%d)\n", dmanr);
-#endif
-
- dmalp = (unsigned int *) dma_base_addr[dmanr];
- count = dmalp[MCFDMA_DBCR];
- return(count);
-}
-
-#endif /* !defined(CONFIG_M5272) */
-#endif /* CONFIG_COLDFIRE */
-
-#define MAX_DMA_CHANNELS 8
-
-/* Don't define MAX_DMA_ADDRESS; it's useless on the m68k/coldfire and any
- occurrence should be flagged as an error. */
-/* under 2.4 it is actually needed by the new bootmem allocator */
-#define MAX_DMA_ADDRESS PAGE_OFFSET
-
-/* These are in kernel/dma.c: */
-extern int request_dma(unsigned int dmanr, const char *device_id); /* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr); /* release it again */
-
-#endif /* _M68K_DMA_H */
diff --git a/arch/m68k/include/asm/elia.h b/arch/m68k/include/asm/elia.h
deleted file mode 100644
index e037d4e2de33..000000000000
--- a/arch/m68k/include/asm/elia.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************/
-
-/*
- * elia.h -- Lineo (formerly Moreton Bay) eLIA platform support.
- *
- * (C) Copyright 1999-2000, Moreton Bay (www.moreton.com.au)
- * (C) Copyright 1999-2000, Lineo (www.lineo.com)
- */
-
-/****************************************************************************/
-#ifndef elia_h
-#define elia_h
-/****************************************************************************/
-
-#include <asm/coldfire.h>
-
-#ifdef CONFIG_eLIA
-
-/*
- * The serial port DTR and DCD lines are also on the Parallel I/O
- * as well, so define those too.
- */
-
-#define eLIA_DCD1 0x0001
-#define eLIA_DCD0 0x0002
-#define eLIA_DTR1 0x0004
-#define eLIA_DTR0 0x0008
-
-#define eLIA_PCIRESET 0x0020
-
-/*
- * Kernel macros to set and unset the LEDs.
- */
-#ifndef __ASSEMBLY__
-extern unsigned short ppdata;
-#endif /* __ASSEMBLY__ */
-
-#endif /* CONFIG_eLIA */
-
-/****************************************************************************/
-#endif /* elia_h */
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
new file mode 100644
index 000000000000..283214dc65a7
--- /dev/null
+++ b/arch/m68k/include/asm/gpio.h
@@ -0,0 +1,238 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 coldfire_gpio_h
+#define coldfire_gpio_h
+
+#include <linux/io.h>
+#include <asm-generic/gpio.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ * The Freescale Coldfire family is quite varied in how they implement GPIO.
+ * Some parts have 8 bit ports, some have 16bit and some have 32bit; some have
+ * only one port, others have multiple ports; some have a single data latch
+ * for both input and output, others have a separate pin data register to read
+ * input; some require a read-modify-write access to change an output, others
+ * have set and clear registers for some of the outputs; Some have all the
+ * GPIOs in a single control area, others have some GPIOs implemented in
+ * different modules.
+ *
+ * This implementation attempts accomodate the differences while presenting
+ * a generic interface that will optimize to as few instructions as possible.
+ */
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+ defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+
+/* These parts have GPIO organized by 8 bit ports */
+
+#define MCFGPIO_PORTTYPE u8
+#define MCFGPIO_PORTSIZE 8
+#define mcfgpio_read(port) __raw_readb(port)
+#define mcfgpio_write(data, port) __raw_writeb(data, port)
+
+#elif defined(CONFIG_M5307) || defined(CONFIG_M5407) || defined(CONFIG_M5272)
+
+/* These parts have GPIO organized by 16 bit ports */
+
+#define MCFGPIO_PORTTYPE u16
+#define MCFGPIO_PORTSIZE 16
+#define mcfgpio_read(port) __raw_readw(port)
+#define mcfgpio_write(data, port) __raw_writew(data, port)
+
+#elif defined(CONFIG_M5249)
+
+/* These parts have GPIO organized by 32 bit ports */
+
+#define MCFGPIO_PORTTYPE u32
+#define MCFGPIO_PORTSIZE 32
+#define mcfgpio_read(port) __raw_readl(port)
+#define mcfgpio_write(data, port) __raw_writel(data, port)
+
+#endif
+
+#define mcfgpio_bit(gpio) (1 << ((gpio) % MCFGPIO_PORTSIZE))
+#define mcfgpio_port(gpio) ((gpio) / MCFGPIO_PORTSIZE)
+
+#if defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+/*
+ * These parts have an 'Edge' Port module (external interrupt/GPIO) which uses
+ * read-modify-write to change an output and a GPIO module which has separate
+ * set/clr registers to directly change outputs with a single write access.
+ */
+#if defined(CONFIG_M528x)
+/*
+ * The 528x also has GPIOs in other modules (GPT, QADC) which use
+ * read-modify-write as well as those controlled by the EPORT and GPIO modules.
+ */
+#define MCFGPIO_SCR_START 40
+#else
+#define MCFGPIO_SCR_START 8
+#endif
+
+#define MCFGPIO_SETR_PORT(gpio) (MCFGPIO_SETR + \
+ mcfgpio_port(gpio - MCFGPIO_SCR_START))
+
+#define MCFGPIO_CLRR_PORT(gpio) (MCFGPIO_CLRR + \
+ mcfgpio_port(gpio - MCFGPIO_SCR_START))
+#else
+
+#define MCFGPIO_SCR_START MCFGPIO_PIN_MAX
+/* with MCFGPIO_SCR == MCFGPIO_PIN_MAX, these will be optimized away */
+#define MCFGPIO_SETR_PORT(gpio) 0
+#define MCFGPIO_CLRR_PORT(gpio) 0
+
+#endif
+/*
+ * Coldfire specific helper functions
+ */
+
+/* return the port pin data register for a gpio */
+static inline u32 __mcf_gpio_ppdr(unsigned gpio)
+{
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+ defined(CONFIG_M5307) || defined(CONFIG_M5407)
+ return MCFSIM_PADAT;
+#elif defined(CONFIG_M5272)
+ if (gpio < 16)
+ return MCFSIM_PADAT;
+ else if (gpio < 32)
+ return MCFSIM_PBDAT;
+ else
+ return MCFSIM_PCDAT;
+#elif defined(CONFIG_M5249)
+ if (gpio < 32)
+ return MCFSIM2_GPIOREAD;
+ else
+ return MCFSIM2_GPIO1READ;
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+ if (gpio < 8)
+ return MCFEPORT_EPPDR;
+#if defined(CONFIG_M528x)
+ else if (gpio < 16)
+ return MCFGPTA_GPTPORT;
+ else if (gpio < 24)
+ return MCFGPTB_GPTPORT;
+ else if (gpio < 32)
+ return MCFQADC_PORTQA;
+ else if (gpio < 40)
+ return MCFQADC_PORTQB;
+#endif
+ else
+ return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#endif
+}
+
+/* return the port output data register for a gpio */
+static inline u32 __mcf_gpio_podr(unsigned gpio)
+{
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+ defined(CONFIG_M5307) || defined(CONFIG_M5407)
+ return MCFSIM_PADAT;
+#elif defined(CONFIG_M5272)
+ if (gpio < 16)
+ return MCFSIM_PADAT;
+ else if (gpio < 32)
+ return MCFSIM_PBDAT;
+ else
+ return MCFSIM_PCDAT;
+#elif defined(CONFIG_M5249)
+ if (gpio < 32)
+ return MCFSIM2_GPIOWRITE;
+ else
+ return MCFSIM2_GPIO1WRITE;
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+ if (gpio < 8)
+ return MCFEPORT_EPDR;
+#if defined(CONFIG_M528x)
+ else if (gpio < 16)
+ return MCFGPTA_GPTPORT;
+ else if (gpio < 24)
+ return MCFGPTB_GPTPORT;
+ else if (gpio < 32)
+ return MCFQADC_PORTQA;
+ else if (gpio < 40)
+ return MCFQADC_PORTQB;
+#endif
+ else
+ return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#endif
+}
+
+/*
+ * The Generic GPIO functions
+ *
+ * If the gpio is a compile time constant and is one of the Coldfire gpios,
+ * use the inline version, otherwise dispatch thru gpiolib.
+ */
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ if (__builtin_constant_p(gpio) && gpio < MCFGPIO_PIN_MAX)
+ return mcfgpio_read(__mcf_gpio_ppdr(gpio)) & mcfgpio_bit(gpio);
+ else
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ if (__builtin_constant_p(gpio) && gpio < MCFGPIO_PIN_MAX) {
+ if (gpio < MCFGPIO_SCR_START) {
+ unsigned long flags;
+ MCFGPIO_PORTTYPE data;
+
+ local_irq_save(flags);
+ data = mcfgpio_read(__mcf_gpio_podr(gpio));
+ if (value)
+ data |= mcfgpio_bit(gpio);
+ else
+ data &= ~mcfgpio_bit(gpio);
+ mcfgpio_write(data, __mcf_gpio_podr(gpio));
+ local_irq_restore(flags);
+ } else {
+ if (value)
+ mcfgpio_write(mcfgpio_bit(gpio),
+ MCFGPIO_SETR_PORT(gpio));
+ else
+ mcfgpio_write(~mcfgpio_bit(gpio),
+ MCFGPIO_CLRR_PORT(gpio));
+ }
+ } else
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return (gpio < MCFGPIO_IRQ_MAX) ? gpio + MCFGPIO_IRQ_VECBASE : -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ return (irq >= MCFGPIO_IRQ_VECBASE &&
+ irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) ?
+ irq - MCFGPIO_IRQ_VECBASE : -ENXIO;
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+ return gpio < MCFGPIO_PIN_MAX ? 0 : __gpio_cansleep(gpio);
+}
+
+#endif
diff --git a/arch/m68k/include/asm/hardirq.h b/arch/m68k/include/asm/hardirq.h
index 56d0d5db231c..07f65725dda0 100644
--- a/arch/m68k/include/asm/hardirq.h
+++ b/arch/m68k/include/asm/hardirq.h
@@ -1,5 +1,8 @@
-#ifdef __uClinux__
-#include "hardirq_no.h"
-#else
-#include "hardirq_mm.h"
-#endif
+#ifndef __M68K_HARDIRQ_H
+#define __M68K_HARDIRQ_H
+
+#include <asm-generic/hardirq.h>
+
+#define HARDIRQ_BITS 8
+
+#endif /* __M68K_HARDIRQ_H */
diff --git a/arch/m68k/include/asm/hardirq_mm.h b/arch/m68k/include/asm/hardirq_mm.h
deleted file mode 100644
index 394ee946015c..000000000000
--- a/arch/m68k/include/asm/hardirq_mm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __M68K_HARDIRQ_H
-#define __M68K_HARDIRQ_H
-
-#include <linux/threads.h>
-#include <linux/cache.h>
-
-/* entry.S is sensitive to the offsets of these fields */
-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
-
-#endif
diff --git a/arch/m68k/include/asm/hardirq_no.h b/arch/m68k/include/asm/hardirq_no.h
deleted file mode 100644
index bfad28149a49..000000000000
--- a/arch/m68k/include/asm/hardirq_no.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __M68K_HARDIRQ_H
-#define __M68K_HARDIRQ_H
-
-#include <linux/cache.h>
-#include <linux/threads.h>
-#include <asm/irq.h>
-
-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
-
-/*
- * The hardirq mask has to be large enough to have
- * space for potentially all IRQ sources in the system
- * nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
-
-void ack_bad_irq(unsigned int irq);
-
-#endif /* __M68K_HARDIRQ_H */
diff --git a/arch/m68k/include/asm/irq.h b/arch/m68k/include/asm/irq.h
index d031416595b2..907eff1edd2f 100644
--- a/arch/m68k/include/asm/irq.h
+++ b/arch/m68k/include/asm/irq.h
@@ -1,5 +1,134 @@
-#ifdef __uClinux__
-#include "irq_no.h"
+#ifndef _M68K_IRQ_H_
+#define _M68K_IRQ_H_
+
+/*
+ * This should be the same as the max(NUM_X_SOURCES) for all the
+ * different m68k hosts compiled into the kernel.
+ * Currently the Atari has 72 and the Amiga 24, but if both are
+ * supported in the kernel it is better to make room for 72.
+ */
+#if defined(CONFIG_COLDFIRE)
+#define NR_IRQS 256
+#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
+#define NR_IRQS 200
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#define NR_IRQS 72
+#elif defined(CONFIG_Q40)
+#define NR_IRQS 43
+#elif defined(CONFIG_AMIGA) || !defined(CONFIG_MMU)
+#define NR_IRQS 32
+#elif defined(CONFIG_APOLLO)
+#define NR_IRQS 24
+#elif defined(CONFIG_HP300)
+#define NR_IRQS 8
#else
-#include "irq_mm.h"
+#define NR_IRQS 0
#endif
+
+#ifdef CONFIG_MMU
+
+#include <linux/linkage.h>
+#include <linux/hardirq.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock_types.h>
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+/*
+ * Interrupt source definitions
+ * General interrupt sources are the level 1-7.
+ * Adding an interrupt service routine for one of these sources
+ * results in the addition of that routine to a chain of routines.
+ * Each one is called in succession. Each individual interrupt
+ * service routine should determine if the device associated with
+ * that routine requires service.
+ */
+
+#define IRQ_SPURIOUS 0
+
+#define IRQ_AUTO_1 1 /* level 1 interrupt */
+#define IRQ_AUTO_2 2 /* level 2 interrupt */
+#define IRQ_AUTO_3 3 /* level 3 interrupt */
+#define IRQ_AUTO_4 4 /* level 4 interrupt */
+#define IRQ_AUTO_5 5 /* level 5 interrupt */
+#define IRQ_AUTO_6 6 /* level 6 interrupt */
+#define IRQ_AUTO_7 7 /* level 7 interrupt (non-maskable) */
+
+#define IRQ_USER 8
+
+extern unsigned int irq_canonicalize(unsigned int irq);
+
+struct pt_regs;
+
+/*
+ * various flags for request_irq() - the Amiga now uses the standard
+ * mechanism like all other architectures - IRQF_DISABLED and
+ * IRQF_SHARED are your friends.
+ */
+#ifndef MACH_AMIGA_ONLY
+#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */
+#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */
+#define IRQ_FLG_FAST (0x0004)
+#define IRQ_FLG_SLOW (0x0008)
+#define IRQ_FLG_STD (0x8000) /* internally used */
+#endif
+
+/*
+ * This structure is used to chain together the ISRs for a particular
+ * interrupt source (if it supports chaining).
+ */
+typedef struct irq_node {
+ irqreturn_t (*handler)(int, void *);
+ void *dev_id;
+ struct irq_node *next;
+ unsigned long flags;
+ const char *devname;
+} irq_node_t;
+
+/*
+ * This structure has only 4 elements for speed reasons
+ */
+struct irq_handler {
+ int (*handler)(int, void *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+};
+
+struct irq_controller {
+ const char *name;
+ spinlock_t lock;
+ int (*startup)(unsigned int irq);
+ void (*shutdown)(unsigned int irq);
+ void (*enable)(unsigned int irq);
+ void (*disable)(unsigned int irq);
+};
+
+extern int m68k_irq_startup(unsigned int);
+extern void m68k_irq_shutdown(unsigned int);
+
+/*
+ * This function returns a new irq_node_t
+ */
+extern irq_node_t *new_irq_node(void);
+
+extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+ void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
+
+asmlinkage void m68k_handle_int(unsigned int);
+asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *);
+
+#else
+#define irq_canonicalize(irq) (irq)
+#endif /* CONFIG_MMU */
+
+#endif /* _M68K_IRQ_H_ */
diff --git a/arch/m68k/include/asm/irq_mm.h b/arch/m68k/include/asm/irq_mm.h
deleted file mode 100644
index 0cab42cad79e..000000000000
--- a/arch/m68k/include/asm/irq_mm.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef _M68K_IRQ_H_
-#define _M68K_IRQ_H_
-
-#include <linux/linkage.h>
-#include <linux/hardirq.h>
-#include <linux/irqreturn.h>
-#include <linux/spinlock_types.h>
-
-/*
- * This should be the same as the max(NUM_X_SOURCES) for all the
- * different m68k hosts compiled into the kernel.
- * Currently the Atari has 72 and the Amiga 24, but if both are
- * supported in the kernel it is better to make room for 72.
- */
-#if defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
-#define NR_IRQS 200
-#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
-#define NR_IRQS 72
-#elif defined(CONFIG_Q40)
-#define NR_IRQS 43
-#elif defined(CONFIG_AMIGA)
-#define NR_IRQS 32
-#elif defined(CONFIG_APOLLO)
-#define NR_IRQS 24
-#elif defined(CONFIG_HP300)
-#define NR_IRQS 8
-#else
-#define NR_IRQS 0
-#endif
-
-/*
- * The hardirq mask has to be large enough to have
- * space for potentially all IRQ sources in the system
- * nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
-
-/*
- * Interrupt source definitions
- * General interrupt sources are the level 1-7.
- * Adding an interrupt service routine for one of these sources
- * results in the addition of that routine to a chain of routines.
- * Each one is called in succession. Each individual interrupt
- * service routine should determine if the device associated with
- * that routine requires service.
- */
-
-#define IRQ_SPURIOUS 0
-
-#define IRQ_AUTO_1 1 /* level 1 interrupt */
-#define IRQ_AUTO_2 2 /* level 2 interrupt */
-#define IRQ_AUTO_3 3 /* level 3 interrupt */
-#define IRQ_AUTO_4 4 /* level 4 interrupt */
-#define IRQ_AUTO_5 5 /* level 5 interrupt */
-#define IRQ_AUTO_6 6 /* level 6 interrupt */
-#define IRQ_AUTO_7 7 /* level 7 interrupt (non-maskable) */
-
-#define IRQ_USER 8
-
-extern unsigned int irq_canonicalize(unsigned int irq);
-
-struct pt_regs;
-
-/*
- * various flags for request_irq() - the Amiga now uses the standard
- * mechanism like all other architectures - IRQF_DISABLED and
- * IRQF_SHARED are your friends.
- */
-#ifndef MACH_AMIGA_ONLY
-#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */
-#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */
-#define IRQ_FLG_FAST (0x0004)
-#define IRQ_FLG_SLOW (0x0008)
-#define IRQ_FLG_STD (0x8000) /* internally used */
-#endif
-
-/*
- * This structure is used to chain together the ISRs for a particular
- * interrupt source (if it supports chaining).
- */
-typedef struct irq_node {
- irqreturn_t (*handler)(int, void *);
- void *dev_id;
- struct irq_node *next;
- unsigned long flags;
- const char *devname;
-} irq_node_t;
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-struct irq_handler {
- int (*handler)(int, void *);
- unsigned long flags;
- void *dev_id;
- const char *devname;
-};
-
-struct irq_controller {
- const char *name;
- spinlock_t lock;
- int (*startup)(unsigned int irq);
- void (*shutdown)(unsigned int irq);
- void (*enable)(unsigned int irq);
- void (*disable)(unsigned int irq);
-};
-
-extern int m68k_irq_startup(unsigned int);
-extern void m68k_irq_shutdown(unsigned int);
-
-/*
- * This function returns a new irq_node_t
- */
-extern irq_node_t *new_irq_node(void);
-
-extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
-extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
- void (*handler)(unsigned int, struct pt_regs *));
-extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
-
-asmlinkage void m68k_handle_int(unsigned int);
-asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *);
-
-#endif /* _M68K_IRQ_H_ */
diff --git a/arch/m68k/include/asm/irq_no.h b/arch/m68k/include/asm/irq_no.h
deleted file mode 100644
index 9373c31ac87d..000000000000
--- a/arch/m68k/include/asm/irq_no.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _M68KNOMMU_IRQ_H_
-#define _M68KNOMMU_IRQ_H_
-
-#ifdef CONFIG_COLDFIRE
-/*
- * On the ColdFire we keep track of all vectors. That way drivers
- * can register whatever vector number they wish, and we can deal
- * with it.
- */
-#define SYS_IRQS 256
-#define NR_IRQS SYS_IRQS
-
-#else
-
-/*
- * # of m68k interrupts
- */
-#define SYS_IRQS 8
-#define NR_IRQS (24 + SYS_IRQS)
-
-#endif /* CONFIG_COLDFIRE */
-
-
-#define irq_canonicalize(irq) (irq)
-
-#endif /* _M68KNOMMU_IRQ_H_ */
diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h
index 7e3594dea88b..08bbe108819f 100644
--- a/arch/m68k/include/asm/m5206sim.h
+++ b/arch/m68k/include/asm/m5206sim.h
@@ -85,8 +85,21 @@
#define MCFSIM_PAR 0xcb /* Pin Assignment reg (r/w) */
#endif
-#define MCFSIM_PADDR 0x1c5 /* Parallel Direction (r/w) */
-#define MCFSIM_PADAT 0x1c9 /* Parallel Port Value (r/w) */
+#define MCFSIM_PADDR (MCF_MBAR + 0x1c5) /* Parallel Direction (r/w) */
+#define MCFSIM_PADAT (MCF_MBAR + 0x1c9) /* Parallel Port Value (r/w) */
+
+/*
+ * Generic GPIO
+ */
+#define MCFGPIO_PIN_MAX 8
+#define MCFGPIO_IRQ_VECBASE -1
+#define MCFGPIO_IRQ_MAX -1
+
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
+#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
/*
* Some symbol defines for the Parallel Port Pin Assignment Register
@@ -111,21 +124,5 @@
#define MCFSIM_DMA2ICR MCFSIM_ICR15 /* DMA 2 ICR */
#endif
-#if defined(CONFIG_M5206e)
-#define MCFSIM_IMR_MASKALL 0xfffe /* All SIM intr sources */
-#endif
-
-/*
- * Macro to get and set IMR register. It is 16 bits on the 5206.
- */
-#define mcf_getimr() \
- *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IMR))
-
-#define mcf_setimr(imr) \
- *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IMR)) = (imr)
-
-#define mcf_getipr() \
- *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IPR))
-
/****************************************************************************/
#endif /* m5206sim_h */
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index 83bbcfd6e8f2..ed2b69b96805 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -11,9 +11,8 @@
#define m520xsim_h
/****************************************************************************/
-
/*
- * Define the 5282 SIM register set addresses.
+ * Define the 520x SIM register set addresses.
*/
#define MCFICM_INTC0 0x48000 /* Base for Interrupt Ctrl 0 */
#define MCFINTC_IPRH 0x00 /* Interrupt pending 32-63 */
@@ -22,8 +21,22 @@
#define MCFINTC_IMRL 0x0c /* Interrupt mask 1-31 */
#define MCFINTC_INTFRCH 0x10 /* Interrupt force 32-63 */
#define MCFINTC_INTFRCL 0x14 /* Interrupt force 1-31 */
+#define MCFINTC_SIMR 0x1c /* Set interrupt mask 0-63 */
+#define MCFINTC_CIMR 0x1d /* Clear interrupt mask 0-63 */
#define MCFINTC_ICR0 0x40 /* Base ICR register */
+/*
+ * The common interrupt controller code just wants to know the absolute
+ * address to the SIMR and CIMR registers (not offsets into IPSBAR).
+ * The 520x family only has a single INTC unit.
+ */
+#define MCFINTC0_SIMR (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_SIMR)
+#define MCFINTC0_CIMR (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_CIMR)
+#define MCFINTC0_ICR0 (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0)
+#define MCFINTC1_SIMR (0)
+#define MCFINTC1_CIMR (0)
+#define MCFINTC1_ICR0 (0)
+
#define MCFINT_VECBASE 64
#define MCFINT_UART0 26 /* Interrupt number for UART0 */
#define MCFINT_UART1 27 /* Interrupt number for UART1 */
@@ -41,6 +54,62 @@
#define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */
#define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */
+#define MCFEPORT_EPDDR 0xFC088002
+#define MCFEPORT_EPDR 0xFC088004
+#define MCFEPORT_EPPDR 0xFC088005
+
+#define MCFGPIO_PODR_BUSCTL 0xFC0A4000
+#define MCFGPIO_PODR_BE 0xFC0A4001
+#define MCFGPIO_PODR_CS 0xFC0A4002
+#define MCFGPIO_PODR_FECI2C 0xFC0A4003
+#define MCFGPIO_PODR_QSPI 0xFC0A4004
+#define MCFGPIO_PODR_TIMER 0xFC0A4005
+#define MCFGPIO_PODR_UART 0xFC0A4006
+#define MCFGPIO_PODR_FECH 0xFC0A4007
+#define MCFGPIO_PODR_FECL 0xFC0A4008
+
+#define MCFGPIO_PDDR_BUSCTL 0xFC0A400C
+#define MCFGPIO_PDDR_BE 0xFC0A400D
+#define MCFGPIO_PDDR_CS 0xFC0A400E
+#define MCFGPIO_PDDR_FECI2C 0xFC0A400F
+#define MCFGPIO_PDDR_QSPI 0xFC0A4010
+#define MCFGPIO_PDDR_TIMER 0xFC0A4011
+#define MCFGPIO_PDDR_UART 0xFC0A4012
+#define MCFGPIO_PDDR_FECH 0xFC0A4013
+#define MCFGPIO_PDDR_FECL 0xFC0A4014
+
+#define MCFGPIO_PPDSDR_BUSCTL 0xFC0A401A
+#define MCFGPIO_PPDSDR_BE 0xFC0A401B
+#define MCFGPIO_PPDSDR_CS 0xFC0A401C
+#define MCFGPIO_PPDSDR_FECI2C 0xFC0A401D
+#define MCFGPIO_PPDSDR_QSPI 0xFC0A401E
+#define MCFGPIO_PPDSDR_TIMER 0xFC0A401F
+#define MCFGPIO_PPDSDR_UART 0xFC0A4021
+#define MCFGPIO_PPDSDR_FECH 0xFC0A4021
+#define MCFGPIO_PPDSDR_FECL 0xFC0A4022
+
+#define MCFGPIO_PCLRR_BUSCTL 0xFC0A4024
+#define MCFGPIO_PCLRR_BE 0xFC0A4025
+#define MCFGPIO_PCLRR_CS 0xFC0A4026
+#define MCFGPIO_PCLRR_FECI2C 0xFC0A4027
+#define MCFGPIO_PCLRR_QSPI 0xFC0A4028
+#define MCFGPIO_PCLRR_TIMER 0xFC0A4029
+#define MCFGPIO_PCLRR_UART 0xFC0A402A
+#define MCFGPIO_PCLRR_FECH 0xFC0A402B
+#define MCFGPIO_PCLRR_FECL 0xFC0A402C
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PODR MCFGPIO_PODR_BUSCTL
+#define MCFGPIO_PDDR MCFGPIO_PDDR_BUSCTL
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_BUSCTL
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_BUSCTL
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_BUSCTL
+
+#define MCFGPIO_PIN_MAX 80
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+/****************************************************************************/
#define MCF_GPIO_PAR_UART (0xA4036)
#define MCF_GPIO_PAR_FECI2C (0xA4033)
@@ -55,10 +124,6 @@
#define MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2 (0x02)
#define MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 (0x04)
-#define ICR_INTRCONF 0x05
-#define MCFPIT_IMR MCFINTC_IMRL
-#define MCFPIT_IMR_IBIT (1 << MCFINT_PIT1)
-
/*
* Reset Controll Unit.
*/
diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h
index 55183b5df1b8..a34894cf8e6f 100644
--- a/arch/m68k/include/asm/m523xsim.h
+++ b/arch/m68k/include/asm/m523xsim.h
@@ -50,5 +50,82 @@
#define MCF_RCR_SWRESET 0x80 /* Software reset bit */
#define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */
+#define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000)
+#define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001)
+#define MCFGPIO_PODR_DATAL (MCF_IPSBAR + 0x100002)
+#define MCFGPIO_PODR_BUSCTL (MCF_IPSBAR + 0x100003)
+#define MCFGPIO_PODR_BS (MCF_IPSBAR + 0x100004)
+#define MCFGPIO_PODR_CS (MCF_IPSBAR + 0x100005)
+#define MCFGPIO_PODR_SDRAM (MCF_IPSBAR + 0x100006)
+#define MCFGPIO_PODR_FECI2C (MCF_IPSBAR + 0x100007)
+#define MCFGPIO_PODR_UARTH (MCF_IPSBAR + 0x100008)
+#define MCFGPIO_PODR_UARTL (MCF_IPSBAR + 0x100009)
+#define MCFGPIO_PODR_QSPI (MCF_IPSBAR + 0x10000A)
+#define MCFGPIO_PODR_TIMER (MCF_IPSBAR + 0x10000B)
+#define MCFGPIO_PODR_ETPU (MCF_IPSBAR + 0x10000C)
+
+#define MCFGPIO_PDDR_ADDR (MCF_IPSBAR + 0x100010)
+#define MCFGPIO_PDDR_DATAH (MCF_IPSBAR + 0x100011)
+#define MCFGPIO_PDDR_DATAL (MCF_IPSBAR + 0x100012)
+#define MCFGPIO_PDDR_BUSCTL (MCF_IPSBAR + 0x100013)
+#define MCFGPIO_PDDR_BS (MCF_IPSBAR + 0x100014)
+#define MCFGPIO_PDDR_CS (MCF_IPSBAR + 0x100015)
+#define MCFGPIO_PDDR_SDRAM (MCF_IPSBAR + 0x100016)
+#define MCFGPIO_PDDR_FECI2C (MCF_IPSBAR + 0x100017)
+#define MCFGPIO_PDDR_UARTH (MCF_IPSBAR + 0x100018)
+#define MCFGPIO_PDDR_UARTL (MCF_IPSBAR + 0x100019)
+#define MCFGPIO_PDDR_QSPI (MCF_IPSBAR + 0x10001A)
+#define MCFGPIO_PDDR_TIMER (MCF_IPSBAR + 0x10001B)
+#define MCFGPIO_PDDR_ETPU (MCF_IPSBAR + 0x10001C)
+
+#define MCFGPIO_PPDSDR_ADDR (MCF_IPSBAR + 0x100020)
+#define MCFGPIO_PPDSDR_DATAH (MCF_IPSBAR + 0x100021)
+#define MCFGPIO_PPDSDR_DATAL (MCF_IPSBAR + 0x100022)
+#define MCFGPIO_PPDSDR_BUSCTL (MCF_IPSBAR + 0x100023)
+#define MCFGPIO_PPDSDR_BS (MCF_IPSBAR + 0x100024)
+#define MCFGPIO_PPDSDR_CS (MCF_IPSBAR + 0x100025)
+#define MCFGPIO_PPDSDR_SDRAM (MCF_IPSBAR + 0x100026)
+#define MCFGPIO_PPDSDR_FECI2C (MCF_IPSBAR + 0x100027)
+#define MCFGPIO_PPDSDR_UARTH (MCF_IPSBAR + 0x100028)
+#define MCFGPIO_PPDSDR_UARTL (MCF_IPSBAR + 0x100029)
+#define MCFGPIO_PPDSDR_QSPI (MCF_IPSBAR + 0x10002A)
+#define MCFGPIO_PPDSDR_TIMER (MCF_IPSBAR + 0x10002B)
+#define MCFGPIO_PPDSDR_ETPU (MCF_IPSBAR + 0x10002C)
+
+#define MCFGPIO_PCLRR_ADDR (MCF_IPSBAR + 0x100030)
+#define MCFGPIO_PCLRR_DATAH (MCF_IPSBAR + 0x100031)
+#define MCFGPIO_PCLRR_DATAL (MCF_IPSBAR + 0x100032)
+#define MCFGPIO_PCLRR_BUSCTL (MCF_IPSBAR + 0x100033)
+#define MCFGPIO_PCLRR_BS (MCF_IPSBAR + 0x100034)
+#define MCFGPIO_PCLRR_CS (MCF_IPSBAR + 0x100035)
+#define MCFGPIO_PCLRR_SDRAM (MCF_IPSBAR + 0x100036)
+#define MCFGPIO_PCLRR_FECI2C (MCF_IPSBAR + 0x100037)
+#define MCFGPIO_PCLRR_UARTH (MCF_IPSBAR + 0x100038)
+#define MCFGPIO_PCLRR_UARTL (MCF_IPSBAR + 0x100039)
+#define MCFGPIO_PCLRR_QSPI (MCF_IPSBAR + 0x10003A)
+#define MCFGPIO_PCLRR_TIMER (MCF_IPSBAR + 0x10003B)
+#define MCFGPIO_PCLRR_ETPU (MCF_IPSBAR + 0x10003C)
+
+/*
+ * EPort
+ */
+
+#define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002)
+#define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004)
+#define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005)
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PODR MCFGPIO_PODR_ADDR
+#define MCFGPIO_PDDR MCFGPIO_PDDR_ADDR
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_ADDR
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_ADDR
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_ADDR
+
+#define MCFGPIO_PIN_MAX 107
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+
/****************************************************************************/
#endif /* m523xsim_h */
diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h
index 366eb8602d2f..255095d0df64 100644
--- a/arch/m68k/include/asm/m5249sim.h
+++ b/arch/m68k/include/asm/m5249sim.h
@@ -71,16 +71,22 @@
#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */
/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
+#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
+
+/*
* General purpose IO registers (in MBAR2).
*/
-#define MCFSIM2_GPIOREAD 0x0 /* GPIO read values */
-#define MCFSIM2_GPIOWRITE 0x4 /* GPIO write values */
-#define MCFSIM2_GPIOENABLE 0x8 /* GPIO enabled */
-#define MCFSIM2_GPIOFUNC 0xc /* GPIO function */
-#define MCFSIM2_GPIO1READ 0xb0 /* GPIO1 read values */
-#define MCFSIM2_GPIO1WRITE 0xb4 /* GPIO1 write values */
-#define MCFSIM2_GPIO1ENABLE 0xb8 /* GPIO1 enabled */
-#define MCFSIM2_GPIO1FUNC 0xbc /* GPIO1 function */
+#define MCFSIM2_GPIOREAD (MCF_MBAR2 + 0x000) /* GPIO read values */
+#define MCFSIM2_GPIOWRITE (MCF_MBAR2 + 0x004) /* GPIO write values */
+#define MCFSIM2_GPIOENABLE (MCF_MBAR2 + 0x008) /* GPIO enabled */
+#define MCFSIM2_GPIOFUNC (MCF_MBAR2 + 0x00C) /* GPIO function */
+#define MCFSIM2_GPIO1READ (MCF_MBAR2 + 0x0B0) /* GPIO1 read values */
+#define MCFSIM2_GPIO1WRITE (MCF_MBAR2 + 0x0B4) /* GPIO1 write values */
+#define MCFSIM2_GPIO1ENABLE (MCF_MBAR2 + 0x0B8) /* GPIO1 enabled */
+#define MCFSIM2_GPIO1FUNC (MCF_MBAR2 + 0x0BC) /* GPIO1 function */
#define MCFSIM2_GPIOINTSTAT 0xc0 /* GPIO interrupt status */
#define MCFSIM2_GPIOINTCLEAR 0xc0 /* GPIO interrupt clear */
@@ -100,20 +106,28 @@
#define MCFSIM2_IDECONFIG1 0x18c /* IDEconfig1 */
#define MCFSIM2_IDECONFIG2 0x190 /* IDEconfig2 */
-
/*
- * Macro to set IMR register. It is 32 bits on the 5249.
+ * Generic GPIO support
*/
-#define MCFSIM_IMR_MASKALL 0x7fffe /* All SIM intr sources */
+#define MCFGPIO_PIN_MAX 64
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
-#define mcf_getimr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR))
-
-#define mcf_setimr(imr) \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr);
+/*
+ * Define the base interrupt for the second interrupt controller.
+ * We set it to 128, out of the way of the base interrupts, and plenty
+ * of room for its 64 interrupts.
+ */
+#define MCFINTC2_VECBASE 128
-#define mcf_getipr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR))
+#define MCFINTC2_GPIOIRQ0 (MCFINTC2_VECBASE + 32)
+#define MCFINTC2_GPIOIRQ1 (MCFINTC2_VECBASE + 33)
+#define MCFINTC2_GPIOIRQ2 (MCFINTC2_VECBASE + 34)
+#define MCFINTC2_GPIOIRQ3 (MCFINTC2_VECBASE + 35)
+#define MCFINTC2_GPIOIRQ4 (MCFINTC2_VECBASE + 36)
+#define MCFINTC2_GPIOIRQ5 (MCFINTC2_VECBASE + 37)
+#define MCFINTC2_GPIOIRQ6 (MCFINTC2_VECBASE + 38)
+#define MCFINTC2_GPIOIRQ7 (MCFINTC2_VECBASE + 39)
/****************************************************************************/
@@ -137,9 +151,9 @@
subql #1,%a1 /* get MBAR2 address in a1 */
/*
- * Move secondary interrupts to base at 128.
+ * Move secondary interrupts to their base (128).
*/
- moveb #0x80,%d0
+ moveb #MCFINTC2_VECBASE,%d0
moveb %d0,0x16b(%a1) /* interrupt base register */
/*
diff --git a/arch/m68k/include/asm/m5272sim.h b/arch/m68k/include/asm/m5272sim.h
index 6217edc21139..df3332c2317d 100644
--- a/arch/m68k/include/asm/m5272sim.h
+++ b/arch/m68k/include/asm/m5272sim.h
@@ -12,7 +12,6 @@
#define m5272sim_h
/****************************************************************************/
-
/*
* Define the 5272 SIM register set addresses.
*/
@@ -63,16 +62,59 @@
#define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */
#define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */
-#define MCFSIM_PACNT 0x80 /* Port A Control (r/w) */
-#define MCFSIM_PADDR 0x84 /* Port A Direction (r/w) */
-#define MCFSIM_PADAT 0x86 /* Port A Data (r/w) */
-#define MCFSIM_PBCNT 0x88 /* Port B Control (r/w) */
-#define MCFSIM_PBDDR 0x8c /* Port B Direction (r/w) */
-#define MCFSIM_PBDAT 0x8e /* Port B Data (r/w) */
-#define MCFSIM_PCDDR 0x94 /* Port C Direction (r/w) */
-#define MCFSIM_PCDAT 0x96 /* Port C Data (r/w) */
-#define MCFSIM_PDCNT 0x98 /* Port D Control (r/w) */
+#define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */
+#define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */
+#define MCFSIM_PADAT (MCF_MBAR + 0x86) /* Port A Data (r/w) */
+#define MCFSIM_PBCNT (MCF_MBAR + 0x88) /* Port B Control (r/w) */
+#define MCFSIM_PBDDR (MCF_MBAR + 0x8c) /* Port B Direction (r/w) */
+#define MCFSIM_PBDAT (MCF_MBAR + 0x8e) /* Port B Data (r/w) */
+#define MCFSIM_PCDDR (MCF_MBAR + 0x94) /* Port C Direction (r/w) */
+#define MCFSIM_PCDAT (MCF_MBAR + 0x96) /* Port C Data (r/w) */
+#define MCFSIM_PDCNT (MCF_MBAR + 0x98) /* Port D Control (r/w) */
+
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCFINT_VECBASE 64 /* Base of interrupts */
+#define MCF_IRQ_SPURIOUS 64 /* User Spurious */
+#define MCF_IRQ_EINT1 65 /* External Interrupt 1 */
+#define MCF_IRQ_EINT2 66 /* External Interrupt 2 */
+#define MCF_IRQ_EINT3 67 /* External Interrupt 3 */
+#define MCF_IRQ_EINT4 68 /* External Interrupt 4 */
+#define MCF_IRQ_TIMER1 69 /* Timer 1 */
+#define MCF_IRQ_TIMER2 70 /* Timer 2 */
+#define MCF_IRQ_TIMER3 71 /* Timer 3 */
+#define MCF_IRQ_TIMER4 72 /* Timer 4 */
+#define MCF_IRQ_UART1 73 /* UART 1 */
+#define MCF_IRQ_UART2 74 /* UART 2 */
+#define MCF_IRQ_PLIP 75 /* PLIC 2Khz Periodic */
+#define MCF_IRQ_PLIA 76 /* PLIC Asynchronous */
+#define MCF_IRQ_USB0 77 /* USB Endpoint 0 */
+#define MCF_IRQ_USB1 78 /* USB Endpoint 1 */
+#define MCF_IRQ_USB2 79 /* USB Endpoint 2 */
+#define MCF_IRQ_USB3 80 /* USB Endpoint 3 */
+#define MCF_IRQ_USB4 81 /* USB Endpoint 4 */
+#define MCF_IRQ_USB5 82 /* USB Endpoint 5 */
+#define MCF_IRQ_USB6 83 /* USB Endpoint 6 */
+#define MCF_IRQ_USB7 84 /* USB Endpoint 7 */
+#define MCF_IRQ_DMA 85 /* DMA Controller */
+#define MCF_IRQ_ERX 86 /* Ethernet Receiver */
+#define MCF_IRQ_ETX 87 /* Ethernet Transmitter */
+#define MCF_IRQ_ENTC 88 /* Ethernet Non-Time Critical */
+#define MCF_IRQ_QSPI 89 /* Queued Serial Interface */
+#define MCF_IRQ_EINT5 90 /* External Interrupt 5 */
+#define MCF_IRQ_EINT6 91 /* External Interrupt 6 */
+#define MCF_IRQ_SWTO 92 /* Software Watchdog */
+#define MCFINT_VECMAX 95 /* Maxmum interrupt */
+#define MCF_IRQ_TIMER MCF_IRQ_TIMER1
+#define MCF_IRQ_PROFILER MCF_IRQ_TIMER2
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX 48
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
/****************************************************************************/
#endif /* m5272sim_h */
diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h
index 95f4f8ee8f7c..453356d72d80 100644
--- a/arch/m68k/include/asm/m527xsim.h
+++ b/arch/m68k/include/asm/m527xsim.h
@@ -54,6 +54,175 @@
#define MCFSIM_DMR1 0x5c /* SDRAM address mask 1 */
#endif
+
+#ifdef CONFIG_M5271
+#define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000)
+#define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001)
+#define MCFGPIO_PODR_DATAL (MCF_IPSBAR + 0x100002)
+#define MCFGPIO_PODR_BUSCTL (MCF_IPSBAR + 0x100003)
+#define MCFGPIO_PODR_BS (MCF_IPSBAR + 0x100004)
+#define MCFGPIO_PODR_CS (MCF_IPSBAR + 0x100005)
+#define MCFGPIO_PODR_SDRAM (MCF_IPSBAR + 0x100006)
+#define MCFGPIO_PODR_FECI2C (MCF_IPSBAR + 0x100007)
+#define MCFGPIO_PODR_UARTH (MCF_IPSBAR + 0x100008)
+#define MCFGPIO_PODR_UARTL (MCF_IPSBAR + 0x100009)
+#define MCFGPIO_PODR_QSPI (MCF_IPSBAR + 0x10000A)
+#define MCFGPIO_PODR_TIMER (MCF_IPSBAR + 0x10000B)
+
+#define MCFGPIO_PDDR_ADDR (MCF_IPSBAR + 0x100010)
+#define MCFGPIO_PDDR_DATAH (MCF_IPSBAR + 0x100011)
+#define MCFGPIO_PDDR_DATAL (MCF_IPSBAR + 0x100012)
+#define MCFGPIO_PDDR_BUSCTL (MCF_IPSBAR + 0x100013)
+#define MCFGPIO_PDDR_BS (MCF_IPSBAR + 0x100014)
+#define MCFGPIO_PDDR_CS (MCF_IPSBAR + 0x100015)
+#define MCFGPIO_PDDR_SDRAM (MCF_IPSBAR + 0x100016)
+#define MCFGPIO_PDDR_FECI2C (MCF_IPSBAR + 0x100017)
+#define MCFGPIO_PDDR_UARTH (MCF_IPSBAR + 0x100018)
+#define MCFGPIO_PDDR_UARTL (MCF_IPSBAR + 0x100019)
+#define MCFGPIO_PDDR_QSPI (MCF_IPSBAR + 0x10001A)
+#define MCFGPIO_PDDR_TIMER (MCF_IPSBAR + 0x10001B)
+
+#define MCFGPIO_PPDSDR_ADDR (MCF_IPSBAR + 0x100020)
+#define MCFGPIO_PPDSDR_DATAH (MCF_IPSBAR + 0x100021)
+#define MCFGPIO_PPDSDR_DATAL (MCF_IPSBAR + 0x100022)
+#define MCFGPIO_PPDSDR_BUSCTL (MCF_IPSBAR + 0x100023)
+#define MCFGPIO_PPDSDR_BS (MCF_IPSBAR + 0x100024)
+#define MCFGPIO_PPDSDR_CS (MCF_IPSBAR + 0x100025)
+#define MCFGPIO_PPDSDR_SDRAM (MCF_IPSBAR + 0x100026)
+#define MCFGPIO_PPDSDR_FECI2C (MCF_IPSBAR + 0x100027)
+#define MCFGPIO_PPDSDR_UARTH (MCF_IPSBAR + 0x100028)
+#define MCFGPIO_PPDSDR_UARTL (MCF_IPSBAR + 0x100029)
+#define MCFGPIO_PPDSDR_QSPI (MCF_IPSBAR + 0x10002A)
+#define MCFGPIO_PPDSDR_TIMER (MCF_IPSBAR + 0x10002B)
+
+#define MCFGPIO_PCLRR_ADDR (MCF_IPSBAR + 0x100030)
+#define MCFGPIO_PCLRR_DATAH (MCF_IPSBAR + 0x100031)
+#define MCFGPIO_PCLRR_DATAL (MCF_IPSBAR + 0x100032)
+#define MCFGPIO_PCLRR_BUSCTL (MCF_IPSBAR + 0x100033)
+#define MCFGPIO_PCLRR_BS (MCF_IPSBAR + 0x100034)
+#define MCFGPIO_PCLRR_CS (MCF_IPSBAR + 0x100035)
+#define MCFGPIO_PCLRR_SDRAM (MCF_IPSBAR + 0x100036)
+#define MCFGPIO_PCLRR_FECI2C (MCF_IPSBAR + 0x100037)
+#define MCFGPIO_PCLRR_UARTH (MCF_IPSBAR + 0x100038)
+#define MCFGPIO_PCLRR_UARTL (MCF_IPSBAR + 0x100039)
+#define MCFGPIO_PCLRR_QSPI (MCF_IPSBAR + 0x10003A)
+#define MCFGPIO_PCLRR_TIMER (MCF_IPSBAR + 0x10003B)
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PODR MCFGPIO_PODR_ADDR
+#define MCFGPIO_PDDR MCFGPIO_PDDR_ADDR
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_ADDR
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_ADDR
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_ADDR
+
+#define MCFGPIO_PIN_MAX 100
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+#endif
+
+#ifdef CONFIG_M5275
+#define MCFGPIO_PODR_BUSCTL (MCF_IPSBAR + 0x100004)
+#define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100005)
+#define MCFGPIO_PODR_CS (MCF_IPSBAR + 0x100008)
+#define MCFGPIO_PODR_FEC0H (MCF_IPSBAR + 0x10000A)
+#define MCFGPIO_PODR_FEC0L (MCF_IPSBAR + 0x10000B)
+#define MCFGPIO_PODR_FECI2C (MCF_IPSBAR + 0x10000C)
+#define MCFGPIO_PODR_QSPI (MCF_IPSBAR + 0x10000D)
+#define MCFGPIO_PODR_SDRAM (MCF_IPSBAR + 0x10000E)
+#define MCFGPIO_PODR_TIMERH (MCF_IPSBAR + 0x10000F)
+#define MCFGPIO_PODR_TIMERL (MCF_IPSBAR + 0x100010)
+#define MCFGPIO_PODR_UARTL (MCF_IPSBAR + 0x100011)
+#define MCFGPIO_PODR_FEC1H (MCF_IPSBAR + 0x100012)
+#define MCFGPIO_PODR_FEC1L (MCF_IPSBAR + 0x100013)
+#define MCFGPIO_PODR_BS (MCF_IPSBAR + 0x100014)
+#define MCFGPIO_PODR_IRQ (MCF_IPSBAR + 0x100015)
+#define MCFGPIO_PODR_USBH (MCF_IPSBAR + 0x100016)
+#define MCFGPIO_PODR_USBL (MCF_IPSBAR + 0x100017)
+#define MCFGPIO_PODR_UARTH (MCF_IPSBAR + 0x100018)
+
+#define MCFGPIO_PDDR_BUSCTL (MCF_IPSBAR + 0x100020)
+#define MCFGPIO_PDDR_ADDR (MCF_IPSBAR + 0x100021)
+#define MCFGPIO_PDDR_CS (MCF_IPSBAR + 0x100024)
+#define MCFGPIO_PDDR_FEC0H (MCF_IPSBAR + 0x100026)
+#define MCFGPIO_PDDR_FEC0L (MCF_IPSBAR + 0x100027)
+#define MCFGPIO_PDDR_FECI2C (MCF_IPSBAR + 0x100028)
+#define MCFGPIO_PDDR_QSPI (MCF_IPSBAR + 0x100029)
+#define MCFGPIO_PDDR_SDRAM (MCF_IPSBAR + 0x10002A)
+#define MCFGPIO_PDDR_TIMERH (MCF_IPSBAR + 0x10002B)
+#define MCFGPIO_PDDR_TIMERL (MCF_IPSBAR + 0x10002C)
+#define MCFGPIO_PDDR_UARTL (MCF_IPSBAR + 0x10002D)
+#define MCFGPIO_PDDR_FEC1H (MCF_IPSBAR + 0x10002E)
+#define MCFGPIO_PDDR_FEC1L (MCF_IPSBAR + 0x10002F)
+#define MCFGPIO_PDDR_BS (MCF_IPSBAR + 0x100030)
+#define MCFGPIO_PDDR_IRQ (MCF_IPSBAR + 0x100031)
+#define MCFGPIO_PDDR_USBH (MCF_IPSBAR + 0x100032)
+#define MCFGPIO_PDDR_USBL (MCF_IPSBAR + 0x100033)
+#define MCFGPIO_PDDR_UARTH (MCF_IPSBAR + 0x100034)
+
+#define MCFGPIO_PPDSDR_BUSCTL (MCF_IPSBAR + 0x10003C)
+#define MCFGPIO_PPDSDR_ADDR (MCF_IPSBAR + 0x10003D)
+#define MCFGPIO_PPDSDR_CS (MCF_IPSBAR + 0x100040)
+#define MCFGPIO_PPDSDR_FEC0H (MCF_IPSBAR + 0x100042)
+#define MCFGPIO_PPDSDR_FEC0L (MCF_IPSBAR + 0x100043)
+#define MCFGPIO_PPDSDR_FECI2C (MCF_IPSBAR + 0x100044)
+#define MCFGPIO_PPDSDR_QSPI (MCF_IPSBAR + 0x100045)
+#define MCFGPIO_PPDSDR_SDRAM (MCF_IPSBAR + 0x100046)
+#define MCFGPIO_PPDSDR_TIMERH (MCF_IPSBAR + 0x100047)
+#define MCFGPIO_PPDSDR_TIMERL (MCF_IPSBAR + 0x100048)
+#define MCFGPIO_PPDSDR_UARTL (MCF_IPSBAR + 0x100049)
+#define MCFGPIO_PPDSDR_FEC1H (MCF_IPSBAR + 0x10004A)
+#define MCFGPIO_PPDSDR_FEC1L (MCF_IPSBAR + 0x10004B)
+#define MCFGPIO_PPDSDR_BS (MCF_IPSBAR + 0x10004C)
+#define MCFGPIO_PPDSDR_IRQ (MCF_IPSBAR + 0x10004D)
+#define MCFGPIO_PPDSDR_USBH (MCF_IPSBAR + 0x10004E)
+#define MCFGPIO_PPDSDR_USBL (MCF_IPSBAR + 0x10004F)
+#define MCFGPIO_PPDSDR_UARTH (MCF_IPSBAR + 0x100050)
+
+#define MCFGPIO_PCLRR_BUSCTL (MCF_IPSBAR + 0x100058)
+#define MCFGPIO_PCLRR_ADDR (MCF_IPSBAR + 0x100059)
+#define MCFGPIO_PCLRR_CS (MCF_IPSBAR + 0x10005C)
+#define MCFGPIO_PCLRR_FEC0H (MCF_IPSBAR + 0x10005E)
+#define MCFGPIO_PCLRR_FEC0L (MCF_IPSBAR + 0x10005F)
+#define MCFGPIO_PCLRR_FECI2C (MCF_IPSBAR + 0x100060)
+#define MCFGPIO_PCLRR_QSPI (MCF_IPSBAR + 0x100061)
+#define MCFGPIO_PCLRR_SDRAM (MCF_IPSBAR + 0x100062)
+#define MCFGPIO_PCLRR_TIMERH (MCF_IPSBAR + 0x100063)
+#define MCFGPIO_PCLRR_TIMERL (MCF_IPSBAR + 0x100064)
+#define MCFGPIO_PCLRR_UARTL (MCF_IPSBAR + 0x100065)
+#define MCFGPIO_PCLRR_FEC1H (MCF_IPSBAR + 0x100066)
+#define MCFGPIO_PCLRR_FEC1L (MCF_IPSBAR + 0x100067)
+#define MCFGPIO_PCLRR_BS (MCF_IPSBAR + 0x100068)
+#define MCFGPIO_PCLRR_IRQ (MCF_IPSBAR + 0x100069)
+#define MCFGPIO_PCLRR_USBH (MCF_IPSBAR + 0x10006A)
+#define MCFGPIO_PCLRR_USBL (MCF_IPSBAR + 0x10006B)
+#define MCFGPIO_PCLRR_UARTH (MCF_IPSBAR + 0x10006C)
+
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PODR MCFGPIO_PODR_BUSCTL
+#define MCFGPIO_PDDR MCFGPIO_PDDR_BUSCTL
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_BUSCTL
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_BUSCTL
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_BUSCTL
+
+#define MCFGPIO_PIN_MAX 148
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+#endif
+
+/*
+ * EPort
+ */
+
+#define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002)
+#define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004)
+#define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005)
+
+
/*
* GPIO pins setups to enable the UARTs.
*/
diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h
index d79c49f8134a..e2ad1f42b657 100644
--- a/arch/m68k/include/asm/m528xsim.h
+++ b/arch/m68k/include/asm/m528xsim.h
@@ -41,6 +41,157 @@
#define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */
/*
+ * GPIO registers
+ */
+#define MCFGPIO_PORTA (MCF_IPSBAR + 0x00100000)
+#define MCFGPIO_PORTB (MCF_IPSBAR + 0x00100001)
+#define MCFGPIO_PORTC (MCF_IPSBAR + 0x00100002)
+#define MCFGPIO_PORTD (MCF_IPSBAR + 0x00100003)
+#define MCFGPIO_PORTE (MCF_IPSBAR + 0x00100004)
+#define MCFGPIO_PORTF (MCF_IPSBAR + 0x00100005)
+#define MCFGPIO_PORTG (MCF_IPSBAR + 0x00100006)
+#define MCFGPIO_PORTH (MCF_IPSBAR + 0x00100007)
+#define MCFGPIO_PORTJ (MCF_IPSBAR + 0x00100008)
+#define MCFGPIO_PORTDD (MCF_IPSBAR + 0x00100009)
+#define MCFGPIO_PORTEH (MCF_IPSBAR + 0x0010000A)
+#define MCFGPIO_PORTEL (MCF_IPSBAR + 0x0010000B)
+#define MCFGPIO_PORTAS (MCF_IPSBAR + 0x0010000C)
+#define MCFGPIO_PORTQS (MCF_IPSBAR + 0x0010000D)
+#define MCFGPIO_PORTSD (MCF_IPSBAR + 0x0010000E)
+#define MCFGPIO_PORTTC (MCF_IPSBAR + 0x0010000F)
+#define MCFGPIO_PORTTD (MCF_IPSBAR + 0x00100010)
+#define MCFGPIO_PORTUA (MCF_IPSBAR + 0x00100011)
+
+#define MCFGPIO_DDRA (MCF_IPSBAR + 0x00100014)
+#define MCFGPIO_DDRB (MCF_IPSBAR + 0x00100015)
+#define MCFGPIO_DDRC (MCF_IPSBAR + 0x00100016)
+#define MCFGPIO_DDRD (MCF_IPSBAR + 0x00100017)
+#define MCFGPIO_DDRE (MCF_IPSBAR + 0x00100018)
+#define MCFGPIO_DDRF (MCF_IPSBAR + 0x00100019)
+#define MCFGPIO_DDRG (MCF_IPSBAR + 0x0010001A)
+#define MCFGPIO_DDRH (MCF_IPSBAR + 0x0010001B)
+#define MCFGPIO_DDRJ (MCF_IPSBAR + 0x0010001C)
+#define MCFGPIO_DDRDD (MCF_IPSBAR + 0x0010001D)
+#define MCFGPIO_DDREH (MCF_IPSBAR + 0x0010001E)
+#define MCFGPIO_DDREL (MCF_IPSBAR + 0x0010001F)
+#define MCFGPIO_DDRAS (MCF_IPSBAR + 0x00100020)
+#define MCFGPIO_DDRQS (MCF_IPSBAR + 0x00100021)
+#define MCFGPIO_DDRSD (MCF_IPSBAR + 0x00100022)
+#define MCFGPIO_DDRTC (MCF_IPSBAR + 0x00100023)
+#define MCFGPIO_DDRTD (MCF_IPSBAR + 0x00100024)
+#define MCFGPIO_DDRUA (MCF_IPSBAR + 0x00100025)
+
+#define MCFGPIO_PORTAP (MCF_IPSBAR + 0x00100028)
+#define MCFGPIO_PORTBP (MCF_IPSBAR + 0x00100029)
+#define MCFGPIO_PORTCP (MCF_IPSBAR + 0x0010002A)
+#define MCFGPIO_PORTDP (MCF_IPSBAR + 0x0010002B)
+#define MCFGPIO_PORTEP (MCF_IPSBAR + 0x0010002C)
+#define MCFGPIO_PORTFP (MCF_IPSBAR + 0x0010002D)
+#define MCFGPIO_PORTGP (MCF_IPSBAR + 0x0010002E)
+#define MCFGPIO_PORTHP (MCF_IPSBAR + 0x0010002F)
+#define MCFGPIO_PORTJP (MCF_IPSBAR + 0x00100030)
+#define MCFGPIO_PORTDDP (MCF_IPSBAR + 0x00100031)
+#define MCFGPIO_PORTEHP (MCF_IPSBAR + 0x00100032)
+#define MCFGPIO_PORTELP (MCF_IPSBAR + 0x00100033)
+#define MCFGPIO_PORTASP (MCF_IPSBAR + 0x00100034)
+#define MCFGPIO_PORTQSP (MCF_IPSBAR + 0x00100035)
+#define MCFGPIO_PORTSDP (MCF_IPSBAR + 0x00100036)
+#define MCFGPIO_PORTTCP (MCF_IPSBAR + 0x00100037)
+#define MCFGPIO_PORTTDP (MCF_IPSBAR + 0x00100038)
+#define MCFGPIO_PORTUAP (MCF_IPSBAR + 0x00100039)
+
+#define MCFGPIO_SETA (MCF_IPSBAR + 0x00100028)
+#define MCFGPIO_SETB (MCF_IPSBAR + 0x00100029)
+#define MCFGPIO_SETC (MCF_IPSBAR + 0x0010002A)
+#define MCFGPIO_SETD (MCF_IPSBAR + 0x0010002B)
+#define MCFGPIO_SETE (MCF_IPSBAR + 0x0010002C)
+#define MCFGPIO_SETF (MCF_IPSBAR + 0x0010002D)
+#define MCFGPIO_SETG (MCF_IPSBAR + 0x0010002E)
+#define MCFGPIO_SETH (MCF_IPSBAR + 0x0010002F)
+#define MCFGPIO_SETJ (MCF_IPSBAR + 0x00100030)
+#define MCFGPIO_SETDD (MCF_IPSBAR + 0x00100031)
+#define MCFGPIO_SETEH (MCF_IPSBAR + 0x00100032)
+#define MCFGPIO_SETEL (MCF_IPSBAR + 0x00100033)
+#define MCFGPIO_SETAS (MCF_IPSBAR + 0x00100034)
+#define MCFGPIO_SETQS (MCF_IPSBAR + 0x00100035)
+#define MCFGPIO_SETSD (MCF_IPSBAR + 0x00100036)
+#define MCFGPIO_SETTC (MCF_IPSBAR + 0x00100037)
+#define MCFGPIO_SETTD (MCF_IPSBAR + 0x00100038)
+#define MCFGPIO_SETUA (MCF_IPSBAR + 0x00100039)
+
+#define MCFGPIO_CLRA (MCF_IPSBAR + 0x0010003C)
+#define MCFGPIO_CLRB (MCF_IPSBAR + 0x0010003D)
+#define MCFGPIO_CLRC (MCF_IPSBAR + 0x0010003E)
+#define MCFGPIO_CLRD (MCF_IPSBAR + 0x0010003F)
+#define MCFGPIO_CLRE (MCF_IPSBAR + 0x00100040)
+#define MCFGPIO_CLRF (MCF_IPSBAR + 0x00100041)
+#define MCFGPIO_CLRG (MCF_IPSBAR + 0x00100042)
+#define MCFGPIO_CLRH (MCF_IPSBAR + 0x00100043)
+#define MCFGPIO_CLRJ (MCF_IPSBAR + 0x00100044)
+#define MCFGPIO_CLRDD (MCF_IPSBAR + 0x00100045)
+#define MCFGPIO_CLREH (MCF_IPSBAR + 0x00100046)
+#define MCFGPIO_CLREL (MCF_IPSBAR + 0x00100047)
+#define MCFGPIO_CLRAS (MCF_IPSBAR + 0x00100048)
+#define MCFGPIO_CLRQS (MCF_IPSBAR + 0x00100049)
+#define MCFGPIO_CLRSD (MCF_IPSBAR + 0x0010004A)
+#define MCFGPIO_CLRTC (MCF_IPSBAR + 0x0010004B)
+#define MCFGPIO_CLRTD (MCF_IPSBAR + 0x0010004C)
+#define MCFGPIO_CLRUA (MCF_IPSBAR + 0x0010004D)
+
+#define MCFGPIO_PBCDPAR (MCF_IPSBAR + 0x00100050)
+#define MCFGPIO_PFPAR (MCF_IPSBAR + 0x00100051)
+#define MCFGPIO_PEPAR (MCF_IPSBAR + 0x00100052)
+#define MCFGPIO_PJPAR (MCF_IPSBAR + 0x00100054)
+#define MCFGPIO_PSDPAR (MCF_IPSBAR + 0x00100055)
+#define MCFGPIO_PASPAR (MCF_IPSBAR + 0x00100056)
+#define MCFGPIO_PEHLPAR (MCF_IPSBAR + 0x00100058)
+#define MCFGPIO_PQSPAR (MCF_IPSBAR + 0x00100059)
+#define MCFGPIO_PTCPAR (MCF_IPSBAR + 0x0010005A)
+#define MCFGPIO_PTDPAR (MCF_IPSBAR + 0x0010005B)
+#define MCFGPIO_PUAPAR (MCF_IPSBAR + 0x0010005C)
+
+/*
+ * Edge Port registers
+ */
+#define MCFEPORT_EPPAR (MCF_IPSBAR + 0x00130000)
+#define MCFEPORT_EPDDR (MCF_IPSBAR + 0x00130002)
+#define MCFEPORT_EPIER (MCF_IPSBAR + 0x00130003)
+#define MCFEPORT_EPDR (MCF_IPSBAR + 0x00130004)
+#define MCFEPORT_EPPDR (MCF_IPSBAR + 0x00130005)
+#define MCFEPORT_EPFR (MCF_IPSBAR + 0x00130006)
+
+/*
+ * Queued ADC registers
+ */
+#define MCFQADC_PORTQA (MCF_IPSBAR + 0x00190006)
+#define MCFQADC_PORTQB (MCF_IPSBAR + 0x00190007)
+#define MCFQADC_DDRQA (MCF_IPSBAR + 0x00190008)
+#define MCFQADC_DDRQB (MCF_IPSBAR + 0x00190009)
+
+/*
+ * General Purpose Timers registers
+ */
+#define MCFGPTA_GPTPORT (MCF_IPSBAR + 0x001A001D)
+#define MCFGPTA_GPTDDR (MCF_IPSBAR + 0x001A001E)
+#define MCFGPTB_GPTPORT (MCF_IPSBAR + 0x001B001D)
+#define MCFGPTB_GPTDDR (MCF_IPSBAR + 0x001B001E)
+/*
+ *
+ * definitions for generic gpio support
+ *
+ */
+#define MCFGPIO_PODR MCFGPIO_PORTA /* port output data */
+#define MCFGPIO_PDDR MCFGPIO_DDRA /* port data direction */
+#define MCFGPIO_PPDR MCFGPIO_PORTAP /* port pin data */
+#define MCFGPIO_SETR MCFGPIO_SETA /* set output */
+#define MCFGPIO_CLRR MCFGPIO_CLRA /* clr output */
+
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+#define MCFGPIO_PIN_MAX 180
+
+
+/*
* Derek Cheung - 6 Feb 2005
* add I2C and QSPI register definition using Freescale's MCF5282
*/
diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h
index 5886728409c0..c6830e5b54ce 100644
--- a/arch/m68k/include/asm/m5307sim.h
+++ b/arch/m68k/include/asm/m5307sim.h
@@ -90,8 +90,15 @@
#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */
#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */
-#define MCFSIM_PADDR 0x244 /* Parallel Direction (r/w) */
-#define MCFSIM_PADAT 0x248 /* Parallel Data (r/w) */
+#define MCFSIM_PADDR (MCF_MBAR + 0x244)
+#define MCFSIM_PADAT (MCF_MBAR + 0x248)
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX 16
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
/* Definition offset address for CS2-7 -- old mask 5307 */
@@ -117,22 +124,6 @@
#define MCFSIM_DMA2ICR MCFSIM_ICR8 /* DMA 2 ICR */
#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */
-#if defined(CONFIG_M5307)
-#define MCFSIM_IMR_MASKALL 0x3fffe /* All SIM intr sources */
-#endif
-
-/*
- * Macro to set IMR register. It is 32 bits on the 5307.
- */
-#define mcf_getimr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR))
-
-#define mcf_setimr(imr) \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr);
-
-#define mcf_getipr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR))
-
/*
* Some symbol defines for the Parallel Port Pin Assignment Register
@@ -149,6 +140,11 @@
#define IRQ3_LEVEL6 0x40
#define IRQ1_LEVEL2 0x20
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
+#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
/*
* Define the Cache register flags.
diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h
index eb7fd4448947..27388d38210b 100644
--- a/arch/m68k/include/asm/m532xsim.h
+++ b/arch/m68k/include/asm/m532xsim.h
@@ -56,47 +56,21 @@
#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */
-#define MCFSIM_IMR_MASKALL 0xFFFFFFFF /* All SIM intr sources */
-
-#define MCFSIM_IMR_SIMR0 0xFC04801C
-#define MCFSIM_IMR_SIMR1 0xFC04C01C
-#define MCFSIM_IMR_CIMR0 0xFC04801D
-#define MCFSIM_IMR_CIMR1 0xFC04C01D
+#define MCFINTC0_SIMR 0xFC04801C
+#define MCFINTC0_CIMR 0xFC04801D
+#define MCFINTC0_ICR0 0xFC048040
+#define MCFINTC1_SIMR 0xFC04C01C
+#define MCFINTC1_CIMR 0xFC04C01D
+#define MCFINTC1_ICR0 0xFC04C040
#define MCFSIM_ICR_TIMER1 (0xFC048040+32)
#define MCFSIM_ICR_TIMER2 (0xFC048040+33)
-
/*
- * Macro to set IMR register. It is 32 bits on the 5307.
+ * Define system peripheral IRQ usage.
*/
-#define mcf_getimr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR))
-
-#define mcf_setimr(imr) \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr);
-
-#define mcf_getipr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR))
-
-#define mcf_getiprl() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPRL))
-
-#define mcf_getiprh() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPRH))
-
-
-#define mcf_enable_irq0(irq) \
- *((volatile unsigned char*) (MCFSIM_IMR_CIMR0)) = (irq);
-
-#define mcf_enable_irq1(irq) \
- *((volatile unsigned char*) (MCFSIM_IMR_CIMR1)) = (irq);
-
-#define mcf_disable_irq0(irq) \
- *((volatile unsigned char*) (MCFSIM_IMR_SIMR0)) = (irq);
-
-#define mcf_disable_irq1(irq) \
- *((volatile unsigned char*) (MCFSIM_IMR_SIMR1)) = (irq);
+#define MCF_IRQ_TIMER (64 + 32) /* Timer0 */
+#define MCF_IRQ_PROFILER (64 + 33) /* Timer1 */
/*
* Define the Cache register flags.
@@ -422,70 +396,70 @@
*********************************************************************/
/* Register read/write macros */
-#define MCF_GPIO_PODR_FECH MCF_REG08(0xFC0A4000)
-#define MCF_GPIO_PODR_FECL MCF_REG08(0xFC0A4001)
-#define MCF_GPIO_PODR_SSI MCF_REG08(0xFC0A4002)
-#define MCF_GPIO_PODR_BUSCTL MCF_REG08(0xFC0A4003)
-#define MCF_GPIO_PODR_BE MCF_REG08(0xFC0A4004)
-#define MCF_GPIO_PODR_CS MCF_REG08(0xFC0A4005)
-#define MCF_GPIO_PODR_PWM MCF_REG08(0xFC0A4006)
-#define MCF_GPIO_PODR_FECI2C MCF_REG08(0xFC0A4007)
-#define MCF_GPIO_PODR_UART MCF_REG08(0xFC0A4009)
-#define MCF_GPIO_PODR_QSPI MCF_REG08(0xFC0A400A)
-#define MCF_GPIO_PODR_TIMER MCF_REG08(0xFC0A400B)
-#define MCF_GPIO_PODR_LCDDATAH MCF_REG08(0xFC0A400D)
-#define MCF_GPIO_PODR_LCDDATAM MCF_REG08(0xFC0A400E)
-#define MCF_GPIO_PODR_LCDDATAL MCF_REG08(0xFC0A400F)
-#define MCF_GPIO_PODR_LCDCTLH MCF_REG08(0xFC0A4010)
-#define MCF_GPIO_PODR_LCDCTLL MCF_REG08(0xFC0A4011)
-#define MCF_GPIO_PDDR_FECH MCF_REG08(0xFC0A4014)
-#define MCF_GPIO_PDDR_FECL MCF_REG08(0xFC0A4015)
-#define MCF_GPIO_PDDR_SSI MCF_REG08(0xFC0A4016)
-#define MCF_GPIO_PDDR_BUSCTL MCF_REG08(0xFC0A4017)
-#define MCF_GPIO_PDDR_BE MCF_REG08(0xFC0A4018)
-#define MCF_GPIO_PDDR_CS MCF_REG08(0xFC0A4019)
-#define MCF_GPIO_PDDR_PWM MCF_REG08(0xFC0A401A)
-#define MCF_GPIO_PDDR_FECI2C MCF_REG08(0xFC0A401B)
-#define MCF_GPIO_PDDR_UART MCF_REG08(0xFC0A401C)
-#define MCF_GPIO_PDDR_QSPI MCF_REG08(0xFC0A401E)
-#define MCF_GPIO_PDDR_TIMER MCF_REG08(0xFC0A401F)
-#define MCF_GPIO_PDDR_LCDDATAH MCF_REG08(0xFC0A4021)
-#define MCF_GPIO_PDDR_LCDDATAM MCF_REG08(0xFC0A4022)
-#define MCF_GPIO_PDDR_LCDDATAL MCF_REG08(0xFC0A4023)
-#define MCF_GPIO_PDDR_LCDCTLH MCF_REG08(0xFC0A4024)
-#define MCF_GPIO_PDDR_LCDCTLL MCF_REG08(0xFC0A4025)
-#define MCF_GPIO_PPDSDR_FECH MCF_REG08(0xFC0A4028)
-#define MCF_GPIO_PPDSDR_FECL MCF_REG08(0xFC0A4029)
-#define MCF_GPIO_PPDSDR_SSI MCF_REG08(0xFC0A402A)
-#define MCF_GPIO_PPDSDR_BUSCTL MCF_REG08(0xFC0A402B)
-#define MCF_GPIO_PPDSDR_BE MCF_REG08(0xFC0A402C)
-#define MCF_GPIO_PPDSDR_CS MCF_REG08(0xFC0A402D)
-#define MCF_GPIO_PPDSDR_PWM MCF_REG08(0xFC0A402E)
-#define MCF_GPIO_PPDSDR_FECI2C MCF_REG08(0xFC0A402F)
-#define MCF_GPIO_PPDSDR_UART MCF_REG08(0xFC0A4031)
-#define MCF_GPIO_PPDSDR_QSPI MCF_REG08(0xFC0A4032)
-#define MCF_GPIO_PPDSDR_TIMER MCF_REG08(0xFC0A4033)
-#define MCF_GPIO_PPDSDR_LCDDATAH MCF_REG08(0xFC0A4035)
-#define MCF_GPIO_PPDSDR_LCDDATAM MCF_REG08(0xFC0A4036)
-#define MCF_GPIO_PPDSDR_LCDDATAL MCF_REG08(0xFC0A4037)
-#define MCF_GPIO_PPDSDR_LCDCTLH MCF_REG08(0xFC0A4038)
-#define MCF_GPIO_PPDSDR_LCDCTLL MCF_REG08(0xFC0A4039)
-#define MCF_GPIO_PCLRR_FECH MCF_REG08(0xFC0A403C)
-#define MCF_GPIO_PCLRR_FECL MCF_REG08(0xFC0A403D)
-#define MCF_GPIO_PCLRR_SSI MCF_REG08(0xFC0A403E)
-#define MCF_GPIO_PCLRR_BUSCTL MCF_REG08(0xFC0A403F)
-#define MCF_GPIO_PCLRR_BE MCF_REG08(0xFC0A4040)
-#define MCF_GPIO_PCLRR_CS MCF_REG08(0xFC0A4041)
-#define MCF_GPIO_PCLRR_PWM MCF_REG08(0xFC0A4042)
-#define MCF_GPIO_PCLRR_FECI2C MCF_REG08(0xFC0A4043)
-#define MCF_GPIO_PCLRR_UART MCF_REG08(0xFC0A4045)
-#define MCF_GPIO_PCLRR_QSPI MCF_REG08(0xFC0A4046)
-#define MCF_GPIO_PCLRR_TIMER MCF_REG08(0xFC0A4047)
-#define MCF_GPIO_PCLRR_LCDDATAH MCF_REG08(0xFC0A4049)
-#define MCF_GPIO_PCLRR_LCDDATAM MCF_REG08(0xFC0A404A)
-#define MCF_GPIO_PCLRR_LCDDATAL MCF_REG08(0xFC0A404B)
-#define MCF_GPIO_PCLRR_LCDCTLH MCF_REG08(0xFC0A404C)
-#define MCF_GPIO_PCLRR_LCDCTLL MCF_REG08(0xFC0A404D)
+#define MCFGPIO_PODR_FECH (0xFC0A4000)
+#define MCFGPIO_PODR_FECL (0xFC0A4001)
+#define MCFGPIO_PODR_SSI (0xFC0A4002)
+#define MCFGPIO_PODR_BUSCTL (0xFC0A4003)
+#define MCFGPIO_PODR_BE (0xFC0A4004)
+#define MCFGPIO_PODR_CS (0xFC0A4005)
+#define MCFGPIO_PODR_PWM (0xFC0A4006)
+#define MCFGPIO_PODR_FECI2C (0xFC0A4007)
+#define MCFGPIO_PODR_UART (0xFC0A4009)
+#define MCFGPIO_PODR_QSPI (0xFC0A400A)
+#define MCFGPIO_PODR_TIMER (0xFC0A400B)
+#define MCFGPIO_PODR_LCDDATAH (0xFC0A400D)
+#define MCFGPIO_PODR_LCDDATAM (0xFC0A400E)
+#define MCFGPIO_PODR_LCDDATAL (0xFC0A400F)
+#define MCFGPIO_PODR_LCDCTLH (0xFC0A4010)
+#define MCFGPIO_PODR_LCDCTLL (0xFC0A4011)
+#define MCFGPIO_PDDR_FECH (0xFC0A4014)
+#define MCFGPIO_PDDR_FECL (0xFC0A4015)
+#define MCFGPIO_PDDR_SSI (0xFC0A4016)
+#define MCFGPIO_PDDR_BUSCTL (0xFC0A4017)
+#define MCFGPIO_PDDR_BE (0xFC0A4018)
+#define MCFGPIO_PDDR_CS (0xFC0A4019)
+#define MCFGPIO_PDDR_PWM (0xFC0A401A)
+#define MCFGPIO_PDDR_FECI2C (0xFC0A401B)
+#define MCFGPIO_PDDR_UART (0xFC0A401C)
+#define MCFGPIO_PDDR_QSPI (0xFC0A401E)
+#define MCFGPIO_PDDR_TIMER (0xFC0A401F)
+#define MCFGPIO_PDDR_LCDDATAH (0xFC0A4021)
+#define MCFGPIO_PDDR_LCDDATAM (0xFC0A4022)
+#define MCFGPIO_PDDR_LCDDATAL (0xFC0A4023)
+#define MCFGPIO_PDDR_LCDCTLH (0xFC0A4024)
+#define MCFGPIO_PDDR_LCDCTLL (0xFC0A4025)
+#define MCFGPIO_PPDSDR_FECH (0xFC0A4028)
+#define MCFGPIO_PPDSDR_FECL (0xFC0A4029)
+#define MCFGPIO_PPDSDR_SSI (0xFC0A402A)
+#define MCFGPIO_PPDSDR_BUSCTL (0xFC0A402B)
+#define MCFGPIO_PPDSDR_BE (0xFC0A402C)
+#define MCFGPIO_PPDSDR_CS (0xFC0A402D)
+#define MCFGPIO_PPDSDR_PWM (0xFC0A402E)
+#define MCFGPIO_PPDSDR_FECI2C (0xFC0A402F)
+#define MCFGPIO_PPDSDR_UART (0xFC0A4031)
+#define MCFGPIO_PPDSDR_QSPI (0xFC0A4032)
+#define MCFGPIO_PPDSDR_TIMER (0xFC0A4033)
+#define MCFGPIO_PPDSDR_LCDDATAH (0xFC0A4035)
+#define MCFGPIO_PPDSDR_LCDDATAM (0xFC0A4036)
+#define MCFGPIO_PPDSDR_LCDDATAL (0xFC0A4037)
+#define MCFGPIO_PPDSDR_LCDCTLH (0xFC0A4038)
+#define MCFGPIO_PPDSDR_LCDCTLL (0xFC0A4039)
+#define MCFGPIO_PCLRR_FECH (0xFC0A403C)
+#define MCFGPIO_PCLRR_FECL (0xFC0A403D)
+#define MCFGPIO_PCLRR_SSI (0xFC0A403E)
+#define MCFGPIO_PCLRR_BUSCTL (0xFC0A403F)
+#define MCFGPIO_PCLRR_BE (0xFC0A4040)
+#define MCFGPIO_PCLRR_CS (0xFC0A4041)
+#define MCFGPIO_PCLRR_PWM (0xFC0A4042)
+#define MCFGPIO_PCLRR_FECI2C (0xFC0A4043)
+#define MCFGPIO_PCLRR_UART (0xFC0A4045)
+#define MCFGPIO_PCLRR_QSPI (0xFC0A4046)
+#define MCFGPIO_PCLRR_TIMER (0xFC0A4047)
+#define MCFGPIO_PCLRR_LCDDATAH (0xFC0A4049)
+#define MCFGPIO_PCLRR_LCDDATAM (0xFC0A404A)
+#define MCFGPIO_PCLRR_LCDDATAL (0xFC0A404B)
+#define MCFGPIO_PCLRR_LCDCTLH (0xFC0A404C)
+#define MCFGPIO_PCLRR_LCDCTLL (0xFC0A404D)
#define MCF_GPIO_PAR_FEC MCF_REG08(0xFC0A4050)
#define MCF_GPIO_PAR_PWM MCF_REG08(0xFC0A4051)
#define MCF_GPIO_PAR_BUSCTL MCF_REG08(0xFC0A4052)
@@ -1187,6 +1161,20 @@
/* Bit definitions and macros for MCF_GPIO_DSCR_IRQ */
#define MCF_GPIO_DSCR_IRQ_IRQ_DSE(x) (((x)&0x03)<<0)
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PODR MCFGPIO_PODR_FECH
+#define MCFGPIO_PDDR MCFGPIO_PDDR_FECH
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_FECH
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_FECH
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_FECH
+
+#define MCFGPIO_PIN_MAX 136
+#define MCFGPIO_IRQ_MAX 8
+#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
+
+
/*********************************************************************
*
* Interrupt Controller (INTC)
@@ -2154,12 +2142,12 @@
*********************************************************************/
/* Register read/write macros */
-#define MCF_EPORT_EPPAR MCF_REG16(0xFC094000)
-#define MCF_EPORT_EPDDR MCF_REG08(0xFC094002)
-#define MCF_EPORT_EPIER MCF_REG08(0xFC094003)
-#define MCF_EPORT_EPDR MCF_REG08(0xFC094004)
-#define MCF_EPORT_EPPDR MCF_REG08(0xFC094005)
-#define MCF_EPORT_EPFR MCF_REG08(0xFC094006)
+#define MCFEPORT_EPPAR (0xFC094000)
+#define MCFEPORT_EPDDR (0xFC094002)
+#define MCFEPORT_EPIER (0xFC094003)
+#define MCFEPORT_EPDR (0xFC094004)
+#define MCFEPORT_EPPDR (0xFC094005)
+#define MCFEPORT_EPFR (0xFC094006)
/* Bit definitions and macros for MCF_EPORT_EPPAR */
#define MCF_EPORT_EPPAR_EPPA1(x) (((x)&0x0003)<<2)
diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h
index cc22c4a53005..c399abbf953c 100644
--- a/arch/m68k/include/asm/m5407sim.h
+++ b/arch/m68k/include/asm/m5407sim.h
@@ -73,9 +73,15 @@
#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */
#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */
-#define MCFSIM_PADDR 0x244 /* Parallel Direction (r/w) */
-#define MCFSIM_PADAT 0x248 /* Parallel Data (r/w) */
+#define MCFSIM_PADDR (MCF_MBAR + 0x244)
+#define MCFSIM_PADAT (MCF_MBAR + 0x248)
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX 16
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
/*
* Some symbol defines for the above...
@@ -91,19 +97,6 @@
#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */
/*
- * Macro to set IMR register. It is 32 bits on the 5407.
- */
-#define mcf_getimr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR))
-
-#define mcf_setimr(imr) \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr);
-
-#define mcf_getipr() \
- *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR))
-
-
-/*
* Some symbol defines for the Parallel Port Pin Assignment Register
*/
#define MCFSIM_PAR_DREQ0 0x40 /* Set to select DREQ0 input */
@@ -118,6 +111,11 @@
#define IRQ3_LEVEL6 0x40
#define IRQ1_LEVEL2 0x20
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
+#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
/*
* Define the Cache register flags.
diff --git a/arch/m68k/include/asm/mcfgpio.h b/arch/m68k/include/asm/mcfgpio.h
new file mode 100644
index 000000000000..ee5e4ccce89e
--- /dev/null
+++ b/arch/m68k/include/asm/mcfgpio.h
@@ -0,0 +1,40 @@
+/*
+ * Coldfire generic GPIO support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 mcfgpio_h
+#define mcfgpio_h
+
+#include <linux/io.h>
+#include <asm-generic/gpio.h>
+
+struct mcf_gpio_chip {
+ struct gpio_chip gpio_chip;
+ void __iomem *pddr;
+ void __iomem *podr;
+ void __iomem *ppdr;
+ void __iomem *setr;
+ void __iomem *clrr;
+ const u8 *gpio_to_pinmux;
+};
+
+int mcf_gpio_direction_input(struct gpio_chip *, unsigned);
+int mcf_gpio_get_value(struct gpio_chip *, unsigned);
+int mcf_gpio_direction_output(struct gpio_chip *, unsigned, int);
+void mcf_gpio_set_value(struct gpio_chip *, unsigned, int);
+void mcf_gpio_set_value_fast(struct gpio_chip *, unsigned, int);
+int mcf_gpio_request(struct gpio_chip *, unsigned);
+void mcf_gpio_free(struct gpio_chip *, unsigned);
+
+#endif
diff --git a/arch/m68k/include/asm/mcfintc.h b/arch/m68k/include/asm/mcfintc.h
new file mode 100644
index 000000000000..4183320a3813
--- /dev/null
+++ b/arch/m68k/include/asm/mcfintc.h
@@ -0,0 +1,89 @@
+/****************************************************************************/
+
+/*
+ * mcfintc.h -- support definitions for the simple ColdFire
+ * Interrupt Controller
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@uclinux.org>
+ */
+
+/****************************************************************************/
+#ifndef mcfintc_h
+#define mcfintc_h
+/****************************************************************************/
+
+/*
+ * Most of the older ColdFire parts use the same simple interrupt
+ * controller. This is currently used on the 5206, 5206e, 5249, 5307
+ * and 5407 parts.
+ *
+ * The builtin peripherals are masked through dedicated bits in the
+ * Interrupt Mask register (IMR) - and this is not indexed (or in any way
+ * related to) the actual interrupt number they use. So knowing the IRQ
+ * number doesn't explicitly map to a certain internal device for
+ * interrupt control purposes.
+ */
+
+/*
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_AUTOVEC 0x80 /* Auto-vectored intr */
+#define MCFSIM_ICR_LEVEL0 0x00 /* Level 0 intr */
+#define MCFSIM_ICR_LEVEL1 0x04 /* Level 1 intr */
+#define MCFSIM_ICR_LEVEL2 0x08 /* Level 2 intr */
+#define MCFSIM_ICR_LEVEL3 0x0c /* Level 3 intr */
+#define MCFSIM_ICR_LEVEL4 0x10 /* Level 4 intr */
+#define MCFSIM_ICR_LEVEL5 0x14 /* Level 5 intr */
+#define MCFSIM_ICR_LEVEL6 0x18 /* Level 6 intr */
+#define MCFSIM_ICR_LEVEL7 0x1c /* Level 7 intr */
+
+#define MCFSIM_ICR_PRI0 0x00 /* Priority 0 intr */
+#define MCFSIM_ICR_PRI1 0x01 /* Priority 1 intr */
+#define MCFSIM_ICR_PRI2 0x02 /* Priority 2 intr */
+#define MCFSIM_ICR_PRI3 0x03 /* Priority 3 intr */
+
+/*
+ * IMR bit position definitions. Not all ColdFire parts with this interrupt
+ * controller actually support all of these interrupt sources. But the bit
+ * numbers are the same in all cores.
+ */
+#define MCFINTC_EINT1 1 /* External int #1 */
+#define MCFINTC_EINT2 2 /* External int #2 */
+#define MCFINTC_EINT3 3 /* External int #3 */
+#define MCFINTC_EINT4 4 /* External int #4 */
+#define MCFINTC_EINT5 5 /* External int #5 */
+#define MCFINTC_EINT6 6 /* External int #6 */
+#define MCFINTC_EINT7 7 /* External int #7 */
+#define MCFINTC_SWT 8 /* Software Watchdog */
+#define MCFINTC_TIMER1 9
+#define MCFINTC_TIMER2 10
+#define MCFINTC_I2C 11 /* I2C / MBUS */
+#define MCFINTC_UART0 12
+#define MCFINTC_UART1 13
+#define MCFINTC_DMA0 14
+#define MCFINTC_DMA1 15
+#define MCFINTC_DMA2 16
+#define MCFINTC_DMA3 17
+#define MCFINTC_QSPI 18
+
+#ifndef __ASSEMBLER__
+
+/*
+ * There is no one-is-one correspondance between the interrupt number (irq)
+ * and the bit fields on the mask register. So we create a per-cpu type
+ * mapping of irq to mask bit. The CPU platform code needs to register
+ * its supported irq's at init time, using this function.
+ */
+extern unsigned char mcf_irq2imr[];
+static inline void mcf_mapirq2imr(int irq, int imr)
+{
+ mcf_irq2imr[irq] = imr;
+}
+
+void mcf_autovector(int irq);
+void mcf_setimr(int index);
+void mcf_clrimr(int index);
+#endif
+
+/****************************************************************************/
+#endif /* mcfintc_h */
diff --git a/arch/m68k/include/asm/mcfsim.h b/arch/m68k/include/asm/mcfsim.h
index da3f2ceff3a4..bf621467f35d 100644
--- a/arch/m68k/include/asm/mcfsim.h
+++ b/arch/m68k/include/asm/mcfsim.h
@@ -12,19 +12,21 @@
#define mcfsim_h
/****************************************************************************/
-
/*
- * Include 5204, 5206/e, 5235, 5249, 5270/5271, 5272, 5280/5282,
- * 5307 or 5407 specific addresses.
+ * Include the appropriate ColdFire CPU specific System Integration Module
+ * (SIM) definitions.
*/
#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
#include <asm/m5206sim.h>
+#include <asm/mcfintc.h>
#elif defined(CONFIG_M520x)
#include <asm/m520xsim.h>
#elif defined(CONFIG_M523x)
#include <asm/m523xsim.h>
+#include <asm/mcfintc.h>
#elif defined(CONFIG_M5249)
#include <asm/m5249sim.h>
+#include <asm/mcfintc.h>
#elif defined(CONFIG_M527x)
#include <asm/m527xsim.h>
#elif defined(CONFIG_M5272)
@@ -33,94 +35,13 @@
#include <asm/m528xsim.h>
#elif defined(CONFIG_M5307)
#include <asm/m5307sim.h>
+#include <asm/mcfintc.h>
#elif defined(CONFIG_M532x)
#include <asm/m532xsim.h>
#elif defined(CONFIG_M5407)
#include <asm/m5407sim.h>
+#include <asm/mcfintc.h>
#endif
-
-/*
- * Define the base address of the SIM within the MBAR address space.
- */
-#define MCFSIM_BASE 0x0 /* Base address of SIM */
-
-
-/*
- * Bit definitions for the ICR family of registers.
- */
-#define MCFSIM_ICR_AUTOVEC 0x80 /* Auto-vectored intr */
-#define MCFSIM_ICR_LEVEL0 0x00 /* Level 0 intr */
-#define MCFSIM_ICR_LEVEL1 0x04 /* Level 1 intr */
-#define MCFSIM_ICR_LEVEL2 0x08 /* Level 2 intr */
-#define MCFSIM_ICR_LEVEL3 0x0c /* Level 3 intr */
-#define MCFSIM_ICR_LEVEL4 0x10 /* Level 4 intr */
-#define MCFSIM_ICR_LEVEL5 0x14 /* Level 5 intr */
-#define MCFSIM_ICR_LEVEL6 0x18 /* Level 6 intr */
-#define MCFSIM_ICR_LEVEL7 0x1c /* Level 7 intr */
-
-#define MCFSIM_ICR_PRI0 0x00 /* Priority 0 intr */
-#define MCFSIM_ICR_PRI1 0x01 /* Priority 1 intr */
-#define MCFSIM_ICR_PRI2 0x02 /* Priority 2 intr */
-#define MCFSIM_ICR_PRI3 0x03 /* Priority 3 intr */
-
-/*
- * Bit definitions for the Interrupt Mask register (IMR).
- */
-#define MCFSIM_IMR_EINT1 0x0002 /* External intr # 1 */
-#define MCFSIM_IMR_EINT2 0x0004 /* External intr # 2 */
-#define MCFSIM_IMR_EINT3 0x0008 /* External intr # 3 */
-#define MCFSIM_IMR_EINT4 0x0010 /* External intr # 4 */
-#define MCFSIM_IMR_EINT5 0x0020 /* External intr # 5 */
-#define MCFSIM_IMR_EINT6 0x0040 /* External intr # 6 */
-#define MCFSIM_IMR_EINT7 0x0080 /* External intr # 7 */
-
-#define MCFSIM_IMR_SWD 0x0100 /* Software Watchdog intr */
-#define MCFSIM_IMR_TIMER1 0x0200 /* TIMER 1 intr */
-#define MCFSIM_IMR_TIMER2 0x0400 /* TIMER 2 intr */
-#define MCFSIM_IMR_MBUS 0x0800 /* MBUS intr */
-#define MCFSIM_IMR_UART1 0x1000 /* UART 1 intr */
-#define MCFSIM_IMR_UART2 0x2000 /* UART 2 intr */
-
-#if defined(CONFIG_M5206e)
-#define MCFSIM_IMR_DMA1 0x4000 /* DMA 1 intr */
-#define MCFSIM_IMR_DMA2 0x8000 /* DMA 2 intr */
-#elif defined(CONFIG_M5249) || defined(CONFIG_M5307)
-#define MCFSIM_IMR_DMA0 0x4000 /* DMA 0 intr */
-#define MCFSIM_IMR_DMA1 0x8000 /* DMA 1 intr */
-#define MCFSIM_IMR_DMA2 0x10000 /* DMA 2 intr */
-#define MCFSIM_IMR_DMA3 0x20000 /* DMA 3 intr */
-#endif
-
-/*
- * Mask for all of the SIM devices. Some parts have more or less
- * SIM devices. This is a catchall for the sandard set.
- */
-#ifndef MCFSIM_IMR_MASKALL
-#define MCFSIM_IMR_MASKALL 0x3ffe /* All intr sources */
-#endif
-
-
-/*
- * PIT interrupt settings, if not found in mXXXXsim.h file.
- */
-#ifndef ICR_INTRCONF
-#define ICR_INTRCONF 0x2b /* PIT1 level 5, priority 3 */
-#endif
-#ifndef MCFPIT_IMR
-#define MCFPIT_IMR MCFINTC_IMRH
-#endif
-#ifndef MCFPIT_IMR_IBIT
-#define MCFPIT_IMR_IBIT (1 << (MCFINT_PIT1 - 32))
-#endif
-
-
-#ifndef __ASSEMBLY__
-/*
- * Definition for the interrupt auto-vectoring support.
- */
-extern void mcf_autovector(unsigned int vec);
-#endif /* __ASSEMBLY__ */
-
/****************************************************************************/
#endif /* mcfsim_h */
diff --git a/arch/m68k/include/asm/mcfsmc.h b/arch/m68k/include/asm/mcfsmc.h
index 2d7a4dbd9683..527bea5d6788 100644
--- a/arch/m68k/include/asm/mcfsmc.h
+++ b/arch/m68k/include/asm/mcfsmc.h
@@ -167,15 +167,15 @@ void smc_remap(unsigned int ioaddr)
static int once = 0;
extern unsigned short ppdata;
if (once++ == 0) {
- *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADDR)) = 0x00ec;
+ *((volatile unsigned short *)MCFSIM_PADDR) = 0x00ec;
ppdata |= 0x0080;
- *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADAT)) = ppdata;
+ *((volatile unsigned short *)MCFSIM_PADAT) = ppdata;
outw(0x0001, ioaddr + BANK_SELECT);
outw(0x0001, ioaddr + BANK_SELECT);
outw(0x0067, ioaddr + BASE);
ppdata &= ~0x0080;
- *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADAT)) = ppdata;
+ *((volatile unsigned short *)MCFSIM_PADAT) = ppdata;
}
*((volatile unsigned short *)(MCF_MBAR+MCFSIM_CSCR3)) = 0x1180;
diff --git a/arch/m68k/include/asm/motorola_pgalloc.h b/arch/m68k/include/asm/motorola_pgalloc.h
index d08bf6261df8..15ee4c74a9f0 100644
--- a/arch/m68k/include/asm/motorola_pgalloc.h
+++ b/arch/m68k/include/asm/motorola_pgalloc.h
@@ -54,7 +54,8 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t page)
__free_page(page);
}
-static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page)
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
+ unsigned long address)
{
pgtable_page_dtor(page);
cache_page(kmap(page));
@@ -73,7 +74,8 @@ static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
return free_pointer_table(pmd);
}
-static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+ unsigned long address)
{
return free_pointer_table(pmd);
}
diff --git a/arch/m68k/include/asm/nettel.h b/arch/m68k/include/asm/nettel.h
index 0299f6a2deeb..4dec2d9fb994 100644
--- a/arch/m68k/include/asm/nettel.h
+++ b/arch/m68k/include/asm/nettel.h
@@ -48,14 +48,14 @@ extern volatile unsigned short ppdata;
static __inline__ unsigned int mcf_getppdata(void)
{
volatile unsigned short *pp;
- pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT);
+ pp = (volatile unsigned short *) MCFSIM_PADAT;
return((unsigned int) *pp);
}
static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits)
{
volatile unsigned short *pp;
- pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT);
+ pp = (volatile unsigned short *) MCFSIM_PADAT;
ppdata = (ppdata & ~mask) | bits;
*pp = ppdata;
}
diff --git a/arch/m68k/include/asm/pinmux.h b/arch/m68k/include/asm/pinmux.h
new file mode 100644
index 000000000000..119ee686dbd1
--- /dev/null
+++ b/arch/m68k/include/asm/pinmux.h
@@ -0,0 +1,30 @@
+/*
+ * Coldfire generic GPIO pinmux support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 pinmux_h
+#define pinmux_h
+
+#define MCFPINMUX_NONE -1
+
+extern int mcf_pinmux_request(unsigned, unsigned);
+extern void mcf_pinmux_release(unsigned, unsigned);
+
+static inline int mcf_pinmux_is_valid(unsigned pinmux)
+{
+ return pinmux != MCFPINMUX_NONE;
+}
+
+#endif
+
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index fc3f2c22f2b8..74fd674b15ad 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -1,5 +1,170 @@
-#ifdef __uClinux__
-#include "processor_no.h"
+/*
+ * include/asm-m68k/processor.h
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#ifndef __ASM_M68K_PROCESSOR_H
+#define __ASM_M68K_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#include <linux/thread_info.h>
+#include <asm/segment.h>
+#include <asm/fpu.h>
+#include <asm/ptrace.h>
+
+static inline unsigned long rdusp(void)
+{
+#ifdef CONFIG_COLDFIRE
+ extern unsigned int sw_usp;
+ return sw_usp;
#else
-#include "processor_mm.h"
+ unsigned long usp;
+ __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
+ return usp;
+#endif
+}
+
+static inline void wrusp(unsigned long usp)
+{
+#ifdef CONFIG_COLDFIRE
+ extern unsigned int sw_usp;
+ sw_usp = usp;
+#else
+ __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
+#endif
+}
+
+/*
+ * User space process size: 3.75GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
+#ifndef CONFIG_SUN3
+#define TASK_SIZE (0xF0000000UL)
+#else
+#define TASK_SIZE (0x0E000000UL)
+#endif
+
+#ifdef __KERNEL__
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
+#endif
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#ifdef CONFIG_MMU
+#ifndef CONFIG_SUN3
+#define TASK_UNMAPPED_BASE 0xC0000000UL
+#else
+#define TASK_UNMAPPED_BASE 0x0A000000UL
+#endif
+#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
+#else
+#define TASK_UNMAPPED_BASE 0
+#endif
+
+struct thread_struct {
+ unsigned long ksp; /* kernel stack pointer */
+ unsigned long usp; /* user stack pointer */
+ unsigned short sr; /* saved status register */
+ unsigned short fs; /* saved fs (sfc, dfc) */
+ unsigned long crp[2]; /* cpu root pointer */
+ unsigned long esp0; /* points to SR of stack frame */
+ unsigned long faddr; /* info about last fault */
+ int signo, code;
+ unsigned long fp[8*3];
+ unsigned long fpcntl[3]; /* fp control regs */
+ unsigned char fpstate[FPSTATESIZE]; /* floating point state */
+ struct thread_info info;
+};
+
+#define INIT_THREAD { \
+ .ksp = sizeof(init_stack) + (unsigned long) init_stack, \
+ .sr = PS_S, \
+ .fs = __KERNEL_DS, \
+ .info = INIT_THREAD_INFO(init_task), \
+}
+
+#ifdef CONFIG_MMU
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+static inline void start_thread(struct pt_regs * regs, unsigned long pc,
+ unsigned long usp)
+{
+ /* reads from user space */
+ set_fs(USER_DS);
+
+ regs->pc = pc;
+ regs->sr &= ~0x2000;
+ wrusp(usp);
+}
+
+#else
+
+/*
+ * Coldfire stacks need to be re-aligned on trap exit, conventional
+ * 68k can handle this case cleanly.
+ */
+#ifdef CONFIG_COLDFIRE
+#define reformat(_regs) do { (_regs)->format = 0x4; } while(0)
+#else
+#define reformat(_regs) do { } while (0)
+#endif
+
+#define start_thread(_regs, _pc, _usp) \
+do { \
+ set_fs(USER_DS); /* reads from user space */ \
+ (_regs)->pc = (_pc); \
+ ((struct switch_stack *)(_regs))[-1].a6 = 0; \
+ reformat(_regs); \
+ if (current->mm) \
+ (_regs)->d5 = current->mm->start_data; \
+ (_regs)->sr &= ~0x2000; \
+ wrusp(_usp); \
+} while(0)
+
+#endif
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk) do { } while (0)
+
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
+
+extern unsigned long thread_saved_pc(struct task_struct *tsk);
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk) \
+ ({ \
+ unsigned long eip = 0; \
+ if ((tsk)->thread.esp0 > PAGE_SIZE && \
+ (virt_addr_valid((tsk)->thread.esp0))) \
+ eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
+ eip; })
+#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
+
+#define cpu_relax() barrier()
+
#endif
diff --git a/arch/m68k/include/asm/processor_mm.h b/arch/m68k/include/asm/processor_mm.h
deleted file mode 100644
index 1f61ef53f0e0..000000000000
--- a/arch/m68k/include/asm/processor_mm.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * include/asm-m68k/processor.h
- *
- * Copyright (C) 1995 Hamish Macdonald
- */
-
-#ifndef __ASM_M68K_PROCESSOR_H
-#define __ASM_M68K_PROCESSOR_H
-
-/*
- * Default implementation of macro that returns current
- * instruction pointer ("program counter").
- */
-#define current_text_addr() ({ __label__ _l; _l: &&_l;})
-
-#include <linux/thread_info.h>
-#include <asm/segment.h>
-#include <asm/fpu.h>
-#include <asm/ptrace.h>
-
-static inline unsigned long rdusp(void)
-{
- unsigned long usp;
-
- __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
- return usp;
-}
-
-static inline void wrusp(unsigned long usp)
-{
- __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
-}
-
-/*
- * User space process size: 3.75GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- */
-#ifndef CONFIG_SUN3
-#define TASK_SIZE (0xF0000000UL)
-#else
-#define TASK_SIZE (0x0E000000UL)
-#endif
-
-#ifdef __KERNEL__
-#define STACK_TOP TASK_SIZE
-#define STACK_TOP_MAX STACK_TOP
-#endif
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#ifndef CONFIG_SUN3
-#define TASK_UNMAPPED_BASE 0xC0000000UL
-#else
-#define TASK_UNMAPPED_BASE 0x0A000000UL
-#endif
-#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
-
-struct thread_struct {
- unsigned long ksp; /* kernel stack pointer */
- unsigned long usp; /* user stack pointer */
- unsigned short sr; /* saved status register */
- unsigned short fs; /* saved fs (sfc, dfc) */
- unsigned long crp[2]; /* cpu root pointer */
- unsigned long esp0; /* points to SR of stack frame */
- unsigned long faddr; /* info about last fault */
- int signo, code;
- unsigned long fp[8*3];
- unsigned long fpcntl[3]; /* fp control regs */
- unsigned char fpstate[FPSTATESIZE]; /* floating point state */
- struct thread_info info;
-};
-
-#define INIT_THREAD { \
- .ksp = sizeof(init_stack) + (unsigned long) init_stack, \
- .sr = PS_S, \
- .fs = __KERNEL_DS, \
- .info = INIT_THREAD_INFO(init_task), \
-}
-
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-static inline void start_thread(struct pt_regs * regs, unsigned long pc,
- unsigned long usp)
-{
- /* reads from user space */
- set_fs(USER_DS);
-
- regs->pc = pc;
- regs->sr &= ~0x2000;
- wrusp(usp);
-}
-
-/* Forward declaration, a strange C thing */
-struct task_struct;
-
-/* Free all resources held by a thread. */
-static inline void release_thread(struct task_struct *dead_task)
-{
-}
-
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
-/*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
-extern unsigned long thread_saved_pc(struct task_struct *tsk);
-
-unsigned long get_wchan(struct task_struct *p);
-
-#define KSTK_EIP(tsk) \
- ({ \
- unsigned long eip = 0; \
- if ((tsk)->thread.esp0 > PAGE_SIZE && \
- (virt_addr_valid((tsk)->thread.esp0))) \
- eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
- eip; })
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-
-#define cpu_relax() barrier()
-
-#endif
diff --git a/arch/m68k/include/asm/processor_no.h b/arch/m68k/include/asm/processor_no.h
deleted file mode 100644
index 7a1e0ba35f5a..000000000000
--- a/arch/m68k/include/asm/processor_no.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * include/asm-m68knommu/processor.h
- *
- * Copyright (C) 1995 Hamish Macdonald
- */
-
-#ifndef __ASM_M68K_PROCESSOR_H
-#define __ASM_M68K_PROCESSOR_H
-
-/*
- * Default implementation of macro that returns current
- * instruction pointer ("program counter").
- */
-#define current_text_addr() ({ __label__ _l; _l: &&_l;})
-
-#include <linux/compiler.h>
-#include <linux/threads.h>
-#include <asm/types.h>
-#include <asm/segment.h>
-#include <asm/fpu.h>
-#include <asm/ptrace.h>
-#include <asm/current.h>
-
-static inline unsigned long rdusp(void)
-{
-#ifdef CONFIG_COLDFIRE
- extern unsigned int sw_usp;
- return(sw_usp);
-#else
- unsigned long usp;
- __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
- return usp;
-#endif
-}
-
-static inline void wrusp(unsigned long usp)
-{
-#ifdef CONFIG_COLDFIRE
- extern unsigned int sw_usp;
- sw_usp = usp;
-#else
- __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
-#endif
-}
-
-/*
- * User space process size: 3.75GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- */
-#define TASK_SIZE (0xF0000000UL)
-
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's. We won't be using it
- */
-#define TASK_UNMAPPED_BASE 0
-
-/*
- * if you change this structure, you must change the code and offsets
- * in m68k/machasm.S
- */
-
-struct thread_struct {
- unsigned long ksp; /* kernel stack pointer */
- unsigned long usp; /* user stack pointer */
- unsigned short sr; /* saved status register */
- unsigned short fs; /* saved fs (sfc, dfc) */
- unsigned long crp[2]; /* cpu root pointer */
- unsigned long esp0; /* points to SR of stack frame */
- unsigned long fp[8*3];
- unsigned long fpcntl[3]; /* fp control regs */
- unsigned char fpstate[FPSTATESIZE]; /* floating point state */
-};
-
-#define INIT_THREAD { \
- .ksp = sizeof(init_stack) + (unsigned long) init_stack, \
- .sr = PS_S, \
- .fs = __KERNEL_DS, \
-}
-
-/*
- * Coldfire stacks need to be re-aligned on trap exit, conventional
- * 68k can handle this case cleanly.
- */
-#if defined(CONFIG_COLDFIRE)
-#define reformat(_regs) do { (_regs)->format = 0x4; } while(0)
-#else
-#define reformat(_regs) do { } while (0)
-#endif
-
-/*
- * Do necessary setup to start up a newly executed thread.
- *
- * pass the data segment into user programs if it exists,
- * it can't hurt anything as far as I can tell
- */
-#define start_thread(_regs, _pc, _usp) \
-do { \
- set_fs(USER_DS); /* reads from user space */ \
- (_regs)->pc = (_pc); \
- ((struct switch_stack *)(_regs))[-1].a6 = 0; \
- reformat(_regs); \
- if (current->mm) \
- (_regs)->d5 = current->mm->start_data; \
- (_regs)->sr &= ~0x2000; \
- wrusp(_usp); \
-} while(0)
-
-/* Forward declaration, a strange C thing */
-struct task_struct;
-
-/* Free all resources held by a thread. */
-static inline void release_thread(struct task_struct *dead_task)
-{
-}
-
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
-/*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
-unsigned long thread_saved_pc(struct task_struct *tsk);
-unsigned long get_wchan(struct task_struct *p);
-
-#define KSTK_EIP(tsk) \
- ({ \
- unsigned long eip = 0; \
- if ((tsk)->thread.esp0 > PAGE_SIZE && \
- (virt_addr_valid((tsk)->thread.esp0))) \
- eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
- eip; })
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-
-#define cpu_relax() barrier()
-
-#endif
diff --git a/arch/m68k/include/asm/sun3_pgalloc.h b/arch/m68k/include/asm/sun3_pgalloc.h
index d4c83f143816..48d80d5a666f 100644
--- a/arch/m68k/include/asm/sun3_pgalloc.h
+++ b/arch/m68k/include/asm/sun3_pgalloc.h
@@ -32,7 +32,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t page)
__free_page(page);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,addr) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb), pte); \
@@ -80,7 +80,7 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page
* inside the pgd, so has no extra memory associated with it.
*/
#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb, x) do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr) do { } while (0)
static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 01d212bb05a6..47eac19e8f61 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -82,13 +82,6 @@ SECTIONS
_end = . ;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
@@ -97,4 +90,7 @@ SECTIONS
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
+
+ /* Sections to be discarded */
+ DISCARDS
}
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index c192f773db96..03efaf04d7d7 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -77,13 +77,6 @@ __init_begin = .;
_end = . ;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
.crap : {
/* Stabs debugging sections. */
*(.stab)
@@ -96,4 +89,6 @@ __init_begin = .;
*(.note)
}
+ /* Sections to be discarded */
+ DISCARDS
}
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 534376299a99..e2201b90aa22 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -47,6 +47,10 @@ config GENERIC_FIND_NEXT_BIT
bool
default y
+config GENERIC_GPIO
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
@@ -182,6 +186,8 @@ config M527x
config COLDFIRE
bool
depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
default y
config CLOCK_SET
diff --git a/arch/m68knommu/kernel/irq.c b/arch/m68knommu/kernel/irq.c
index 56e0f4c55a67..c9cac36d4422 100644
--- a/arch/m68knommu/kernel/irq.c
+++ b/arch/m68knommu/kernel/irq.c
@@ -29,32 +29,6 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
set_irq_regs(oldregs);
}
-void ack_bad_irq(unsigned int irq)
-{
- printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
-}
-
-static struct irq_chip m_irq_chip = {
- .name = "M68K-INTC",
- .enable = enable_vector,
- .disable = disable_vector,
- .ack = ack_vector,
-};
-
-void __init init_IRQ(void)
-{
- int irq;
-
- init_vectors();
-
- for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &m_irq_chip;
- }
-}
-
int show_interrupts(struct seq_file *p, void *v)
{
struct irqaction *ap;
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index d182b2f72211..c2aa717de08a 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -69,7 +69,7 @@ static unsigned long read_rtc_mmss(void)
if ((year += 1900) < 1970)
year += 100;
- return mktime(year, mon, day, hour, min, sec);;
+ return mktime(year, mon, day, hour, min, sec);
}
unsigned long read_persistent_clock(void)
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index b7fe505e358d..2736a5e309c0 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -184,12 +184,6 @@ SECTIONS {
__init_end = .;
} > INIT
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
.bss : {
. = ALIGN(4);
_sbss = . ;
@@ -200,5 +194,6 @@ SECTIONS {
_end = . ;
} > BSS
+ DISCARDS
}
diff --git a/arch/m68knommu/lib/checksum.c b/arch/m68knommu/lib/checksum.c
index 269d83bfbbe1..eccf25d3d73e 100644
--- a/arch/m68knommu/lib/checksum.c
+++ b/arch/m68knommu/lib/checksum.c
@@ -92,6 +92,7 @@ out:
return result;
}
+#ifdef CONFIG_COLDFIRE
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
@@ -100,6 +101,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
return (__force __sum16)~do_csum(iph,ihl*4);
}
+#endif
/*
* computes the checksum of a memory block at buff, length len,
@@ -127,15 +129,6 @@ __wsum csum_partial(const void *buff, int len, __wsum sum)
EXPORT_SYMBOL(csum_partial);
/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-__sum16 ip_compute_csum(const void *buff, int len)
-{
- return (__force __sum16)~do_csum(buff,len);
-}
-
-/*
* copy from fs while checksumming, otherwise like csum_partial
*/
diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile
index a439d9ab3f27..113c33390064 100644
--- a/arch/m68knommu/platform/5206/Makefile
+++ b/arch/m68knommu/platform/5206/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
index f6f79874e9af..9c335465e66d 100644
--- a/arch/m68knommu/platform/5206/config.c
+++ b/arch/m68knommu/platform/5206/config.c
@@ -49,11 +49,11 @@ static void __init m5206_uart_init_line(int line, int irq)
if (line == 0) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+ mcf_mapirq2imr(irq, MCFINTC_UART0);
} else if (line == 1) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+ mcf_mapirq2imr(irq, MCFINTC_UART1);
}
}
@@ -68,38 +68,19 @@ static void __init m5206_uarts_init(void)
/***************************************************************************/
-void mcf_autovector(unsigned int vec)
+static void __init m5206_timers_init(void)
{
- volatile unsigned char *mbar;
- unsigned char icr;
-
- if ((vec >= 25) && (vec <= 31)) {
- vec -= 25;
- mbar = (volatile unsigned char *) MCF_MBAR;
- icr = MCFSIM_ICR_AUTOVEC | (vec << 3);
- *(mbar + MCFSIM_ICR1 + vec) = icr;
- vec = 0x1 << (vec + 1);
- mcf_setimr(mcf_getimr() & ~vec);
- }
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(unsigned int timer, unsigned int level)
-{
- volatile unsigned char *icrp;
- unsigned int icr, imr;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: icr = MCFSIM_TIMER2ICR; imr = MCFSIM_IMR_TIMER2; break;
- default: icr = MCFSIM_TIMER1ICR; imr = MCFSIM_IMR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (MCF_MBAR + icr);
- *icrp = MCFSIM_ICR_AUTOVEC | (level << 2) | MCFSIM_ICR_PRI3;
- mcf_setimr(mcf_getimr() & ~imr);
- }
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
}
/***************************************************************************/
@@ -117,15 +98,20 @@ void m5206_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
mach_reset = m5206_cpu_reset;
+ m5206_timers_init();
+ m5206_uarts_init();
+
+ /* Only support the external interrupts on their primary level */
+ mcf_mapirq2imr(25, MCFINTC_EINT1);
+ mcf_mapirq2imr(28, MCFINTC_EINT4);
+ mcf_mapirq2imr(31, MCFINTC_EINT7);
}
/***************************************************************************/
static int __init init_BSP(void)
{
- m5206_uarts_init();
platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5206/gpio.c b/arch/m68knommu/platform/5206/gpio.c
new file mode 100644
index 000000000000..60f779ce1651
--- /dev/null
+++ b/arch/m68knommu/platform/5206/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PP",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFSIM_PADDR,
+ .podr = MCFSIM_PADAT,
+ .ppdr = MCFSIM_PADAT,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile
index a439d9ab3f27..113c33390064 100644
--- a/arch/m68knommu/platform/5206e/Makefile
+++ b/arch/m68knommu/platform/5206e/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index 65887799db81..0f41ba82a3b5 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -15,6 +15,7 @@
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
#include <asm/mcfdma.h>
#include <asm/mcfuart.h>
@@ -49,11 +50,11 @@ static void __init m5206e_uart_init_line(int line, int irq)
if (line == 0) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+ mcf_mapirq2imr(irq, MCFINTC_UART0);
} else if (line == 1) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+ mcf_mapirq2imr(irq, MCFINTC_UART1);
}
}
@@ -68,38 +69,19 @@ static void __init m5206e_uarts_init(void)
/***************************************************************************/
-void mcf_autovector(unsigned int vec)
-{
- volatile unsigned char *mbar;
- unsigned char icr;
-
- if ((vec >= 25) && (vec <= 31)) {
- vec -= 25;
- mbar = (volatile unsigned char *) MCF_MBAR;
- icr = MCFSIM_ICR_AUTOVEC | (vec << 3);
- *(mbar + MCFSIM_ICR1 + vec) = icr;
- vec = 0x1 << (vec + 1);
- mcf_setimr(mcf_getimr() & ~vec);
- }
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(unsigned int timer, unsigned int level)
+static void __init m5206e_timers_init(void)
{
- volatile unsigned char *icrp;
- unsigned int icr, imr;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: icr = MCFSIM_TIMER2ICR; imr = MCFSIM_IMR_TIMER2; break;
- default: icr = MCFSIM_TIMER1ICR; imr = MCFSIM_IMR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (MCF_MBAR + icr);
- *icrp = MCFSIM_ICR_AUTOVEC | (level << 2) | MCFSIM_ICR_PRI3;
- mcf_setimr(mcf_getimr() & ~imr);
- }
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
}
/***************************************************************************/
@@ -117,8 +99,6 @@ void m5206e_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
-
#if defined(CONFIG_NETtel)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
@@ -126,13 +106,19 @@ void __init config_BSP(char *commandp, int size)
#endif /* CONFIG_NETtel */
mach_reset = m5206e_cpu_reset;
+ m5206e_timers_init();
+ m5206e_uarts_init();
+
+ /* Only support the external interrupts on their primary level */
+ mcf_mapirq2imr(25, MCFINTC_EINT1);
+ mcf_mapirq2imr(28, MCFINTC_EINT4);
+ mcf_mapirq2imr(31, MCFINTC_EINT7);
}
/***************************************************************************/
static int __init init_BSP(void)
{
- m5206e_uarts_init();
platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5206e/gpio.c b/arch/m68knommu/platform/5206e/gpio.c
new file mode 100644
index 000000000000..60f779ce1651
--- /dev/null
+++ b/arch/m68knommu/platform/5206e/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PP",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFSIM_PADDR,
+ .podr = MCFSIM_PADAT,
+ .ppdr = MCFSIM_PADAT,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile
index a50e76acc8fd..435ab3483dc1 100644
--- a/arch/m68knommu/platform/520x/Makefile
+++ b/arch/m68knommu/platform/520x/Makefile
@@ -14,4 +14,4 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c
index 1c43a8aec69b..92614de42cd3 100644
--- a/arch/m68knommu/platform/520x/config.c
+++ b/arch/m68knommu/platform/520x/config.c
@@ -81,20 +81,11 @@ static struct platform_device *m520x_devices[] __initdata = {
/***************************************************************************/
-#define INTC0 (MCF_MBAR + MCFICM_INTC0)
-
static void __init m520x_uart_init_line(int line, int irq)
{
- u32 imr;
u16 par;
u8 par2;
- writeb(0x03, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
-
- imr = readl(INTC0 + MCFINTC_IMRL);
- imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
- writel(imr, INTC0 + MCFINTC_IMRL);
-
switch (line) {
case 0:
par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
@@ -131,18 +122,8 @@ static void __init m520x_uarts_init(void)
static void __init m520x_fec_init(void)
{
- u32 imr;
u8 v;
- /* Unmask FEC interrupts at ColdFire interrupt controller */
- writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 36);
- writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 40);
- writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 42);
-
- imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
- imr &= ~0x0001FFF0;
- writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
-
/* Set multi-function pins to ethernet mode */
v = readb(MCF_IPSBAR + MCF_GPIO_PAR_FEC);
writeb(v | 0xf0, MCF_IPSBAR + MCF_GPIO_PAR_FEC);
@@ -153,17 +134,6 @@ static void __init m520x_fec_init(void)
/***************************************************************************/
-/*
- * Program the vector to be an auto-vectored.
- */
-
-void mcf_autovector(unsigned int vec)
-{
- /* Everything is auto-vectored on the 520x devices */
-}
-
-/***************************************************************************/
-
static void m520x_cpu_reset(void)
{
local_irq_disable();
diff --git a/arch/m68knommu/platform/520x/gpio.c b/arch/m68knommu/platform/520x/gpio.c
new file mode 100644
index 000000000000..15b5bb62a698
--- /dev/null
+++ b/arch/m68knommu/platform/520x/gpio.c
@@ -0,0 +1,211 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PIRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "BUSCTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 8,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BUSCTL,
+ .podr = MCFGPIO_PODR_BUSCTL,
+ .ppdr = MCFGPIO_PPDSDR_BUSCTL,
+ .setr = MCFGPIO_PPDSDR_BUSCTL,
+ .clrr = MCFGPIO_PCLRR_BUSCTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BE",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 16,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BE,
+ .podr = MCFGPIO_PODR_BE,
+ .ppdr = MCFGPIO_PPDSDR_BE,
+ .setr = MCFGPIO_PPDSDR_BE,
+ .clrr = MCFGPIO_PCLRR_BE,
+ },
+ {
+ .gpio_chip = {
+ .label = "CS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 25,
+ .ngpio = 3,
+ },
+ .pddr = MCFGPIO_PDDR_CS,
+ .podr = MCFGPIO_PODR_CS,
+ .ppdr = MCFGPIO_PPDSDR_CS,
+ .setr = MCFGPIO_PPDSDR_CS,
+ .clrr = MCFGPIO_PCLRR_CS,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECI2C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_FECI2C,
+ .podr = MCFGPIO_PODR_FECI2C,
+ .ppdr = MCFGPIO_PPDSDR_FECI2C,
+ .setr = MCFGPIO_PPDSDR_FECI2C,
+ .clrr = MCFGPIO_PCLRR_FECI2C,
+ },
+ {
+ .gpio_chip = {
+ .label = "QSPI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_QSPI,
+ .podr = MCFGPIO_PODR_QSPI,
+ .ppdr = MCFGPIO_PPDSDR_QSPI,
+ .setr = MCFGPIO_PPDSDR_QSPI,
+ .clrr = MCFGPIO_PCLRR_QSPI,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMER",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 48,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_TIMER,
+ .podr = MCFGPIO_PODR_TIMER,
+ .ppdr = MCFGPIO_PPDSDR_TIMER,
+ .setr = MCFGPIO_PPDSDR_TIMER,
+ .clrr = MCFGPIO_PCLRR_TIMER,
+ },
+ {
+ .gpio_chip = {
+ .label = "UART",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 56,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_UART,
+ .podr = MCFGPIO_PODR_UART,
+ .ppdr = MCFGPIO_PPDSDR_UART,
+ .setr = MCFGPIO_PPDSDR_UART,
+ .clrr = MCFGPIO_PCLRR_UART,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FECH,
+ .podr = MCFGPIO_PODR_FECH,
+ .ppdr = MCFGPIO_PPDSDR_FECH,
+ .setr = MCFGPIO_PPDSDR_FECH,
+ .clrr = MCFGPIO_PCLRR_FECH,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FECL,
+ .podr = MCFGPIO_PODR_FECL,
+ .ppdr = MCFGPIO_PPDSDR_FECL,
+ .setr = MCFGPIO_PPDSDR_FECL,
+ .clrr = MCFGPIO_PCLRR_FECL,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68knommu/platform/523x/Makefile
index 5694d593f029..b8f9b45440c2 100644
--- a/arch/m68knommu/platform/523x/Makefile
+++ b/arch/m68knommu/platform/523x/Makefile
@@ -14,4 +14,4 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
index 961fefebca14..00f08d2e43b0 100644
--- a/arch/m68knommu/platform/523x/config.c
+++ b/arch/m68knommu/platform/523x/config.c
@@ -82,66 +82,6 @@ static struct platform_device *m523x_devices[] __initdata = {
/***************************************************************************/
-#define INTC0 (MCF_MBAR + MCFICM_INTC0)
-
-static void __init m523x_uart_init_line(int line, int irq)
-{
- u32 imr;
-
- if ((line < 0) || (line > 2))
- return;
-
- writeb(0x30+line, (INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line));
-
- imr = readl(INTC0 + MCFINTC_IMRL);
- imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
- writel(imr, INTC0 + MCFINTC_IMRL);
-}
-
-static void __init m523x_uarts_init(void)
-{
- const int nrlines = ARRAY_SIZE(m523x_uart_platform);
- int line;
-
- for (line = 0; (line < nrlines); line++)
- m523x_uart_init_line(line, m523x_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m523x_fec_init(void)
-{
- u32 imr;
-
- /* Unmask FEC interrupts at ColdFire interrupt controller */
- writeb(0x28, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 23);
- writeb(0x27, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 27);
- writeb(0x26, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 29);
-
- imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
- imr &= ~0xf;
- writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
- imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
- imr &= ~0xff800001;
- writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
-}
-
-/***************************************************************************/
-
-void mcf_disableall(void)
-{
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
-}
-
-/***************************************************************************/
-
-void mcf_autovector(unsigned int vec)
-{
- /* Everything is auto-vectored on the 523x */
-}
-/***************************************************************************/
-
static void m523x_cpu_reset(void)
{
local_irq_disable();
@@ -152,10 +92,7 @@ static void m523x_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_disableall();
mach_reset = m523x_cpu_reset;
- m523x_uarts_init();
- m523x_fec_init();
}
/***************************************************************************/
diff --git a/arch/m68knommu/platform/523x/gpio.c b/arch/m68knommu/platform/523x/gpio.c
new file mode 100644
index 000000000000..f02840d54d3c
--- /dev/null
+++ b/arch/m68knommu/platform/523x/gpio.c
@@ -0,0 +1,283 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PIRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "ADDR",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 13,
+ .ngpio = 3,
+ },
+ .pddr = MCFGPIO_PDDR_ADDR,
+ .podr = MCFGPIO_PODR_ADDR,
+ .ppdr = MCFGPIO_PPDSDR_ADDR,
+ .setr = MCFGPIO_PPDSDR_ADDR,
+ .clrr = MCFGPIO_PCLRR_ADDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "DATAH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 16,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_DATAH,
+ .podr = MCFGPIO_PODR_DATAH,
+ .ppdr = MCFGPIO_PPDSDR_DATAH,
+ .setr = MCFGPIO_PPDSDR_DATAH,
+ .clrr = MCFGPIO_PCLRR_DATAH,
+ },
+ {
+ .gpio_chip = {
+ .label = "DATAL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 24,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_DATAL,
+ .podr = MCFGPIO_PODR_DATAL,
+ .ppdr = MCFGPIO_PPDSDR_DATAL,
+ .setr = MCFGPIO_PPDSDR_DATAL,
+ .clrr = MCFGPIO_PCLRR_DATAL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BUSCTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_BUSCTL,
+ .podr = MCFGPIO_PODR_BUSCTL,
+ .ppdr = MCFGPIO_PPDSDR_BUSCTL,
+ .setr = MCFGPIO_PPDSDR_BUSCTL,
+ .clrr = MCFGPIO_PCLRR_BUSCTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BS,
+ .podr = MCFGPIO_PODR_BS,
+ .ppdr = MCFGPIO_PPDSDR_BS,
+ .setr = MCFGPIO_PPDSDR_BS,
+ .clrr = MCFGPIO_PCLRR_BS,
+ },
+ {
+ .gpio_chip = {
+ .label = "CS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 49,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_PDDR_CS,
+ .podr = MCFGPIO_PODR_CS,
+ .ppdr = MCFGPIO_PPDSDR_CS,
+ .setr = MCFGPIO_PPDSDR_CS,
+ .clrr = MCFGPIO_PCLRR_CS,
+ },
+ {
+ .gpio_chip = {
+ .label = "SDRAM",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 56,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_PDDR_SDRAM,
+ .podr = MCFGPIO_PODR_SDRAM,
+ .ppdr = MCFGPIO_PPDSDR_SDRAM,
+ .setr = MCFGPIO_PPDSDR_SDRAM,
+ .clrr = MCFGPIO_PCLRR_SDRAM,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECI2C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_FECI2C,
+ .podr = MCFGPIO_PODR_FECI2C,
+ .ppdr = MCFGPIO_PPDSDR_FECI2C,
+ .setr = MCFGPIO_PPDSDR_FECI2C,
+ .clrr = MCFGPIO_PCLRR_FECI2C,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 2,
+ },
+ .pddr = MCFGPIO_PDDR_UARTH,
+ .podr = MCFGPIO_PODR_UARTH,
+ .ppdr = MCFGPIO_PPDSDR_UARTH,
+ .setr = MCFGPIO_PPDSDR_UARTH,
+ .clrr = MCFGPIO_PCLRR_UARTH,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 80,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_UARTL,
+ .podr = MCFGPIO_PODR_UARTL,
+ .ppdr = MCFGPIO_PPDSDR_UARTL,
+ .setr = MCFGPIO_PPDSDR_UARTL,
+ .clrr = MCFGPIO_PCLRR_UARTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "QSPI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 88,
+ .ngpio = 5,
+ },
+ .pddr = MCFGPIO_PDDR_QSPI,
+ .podr = MCFGPIO_PODR_QSPI,
+ .ppdr = MCFGPIO_PPDSDR_QSPI,
+ .setr = MCFGPIO_PPDSDR_QSPI,
+ .clrr = MCFGPIO_PCLRR_QSPI,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMER",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 96,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_TIMER,
+ .podr = MCFGPIO_PODR_TIMER,
+ .ppdr = MCFGPIO_PPDSDR_TIMER,
+ .setr = MCFGPIO_PPDSDR_TIMER,
+ .clrr = MCFGPIO_PCLRR_TIMER,
+ },
+ {
+ .gpio_chip = {
+ .label = "ETPU",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 104,
+ .ngpio = 3,
+ },
+ .pddr = MCFGPIO_PDDR_ETPU,
+ .podr = MCFGPIO_PODR_ETPU,
+ .ppdr = MCFGPIO_PPDSDR_ETPU,
+ .setr = MCFGPIO_PPDSDR_ETPU,
+ .clrr = MCFGPIO_PCLRR_ETPU,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile
index a439d9ab3f27..f56225d1582f 100644
--- a/arch/m68knommu/platform/5249/Makefile
+++ b/arch/m68knommu/platform/5249/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o intc2.o
diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c
index 93d998825925..646f5ba462fc 100644
--- a/arch/m68knommu/platform/5249/config.c
+++ b/arch/m68knommu/platform/5249/config.c
@@ -48,11 +48,11 @@ static void __init m5249_uart_init_line(int line, int irq)
if (line == 0) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+ mcf_mapirq2imr(irq, MCFINTC_UART0);
} else if (line == 1) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+ mcf_mapirq2imr(irq, MCFINTC_UART1);
}
}
@@ -65,38 +65,21 @@ static void __init m5249_uarts_init(void)
m5249_uart_init_line(line, m5249_uart_platform[line].irq);
}
-
/***************************************************************************/
-void mcf_autovector(unsigned int vec)
+static void __init m5249_timers_init(void)
{
- volatile unsigned char *mbar;
-
- if ((vec >= 25) && (vec <= 31)) {
- mbar = (volatile unsigned char *) MCF_MBAR;
- vec = 0x1 << (vec - 24);
- *(mbar + MCFSIM_AVR) |= vec;
- mcf_setimr(mcf_getimr() & ~vec);
- }
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(unsigned int timer, unsigned int level)
-{
- volatile unsigned char *icrp;
- unsigned int icr, imr;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: icr = MCFSIM_TIMER2ICR; imr = MCFSIM_IMR_TIMER2; break;
- default: icr = MCFSIM_TIMER1ICR; imr = MCFSIM_IMR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (MCF_MBAR + icr);
- *icrp = MCFSIM_ICR_AUTOVEC | (level << 2) | MCFSIM_ICR_PRI3;
- mcf_setimr(mcf_getimr() & ~imr);
- }
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
}
/***************************************************************************/
@@ -114,15 +97,15 @@ void m5249_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
mach_reset = m5249_cpu_reset;
+ m5249_timers_init();
+ m5249_uarts_init();
}
/***************************************************************************/
static int __init init_BSP(void)
{
- m5249_uarts_init();
platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5249/gpio.c b/arch/m68knommu/platform/5249/gpio.c
new file mode 100644
index 000000000000..c611eab8b3b6
--- /dev/null
+++ b/arch/m68knommu/platform/5249/gpio.c
@@ -0,0 +1,65 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "GPIO0",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 32,
+ },
+ .pddr = MCFSIM2_GPIOENABLE,
+ .podr = MCFSIM2_GPIOWRITE,
+ .ppdr = MCFSIM2_GPIOREAD,
+ },
+ {
+ .gpio_chip = {
+ .label = "GPIO1",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .base = 32,
+ .ngpio = 32,
+ },
+ .pddr = MCFSIM2_GPIO1ENABLE,
+ .podr = MCFSIM2_GPIO1WRITE,
+ .ppdr = MCFSIM2_GPIO1READ,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5249/intc2.c b/arch/m68knommu/platform/5249/intc2.c
new file mode 100644
index 000000000000..d09d9da04537
--- /dev/null
+++ b/arch/m68knommu/platform/5249/intc2.c
@@ -0,0 +1,59 @@
+/*
+ * intc2.c -- support for the 2nd INTC controller of the 5249
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void intc2_irq_gpio_mask(unsigned int irq)
+{
+ u32 imr;
+ imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+ imr &= ~(0x1 << (irq - MCFINTC2_GPIOIRQ0));
+ writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_unmask(unsigned int irq)
+{
+ u32 imr;
+ imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+ imr |= (0x1 << (irq - MCFINTC2_GPIOIRQ0));
+ writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_ack(unsigned int irq)
+{
+ writel(0x1 << (irq - MCFINTC2_GPIOIRQ0), MCF_MBAR2 + MCFSIM2_GPIOINTCLEAR);
+}
+
+static struct irq_chip intc2_irq_gpio_chip = {
+ .name = "CF-INTC2",
+ .mask = intc2_irq_gpio_mask,
+ .unmask = intc2_irq_gpio_unmask,
+ .ack = intc2_irq_gpio_ack,
+};
+
+static int __init mcf_intc2_init(void)
+{
+ int irq;
+
+ /* GPIO interrupt sources */
+ for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++)
+ irq_desc[irq].chip = &intc2_irq_gpio_chip;
+
+ return 0;
+}
+
+arch_initcall(mcf_intc2_init);
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile
index 26135d92b34d..93673ef8e2c1 100644
--- a/arch/m68knommu/platform/5272/Makefile
+++ b/arch/m68knommu/platform/5272/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o intc.o
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index 5f95fcde05fd..59278c0887d0 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -20,12 +20,6 @@
/***************************************************************************/
-extern unsigned int mcf_timervector;
-extern unsigned int mcf_profilevector;
-extern unsigned int mcf_timerlevel;
-
-/***************************************************************************/
-
/*
* Some platforms need software versions of the GPIO data registers.
*/
@@ -37,11 +31,11 @@ unsigned char ledbank = 0xff;
static struct mcf_platform_uart m5272_uart_platform[] = {
{
.mapbase = MCF_MBAR + MCFUART_BASE1,
- .irq = 73,
+ .irq = MCF_IRQ_UART1,
},
{
.mapbase = MCF_MBAR + MCFUART_BASE2,
- .irq = 74,
+ .irq = MCF_IRQ_UART2,
},
{ },
};
@@ -59,18 +53,18 @@ static struct resource m5272_fec_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 86,
- .end = 86,
+ .start = MCF_IRQ_ERX,
+ .end = MCF_IRQ_ERX,
.flags = IORESOURCE_IRQ,
},
{
- .start = 87,
- .end = 87,
+ .start = MCF_IRQ_ETX,
+ .end = MCF_IRQ_ETX,
.flags = IORESOURCE_IRQ,
},
{
- .start = 88,
- .end = 88,
+ .start = MCF_IRQ_ENTC,
+ .end = MCF_IRQ_ENTC,
.flags = IORESOURCE_IRQ,
},
};
@@ -94,9 +88,6 @@ static void __init m5272_uart_init_line(int line, int irq)
u32 v;
if ((line >= 0) && (line < 2)) {
- v = (line) ? 0x0e000000 : 0xe0000000;
- writel(v, MCF_MBAR + MCFSIM_ICR2);
-
/* Enable the output lines for the serial ports */
v = readl(MCF_MBAR + MCFSIM_PBCNT);
v = (v & ~0x000000ff) | 0x00000055;
@@ -119,54 +110,6 @@ static void __init m5272_uarts_init(void)
/***************************************************************************/
-static void __init m5272_fec_init(void)
-{
- u32 imr;
-
- /* Unmask FEC interrupts at ColdFire interrupt controller */
- imr = readl(MCF_MBAR + MCFSIM_ICR3);
- imr = (imr & ~0x00000fff) | 0x00000ddd;
- writel(imr, MCF_MBAR + MCFSIM_ICR3);
-
- imr = readl(MCF_MBAR + MCFSIM_ICR1);
- imr = (imr & ~0x0f000000) | 0x0d000000;
- writel(imr, MCF_MBAR + MCFSIM_ICR1);
-}
-
-/***************************************************************************/
-
-void mcf_disableall(void)
-{
- volatile unsigned long *icrp;
-
- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- icrp[0] = 0x88888888;
- icrp[1] = 0x88888888;
- icrp[2] = 0x88888888;
- icrp[3] = 0x88888888;
-}
-
-/***************************************************************************/
-
-void mcf_autovector(unsigned int vec)
-{
- /* Everything is auto-vectored on the 5272 */
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(int timer, int level)
-{
- volatile unsigned long *icrp;
-
- if ((timer >= 1 ) && (timer <= 4)) {
- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = (0x8 | level) << ((4 - timer) * 4);
- }
-}
-
-/***************************************************************************/
-
static void m5272_cpu_reset(void)
{
local_irq_disable();
@@ -190,8 +133,6 @@ void __init config_BSP(char *commandp, int size)
*pivrp = 0x40;
#endif
- mcf_disableall();
-
#if defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
@@ -202,8 +143,6 @@ void __init config_BSP(char *commandp, int size)
commandp[size-1] = 0;
#endif
- mcf_timervector = 69;
- mcf_profilevector = 70;
mach_reset = m5272_cpu_reset;
}
@@ -212,7 +151,6 @@ void __init config_BSP(char *commandp, int size)
static int __init init_BSP(void)
{
m5272_uarts_init();
- m5272_fec_init();
platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5272/gpio.c b/arch/m68knommu/platform/5272/gpio.c
new file mode 100644
index 000000000000..459db89a89cc
--- /dev/null
+++ b/arch/m68knommu/platform/5272/gpio.c
@@ -0,0 +1,81 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PA",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 16,
+ },
+ .pddr = MCFSIM_PADDR,
+ .podr = MCFSIM_PADAT,
+ .ppdr = MCFSIM_PADAT,
+ },
+ {
+ .gpio_chip = {
+ .label = "PB",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .base = 16,
+ .ngpio = 16,
+ },
+ .pddr = MCFSIM_PBDDR,
+ .podr = MCFSIM_PBDAT,
+ .ppdr = MCFSIM_PBDAT,
+ },
+ {
+ .gpio_chip = {
+ .label = "PC",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .base = 32,
+ .ngpio = 16,
+ },
+ .pddr = MCFSIM_PCDDR,
+ .podr = MCFSIM_PCDAT,
+ .ppdr = MCFSIM_PCDAT,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c
new file mode 100644
index 000000000000..7081e0a9720e
--- /dev/null
+++ b/arch/m68knommu/platform/5272/intc.c
@@ -0,0 +1,138 @@
+/*
+ * intc.c -- interrupt controller or ColdFire 5272 SoC
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * The 5272 ColdFire interrupt controller is nothing like any other
+ * ColdFire interrupt controller - it truly is completely different.
+ * Given its age it is unlikely to be used on any other ColdFire CPU.
+ */
+
+/*
+ * The masking and priproty setting of interrupts on the 5272 is done
+ * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
+ * loose mapping of vector number to register and internal bits, but
+ * a table is the easiest and quickest way to map them.
+ */
+struct irqmap {
+ unsigned char icr;
+ unsigned char index;
+ unsigned char ack;
+};
+
+static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
+ /*MCF_IRQ_SPURIOUS*/ { .icr = 0, .index = 0, .ack = 0, },
+ /*MCF_IRQ_EINT1*/ { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
+ /*MCF_IRQ_EINT2*/ { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
+ /*MCF_IRQ_EINT3*/ { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
+ /*MCF_IRQ_EINT4*/ { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
+ /*MCF_IRQ_TIMER1*/ { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
+ /*MCF_IRQ_TIMER2*/ { .icr = MCFSIM_ICR1, .index = 8, .ack = 0, },
+ /*MCF_IRQ_TIMER3*/ { .icr = MCFSIM_ICR1, .index = 4, .ack = 0, },
+ /*MCF_IRQ_TIMER4*/ { .icr = MCFSIM_ICR1, .index = 0, .ack = 0, },
+ /*MCF_IRQ_UART1*/ { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
+ /*MCF_IRQ_UART2*/ { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
+ /*MCF_IRQ_PLIP*/ { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
+ /*MCF_IRQ_PLIA*/ { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
+ /*MCF_IRQ_USB0*/ { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
+ /*MCF_IRQ_USB1*/ { .icr = MCFSIM_ICR2, .index = 8, .ack = 0, },
+ /*MCF_IRQ_USB2*/ { .icr = MCFSIM_ICR2, .index = 4, .ack = 0, },
+ /*MCF_IRQ_USB3*/ { .icr = MCFSIM_ICR2, .index = 0, .ack = 0, },
+ /*MCF_IRQ_USB4*/ { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
+ /*MCF_IRQ_USB5*/ { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
+ /*MCF_IRQ_USB6*/ { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
+ /*MCF_IRQ_USB7*/ { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
+ /*MCF_IRQ_DMA*/ { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
+ /*MCF_IRQ_ERX*/ { .icr = MCFSIM_ICR3, .index = 8, .ack = 0, },
+ /*MCF_IRQ_ETX*/ { .icr = MCFSIM_ICR3, .index = 4, .ack = 0, },
+ /*MCF_IRQ_ENTC*/ { .icr = MCFSIM_ICR3, .index = 0, .ack = 0, },
+ /*MCF_IRQ_QSPI*/ { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
+ /*MCF_IRQ_EINT5*/ { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
+ /*MCF_IRQ_EINT6*/ { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
+ /*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
+};
+
+static void intc_irq_mask(unsigned int irq)
+{
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+ u32 v;
+ irq -= MCFINT_VECBASE;
+ v = 0x8 << intc_irqmap[irq].index;
+ writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+ }
+}
+
+static void intc_irq_unmask(unsigned int irq)
+{
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+ u32 v;
+ irq -= MCFINT_VECBASE;
+ v = 0xd << intc_irqmap[irq].index;
+ writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+ }
+}
+
+static void intc_irq_ack(unsigned int irq)
+{
+ /* Only external interrupts are acked */
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+ irq -= MCFINT_VECBASE;
+ if (intc_irqmap[irq].ack) {
+ u32 v;
+ v = 0xd << intc_irqmap[irq].index;
+ writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+ }
+ }
+}
+
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+ /* We can set the edge type here for external interrupts */
+ return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+ .name = "CF-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+ .ack = intc_irq_ack,
+ .set_type = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+ int irq;
+
+ init_vectors();
+
+ /* Mask all interrupt sources */
+ writel(0x88888888, MCF_MBAR + MCFSIM_ICR1);
+ writel(0x88888888, MCF_MBAR + MCFSIM_ICR2);
+ writel(0x88888888, MCF_MBAR + MCFSIM_ICR3);
+ writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
+
+ for (irq = 0; (irq < NR_IRQS); irq++) {
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = NULL;
+ irq_desc[irq].depth = 1;
+ irq_desc[irq].chip = &intc_irq_chip;
+ intc_irq_set_type(irq, 0);
+ }
+}
+
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
index 26135d92b34d..3d90e6d92459 100644
--- a/arch/m68knommu/platform/527x/Makefile
+++ b/arch/m68knommu/platform/527x/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
index f746439cfd3e..fa51be172830 100644
--- a/arch/m68knommu/platform/527x/config.c
+++ b/arch/m68knommu/platform/527x/config.c
@@ -116,23 +116,13 @@ static struct platform_device *m527x_devices[] __initdata = {
/***************************************************************************/
-#define INTC0 (MCF_MBAR + MCFICM_INTC0)
-
static void __init m527x_uart_init_line(int line, int irq)
{
u16 sepmask;
- u32 imr;
if ((line < 0) || (line > 2))
return;
- /* level 6, line based priority */
- writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
-
- imr = readl(INTC0 + MCFINTC_IMRL);
- imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
- writel(imr, INTC0 + MCFINTC_IMRL);
-
/*
* External Pin Mask Setting & Enable External Pin for Interface
*/
@@ -157,32 +147,11 @@ static void __init m527x_uarts_init(void)
/***************************************************************************/
-static void __init m527x_fec_irq_init(int nr)
-{
- unsigned long base;
- u32 imr;
-
- base = MCF_IPSBAR + (nr ? MCFICM_INTC1 : MCFICM_INTC0);
-
- writeb(0x28, base + MCFINTC_ICR0 + 23);
- writeb(0x27, base + MCFINTC_ICR0 + 27);
- writeb(0x26, base + MCFINTC_ICR0 + 29);
-
- imr = readl(base + MCFINTC_IMRH);
- imr &= ~0xf;
- writel(imr, base + MCFINTC_IMRH);
- imr = readl(base + MCFINTC_IMRL);
- imr &= ~0xff800001;
- writel(imr, base + MCFINTC_IMRL);
-}
-
static void __init m527x_fec_init(void)
{
u16 par;
u8 v;
- m527x_fec_irq_init(0);
-
/* Set multi-function pins to ethernet mode for fec0 */
#if defined(CONFIG_M5271)
v = readb(MCF_IPSBAR + 0x100047);
@@ -195,8 +164,6 @@ static void __init m527x_fec_init(void)
#endif
#ifdef CONFIG_FEC2
- m527x_fec_irq_init(1);
-
/* Set multi-function pins to ethernet mode for fec1 */
par = readw(MCF_IPSBAR + 0x100082);
writew(par | 0xa0, MCF_IPSBAR + 0x100082);
@@ -207,21 +174,6 @@ static void __init m527x_fec_init(void)
/***************************************************************************/
-void mcf_disableall(void)
-{
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
-}
-
-/***************************************************************************/
-
-void mcf_autovector(unsigned int vec)
-{
- /* Everything is auto-vectored on the 5272 */
-}
-
-/***************************************************************************/
-
static void m527x_cpu_reset(void)
{
local_irq_disable();
@@ -232,7 +184,6 @@ static void m527x_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_disableall();
mach_reset = m527x_cpu_reset;
m527x_uarts_init();
m527x_fec_init();
diff --git a/arch/m68knommu/platform/527x/gpio.c b/arch/m68knommu/platform/527x/gpio.c
new file mode 100644
index 000000000000..1028142851ac
--- /dev/null
+++ b/arch/m68knommu/platform/527x/gpio.c
@@ -0,0 +1,607 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+#if defined(CONFIG_M5271)
+ {
+ .gpio_chip = {
+ .label = "PIRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "ADDR",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 13,
+ .ngpio = 3,
+ },
+ .pddr = MCFGPIO_PDDR_ADDR,
+ .podr = MCFGPIO_PODR_ADDR,
+ .ppdr = MCFGPIO_PPDSDR_ADDR,
+ .setr = MCFGPIO_PPDSDR_ADDR,
+ .clrr = MCFGPIO_PCLRR_ADDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "DATAH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 16,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_DATAH,
+ .podr = MCFGPIO_PODR_DATAH,
+ .ppdr = MCFGPIO_PPDSDR_DATAH,
+ .setr = MCFGPIO_PPDSDR_DATAH,
+ .clrr = MCFGPIO_PCLRR_DATAH,
+ },
+ {
+ .gpio_chip = {
+ .label = "DATAL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 24,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_DATAL,
+ .podr = MCFGPIO_PODR_DATAL,
+ .ppdr = MCFGPIO_PPDSDR_DATAL,
+ .setr = MCFGPIO_PPDSDR_DATAL,
+ .clrr = MCFGPIO_PCLRR_DATAL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BUSCTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_BUSCTL,
+ .podr = MCFGPIO_PODR_BUSCTL,
+ .ppdr = MCFGPIO_PPDSDR_BUSCTL,
+ .setr = MCFGPIO_PPDSDR_BUSCTL,
+ .clrr = MCFGPIO_PCLRR_BUSCTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BS,
+ .podr = MCFGPIO_PODR_BS,
+ .ppdr = MCFGPIO_PPDSDR_BS,
+ .setr = MCFGPIO_PPDSDR_BS,
+ .clrr = MCFGPIO_PCLRR_BS,
+ },
+ {
+ .gpio_chip = {
+ .label = "CS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 49,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_PDDR_CS,
+ .podr = MCFGPIO_PODR_CS,
+ .ppdr = MCFGPIO_PPDSDR_CS,
+ .setr = MCFGPIO_PPDSDR_CS,
+ .clrr = MCFGPIO_PCLRR_CS,
+ },
+ {
+ .gpio_chip = {
+ .label = "SDRAM",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 56,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_PDDR_SDRAM,
+ .podr = MCFGPIO_PODR_SDRAM,
+ .ppdr = MCFGPIO_PPDSDR_SDRAM,
+ .setr = MCFGPIO_PPDSDR_SDRAM,
+ .clrr = MCFGPIO_PCLRR_SDRAM,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECI2C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_FECI2C,
+ .podr = MCFGPIO_PODR_FECI2C,
+ .ppdr = MCFGPIO_PPDSDR_FECI2C,
+ .setr = MCFGPIO_PPDSDR_FECI2C,
+ .clrr = MCFGPIO_PCLRR_FECI2C,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 2,
+ },
+ .pddr = MCFGPIO_PDDR_UARTH,
+ .podr = MCFGPIO_PODR_UARTH,
+ .ppdr = MCFGPIO_PPDSDR_UARTH,
+ .setr = MCFGPIO_PPDSDR_UARTH,
+ .clrr = MCFGPIO_PCLRR_UARTH,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 80,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_UARTL,
+ .podr = MCFGPIO_PODR_UARTL,
+ .ppdr = MCFGPIO_PPDSDR_UARTL,
+ .setr = MCFGPIO_PPDSDR_UARTL,
+ .clrr = MCFGPIO_PCLRR_UARTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "QSPI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 88,
+ .ngpio = 5,
+ },
+ .pddr = MCFGPIO_PDDR_QSPI,
+ .podr = MCFGPIO_PODR_QSPI,
+ .ppdr = MCFGPIO_PPDSDR_QSPI,
+ .setr = MCFGPIO_PPDSDR_QSPI,
+ .clrr = MCFGPIO_PCLRR_QSPI,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMER",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 96,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_TIMER,
+ .podr = MCFGPIO_PODR_TIMER,
+ .ppdr = MCFGPIO_PPDSDR_TIMER,
+ .setr = MCFGPIO_PPDSDR_TIMER,
+ .clrr = MCFGPIO_PCLRR_TIMER,
+ },
+#elif defined(CONFIG_M5275)
+ {
+ .gpio_chip = {
+ .label = "PIRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "BUSCTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 8,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_BUSCTL,
+ .podr = MCFGPIO_PODR_BUSCTL,
+ .ppdr = MCFGPIO_PPDSDR_BUSCTL,
+ .setr = MCFGPIO_PPDSDR_BUSCTL,
+ .clrr = MCFGPIO_PCLRR_BUSCTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "ADDR",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 21,
+ .ngpio = 3,
+ },
+ .pddr = MCFGPIO_PDDR_ADDR,
+ .podr = MCFGPIO_PODR_ADDR,
+ .ppdr = MCFGPIO_PPDSDR_ADDR,
+ .setr = MCFGPIO_PPDSDR_ADDR,
+ .clrr = MCFGPIO_PCLRR_ADDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "CS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 25,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_PDDR_CS,
+ .podr = MCFGPIO_PODR_CS,
+ .ppdr = MCFGPIO_PPDSDR_CS,
+ .setr = MCFGPIO_PPDSDR_CS,
+ .clrr = MCFGPIO_PCLRR_CS,
+ },
+ {
+ .gpio_chip = {
+ .label = "FEC0H",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FEC0H,
+ .podr = MCFGPIO_PODR_FEC0H,
+ .ppdr = MCFGPIO_PPDSDR_FEC0H,
+ .setr = MCFGPIO_PPDSDR_FEC0H,
+ .clrr = MCFGPIO_PCLRR_FEC0H,
+ },
+ {
+ .gpio_chip = {
+ .label = "FEC0L",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FEC0L,
+ .podr = MCFGPIO_PODR_FEC0L,
+ .ppdr = MCFGPIO_PPDSDR_FEC0L,
+ .setr = MCFGPIO_PPDSDR_FEC0L,
+ .clrr = MCFGPIO_PCLRR_FEC0L,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECI2C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 48,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_PDDR_FECI2C,
+ .podr = MCFGPIO_PODR_FECI2C,
+ .ppdr = MCFGPIO_PPDSDR_FECI2C,
+ .setr = MCFGPIO_PPDSDR_FECI2C,
+ .clrr = MCFGPIO_PCLRR_FECI2C,
+ },
+ {
+ .gpio_chip = {
+ .label = "QSPI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 56,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_PDDR_QSPI,
+ .podr = MCFGPIO_PODR_QSPI,
+ .ppdr = MCFGPIO_PPDSDR_QSPI,
+ .setr = MCFGPIO_PPDSDR_QSPI,
+ .clrr = MCFGPIO_PCLRR_QSPI,
+ },
+ {
+ .gpio_chip = {
+ .label = "SDRAM",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_SDRAM,
+ .podr = MCFGPIO_PODR_SDRAM,
+ .ppdr = MCFGPIO_PPDSDR_SDRAM,
+ .setr = MCFGPIO_PPDSDR_SDRAM,
+ .clrr = MCFGPIO_PCLRR_SDRAM,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMERH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_TIMERH,
+ .podr = MCFGPIO_PODR_TIMERH,
+ .ppdr = MCFGPIO_PPDSDR_TIMERH,
+ .setr = MCFGPIO_PPDSDR_TIMERH,
+ .clrr = MCFGPIO_PCLRR_TIMERH,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMERL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 80,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_TIMERL,
+ .podr = MCFGPIO_PODR_TIMERL,
+ .ppdr = MCFGPIO_PPDSDR_TIMERL,
+ .setr = MCFGPIO_PPDSDR_TIMERL,
+ .clrr = MCFGPIO_PCLRR_TIMERL,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 88,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_UARTL,
+ .podr = MCFGPIO_PODR_UARTL,
+ .ppdr = MCFGPIO_PPDSDR_UARTL,
+ .setr = MCFGPIO_PPDSDR_UARTL,
+ .clrr = MCFGPIO_PCLRR_UARTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "FEC1H",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 96,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FEC1H,
+ .podr = MCFGPIO_PODR_FEC1H,
+ .ppdr = MCFGPIO_PPDSDR_FEC1H,
+ .setr = MCFGPIO_PPDSDR_FEC1H,
+ .clrr = MCFGPIO_PCLRR_FEC1H,
+ },
+ {
+ .gpio_chip = {
+ .label = "FEC1L",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 104,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FEC1L,
+ .podr = MCFGPIO_PODR_FEC1L,
+ .ppdr = MCFGPIO_PPDSDR_FEC1L,
+ .setr = MCFGPIO_PPDSDR_FEC1L,
+ .clrr = MCFGPIO_PCLRR_FEC1L,
+ },
+ {
+ .gpio_chip = {
+ .label = "BS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 114,
+ .ngpio = 2,
+ },
+ .pddr = MCFGPIO_PDDR_BS,
+ .podr = MCFGPIO_PODR_BS,
+ .ppdr = MCFGPIO_PPDSDR_BS,
+ .setr = MCFGPIO_PPDSDR_BS,
+ .clrr = MCFGPIO_PCLRR_BS,
+ },
+ {
+ .gpio_chip = {
+ .label = "IRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 121,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_PDDR_IRQ,
+ .podr = MCFGPIO_PODR_IRQ,
+ .ppdr = MCFGPIO_PPDSDR_IRQ,
+ .setr = MCFGPIO_PPDSDR_IRQ,
+ .clrr = MCFGPIO_PCLRR_IRQ,
+ },
+ {
+ .gpio_chip = {
+ .label = "USBH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 128,
+ .ngpio = 1,
+ },
+ .pddr = MCFGPIO_PDDR_USBH,
+ .podr = MCFGPIO_PODR_USBH,
+ .ppdr = MCFGPIO_PPDSDR_USBH,
+ .setr = MCFGPIO_PPDSDR_USBH,
+ .clrr = MCFGPIO_PCLRR_USBH,
+ },
+ {
+ .gpio_chip = {
+ .label = "USBL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 136,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_USBL,
+ .podr = MCFGPIO_PODR_USBL,
+ .ppdr = MCFGPIO_PPDSDR_USBL,
+ .setr = MCFGPIO_PPDSDR_USBL,
+ .clrr = MCFGPIO_PCLRR_USBL,
+ },
+ {
+ .gpio_chip = {
+ .label = "UARTH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 144,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_UARTH,
+ .podr = MCFGPIO_PODR_UARTH,
+ .ppdr = MCFGPIO_PPDSDR_UARTH,
+ .setr = MCFGPIO_PPDSDR_UARTH,
+ .clrr = MCFGPIO_PCLRR_UARTH,
+ },
+#endif
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
index 26135d92b34d..3d90e6d92459 100644
--- a/arch/m68knommu/platform/528x/Makefile
+++ b/arch/m68knommu/platform/528x/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
index a1d1a61c4fe6..6e608d1836f1 100644
--- a/arch/m68knommu/platform/528x/config.c
+++ b/arch/m68knommu/platform/528x/config.c
@@ -3,8 +3,8 @@
/*
* linux/arch/m68knommu/platform/528x/config.c
*
- * Sub-architcture dependant initialization code for the Motorola
- * 5280 and 5282 CPUs.
+ * Sub-architcture dependant initialization code for the Freescale
+ * 5280, 5281 and 5282 CPUs.
*
* Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
* Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
@@ -15,20 +15,13 @@
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
-#ifdef CONFIG_MTD_PARTITIONS
-#include <linux/mtd/partitions.h>
-#endif
-
/***************************************************************************/
static struct mcf_platform_uart m528x_uart_platform[] = {
@@ -91,23 +84,13 @@ static struct platform_device *m528x_devices[] __initdata = {
/***************************************************************************/
-#define INTC0 (MCF_MBAR + MCFICM_INTC0)
-
static void __init m528x_uart_init_line(int line, int irq)
{
u8 port;
- u32 imr;
if ((line < 0) || (line > 2))
return;
- /* level 6, line based priority */
- writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
-
- imr = readl(INTC0 + MCFINTC_IMRL);
- imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
- writel(imr, INTC0 + MCFINTC_IMRL);
-
/* make sure PUAPAR is set for UART0 and UART1 */
if (line < 2) {
port = readb(MCF_MBAR + MCF5282_GPIO_PUAPAR);
@@ -129,21 +112,8 @@ static void __init m528x_uarts_init(void)
static void __init m528x_fec_init(void)
{
- u32 imr;
u16 v16;
- /* Unmask FEC interrupts at ColdFire interrupt controller */
- writeb(0x28, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 23);
- writeb(0x27, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 27);
- writeb(0x26, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 29);
-
- imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
- imr &= ~0xf;
- writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
- imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
- imr &= ~0xff800001;
- writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
-
/* Set multi-function pins to ethernet mode for fec0 */
v16 = readw(MCF_IPSBAR + 0x100056);
writew(v16 | 0xf00, MCF_IPSBAR + 0x100056);
@@ -152,21 +122,6 @@ static void __init m528x_fec_init(void)
/***************************************************************************/
-void mcf_disableall(void)
-{
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
- *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
-}
-
-/***************************************************************************/
-
-void mcf_autovector(unsigned int vec)
-{
- /* Everything is auto-vectored on the 5272 */
-}
-
-/***************************************************************************/
-
static void m528x_cpu_reset(void)
{
local_irq_disable();
@@ -204,8 +159,6 @@ void wildfiremod_halt(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_disableall();
-
#ifdef CONFIG_WILDFIRE
mach_halt = wildfire_halt;
#endif
diff --git a/arch/m68knommu/platform/528x/gpio.c b/arch/m68knommu/platform/528x/gpio.c
new file mode 100644
index 000000000000..ec593950696a
--- /dev/null
+++ b/arch/m68knommu/platform/528x/gpio.c
@@ -0,0 +1,438 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "NQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .base = 1,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "TA",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 8,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPTA_GPTDDR,
+ .podr = MCFGPTA_GPTPORT,
+ .ppdr = MCFGPTB_GPTPORT,
+ },
+ {
+ .gpio_chip = {
+ .label = "TB",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 16,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPTB_GPTDDR,
+ .podr = MCFGPTB_GPTPORT,
+ .ppdr = MCFGPTB_GPTPORT,
+ },
+ {
+ .gpio_chip = {
+ .label = "QA",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 24,
+ .ngpio = 4,
+ },
+ .pddr = MCFQADC_DDRQA,
+ .podr = MCFQADC_PORTQA,
+ .ppdr = MCFQADC_PORTQA,
+ },
+ {
+ .gpio_chip = {
+ .label = "QB",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 4,
+ },
+ .pddr = MCFQADC_DDRQB,
+ .podr = MCFQADC_PORTQB,
+ .ppdr = MCFQADC_PORTQB,
+ },
+ {
+ .gpio_chip = {
+ .label = "A",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRA,
+ .podr = MCFGPIO_PORTA,
+ .ppdr = MCFGPIO_PORTAP,
+ .setr = MCFGPIO_SETA,
+ .clrr = MCFGPIO_CLRA,
+ },
+ {
+ .gpio_chip = {
+ .label = "B",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 48,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRB,
+ .podr = MCFGPIO_PORTB,
+ .ppdr = MCFGPIO_PORTBP,
+ .setr = MCFGPIO_SETB,
+ .clrr = MCFGPIO_CLRB,
+ },
+ {
+ .gpio_chip = {
+ .label = "C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 56,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRC,
+ .podr = MCFGPIO_PORTC,
+ .ppdr = MCFGPIO_PORTCP,
+ .setr = MCFGPIO_SETC,
+ .clrr = MCFGPIO_CLRC,
+ },
+ {
+ .gpio_chip = {
+ .label = "D",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRD,
+ .podr = MCFGPIO_PORTD,
+ .ppdr = MCFGPIO_PORTDP,
+ .setr = MCFGPIO_SETD,
+ .clrr = MCFGPIO_CLRD,
+ },
+ {
+ .gpio_chip = {
+ .label = "E",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRE,
+ .podr = MCFGPIO_PORTE,
+ .ppdr = MCFGPIO_PORTEP,
+ .setr = MCFGPIO_SETE,
+ .clrr = MCFGPIO_CLRE,
+ },
+ {
+ .gpio_chip = {
+ .label = "F",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 80,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRF,
+ .podr = MCFGPIO_PORTF,
+ .ppdr = MCFGPIO_PORTFP,
+ .setr = MCFGPIO_SETF,
+ .clrr = MCFGPIO_CLRF,
+ },
+ {
+ .gpio_chip = {
+ .label = "G",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 88,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRG,
+ .podr = MCFGPIO_PORTG,
+ .ppdr = MCFGPIO_PORTGP,
+ .setr = MCFGPIO_SETG,
+ .clrr = MCFGPIO_CLRG,
+ },
+ {
+ .gpio_chip = {
+ .label = "H",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 96,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRH,
+ .podr = MCFGPIO_PORTH,
+ .ppdr = MCFGPIO_PORTHP,
+ .setr = MCFGPIO_SETH,
+ .clrr = MCFGPIO_CLRH,
+ },
+ {
+ .gpio_chip = {
+ .label = "J",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 104,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRJ,
+ .podr = MCFGPIO_PORTJ,
+ .ppdr = MCFGPIO_PORTJP,
+ .setr = MCFGPIO_SETJ,
+ .clrr = MCFGPIO_CLRJ,
+ },
+ {
+ .gpio_chip = {
+ .label = "DD",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 112,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDRDD,
+ .podr = MCFGPIO_PORTDD,
+ .ppdr = MCFGPIO_PORTDDP,
+ .setr = MCFGPIO_SETDD,
+ .clrr = MCFGPIO_CLRDD,
+ },
+ {
+ .gpio_chip = {
+ .label = "EH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 120,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDREH,
+ .podr = MCFGPIO_PORTEH,
+ .ppdr = MCFGPIO_PORTEHP,
+ .setr = MCFGPIO_SETEH,
+ .clrr = MCFGPIO_CLREH,
+ },
+ {
+ .gpio_chip = {
+ .label = "EL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 128,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_DDREL,
+ .podr = MCFGPIO_PORTEL,
+ .ppdr = MCFGPIO_PORTELP,
+ .setr = MCFGPIO_SETEL,
+ .clrr = MCFGPIO_CLREL,
+ },
+ {
+ .gpio_chip = {
+ .label = "AS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 136,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_DDRAS,
+ .podr = MCFGPIO_PORTAS,
+ .ppdr = MCFGPIO_PORTASP,
+ .setr = MCFGPIO_SETAS,
+ .clrr = MCFGPIO_CLRAS,
+ },
+ {
+ .gpio_chip = {
+ .label = "QS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 144,
+ .ngpio = 7,
+ },
+ .pddr = MCFGPIO_DDRQS,
+ .podr = MCFGPIO_PORTQS,
+ .ppdr = MCFGPIO_PORTQSP,
+ .setr = MCFGPIO_SETQS,
+ .clrr = MCFGPIO_CLRQS,
+ },
+ {
+ .gpio_chip = {
+ .label = "SD",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 152,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_DDRSD,
+ .podr = MCFGPIO_PORTSD,
+ .ppdr = MCFGPIO_PORTSDP,
+ .setr = MCFGPIO_SETSD,
+ .clrr = MCFGPIO_CLRSD,
+ },
+ {
+ .gpio_chip = {
+ .label = "TC",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 160,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_DDRTC,
+ .podr = MCFGPIO_PORTTC,
+ .ppdr = MCFGPIO_PORTTCP,
+ .setr = MCFGPIO_SETTC,
+ .clrr = MCFGPIO_CLRTC,
+ },
+ {
+ .gpio_chip = {
+ .label = "TD",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 168,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_DDRTD,
+ .podr = MCFGPIO_PORTTD,
+ .ppdr = MCFGPIO_PORTTDP,
+ .setr = MCFGPIO_SETTD,
+ .clrr = MCFGPIO_CLRTD,
+ },
+ {
+ .gpio_chip = {
+ .label = "UA",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 176,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_DDRUA,
+ .podr = MCFGPIO_PORTUA,
+ .ppdr = MCFGPIO_PORTUAP,
+ .setr = MCFGPIO_SETUA,
+ .clrr = MCFGPIO_CLRUA,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
index cfd586860fd8..667db6598451 100644
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y += config.o
+obj-y += config.o gpio.o
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
index 39da9e9ff674..00900ac06a9c 100644
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -21,12 +21,6 @@
/***************************************************************************/
-extern unsigned int mcf_timervector;
-extern unsigned int mcf_profilevector;
-extern unsigned int mcf_timerlevel;
-
-/***************************************************************************/
-
/*
* Some platforms need software versions of the GPIO data registers.
*/
@@ -64,11 +58,11 @@ static void __init m5307_uart_init_line(int line, int irq)
if (line == 0) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+ mcf_mapirq2imr(irq, MCFINTC_UART0);
} else if (line == 1) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+ mcf_mapirq2imr(irq, MCFINTC_UART1);
}
}
@@ -83,35 +77,19 @@ static void __init m5307_uarts_init(void)
/***************************************************************************/
-void mcf_autovector(unsigned int vec)
-{
- volatile unsigned char *mbar;
-
- if ((vec >= 25) && (vec <= 31)) {
- mbar = (volatile unsigned char *) MCF_MBAR;
- vec = 0x1 << (vec - 24);
- *(mbar + MCFSIM_AVR) |= vec;
- mcf_setimr(mcf_getimr() & ~vec);
- }
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(unsigned int timer, unsigned int level)
+static void __init m5307_timers_init(void)
{
- volatile unsigned char *icrp;
- unsigned int icr, imr;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: icr = MCFSIM_TIMER2ICR; imr = MCFSIM_IMR_TIMER2; break;
- default: icr = MCFSIM_TIMER1ICR; imr = MCFSIM_IMR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (MCF_MBAR + icr);
- *icrp = MCFSIM_ICR_AUTOVEC | (level << 2) | MCFSIM_ICR_PRI3;
- mcf_setimr(mcf_getimr() & ~imr);
- }
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
}
/***************************************************************************/
@@ -129,20 +107,22 @@ void m5307_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
-
#if defined(CONFIG_NETtel) || \
defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
commandp[size-1] = 0;
- /* Different timer setup - to prevent device clash */
- mcf_timervector = 30;
- mcf_profilevector = 31;
- mcf_timerlevel = 6;
#endif
mach_reset = m5307_cpu_reset;
+ m5307_timers_init();
+ m5307_uarts_init();
+
+ /* Only support the external interrupts on their primary level */
+ mcf_mapirq2imr(25, MCFINTC_EINT1);
+ mcf_mapirq2imr(27, MCFINTC_EINT3);
+ mcf_mapirq2imr(29, MCFINTC_EINT5);
+ mcf_mapirq2imr(31, MCFINTC_EINT7);
#ifdef CONFIG_BDM_DISABLE
/*
@@ -158,7 +138,6 @@ void __init config_BSP(char *commandp, int size)
static int __init init_BSP(void)
{
- m5307_uarts_init();
platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5307/gpio.c b/arch/m68knommu/platform/5307/gpio.c
new file mode 100644
index 000000000000..8da5880e4066
--- /dev/null
+++ b/arch/m68knommu/platform/5307/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PP",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 16,
+ },
+ .pddr = MCFSIM_PADDR,
+ .podr = MCFSIM_PADAT,
+ .ppdr = MCFSIM_PADAT,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile
index e431912f5628..4cc23245bcd1 100644
--- a/arch/m68knommu/platform/532x/Makefile
+++ b/arch/m68knommu/platform/532x/Makefile
@@ -15,4 +15,4 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
#obj-y := config.o usb-mcf532x.o spi-mcf532x.o
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
index cdb761971f7a..d632948e64e5 100644
--- a/arch/m68knommu/platform/532x/config.c
+++ b/arch/m68knommu/platform/532x/config.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
@@ -31,12 +30,6 @@
/***************************************************************************/
-extern unsigned int mcf_timervector;
-extern unsigned int mcf_profilevector;
-extern unsigned int mcf_timerlevel;
-
-/***************************************************************************/
-
static struct mcf_platform_uart m532x_uart_platform[] = {
{
.mapbase = MCFUART_BASE1,
@@ -88,6 +81,7 @@ static struct platform_device m532x_fec = {
.num_resources = ARRAY_SIZE(m532x_fec_resources),
.resource = m532x_fec_resources,
};
+
static struct platform_device *m532x_devices[] __initdata = {
&m532x_uart,
&m532x_fec,
@@ -98,18 +92,11 @@ static struct platform_device *m532x_devices[] __initdata = {
static void __init m532x_uart_init_line(int line, int irq)
{
if (line == 0) {
- MCF_INTC0_ICR26 = 0x3;
- MCF_INTC0_CIMR = 26;
/* GPIO initialization */
MCF_GPIO_PAR_UART |= 0x000F;
} else if (line == 1) {
- MCF_INTC0_ICR27 = 0x3;
- MCF_INTC0_CIMR = 27;
/* GPIO initialization */
MCF_GPIO_PAR_UART |= 0x0FF0;
- } else if (line == 2) {
- MCF_INTC0_ICR28 = 0x3;
- MCF_INTC0_CIMR = 28;
}
}
@@ -125,14 +112,6 @@ static void __init m532x_uarts_init(void)
static void __init m532x_fec_init(void)
{
- /* Unmask FEC interrupts at ColdFire interrupt controller */
- MCF_INTC0_ICR36 = 0x2;
- MCF_INTC0_ICR40 = 0x2;
- MCF_INTC0_ICR42 = 0x2;
-
- MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK36 |
- MCF_INTC_IMRH_INT_MASK40 | MCF_INTC_IMRH_INT_MASK42);
-
/* Set multi-function pins to ethernet mode for fec0 */
MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
@@ -142,26 +121,6 @@ static void __init m532x_fec_init(void)
/***************************************************************************/
-void mcf_settimericr(unsigned int timer, unsigned int level)
-{
- volatile unsigned char *icrp;
- unsigned int icr;
- unsigned char irq;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: irq = 33; icr = MCFSIM_ICR_TIMER2; break;
- default: irq = 32; icr = MCFSIM_ICR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (icr);
- *icrp = level;
- mcf_enable_irq0(irq);
- }
-}
-
-/***************************************************************************/
-
static void m532x_cpu_reset(void)
{
local_irq_disable();
@@ -172,8 +131,6 @@ static void m532x_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
-
#if !defined(CONFIG_BOOTPARAM)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0x4000, 4);
@@ -185,10 +142,6 @@ void __init config_BSP(char *commandp, int size)
}
#endif
- mcf_timervector = 64+32;
- mcf_profilevector = 64+33;
- mach_reset = m532x_cpu_reset;
-
#ifdef CONFIG_BDM_DISABLE
/*
* Disable the BDM clocking. This also turns off most of the rest of
@@ -438,8 +391,8 @@ void gpio_init(void)
/* Initialize TIN3 as a GPIO output to enable the write
half of the latch */
MCF_GPIO_PAR_TIMER = 0x00;
- MCF_GPIO_PDDR_TIMER = 0x08;
- MCF_GPIO_PCLRR_TIMER = 0x0;
+ __raw_writeb(0x08, MCFGPIO_PDDR_TIMER);
+ __raw_writeb(0x00, MCFGPIO_PCLRR_TIMER);
}
diff --git a/arch/m68knommu/platform/532x/gpio.c b/arch/m68knommu/platform/532x/gpio.c
new file mode 100644
index 000000000000..184b77382c3d
--- /dev/null
+++ b/arch/m68knommu/platform/532x/gpio.c
@@ -0,0 +1,337 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PIRQ",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 8,
+ },
+ .pddr = MCFEPORT_EPDDR,
+ .podr = MCFEPORT_EPDR,
+ .ppdr = MCFEPORT_EPPDR,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 8,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FECH,
+ .podr = MCFGPIO_PODR_FECH,
+ .ppdr = MCFGPIO_PPDSDR_FECH,
+ .setr = MCFGPIO_PPDSDR_FECH,
+ .clrr = MCFGPIO_PCLRR_FECH,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 16,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_FECL,
+ .podr = MCFGPIO_PODR_FECL,
+ .ppdr = MCFGPIO_PPDSDR_FECL,
+ .setr = MCFGPIO_PPDSDR_FECL,
+ .clrr = MCFGPIO_PCLRR_FECL,
+ },
+ {
+ .gpio_chip = {
+ .label = "SSI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 24,
+ .ngpio = 5,
+ },
+ .pddr = MCFGPIO_PDDR_SSI,
+ .podr = MCFGPIO_PODR_SSI,
+ .ppdr = MCFGPIO_PPDSDR_SSI,
+ .setr = MCFGPIO_PPDSDR_SSI,
+ .clrr = MCFGPIO_PCLRR_SSI,
+ },
+ {
+ .gpio_chip = {
+ .label = "BUSCTL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 32,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BUSCTL,
+ .podr = MCFGPIO_PODR_BUSCTL,
+ .ppdr = MCFGPIO_PPDSDR_BUSCTL,
+ .setr = MCFGPIO_PPDSDR_BUSCTL,
+ .clrr = MCFGPIO_PCLRR_BUSCTL,
+ },
+ {
+ .gpio_chip = {
+ .label = "BE",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 40,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_BE,
+ .podr = MCFGPIO_PODR_BE,
+ .ppdr = MCFGPIO_PPDSDR_BE,
+ .setr = MCFGPIO_PPDSDR_BE,
+ .clrr = MCFGPIO_PCLRR_BE,
+ },
+ {
+ .gpio_chip = {
+ .label = "CS",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 49,
+ .ngpio = 5,
+ },
+ .pddr = MCFGPIO_PDDR_CS,
+ .podr = MCFGPIO_PODR_CS,
+ .ppdr = MCFGPIO_PPDSDR_CS,
+ .setr = MCFGPIO_PPDSDR_CS,
+ .clrr = MCFGPIO_PCLRR_CS,
+ },
+ {
+ .gpio_chip = {
+ .label = "PWM",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 58,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_PWM,
+ .podr = MCFGPIO_PODR_PWM,
+ .ppdr = MCFGPIO_PPDSDR_PWM,
+ .setr = MCFGPIO_PPDSDR_PWM,
+ .clrr = MCFGPIO_PCLRR_PWM,
+ },
+ {
+ .gpio_chip = {
+ .label = "FECI2C",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 64,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_FECI2C,
+ .podr = MCFGPIO_PODR_FECI2C,
+ .ppdr = MCFGPIO_PPDSDR_FECI2C,
+ .setr = MCFGPIO_PPDSDR_FECI2C,
+ .clrr = MCFGPIO_PCLRR_FECI2C,
+ },
+ {
+ .gpio_chip = {
+ .label = "UART",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 72,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_UART,
+ .podr = MCFGPIO_PODR_UART,
+ .ppdr = MCFGPIO_PPDSDR_UART,
+ .setr = MCFGPIO_PPDSDR_UART,
+ .clrr = MCFGPIO_PCLRR_UART,
+ },
+ {
+ .gpio_chip = {
+ .label = "QSPI",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 80,
+ .ngpio = 6,
+ },
+ .pddr = MCFGPIO_PDDR_QSPI,
+ .podr = MCFGPIO_PODR_QSPI,
+ .ppdr = MCFGPIO_PPDSDR_QSPI,
+ .setr = MCFGPIO_PPDSDR_QSPI,
+ .clrr = MCFGPIO_PCLRR_QSPI,
+ },
+ {
+ .gpio_chip = {
+ .label = "TIMER",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 88,
+ .ngpio = 4,
+ },
+ .pddr = MCFGPIO_PDDR_TIMER,
+ .podr = MCFGPIO_PODR_TIMER,
+ .ppdr = MCFGPIO_PPDSDR_TIMER,
+ .setr = MCFGPIO_PPDSDR_TIMER,
+ .clrr = MCFGPIO_PCLRR_TIMER,
+ },
+ {
+ .gpio_chip = {
+ .label = "LCDDATAH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 96,
+ .ngpio = 2,
+ },
+ .pddr = MCFGPIO_PDDR_LCDDATAH,
+ .podr = MCFGPIO_PODR_LCDDATAH,
+ .ppdr = MCFGPIO_PPDSDR_LCDDATAH,
+ .setr = MCFGPIO_PPDSDR_LCDDATAH,
+ .clrr = MCFGPIO_PCLRR_LCDDATAH,
+ },
+ {
+ .gpio_chip = {
+ .label = "LCDDATAM",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 104,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_LCDDATAM,
+ .podr = MCFGPIO_PODR_LCDDATAM,
+ .ppdr = MCFGPIO_PPDSDR_LCDDATAM,
+ .setr = MCFGPIO_PPDSDR_LCDDATAM,
+ .clrr = MCFGPIO_PCLRR_LCDDATAM,
+ },
+ {
+ .gpio_chip = {
+ .label = "LCDDATAL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 112,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_LCDDATAL,
+ .podr = MCFGPIO_PODR_LCDDATAL,
+ .ppdr = MCFGPIO_PPDSDR_LCDDATAL,
+ .setr = MCFGPIO_PPDSDR_LCDDATAL,
+ .clrr = MCFGPIO_PCLRR_LCDDATAL,
+ },
+ {
+ .gpio_chip = {
+ .label = "LCDCTLH",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 120,
+ .ngpio = 1,
+ },
+ .pddr = MCFGPIO_PDDR_LCDCTLH,
+ .podr = MCFGPIO_PODR_LCDCTLH,
+ .ppdr = MCFGPIO_PPDSDR_LCDCTLH,
+ .setr = MCFGPIO_PPDSDR_LCDCTLH,
+ .clrr = MCFGPIO_PCLRR_LCDCTLH,
+ },
+ {
+ .gpio_chip = {
+ .label = "LCDCTLL",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value_fast,
+ .base = 128,
+ .ngpio = 8,
+ },
+ .pddr = MCFGPIO_PDDR_LCDCTLL,
+ .podr = MCFGPIO_PODR_LCDCTLL,
+ .ppdr = MCFGPIO_PPDSDR_LCDCTLL,
+ .setr = MCFGPIO_PPDSDR_LCDCTLL,
+ .clrr = MCFGPIO_PCLRR_LCDCTLL,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile
index e6035e7a2d3f..dee62c5dbaa6 100644
--- a/arch/m68knommu/platform/5407/Makefile
+++ b/arch/m68knommu/platform/5407/Makefile
@@ -14,5 +14,5 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-y := config.o
+obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c
index b41d942bf8d0..70ea789a400c 100644
--- a/arch/m68knommu/platform/5407/config.c
+++ b/arch/m68knommu/platform/5407/config.c
@@ -20,12 +20,6 @@
/***************************************************************************/
-extern unsigned int mcf_timervector;
-extern unsigned int mcf_profilevector;
-extern unsigned int mcf_timerlevel;
-
-/***************************************************************************/
-
static struct mcf_platform_uart m5407_uart_platform[] = {
{
.mapbase = MCF_MBAR + MCFUART_BASE1,
@@ -55,11 +49,11 @@ static void __init m5407_uart_init_line(int line, int irq)
if (line == 0) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+ mcf_mapirq2imr(irq, MCFINTC_UART0);
} else if (line == 1) {
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+ mcf_mapirq2imr(irq, MCFINTC_UART1);
}
}
@@ -74,35 +68,19 @@ static void __init m5407_uarts_init(void)
/***************************************************************************/
-void mcf_autovector(unsigned int vec)
-{
- volatile unsigned char *mbar;
-
- if ((vec >= 25) && (vec <= 31)) {
- mbar = (volatile unsigned char *) MCF_MBAR;
- vec = 0x1 << (vec - 24);
- *(mbar + MCFSIM_AVR) |= vec;
- mcf_setimr(mcf_getimr() & ~vec);
- }
-}
-
-/***************************************************************************/
-
-void mcf_settimericr(unsigned int timer, unsigned int level)
+static void __init m5407_timers_init(void)
{
- volatile unsigned char *icrp;
- unsigned int icr, imr;
-
- if (timer <= 2) {
- switch (timer) {
- case 2: icr = MCFSIM_TIMER2ICR; imr = MCFSIM_IMR_TIMER2; break;
- default: icr = MCFSIM_TIMER1ICR; imr = MCFSIM_IMR_TIMER1; break;
- }
-
- icrp = (volatile unsigned char *) (MCF_MBAR + icr);
- *icrp = MCFSIM_ICR_AUTOVEC | (level << 2) | MCFSIM_ICR_PRI3;
- mcf_setimr(mcf_getimr() & ~imr);
- }
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
}
/***************************************************************************/
@@ -120,23 +98,21 @@ void m5407_cpu_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mcf_setimr(MCFSIM_IMR_MASKALL);
-
-#if defined(CONFIG_CLEOPATRA)
- /* Different timer setup - to prevent device clash */
- mcf_timervector = 30;
- mcf_profilevector = 31;
- mcf_timerlevel = 6;
-#endif
-
mach_reset = m5407_cpu_reset;
+ m5407_timers_init();
+ m5407_uarts_init();
+
+ /* Only support the external interrupts on their primary level */
+ mcf_mapirq2imr(25, MCFINTC_EINT1);
+ mcf_mapirq2imr(27, MCFINTC_EINT3);
+ mcf_mapirq2imr(29, MCFINTC_EINT5);
+ mcf_mapirq2imr(31, MCFINTC_EINT7);
}
/***************************************************************************/
static int __init init_BSP(void)
{
- m5407_uarts_init();
platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5407/gpio.c b/arch/m68knommu/platform/5407/gpio.c
new file mode 100644
index 000000000000..8da5880e4066
--- /dev/null
+++ b/arch/m68knommu/platform/5407/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "PP",
+ .request = mcf_gpio_request,
+ .free = mcf_gpio_free,
+ .direction_input = mcf_gpio_direction_input,
+ .direction_output = mcf_gpio_direction_output,
+ .get = mcf_gpio_get_value,
+ .set = mcf_gpio_set_value,
+ .ngpio = 16,
+ },
+ .pddr = MCFSIM_PADDR,
+ .podr = MCFSIM_PADAT,
+ .ppdr = MCFSIM_PADAT,
+ },
+};
+
+static int __init mcf_gpio_init(void)
+{
+ unsigned i = 0;
+ while (i < ARRAY_SIZE(mcf_gpio_chips))
+ (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+ return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
index 72e56d554f4f..b91ee85d4b5d 100644
--- a/arch/m68knommu/platform/68328/ints.c
+++ b/arch/m68knommu/platform/68328/ints.c
@@ -73,34 +73,6 @@ extern e_vector *_ramvec;
/* The number of spurious interrupts */
volatile unsigned int num_spurious;
-/*
- * This function should be called during kernel startup to initialize
- * the machine vector table.
- */
-void __init init_vectors(void)
-{
- int i;
-
- /* set up the vectors */
- for (i = 72; i < 256; ++i)
- _ramvec[i] = (e_vector) bad_interrupt;
-
- _ramvec[32] = system_call;
-
- _ramvec[65] = (e_vector) inthandler1;
- _ramvec[66] = (e_vector) inthandler2;
- _ramvec[67] = (e_vector) inthandler3;
- _ramvec[68] = (e_vector) inthandler4;
- _ramvec[69] = (e_vector) inthandler5;
- _ramvec[70] = (e_vector) inthandler6;
- _ramvec[71] = (e_vector) inthandler7;
-
- IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
-
- /* turn off all interrupts */
- IMR = ~0;
-}
-
/* The 68k family did not have a good way to determine the source
* of interrupts until later in the family. The EC000 core does
* not provide the vector number on the stack, we vector everything
@@ -163,18 +135,54 @@ void process_int(int vec, struct pt_regs *fp)
}
}
-void enable_vector(unsigned int irq)
+static void intc_irq_unmask(unsigned int irq)
{
IMR &= ~(1<<irq);
}
-void disable_vector(unsigned int irq)
+static void intc_irq_mask(unsigned int irq)
{
IMR |= (1<<irq);
}
-void ack_vector(unsigned int irq)
+static struct irq_chip intc_irq_chip = {
+ .name = "M68K-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+};
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the machine vector table.
+ */
+void __init init_IRQ(void)
{
- /* Nothing needed */
+ int i;
+
+ /* set up the vectors */
+ for (i = 72; i < 256; ++i)
+ _ramvec[i] = (e_vector) bad_interrupt;
+
+ _ramvec[32] = system_call;
+
+ _ramvec[65] = (e_vector) inthandler1;
+ _ramvec[66] = (e_vector) inthandler2;
+ _ramvec[67] = (e_vector) inthandler3;
+ _ramvec[68] = (e_vector) inthandler4;
+ _ramvec[69] = (e_vector) inthandler5;
+ _ramvec[70] = (e_vector) inthandler6;
+ _ramvec[71] = (e_vector) inthandler7;
+
+ IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
+
+ /* turn off all interrupts */
+ IMR = ~0;
+
+ for (i = 0; (i < NR_IRQS); i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &intc_irq_chip;
+ }
}
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c
index c36781157e09..1143f77caca4 100644
--- a/arch/m68knommu/platform/68360/ints.c
+++ b/arch/m68knommu/platform/68360/ints.c
@@ -37,11 +37,33 @@ extern void *_ramvec[];
/* The number of spurious interrupts */
volatile unsigned int num_spurious;
+static void intc_irq_unmask(unsigned int irq)
+{
+ pquicc->intr_cimr |= (1 << irq);
+}
+
+static void intc_irq_mask(unsigned int irq)
+{
+ pquicc->intr_cimr &= ~(1 << irq);
+}
+
+static void intc_irq_ack(unsigned int irq)
+{
+ pquicc->intr_cisr = (1 << irq);
+}
+
+static struct irq_chip intc_irq_chip = {
+ .name = "M68K-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+ .ack = intc_irq_ack,
+};
+
/*
* This function should be called during kernel startup to initialize
* the vector table.
*/
-void init_vectors(void)
+void init_IRQ(void)
{
int i;
int vba = (CPM_VECTOR_BASE<<4);
@@ -109,20 +131,12 @@ void init_vectors(void)
/* turn off all CPM interrupts */
pquicc->intr_cimr = 0x00000000;
-}
-
-void enable_vector(unsigned int irq)
-{
- pquicc->intr_cimr |= (1 << irq);
-}
-void disable_vector(unsigned int irq)
-{
- pquicc->intr_cimr &= ~(1 << irq);
-}
-
-void ack_vector(unsigned int irq)
-{
- pquicc->intr_cisr = (1 << irq);
+ for (i = 0; (i < NR_IRQS); i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &intc_irq_chip;
+ }
}
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
index 1bcb9372353f..f72a0e5d9996 100644
--- a/arch/m68knommu/platform/coldfire/Makefile
+++ b/arch/m68knommu/platform/coldfire/Makefile
@@ -15,16 +15,17 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
obj-$(CONFIG_COLDFIRE) += clk.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206) += timers.o
-obj-$(CONFIG_M5206e) += timers.o
-obj-$(CONFIG_M520x) += pit.o
-obj-$(CONFIG_M523x) += pit.o dma_timer.o
-obj-$(CONFIG_M5249) += timers.o
-obj-$(CONFIG_M527x) += pit.o
+obj-$(CONFIG_M5206) += timers.o intc.o
+obj-$(CONFIG_M5206e) += timers.o intc.o
+obj-$(CONFIG_M520x) += pit.o intc-simr.o
+obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o
+obj-$(CONFIG_M5249) += timers.o intc.o
+obj-$(CONFIG_M527x) += pit.o intc-2.o
obj-$(CONFIG_M5272) += timers.o
-obj-$(CONFIG_M528x) += pit.o
-obj-$(CONFIG_M5307) += timers.o
-obj-$(CONFIG_M532x) += timers.o
-obj-$(CONFIG_M5407) += timers.o
+obj-$(CONFIG_M528x) += pit.o intc-2.o
+obj-$(CONFIG_M5307) += timers.o intc.o
+obj-$(CONFIG_M532x) += timers.o intc-simr.o
+obj-$(CONFIG_M5407) += timers.o intc.o
+obj-y += pinmux.o gpio.o
extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/gpio.c b/arch/m68knommu/platform/coldfire/gpio.c
new file mode 100644
index 000000000000..ff0045793450
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/gpio.c
@@ -0,0 +1,127 @@
+/*
+ * Coldfire generic GPIO support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/gpio.h>
+#include <asm/pinmux.h>
+#include <asm/mcfgpio.h>
+
+#define MCF_CHIP(chip) container_of(chip, struct mcf_gpio_chip, gpio_chip)
+
+int mcf_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned long flags;
+ MCFGPIO_PORTTYPE dir;
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ local_irq_save(flags);
+ dir = mcfgpio_read(mcf_chip->pddr);
+ dir &= ~mcfgpio_bit(chip->base + offset);
+ mcfgpio_write(dir, mcf_chip->pddr);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int mcf_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ return mcfgpio_read(mcf_chip->ppdr) & mcfgpio_bit(chip->base + offset);
+}
+
+int mcf_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ unsigned long flags;
+ MCFGPIO_PORTTYPE data;
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ local_irq_save(flags);
+ /* write the value to the output latch */
+ data = mcfgpio_read(mcf_chip->podr);
+ if (value)
+ data |= mcfgpio_bit(chip->base + offset);
+ else
+ data &= ~mcfgpio_bit(chip->base + offset);
+ mcfgpio_write(data, mcf_chip->podr);
+
+ /* now set the direction to output */
+ data = mcfgpio_read(mcf_chip->pddr);
+ data |= mcfgpio_bit(chip->base + offset);
+ mcfgpio_write(data, mcf_chip->pddr);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+void mcf_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ unsigned long flags;
+ MCFGPIO_PORTTYPE data;
+
+ local_irq_save(flags);
+ data = mcfgpio_read(mcf_chip->podr);
+ if (value)
+ data |= mcfgpio_bit(chip->base + offset);
+ else
+ data &= ~mcfgpio_bit(chip->base + offset);
+ mcfgpio_write(data, mcf_chip->podr);
+ local_irq_restore(flags);
+}
+
+void mcf_gpio_set_value_fast(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ if (value)
+ mcfgpio_write(mcfgpio_bit(chip->base + offset), mcf_chip->setr);
+ else
+ mcfgpio_write(~mcfgpio_bit(chip->base + offset), mcf_chip->clrr);
+}
+
+int mcf_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ return mcf_chip->gpio_to_pinmux ?
+ mcf_pinmux_request(mcf_chip->gpio_to_pinmux[offset], 0) : 0;
+}
+
+void mcf_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+ mcf_gpio_direction_input(chip, offset);
+
+ if (mcf_chip->gpio_to_pinmux)
+ mcf_pinmux_release(mcf_chip->gpio_to_pinmux[offset], 0);
+}
+
+struct sysdev_class mcf_gpio_sysclass = {
+ .name = "gpio",
+};
+
+static int __init mcf_gpio_sysinit(void)
+{
+ return sysdev_class_register(&mcf_gpio_sysclass);
+}
+
+core_initcall(mcf_gpio_sysinit);
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c
new file mode 100644
index 000000000000..5598c8b8661f
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/intc-2.c
@@ -0,0 +1,93 @@
+/*
+ * intc-1.c
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * Each vector needs a unique priority and level asscoiated with it.
+ * We don't really care so much what they are, we don't rely on the
+ * tranditional priority interrupt scheme of the m68k/ColdFire.
+ */
+static u8 intc_intpri = 0x36;
+
+static void intc_irq_mask(unsigned int irq)
+{
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ unsigned long imraddr;
+ u32 val, imrbit;
+
+ irq -= MCFINT_VECBASE;
+ imraddr = MCF_IPSBAR;
+ imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+ imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
+ imrbit = 0x1 << (irq & 0x1f);
+
+ val = __raw_readl(imraddr);
+ __raw_writel(val | imrbit, imraddr);
+ }
+}
+
+static void intc_irq_unmask(unsigned int irq)
+{
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ unsigned long intaddr, imraddr, icraddr;
+ u32 val, imrbit;
+
+ irq -= MCFINT_VECBASE;
+ intaddr = MCF_IPSBAR;
+ intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+ imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
+ icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
+ imrbit = 0x1 << (irq & 0x1f);
+
+ /* Don't set the "maskall" bit! */
+ if ((irq & 0x20) == 0)
+ imrbit |= 0x1;
+
+ if (__raw_readb(icraddr) == 0)
+ __raw_writeb(intc_intpri--, icraddr);
+
+ val = __raw_readl(imraddr);
+ __raw_writel(val & ~imrbit, imraddr);
+ }
+}
+
+static struct irq_chip intc_irq_chip = {
+ .name = "CF-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+};
+
+void __init init_IRQ(void)
+{
+ int irq;
+
+ init_vectors();
+
+ /* Mask all interrupt sources */
+ __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+ __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
+
+ for (irq = 0; (irq < NR_IRQS); irq++) {
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = NULL;
+ irq_desc[irq].depth = 1;
+ irq_desc[irq].chip = &intc_irq_chip;
+ }
+}
+
diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c
new file mode 100644
index 000000000000..1b01e79c2f63
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/intc-simr.c
@@ -0,0 +1,78 @@
+/*
+ * intc-simr.c
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+static void intc_irq_mask(unsigned int irq)
+{
+ if (irq >= MCFINT_VECBASE) {
+ if (irq < MCFINT_VECBASE + 64)
+ __raw_writeb(irq - MCFINT_VECBASE, MCFINTC0_SIMR);
+ else if ((irq < MCFINT_VECBASE + 128) && MCFINTC1_SIMR)
+ __raw_writeb(irq - MCFINT_VECBASE - 64, MCFINTC1_SIMR);
+ }
+}
+
+static void intc_irq_unmask(unsigned int irq)
+{
+ if (irq >= MCFINT_VECBASE) {
+ if (irq < MCFINT_VECBASE + 64)
+ __raw_writeb(irq - MCFINT_VECBASE, MCFINTC0_CIMR);
+ else if ((irq < MCFINT_VECBASE + 128) && MCFINTC1_CIMR)
+ __raw_writeb(irq - MCFINT_VECBASE - 64, MCFINTC1_CIMR);
+ }
+}
+
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+ if (irq >= MCFINT_VECBASE) {
+ if (irq < MCFINT_VECBASE + 64)
+ __raw_writeb(5, MCFINTC0_ICR0 + irq - MCFINT_VECBASE);
+ else if ((irq < MCFINT_VECBASE) && MCFINTC1_ICR0)
+ __raw_writeb(5, MCFINTC1_ICR0 + irq - MCFINT_VECBASE - 64);
+ }
+ return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+ .name = "CF-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+ .set_type = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+ int irq;
+
+ init_vectors();
+
+ /* Mask all interrupt sources */
+ __raw_writeb(0xff, MCFINTC0_SIMR);
+ if (MCFINTC1_SIMR)
+ __raw_writeb(0xff, MCFINTC1_SIMR);
+
+ for (irq = 0; (irq < NR_IRQS); irq++) {
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = NULL;
+ irq_desc[irq].depth = 1;
+ irq_desc[irq].chip = &intc_irq_chip;
+ intc_irq_set_type(irq, 0);
+ }
+}
+
diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c
new file mode 100644
index 000000000000..506df2c18fb6
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/intc.c
@@ -0,0 +1,153 @@
+/*
+ * intc.c -- support for the old ColdFire interrupt controller
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ * The mapping of irq number to a mask register bit is not one-to-one.
+ * The irq numbers are either based on "level" of interrupt or fixed
+ * for an autovector-able interrupt. So we keep a local data structure
+ * that maps from irq to mask register. Not all interrupts will have
+ * an IMR bit.
+ */
+unsigned char mcf_irq2imr[NR_IRQS];
+
+/*
+ * Define the miniumun and maximum external interrupt numbers.
+ * This is also used as the "level" interrupt numbers.
+ */
+#define EIRQ1 25
+#define EIRQ7 31
+
+/*
+ * In the early version 2 core ColdFire parts the IMR register was 16 bits
+ * in size. Version 3 (and later version 2) core parts have a 32 bit
+ * sized IMR register. Provide some size independant methods to access the
+ * IMR register.
+ */
+#ifdef MCFSIM_IMR_IS_16BITS
+
+void mcf_setimr(int index)
+{
+ u16 imr;
+ imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+ __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+ u16 imr;
+ imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+ __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+ u16 imr;
+ imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+ imr |= mask;
+ __raw_writew(imr, MCF_MBAR + MCFSIM_IMR);
+}
+
+#else
+
+void mcf_setimr(int index)
+{
+ u32 imr;
+ imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+ __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+ u32 imr;
+ imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+ __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+ u32 imr;
+ imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+ imr |= mask;
+ __raw_writel(imr, MCF_MBAR + MCFSIM_IMR);
+}
+
+#endif
+
+/*
+ * Interrupts can be "vectored" on the ColdFire cores that support this old
+ * interrupt controller. That is, the device raising the interrupt can also
+ * supply the vector number to interrupt through. The AVR register of the
+ * interrupt controller enables or disables this for each external interrupt,
+ * so provide generic support for this. Setting this up is out-of-band for
+ * the interrupt system API's, and needs to be done by the driver that
+ * supports this device. Very few devices actually use this.
+ */
+void mcf_autovector(int irq)
+{
+#ifdef MCFSIM_AVR
+ if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
+ u8 avec;
+ avec = __raw_readb(MCF_MBAR + MCFSIM_AVR);
+ avec |= (0x1 << (irq - EIRQ1 + 1));
+ __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR);
+ }
+#endif
+}
+
+static void intc_irq_mask(unsigned int irq)
+{
+ if (mcf_irq2imr[irq])
+ mcf_setimr(mcf_irq2imr[irq]);
+}
+
+static void intc_irq_unmask(unsigned int irq)
+{
+ if (mcf_irq2imr[irq])
+ mcf_clrimr(mcf_irq2imr[irq]);
+}
+
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+ return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+ .name = "CF-INTC",
+ .mask = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+ .set_type = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+ int irq;
+
+ init_vectors();
+ mcf_maskimr(0xffffffff);
+
+ for (irq = 0; (irq < NR_IRQS); irq++) {
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = NULL;
+ irq_desc[irq].depth = 1;
+ irq_desc[irq].chip = &intc_irq_chip;
+ intc_irq_set_type(irq, 0);
+ }
+}
+
diff --git a/arch/m68knommu/platform/coldfire/pinmux.c b/arch/m68knommu/platform/coldfire/pinmux.c
new file mode 100644
index 000000000000..8c62b825939f
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/pinmux.c
@@ -0,0 +1,28 @@
+/*
+ * Coldfire generic GPIO pinmux support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/pinmux.h>
+
+int mcf_pinmux_request(unsigned pinmux, unsigned func)
+{
+ return 0;
+}
+
+void mcf_pinmux_release(unsigned pinmux, unsigned func)
+{
+}
diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c
index 61b96211f8ff..d8720ee34510 100644
--- a/arch/m68knommu/platform/coldfire/pit.c
+++ b/arch/m68knommu/platform/coldfire/pit.c
@@ -32,7 +32,6 @@
*/
#define FREQ ((MCF_CLK / 2) / 64)
#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a))
-#define INTC0 (MCF_IPSBAR + MCFICM_INTC0)
#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
static u32 pit_cnt;
@@ -154,8 +153,6 @@ static struct clocksource pit_clk = {
void hw_timer_init(void)
{
- u32 imr;
-
cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
cf_pit_clockevent.max_delta_ns =
@@ -166,11 +163,6 @@ void hw_timer_init(void)
setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
- __raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1);
- imr = __raw_readl(INTC0 + MCFPIT_IMR);
- imr &= ~MCFPIT_IMR_IBIT;
- __raw_writel(imr, INTC0 + MCFPIT_IMR);
-
pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
clocksource_register(&pit_clk);
}
diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c
index 1ba8a3731653..2304d736c701 100644
--- a/arch/m68knommu/platform/coldfire/timers.c
+++ b/arch/m68knommu/platform/coldfire/timers.c
@@ -31,19 +31,9 @@
#define TA(a) (MCF_MBAR + MCFTIMER_BASE1 + (a))
/*
- * Default the timer and vector to use for ColdFire. Some ColdFire
- * CPU's and some boards may want different. Their sub-architecture
- * startup code (in config.c) can change these if they want.
- */
-unsigned int mcf_timervector = 29;
-unsigned int mcf_profilevector = 31;
-unsigned int mcf_timerlevel = 5;
-
-/*
* These provide the underlying interrupt vector support.
* Unfortunately it is a little different on each ColdFire.
*/
-extern void mcf_settimericr(int timer, int level);
void coldfire_profile_init(void);
#if defined(CONFIG_M532x)
@@ -107,8 +97,6 @@ static struct clocksource mcftmr_clk = {
void hw_timer_init(void)
{
- setup_irq(mcf_timervector, &mcftmr_timer_irq);
-
__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
mcftmr_cycles_per_jiffy = FREQ / HZ;
/*
@@ -124,7 +112,7 @@ void hw_timer_init(void)
mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);
clocksource_register(&mcftmr_clk);
- mcf_settimericr(1, mcf_timerlevel);
+ setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
#ifdef CONFIG_HIGHPROFILE
coldfire_profile_init();
@@ -171,8 +159,6 @@ void coldfire_profile_init(void)
printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
PROFILEHZ);
- setup_irq(mcf_profilevector, &coldfire_profile_irq);
-
/* Set up TIMER 2 as high speed profile clock */
__raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
@@ -180,7 +166,7 @@ void coldfire_profile_init(void)
__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
- mcf_settimericr(2, 7);
+ setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
}
/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/vectors.c b/arch/m68knommu/platform/coldfire/vectors.c
index bdca0297fa9a..a21d3f870b7a 100644
--- a/arch/m68knommu/platform/coldfire/vectors.c
+++ b/arch/m68knommu/platform/coldfire/vectors.c
@@ -1,7 +1,7 @@
/***************************************************************************/
/*
- * linux/arch/m68knommu/platform/5307/vectors.c
+ * linux/arch/m68knommu/platform/coldfire/vectors.c
*
* Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
*/
@@ -15,7 +15,6 @@
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
#include <asm/mcfwdebug.h>
/***************************************************************************/
@@ -79,20 +78,3 @@ void __init init_vectors(void)
}
/***************************************************************************/
-
-void enable_vector(unsigned int irq)
-{
- /* Currently no action on ColdFire */
-}
-
-void disable_vector(unsigned int irq)
-{
- /* Currently no action on ColdFire */
-}
-
-void ack_vector(unsigned int irq)
-{
- /* Currently no action on ColdFire */
-}
-
-/***************************************************************************/
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index d0bcf80a1136..8439598d4655 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -6,14 +6,16 @@ endif
# What CPU vesion are we building for, and crack it open
# as major.minor.rev
-CPU_VER=$(subst ",,$(CONFIG_XILINX_MICROBLAZE0_HW_VER) )
-CPU_MAJOR=$(shell echo $(CPU_VER) | cut -d '.' -f 1)
-CPU_MINOR=$(shell echo $(CPU_VER) | cut -d '.' -f 2)
-CPU_REV=$(shell echo $(CPU_VER) | cut -d '.' -f 3)
+CPU_VER := $(shell echo $(CONFIG_XILINX_MICROBLAZE0_HW_VER))
+CPU_MAJOR := $(shell echo $(CPU_VER) | cut -d '.' -f 1)
+CPU_MINOR := $(shell echo $(CPU_VER) | cut -d '.' -f 2)
+CPU_REV := $(shell echo $(CPU_VER) | cut -d '.' -f 3)
export CPU_VER CPU_MAJOR CPU_MINOR CPU_REV
# Use cpu-related CONFIG_ vars to set compile options.
+# The various CONFIG_XILINX cpu features options are integers 0/1/2...
+# rather than bools y/n
# Work out HW multipler support. This is icky.
# 1. Spartan2 has no HW multiplers.
@@ -34,30 +36,29 @@ CPUFLAGS-$(CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR) += -mxl-pattern-compare
CPUFLAGS-1 += $(call cc-option,-mcpu=v$(CPU_VER))
-# The various CONFIG_XILINX cpu features options are integers 0/1/2...
-# rather than bools y/n
-
# r31 holds current when in kernel mode
-CFLAGS_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
+KBUILD_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
LDFLAGS :=
LDFLAGS_vmlinux :=
-LDFLAGS_BLOB := --format binary --oformat elf32-microblaze
-LIBGCC := $(shell $(CC) $(CFLAGS_KERNEL) -print-libgcc-file-name)
+LIBGCC := $(shell $(CC) $(KBUILD_KERNEL) -print-libgcc-file-name)
-head-y := arch/microblaze/kernel/head.o
-libs-y += arch/microblaze/lib/ $(LIBGCC)
-core-y += arch/microblaze/kernel/ arch/microblaze/mm/ \
- arch/microblaze/platform/
+head-y := arch/microblaze/kernel/head.o
+libs-y += arch/microblaze/lib/
+libs-y += $(LIBGCC)
+core-y += arch/microblaze/kernel/
+core-y += arch/microblaze/mm/
+core-y += arch/microblaze/platform/
-boot := arch/$(ARCH)/boot
+boot := arch/microblaze/boot
# defines filename extension depending memory management type
ifeq ($(CONFIG_MMU),)
-MMUEXT := -nommu
+MMU := -nommu
endif
-export MMUEXT
+
+export MMU
all: linux.bin
diff --git a/arch/microblaze/include/asm/device.h b/arch/microblaze/include/asm/device.h
index c042830793ed..30286db27c1c 100644
--- a/arch/microblaze/include/asm/device.h
+++ b/arch/microblaze/include/asm/device.h
@@ -16,6 +16,9 @@ struct dev_archdata {
struct device_node *of_node;
};
+struct pdev_archdata {
+};
+
#endif /* _ASM_MICROBLAZE_DEVICE_H */
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index 5c173424d074..7c3ec13b44d8 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -14,7 +14,6 @@
#include <asm/byteorder.h>
#include <asm/page.h>
#include <linux/types.h>
-#include <asm/byteorder.h>
#include <linux/mm.h> /* Get struct page {...} */
diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h
index 59a757e46ba5..b0131da1387b 100644
--- a/arch/microblaze/include/asm/pgalloc.h
+++ b/arch/microblaze/include/asm/pgalloc.h
@@ -180,7 +180,7 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
__free_page(ptepage);
}
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
#define pmd_populate(mm, pmd, pte) (pmd_val(*(pmd)) = page_address(pte))
@@ -193,7 +193,7 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
*/
#define pmd_alloc_one(mm, address) ({ BUG(); ((pmd_t *)2); })
/*#define pmd_free(mm, x) do { } while (0)*/
-#define __pmd_free_tlb(tlb, x) do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
extern int do_check_pgt_cache(int, int);
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index 4c57a586a989..cc3a4dfc3eaa 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -185,6 +185,7 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/* Definitions for MicroBlaze. */
#define _PAGE_GUARDED 0x001 /* G: page is guarded from prefetch */
+#define _PAGE_FILE 0x001 /* when !present: nonlinear file mapping */
#define _PAGE_PRESENT 0x002 /* software: PTE contains a translation */
#define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */
#define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */
@@ -320,8 +321,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-/* FIXME */
-static inline int pte_file(pte_t pte) { return 0; }
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -488,7 +488,7 @@ static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
/* Encode and decode a nonlinear file mapping entry */
#define PTE_FILE_MAX_BITS 29
#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
-#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) })
+#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index 20f7b3a926e8..37e6f305a68e 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -16,6 +16,18 @@
#define _ASM_MICROBLAZE_PROM_H
#ifdef __KERNEL__
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
+#define OF_DT_END_NODE 0x2 /* End node */
+#define OF_DT_PROP 0x3 /* Property: name off, size, content */
+#define OF_DT_NOP 0x4 /* nop */
+#define OF_DT_END 0x9
+
+#define OF_DT_VERSION 0x10
+
+#ifndef __ASSEMBLY__
+
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
@@ -29,16 +41,6 @@
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size, content */
-#define OF_DT_NOP 0x4 /* nop */
-#define OF_DT_END 0x9
-
-#define OF_DT_VERSION 0x10
-
/*
* This is what gets passed to the kernel by prom_init or kexec
*
@@ -309,5 +311,6 @@ extern void __iomem *of_iomap(struct device_node *device, int index);
*/
#include <linux/of.h>
+#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_PROM_H */
diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h
index c472d2801132..e8abd4a0349c 100644
--- a/arch/microblaze/include/asm/tlb.h
+++ b/arch/microblaze/include/asm/tlb.h
@@ -11,7 +11,7 @@
#ifndef _ASM_MICROBLAZE_TLB_H
#define _ASM_MICROBLAZE_TLB_H
-#define tlb_flush(tlb) do {} while (0)
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
#include <asm-generic/tlb.h>
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 65adad61e7e9..5431b4631a7a 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -189,7 +189,7 @@ extern long strnlen_user(const char *src, long count);
#define __put_user(x, ptr) \
({ \
- __typeof__(*(ptr)) __gu_val = x; \
+ __typeof__(*(ptr)) volatile __gu_val = (x); \
long __gu_err = 0; \
switch (sizeof(__gu_val)) { \
case 1: \
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index f4a5e19a20eb..d487729683de 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -17,4 +17,4 @@ obj-$(CONFIG_HEART_BEAT) += heartbeat.o
obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU) += misc.o
-obj-y += entry$(MMUEXT).o
+obj-y += entry$(MMU).o
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
index 153f57c57b6d..c259786e7faa 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -22,7 +22,7 @@
#define CI(c, p) { ci->c = PVR_##p(pvr); }
#define err_printk(x) \
- early_printk("ERROR: Microblaze " x " - different for PVR and DTS\n");
+ early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
{
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
index 450ca6bb828d..adb448f93d5f 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-static.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c
@@ -18,7 +18,7 @@ static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY;
static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER;
#define err_printk(x) \
- early_printk("ERROR: Microblaze " x "- different for kernel and DTS\n");
+ early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n");
void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
{
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index a10bea119b94..c411c6757deb 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -26,6 +26,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"7.10.b", 0x09},
{"7.10.c", 0x0a},
{"7.10.d", 0x0b},
+ {"7.20.a", 0x0c},
+ {"7.20.b", 0x0d},
/* FIXME There is no keycode defined in MBV for these versions */
{"2.10.a", 0x10},
{"3.00.a", 0x20},
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index e568d6ec621b..e41c6ce2a7be 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -31,6 +31,7 @@
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/page.h>
+#include <asm/prom.h> /* for OF_DT_HEADER */
#ifdef CONFIG_MMU
#include <asm/setup.h> /* COMMAND_LINE_SIZE */
@@ -54,11 +55,19 @@ ENTRY(_start)
andi r1, r1, ~2
mts rmsr, r1
-/* save fdt to kernel location */
-/* r7 stores pointer to fdt blob */
- beqi r7, no_fdt_arg
+/* r7 may point to an FDT, or there may be one linked in.
+ if it's in r7, we've got to save it away ASAP.
+ We ensure r7 points to a valid FDT, just in case the bootloader
+ is broken or non-existent */
+ beqi r7, no_fdt_arg /* NULL pointer? don't copy */
+ lw r11, r0, r7 /* Does r7 point to a */
+ rsubi r11, r11, OF_DT_HEADER /* valid FDT? */
+ beqi r11, _prepare_copy_fdt
+ or r7, r0, r0 /* clear R7 when not valid DTB */
+ bnei r11, no_fdt_arg /* No - get out of here */
+_prepare_copy_fdt:
or r11, r0, r0 /* incremment */
- ori r4, r0, TOPHYS(_fdt_start) /* save bram context */
+ ori r4, r0, TOPHYS(_fdt_start)
ori r3, r0, (0x4000 - 4)
_copy_fdt:
lw r12, r7, r11 /* r12 = r7 + r11 */
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index 9d591cd74fc2..3288c9737671 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -74,6 +74,7 @@
#include <asm/mmu.h>
#include <asm/pgtable.h>
+#include <asm/signal.h>
#include <asm/asm-offsets.h>
/* Helpful Macros */
@@ -428,19 +429,9 @@ handle_unaligned_ex:
mfs r17, rbtr; /* ESR[DS] set - return address in BTR */
nop
_no_delayslot:
-#endif
-
-#ifdef CONFIG_MMU
- /* Check if unaligned address is last on a 4k page */
- andi r5, r4, 0xffc
- xori r5, r5, 0xffc
- bnei r5, _unaligned_ex2
- _unaligned_ex1:
- RESTORE_STATE;
-/* Another page must be accessed or physical address not in page table */
- bri unaligned_data_trap
-
- _unaligned_ex2:
+ /* jump to high level unaligned handler */
+ RESTORE_STATE;
+ bri unaligned_data_trap
#endif
andi r6, r3, 0x3E0; /* Mask and extract the register operand */
srl r6, r6; /* r6 >> 5 */
@@ -450,45 +441,6 @@ _no_delayslot:
srl r6, r6;
/* Store the register operand in a temporary location */
sbi r6, r0, TOPHYS(ex_reg_op);
-#ifdef CONFIG_MMU
- /* Get physical address */
- /* If we are faulting a kernel address, we have to use the
- * kernel page tables.
- */
- ori r5, r0, CONFIG_KERNEL_START
- cmpu r5, r4, r5
- bgti r5, _unaligned_ex3
- ori r5, r0, swapper_pg_dir
- bri _unaligned_ex4
-
- /* Get the PGD for the current thread. */
-_unaligned_ex3: /* user thread */
- addi r5 ,CURRENT_TASK, TOPHYS(0); /* get current task address */
- lwi r5, r5, TASK_THREAD + PGDIR
-_unaligned_ex4:
- tophys(r5,r5)
- BSRLI(r6,r4,20) /* Create L1 (pgdir/pmd) address */
- andi r6, r6, 0xffc
-/* Assume pgdir aligned on 4K boundary, no need for "andi r5,r5,0xfffff003" */
- or r5, r5, r6
- lwi r6, r5, 0 /* Get L1 entry */
- andi r5, r6, 0xfffff000 /* Extract L2 (pte) base address. */
- beqi r5, _unaligned_ex1 /* Bail if no table */
-
- tophys(r5,r5)
- BSRLI(r6,r4,10) /* Compute PTE address */
- andi r6, r6, 0xffc
- andi r5, r5, 0xfffff003
- or r5, r5, r6
- lwi r5, r5, 0 /* Get Linux PTE */
-
- andi r6, r5, _PAGE_PRESENT
- beqi r6, _unaligned_ex1 /* Bail if no page */
-
- andi r5, r5, 0xfffff000 /* Extract RPN */
- andi r4, r4, 0x00000fff /* Extract offset */
- or r4, r4, r5 /* Create physical address */
-#endif /* CONFIG_MMU */
andi r6, r3, 0x400; /* Extract ESR[S] */
bnei r6, ex_sw;
@@ -959,15 +911,15 @@ _unaligned_data_exception:
andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */
ex_lw_vm:
beqid r6, ex_lhw_vm;
- lbui r5, r4, 0; /* Exception address in r4 - delay slot */
+load1: lbui r5, r4, 0; /* Exception address in r4 - delay slot */
/* Load a word, byte-by-byte from destination address and save it in tmp space*/
la r6, r0, ex_tmp_data_loc_0;
sbi r5, r6, 0;
- lbui r5, r4, 1;
+load2: lbui r5, r4, 1;
sbi r5, r6, 1;
- lbui r5, r4, 2;
+load3: lbui r5, r4, 2;
sbi r5, r6, 2;
- lbui r5, r4, 3;
+load4: lbui r5, r4, 3;
sbi r5, r6, 3;
brid ex_lw_tail_vm;
/* Get the destination register value into r3 - delay slot */
@@ -977,7 +929,7 @@ ex_lhw_vm:
* save it in tmp space */
la r6, r0, ex_tmp_data_loc_0;
sbi r5, r6, 0;
- lbui r5, r4, 1;
+load5: lbui r5, r4, 1;
sbi r5, r6, 1;
lhui r3, r6, 0; /* Get the destination register value into r3 */
ex_lw_tail_vm:
@@ -996,22 +948,53 @@ ex_sw_tail_vm:
swi r3, r5, 0; /* Get the word - delay slot */
/* Store the word, byte-by-byte into destination address */
lbui r3, r5, 0;
- sbi r3, r4, 0;
+store1: sbi r3, r4, 0;
lbui r3, r5, 1;
- sbi r3, r4, 1;
+store2: sbi r3, r4, 1;
lbui r3, r5, 2;
- sbi r3, r4, 2;
+store3: sbi r3, r4, 2;
lbui r3, r5, 3;
brid ret_from_exc;
- sbi r3, r4, 3; /* Delay slot */
+store4: sbi r3, r4, 3; /* Delay slot */
ex_shw_vm:
/* Store the lower half-word, byte-by-byte into destination address */
lbui r3, r5, 2;
- sbi r3, r4, 0;
+store5: sbi r3, r4, 0;
lbui r3, r5, 3;
brid ret_from_exc;
- sbi r3, r4, 1; /* Delay slot */
+store6: sbi r3, r4, 1; /* Delay slot */
ex_sw_end_vm: /* Exception handling of store word, ends. */
+
+/* We have to prevent cases that get/put_user macros get unaligned pointer
+ * to bad page area. We have to find out which origin instruction caused it
+ * and called fixup for that origin instruction not instruction in unaligned
+ * handler */
+ex_unaligned_fixup:
+ ori r5, r7, 0 /* setup pointer to pt_regs */
+ lwi r6, r7, PT_PC; /* faulting address is one instruction above */
+ addik r6, r6, -4 /* for finding proper fixup */
+ swi r6, r7, PT_PC; /* a save back it to PT_PC */
+ addik r7, r0, SIGSEGV
+ /* call bad_page_fault for finding aligned fixup, fixup address is saved
+ * in PT_PC which is used as return address from exception */
+ la r15, r0, ret_from_exc-8 /* setup return address */
+ brid bad_page_fault
+ nop
+
+/* We prevent all load/store because it could failed any attempt to access */
+.section __ex_table,"a";
+ .word load1,ex_unaligned_fixup;
+ .word load2,ex_unaligned_fixup;
+ .word load3,ex_unaligned_fixup;
+ .word load4,ex_unaligned_fixup;
+ .word load5,ex_unaligned_fixup;
+ .word store1,ex_unaligned_fixup;
+ .word store2,ex_unaligned_fixup;
+ .word store3,ex_unaligned_fixup;
+ .word store4,ex_unaligned_fixup;
+ .word store5,ex_unaligned_fixup;
+ .word store6,ex_unaligned_fixup;
+.previous;
.end _unaligned_data_exception
#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/kernel/module.c b/arch/microblaze/kernel/module.c
index 51414171326f..5a45b1adfef1 100644
--- a/arch/microblaze/kernel/module.c
+++ b/arch/microblaze/kernel/module.c
@@ -57,7 +57,6 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
unsigned long int *location;
- unsigned long int locoffs;
unsigned long int value;
#if __GNUC__ < 4
unsigned long int old_value;
@@ -113,10 +112,12 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
break;
case R_MICROBLAZE_64_PCREL:
- locoffs = (location[0] & 0xFFFF) << 16 |
+#if __GNUC__ < 4
+ old_value = (location[0] & 0xFFFF) << 16 |
(location[1] & 0xFFFF);
- value -= (unsigned long int)(location) + 4 +
- locoffs;
+ value -= old_value;
+#endif
+ value -= (unsigned long int)(location) + 4;
location[0] = (location[0] & 0xFFFF0000) |
(value >> 16);
location[1] = (location[1] & 0xFFFF0000) |
@@ -125,6 +126,14 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
value);
break;
+ case R_MICROBLAZE_32_PCREL_LO:
+ pr_debug("R_MICROBLAZE_32_PCREL_LO\n");
+ break;
+
+ case R_MICROBLAZE_64_NONE:
+ pr_debug("R_MICROBLAZE_NONE\n");
+ break;
+
case R_MICROBLAZE_NONE:
pr_debug("R_MICROBLAZE_NONE\n");
break;
@@ -133,7 +142,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
printk(KERN_ERR "module %s: "
"Unknown relocation: %u\n",
module->name,
- ELF32_R_TYPE(rela->r_info));
+ ELF32_R_TYPE(rela[i].r_info));
return -ENOEXEC;
}
}
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 8709bea09604..2a97bf513b64 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -138,8 +138,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
setup_early_printk(NULL);
#endif
- early_printk("Ramdisk addr 0x%08x, FDT 0x%08x\n", ram, fdt);
- printk(KERN_NOTICE "Found FDT at 0x%08x\n", fdt);
+ early_printk("Ramdisk addr 0x%08x, ", ram);
+ if (fdt)
+ early_printk("FDT at 0x%08x\n", fdt);
+ else
+ early_printk("Compiled-in FDT at 0x%08x\n",
+ (unsigned int)_fdt_start);
#ifdef CONFIG_MTD_UCLINUX
early_printk("Found romfs @ 0x%08x (0x%08x)\n",
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c
index e000bce09b2b..b96f1682bb24 100644
--- a/arch/microblaze/kernel/sys_microblaze.c
+++ b/arch/microblaze/kernel/sys_microblaze.c
@@ -33,105 +33,6 @@
#include <linux/unistd.h>
#include <asm/syscalls.h>
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly. This will be remove with new toolchain.
- */
-asmlinkage long
-sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
-{
- int version, ret;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- ret = -EINVAL;
- switch (call) {
- case SEMOP:
- ret = sys_semop(first, (struct sembuf *)ptr, second);
- break;
- case SEMGET:
- ret = sys_semget(first, second, third);
- break;
- case SEMCTL:
- {
- union semun fourth;
-
- if (!ptr)
- break;
- ret = (access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
- || (get_user(fourth.__pad, (void **)ptr)) ;
- if (ret)
- break;
- ret = sys_semctl(first, second, third, fourth);
- break;
- }
- case MSGSND:
- ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third);
- break;
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
-
- if (!ptr)
- break;
- ret = (access_ok(VERIFY_READ, ptr, sizeof(tmp))
- ? 0 : -EFAULT) || copy_from_user(&tmp,
- (struct ipc_kludge *) ptr, sizeof(tmp));
- if (ret)
- break;
- ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp,
- third);
- break;
- }
- default:
- ret = sys_msgrcv(first, (struct msgbuf *) ptr,
- second, fifth, third);
- break;
- }
- break;
- case MSGGET:
- ret = sys_msgget((key_t) first, second);
- break;
- case MSGCTL:
- ret = sys_msgctl(first, second, (struct msqid_ds *) ptr);
- break;
- case SHMAT:
- switch (version) {
- default: {
- ulong raddr;
- ret = access_ok(VERIFY_WRITE, (ulong *) third,
- sizeof(ulong)) ? 0 : -EFAULT;
- if (ret)
- break;
- ret = do_shmat(first, (char *) ptr, second, &raddr);
- if (ret)
- break;
- ret = put_user(raddr, (ulong *) third);
- break;
- }
- case 1: /* iBCS2 emulator entry point */
- if (!segment_eq(get_fs(), get_ds()))
- break;
- ret = do_shmat(first, (char *) ptr, second,
- (ulong *) third);
- break;
- }
- break;
- case SHMDT:
- ret = sys_shmdt((char *)ptr);
- break;
- case SHMGET:
- ret = sys_shmget(first, second, third);
- break;
- case SHMCTL:
- ret = sys_shmctl(first, second, (struct shmid_ds *) ptr);
- break;
- }
- return ret;
-}
asmlinkage long microblaze_vfork(struct pt_regs *regs)
{
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index 31b32a6c5f4e..216db817beb6 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -121,7 +121,7 @@ ENTRY(sys_call_table)
.long sys_wait4
.long sys_swapoff /* 115 */
.long sys_sysinfo
- .long sys_ipc
+ .long sys_ni_syscall /* old sys_ipc */
.long sys_fsync
.long sys_ni_syscall /* sys_sigreturn_wrapper */
.long sys_clone /* 120 */
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index d34d38dcd12c..ec5fa91a48d8 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -23,8 +23,8 @@ SECTIONS {
_stext = . ;
*(.text .text.*)
*(.fixup)
-
- *(.exitcall.exit)
+ EXIT_TEXT
+ EXIT_CALL
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
@@ -162,4 +162,6 @@ SECTIONS {
}
. = ALIGN(4096);
_end = .;
+
+ DISCARDS
}
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index 956607a63f4c..d9d249a66ff2 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -69,7 +69,7 @@ static int store_updates_sp(struct pt_regs *regs)
* It is called from do_page_fault above and from some of the procedures
* in traps.c.
*/
-static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
{
const struct exception_table_entry *fixup;
/* MS: no context */
@@ -122,15 +122,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
}
#endif /* CONFIG_KGDB */
- if (in_atomic() || mm == NULL) {
- /* FIXME */
- if (kernel_mode(regs)) {
- printk(KERN_EMERG
- "Page fault in kernel mode - Oooou!!! pid %d\n",
- current->pid);
- _exception(SIGSEGV, regs, code, address);
- return;
- }
+ if (in_atomic() || !mm) {
+ if (kernel_mode(regs))
+ goto bad_area_nosemaphore;
+
/* in_atomic() in user mode is really bad,
as is current->mm == NULL. */
printk(KERN_EMERG "Page fault in user mode with "
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 33fbae79af5e..7e94a49224d7 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -89,7 +89,7 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = {
.irq = AU1000_RTC_MATCH2_INT,
.set_next_event = au1x_rtcmatch2_set_next_event,
.set_mode = au1x_rtcmatch2_set_mode,
- .cpumask = CPU_MASK_ALL_PTR,
+ .cpumask = cpu_all_mask,
};
static struct irqaction au1x_rtcmatch2_irqaction = {
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index d6903c3f3d51..7c0528b0e34c 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -14,5 +14,9 @@ obj-y += dma-octeon.o flash_setup.o
obj-y += octeon-memcpy.o
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_PCI) += pci-common.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_PCI) += pcie.o
+obj-$(CONFIG_PCI_MSI) += msi.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/cavium-octeon/msi.c b/arch/mips/cavium-octeon/msi.c
new file mode 100644
index 000000000000..964b03b75a8f
--- /dev/null
+++ b/arch/mips/cavium-octeon/msi.c
@@ -0,0 +1,288 @@
+/*
+ * 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) 2005-2007 Cavium Networks
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-npi-defs.h>
+#include <asm/octeon/cvmx-pci-defs.h>
+#include <asm/octeon/cvmx-npei-defs.h>
+#include <asm/octeon/cvmx-pexp-defs.h>
+
+#include "pci-common.h"
+
+/*
+ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
+ * in use.
+ */
+static uint64_t msi_free_irq_bitmask;
+
+/*
+ * Each bit in msi_multiple_irq_bitmask tells that the device using
+ * this bit in msi_free_irq_bitmask is also using the next bit. This
+ * is used so we can disable all of the MSI interrupts when a device
+ * uses multiple.
+ */
+static uint64_t msi_multiple_irq_bitmask;
+
+/*
+ * This lock controls updates to msi_free_irq_bitmask and
+ * msi_multiple_irq_bitmask.
+ */
+static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
+
+
+/**
+ * Called when a driver request MSI interrupts instead of the
+ * legacy INT A-D. This routine will allocate multiple interrupts
+ * for MSI devices that support them. A device can override this by
+ * programming the MSI control bits [6:4] before calling
+ * pci_enable_msi().
+ *
+ * @param dev Device requesting MSI interrupts
+ * @param desc MSI descriptor
+ *
+ * Returns 0 on success.
+ */
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+{
+ struct msi_msg msg;
+ uint16_t control;
+ int configured_private_bits;
+ int request_private_bits;
+ int irq;
+ int irq_step;
+ uint64_t search_mask;
+
+ /*
+ * Read the MSI config to figure out how many IRQs this device
+ * wants. Most devices only want 1, which will give
+ * configured_private_bits and request_private_bits equal 0.
+ */
+ pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
+ &control);
+
+ /*
+ * If the number of private bits has been configured then use
+ * that value instead of the requested number. This gives the
+ * driver the chance to override the number of interrupts
+ * before calling pci_enable_msi().
+ */
+ configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
+ if (configured_private_bits == 0) {
+ /* Nothing is configured, so use the hardware requested size */
+ request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
+ } else {
+ /*
+ * Use the number of configured bits, assuming the
+ * driver wanted to override the hardware request
+ * value.
+ */
+ request_private_bits = configured_private_bits;
+ }
+
+ /*
+ * The PCI 2.3 spec mandates that there are at most 32
+ * interrupts. If this device asks for more, only give it one.
+ */
+ if (request_private_bits > 5)
+ request_private_bits = 0;
+
+try_only_one:
+ /*
+ * The IRQs have to be aligned on a power of two based on the
+ * number being requested.
+ */
+ irq_step = 1 << request_private_bits;
+
+ /* Mask with one bit for each IRQ */
+ search_mask = (1 << irq_step) - 1;
+
+ /*
+ * We're going to search msi_free_irq_bitmask_lock for zero
+ * bits. This represents an MSI interrupt number that isn't in
+ * use.
+ */
+ spin_lock(&msi_free_irq_bitmask_lock);
+ for (irq = 0; irq < 64; irq += irq_step) {
+ if ((msi_free_irq_bitmask & (search_mask << irq)) == 0) {
+ msi_free_irq_bitmask |= search_mask << irq;
+ msi_multiple_irq_bitmask |= (search_mask >> 1) << irq;
+ break;
+ }
+ }
+ spin_unlock(&msi_free_irq_bitmask_lock);
+
+ /* Make sure the search for available interrupts didn't fail */
+ if (irq >= 64) {
+ if (request_private_bits) {
+ pr_err("arch_setup_msi_irq: Unable to find %d free "
+ "interrupts, trying just one",
+ 1 << request_private_bits);
+ request_private_bits = 0;
+ goto try_only_one;
+ } else
+ panic("arch_setup_msi_irq: Unable to find a free MSI "
+ "interrupt");
+ }
+
+ /* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */
+ irq += OCTEON_IRQ_MSI_BIT0;
+
+ switch (octeon_dma_bar_type) {
+ case OCTEON_DMA_BAR_TYPE_SMALL:
+ /* When not using big bar, Bar 0 is based at 128MB */
+ msg.address_lo =
+ ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
+ msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
+ case OCTEON_DMA_BAR_TYPE_BIG:
+ /* When using big bar, Bar 0 is based at 0 */
+ msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
+ msg.address_hi = (0 + CVMX_PCI_MSI_RCV) >> 32;
+ break;
+ case OCTEON_DMA_BAR_TYPE_PCIE:
+ /* When using PCIe, Bar 0 is based at 0 */
+ /* FIXME CVMX_NPEI_MSI_RCV* other than 0? */
+ msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff;
+ msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;
+ break;
+ default:
+ panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n");
+ }
+ msg.data = irq - OCTEON_IRQ_MSI_BIT0;
+
+ /* Update the number of IRQs the device has available to it */
+ control &= ~PCI_MSI_FLAGS_QSIZE;
+ control |= request_private_bits << 4;
+ pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
+ control);
+
+ set_irq_msi(irq, desc);
+ write_msi_msg(irq, &msg);
+ return 0;
+}
+
+
+/**
+ * Called when a device no longer needs its MSI interrupts. All
+ * MSI interrupts for the device are freed.
+ *
+ * @irq: The devices first irq number. There may be multple in sequence.
+ */
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ int number_irqs;
+ uint64_t bitmask;
+
+ if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_BIT63))
+ panic("arch_teardown_msi_irq: Attempted to teardown illegal "
+ "MSI interrupt (%d)", irq);
+ irq -= OCTEON_IRQ_MSI_BIT0;
+
+ /*
+ * Count the number of IRQs we need to free by looking at the
+ * msi_multiple_irq_bitmask. Each bit set means that the next
+ * IRQ is also owned by this device.
+ */
+ number_irqs = 0;
+ while ((irq+number_irqs < 64) &&
+ (msi_multiple_irq_bitmask & (1ull << (irq + number_irqs))))
+ number_irqs++;
+ number_irqs++;
+ /* Mask with one bit for each IRQ */
+ bitmask = (1 << number_irqs) - 1;
+ /* Shift the mask to the correct bit location */
+ bitmask <<= irq;
+ if ((msi_free_irq_bitmask & bitmask) != bitmask)
+ panic("arch_teardown_msi_irq: Attempted to teardown MSI "
+ "interrupt (%d) not in use", irq);
+
+ /* Checks are done, update the in use bitmask */
+ spin_lock(&msi_free_irq_bitmask_lock);
+ msi_free_irq_bitmask &= ~bitmask;
+ msi_multiple_irq_bitmask &= ~bitmask;
+ spin_unlock(&msi_free_irq_bitmask_lock);
+}
+
+
+/**
+ * Called by the interrupt handling code when an MSI interrupt
+ * occurs.
+ *
+ * @param cpl
+ * @param dev_id
+ *
+ * @return
+ */
+static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
+{
+ uint64_t msi_bits;
+ int irq;
+
+ if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE)
+ msi_bits = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_RCV0);
+ else
+ msi_bits = cvmx_read_csr(CVMX_NPI_NPI_MSI_RCV);
+ irq = fls64(msi_bits);
+ if (irq) {
+ irq += OCTEON_IRQ_MSI_BIT0 - 1;
+ if (irq_desc[irq].action) {
+ do_IRQ(irq);
+ return IRQ_HANDLED;
+ } else {
+ pr_err("Spurious MSI interrupt %d\n", irq);
+ if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
+ /* These chips have PCIe */
+ cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0,
+ 1ull << (irq -
+ OCTEON_IRQ_MSI_BIT0));
+ } else {
+ /* These chips have PCI */
+ cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV,
+ 1ull << (irq -
+ OCTEON_IRQ_MSI_BIT0));
+ }
+ }
+ }
+ return IRQ_NONE;
+}
+
+
+/**
+ * Initializes the MSI interrupt handling code
+ *
+ * @return
+ */
+int octeon_msi_initialize(void)
+{
+ int r;
+ if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
+ r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+ IRQF_SHARED,
+ "MSI[0:63]", octeon_msi_interrupt);
+ } else if (octeon_is_pci_host()) {
+ r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+ IRQF_SHARED,
+ "MSI[0:15]", octeon_msi_interrupt);
+ r += request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
+ IRQF_SHARED,
+ "MSI[16:31]", octeon_msi_interrupt);
+ r += request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
+ IRQF_SHARED,
+ "MSI[32:47]", octeon_msi_interrupt);
+ r += request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
+ IRQF_SHARED,
+ "MSI[48:63]", octeon_msi_interrupt);
+ }
+ return 0;
+}
+
+subsys_initcall(octeon_msi_initialize);
diff --git a/arch/mips/cavium-octeon/pci-common.c b/arch/mips/cavium-octeon/pci-common.c
new file mode 100644
index 000000000000..cd029f88da7f
--- /dev/null
+++ b/arch/mips/cavium-octeon/pci-common.c
@@ -0,0 +1,137 @@
+/*
+ * 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) 2005-2007 Cavium Networks
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include "pci-common.h"
+
+typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
+enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
+
+/**
+ * Map a PCI device to the appropriate interrupt line
+ *
+ * @param dev The Linux PCI device structure for the device to map
+ * @param slot The slot number for this device on __BUS 0__. Linux
+ * enumerates through all the bridges and figures out the
+ * slot on Bus 0 where this device eventually hooks to.
+ * @param pin The PCI interrupt pin read from the device, then swizzled
+ * as it goes through each bridge.
+ * @return Interrupt number for the device
+ */
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (octeon_pcibios_map_irq)
+ return octeon_pcibios_map_irq(dev, slot, pin);
+ else
+ panic("octeon_pcibios_map_irq doesn't point to a "
+ "pcibios_map_irq() function");
+}
+
+
+/**
+ * Called to perform platform specific PCI setup
+ *
+ * @param dev
+ * @return
+ */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ uint16_t config;
+ uint32_t dconfig;
+ int pos;
+ /*
+ * Force the Cache line setting to 64 bytes. The standard
+ * Linux bus scan doesn't seem to set it. Octeon really has
+ * 128 byte lines, but Intel bridges get really upset if you
+ * try and set values above 64 bytes. Value is specified in
+ * 32bit words.
+ */
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
+ /* Set latency timers for all devices */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
+
+ /* Enable reporting System errors and parity errors on all devices */
+ /* Enable parity checking and error reporting */
+ pci_read_config_word(dev, PCI_COMMAND, &config);
+ config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ pci_write_config_word(dev, PCI_COMMAND, config);
+
+ if (dev->subordinate) {
+ /* Set latency timers on sub bridges */
+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
+ /* More bridge error detection */
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
+ config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
+ }
+
+ /* Enable the PCIe normal error reporting */
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pos) {
+ /* Update Device Control */
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
+ /* Correctable Error Reporting */
+ config |= PCI_EXP_DEVCTL_CERE;
+ /* Non-Fatal Error Reporting */
+ config |= PCI_EXP_DEVCTL_NFERE;
+ /* Fatal Error Reporting */
+ config |= PCI_EXP_DEVCTL_FERE;
+ /* Unsupported Request */
+ config |= PCI_EXP_DEVCTL_URRE;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
+ }
+
+ /* Find the Advanced Error Reporting capability */
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ if (pos) {
+ /* Clear Uncorrectable Error Status */
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+ &dconfig);
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+ dconfig);
+ /* Enable reporting of all uncorrectable errors */
+ /* Uncorrectable Error Mask - turned on bits disable errors */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
+ /*
+ * Leave severity at HW default. This only controls if
+ * errors are reported as uncorrectable or
+ * correctable, not if the error is reported.
+ */
+ /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
+ /* Clear Correctable Error Status */
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
+ /* Enable reporting of all correctable errors */
+ /* Correctable Error Mask - turned on bits disable errors */
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
+ /* Advanced Error Capabilities */
+ pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
+ /* ECRC Generation Enable */
+ if (config & PCI_ERR_CAP_ECRC_GENC)
+ config |= PCI_ERR_CAP_ECRC_GENE;
+ /* ECRC Check Enable */
+ if (config & PCI_ERR_CAP_ECRC_CHKC)
+ config |= PCI_ERR_CAP_ECRC_CHKE;
+ pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
+ /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
+ /* Report all errors to the root complex */
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
+ PCI_ERR_ROOT_CMD_COR_EN |
+ PCI_ERR_ROOT_CMD_NONFATAL_EN |
+ PCI_ERR_ROOT_CMD_FATAL_EN);
+ /* Clear the Root status register */
+ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
+ }
+
+ return 0;
+}
diff --git a/arch/mips/cavium-octeon/pci-common.h b/arch/mips/cavium-octeon/pci-common.h
new file mode 100644
index 000000000000..74ae79991e45
--- /dev/null
+++ b/arch/mips/cavium-octeon/pci-common.h
@@ -0,0 +1,39 @@
+/*
+ * 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) 2005-2007 Cavium Networks
+ */
+#ifndef __OCTEON_PCI_COMMON_H__
+#define __OCTEON_PCI_COMMON_H__
+
+#include <linux/pci.h>
+
+/* Some PCI cards require delays when accessing config space. */
+#define PCI_CONFIG_SPACE_DELAY 10000
+
+/* pcibios_map_irq() is defined inside pci-common.c. All it does is call the
+ Octeon specific version pointed to by this variable. This function needs to
+ change for PCI or PCIe based hosts */
+extern typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
+
+/* The following defines are only used when octeon_dma_bar_type =
+ OCTEON_DMA_BAR_TYPE_BIG */
+#define OCTEON_PCI_BAR1_HOLE_BITS 5
+#define OCTEON_PCI_BAR1_HOLE_SIZE (1ul<<(OCTEON_PCI_BAR1_HOLE_BITS+3))
+
+enum octeon_dma_bar_type {
+ OCTEON_DMA_BAR_TYPE_INVALID,
+ OCTEON_DMA_BAR_TYPE_SMALL,
+ OCTEON_DMA_BAR_TYPE_BIG,
+ OCTEON_DMA_BAR_TYPE_PCIE
+};
+
+/**
+ * This is a variable to tell the DMA mapping system in dma-octeon.c
+ * how to map PCI DMA addresses.
+ */
+extern enum octeon_dma_bar_type octeon_dma_bar_type;
+
+#endif
diff --git a/arch/mips/cavium-octeon/pci.c b/arch/mips/cavium-octeon/pci.c
new file mode 100644
index 000000000000..67c0ff5e92f1
--- /dev/null
+++ b/arch/mips/cavium-octeon/pci.c
@@ -0,0 +1,568 @@
+/*
+ * 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) 2005-2007 Cavium Networks
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/time.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-npi-defs.h>
+#include <asm/octeon/cvmx-pci-defs.h>
+
+#include "pci-common.h"
+
+#define USE_OCTEON_INTERNAL_ARBITER
+
+/*
+ * Octeon's PCI controller uses did=3, subdid=2 for PCI IO
+ * addresses. Use PCI endian swapping 1 so no address swapping is
+ * necessary. The Linux io routines will endian swap the data.
+ */
+#define OCTEON_PCI_IOSPACE_BASE 0x80011a0400000000ull
+#define OCTEON_PCI_IOSPACE_SIZE (1ull<<32)
+
+/* Octeon't PCI controller uses did=3, subdid=3 for PCI memory. */
+#define OCTEON_PCI_MEMSPACE_OFFSET (0x00011b0000000000ull)
+
+/**
+ * This is the bit decoding used for the Octeon PCI controller addresses
+ */
+union octeon_pci_address {
+ uint64_t u64;
+ struct {
+ uint64_t upper:2;
+ uint64_t reserved:13;
+ uint64_t io:1;
+ uint64_t did:5;
+ uint64_t subdid:3;
+ uint64_t reserved2:4;
+ uint64_t endian_swap:2;
+ uint64_t reserved3:10;
+ uint64_t bus:8;
+ uint64_t dev:5;
+ uint64_t func:3;
+ uint64_t reg:8;
+ } s;
+};
+
+/**
+ * Return the mapping of PCI device number to IRQ line. Each
+ * character in the return string represents the interrupt
+ * line for the device at that position. Device 1 maps to the
+ * first character, etc. The characters A-D are used for PCI
+ * interrupts.
+ *
+ * Returns PCI interrupt mapping
+ */
+const char *octeon_get_pci_interrupts(void)
+{
+ /*
+ * Returning an empty string causes the interrupts to be
+ * routed based on the PCI specification. From the PCI spec:
+ *
+ * INTA# of Device Number 0 is connected to IRQW on the system
+ * board. (Device Number has no significance regarding being
+ * located on the system board or in a connector.) INTA# of
+ * Device Number 1 is connected to IRQX on the system
+ * board. INTA# of Device Number 2 is connected to IRQY on the
+ * system board. INTA# of Device Number 3 is connected to IRQZ
+ * on the system board. The table below describes how each
+ * agent's INTx# lines are connected to the system board
+ * interrupt lines. The following equation can be used to
+ * determine to which INTx# signal on the system board a given
+ * device's INTx# line(s) is connected.
+ *
+ * MB = (D + I) MOD 4 MB = System board Interrupt (IRQW = 0,
+ * IRQX = 1, IRQY = 2, and IRQZ = 3) D = Device Number I =
+ * Interrupt Number (INTA# = 0, INTB# = 1, INTC# = 2, and
+ * INTD# = 3)
+ */
+ switch (octeon_bootinfo->board_type) {
+ case CVMX_BOARD_TYPE_NAO38:
+ /* This is really the NAC38 */
+ return "AAAAADABAAAAAAAAAAAAAAAAAAAAAAAA";
+ case CVMX_BOARD_TYPE_THUNDER:
+ return "";
+ case CVMX_BOARD_TYPE_EBH3000:
+ return "";
+ case CVMX_BOARD_TYPE_EBH3100:
+ case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
+ case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
+ return "AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ case CVMX_BOARD_TYPE_BBGW_REF:
+ return "AABCD";
+ default:
+ return "";
+ }
+}
+
+/**
+ * Map a PCI device to the appropriate interrupt line
+ *
+ * @dev: The Linux PCI device structure for the device to map
+ * @slot: The slot number for this device on __BUS 0__. Linux
+ * enumerates through all the bridges and figures out the
+ * slot on Bus 0 where this device eventually hooks to.
+ * @pin: The PCI interrupt pin read from the device, then swizzled
+ * as it goes through each bridge.
+ * Returns Interrupt number for the device
+ */
+int __init octeon_pci_pcibios_map_irq(const struct pci_dev *dev,
+ u8 slot, u8 pin)
+{
+ int irq_num;
+ const char *interrupts;
+ int dev_num;
+
+ /* Get the board specific interrupt mapping */
+ interrupts = octeon_get_pci_interrupts();
+
+ dev_num = dev->devfn >> 3;
+ if (dev_num < strlen(interrupts))
+ irq_num = ((interrupts[dev_num] - 'A' + pin - 1) & 3) +
+ OCTEON_IRQ_PCI_INT0;
+ else
+ irq_num = ((slot + pin - 3) & 3) + OCTEON_IRQ_PCI_INT0;
+ return irq_num;
+}
+
+
+/**
+ * Read a value from configuration space
+ *
+ */
+static int octeon_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ union octeon_pci_address pci_addr;
+
+ pci_addr.u64 = 0;
+ pci_addr.s.upper = 2;
+ pci_addr.s.io = 1;
+ pci_addr.s.did = 3;
+ pci_addr.s.subdid = 1;
+ pci_addr.s.endian_swap = 1;
+ pci_addr.s.bus = bus->number;
+ pci_addr.s.dev = devfn >> 3;
+ pci_addr.s.func = devfn & 0x7;
+ pci_addr.s.reg = reg;
+
+#if PCI_CONFIG_SPACE_DELAY
+ udelay(PCI_CONFIG_SPACE_DELAY);
+#endif
+ switch (size) {
+ case 4:
+ *val = le32_to_cpu(cvmx_read64_uint32(pci_addr.u64));
+ return PCIBIOS_SUCCESSFUL;
+ case 2:
+ *val = le16_to_cpu(cvmx_read64_uint16(pci_addr.u64));
+ return PCIBIOS_SUCCESSFUL;
+ case 1:
+ *val = cvmx_read64_uint8(pci_addr.u64);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+
+/**
+ * Write a value to PCI configuration space
+ *
+ * @bus:
+ * @devfn:
+ * @reg:
+ * @size:
+ * @val:
+ * Returns
+ */
+static int octeon_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ union octeon_pci_address pci_addr;
+
+ pci_addr.u64 = 0;
+ pci_addr.s.upper = 2;
+ pci_addr.s.io = 1;
+ pci_addr.s.did = 3;
+ pci_addr.s.subdid = 1;
+ pci_addr.s.endian_swap = 1;
+ pci_addr.s.bus = bus->number;
+ pci_addr.s.dev = devfn >> 3;
+ pci_addr.s.func = devfn & 0x7;
+ pci_addr.s.reg = reg;
+
+#if PCI_CONFIG_SPACE_DELAY
+ udelay(PCI_CONFIG_SPACE_DELAY);
+#endif
+ switch (size) {
+ case 4:
+ cvmx_write64_uint32(pci_addr.u64, cpu_to_le32(val));
+ return PCIBIOS_SUCCESSFUL;
+ case 2:
+ cvmx_write64_uint16(pci_addr.u64, cpu_to_le16(val));
+ return PCIBIOS_SUCCESSFUL;
+ case 1:
+ cvmx_write64_uint8(pci_addr.u64, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+
+static struct pci_ops octeon_pci_ops = {
+ octeon_read_config,
+ octeon_write_config,
+};
+
+static struct resource octeon_pci_mem_resource = {
+ .start = 0,
+ .end = 0,
+ .name = "Octeon PCI MEM",
+ .flags = IORESOURCE_MEM,
+};
+
+/*
+ * PCI ports must be above 16KB so the ISA bus filtering in the PCI-X to PCI
+ * bridge
+ */
+static struct resource octeon_pci_io_resource = {
+ .start = 0x4000,
+ .end = OCTEON_PCI_IOSPACE_SIZE - 1,
+ .name = "Octeon PCI IO",
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller octeon_pci_controller = {
+ .pci_ops = &octeon_pci_ops,
+ .mem_resource = &octeon_pci_mem_resource,
+ .mem_offset = OCTEON_PCI_MEMSPACE_OFFSET,
+ .io_resource = &octeon_pci_io_resource,
+ .io_offset = 0,
+ .io_map_base = OCTEON_PCI_IOSPACE_BASE,
+};
+
+
+/**
+ * Low level initialize the Octeon PCI controller
+ *
+ * Returns
+ */
+static void octeon_pci_initialize(void)
+{
+ union cvmx_pci_cfg01 cfg01;
+ union cvmx_npi_ctl_status ctl_status;
+ union cvmx_pci_ctl_status_2 ctl_status_2;
+ union cvmx_pci_cfg19 cfg19;
+ union cvmx_pci_cfg16 cfg16;
+ union cvmx_pci_cfg22 cfg22;
+ union cvmx_pci_cfg56 cfg56;
+
+ /* Reset the PCI Bus */
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1);
+ cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+
+ udelay(2000); /* Hold PCI reset for 2 ms */
+
+ ctl_status.u64 = 0; /* cvmx_read_csr(CVMX_NPI_CTL_STATUS); */
+ ctl_status.s.max_word = 1;
+ ctl_status.s.timer = 1;
+ cvmx_write_csr(CVMX_NPI_CTL_STATUS, ctl_status.u64);
+
+ /* Deassert PCI reset and advertize PCX Host Mode Device Capability
+ (64b) */
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4);
+ cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+
+ udelay(2000); /* Wait 2 ms after deasserting PCI reset */
+
+ ctl_status_2.u32 = 0;
+ ctl_status_2.s.tsr_hwm = 1; /* Initializes to 0. Must be set
+ before any PCI reads. */
+ ctl_status_2.s.bar2pres = 1; /* Enable BAR2 */
+ ctl_status_2.s.bar2_enb = 1;
+ ctl_status_2.s.bar2_cax = 1; /* Don't use L2 */
+ ctl_status_2.s.bar2_esx = 1;
+ ctl_status_2.s.pmo_amod = 1; /* Round robin priority */
+ if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG) {
+ /* BAR1 hole */
+ ctl_status_2.s.bb1_hole = OCTEON_PCI_BAR1_HOLE_BITS;
+ ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */
+ ctl_status_2.s.bb_ca = 1; /* Don't use L2 with big bars */
+ ctl_status_2.s.bb_es = 1; /* Big bar in byte swap mode */
+ ctl_status_2.s.bb1 = 1; /* BAR1 is big */
+ ctl_status_2.s.bb0 = 1; /* BAR0 is big */
+ }
+
+ octeon_npi_write32(CVMX_NPI_PCI_CTL_STATUS_2, ctl_status_2.u32);
+ udelay(2000); /* Wait 2 ms before doing PCI reads */
+
+ ctl_status_2.u32 = octeon_npi_read32(CVMX_NPI_PCI_CTL_STATUS_2);
+ pr_notice("PCI Status: %s %s-bit\n",
+ ctl_status_2.s.ap_pcix ? "PCI-X" : "PCI",
+ ctl_status_2.s.ap_64ad ? "64" : "32");
+
+ if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
+ union cvmx_pci_cnt_reg cnt_reg_start;
+ union cvmx_pci_cnt_reg cnt_reg_end;
+ unsigned long cycles, pci_clock;
+
+ cnt_reg_start.u64 = cvmx_read_csr(CVMX_NPI_PCI_CNT_REG);
+ cycles = read_c0_cvmcount();
+ udelay(1000);
+ cnt_reg_end.u64 = cvmx_read_csr(CVMX_NPI_PCI_CNT_REG);
+ cycles = read_c0_cvmcount() - cycles;
+ pci_clock = (cnt_reg_end.s.pcicnt - cnt_reg_start.s.pcicnt) /
+ (cycles / (mips_hpt_frequency / 1000000));
+ pr_notice("PCI Clock: %lu MHz\n", pci_clock);
+ }
+
+ /*
+ * TDOMC must be set to one in PCI mode. TDOMC should be set to 4
+ * in PCI-X mode to allow four oustanding splits. Otherwise,
+ * should not change from its reset value. Don't write PCI_CFG19
+ * in PCI mode (0x82000001 reset value), write it to 0x82000004
+ * after PCI-X mode is known. MRBCI,MDWE,MDRE -> must be zero.
+ * MRBCM -> must be one.
+ */
+ if (ctl_status_2.s.ap_pcix) {
+ cfg19.u32 = 0;
+ /*
+ * Target Delayed/Split request outstanding maximum
+ * count. [1..31] and 0=32. NOTE: If the user
+ * programs these bits beyond the Designed Maximum
+ * outstanding count, then the designed maximum table
+ * depth will be used instead. No additional
+ * Deferred/Split transactions will be accepted if
+ * this outstanding maximum count is
+ * reached. Furthermore, no additional deferred/split
+ * transactions will be accepted if the I/O delay/ I/O
+ * Split Request outstanding maximum is reached.
+ */
+ cfg19.s.tdomc = 4;
+ /*
+ * Master Deferred Read Request Outstanding Max Count
+ * (PCI only). CR4C[26:24] Max SAC cycles MAX DAC
+ * cycles 000 8 4 001 1 0 010 2 1 011 3 1 100 4 2 101
+ * 5 2 110 6 3 111 7 3 For example, if these bits are
+ * programmed to 100, the core can support 2 DAC
+ * cycles, 4 SAC cycles or a combination of 1 DAC and
+ * 2 SAC cycles. NOTE: For the PCI-X maximum
+ * outstanding split transactions, refer to
+ * CRE0[22:20].
+ */
+ cfg19.s.mdrrmc = 2;
+ /*
+ * Master Request (Memory Read) Byte Count/Byte Enable
+ * select. 0 = Byte Enables valid. In PCI mode, a
+ * burst transaction cannot be performed using Memory
+ * Read command=4?h6. 1 = DWORD Byte Count valid
+ * (default). In PCI Mode, the memory read byte
+ * enables are automatically generated by the
+ * core. Note: N3 Master Request transaction sizes are
+ * always determined through the
+ * am_attr[<35:32>|<7:0>] field.
+ */
+ cfg19.s.mrbcm = 1;
+ octeon_npi_write32(CVMX_NPI_PCI_CFG19, cfg19.u32);
+ }
+
+
+ cfg01.u32 = 0;
+ cfg01.s.msae = 1; /* Memory Space Access Enable */
+ cfg01.s.me = 1; /* Master Enable */
+ cfg01.s.pee = 1; /* PERR# Enable */
+ cfg01.s.see = 1; /* System Error Enable */
+ cfg01.s.fbbe = 1; /* Fast Back to Back Transaction Enable */
+
+ octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
+
+#ifdef USE_OCTEON_INTERNAL_ARBITER
+ /*
+ * When OCTEON is a PCI host, most systems will use OCTEON's
+ * internal arbiter, so must enable it before any PCI/PCI-X
+ * traffic can occur.
+ */
+ {
+ union cvmx_npi_pci_int_arb_cfg pci_int_arb_cfg;
+
+ pci_int_arb_cfg.u64 = 0;
+ pci_int_arb_cfg.s.en = 1; /* Internal arbiter enable */
+ cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, pci_int_arb_cfg.u64);
+ }
+#endif /* USE_OCTEON_INTERNAL_ARBITER */
+
+ /*
+ * Preferrably written to 1 to set MLTD. [RDSATI,TRTAE,
+ * TWTAE,TMAE,DPPMR -> must be zero. TILT -> must not be set to
+ * 1..7.
+ */
+ cfg16.u32 = 0;
+ cfg16.s.mltd = 1; /* Master Latency Timer Disable */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG16, cfg16.u32);
+
+ /*
+ * Should be written to 0x4ff00. MTTV -> must be zero.
+ * FLUSH -> must be 1. MRV -> should be 0xFF.
+ */
+ cfg22.u32 = 0;
+ /* Master Retry Value [1..255] and 0=infinite */
+ cfg22.s.mrv = 0xff;
+ /*
+ * AM_DO_FLUSH_I control NOTE: This bit MUST BE ONE for proper
+ * N3K operation.
+ */
+ cfg22.s.flush = 1;
+ octeon_npi_write32(CVMX_NPI_PCI_CFG22, cfg22.u32);
+
+ /*
+ * MOST Indicates the maximum number of outstanding splits (in -1
+ * notation) when OCTEON is in PCI-X mode. PCI-X performance is
+ * affected by the MOST selection. Should generally be written
+ * with one of 0x3be807, 0x2be807, 0x1be807, or 0x0be807,
+ * depending on the desired MOST of 3, 2, 1, or 0, respectively.
+ */
+ cfg56.u32 = 0;
+ cfg56.s.pxcid = 7; /* RO - PCI-X Capability ID */
+ cfg56.s.ncp = 0xe8; /* RO - Next Capability Pointer */
+ cfg56.s.dpere = 1; /* Data Parity Error Recovery Enable */
+ cfg56.s.roe = 1; /* Relaxed Ordering Enable */
+ cfg56.s.mmbc = 1; /* Maximum Memory Byte Count
+ [0=512B,1=1024B,2=2048B,3=4096B] */
+ cfg56.s.most = 3; /* Maximum outstanding Split transactions [0=1
+ .. 7=32] */
+
+ octeon_npi_write32(CVMX_NPI_PCI_CFG56, cfg56.u32);
+
+ /*
+ * Affects PCI performance when OCTEON services reads to its
+ * BAR1/BAR2. Refer to Section 10.6.1. The recommended values are
+ * 0x22, 0x33, and 0x33 for PCI_READ_CMD_6, PCI_READ_CMD_C, and
+ * PCI_READ_CMD_E, respectively. Unfortunately due to errata DDR-700,
+ * these values need to be changed so they won't possibly prefetch off
+ * of the end of memory if PCI is DMAing a buffer at the end of
+ * memory. Note that these values differ from their reset values.
+ */
+ octeon_npi_write32(CVMX_NPI_PCI_READ_CMD_6, 0x21);
+ octeon_npi_write32(CVMX_NPI_PCI_READ_CMD_C, 0x31);
+ octeon_npi_write32(CVMX_NPI_PCI_READ_CMD_E, 0x31);
+}
+
+
+/**
+ * Initialize the Octeon PCI controller
+ *
+ * Returns
+ */
+static int __init octeon_pci_setup(void)
+{
+ union cvmx_npi_mem_access_subidx mem_access;
+ int index;
+
+ /* Only these chips have PCI */
+ if (octeon_has_feature(OCTEON_FEATURE_PCIE))
+ return 0;
+
+ /* Point pcibios_map_irq() to the PCI version of it */
+ octeon_pcibios_map_irq = octeon_pci_pcibios_map_irq;
+
+ /* Only use the big bars on chips that support it */
+ if (OCTEON_IS_MODEL(OCTEON_CN31XX) ||
+ OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2) ||
+ OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1))
+ octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_SMALL;
+ else
+ octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
+
+ /* PCI I/O and PCI MEM values */
+ set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
+ ioport_resource.start = 0;
+ ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;
+ if (!octeon_is_pci_host()) {
+ pr_notice("Not in host mode, PCI Controller not initialized\n");
+ return 0;
+ }
+
+ pr_notice("%s Octeon big bar support\n",
+ (octeon_dma_bar_type ==
+ OCTEON_DMA_BAR_TYPE_BIG) ? "Enabling" : "Disabling");
+
+ octeon_pci_initialize();
+
+ mem_access.u64 = 0;
+ mem_access.s.esr = 1; /* Endian-Swap on read. */
+ mem_access.s.esw = 1; /* Endian-Swap on write. */
+ mem_access.s.nsr = 0; /* No-Snoop on read. */
+ mem_access.s.nsw = 0; /* No-Snoop on write. */
+ mem_access.s.ror = 0; /* Relax Read on read. */
+ mem_access.s.row = 0; /* Relax Order on write. */
+ mem_access.s.ba = 0; /* PCI Address bits [63:36]. */
+ cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, mem_access.u64);
+
+ /*
+ * Remap the Octeon BAR 2 above all 32 bit devices
+ * (0x8000000000ul). This is done here so it is remapped
+ * before the readl()'s below. We don't want BAR2 overlapping
+ * with BAR0/BAR1 during these reads.
+ */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG08, 0);
+ octeon_npi_write32(CVMX_NPI_PCI_CFG09, 0x80);
+
+ /* Disable the BAR1 movable mappings */
+ for (index = 0; index < 32; index++)
+ octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index), 0);
+
+ if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG) {
+ /* Remap the Octeon BAR 0 to 0-2GB */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG04, 0);
+ octeon_npi_write32(CVMX_NPI_PCI_CFG05, 0);
+
+ /*
+ * Remap the Octeon BAR 1 to map 2GB-4GB (minus the
+ * BAR 1 hole).
+ */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG06, 2ul << 30);
+ octeon_npi_write32(CVMX_NPI_PCI_CFG07, 0);
+
+ /* Devices go after BAR1 */
+ octeon_pci_mem_resource.start =
+ OCTEON_PCI_MEMSPACE_OFFSET + (4ul << 30) -
+ (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
+ octeon_pci_mem_resource.end =
+ octeon_pci_mem_resource.start + (1ul << 30);
+ } else {
+ /* Remap the Octeon BAR 0 to map 128MB-(128MB+4KB) */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG04, 128ul << 20);
+ octeon_npi_write32(CVMX_NPI_PCI_CFG05, 0);
+
+ /* Remap the Octeon BAR 1 to map 0-128MB */
+ octeon_npi_write32(CVMX_NPI_PCI_CFG06, 0);
+ octeon_npi_write32(CVMX_NPI_PCI_CFG07, 0);
+
+ /* Devices go after BAR0 */
+ octeon_pci_mem_resource.start =
+ OCTEON_PCI_MEMSPACE_OFFSET + (128ul << 20) +
+ (4ul << 10);
+ octeon_pci_mem_resource.end =
+ octeon_pci_mem_resource.start + (1ul << 30);
+ }
+
+ register_pci_controller(&octeon_pci_controller);
+
+ /*
+ * Clear any errors that might be pending from before the bus
+ * was setup properly.
+ */
+ cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1);
+ return 0;
+}
+
+arch_initcall(octeon_pci_setup);
diff --git a/arch/mips/cavium-octeon/pcie.c b/arch/mips/cavium-octeon/pcie.c
new file mode 100644
index 000000000000..49d14081b3b5
--- /dev/null
+++ b/arch/mips/cavium-octeon/pcie.c
@@ -0,0 +1,1370 @@
+/*
+ * 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) 2007, 2008 Cavium Networks
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-npei-defs.h>
+#include <asm/octeon/cvmx-pciercx-defs.h>
+#include <asm/octeon/cvmx-pescx-defs.h>
+#include <asm/octeon/cvmx-pexp-defs.h>
+#include <asm/octeon/cvmx-helper-errata.h>
+
+#include "pci-common.h"
+
+union cvmx_pcie_address {
+ uint64_t u64;
+ struct {
+ uint64_t upper:2; /* Normally 2 for XKPHYS */
+ uint64_t reserved_49_61:13; /* Must be zero */
+ uint64_t io:1; /* 1 for IO space access */
+ uint64_t did:5; /* PCIe DID = 3 */
+ uint64_t subdid:3; /* PCIe SubDID = 1 */
+ uint64_t reserved_36_39:4; /* Must be zero */
+ uint64_t es:2; /* Endian swap = 1 */
+ uint64_t port:2; /* PCIe port 0,1 */
+ uint64_t reserved_29_31:3; /* Must be zero */
+ /*
+ * Selects the type of the configuration request (0 = type 0,
+ * 1 = type 1).
+ */
+ uint64_t ty:1;
+ /* Target bus number sent in the ID in the request. */
+ uint64_t bus:8;
+ /*
+ * Target device number sent in the ID in the
+ * request. Note that Dev must be zero for type 0
+ * configuration requests.
+ */
+ uint64_t dev:5;
+ /* Target function number sent in the ID in the request. */
+ uint64_t func:3;
+ /*
+ * Selects a register in the configuration space of
+ * the target.
+ */
+ uint64_t reg:12;
+ } config;
+ struct {
+ uint64_t upper:2; /* Normally 2 for XKPHYS */
+ uint64_t reserved_49_61:13; /* Must be zero */
+ uint64_t io:1; /* 1 for IO space access */
+ uint64_t did:5; /* PCIe DID = 3 */
+ uint64_t subdid:3; /* PCIe SubDID = 2 */
+ uint64_t reserved_36_39:4; /* Must be zero */
+ uint64_t es:2; /* Endian swap = 1 */
+ uint64_t port:2; /* PCIe port 0,1 */
+ uint64_t address:32; /* PCIe IO address */
+ } io;
+ struct {
+ uint64_t upper:2; /* Normally 2 for XKPHYS */
+ uint64_t reserved_49_61:13; /* Must be zero */
+ uint64_t io:1; /* 1 for IO space access */
+ uint64_t did:5; /* PCIe DID = 3 */
+ uint64_t subdid:3; /* PCIe SubDID = 3-6 */
+ uint64_t reserved_36_39:4; /* Must be zero */
+ uint64_t address:36; /* PCIe Mem address */
+ } mem;
+};
+
+/**
+ * Return the Core virtual base address for PCIe IO access. IOs are
+ * read/written as an offset from this address.
+ *
+ * @pcie_port: PCIe port the IO is for
+ *
+ * Returns 64bit Octeon IO base address for read/write
+ */
+static inline uint64_t cvmx_pcie_get_io_base_address(int pcie_port)
+{
+ union cvmx_pcie_address pcie_addr;
+ pcie_addr.u64 = 0;
+ pcie_addr.io.upper = 0;
+ pcie_addr.io.io = 1;
+ pcie_addr.io.did = 3;
+ pcie_addr.io.subdid = 2;
+ pcie_addr.io.es = 1;
+ pcie_addr.io.port = pcie_port;
+ return pcie_addr.u64;
+}
+
+/**
+ * Size of the IO address region returned at address
+ * cvmx_pcie_get_io_base_address()
+ *
+ * @pcie_port: PCIe port the IO is for
+ *
+ * Returns Size of the IO window
+ */
+static inline uint64_t cvmx_pcie_get_io_size(int pcie_port)
+{
+ return 1ull << 32;
+}
+
+/**
+ * Return the Core virtual base address for PCIe MEM access. Memory is
+ * read/written as an offset from this address.
+ *
+ * @pcie_port: PCIe port the IO is for
+ *
+ * Returns 64bit Octeon IO base address for read/write
+ */
+static inline uint64_t cvmx_pcie_get_mem_base_address(int pcie_port)
+{
+ union cvmx_pcie_address pcie_addr;
+ pcie_addr.u64 = 0;
+ pcie_addr.mem.upper = 0;
+ pcie_addr.mem.io = 1;
+ pcie_addr.mem.did = 3;
+ pcie_addr.mem.subdid = 3 + pcie_port;
+ return pcie_addr.u64;
+}
+
+/**
+ * Size of the Mem address region returned at address
+ * cvmx_pcie_get_mem_base_address()
+ *
+ * @pcie_port: PCIe port the IO is for
+ *
+ * Returns Size of the Mem window
+ */
+static inline uint64_t cvmx_pcie_get_mem_size(int pcie_port)
+{
+ return 1ull << 36;
+}
+
+/**
+ * Read a PCIe config space register indirectly. This is used for
+ * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
+ *
+ * @pcie_port: PCIe port to read from
+ * @cfg_offset: Address to read
+ *
+ * Returns Value read
+ */
+static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)
+{
+ union cvmx_pescx_cfg_rd pescx_cfg_rd;
+ pescx_cfg_rd.u64 = 0;
+ pescx_cfg_rd.s.addr = cfg_offset;
+ cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64);
+ pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port));
+ return pescx_cfg_rd.s.data;
+}
+
+/**
+ * Write a PCIe config space register indirectly. This is used for
+ * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.
+ *
+ * @pcie_port: PCIe port to write to
+ * @cfg_offset: Address to write
+ * @val: Value to write
+ */
+static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset,
+ uint32_t val)
+{
+ union cvmx_pescx_cfg_wr pescx_cfg_wr;
+ pescx_cfg_wr.u64 = 0;
+ pescx_cfg_wr.s.addr = cfg_offset;
+ pescx_cfg_wr.s.data = val;
+ cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64);
+}
+
+/**
+ * Build a PCIe config space request address for a device
+ *
+ * @pcie_port: PCIe port to access
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ *
+ * Returns 64bit Octeon IO address
+ */
+static inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus,
+ int dev, int fn, int reg)
+{
+ union cvmx_pcie_address pcie_addr;
+ union cvmx_pciercx_cfg006 pciercx_cfg006;
+
+ pciercx_cfg006.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port));
+ if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0))
+ return 0;
+
+ pcie_addr.u64 = 0;
+ pcie_addr.config.upper = 2;
+ pcie_addr.config.io = 1;
+ pcie_addr.config.did = 3;
+ pcie_addr.config.subdid = 1;
+ pcie_addr.config.es = 1;
+ pcie_addr.config.port = pcie_port;
+ pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum);
+ pcie_addr.config.bus = bus;
+ pcie_addr.config.dev = dev;
+ pcie_addr.config.func = fn;
+ pcie_addr.config.reg = reg;
+ return pcie_addr.u64;
+}
+
+/**
+ * Read 8bits from a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ *
+ * Returns Result of the read
+ */
+static uint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev,
+ int fn, int reg)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ return cvmx_read64_uint8(address);
+ else
+ return 0xff;
+}
+
+/**
+ * Read 16bits from a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ *
+ * Returns Result of the read
+ */
+static uint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev,
+ int fn, int reg)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ return le16_to_cpu(cvmx_read64_uint16(address));
+ else
+ return 0xffff;
+}
+
+/**
+ * Read 32bits from a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ *
+ * Returns Result of the read
+ */
+static uint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev,
+ int fn, int reg)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ return le32_to_cpu(cvmx_read64_uint32(address));
+ else
+ return 0xffffffff;
+}
+
+/**
+ * Write 8bits to a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ * @val: Value to write
+ */
+static void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn,
+ int reg, uint8_t val)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ cvmx_write64_uint8(address, val);
+}
+
+/**
+ * Write 16bits to a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ * @val: Value to write
+ */
+static void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn,
+ int reg, uint16_t val)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ cvmx_write64_uint16(address, cpu_to_le16(val));
+}
+
+/**
+ * Write 32bits to a Device's config space
+ *
+ * @pcie_port: PCIe port the device is on
+ * @bus: Sub bus
+ * @dev: Device ID
+ * @fn: Device sub function
+ * @reg: Register to access
+ * @val: Value to write
+ */
+static void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn,
+ int reg, uint32_t val)
+{
+ uint64_t address =
+ __cvmx_pcie_build_config_addr(pcie_port, bus, dev, fn, reg);
+ if (address)
+ cvmx_write64_uint32(address, cpu_to_le32(val));
+}
+
+/**
+ * Initialize the RC config space CSRs
+ *
+ * @pcie_port: PCIe port to initialize
+ */
+static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
+{
+ union cvmx_pciercx_cfg030 pciercx_cfg030;
+ union cvmx_npei_ctl_status2 npei_ctl_status2;
+ union cvmx_pciercx_cfg070 pciercx_cfg070;
+ union cvmx_pciercx_cfg001 pciercx_cfg001;
+ union cvmx_pciercx_cfg032 pciercx_cfg032;
+ union cvmx_pciercx_cfg006 pciercx_cfg006;
+ union cvmx_pciercx_cfg008 pciercx_cfg008;
+ union cvmx_pciercx_cfg009 pciercx_cfg009;
+ union cvmx_pciercx_cfg010 pciercx_cfg010;
+ union cvmx_pciercx_cfg011 pciercx_cfg011;
+ union cvmx_pciercx_cfg035 pciercx_cfg035;
+ union cvmx_pciercx_cfg075 pciercx_cfg075;
+ union cvmx_pciercx_cfg034 pciercx_cfg034;
+
+ /* Max Payload Size (PCIE*_CFG030[MPS]) */
+ /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
+ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
+ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
+ pciercx_cfg030.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port));
+ /*
+ * Max payload size = 128 bytes for best Octeon DMA
+ * performance.
+ */
+ pciercx_cfg030.s.mps = 0;
+ /*
+ * Max read request size = 128 bytes for best Octeon DMA
+ * performance.
+ */
+ pciercx_cfg030.s.mrrs = 0;
+ /* Enable relaxed ordering. */
+ pciercx_cfg030.s.ro_en = 1;
+ /* Enable no snoop. */
+ pciercx_cfg030.s.ns_en = 1;
+ /* Correctable error reporting enable. */
+ pciercx_cfg030.s.ce_en = 1;
+ /* Non-fatal error reporting enable. */
+ pciercx_cfg030.s.nfe_en = 1;
+ /* Fatal error reporting enable. */
+ pciercx_cfg030.s.fe_en = 1;
+ /* Unsupported request reporting enable. */
+ pciercx_cfg030.s.ur_en = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port),
+ pciercx_cfg030.u32);
+
+ /*
+ * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match
+ * PCIE*_CFG030[MPS]
+ *
+ * Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not
+ * exceed PCIE*_CFG030[MRRS].
+ */
+ npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
+ /* Max payload size = 128 bytes for best Octeon DMA performance */
+ npei_ctl_status2.s.mps = 0;
+ /* Max read request size = 128 bytes for best Octeon DMA performance */
+ npei_ctl_status2.s.mrrs = 0;
+ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
+
+ /* ECRC Generation (PCIE*_CFG070[GE,CE]) */
+ pciercx_cfg070.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));
+ pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */
+ pciercx_cfg070.s.ce = 1; /* ECRC check enable. */
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port),
+ pciercx_cfg070.u32);
+
+ /*
+ * Access Enables (PCIE*_CFG001[MSAE,ME]) ME and MSAE should
+ * always be set.
+ *
+ * Interrupt Disable (PCIE*_CFG001[I_DIS]) System Error
+ * Message Enable (PCIE*_CFG001[SEE])
+ */
+ pciercx_cfg001.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));
+ pciercx_cfg001.s.msae = 1; /* Memory space enable. */
+ pciercx_cfg001.s.me = 1; /* Bus master enable. */
+ pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */
+ pciercx_cfg001.s.see = 1; /* SERR# enable */
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port),
+ pciercx_cfg001.u32);
+
+ /* Advanced Error Recovery Message Enables */
+ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0);
+ /* Use CVMX_PCIERCX_CFG067 hardware default */
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0);
+
+ /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
+ pciercx_cfg032.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
+ pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port),
+ pciercx_cfg032.u32);
+
+ /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */
+
+ /*
+ * Link Width Mode (PCIERCn_CFG452[LME]) - Set during
+ * cvmx_pcie_rc_initialize_link()
+ *
+ * Primary Bus Number (PCIERCn_CFG006[PBNUM])
+ *
+ * We set the primary bus number to 1 so IDT bridges are
+ * happy. They don't like zero.
+ */
+ pciercx_cfg006.u32 = 0;
+ pciercx_cfg006.s.pbnum = 1;
+ pciercx_cfg006.s.sbnum = 1;
+ pciercx_cfg006.s.subbnum = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port),
+ pciercx_cfg006.u32);
+
+ /*
+ * Memory-mapped I/O BAR (PCIERCn_CFG008)
+ * Most applications should disable the memory-mapped I/O BAR by
+ * setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR]
+ */
+ pciercx_cfg008.u32 = 0;
+ pciercx_cfg008.s.mb_addr = 0x100;
+ pciercx_cfg008.s.ml_addr = 0;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port),
+ pciercx_cfg008.u32);
+
+ /*
+ * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011)
+ * Most applications should disable the prefetchable BAR by setting
+ * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] <
+ * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE]
+ */
+ pciercx_cfg009.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));
+ pciercx_cfg010.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));
+ pciercx_cfg011.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));
+ pciercx_cfg009.s.lmem_base = 0x100;
+ pciercx_cfg009.s.lmem_limit = 0;
+ pciercx_cfg010.s.umem_base = 0x100;
+ pciercx_cfg011.s.umem_limit = 0;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port),
+ pciercx_cfg009.u32);
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port),
+ pciercx_cfg010.u32);
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port),
+ pciercx_cfg011.u32);
+
+ /*
+ * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE])
+ * PME Interrupt Enables (PCIERCn_CFG035[PMEIE])
+ */
+ pciercx_cfg035.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));
+ /* System error on correctable error enable. */
+ pciercx_cfg035.s.secee = 1;
+ /* System error on fatal error enable. */
+ pciercx_cfg035.s.sefee = 1;
+ /* System error on non-fatal error enable. */
+ pciercx_cfg035.s.senfee = 1;
+ /* PME interrupt enable. */
+ pciercx_cfg035.s.pmeie = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port),
+ pciercx_cfg035.u32);
+
+ /*
+ * Advanced Error Recovery Interrupt Enables
+ * (PCIERCn_CFG075[CERE,NFERE,FERE])
+ */
+ pciercx_cfg075.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));
+ /* Correctable error reporting enable. */
+ pciercx_cfg075.s.cere = 1;
+ /* Non-fatal error reporting enable. */
+ pciercx_cfg075.s.nfere = 1;
+ /* Fatal error reporting enable. */
+ pciercx_cfg075.s.fere = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port),
+ pciercx_cfg075.u32);
+
+ /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN],
+ * PCIERCn_CFG034[DLLS_EN,CCINT_EN])
+ */
+ pciercx_cfg034.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));
+ /* Hot-plug interrupt enable. */
+ pciercx_cfg034.s.hpint_en = 1;
+ /* Data Link Layer state changed enable */
+ pciercx_cfg034.s.dlls_en = 1;
+ /* Command completed interrupt enable. */
+ pciercx_cfg034.s.ccint_en = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port),
+ pciercx_cfg034.u32);
+}
+
+/**
+ * Initialize a host mode PCIe link. This function takes a PCIe
+ * port from reset to a link up state. Software can then begin
+ * configuring the rest of the link.
+ *
+ * @pcie_port: PCIe port to initialize
+ *
+ * Returns Zero on success
+ */
+static int __cvmx_pcie_rc_initialize_link(int pcie_port)
+{
+ uint64_t start_cycle;
+ union cvmx_pescx_ctl_status pescx_ctl_status;
+ union cvmx_pciercx_cfg452 pciercx_cfg452;
+ union cvmx_pciercx_cfg032 pciercx_cfg032;
+ union cvmx_pciercx_cfg448 pciercx_cfg448;
+
+ /* Set the lane width */
+ pciercx_cfg452.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));
+ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
+ if (pescx_ctl_status.s.qlm_cfg == 0) {
+ /* We're in 8 lane (56XX) or 4 lane (54XX) mode */
+ pciercx_cfg452.s.lme = 0xf;
+ } else {
+ /* We're in 4 lane (56XX) or 2 lane (52XX) mode */
+ pciercx_cfg452.s.lme = 0x7;
+ }
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port),
+ pciercx_cfg452.u32);
+
+ /*
+ * CN52XX pass 1.x has an errata where length mismatches on UR
+ * responses can cause bus errors on 64bit memory
+ * reads. Turning off length error checking fixes this.
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+ union cvmx_pciercx_cfg455 pciercx_cfg455;
+ pciercx_cfg455.u32 =
+ cvmx_pcie_cfgx_read(pcie_port,
+ CVMX_PCIERCX_CFG455(pcie_port));
+ pciercx_cfg455.s.m_cpl_len_err = 1;
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port),
+ pciercx_cfg455.u32);
+ }
+
+ /* Lane swap needs to be manually enabled for CN52XX */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) {
+ pescx_ctl_status.s.lane_swp = 1;
+ cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),
+ pescx_ctl_status.u64);
+ }
+
+ /* Bring up the link */
+ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
+ pescx_ctl_status.s.lnk_enb = 1;
+ cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64);
+
+ /*
+ * CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to
+ * be disabled.
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
+ __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0);
+
+ /* Wait for the link to come up */
+ cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port);
+ start_cycle = cvmx_get_cycle();
+ do {
+ if (cvmx_get_cycle() - start_cycle >
+ 2 * cvmx_sysinfo_get()->cpu_clock_hz) {
+ cvmx_dprintf("PCIe: Port %d link timeout\n",
+ pcie_port);
+ return -1;
+ }
+ cvmx_wait(10000);
+ pciercx_cfg032.u32 =
+ cvmx_pcie_cfgx_read(pcie_port,
+ CVMX_PCIERCX_CFG032(pcie_port));
+ } while (pciercx_cfg032.s.dlla == 0);
+
+ /* Display the link status */
+ cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port,
+ pciercx_cfg032.s.nlw);
+
+ /*
+ * Update the Replay Time Limit. Empirically, some PCIe
+ * devices take a little longer to respond than expected under
+ * load. As a workaround for this we configure the Replay Time
+ * Limit to the value expected for a 512 byte MPS instead of
+ * our actual 256 byte MPS. The numbers below are directly
+ * from the PCIe spec table 3-4.
+ */
+ pciercx_cfg448.u32 =
+ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
+ switch (pciercx_cfg032.s.nlw) {
+ case 1: /* 1 lane */
+ pciercx_cfg448.s.rtl = 1677;
+ break;
+ case 2: /* 2 lanes */
+ pciercx_cfg448.s.rtl = 867;
+ break;
+ case 4: /* 4 lanes */
+ pciercx_cfg448.s.rtl = 462;
+ break;
+ case 8: /* 8 lanes */
+ pciercx_cfg448.s.rtl = 258;
+ break;
+ }
+ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port),
+ pciercx_cfg448.u32);
+
+ return 0;
+}
+
+/**
+ * Initialize a PCIe port for use in host(RC) mode. It doesn't
+ * enumerate the bus.
+ *
+ * @pcie_port: PCIe port to initialize
+ *
+ * Returns Zero on success
+ */
+static int cvmx_pcie_rc_initialize(int pcie_port)
+{
+ int i;
+ union cvmx_ciu_soft_prst ciu_soft_prst;
+ union cvmx_pescx_bist_status pescx_bist_status;
+ union cvmx_pescx_bist_status2 pescx_bist_status2;
+ union cvmx_npei_ctl_status npei_ctl_status;
+ union cvmx_npei_mem_access_ctl npei_mem_access_ctl;
+ union cvmx_npei_mem_access_subidx mem_access_subid;
+ union cvmx_npei_dbg_data npei_dbg_data;
+ union cvmx_pescx_ctl_status2 pescx_ctl_status2;
+
+ /*
+ * Make sure we aren't trying to setup a target mode interface
+ * in host mode.
+ */
+ npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
+ if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) {
+ cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called "
+ "on port0, but port0 is not in host mode\n");
+ return -1;
+ }
+
+ /*
+ * Make sure a CN52XX isn't trying to bring up port 1 when it
+ * is disabled.
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
+ npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+ if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) {
+ cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() "
+ "called on port1, but port1 is "
+ "disabled\n");
+ return -1;
+ }
+ }
+
+ /*
+ * PCIe switch arbitration mode. '0' == fixed priority NPEI,
+ * PCIe0, then PCIe1. '1' == round robin.
+ */
+ npei_ctl_status.s.arb = 1;
+ /* Allow up to 0x20 config retries */
+ npei_ctl_status.s.cfg_rtry = 0x20;
+ /*
+ * CN52XX pass1.x has an errata where P0_NTAGS and P1_NTAGS
+ * don't reset.
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+ npei_ctl_status.s.p0_ntags = 0x20;
+ npei_ctl_status.s.p1_ntags = 0x20;
+ }
+ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS, npei_ctl_status.u64);
+
+ /* Bring the PCIe out of reset */
+ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) {
+ /*
+ * The EBH5200 board swapped the PCIe reset lines on
+ * the board. As a workaround for this bug, we bring
+ * both PCIe ports out of reset at the same time
+ * instead of on separate calls. So for port 0, we
+ * bring both out of reset and do nothing on port 1.
+ */
+ if (pcie_port == 0) {
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+ /*
+ * After a chip reset the PCIe will also be in
+ * reset. If it isn't, most likely someone is
+ * trying to init it again without a proper
+ * PCIe reset.
+ */
+ if (ciu_soft_prst.s.soft_prst == 0) {
+ /* Reset the ports */
+ ciu_soft_prst.s.soft_prst = 1;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST,
+ ciu_soft_prst.u64);
+ ciu_soft_prst.u64 =
+ cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+ ciu_soft_prst.s.soft_prst = 1;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST1,
+ ciu_soft_prst.u64);
+ /* Wait until pcie resets the ports. */
+ udelay(2000);
+ }
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+ ciu_soft_prst.s.soft_prst = 0;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+ ciu_soft_prst.s.soft_prst = 0;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
+ }
+ } else {
+ /*
+ * The normal case: The PCIe ports are completely
+ * separate and can be brought out of reset
+ * independently.
+ */
+ if (pcie_port)
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+ else
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+ /*
+ * After a chip reset the PCIe will also be in
+ * reset. If it isn't, most likely someone is trying
+ * to init it again without a proper PCIe reset.
+ */
+ if (ciu_soft_prst.s.soft_prst == 0) {
+ /* Reset the port */
+ ciu_soft_prst.s.soft_prst = 1;
+ if (pcie_port)
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST1,
+ ciu_soft_prst.u64);
+ else
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST,
+ ciu_soft_prst.u64);
+ /* Wait until pcie resets the ports. */
+ udelay(2000);
+ }
+ if (pcie_port) {
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+ ciu_soft_prst.s.soft_prst = 0;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
+ } else {
+ ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+ ciu_soft_prst.s.soft_prst = 0;
+ cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
+ }
+ }
+
+ /*
+ * Wait for PCIe reset to complete. Due to errata PCIE-700, we
+ * don't poll PESCX_CTL_STATUS2[PCIERST], but simply wait a
+ * fixed number of cycles.
+ */
+ cvmx_wait(400000);
+
+ /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and
+ CN52XX, so we only probe it on newer chips */
+ if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
+ && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+ /* Clear PCLK_RUN so we can check if the clock is running */
+ pescx_ctl_status2.u64 =
+ cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
+ pescx_ctl_status2.s.pclk_run = 1;
+ cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port),
+ pescx_ctl_status2.u64);
+ /*
+ * Now that we cleared PCLK_RUN, wait for it to be set
+ * again telling us the clock is running.
+ */
+ if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port),
+ union cvmx_pescx_ctl_status2,
+ pclk_run, ==, 1, 10000)) {
+ cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n",
+ pcie_port);
+ return -1;
+ }
+ }
+
+ /*
+ * Check and make sure PCIe came out of reset. If it doesn't
+ * the board probably hasn't wired the clocks up and the
+ * interface should be skipped.
+ */
+ pescx_ctl_status2.u64 =
+ cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
+ if (pescx_ctl_status2.s.pcierst) {
+ cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n",
+ pcie_port);
+ return -1;
+ }
+
+ /*
+ * Check BIST2 status. If any bits are set skip this interface. This
+ * is an attempt to catch PCIE-813 on pass 1 parts.
+ */
+ pescx_bist_status2.u64 =
+ cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));
+ if (pescx_bist_status2.u64) {
+ cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this "
+ "port isn't hooked up, skipping.\n",
+ pcie_port);
+ return -1;
+ }
+
+ /* Check BIST status */
+ pescx_bist_status.u64 =
+ cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));
+ if (pescx_bist_status.u64)
+ cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n",
+ pcie_port, CAST64(pescx_bist_status.u64));
+
+ /* Initialize the config space CSRs */
+ __cvmx_pcie_rc_initialize_config_space(pcie_port);
+
+ /* Bring the link up */
+ if (__cvmx_pcie_rc_initialize_link(pcie_port)) {
+ cvmx_dprintf
+ ("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n");
+ return -1;
+ }
+
+ /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
+ npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL);
+ /* Allow 16 words to combine */
+ npei_mem_access_ctl.s.max_word = 0;
+ /* Wait up to 127 cycles for more data */
+ npei_mem_access_ctl.s.timer = 127;
+ cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);
+
+ /* Setup Mem access SubDIDs */
+ mem_access_subid.u64 = 0;
+ /* Port the request is sent to. */
+ mem_access_subid.s.port = pcie_port;
+ /* Due to an errata on pass 1 chips, no merging is allowed. */
+ mem_access_subid.s.nmerge = 1;
+ /* Endian-swap for Reads. */
+ mem_access_subid.s.esr = 1;
+ /* Endian-swap for Writes. */
+ mem_access_subid.s.esw = 1;
+ /* No Snoop for Reads. */
+ mem_access_subid.s.nsr = 1;
+ /* No Snoop for Writes. */
+ mem_access_subid.s.nsw = 1;
+ /* Disable Relaxed Ordering for Reads. */
+ mem_access_subid.s.ror = 0;
+ /* Disable Relaxed Ordering for Writes. */
+ mem_access_subid.s.row = 0;
+ /* PCIe Adddress Bits <63:34>. */
+ mem_access_subid.s.ba = 0;
+
+ /*
+ * Setup mem access 12-15 for port 0, 16-19 for port 1,
+ * supplying 36 bits of address space.
+ */
+ for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {
+ cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i),
+ mem_access_subid.u64);
+ /* Set each SUBID to extend the addressable range */
+ mem_access_subid.s.ba += 1;
+ }
+
+ /*
+ * Disable the peer to peer forwarding register. This must be
+ * setup by the OS after it enumerates the bus and assigns
+ * addresses to the PCIe busses.
+ */
+ for (i = 0; i < 4; i++) {
+ cvmx_write_csr(CVMX_PESCX_P2P_BARX_START(i, pcie_port), -1);
+ cvmx_write_csr(CVMX_PESCX_P2P_BARX_END(i, pcie_port), -1);
+ }
+
+ /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
+ cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
+
+ /*
+ * Disable Octeon's BAR1. It isn't needed in RC mode since
+ * BAR2 maps all of memory. BAR2 also maps 256MB-512MB into
+ * the 2nd 256MB of memory.
+ */
+ cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), -1);
+
+ /*
+ * Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take
+ * precedence where they overlap. It also overlaps with the
+ * device addresses, so make sure the peer to peer forwarding
+ * is set right.
+ */
+ cvmx_write_csr(CVMX_PESCX_P2N_BAR2_START(pcie_port), 0);
+
+ /*
+ * Setup BAR2 attributes
+ *
+ * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM])
+ * - PTLP_RO,CTLP_RO should normally be set (except for debug).
+ * - WAIT_COM=0 will likely work for all applications.
+ *
+ * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]).
+ */
+ if (pcie_port) {
+ union cvmx_npei_ctl_port1 npei_ctl_port;
+ npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT1);
+ npei_ctl_port.s.bar2_enb = 1;
+ npei_ctl_port.s.bar2_esx = 1;
+ npei_ctl_port.s.bar2_cax = 0;
+ npei_ctl_port.s.ptlp_ro = 1;
+ npei_ctl_port.s.ctlp_ro = 1;
+ npei_ctl_port.s.wait_com = 0;
+ npei_ctl_port.s.waitl_com = 0;
+ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT1, npei_ctl_port.u64);
+ } else {
+ union cvmx_npei_ctl_port0 npei_ctl_port;
+ npei_ctl_port.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_PORT0);
+ npei_ctl_port.s.bar2_enb = 1;
+ npei_ctl_port.s.bar2_esx = 1;
+ npei_ctl_port.s.bar2_cax = 0;
+ npei_ctl_port.s.ptlp_ro = 1;
+ npei_ctl_port.s.ctlp_ro = 1;
+ npei_ctl_port.s.wait_com = 0;
+ npei_ctl_port.s.waitl_com = 0;
+ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64);
+ }
+ return 0;
+}
+
+
+/* Above was cvmx-pcie.c, below original pcie.c */
+
+
+/**
+ * Map a PCI device to the appropriate interrupt line
+ *
+ * @param dev The Linux PCI device structure for the device to map
+ * @param slot The slot number for this device on __BUS 0__. Linux
+ * enumerates through all the bridges and figures out the
+ * slot on Bus 0 where this device eventually hooks to.
+ * @param pin The PCI interrupt pin read from the device, then swizzled
+ * as it goes through each bridge.
+ * @return Interrupt number for the device
+ */
+int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
+ u8 slot, u8 pin)
+{
+ /*
+ * The EBH5600 board with the PCI to PCIe bridge mistakenly
+ * wires the first slot for both device id 2 and interrupt
+ * A. According to the PCI spec, device id 2 should be C. The
+ * following kludge attempts to fix this.
+ */
+ if (strstr(octeon_board_type_string(), "EBH5600") &&
+ dev->bus && dev->bus->parent) {
+ /*
+ * Iterate all the way up the device chain and find
+ * the root bus.
+ */
+ while (dev->bus && dev->bus->parent)
+ dev = to_pci_dev(dev->bus->bridge);
+ /* If the root bus is number 0 and the PEX 8114 is the
+ * root, assume we are behind the miswired bus. We
+ * need to correct the swizzle level by two. Yuck.
+ */
+ if ((dev->bus->number == 0) &&
+ (dev->vendor == 0x10b5) && (dev->device == 0x8114)) {
+ /*
+ * The pin field is one based, not zero. We
+ * need to swizzle it by minus two.
+ */
+ pin = ((pin - 3) & 3) + 1;
+ }
+ }
+ /*
+ * The -1 is because pin starts with one, not zero. It might
+ * be that this equation needs to include the slot number, but
+ * I don't have hardware to check that against.
+ */
+ return pin - 1 + OCTEON_IRQ_PCI_INT0;
+}
+
+/**
+ * Read a value from configuration space
+ *
+ * @param bus
+ * @param devfn
+ * @param reg
+ * @param size
+ * @param val
+ * @return
+ */
+static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
+ unsigned int devfn, int reg, int size,
+ u32 *val)
+{
+ union octeon_cvmemctl cvmmemctl;
+ union octeon_cvmemctl cvmmemctl_save;
+ int bus_number = bus->number;
+
+ /*
+ * We need to force the bus number to be zero on the root
+ * bus. Linux numbers the 2nd root bus to start after all
+ * buses on root 0.
+ */
+ if (bus->parent == NULL)
+ bus_number = 0;
+
+ /*
+ * PCIe only has a single device connected to Octeon. It is
+ * always device ID 0. Don't bother doing reads for other
+ * device IDs on the first segment.
+ */
+ if ((bus_number == 0) && (devfn >> 3 != 0))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /*
+ * The following is a workaround for the CN57XX, CN56XX,
+ * CN55XX, and CN54XX errata with PCIe config reads from non
+ * existent devices. These chips will hang the PCIe link if a
+ * config read is performed that causes a UR response.
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||
+ OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) {
+ /*
+ * For our EBH5600 board, port 0 has a bridge with two
+ * PCI-X slots. We need a new special checks to make
+ * sure we only probe valid stuff. The PCIe->PCI-X
+ * bridge only respondes to device ID 0, function
+ * 0-1
+ */
+ if ((bus_number == 0) && (devfn >= 2))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ /*
+ * The PCI-X slots are device ID 2,3. Choose one of
+ * the below "if" blocks based on what is plugged into
+ * the board.
+ */
+#if 1
+ /* Use this option if you aren't using either slot */
+ if (bus_number == 1)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+#elif 0
+ /*
+ * Use this option if you are using the first slot but
+ * not the second.
+ */
+ if ((bus_number == 1) && (devfn >> 3 != 2))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+#elif 0
+ /*
+ * Use this option if you are using the second slot
+ * but not the first.
+ */
+ if ((bus_number == 1) && (devfn >> 3 != 3))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+#elif 0
+ /* Use this opion if you are using both slots */
+ if ((bus_number == 1) &&
+ !((devfn == (2 << 3)) || (devfn == (3 << 3))))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+#endif
+
+ /*
+ * Shorten the DID timeout so bus errors for PCIe
+ * config reads from non existent devices happen
+ * faster. This allows us to continue booting even if
+ * the above "if" checks are wrong. Once one of these
+ * errors happens, the PCIe port is dead.
+ */
+ cvmmemctl_save.u64 = __read_64bit_c0_register($11, 7);
+ cvmmemctl.u64 = cvmmemctl_save.u64;
+ cvmmemctl.s.didtto = 2;
+ __write_64bit_c0_register($11, 7, cvmmemctl.u64);
+ }
+
+ switch (size) {
+ case 4:
+ *val = cvmx_pcie_config_read32(pcie_port, bus_number,
+ devfn >> 3, devfn & 0x7, reg);
+ break;
+ case 2:
+ *val = cvmx_pcie_config_read16(pcie_port, bus_number,
+ devfn >> 3, devfn & 0x7, reg);
+ break;
+ case 1:
+ *val = cvmx_pcie_config_read8(pcie_port, bus_number, devfn >> 3,
+ devfn & 0x7, reg);
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||
+ OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1))
+ __write_64bit_c0_register($11, 7, cvmmemctl_save.u64);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int octeon_pcie0_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ return octeon_pcie_read_config(0, bus, devfn, reg, size, val);
+}
+
+static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ return octeon_pcie_read_config(1, bus, devfn, reg, size, val);
+}
+
+
+
+/**
+ * Write a value to PCI configuration space
+ *
+ * @param bus
+ * @param devfn
+ * @param reg
+ * @param size
+ * @param val
+ * @return
+ */
+static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus,
+ unsigned int devfn, int reg,
+ int size, u32 val)
+{
+ int bus_number = bus->number;
+ /*
+ * We need to force the bus number to be zero on the root
+ * bus. Linux numbers the 2nd root bus to start after all
+ * busses on root 0.
+ */
+ if (bus->parent == NULL)
+ bus_number = 0;
+
+ switch (size) {
+ case 4:
+ cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3,
+ devfn & 0x7, reg, val);
+ return PCIBIOS_SUCCESSFUL;
+ case 2:
+ cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3,
+ devfn & 0x7, reg, val);
+ return PCIBIOS_SUCCESSFUL;
+ case 1:
+ cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3,
+ devfn & 0x7, reg, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+#if PCI_CONFIG_SPACE_DELAY
+ udelay(PCI_CONFIG_SPACE_DELAY);
+#endif
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+static int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ return octeon_pcie_write_config(0, bus, devfn, reg, size, val);
+}
+
+static int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ return octeon_pcie_write_config(1, bus, devfn, reg, size, val);
+}
+
+static struct pci_ops octeon_pcie0_ops = {
+ octeon_pcie0_read_config,
+ octeon_pcie0_write_config,
+};
+
+static struct resource octeon_pcie0_mem_resource = {
+ .name = "Octeon PCIe0 MEM",
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource octeon_pcie0_io_resource = {
+ .name = "Octeon PCIe0 IO",
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller octeon_pcie0_controller = {
+ .pci_ops = &octeon_pcie0_ops,
+ .mem_resource = &octeon_pcie0_mem_resource,
+ .io_resource = &octeon_pcie0_io_resource,
+};
+
+static struct pci_ops octeon_pcie1_ops = {
+ octeon_pcie1_read_config,
+ octeon_pcie1_write_config,
+};
+
+static struct resource octeon_pcie1_mem_resource = {
+ .name = "Octeon PCIe1 MEM",
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource octeon_pcie1_io_resource = {
+ .name = "Octeon PCIe1 IO",
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller octeon_pcie1_controller = {
+ .pci_ops = &octeon_pcie1_ops,
+ .mem_resource = &octeon_pcie1_mem_resource,
+ .io_resource = &octeon_pcie1_io_resource,
+};
+
+
+/**
+ * Initialize the Octeon PCIe controllers
+ *
+ * @return
+ */
+static int __init octeon_pcie_setup(void)
+{
+ union cvmx_npei_ctl_status npei_ctl_status;
+ int result;
+
+ /* These chips don't have PCIe */
+ if (!octeon_has_feature(OCTEON_FEATURE_PCIE))
+ return 0;
+
+ /* Point pcibios_map_irq() to the PCIe version of it */
+ octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq;
+
+ /* Use the PCIe based DMA mappings */
+ octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE;
+
+ /*
+ * PCIe I/O range. It is based on port 0 but includes up until
+ * port 1's end.
+ */
+ set_io_port_base(CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)));
+ ioport_resource.start = 0;
+ ioport_resource.end =
+ cvmx_pcie_get_io_base_address(1) -
+ cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1;
+
+ npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
+ if (npei_ctl_status.s.host_mode) {
+ pr_notice("PCIe: Initializing port 0\n");
+ result = cvmx_pcie_rc_initialize(0);
+ if (result == 0) {
+ /* Memory offsets are physical addresses */
+ octeon_pcie0_controller.mem_offset =
+ cvmx_pcie_get_mem_base_address(0);
+ /* IO offsets are Mips virtual addresses */
+ octeon_pcie0_controller.io_map_base =
+ CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address
+ (0));
+ octeon_pcie0_controller.io_offset = 0;
+ /*
+ * To keep things similar to PCI, we start
+ * device addresses at the same place as PCI
+ * uisng big bar support. This normally
+ * translates to 4GB-256MB, which is the same
+ * as most x86 PCs.
+ */
+ octeon_pcie0_controller.mem_resource->start =
+ cvmx_pcie_get_mem_base_address(0) +
+ (4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
+ octeon_pcie0_controller.mem_resource->end =
+ cvmx_pcie_get_mem_base_address(0) +
+ cvmx_pcie_get_mem_size(0) - 1;
+ /*
+ * Ports must be above 16KB for the ISA bus
+ * filtering in the PCI-X to PCI bridge.
+ */
+ octeon_pcie0_controller.io_resource->start = 4 << 10;
+ octeon_pcie0_controller.io_resource->end =
+ cvmx_pcie_get_io_size(0) - 1;
+ register_pci_controller(&octeon_pcie0_controller);
+ }
+ } else {
+ pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n");
+ }
+
+ /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */
+ if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
+ union cvmx_npei_dbg_data npei_dbg_data;
+ npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+ if (npei_dbg_data.cn52xx.qlm0_link_width)
+ return 0;
+ }
+
+ pr_notice("PCIe: Initializing port 1\n");
+ result = cvmx_pcie_rc_initialize(1);
+ if (result == 0) {
+ /* Memory offsets are physical addresses */
+ octeon_pcie1_controller.mem_offset =
+ cvmx_pcie_get_mem_base_address(1);
+ /* IO offsets are Mips virtual addresses */
+ octeon_pcie1_controller.io_map_base =
+ CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(1));
+ octeon_pcie1_controller.io_offset =
+ cvmx_pcie_get_io_base_address(1) -
+ cvmx_pcie_get_io_base_address(0);
+ /*
+ * To keep things similar to PCI, we start device
+ * addresses at the same place as PCI uisng big bar
+ * support. This normally translates to 4GB-256MB,
+ * which is the same as most x86 PCs.
+ */
+ octeon_pcie1_controller.mem_resource->start =
+ cvmx_pcie_get_mem_base_address(1) + (4ul << 30) -
+ (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
+ octeon_pcie1_controller.mem_resource->end =
+ cvmx_pcie_get_mem_base_address(1) +
+ cvmx_pcie_get_mem_size(1) - 1;
+ /*
+ * Ports must be above 16KB for the ISA bus filtering
+ * in the PCI-X to PCI bridge.
+ */
+ octeon_pcie1_controller.io_resource->start =
+ cvmx_pcie_get_io_base_address(1) -
+ cvmx_pcie_get_io_base_address(0);
+ octeon_pcie1_controller.io_resource->end =
+ octeon_pcie1_controller.io_resource->start +
+ cvmx_pcie_get_io_size(1) - 1;
+ register_pci_controller(&octeon_pcie1_controller);
+ }
+ return 0;
+}
+
+arch_initcall(octeon_pcie_setup);
diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h
index 07547231e078..59f28e9412c4 100644
--- a/arch/mips/include/asm/mach-ip27/topology.h
+++ b/arch/mips/include/asm/mach-ip27/topology.h
@@ -24,12 +24,10 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
#define cpu_to_node(cpu) (sn_cpu_info[(cpu)].p_nodeid)
#define parent_node(node) (node)
-#define node_to_cpumask(node) (hub_data(node)->h_cpus)
#define cpumask_of_node(node) (&hub_data(node)->h_cpus)
struct pci_bus;
extern int pcibus_to_node(struct pci_bus *);
-#define pcibus_to_cpumask(bus) (cpu_online_map)
#define cpumask_of_pcibus(bus) (cpu_online_mask)
extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
index d3bea88d8744..d9743536a621 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -178,8 +178,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* Mark current->active_mm as not "active" anymore.
* We don't want to mislead possible IPI tlb flush routines.
*/
- cpu_clear(cpu, prev->cpu_vm_mask);
- cpu_set(cpu, next->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
+ cpumask_set_cpu(cpu, mm_cpumask(next));
local_irq_restore(flags);
}
@@ -235,8 +235,8 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next)
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
/* mark mmu ownership change */
- cpu_clear(cpu, prev->cpu_vm_mask);
- cpu_set(cpu, next->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
+ cpumask_set_cpu(cpu, mm_cpumask(next));
local_irq_restore(flags);
}
@@ -258,7 +258,7 @@ drop_mmu_context(struct mm_struct *mm, unsigned cpu)
local_irq_save(flags);
- if (cpu_isset(cpu, mm->cpu_vm_mask)) {
+ if (cpumask_test_cpu(cpu, mm_cpumask(mm))) {
get_new_mmu_context(mm, cpu);
#ifdef CONFIG_MIPS_MT_SMTC
/* See comments for similar code above */
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index a68d111e55e9..5ebf82572ec0 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -65,8 +65,6 @@ extern int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
extern unsigned int pcibios_assign_all_busses(void);
-#define pcibios_scan_all_fns(a, b) 0
-
extern unsigned long PCIBIOS_MIN_IO;
extern unsigned long PCIBIOS_MIN_MEM;
diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h
index 1275831dda29..3738f4b48cbd 100644
--- a/arch/mips/include/asm/pgalloc.h
+++ b/arch/mips/include/asm/pgalloc.h
@@ -98,23 +98,12 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
__free_pages(pte, PTE_ORDER);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,address) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb), pte); \
} while (0)
-#ifdef CONFIG_32BIT
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb, x) do { } while (0)
-
-#endif
-
#ifdef CONFIG_64BIT
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -132,7 +121,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
free_pages((unsigned long)pmd, PMD_ORDER);
}
-#define __pmd_free_tlb(tlb, x) pmd_free((tlb)->mm, x)
+#define __pmd_free_tlb(tlb, x, addr) pmd_free((tlb)->mm, x)
#endif
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index fd545547b8aa..9e09af34c8a8 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -19,7 +19,7 @@ struct task_struct;
struct plat_smp_ops {
void (*send_ipi_single)(int cpu, unsigned int action);
- void (*send_ipi_mask)(cpumask_t mask, unsigned int action);
+ void (*send_ipi_mask)(const struct cpumask *mask, unsigned int action);
void (*init_secondary)(void);
void (*smp_finish)(void);
void (*cpus_done)(void);
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index aaa2d4ab26dc..e15f11a09311 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -78,6 +78,6 @@ extern void play_dead(void);
extern asmlinkage void smp_call_function_interrupt(void);
extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#endif /* __ASM_SMP_H */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 15874f9812cc..7c4a94f43706 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -164,7 +164,7 @@ EXPORT(sysn32_call_table)
PTR sys_connect
PTR sys_accept
PTR sys_sendto
- PTR sys_recvfrom
+ PTR compat_sys_recvfrom
PTR compat_sys_sendmsg /* 6045 */
PTR compat_sys_recvmsg
PTR sys_shutdown
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 781e0f1e9533..821fc978673d 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -378,8 +378,8 @@ sys_call_table:
PTR sys_getsockname
PTR sys_getsockopt
PTR sys_listen
- PTR sys_recv /* 4175 */
- PTR sys_recvfrom
+ PTR compat_sys_recv /* 4175 */
+ PTR compat_sys_recvfrom
PTR compat_sys_recvmsg
PTR sys_send
PTR compat_sys_sendmsg
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
index ad0ff5dc4d59..cc81771b882c 100644
--- a/arch/mips/kernel/smp-cmp.c
+++ b/arch/mips/kernel/smp-cmp.c
@@ -80,11 +80,11 @@ void cmp_send_ipi_single(int cpu, unsigned int action)
local_irq_restore(flags);
}
-static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void cmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
cmp_send_ipi_single(i, action);
}
@@ -171,7 +171,7 @@ void __init cmp_smp_setup(void)
for (i = 1; i < NR_CPUS; i++) {
if (amon_cpu_avail(i)) {
- cpu_set(i, cpu_possible_map);
+ set_cpu_possible(i, true);
__cpu_number_map[i] = ++ncpu;
__cpu_logical_map[ncpu] = i;
}
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 6f7ee5ac46ee..43e7cdc5ded2 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -70,7 +70,7 @@ static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
write_vpe_c0_vpeconf0(tmp);
/* Record this as available CPU */
- cpu_set(tc, cpu_possible_map);
+ set_cpu_possible(tc, true);
__cpu_number_map[tc] = ++ncpu;
__cpu_logical_map[ncpu] = tc;
}
@@ -141,11 +141,11 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action)
local_irq_restore(flags);
}
-static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
vsmp_send_ipi_single(i, action);
}
diff --git a/arch/mips/kernel/smp-up.c b/arch/mips/kernel/smp-up.c
index 2508d55d68fd..00500fea2750 100644
--- a/arch/mips/kernel/smp-up.c
+++ b/arch/mips/kernel/smp-up.c
@@ -18,7 +18,8 @@ static void up_send_ipi_single(int cpu, unsigned int action)
panic(KERN_ERR "%s called", __func__);
}
-static inline void up_send_ipi_mask(cpumask_t mask, unsigned int action)
+static inline void up_send_ipi_mask(const struct cpumask *mask,
+ unsigned int action)
{
panic(KERN_ERR "%s called", __func__);
}
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index bc7d9b05e2f4..b5f7f17551ba 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -129,7 +129,7 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_idle();
}
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION);
}
@@ -184,15 +184,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
mp_ops->prepare_cpus(max_cpus);
set_cpu_sibling_map(0);
#ifndef CONFIG_HOTPLUG_CPU
- cpu_present_map = cpu_possible_map;
+ init_cpu_present(&cpu_possible_map);
#endif
}
/* preload SMP state for boot cpu */
void __devinit smp_prepare_boot_cpu(void)
{
- cpu_set(0, cpu_possible_map);
- cpu_set(0, cpu_online_map);
+ set_cpu_possible(0, true);
+ set_cpu_online(0, true);
cpu_set(0, cpu_callin_map);
}
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 8a0626cbb108..d3b4162d09c7 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -305,7 +305,7 @@ int __init smtc_build_cpu_map(int start_cpu_slot)
*/
ntcs = ((read_c0_mvpconf0() & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
for (i=start_cpu_slot; i<NR_CPUS && i<ntcs; i++) {
- cpu_set(i, cpu_possible_map);
+ set_cpu_possible(i, true);
__cpu_number_map[i] = i;
__cpu_logical_map[i] = i;
}
@@ -522,8 +522,8 @@ void smtc_prepare_cpus(int cpus)
* Pull any physically present but unused TCs out of circulation.
*/
while (tc < (((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1)) {
- cpu_clear(tc, cpu_possible_map);
- cpu_clear(tc, cpu_present_map);
+ set_cpu_possible(tc, false);
+ set_cpu_present(tc, false);
tc++;
}
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 58738c8d754f..1474c18fb777 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -176,17 +176,6 @@ SECTIONS
_end = . ;
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exitcall.exit)
-
- /* ABI crap starts here */
- *(.MIPS.options)
- *(.options)
- *(.pdr)
- *(.reginfo)
- }
-
/* These mark the ABI of the kernel for debuggers. */
.mdebug.abi32 : {
KEEP(*(.mdebug.abi32))
@@ -212,4 +201,14 @@ SECTIONS
*(.gptab.bss)
*(.gptab.sbss)
}
+
+ /* Sections to be discarded */
+ DISCARDS
+ /DISCARD/ : {
+ /* ABI crap starts here */
+ *(.MIPS.options)
+ *(.options)
+ *(.pdr)
+ *(.reginfo)
+ }
}
diff --git a/arch/mips/mipssim/sim_smtc.c b/arch/mips/mipssim/sim_smtc.c
index d6e4f656ad14..5da30b6a65b7 100644
--- a/arch/mips/mipssim/sim_smtc.c
+++ b/arch/mips/mipssim/sim_smtc.c
@@ -43,11 +43,12 @@ static void ssmtc_send_ipi_single(int cpu, unsigned int action)
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
}
-static inline void ssmtc_send_ipi_mask(cpumask_t mask, unsigned int action)
+static inline void ssmtc_send_ipi_mask(const struct cpumask *mask,
+ unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
ssmtc_send_ipi_single(i, action);
}
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index b165cdcb2818..d3914f2335de 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -79,7 +79,7 @@ static void octeon_flush_icache_all_cores(struct vm_area_struct *vma)
* cores it has been used on
*/
if (vma)
- mask = vma->vm_mm->cpu_vm_mask;
+ mask = *mm_cpumask(vma->vm_mm);
else
mask = cpu_online_map;
cpu_clear(cpu, mask);
diff --git a/arch/mips/mti-malta/malta-smtc.c b/arch/mips/mti-malta/malta-smtc.c
index 499ffe5475df..192cfd2a539c 100644
--- a/arch/mips/mti-malta/malta-smtc.c
+++ b/arch/mips/mti-malta/malta-smtc.c
@@ -21,11 +21,11 @@ static void msmtc_send_ipi_single(int cpu, unsigned int action)
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
}
-static void msmtc_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void msmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
msmtc_send_ipi_single(i, action);
}
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
index 8ace27716232..326fe7a392e8 100644
--- a/arch/mips/pmc-sierra/yosemite/smp.c
+++ b/arch/mips/pmc-sierra/yosemite/smp.c
@@ -97,11 +97,11 @@ static void yos_send_ipi_single(int cpu, unsigned int action)
}
}
-static void yos_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
yos_send_ipi_single(i, action);
}
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 060d853d7b35..f61c164d1e67 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -421,7 +421,7 @@ static void __init node_mem_init(cnodeid_t node)
/*
* A node with nothing. We use it to avoid any special casing in
- * node_to_cpumask
+ * cpumask_of_node
*/
static struct node_data null_node = {
.hub = {
diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c
index cbcd7eb83bd1..9aa8f2951df6 100644
--- a/arch/mips/sgi-ip27/ip27-smp.c
+++ b/arch/mips/sgi-ip27/ip27-smp.c
@@ -165,11 +165,11 @@ static void ip27_send_ipi_single(int destid, unsigned int action)
REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq);
}
-static void ip27_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void ip27_send_ipi(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
ip27_send_ipi_single(i, action);
}
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 314691648c97..47b347c992ea 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -82,11 +82,12 @@ static void bcm1480_send_ipi_single(int cpu, unsigned int action)
__raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
}
-static void bcm1480_send_ipi_mask(cpumask_t mask, unsigned int action)
+static void bcm1480_send_ipi_mask(const struct cpumask *mask,
+ unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
bcm1480_send_ipi_single(i, action);
}
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index cad14003b84f..c00a5cb1128d 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -70,11 +70,12 @@ static void sb1250_send_ipi_single(int cpu, unsigned int action)
__raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
}
-static inline void sb1250_send_ipi_mask(cpumask_t mask, unsigned int action)
+static inline void sb1250_send_ipi_mask(const struct cpumask *mask,
+ unsigned int action)
{
unsigned int i;
- for_each_cpu_mask(i, mask)
+ for_each_cpu(i, mask)
sb1250_send_ipi_single(i, action);
}
diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h
index 2db746a251f8..1a55d61f0d06 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -17,7 +17,7 @@
#include <linux/mm.h>
/*
- * virtually-indexed cache managment (our cache is physically indexed)
+ * virtually-indexed cache management (our cache is physically indexed)
*/
#define flush_cache_all() do {} while (0)
#define flush_cache_mm(mm) do {} while (0)
@@ -31,7 +31,7 @@
#define flush_dcache_mmap_unlock(mapping) do {} while (0)
/*
- * physically-indexed cache managment
+ * physically-indexed cache management
*/
#ifndef CONFIG_MN10300_CACHE_DISABLED
diff --git a/arch/mn10300/include/asm/gdb-stub.h b/arch/mn10300/include/asm/gdb-stub.h
index e5a6368559af..556cce992548 100644
--- a/arch/mn10300/include/asm/gdb-stub.h
+++ b/arch/mn10300/include/asm/gdb-stub.h
@@ -109,7 +109,6 @@ extern asmlinkage int gdbstub_intercept(struct pt_regs *, enum exception_code);
extern asmlinkage void gdbstub_exception(struct pt_regs *, enum exception_code);
extern asmlinkage void __gdbstub_bug_trap(void);
extern asmlinkage void __gdbstub_pause(void);
-extern asmlinkage void start_kernel(void);
#ifndef CONFIG_MN10300_CACHE_DISABLED
extern asmlinkage void gdbstub_purge_cache(void);
diff --git a/arch/mn10300/include/asm/mmu_context.h b/arch/mn10300/include/asm/mmu_context.h
index a9e2e34f69b0..cb294c244de3 100644
--- a/arch/mn10300/include/asm/mmu_context.h
+++ b/arch/mn10300/include/asm/mmu_context.h
@@ -38,13 +38,13 @@ extern unsigned long mmu_context_cache[NR_CPUS];
#define enter_lazy_tlb(mm, tsk) do {} while (0)
#ifdef CONFIG_SMP
-#define cpu_ran_vm(cpu, task) \
- cpu_set((cpu), (task)->cpu_vm_mask)
-#define cpu_maybe_ran_vm(cpu, task) \
- cpu_test_and_set((cpu), (task)->cpu_vm_mask)
+#define cpu_ran_vm(cpu, mm) \
+ cpumask_set_cpu((cpu), mm_cpumask(mm))
+#define cpu_maybe_ran_vm(cpu, mm) \
+ cpumask_test_and_set_cpu((cpu), mm_cpumask(mm))
#else
-#define cpu_ran_vm(cpu, task) do {} while (0)
-#define cpu_maybe_ran_vm(cpu, task) true
+#define cpu_ran_vm(cpu, mm) do {} while (0)
+#define cpu_maybe_ran_vm(cpu, mm) true
#endif /* CONFIG_SMP */
/*
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 35d2ed6396f6..5b43a1d51173 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -102,7 +102,18 @@ extern void pcibios_bus_to_resource(struct pci_dev *dev,
struct resource *res,
struct pci_bus_region *region);
-#define pcibios_scan_all_fns(a, b) 0
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+ struct resource *root = NULL;
+
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ if (res->flags & IORESOURCE_MEM)
+ root = &iomem_resource;
+
+ return root;
+}
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/arch/mn10300/include/asm/pgalloc.h b/arch/mn10300/include/asm/pgalloc.h
index ec057e1bd4cf..a19f11327cd8 100644
--- a/arch/mn10300/include/asm/pgalloc.h
+++ b/arch/mn10300/include/asm/pgalloc.h
@@ -51,6 +51,6 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte)
}
-#define __pte_free_tlb(tlb, pte) tlb_remove_page((tlb), (pte))
+#define __pte_free_tlb(tlb, pte, addr) tlb_remove_page((tlb), (pte))
#endif /* _ASM_PGALLOC_H */
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
index f4aa07934654..76f41bdb79c4 100644
--- a/arch/mn10300/kernel/vmlinux.lds.S
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -115,12 +115,10 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
pg0 = .;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_CALL
- }
-
STABS_DEBUG
DWARF_DEBUG
+
+ /* Sections to be discarded */
+ DISCARDS
}
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 7d842d699df2..64c7aa590ae5 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -233,7 +233,6 @@ static inline void pcibios_register_hba(struct pci_hba_data *x)
* rp7420/8420 boxes and then revisit this issue.
*/
#define pcibios_assign_all_busses() (1)
-#define pcibios_scan_all_fns(a, b) (0)
#define PCIBIOS_MIN_IO 0x10
#define PCIBIOS_MIN_MEM 0x1000 /* NBPG - but pci/setup-res.c dies */
diff --git a/arch/parisc/include/asm/smp.h b/arch/parisc/include/asm/smp.h
index 21eb45a52629..2e73623feb6b 100644
--- a/arch/parisc/include/asm/smp.h
+++ b/arch/parisc/include/asm/smp.h
@@ -30,7 +30,6 @@ extern void smp_send_all_nop(void);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
#endif /* !ASSEMBLY */
diff --git a/arch/parisc/include/asm/tlb.h b/arch/parisc/include/asm/tlb.h
index 383b1db310ee..07924903989e 100644
--- a/arch/parisc/include/asm/tlb.h
+++ b/arch/parisc/include/asm/tlb.h
@@ -21,7 +21,7 @@ do { if (!(tlb)->fullmm) \
#include <asm-generic/tlb.h>
-#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
#endif
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index fd2cc4fd2b65..aea1784edbd1 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -237,9 +237,12 @@ SECTIONS
/* freed after init ends here */
_end = . ;
+ STABS_DEBUG
+ .note 0 : { *(.note) }
+
/* Sections to be discarded */
+ DISCARDS
/DISCARD/ : {
- *(.exitcall.exit)
#ifdef CONFIG_64BIT
/* temporary hack until binutils is fixed to not emit these
* for static binaries
@@ -252,7 +255,4 @@ SECTIONS
*(.gnu.hash)
#endif
}
-
- STABS_DEBUG
- .note 0 : { *(.note) }
}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d00131ca0835..3b84539cdcf4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -46,6 +46,9 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
bool
default y
+config HAVE_LEGACY_PER_CPU_AREA
+ def_bool PPC64
+
config HAVE_SETUP_PER_CPU_AREA
def_bool PPC64
@@ -472,7 +475,7 @@ config PPC_16K_PAGES
bool "16k page size" if 44x
config PPC_64K_PAGES
- bool "64k page size" if 44x || PPC_STD_MMU_64
+ bool "64k page size" if 44x || PPC_STD_MMU_64 || PPC_BOOK3E_64
select PPC_HAS_HASH_64K if PPC_STD_MMU_64
config PPC_256K_PAGES
@@ -492,16 +495,16 @@ endchoice
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
- range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
- default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
- range 13 64 if PPC_STD_MMU_64 && !PPC_64K_PAGES
- default "13" if PPC_STD_MMU_64 && !PPC_64K_PAGES
- range 9 64 if PPC_STD_MMU_32 && PPC_16K_PAGES
- default "9" if PPC_STD_MMU_32 && PPC_16K_PAGES
- range 7 64 if PPC_STD_MMU_32 && PPC_64K_PAGES
- default "7" if PPC_STD_MMU_32 && PPC_64K_PAGES
- range 5 64 if PPC_STD_MMU_32 && PPC_256K_PAGES
- default "5" if PPC_STD_MMU_32 && PPC_256K_PAGES
+ range 9 64 if PPC64 && PPC_64K_PAGES
+ default "9" if PPC64 && PPC_64K_PAGES
+ range 13 64 if PPC64 && !PPC_64K_PAGES
+ default "13" if PPC64 && !PPC_64K_PAGES
+ range 9 64 if PPC32 && PPC_16K_PAGES
+ default "9" if PPC32 && PPC_16K_PAGES
+ range 7 64 if PPC32 && PPC_64K_PAGES
+ default "7" if PPC32 && PPC_64K_PAGES
+ range 5 64 if PPC32 && PPC_256K_PAGES
+ default "5" if PPC32 && PPC_256K_PAGES
range 11 64
default "11"
help
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index bc35f4e2b81c..952a3963e9e8 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -77,7 +77,7 @@ CPP = $(CC) -E $(KBUILD_CFLAGS)
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
ifeq ($(CONFIG_PPC64),y)
-GCC_BROKEN_VEC := $(shell if [ $(call cc-version) -lt 0400 ] ; then echo "y"; fi)
+GCC_BROKEN_VEC := $(call cc-ifversion, -lt, 0400, y)
ifeq ($(CONFIG_POWER4_ONLY),y)
ifeq ($(CONFIG_ALTIVEC),y)
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 5fd1ad09bdf2..c920170b7dfe 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for AMCC Canyonlands (460EX)
*
- * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ * Copyright 2008-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without
@@ -149,19 +149,19 @@
/*RXDE*/ 0x5 0x4>;
};
- USB0: ehci@bffd0400 {
- compatible = "ibm,usb-ehci-460ex", "usb-ehci";
- interrupt-parent = <&UIC2>;
- interrupts = <0x1d 4>;
- reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
- };
+ USB0: ehci@bffd0400 {
+ compatible = "ibm,usb-ehci-460ex", "usb-ehci";
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x1d 4>;
+ reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
+ };
- USB1: usb@bffd0000 {
- compatible = "ohci-le";
- reg = <4 0xbffd0000 0x60>;
- interrupt-parent = <&UIC2>;
- interrupts = <0x1e 4>;
- };
+ USB1: usb@bffd0000 {
+ compatible = "ohci-le";
+ reg = <4 0xbffd0000 0x60>;
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x1e 4>;
+ };
POB0: opb {
compatible = "ibm,opb-460ex", "ibm,opb";
@@ -215,6 +215,29 @@
reg = <0x03fa0000 0x00060000>;
};
};
+
+ ndfc@3,0 {
+ compatible = "ibm,ndfc";
+ reg = <0x00000003 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x00100000>;
+ };
+ partition@100000 {
+ label = "user";
+ reg = <0x00000000 0x03f00000>;
+ };
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts
index 5e6b08ff6f67..c46561456ede 100644
--- a/arch/powerpc/boot/dts/kilauea.dts
+++ b/arch/powerpc/boot/dts/kilauea.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for AMCC Kilauea (405EX)
*
- * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ * Copyright 2007-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without
@@ -150,7 +150,11 @@
#size-cells = <1>;
partition@0 {
label = "kernel";
- reg = <0x00000000 0x00200000>;
+ reg = <0x00000000 0x001e0000>;
+ };
+ partition@1e0000 {
+ label = "dtb";
+ reg = <0x001e0000 0x00020000>;
};
partition@200000 {
label = "root";
@@ -169,6 +173,29 @@
reg = <0x03fa0000 0x00060000>;
};
};
+
+ ndfc@1,0 {
+ compatible = "ibm,ndfc";
+ reg = <0x00000001 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x00100000>;
+ };
+ partition@100000 {
+ label = "user";
+ reg = <0x00000000 0x03f00000>;
+ };
+ };
+ };
};
UART0: serial@ef600200 {
@@ -198,6 +225,18 @@
reg = <0xef600400 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@68 {
+ compatible = "dallas,ds1338";
+ reg = <0x68>;
+ };
+
+ dtt@48 {
+ compatible = "dallas,ds1775";
+ reg = <0x48>;
+ };
};
IIC1: i2c@ef600500 {
@@ -207,7 +246,6 @@
interrupts = <0x7 0x4>;
};
-
RGMII0: emac-rgmii@ef600b00 {
compatible = "ibm,rgmii-405ex", "ibm,rgmii";
reg = <0xef600b00 0x00000104>;
diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts
index 224b4f0704b8..4f06dbc0d27e 100644
--- a/arch/powerpc/boot/dts/mpc8377_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts
@@ -410,7 +410,7 @@
bus-range = <0 0>;
ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+ 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
sleep = <&pmc 0x00010000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts
index 474ea2fa3f86..aabf3437cadf 100644
--- a/arch/powerpc/boot/dts/mpc8378_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts
@@ -394,7 +394,7 @@
bus-range = <0 0>;
ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+ 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
sleep = <&pmc 0x00010000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts
index d4838af8d379..9b1da864d890 100644
--- a/arch/powerpc/boot/dts/mpc8379_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts
@@ -424,7 +424,7 @@
bus-range = <0x0 0x0>;
ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+ 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
sleep = <&pmc 0x00010000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts
index a680165292f2..9e4ce99e1613 100644
--- a/arch/powerpc/boot/dts/mpc8569mds.dts
+++ b/arch/powerpc/boot/dts/mpc8569mds.dts
@@ -501,6 +501,10 @@
reg = <0x6>;
device_type = "ethernet-phy";
};
+ tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
};
mdio@3520 {
#address-cells = <1>;
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 4db487d1d2a8..ac9e9a58b2b0 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -46,6 +46,7 @@ CROSS=
# directory for object and other files used by this script
object=arch/powerpc/boot
objbin=$object
+dtc=scripts/dtc/dtc
# directory for working files
tmpdir=.
@@ -124,7 +125,7 @@ if [ -n "$dts" ]; then
if [ -z "$dtb" ]; then
dtb="$platform.dtb"
fi
- $object/dtc -O dtb -o "$dtb" -b 0 "$dts"
+ $dtc -O dtb -o "$dtb" -b 0 "$dts"
fi
if [ -z "$kernel" ]; then
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index 865725effe93..9a05ec0ec312 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc7
-# Wed Jun 3 10:18:16 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 13:28:37 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
CONFIG_40x=y
@@ -32,11 +32,11 @@ CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -57,6 +57,7 @@ CONFIG_PPC_DCR_NATIVE=y
CONFIG_PPC_DCR=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +109,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -121,9 +121,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -137,6 +144,11 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -149,7 +161,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -220,6 +232,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_MATH_EMULATION is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -239,9 +252,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -344,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -393,9 +407,8 @@ CONFIG_MTD_OF_PARTS=y
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=m
-CONFIG_MTD_BLOCK=m
-# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
@@ -452,7 +465,17 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_NDFC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
# CONFIG_MTD_ONENAND is not set
#
@@ -465,6 +488,7 @@ CONFIG_MTD_PHYSMAP_OF=y
#
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -504,14 +528,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -546,6 +573,7 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -621,20 +649,150 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC 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
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# 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=y
+# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -649,24 +807,15 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -691,10 +840,69 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
# CONFIG_EDAC is not set
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -708,11 +916,12 @@ CONFIG_EXT2_FS=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -818,6 +1027,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -848,6 +1058,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -859,7 +1072,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -873,16 +1085,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -891,6 +1102,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index 5e85412eb9fa..b312b166be66 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc3
-# Mon Feb 2 13:13:04 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 17:27:20 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -31,15 +31,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,11 +54,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
CONFIG_PPC_DCR_NATIVE=y
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -71,6 +75,7 @@ CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
@@ -93,8 +98,12 @@ CONFIG_SYSFS_DEPRECATED_V2=y
# 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 is not set
CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
@@ -104,23 +113,30 @@ CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=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_EFFICIENT_UNALIGNED_ACCESS=y
@@ -128,6 +144,12 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
@@ -139,8 +161,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -176,6 +197,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y
# CONFIG_ARCHES is not set
CONFIG_CANYONLANDS=y
# CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
# CONFIG_YOSEMITE is not set
# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
CONFIG_PPC44x_SIMPLE=y
@@ -218,6 +240,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_MATH_EMULATION is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -237,10 +260,14 @@ CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_STDBINUTILS=y
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_PROC_DEVICETREE=y
CONFIG_CMDLINE_BOOL=y
@@ -265,6 +292,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_LEGACY is not set
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
# CONFIG_PCCARD is not set
# CONFIG_HOTPLUG_PCI is not set
# CONFIG_HAS_RAPIDIO is not set
@@ -282,14 +310,12 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0xc0000000
-CONFIG_CONSISTENT_START=0xff100000
CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
# Networking options
#
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -339,6 +365,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -351,7 +379,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
# CONFIG_WIRELESS is not set
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
@@ -375,7 +402,101 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_NDFC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
# CONFIG_PARPORT is not set
@@ -418,7 +539,11 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
@@ -439,6 +564,8 @@ CONFIG_NET_ETHERNET=y
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
CONFIG_IBM_NEW_EMAC=y
@@ -457,6 +584,7 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -467,7 +595,6 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
#
# Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -542,7 +669,6 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_RAW_DRIVER is not set
@@ -608,14 +734,17 @@ CONFIG_I2C_IBM_IIC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -640,6 +769,7 @@ CONFIG_SENSORS_AD7414=y
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_F71882FG is not set
# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
@@ -654,11 +784,14 @@ CONFIG_SENSORS_AD7414=y
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
@@ -666,6 +799,7 @@ CONFIG_SENSORS_AD7414=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -700,24 +834,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -759,6 +878,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -767,9 +887,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -789,11 +909,11 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_TMC is not set
#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#
#
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
#
CONFIG_USB_LIBUSUAL=y
@@ -821,7 +941,6 @@ CONFIG_USB_LIBUSUAL=y
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
@@ -837,6 +956,7 @@ CONFIG_USB_LIBUSUAL=y
#
# OTG and related infrastructure
#
+# CONFIG_NOP_USB_XCEIV is not set
# CONFIG_UWB is not set
# CONFIG_MMC is not set
# CONFIG_MEMSTICK is not set
@@ -844,9 +964,70 @@ CONFIG_USB_LIBUSUAL=y
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
# CONFIG_EDAC is not set
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+CONFIG_RTC_DRV_M41T80=y
+# CONFIG_RTC_DRV_M41T80_WDT is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -860,11 +1041,12 @@ CONFIG_EXT2_FS=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -874,6 +1056,11 @@ CONFIG_INOTIFY_USER=y
# CONFIG_FUSE_FS is not set
#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
@@ -906,6 +1093,7 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
CONFIG_CRAMFS=y
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -916,6 +1104,7 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -927,7 +1116,6 @@ CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -941,8 +1129,48 @@ CONFIG_SUNRPC=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
#
# Library routines
@@ -957,11 +1185,13 @@ CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -979,6 +1209,9 @@ CONFIG_DEBUG_KERNEL=y
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 is not set
@@ -989,6 +1222,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1000,7 +1236,6 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1008,27 +1243,36 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-
-#
-# Tracers
-#
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_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_DYNAMIC_PRINTK_DEBUG 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_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig
index 278939713775..a2df0635b6de 100644
--- a/arch/powerpc/configs/83xx/asp8347_defconfig
+++ b/arch/powerpc/configs/83xx/asp8347_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:05 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:02 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
CONFIG_FSL_EMB_PERFMON=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,6 +56,7 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
CONFIG_REDBOOT=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -60,6 +64,7 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -121,9 +125,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -136,6 +147,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -148,7 +163,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -190,6 +205,7 @@ CONFIG_PPC_83xx=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
CONFIG_ASP834x=y
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC834x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -235,6 +251,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -255,9 +272,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -490,6 +512,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -525,7 +548,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -545,14 +570,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -599,6 +627,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -618,8 +647,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -786,13 +817,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -847,6 +882,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -900,24 +936,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -960,6 +981,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1069,6 +1091,7 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1096,6 +1119,10 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1115,10 +1142,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1192,6 +1221,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1287,6 +1317,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1312,22 +1343,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig
index bf0853f29f31..93ebd443a18f 100644
--- a/arch/powerpc/configs/83xx/kmeter1_defconfig
+++ b/arch/powerpc/configs/83xx/kmeter1_defconfig
@@ -1,25 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28
-# Fri Apr 3 10:34:33 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:03 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
+CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,21 +33,22 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_NVRAM=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
CONFIG_OF=y
@@ -52,11 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -71,19 +78,30 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS 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 is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
@@ -93,17 +111,23 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
@@ -116,10 +140,15 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
@@ -127,11 +156,8 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -147,14 +173,11 @@ CONFIG_IOSCHED_NOOP=y
# CONFIG_DEFAULT_CFQ is not set
CONFIG_DEFAULT_NOOP=y
CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_CLASSIC_RCU=y
# CONFIG_FREEZER is not set
#
# Platform support
#
-CONFIG_PPC_MULTIPLATFORM=y
-CONFIG_CLASSIC32=y
# CONFIG_PPC_CHRP is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
@@ -179,6 +202,8 @@ CONFIG_PPC_83xx=y
CONFIG_KMETER1=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
+# CONFIG_AMIGAONE is not set
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
CONFIG_IPIC=y
# CONFIG_MPIC is not set
# CONFIG_MPIC_WEIRD is not set
@@ -194,6 +219,8 @@ CONFIG_IPIC=y
CONFIG_QUICC_ENGINE=y
# CONFIG_QE_GPIO is not set
# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_MCU_MPC8349EMITX is not set
#
# Kernel options
@@ -212,16 +239,17 @@ CONFIG_SCHED_HRTICK=y
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
-# CONFIG_PREEMPT_RCU is not set
CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -233,12 +261,17 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
-# CONFIG_RESOURCES_64BIT is not set
# 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_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
@@ -331,7 +364,10 @@ CONFIG_LLC=m
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
#
# Network testing
@@ -342,8 +378,8 @@ CONFIG_LLC=m
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -362,6 +398,7 @@ CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
@@ -431,6 +468,11 @@ CONFIG_MTD_PHRAM=y
# CONFIG_MTD_ONENAND is not set
#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
# UBI - Unsorted block images
#
CONFIG_MTD_UBI=y
@@ -445,7 +487,6 @@ CONFIG_MTD_UBI_DEBUG=y
# CONFIG_MTD_UBI_DEBUG_MSG is not set
# CONFIG_MTD_UBI_DEBUG_PARANOID is not set
# CONFIG_MTD_UBI_DEBUG_DISABLE_BGT is not set
-# CONFIG_MTD_UBI_DEBUG_USERSPACE_IO is not set
# CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS is not set
# CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES is not set
# CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES is not set
@@ -459,6 +500,7 @@ CONFIG_MTD_UBI_DEBUG=y
# CONFIG_MTD_UBI_DEBUG_MSG_IO is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -505,10 +547,15 @@ CONFIG_MARVELL_PHY=y
# 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 is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+# CONFIG_ETHOC 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
@@ -517,11 +564,12 @@ 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=y
+CONFIG_FSL_PQ_MDIO=y
# CONFIG_GIANFAR is not set
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
-# CONFIG_UGETH_FILTERING is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
# CONFIG_MV643XX_ETH is not set
# CONFIG_NETDEV_10000 is not set
@@ -531,7 +579,10 @@ CONFIG_UCC_GETH=y
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
CONFIG_WAN=y
CONFIG_HDLC=y
# CONFIG_HDLC_RAW is not set
@@ -543,8 +594,6 @@ CONFIG_HDLC=y
#
# X.25/LAPB support is disabled
#
-CONFIG_HDLC_KM=y
-CONFIG_FS_UCC_HDLC=y
# CONFIG_DLCI is not set
CONFIG_PPP=y
CONFIG_PPP_MULTILINK=y
@@ -600,16 +649,18 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_OF_PLATFORM is not set
# CONFIG_SERIAL_QE is not set
CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_NVRAM is not set
# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
-CONFIG_BOOTCOUNT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
@@ -642,20 +693,20 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_AT24 is not set
-# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_MCU_MPC8349EMITX is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -677,27 +728,15 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -720,11 +759,16 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_EDAC is not set
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
CONFIG_UIO=y
# CONFIG_UIO_PDRV is not set
# CONFIG_UIO_PDRV_GENIRQ is not set
# CONFIG_UIO_SMX is not set
# CONFIG_UIO_SERCOS3 is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -736,9 +780,12 @@ CONFIG_UIO=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -748,6 +795,11 @@ CONFIG_INOTIFY_USER=y
# CONFIG_FUSE_FS is not set
#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
@@ -772,10 +824,7 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
@@ -796,6 +845,7 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_UBIFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_OMFS_FS is not set
@@ -804,6 +854,7 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -815,7 +866,6 @@ CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -845,11 +895,13 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_DLM is not set
CONFIG_UCC_FAST=y
CONFIG_UCC=y
+# CONFIG_BINARY_PRINTF is not set
#
# Library routines
#
CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_T10DIF is not set
@@ -859,11 +911,12 @@ CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -883,13 +936,18 @@ CONFIG_DEBUG_FS=y
# CONFIG_LATENCYTOP is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_HAVE_FUNCTION_TRACER=y
-
-#
-# Tracers
-#
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_IRQSTACKS is not set
# CONFIG_VIRQ_DEBUG is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index c5c0fe71a438..ff33a7db2eab 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:06 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:04 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC831x_RDB=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC831x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -503,6 +525,7 @@ CONFIG_MTD_NAND_FSL_ELBC=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -539,7 +562,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -562,10 +587,6 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -583,6 +604,7 @@ CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -591,6 +613,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -610,7 +633,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -643,14 +665,17 @@ CONFIG_MD_RAID1=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -714,6 +739,8 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -735,8 +762,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -924,7 +953,6 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -938,13 +966,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
CONFIG_SPI_BITBANG=y
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1002,6 +1035,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1056,24 +1090,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1135,6 +1155,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1144,9 +1165,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1235,8 +1256,9 @@ CONFIG_USB_GADGET_SELECTED=y
# 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_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
@@ -1244,9 +1266,11 @@ CONFIG_USB_GADGET_SELECTED=y
CONFIG_USB_GADGET_NET2280=y
CONFIG_USB_NET2280=y
# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=y
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_GADGETFS is not set
@@ -1298,6 +1322,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1332,6 +1357,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1351,10 +1380,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1428,6 +1459,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1464,7 +1496,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
# CONFIG_BINARY_PRINTF is not set
@@ -1488,6 +1559,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1518,6 +1590,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1529,7 +1604,6 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1543,16 +1617,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1560,6 +1633,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index af4952feba36..76237d466702 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:06 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:05 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC831x_RDB=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC831x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -503,6 +525,7 @@ CONFIG_MTD_NAND_IDS=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -539,7 +562,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -562,10 +587,6 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -583,6 +604,7 @@ CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -591,6 +613,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -610,7 +633,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -704,14 +726,17 @@ CONFIG_MD_RAID1=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -775,6 +800,8 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -796,8 +823,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -985,7 +1014,6 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -999,13 +1027,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
CONFIG_SPI_BITBANG=y
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1063,6 +1096,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1117,24 +1151,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1196,6 +1216,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1205,9 +1226,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1296,8 +1317,9 @@ CONFIG_USB_GADGET_SELECTED=y
# 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_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
@@ -1305,9 +1327,11 @@ CONFIG_USB_GADGET_SELECTED=y
CONFIG_USB_GADGET_NET2280=y
CONFIG_USB_NET2280=y
# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=y
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_GADGETFS is not set
@@ -1359,6 +1383,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1393,6 +1418,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1412,10 +1441,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1489,6 +1520,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1525,7 +1557,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
# CONFIG_BINARY_PRINTF is not set
@@ -1549,6 +1620,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1579,6 +1651,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1590,7 +1665,6 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1604,16 +1678,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1621,6 +1694,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
index 8c8f660b4fc7..e0e36a113409 100644
--- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:07 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:06 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC832x_MDS=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC832x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -235,6 +251,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -255,9 +272,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -404,6 +426,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -438,7 +461,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -461,10 +486,6 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -482,6 +503,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -490,6 +512,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -509,7 +532,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -532,14 +554,17 @@ CONFIG_SCSI_LOWLEVEL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -586,6 +611,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -605,11 +631,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
# CONFIG_GIANFAR is not set
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -787,13 +815,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -848,6 +880,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -896,23 +929,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -996,6 +1015,7 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1023,6 +1043,10 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1042,10 +1066,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1108,6 +1134,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1165,6 +1192,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1190,22 +1218,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
index 227dbba76795..4f27d4548223 100644
--- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:08 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:07 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC832x_RDB=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC832x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -235,6 +251,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -255,9 +272,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -405,6 +427,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -441,7 +464,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -464,10 +489,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -485,6 +506,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -493,6 +515,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -512,7 +535,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -535,14 +557,17 @@ CONFIG_SCSI_LOWLEVEL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -590,6 +615,8 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -609,11 +636,13 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
# CONFIG_GIANFAR is not set
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -804,7 +833,6 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -817,13 +845,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
CONFIG_SPI_BITBANG=y
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -881,6 +914,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -935,24 +969,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1014,6 +1034,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1023,9 +1044,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1127,6 +1148,8 @@ CONFIG_MMC_BLOCK_BOUNCE=y
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
CONFIG_MMC_SPI=y
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
# CONFIG_MEMSTICK is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_ACCESSIBILITY is not set
@@ -1136,6 +1159,10 @@ CONFIG_MMC_SPI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1155,10 +1182,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1224,6 +1253,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1325,6 +1355,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1350,22 +1381,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
index 24ee7fcac87e..648dac0c9d8d 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:09 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:07 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC834x_ITX=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC834x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -365,6 +382,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -382,7 +400,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -487,6 +509,7 @@ CONFIG_MTD_PHYSMAP=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -523,7 +546,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -594,10 +619,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -615,6 +636,7 @@ CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -623,6 +645,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -642,7 +665,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -737,14 +759,17 @@ CONFIG_MD_RAID1=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -791,8 +816,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -960,7 +987,6 @@ CONFIG_I2C_MPC=y
CONFIG_SENSORS_PCF8574=y
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -973,13 +999,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
CONFIG_SPI_BITBANG=y
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1026,24 +1057,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1085,6 +1102,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1208,6 +1226,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1242,6 +1261,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1261,10 +1284,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1331,6 +1356,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1429,6 +1455,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1454,22 +1481,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
index 7f39543205a9..bf6deb831dc3 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:10 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:08 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC834x_ITX=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC834x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -365,6 +382,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -382,7 +400,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -487,6 +509,7 @@ CONFIG_MTD_PHYSMAP=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -523,7 +546,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -546,10 +571,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -567,6 +588,7 @@ CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -575,6 +597,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -594,7 +617,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -617,14 +639,17 @@ CONFIG_SCSI_LOWLEVEL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -671,8 +696,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -840,7 +867,6 @@ CONFIG_I2C_MPC=y
CONFIG_SENSORS_PCF8574=y
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -853,13 +879,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
CONFIG_SPI_BITBANG=y
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -906,24 +937,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -965,6 +982,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1087,6 +1105,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1121,6 +1140,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1140,10 +1163,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1210,6 +1235,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1308,6 +1334,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1333,22 +1360,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
index 1cd1fcac22c8..3236c47712c2 100644
--- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:11 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:09 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC834x_MDS=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC834x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -365,6 +382,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -382,7 +400,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -403,6 +425,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -437,7 +460,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -457,14 +482,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -527,6 +555,7 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -548,8 +577,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -724,13 +755,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -785,6 +820,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -833,23 +869,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -933,6 +955,7 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -960,6 +983,10 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -979,10 +1006,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1045,6 +1074,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1100,6 +1130,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1125,22 +1156,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
index ce5177393a0d..8c5299d74813 100644
--- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:12 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:10 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -135,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -189,6 +204,7 @@ CONFIG_MPC836x_MDS=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
# CONFIG_AMIGAONE is not set
@@ -233,6 +249,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -253,9 +270,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -364,6 +381,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -381,7 +399,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -485,6 +507,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -519,7 +542,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -542,10 +567,6 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -563,6 +584,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -571,6 +593,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -590,7 +613,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -613,14 +635,17 @@ CONFIG_SCSI_LOWLEVEL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -667,6 +692,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -686,11 +712,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
# CONFIG_GIANFAR is not set
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -868,13 +896,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -929,6 +961,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -977,23 +1010,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1077,6 +1096,7 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1104,6 +1124,10 @@ CONFIG_RTC_DRV_DS1374=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1123,10 +1147,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1190,6 +1216,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1247,6 +1274,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1272,22 +1300,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
index 7f1d1383a249..ff31667a890b 100644
--- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:13 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:12 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -54,12 +57,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -121,9 +125,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -136,6 +147,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -148,7 +163,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -190,6 +205,7 @@ CONFIG_MPC836x_RDK=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
# CONFIG_AMIGAONE is not set
@@ -233,6 +249,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -253,9 +270,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -366,6 +383,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,7 +401,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -498,6 +520,7 @@ CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -533,7 +556,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -553,14 +578,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -607,11 +635,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
# CONFIG_GIANFAR is not set
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -777,7 +807,6 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -791,13 +820,18 @@ CONFIG_SPI_MASTER=y
#
CONFIG_SPI_BITBANG=y
# CONFIG_SPI_GPIO is not set
-CONFIG_SPI_MPC83xx=y
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
CONFIG_SPI_SPIDEV=y
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -865,23 +899,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -990,6 +1011,10 @@ CONFIG_HID=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1009,10 +1034,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1086,6 +1113,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1145,6 +1173,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1170,22 +1199,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
index bf636fd560ad..e285ec0fe958 100644
--- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:12 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:11 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +113,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -121,8 +125,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -136,6 +147,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -148,7 +163,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -190,6 +205,7 @@ CONFIG_MPC837x_MDS=y
# CONFIG_MPC837x_RDB is not set
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC837x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -365,6 +382,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -382,7 +400,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -403,6 +425,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -437,7 +460,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -460,10 +485,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -481,6 +502,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -489,6 +511,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -508,7 +531,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -592,14 +614,17 @@ CONFIG_ATA_SFF=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -646,6 +671,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -665,8 +691,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -844,13 +872,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -905,6 +937,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -953,23 +986,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1026,6 +1045,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1045,10 +1068,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1111,6 +1136,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1170,6 +1196,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1193,22 +1220,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
index fe6454eacbdb..1ab3e4cd3018 100644
--- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:14 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:13 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +113,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -121,8 +125,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -136,6 +147,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -148,7 +163,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -190,6 +205,7 @@ CONFIG_PPC_83xx=y
CONFIG_MPC837x_RDB=y
# CONFIG_SBC834x is not set
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC837x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -254,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -360,6 +377,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -377,7 +395,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -398,6 +420,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -433,7 +456,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -456,10 +481,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -476,6 +497,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -484,6 +506,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -503,7 +526,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -598,14 +620,17 @@ CONFIG_MD_RAID6_PQ=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -652,6 +677,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -671,8 +697,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -842,13 +870,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -903,6 +935,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -956,24 +989,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1011,7 +1029,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1028,10 +1046,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1057,6 +1076,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1141,6 +1161,10 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1160,10 +1184,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1226,6 +1252,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1262,7 +1289,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
# CONFIG_BINARY_PRINTF is not set
@@ -1285,6 +1351,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1308,22 +1375,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig
index fe08f672cb27..a592b5efdc4d 100644
--- a/arch/powerpc/configs/83xx/sbc834x_defconfig
+++ b/arch/powerpc/configs/83xx/sbc834x_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:15 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:13 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,12 +56,14 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -107,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -120,8 +124,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -134,6 +145,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +161,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -188,6 +203,7 @@ CONFIG_PPC_83xx=y
# CONFIG_MPC837x_RDB is not set
CONFIG_SBC834x=y
# CONFIG_ASP834x is not set
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC834x=y
# CONFIG_PPC_86xx is not set
# CONFIG_EMBEDDED6xx is not set
@@ -232,6 +248,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -252,9 +269,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -363,6 +380,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -380,7 +398,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -401,6 +423,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -435,7 +458,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -455,14 +480,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -509,6 +537,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -528,8 +557,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -688,13 +719,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -749,6 +784,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -797,23 +833,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -851,6 +873,10 @@ CONFIG_HID=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -862,10 +888,12 @@ CONFIG_HID=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -928,6 +956,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -971,6 +1000,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -994,22 +1024,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 09146ddaa3ca..ff04e1028f5e 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:16 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:14 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -108,7 +111,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
@@ -121,8 +123,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
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
@@ -136,6 +145,11 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=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 is not set
CONFIG_SLABINFO=y
@@ -143,7 +157,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -176,6 +190,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
CONFIG_KSI8560=y
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -224,6 +239,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -242,9 +258,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -346,6 +362,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -363,7 +380,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -466,6 +487,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -520,7 +542,6 @@ CONFIG_IDE_PROC_FS=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -560,6 +581,7 @@ 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_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
CONFIG_FS_ENET_HAS_FCC=y
@@ -567,6 +589,7 @@ CONFIG_FS_ENET_MDIO_FCC=y
CONFIG_NETDEV_1000=y
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
CONFIG_NETDEV_10000=y
#
@@ -654,6 +677,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -710,22 +738,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -777,6 +790,10 @@ CONFIG_USB_SUPPORT=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -797,10 +814,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -916,6 +935,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -946,6 +966,9 @@ CONFIG_SCHED_DEBUG=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
@@ -958,7 +981,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -972,16 +994,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -990,9 +1011,13 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
index 7b43be7586b6..fb10cc83702e 100644
--- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:17 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:15 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -111,7 +114,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
@@ -124,8 +126,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
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
@@ -138,6 +147,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -145,7 +158,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -178,6 +191,7 @@ CONFIG_MPC8540_ADS=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -226,6 +240,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -244,9 +259,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -348,6 +363,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -365,7 +381,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -387,6 +407,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -423,7 +444,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -462,9 +482,11 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
CONFIG_NETDEV_1000=y
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
CONFIG_NETDEV_10000=y
#
@@ -555,6 +577,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -590,22 +617,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -657,6 +669,10 @@ CONFIG_USB_SUPPORT=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -676,10 +692,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -794,6 +812,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -824,6 +843,9 @@ CONFIG_SCHED_DEBUG=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
@@ -835,7 +857,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -849,16 +870,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -866,6 +886,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
index 62adb71a5d4f..5c8ce6978825 100644
--- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:17 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:16 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -112,7 +115,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
@@ -125,9 +127,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -141,6 +150,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -148,7 +161,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -181,6 +194,7 @@ CONFIG_MPC8560_ADS=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -229,6 +243,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -247,9 +262,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -360,6 +375,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -377,7 +393,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -400,6 +420,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -431,6 +452,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -450,14 +472,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -504,6 +529,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
@@ -527,8 +553,10 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -646,6 +674,11 @@ CONFIG_GEN_RTC=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -707,22 +740,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -779,6 +797,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -798,10 +820,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -916,6 +940,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -946,6 +971,9 @@ CONFIG_SCHED_DEBUG=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
@@ -957,7 +985,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -971,16 +998,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -988,6 +1014,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
index 41209e3a6545..158e63e8607f 100644
--- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
+++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:18 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:17 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -111,7 +114,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
@@ -124,9 +126,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -139,6 +148,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +159,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -179,6 +192,7 @@ CONFIG_MPC85xx_CDS=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -227,6 +241,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -245,9 +260,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -358,6 +373,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -375,7 +391,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -397,6 +417,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -428,6 +449,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -502,14 +524,17 @@ CONFIG_BLK_DEV_IDEDMA=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -556,6 +581,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -575,8 +601,10 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -698,6 +726,11 @@ CONFIG_GEN_RTC=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -737,22 +770,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -809,6 +827,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -828,10 +850,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -946,6 +970,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -976,6 +1001,9 @@ CONFIG_SCHED_DEBUG=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
@@ -987,7 +1015,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1001,16 +1028,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1018,6 +1044,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/sbc8548_defconfig b/arch/powerpc/configs/85xx/sbc8548_defconfig
index 6c36c9c7abfd..2726fca1d694 100644
--- a/arch/powerpc/configs/85xx/sbc8548_defconfig
+++ b/arch/powerpc/configs/85xx/sbc8548_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:19 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:18 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -110,7 +113,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -123,8 +125,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -137,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -144,7 +157,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -177,6 +190,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -224,6 +238,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -242,9 +257,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -354,6 +369,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -371,7 +387,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -391,6 +411,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -422,6 +443,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -441,14 +463,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -495,6 +520,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -514,8 +540,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -637,6 +665,11 @@ CONFIG_GEN_RTC=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -676,22 +709,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -721,6 +739,10 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -732,10 +754,12 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -838,6 +862,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -861,22 +886,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/sbc8560_defconfig b/arch/powerpc/configs/85xx/sbc8560_defconfig
index 4aaf1a6bdc7d..b0c469823b02 100644
--- a/arch/powerpc/configs/85xx/sbc8560_defconfig
+++ b/arch/powerpc/configs/85xx/sbc8560_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:20 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:19 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -111,7 +114,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
@@ -124,7 +126,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -137,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -144,7 +157,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -177,6 +190,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -224,6 +238,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
# CONFIG_MATH_EMULATION is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -242,9 +257,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -346,6 +361,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -363,7 +379,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -385,6 +405,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -421,7 +442,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -460,9 +480,11 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
CONFIG_NETDEV_1000=y
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
CONFIG_NETDEV_10000=y
#
@@ -551,6 +573,11 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -586,22 +613,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -690,6 +702,10 @@ CONFIG_RTC_DRV_M48T59=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -701,10 +717,12 @@ CONFIG_RTC_DRV_M48T59=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -819,6 +837,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -848,6 +867,9 @@ CONFIG_SCHED_DEBUG=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
@@ -859,7 +881,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -873,16 +894,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -890,6 +910,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig
index 79984589db69..04c85dada845 100644
--- a/arch/powerpc/configs/85xx/socrates_defconfig
+++ b/arch/powerpc/configs/85xx/socrates_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:21 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:19 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -109,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -122,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -137,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -149,7 +162,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -182,6 +195,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
CONFIG_SOCRATES=y
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -229,6 +243,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -247,9 +262,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -357,6 +372,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -373,6 +389,7 @@ CONFIG_CAN_BCM=y
# CAN Device Drivers
#
# CONFIG_CAN_VCAN is not set
+# CONFIG_CAN_DEV is not set
# CONFIG_CAN_DEBUG_DEVICES is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
@@ -382,7 +399,11 @@ CONFIG_WIRELESS=y
# CONFIG_WIRELESS_OLD_REGULATORY is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -499,6 +520,7 @@ CONFIG_MTD_NAND_SOCRATES=y
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -535,7 +557,9 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -558,10 +582,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -588,14 +608,17 @@ CONFIG_SCSI_WAIT_SCAN=m
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -643,6 +666,8 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -662,8 +687,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -733,6 +760,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
@@ -746,6 +774,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -862,7 +891,6 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -875,12 +903,18 @@ CONFIG_SPI_MASTER=y
# SPI Master Controller Drivers
#
# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_MPC8xxx is not set
#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -938,6 +972,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -973,24 +1008,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1110,7 +1131,7 @@ CONFIG_USB_HID=y
# CONFIG_HID_CHERRY is not set
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CYPRESS is not set
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
# CONFIG_HID_EZKEY is not set
# CONFIG_HID_KYE is not set
# CONFIG_HID_GYRATION is not set
@@ -1124,10 +1145,11 @@ CONFIG_USB_HID=y
# CONFIG_HID_SAMSUNG is not set
# CONFIG_HID_SONY is not set
# CONFIG_HID_SUNPLUS is not set
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1153,6 +1175,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1162,9 +1185,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1284,6 +1307,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1318,6 +1342,10 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1337,10 +1365,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1449,7 +1479,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
# CONFIG_BINARY_PRINTF is not set
@@ -1473,6 +1542,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1498,22 +1568,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig
index bd1bfcddbd0c..e7e81d6769fe 100644
--- a/arch/powerpc/configs/85xx/stx_gp3_defconfig
+++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:22 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:20 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -112,7 +115,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
@@ -125,9 +127,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -142,6 +151,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -153,7 +166,7 @@ CONFIG_MODULES=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
@@ -186,6 +199,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
CONFIG_STX_GP3=y
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -234,6 +248,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -252,9 +267,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -425,6 +440,7 @@ CONFIG_IP_NF_FILTER=m
# 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
@@ -442,7 +458,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -466,6 +486,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=m
+CONFIG_OF_MDIO=y
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
# CONFIG_PARPORT_PC_FIFO is not set
@@ -507,7 +528,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -581,10 +604,6 @@ CONFIG_BLK_DEV_SR=m
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=m
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
@@ -602,6 +621,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -610,6 +630,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -631,7 +652,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -654,14 +674,17 @@ CONFIG_SCSI_LOWLEVEL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -708,6 +731,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_NET_POCKET is not set
# CONFIG_ATL2 is not set
# CONFIG_FS_ENET is not set
@@ -729,8 +753,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -802,12 +828,13 @@ CONFIG_INPUT_EVDEV=m
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
@@ -821,6 +848,7 @@ CONFIG_MOUSE_PS2_TRACKPOINT=y
# CONFIG_MOUSE_BCM5974 is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
@@ -911,6 +939,7 @@ CONFIG_I2C_ALGOBIT=m
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CPM is not set
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_OCORES is not set
@@ -941,13 +970,17 @@ CONFIG_I2C_ALGOBIT=m
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -1027,6 +1060,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1060,23 +1094,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1143,6 +1163,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1162,10 +1186,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1316,6 +1342,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1346,6 +1373,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1358,7 +1388,6 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1372,16 +1401,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1389,6 +1417,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig
index 767600145fb2..2c407523aad2 100644
--- a/arch/powerpc/configs/85xx/tqm8540_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8540_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:23 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:21 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -109,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -122,9 +124,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -137,6 +146,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -144,7 +157,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -177,6 +190,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
CONFIG_TQM8540=y
# CONFIG_TQM8541 is not set
@@ -225,6 +239,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -243,9 +258,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -353,6 +368,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -370,7 +386,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -471,6 +491,7 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -505,7 +526,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -580,14 +603,17 @@ CONFIG_BLK_DEV_IDEDMA=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -650,6 +676,7 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -671,8 +698,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -850,13 +879,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -911,6 +944,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -945,23 +979,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1018,6 +1038,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1037,10 +1061,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1167,6 +1193,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1192,22 +1219,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig
index 52fafc006dd0..845731dc51c6 100644
--- a/arch/powerpc/configs/85xx/tqm8541_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8541_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:23 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:22 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -110,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -123,9 +125,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -139,6 +148,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +159,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -179,6 +192,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
CONFIG_TQM8541=y
@@ -228,6 +242,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -246,9 +261,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -356,6 +371,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -373,7 +389,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -475,6 +495,7 @@ CONFIG_MTD_CFI_UTIL=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -509,7 +530,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -584,14 +607,17 @@ CONFIG_BLK_DEV_IDEDMA=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -654,6 +680,7 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -676,8 +703,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -831,6 +860,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CPM is not set
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -859,13 +889,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -944,6 +978,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -979,23 +1014,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1052,6 +1073,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1071,10 +1096,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1201,6 +1228,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1226,22 +1254,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig
index 8b4faae7a9a1..4f228a905274 100644
--- a/arch/powerpc/configs/85xx/tqm8548_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8548_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:24 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:23 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -56,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -111,7 +114,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
@@ -124,9 +126,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -140,6 +149,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -152,7 +165,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -185,6 +198,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -234,6 +248,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -252,9 +267,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -281,6 +296,8 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
@@ -368,6 +385,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -497,6 +515,7 @@ CONFIG_MTD_NAND_FSL_UPM=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -531,7 +550,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -551,14 +572,17 @@ CONFIG_HAVE_IDE=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -605,6 +629,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -624,8 +649,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -801,13 +828,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -862,6 +893,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -896,23 +928,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -977,6 +995,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1004,6 +1023,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1015,10 +1038,12 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1145,6 +1170,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1175,6 +1201,9 @@ CONFIG_SCHED_DEBUG=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
@@ -1187,7 +1216,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1201,16 +1229,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1218,6 +1245,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/85xx/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig
index 170360934cec..9196724bebc7 100644
--- a/arch/powerpc/configs/85xx/tqm8555_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8555_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:25 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:24 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -110,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -123,9 +125,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -139,6 +148,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +159,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -179,6 +192,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -228,6 +242,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -246,9 +261,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -356,6 +371,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -373,7 +389,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -475,6 +495,7 @@ CONFIG_MTD_CFI_UTIL=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -509,7 +530,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -584,14 +607,17 @@ CONFIG_BLK_DEV_IDEDMA=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -654,6 +680,7 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -676,8 +703,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -831,6 +860,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CPM is not set
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -859,13 +889,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -944,6 +978,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -979,23 +1014,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1052,6 +1073,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1071,10 +1096,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1201,6 +1228,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1226,22 +1254,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig
index f41cc2444d48..2e49a6e9faf2 100644
--- a/arch/powerpc/configs/85xx/tqm8560_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8560_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:26 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:25 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -110,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -123,9 +125,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -139,6 +148,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +159,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -179,6 +192,7 @@ CONFIG_MPC85xx=y
# CONFIG_MPC85xx_DS is not set
# CONFIG_SOCRATES is not set
# CONFIG_KSI8560 is not set
+# CONFIG_XES_MPC85xx is not set
# CONFIG_STX_GP3 is not set
# CONFIG_TQM8540 is not set
# CONFIG_TQM8541 is not set
@@ -228,6 +242,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -246,9 +261,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -356,6 +371,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -373,7 +389,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -475,6 +495,7 @@ CONFIG_MTD_CFI_UTIL=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -509,7 +530,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -584,14 +607,17 @@ CONFIG_BLK_DEV_IDEDMA=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -654,6 +680,7 @@ CONFIG_E100=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -676,8 +703,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -831,6 +860,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CPM is not set
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -859,13 +889,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -944,6 +978,7 @@ CONFIG_SENSORS_LM75=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -979,23 +1014,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1052,6 +1073,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1071,10 +1096,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1201,6 +1228,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1226,22 +1254,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index 2552cbefba6b..1025da2bf069 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc6
-# Thu Jun 11 11:25:17 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:25 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -35,15 +35,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -64,6 +65,7 @@ CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -114,7 +116,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -127,9 +128,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -144,6 +152,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -157,7 +169,7 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -239,6 +251,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -258,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -287,6 +300,8 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
@@ -404,6 +419,7 @@ CONFIG_IPV6_NDISC_NODETYPE=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
@@ -540,6 +556,7 @@ CONFIG_MTD_NAND_FSL_UPM=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -575,7 +592,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -599,10 +618,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
CONFIG_SCSI_LOGGING=y
@@ -619,6 +634,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -627,6 +643,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -646,7 +663,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -730,14 +746,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -784,6 +803,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -803,8 +823,10 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -986,13 +1008,17 @@ CONFIG_I2C_MPC=y
# CONFIG_DS1682 is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -1072,6 +1098,7 @@ CONFIG_SENSORS_LM90=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1126,23 +1153,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1187,7 +1200,7 @@ CONFIG_USB_HID=y
# CONFIG_HID_CHERRY is not set
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CYPRESS is not set
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
# CONFIG_HID_EZKEY is not set
# CONFIG_HID_KYE is not set
# CONFIG_HID_GYRATION is not set
@@ -1201,10 +1214,11 @@ CONFIG_USB_HID=y
# CONFIG_HID_SAMSUNG is not set
# CONFIG_HID_SONY is not set
# CONFIG_HID_SUNPLUS is not set
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1230,6 +1244,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
@@ -1325,7 +1340,7 @@ CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_GPIO_PLATFORM=y
CONFIG_LEDS_GPIO_OF=y
-# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP3944 is not set
CONFIG_LEDS_PCA955X=y
# CONFIG_LEDS_BD2802 is not set
@@ -1352,8 +1367,6 @@ CONFIG_EDAC=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_MPC85XX=y
-# CONFIG_EDAC_AMD8131 is not set
-# CONFIG_EDAC_AMD8111 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1385,6 +1398,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1425,6 +1439,10 @@ CONFIG_NET_DMA=y
# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1444,11 +1462,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1629,6 +1648,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1659,6 +1679,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1671,7 +1694,6 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1685,16 +1707,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1702,6 +1723,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index b6a23af57f46..527ad1a5e802 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:31 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:31 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,16 +34,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_LOCKBREAK=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -56,11 +59,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -112,9 +117,7 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=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
@@ -127,8 +130,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -143,6 +153,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -156,7 +170,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
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
@@ -216,7 +230,7 @@ CONFIG_MPIC=y
#
# Kernel options
#
-# CONFIG_HIGHMEM is not set
+CONFIG_HIGHMEM=y
CONFIG_TICK_ONESHOT=y
# CONFIG_NO_HZ is not set
CONFIG_HIGH_RES_TIMERS=y
@@ -235,6 +249,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -256,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -285,14 +300,32 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
# CONFIG_PCI_LEGACY is not set
-CONFIG_PCI_DEBUG=y
# CONFIG_PCI_STUB is not set
# CONFIG_PCI_IOV is not set
-# CONFIG_PCCARD is not set
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_IOCTL is not set
+# CONFIG_CARDBUS is not set
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+CONFIG_YENTA_TI=y
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=y
# CONFIG_HOTPLUG_PCI is not set
# CONFIG_HAS_RAPIDIO is not set
@@ -353,8 +386,8 @@ CONFIG_INET_XFRM_TUNNEL=m
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_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -380,174 +413,26 @@ CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=m
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_IPV6_MROUTE is not set
-# CONFIG_NETLABEL is not set
# CONFIG_NETWORK_SECMARK is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_NETFILTER_ADVANCED=y
-CONFIG_BRIDGE_NETFILTER=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_TPROXY is not set
-CONFIG_NETFILTER_XTABLES=m
-# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
-# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
-# CONFIG_NETFILTER_XT_TARGET_HL is not set
-# CONFIG_NETFILTER_XT_TARGET_MARK is not set
-# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
-# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
-# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
-# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
-# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
-# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
-# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
-# CONFIG_NETFILTER_XT_MATCH_ESP is not set
-# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
-CONFIG_NETFILTER_XT_MATCH_HL=m
-# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
-# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
-# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
-# CONFIG_NETFILTER_XT_MATCH_MAC is not set
-# CONFIG_NETFILTER_XT_MATCH_MARK is not set
-# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
-# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
-# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
-# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
-# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
-# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
-# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
-# CONFIG_NETFILTER_XT_MATCH_REALM is not set
-# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
-# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
-# CONFIG_NETFILTER_XT_MATCH_STRING is not set
-# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
-# CONFIG_NETFILTER_XT_MATCH_TIME is not set
-# CONFIG_NETFILTER_XT_MATCH_U32 is not set
-# CONFIG_IP_VS is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_NF_DEFRAG_IPV4 is not set
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-# CONFIG_IP_NF_MATCH_AH is not set
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_ECN=m
-# CONFIG_IP_NF_TARGET_TTL is not set
-CONFIG_IP_NF_RAW=m
-# CONFIG_IP_NF_SECURITY is not set
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-
-#
-# IPv6: Netfilter Configuration
-#
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_IP6_NF_IPTABLES=m
-# CONFIG_IP6_NF_MATCH_AH is not set
-CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_FRAG=m
-CONFIG_IP6_NF_MATCH_OPTS=m
-CONFIG_IP6_NF_MATCH_HL=m
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-# CONFIG_IP6_NF_MATCH_MH is not set
-CONFIG_IP6_NF_MATCH_RT=m
-# CONFIG_IP6_NF_TARGET_HL is not set
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_FILTER=m
-# CONFIG_IP6_NF_TARGET_REJECT is not set
-CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_RAW=m
-# CONFIG_IP6_NF_SECURITY is not set
-# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
-CONFIG_IP_SCTP=m
-# CONFIG_SCTP_DBG_MSG is not set
-# CONFIG_SCTP_DBG_OBJCNT is not set
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-CONFIG_SCTP_HMAC_MD5=y
-CONFIG_TIPC=m
-# CONFIG_TIPC_ADVANCED is not set
-# CONFIG_TIPC_DEBUG is not set
-CONFIG_ATM=m
-CONFIG_ATM_CLIP=m
-# CONFIG_ATM_CLIP_NO_ICMP is not set
-CONFIG_ATM_LANE=m
-CONFIG_ATM_MPOA=m
-CONFIG_ATM_BR2684=m
-# CONFIG_ATM_BR2684_IPFILTER is not set
-CONFIG_STP=m
-CONFIG_BRIDGE=m
+# 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=m
-# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
-CONFIG_LLC=m
# 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=m
+# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
-CONFIG_NET_SCHED=y
-
-#
-# Queueing/Scheduling
-#
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_HTB=m
-CONFIG_NET_SCH_HFSC=m
-CONFIG_NET_SCH_ATM=m
-CONFIG_NET_SCH_PRIO=m
-# CONFIG_NET_SCH_MULTIQ is not set
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_NETEM=m
-# CONFIG_NET_SCH_DRR is not set
-
-#
-# Classification
-#
-CONFIG_NET_CLS=y
-# CONFIG_NET_CLS_BASIC is not set
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_ROUTE=y
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-# CONFIG_CLS_U32_PERF is not set
-# CONFIG_CLS_U32_MARK is not set
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-# CONFIG_NET_CLS_FLOW is not set
-# CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
-# CONFIG_NET_CLS_IND is not set
-CONFIG_NET_SCH_FIFO=y
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
#
@@ -560,12 +445,7 @@ CONFIG_NET_PKTGEN=m
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
CONFIG_FIB_RULES=y
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+# CONFIG_WIRELESS is not set
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -580,9 +460,9 @@ CONFIG_WIRELESS_OLD_REGULATORY=y
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_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
@@ -672,6 +552,7 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -707,9 +588,60 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
#
# SCSI device support
@@ -731,10 +663,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR 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
@@ -751,6 +679,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -759,6 +688,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -778,7 +708,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -791,6 +720,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
# CONFIG_SCSI_DH is not set
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
@@ -842,6 +772,7 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_NS87415 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RZ1000 is not set
@@ -862,14 +793,17 @@ CONFIG_SATA_SIL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
# CONFIG_MACVLAN is not set
@@ -916,6 +850,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -935,8 +870,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -963,22 +900,8 @@ CONFIG_GIANFAR=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+# CONFIG_NET_PCMCIA is not set
# CONFIG_WAN is not set
-CONFIG_ATM_DRIVERS=y
-# CONFIG_ATM_DUMMY is not set
-# CONFIG_ATM_TCP is not set
-# CONFIG_ATM_LANAI is not set
-# CONFIG_ATM_ENI is not set
-# CONFIG_ATM_FIRESTREAM is not set
-# CONFIG_ATM_ZATM is not set
-# CONFIG_ATM_NICSTAR is not set
-# CONFIG_ATM_IDT77252 is not set
-# CONFIG_ATM_AMBASSADOR is not set
-# CONFIG_ATM_HORIZON is not set
-# CONFIG_ATM_IA is not set
-# CONFIG_ATM_FORE200E is not set
-# CONFIG_ATM_HE is not set
-# CONFIG_ATM_SOLOS is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP=m
@@ -990,7 +913,6 @@ CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
# CONFIG_PPP_MPPE is not set
CONFIG_PPPOE=m
-CONFIG_PPPOATM=m
# CONFIG_PPPOL2TP is not set
CONFIG_SLIP=m
CONFIG_SLIP_COMPRESSED=y
@@ -1010,7 +932,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
-CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
#
@@ -1058,6 +980,7 @@ CONFIG_DEVKMEM=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_CS is not set
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
# CONFIG_SERIAL_8250_EXTENDED is not set
@@ -1080,6 +1003,14 @@ CONFIG_HW_RANDOM=y
CONFIG_NVRAM=y
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
@@ -1143,18 +1074,21 @@ CONFIG_DS1682=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
-# CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
+CONFIG_GPIO_SYSFS=y
#
# Memory mapped GPIO expanders:
@@ -1229,6 +1163,7 @@ CONFIG_SENSORS_LM92=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1284,24 +1219,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1346,7 +1266,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1363,10 +1283,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1392,6 +1313,7 @@ CONFIG_USB=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1401,6 +1323,8 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1475,7 +1399,6 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_VST is not set
-# CONFIG_USB_ATM is not set
# CONFIG_USB_GADGET is not set
#
@@ -1521,6 +1444,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
CONFIG_RTC_DRV_RX8581=y
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1548,6 +1472,10 @@ CONFIG_RTC_DRV_RX8581=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1569,10 +1497,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1589,8 +1519,11 @@ CONFIG_INOTIFY_USER=y
#
# CD-ROM/DVD Filesystems
#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
@@ -1598,8 +1531,8 @@ CONFIG_INOTIFY_USER=y
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
# CONFIG_NTFS_FS is not set
#
@@ -1649,6 +1582,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1723,13 +1657,13 @@ CONFIG_NLS_UTF8=m
#
CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_CRC_CCITT=m
+CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
-# CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
-CONFIG_LIBCRC32C=m
+CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_DECOMPRESS_GZIP=y
@@ -1738,6 +1672,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1750,75 +1685,24 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# 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 is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_KERNEL is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_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=y
-# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
-# CONFIG_DEBUG_STACKOVERFLOW is not set
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_CODE_PATCHING_SELFTEST is not set
-# CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
-# CONFIG_XMON is not set
# CONFIG_IRQSTACKS is not set
-# CONFIG_BDI_SWITCH is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1826,15 +1710,9 @@ CONFIG_PRINT_STACK_DEPTH=64
# Security options
#
# CONFIG_KEYS is not set
-CONFIG_SECURITY=y
+# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-CONFIG_SECURITY_NETWORK=y
-# CONFIG_SECURITY_NETWORK_XFRM is not set
-# CONFIG_SECURITY_PATH is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-# CONFIG_SECURITY_ROOTPLUG is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
-# CONFIG_SECURITY_TOMOYO is not set
CONFIG_CRYPTO=y
#
@@ -1854,11 +1732,11 @@ CONFIG_CRYPTO_PCOMP=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_NULL is not set
CONFIG_CRYPTO_WORKQUEUE=y
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_AUTHENC=m
-CONFIG_CRYPTO_TEST=m
+# CONFIG_CRYPTO_TEST is not set
#
# Authenticated Encryption with Associated Data
@@ -1873,53 +1751,52 @@ CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_CTS is not set
-CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_ECB is not set
# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_XTS is not set
#
# Hash modes
#
-CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HMAC=m
# CONFIG_CRYPTO_XCBC is not set
#
# Digest
#
-CONFIG_CRYPTO_CRC32C=m
-CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
+# 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=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_WP512=m
+# CONFIG_CRYPTO_WP512 is not set
#
# Ciphers
#
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_BLOWFISH=m
+# 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=m
-CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
-CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_SALSA20 is not set
# CONFIG_CRYPTO_SEED is not set
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
#
# Compression
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index a66910e63345..cd338d493bed 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:29 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:29 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,16 +34,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_LOCKBREAK=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -56,11 +59,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -91,7 +96,11 @@ CONFIG_CLASSIC_RCU=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_GROUP_SCHED is not set
+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
@@ -109,7 +118,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -122,8 +130,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -138,6 +153,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -151,7 +170,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
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
@@ -168,7 +187,6 @@ CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="cfq"
# CONFIG_FREEZER is not set
-CONFIG_PPC_MSI_BITMAP=y
#
# Platform support
@@ -212,7 +230,7 @@ CONFIG_MPIC=y
#
# Kernel options
#
-# CONFIG_HIGHMEM is not set
+CONFIG_HIGHMEM=y
CONFIG_TICK_ONESHOT=y
# CONFIG_NO_HZ is not set
CONFIG_HIGH_RES_TIMERS=y
@@ -231,6 +249,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -252,9 +271,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -281,13 +300,32 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
-CONFIG_PCI_MSI=y
+# CONFIG_PCI_MSI is not set
# CONFIG_PCI_LEGACY is not set
# CONFIG_PCI_STUB is not set
# CONFIG_PCI_IOV is not set
-# CONFIG_PCCARD is not set
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_IOCTL is not set
+# CONFIG_CARDBUS is not set
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+CONFIG_YENTA_TI=y
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=y
# CONFIG_HOTPLUG_PCI is not set
# CONFIG_HAS_RAPIDIO is not set
@@ -393,6 +431,7 @@ CONFIG_IPV6_TUNNEL=m
# 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
@@ -421,7 +460,9 @@ CONFIG_FIB_RULES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
@@ -511,6 +552,7 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -546,9 +588,60 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
#
# SCSI device support
@@ -570,10 +663,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR 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
@@ -590,6 +679,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -598,6 +688,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -617,7 +708,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -630,6 +720,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
# CONFIG_SCSI_DH is not set
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
@@ -647,14 +738,17 @@ CONFIG_SATA_SIL24=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
# CONFIG_MACVLAN is not set
@@ -701,6 +795,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -720,8 +815,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -748,6 +845,7 @@ CONFIG_GIANFAR=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+# CONFIG_NET_PCMCIA is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -827,6 +925,7 @@ CONFIG_DEVKMEM=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_CS is not set
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
# CONFIG_SERIAL_8250_EXTENDED is not set
@@ -849,6 +948,14 @@ CONFIG_HW_RANDOM=y
CONFIG_NVRAM=y
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
@@ -912,13 +1019,17 @@ CONFIG_DS1682=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -997,6 +1108,7 @@ CONFIG_SENSORS_LM92=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1052,24 +1164,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1114,7 +1211,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1131,10 +1228,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1160,6 +1258,7 @@ CONFIG_USB=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1169,6 +1268,8 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1288,6 +1389,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
CONFIG_RTC_DRV_RX8581=y
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1315,6 +1417,10 @@ CONFIG_RTC_DRV_RX8581=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1336,10 +1442,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1419,6 +1527,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1508,6 +1617,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1531,23 +1641,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index c6a7fc82b69a..ba47883f4aa0 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:30 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:30 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,16 +34,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_LOCKBREAK=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -56,11 +59,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -114,7 +119,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
@@ -127,8 +131,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -143,6 +154,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -156,7 +171,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
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
@@ -235,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -256,9 +272,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -285,6 +301,8 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
@@ -510,6 +528,7 @@ CONFIG_LLC=m
# CONFIG_ECONET is not set
CONFIG_WAN_ROUTER=m
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y
#
@@ -566,7 +585,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -678,6 +701,7 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -713,7 +737,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -737,10 +763,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR 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
@@ -757,6 +779,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -765,6 +788,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -784,7 +808,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -868,14 +891,17 @@ CONFIG_SATA_SIL=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
# CONFIG_MACVLAN is not set
@@ -922,6 +948,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -941,8 +968,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -1149,13 +1178,17 @@ CONFIG_DS1682=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -1235,6 +1268,7 @@ CONFIG_SENSORS_LM92=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1290,24 +1324,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1352,7 +1371,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1369,10 +1388,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1398,6 +1418,7 @@ CONFIG_USB=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1407,6 +1428,8 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1527,6 +1550,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
CONFIG_RTC_DRV_RX8581=y
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1554,6 +1578,10 @@ CONFIG_RTC_DRV_RX8581=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1575,10 +1603,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1645,6 +1675,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1734,6 +1765,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1759,10 +1791,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1774,7 +1810,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1788,17 +1823,16 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_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
@@ -1806,6 +1840,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1829,7 +1866,6 @@ CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_PATH is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
# CONFIG_SECURITY_ROOTPLUG is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
# CONFIG_SECURITY_TOMOYO is not set
CONFIG_CRYPTO=y
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index cfd2efcc6bce..a61f183f7186 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:28 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:27 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -53,11 +56,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -109,7 +114,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -122,9 +126,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -138,6 +149,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -150,7 +165,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -230,6 +245,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -250,9 +266,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -279,6 +295,8 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
@@ -381,6 +399,7 @@ CONFIG_IPV6_NDISC_NODETYPE=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
@@ -398,7 +417,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -549,7 +572,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -620,10 +645,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -640,6 +661,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -648,6 +670,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -667,7 +690,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -751,14 +773,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -792,6 +817,7 @@ CONFIG_ULI526X=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -959,13 +985,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -993,23 +1023,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1106,6 +1122,11 @@ CONFIG_SND_PCM_OSS_PLUGINS=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
@@ -1130,6 +1151,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
@@ -1160,6 +1182,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_INTEL8X0 is not set
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -1251,6 +1274,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1278,6 +1302,10 @@ CONFIG_RTC_DRV_CMOS=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1297,12 +1325,15 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -1464,6 +1495,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1494,6 +1526,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1506,7 +1541,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1520,16 +1554,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1537,6 +1570,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
index 0bee3e303942..7016ce732605 100644
--- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:28 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:28 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -54,11 +57,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -113,7 +118,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -126,9 +130,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -143,6 +154,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -156,7 +171,7 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -234,7 +249,9 @@ CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
-# CONFIG_IOMMU_HELPER is not set
+CONFIG_IOMMU_HELPER=y
+CONFIG_SWIOTLB=y
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -256,9 +273,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -401,6 +418,7 @@ CONFIG_SCTP_HMAC_MD5=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
@@ -419,7 +437,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -444,6 +466,7 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -479,7 +502,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -503,10 +528,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
CONFIG_SCSI_LOGGING=y
@@ -524,6 +545,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -532,6 +554,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -551,7 +574,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -635,14 +657,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -689,6 +714,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -708,8 +734,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -909,13 +937,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -943,76 +975,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MC44S803=m
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-CONFIG_DVB_CAPTURE_DRIVERS=y
-
-#
-# Supported SAA7146 based PCI Adapters
-#
-# CONFIG_TTPCI_EEPROM is not set
-# CONFIG_DVB_BUDGET_CORE is not set
-
-#
-# Supported USB Adapters
-#
-# CONFIG_DVB_USB is not set
-# CONFIG_DVB_TTUSB_BUDGET is not set
-# CONFIG_DVB_TTUSB_DEC is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported BT878 Adapters
-#
-
-#
-# Supported Pluto2 Adapters
-#
-# CONFIG_DVB_PLUTO2 is not set
-
-#
-# Supported SDMC DM1105 Adapters
-#
-# CONFIG_DVB_DM1105 is not set
-
-#
-# Supported DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1052,6 +1017,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
+# 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_AC97_CODEC=y
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
@@ -1078,6 +1048,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
@@ -1108,6 +1079,7 @@ CONFIG_SND_PCI=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -1152,7 +1124,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1169,10 +1141,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1198,6 +1171,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1207,9 +1181,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1329,6 +1303,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1356,6 +1331,10 @@ CONFIG_RTC_DRV_CMOS=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1375,11 +1354,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1454,6 +1434,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -1555,6 +1536,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1585,6 +1567,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1597,7 +1582,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1611,16 +1595,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1628,6 +1611,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index c30a0c715873..f5ca2e0cd402 100644
--- a/arch/powerpc/configs/86xx/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:27 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:26 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,16 +34,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_LOCKBREAK=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -55,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -113,7 +118,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
@@ -126,8 +130,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -142,6 +153,11 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -155,7 +171,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
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
@@ -234,6 +250,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -255,9 +272,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -284,6 +301,8 @@ CONFIG_PCI_DOMAINS=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIEASPM is not set
CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
@@ -508,6 +527,7 @@ CONFIG_LLC=m
# CONFIG_ECONET is not set
CONFIG_WAN_ROUTER=m
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y
#
@@ -564,7 +584,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -675,6 +699,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -709,7 +734,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -736,6 +763,7 @@ CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_DM_SNAPSHOT=y
CONFIG_DM_MIRROR=y
+# CONFIG_DM_LOG_USERSPACE is not set
CONFIG_DM_ZERO=y
# CONFIG_DM_MULTIPATH is not set
# CONFIG_DM_DELAY is not set
@@ -747,14 +775,17 @@ CONFIG_DM_ZERO=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
# CONFIG_MACVLAN is not set
@@ -801,6 +832,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -820,8 +852,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -1018,13 +1052,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1079,6 +1117,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1127,23 +1166,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1207,6 +1232,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1236,8 +1265,8 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
# CONFIG_REISERFS_FS_SECURITY is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
CONFIG_OCFS2_FS=m
CONFIG_OCFS2_FS_O2CB=m
CONFIG_OCFS2_FS_STATS=y
@@ -1245,6 +1274,8 @@ CONFIG_OCFS2_DEBUG_MASKLOG=y
# CONFIG_OCFS2_DEBUG_FS is not set
# CONFIG_OCFS2_FS_POSIX_ACL is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1318,6 +1349,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1409,6 +1441,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1434,10 +1467,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1449,7 +1486,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1463,17 +1499,16 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_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
@@ -1482,9 +1517,13 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
@@ -1505,7 +1544,6 @@ CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
# CONFIG_SECURITY_PATH is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
# CONFIG_SECURITY_TOMOYO is not set
CONFIG_CRYPTO=y
diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig
index 74f7f7c6fdc4..aece6bb5f733 100644
--- a/arch/powerpc/configs/adder875_defconfig
+++ b/arch/powerpc/configs/adder875_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:50 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:47 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
CONFIG_PPC_8xx=y
# CONFIG_40x is not set
@@ -27,15 +27,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -49,12 +50,14 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
CONFIG_REDBOOT=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -101,7 +104,6 @@ CONFIG_EMBEDDED=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
@@ -114,8 +116,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -129,13 +138,18 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=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 is not set
CONFIG_SLABINFO=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -220,6 +234,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_MATH_EMULATION is not set
# CONFIG_8XX_MINIMAL_FPEMU is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -239,9 +254,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -280,6 +295,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -336,6 +352,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -353,7 +370,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -452,6 +473,7 @@ CONFIG_MTD_PHYSMAP_OF=y
#
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
# CONFIG_MISC_DEVICES is not set
@@ -469,7 +491,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -508,6 +529,7 @@ 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_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
CONFIG_FS_ENET_HAS_FEC=y
@@ -556,11 +578,11 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
@@ -622,6 +644,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -644,22 +671,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -685,6 +697,10 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -696,12 +712,15 @@ CONFIG_VIDEO_OUTPUT_CONTROL=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -818,6 +837,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -846,6 +866,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_SLUB_STATS is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -857,7 +880,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -870,16 +892,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -888,9 +909,13 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index 9ffa8de92803..8105360d53f4 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:51 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:48 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_NOT_COHERENT_CACHE=y
CONFIG_CHECK_CACHE_COHERENCY=y
@@ -32,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -54,11 +57,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -118,7 +123,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -131,16 +135,23 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=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=y
CONFIG_TRACEPOINTS=y
-# CONFIG_MARKERS is not set
+CONFIG_MARKERS=y
CONFIG_OPROFILE=m
CONFIG_HAVE_OPROFILE=y
CONFIG_KPROBES=y
@@ -150,6 +161,11 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -162,7 +178,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -258,6 +274,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -279,9 +296,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -331,6 +348,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -583,6 +601,7 @@ CONFIG_LLC=m
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y
#
@@ -663,7 +682,11 @@ CONFIG_WIRELESS_OLD_REGULATORY=y
CONFIG_WIRELESS_EXT=y
CONFIG_WIRELESS_EXT_SYSFS=y
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -772,6 +795,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=m
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -816,10 +840,6 @@ CONFIG_BLK_DEV_SR=m
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
# 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=y
CONFIG_SCSI_LOGGING=y
@@ -836,6 +856,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SRP_ATTRS=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
CONFIG_BLK_DEV_3W_XXXX_RAID=m
CONFIG_SCSI_3W_9XXX=m
CONFIG_SCSI_ACARD=m
@@ -854,6 +875,7 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000
CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
CONFIG_SCSI_ARCMSR=m
@@ -875,7 +897,6 @@ CONFIG_SCSI_GDTH=m
CONFIG_SCSI_IPS=m
CONFIG_SCSI_INITIO=m
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
CONFIG_SCSI_SYM53C8XX_2=m
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
@@ -903,14 +924,17 @@ CONFIG_SCSI_LPFC=m
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
# CONFIG_MACVLAN is not set
@@ -957,6 +981,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -976,6 +1001,7 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_MV643XX_ETH=y
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
@@ -1177,13 +1203,17 @@ CONFIG_I2C_MV64XXX=m
CONFIG_SENSORS_PCF8574=m
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1238,6 +1268,7 @@ CONFIG_SENSORS_SMSC47M1=m
CONFIG_SENSORS_SMSC47B397=m
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
CONFIG_SENSORS_VIA686A=m
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1266,7 +1297,6 @@ CONFIG_SOFT_WATCHDOG=m
#
CONFIG_PCIPCWATCHDOG=m
CONFIG_WDTPCI=m
-CONFIG_WDT_501_PCI=y
#
# USB-based Watchdog Cards
@@ -1289,23 +1319,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1354,6 +1370,7 @@ CONFIG_USB_MON=m
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1362,9 +1379,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=m
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1545,6 +1562,10 @@ CONFIG_DMADEVICES=y
#
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1563,11 +1584,12 @@ CONFIG_FS_MBCACHE=m
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1652,6 +1674,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1764,6 +1787,7 @@ CONFIG_HAS_DMA=y
CONFIG_CHECK_SIGNATURE=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1794,6 +1818,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
CONFIG_DEBUG_SPINLOCK=y
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
CONFIG_STACKTRACE=y
@@ -1807,7 +1834,6 @@ CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_KPROBES_SANITY_TEST is not set
@@ -1824,30 +1850,34 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK 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_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
@@ -1869,7 +1899,6 @@ CONFIG_SECURITY_NETWORK=y
# CONFIG_SECURITY_NETWORK_XFRM is not set
# CONFIG_SECURITY_PATH is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig
index 04915c3a43f6..0aa5b43ffeb2 100644
--- a/arch/powerpc/configs/ep8248e_defconfig
+++ b/arch/powerpc/configs/ep8248e_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:52 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:49 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -53,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -99,7 +104,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -112,8 +116,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -127,6 +138,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -134,7 +149,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_INTEGRITY is not set
#
@@ -213,6 +228,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -228,9 +244,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -300,6 +316,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
@@ -380,7 +397,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
@@ -485,6 +506,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -520,13 +542,17 @@ CONFIG_HAVE_IDE=y
#
#
-# A new alternative FireWire stack is available with EXPERIMENTAL=y
+# You can enable one or both FireWire driver stacks.
#
+
+#
+# See the help texts for more information.
+#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -573,6 +599,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
@@ -594,8 +621,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_JME is not set
@@ -685,6 +714,10 @@ CONFIG_HW_RANDOM=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -728,22 +761,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -771,6 +789,10 @@ CONFIG_DAB=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -787,9 +809,10 @@ CONFIG_JBD=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -935,6 +958,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -960,6 +984,9 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -971,7 +998,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -985,22 +1011,23 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig
index c2a439595f4d..2c292e25cc01 100644
--- a/arch/powerpc/configs/ep88xc_defconfig
+++ b/arch/powerpc/configs/ep88xc_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:53 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:49 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
CONFIG_PPC_8xx=y
# CONFIG_40x is not set
@@ -27,15 +27,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -49,11 +50,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -100,7 +103,6 @@ CONFIG_EMBEDDED=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
@@ -113,8 +115,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -128,13 +137,17 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -220,6 +233,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_MATH_EMULATION is not set
CONFIG_8XX_MINIMAL_FPEMU=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -239,9 +253,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -280,6 +294,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -336,6 +351,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -353,7 +369,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -452,6 +472,7 @@ CONFIG_MTD_PHYSMAP_OF=y
#
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
# CONFIG_MISC_DEVICES is not set
@@ -469,7 +490,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -508,6 +528,7 @@ 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_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
CONFIG_FS_ENET_HAS_FEC=y
@@ -579,6 +600,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -602,22 +628,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -642,6 +653,10 @@ CONFIG_DAB=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -653,12 +668,15 @@ CONFIG_DAB=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -775,6 +793,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -803,6 +822,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_SLUB_STATS is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -814,7 +836,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -827,16 +848,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -844,6 +864,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig
index a4053ab9e244..45671e7dd2c7 100644
--- a/arch/powerpc/configs/linkstation_defconfig
+++ b/arch/powerpc/configs/linkstation_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:54 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:50 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +55,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -114,7 +119,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
@@ -127,9 +131,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_COMPAT_BRK is not set
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -143,6 +154,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -155,7 +170,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -237,6 +252,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -257,9 +273,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -480,6 +496,7 @@ CONFIG_IP_NF_ARP_MANGLE=m
# 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
@@ -498,7 +515,11 @@ CONFIG_WIRELESS_OLD_REGULATORY=y
CONFIG_WIRELESS_EXT=y
CONFIG_WIRELESS_EXT_SYSFS=y
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -647,7 +668,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=m
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -670,10 +693,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -691,6 +710,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -699,6 +719,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -718,7 +739,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -802,14 +822,17 @@ CONFIG_PATA_SIL680=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -846,6 +869,7 @@ CONFIG_TULIP_MMIO=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -865,8 +889,10 @@ CONFIG_R8169=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -1074,13 +1100,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1135,6 +1165,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1169,23 +1200,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1245,6 +1262,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1254,9 +1272,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1423,6 +1441,7 @@ CONFIG_RTC_DRV_RS5C372=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1450,6 +1469,10 @@ CONFIG_RTC_DRV_RS5C372=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1469,14 +1492,16 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-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_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1548,6 +1573,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=m
CONFIG_NFSD_V3=y
@@ -1578,7 +1604,7 @@ CONFIG_CIFS=m
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=m
+CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
# CONFIG_NLS_CODEPAGE_737 is not set
@@ -1645,6 +1671,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1675,6 +1702,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1686,7 +1716,6 @@ CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1700,16 +1729,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1717,6 +1745,8 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
index 31e1df665157..e9491c1c3f31 100644
--- a/arch/powerpc/configs/mgcoge_defconfig
+++ b/arch/powerpc/configs/mgcoge_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:55 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:51 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -53,6 +56,7 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
CONFIG_HIBERNATE_32=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
@@ -60,6 +64,7 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -105,7 +110,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -119,8 +123,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -134,6 +145,11 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=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 is not set
CONFIG_SLABINFO=y
@@ -141,7 +157,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_INTEGRITY is not set
#
@@ -225,6 +241,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -240,9 +257,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -313,6 +330,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
@@ -374,7 +392,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
@@ -484,6 +506,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -523,13 +546,17 @@ CONFIG_HAVE_IDE=y
#
#
-# A new alternative FireWire stack is available with EXPERIMENTAL=y
+# You can enable one or both FireWire driver stacks.
#
+
+#
+# See the help texts for more information.
+#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -577,6 +604,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
CONFIG_FS_ENET_HAS_SCC=y
@@ -654,6 +682,10 @@ CONFIG_HW_RANDOM=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -697,22 +729,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -740,6 +757,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -757,9 +778,10 @@ CONFIG_JBD=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -916,6 +938,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -941,6 +964,9 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -952,7 +978,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -966,16 +991,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -983,9 +1007,12 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig
index 24fa90792c54..1ae85a3b2942 100644
--- a/arch/powerpc/configs/mgsuvd_defconfig
+++ b/arch/powerpc/configs/mgsuvd_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:55 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:52 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
CONFIG_PPC_8xx=y
# CONFIG_40x is not set
@@ -27,15 +27,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -48,11 +49,13 @@ CONFIG_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -102,7 +105,6 @@ CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
# CONFIG_BUG is not set
@@ -115,7 +117,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -129,6 +138,11 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=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 is not set
CONFIG_SLABINFO=y
@@ -136,7 +150,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -222,6 +236,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -241,9 +256,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -281,6 +296,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -342,6 +358,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -359,7 +376,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -463,6 +484,7 @@ CONFIG_MTD_PHYSMAP_OF=y
#
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -492,7 +514,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -531,6 +552,7 @@ 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_FS_ENET=y
CONFIG_FS_ENET_HAS_SCC=y
# CONFIG_FS_ENET_HAS_FEC is not set
@@ -602,6 +624,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -625,22 +652,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -665,6 +677,10 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -687,10 +703,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -823,6 +841,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -844,24 +863,14 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_IRQSTACKS is not set
# CONFIG_VIRQ_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
index 642ab67c8431..f23428c3b34e 100644
--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
+++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:56 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:53 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +55,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -106,7 +111,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -119,9 +123,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -134,6 +145,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -141,7 +156,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -220,6 +235,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -240,9 +256,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -348,6 +364,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -365,7 +382,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -385,6 +406,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -416,6 +438,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -438,10 +461,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -458,6 +477,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -466,6 +486,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -485,7 +506,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -568,14 +588,17 @@ CONFIG_SATA_MV=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -642,6 +665,7 @@ CONFIG_8139TOO=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -663,7 +687,9 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_TSI108_ETH=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -785,6 +811,11 @@ CONFIG_GEN_RTC=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -824,22 +855,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -896,6 +912,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -915,11 +935,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1038,6 +1059,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1063,22 +1085,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig
index cb966ca2ce89..02716f72db6f 100644
--- a/arch/powerpc/configs/mpc8272_ads_defconfig
+++ b/arch/powerpc/configs/mpc8272_ads_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:57 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:54 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -53,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -99,7 +104,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -112,9 +116,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -128,6 +139,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -135,7 +150,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_INTEGRITY is not set
#
@@ -216,6 +231,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -231,9 +247,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -303,6 +319,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
@@ -383,7 +400,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
@@ -489,6 +510,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -524,13 +546,17 @@ CONFIG_HAVE_IDE=y
#
#
-# A new alternative FireWire stack is available with EXPERIMENTAL=y
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -577,6 +603,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
@@ -598,8 +625,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_JME is not set
@@ -671,12 +700,13 @@ CONFIG_INPUT_EVDEV=y
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
@@ -741,6 +771,10 @@ CONFIG_HW_RANDOM=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -784,22 +818,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -828,6 +847,10 @@ CONFIG_DAB=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -847,9 +870,10 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -998,6 +1022,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1028,6 +1053,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1039,7 +1067,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1053,22 +1080,23 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig
index 433c303eb82b..4a96cb6925b4 100644
--- a/arch/powerpc/configs/mpc83xx_defconfig
+++ b/arch/powerpc/configs/mpc83xx_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:21:58 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:55 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_FSL_EMB_PERFMON is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -31,15 +33,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -54,6 +57,7 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_REDBOOT=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
@@ -61,6 +65,7 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -110,7 +115,6 @@ CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -123,8 +127,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
@@ -138,6 +149,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -150,7 +165,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -192,6 +207,7 @@ CONFIG_MPC837x_MDS=y
CONFIG_MPC837x_RDB=y
CONFIG_SBC834x=y
CONFIG_ASP834x=y
+# CONFIG_KMETER1 is not set
CONFIG_PPC_MPC831x=y
CONFIG_PPC_MPC832x=y
CONFIG_PPC_MPC834x=y
@@ -241,6 +257,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -261,9 +278,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -374,6 +391,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -391,7 +409,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -507,6 +529,7 @@ CONFIG_MTD_NAND_FSL_ELBC=y
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -542,7 +565,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -565,10 +590,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -586,6 +607,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -594,6 +616,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -613,7 +636,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -697,14 +719,17 @@ CONFIG_ATA_SFF=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -751,6 +776,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -770,11 +796,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -965,13 +993,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -1050,6 +1082,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1104,24 +1137,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1159,7 +1177,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1176,10 +1194,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1205,6 +1224,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1291,6 +1311,10 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1310,10 +1334,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1377,6 +1403,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1413,7 +1440,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
CONFIG_UCC_FAST=y
CONFIG_UCC=y
@@ -1438,6 +1504,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1461,22 +1528,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index c162724fed4f..ada595898af1 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Tue Apr 21 15:40:23 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:55 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -34,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -57,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -116,7 +119,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -129,9 +131,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -146,6 +155,11 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=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 is not set
CONFIG_SLABINFO=y
@@ -158,7 +172,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -191,6 +205,7 @@ CONFIG_MPC8536_DS=y
CONFIG_MPC85xx_DS=y
CONFIG_SOCRATES=y
CONFIG_KSI8560=y
+# CONFIG_XES_MPC85xx is not set
CONFIG_STX_GP3=y
CONFIG_TQM8540=y
CONFIG_TQM8541=y
@@ -241,7 +256,9 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
-# CONFIG_IOMMU_HELPER is not set
+CONFIG_IOMMU_HELPER=y
+CONFIG_SWIOTLB=y
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -260,9 +277,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -296,7 +313,8 @@ CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_IOV is not set
# CONFIG_PCCARD is not set
# CONFIG_HOTPLUG_PCI is not set
-# CONFIG_HAS_RAPIDIO is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
#
# Advanced setup
@@ -406,6 +424,7 @@ CONFIG_SCTP_HMAC_MD5=y
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -424,7 +443,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -450,6 +473,7 @@ CONFIG_EXTRA_FIRMWARE=""
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -485,7 +509,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -509,10 +535,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
CONFIG_SCSI_LOGGING=y
@@ -530,6 +552,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -538,6 +561,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -557,7 +581,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -641,14 +664,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -695,6 +721,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
CONFIG_FS_ENET_HAS_SCC=y
@@ -718,11 +745,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -897,6 +926,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
CONFIG_I2C_CPM=m
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -927,13 +957,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -987,76 +1021,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MC44S803=m
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-CONFIG_DVB_CAPTURE_DRIVERS=y
-
-#
-# Supported SAA7146 based PCI Adapters
-#
-# CONFIG_TTPCI_EEPROM is not set
-# CONFIG_DVB_BUDGET_CORE is not set
-
-#
-# Supported USB Adapters
-#
-# CONFIG_DVB_USB is not set
-# CONFIG_DVB_TTUSB_BUDGET is not set
-# CONFIG_DVB_TTUSB_DEC is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported BT878 Adapters
-#
-
-#
-# Supported Pluto2 Adapters
-#
-# CONFIG_DVB_PLUTO2 is not set
-
-#
-# Supported SDMC DM1105 Adapters
-#
-# CONFIG_DVB_DM1105 is not set
-
-#
-# Supported DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1096,6 +1063,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
+# 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_AC97_CODEC=y
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
@@ -1122,6 +1094,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
@@ -1152,6 +1125,7 @@ CONFIG_SND_PCI=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -1196,7 +1170,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1213,10 +1187,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1242,6 +1217,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1251,9 +1227,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1352,8 +1328,6 @@ CONFIG_EDAC=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_MPC85XX=y
-# CONFIG_EDAC_AMD8131 is not set
-# CONFIG_EDAC_AMD8111 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1385,6 +1359,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1425,6 +1400,10 @@ CONFIG_DMA_ENGINE=y
# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1445,11 +1424,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1524,6 +1504,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -1628,6 +1609,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1658,6 +1640,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1670,7 +1655,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1684,16 +1668,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1702,9 +1685,13 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 1aa1c508d600..db082ce5a1c5 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Tue Apr 21 15:41:18 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:56 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
CONFIG_PPC_85xx=y
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
@@ -35,15 +35,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -58,11 +59,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -117,7 +120,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -130,9 +132,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -148,6 +157,11 @@ CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=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 is not set
CONFIG_SLABINFO=y
@@ -161,7 +175,7 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -194,6 +208,7 @@ CONFIG_MPC8536_DS=y
CONFIG_MPC85xx_DS=y
CONFIG_SOCRATES=y
CONFIG_KSI8560=y
+# CONFIG_XES_MPC85xx is not set
CONFIG_STX_GP3=y
CONFIG_TQM8540=y
CONFIG_TQM8541=y
@@ -244,7 +259,9 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
-# CONFIG_IOMMU_HELPER is not set
+CONFIG_IOMMU_HELPER=y
+CONFIG_SWIOTLB=y
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -264,9 +281,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -300,7 +317,8 @@ CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_IOV is not set
# CONFIG_PCCARD is not set
# CONFIG_HOTPLUG_PCI is not set
-# CONFIG_HAS_RAPIDIO is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
#
# Advanced setup
@@ -410,6 +428,7 @@ CONFIG_SCTP_HMAC_MD5=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
@@ -428,7 +447,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -454,6 +477,7 @@ CONFIG_EXTRA_FIRMWARE=""
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -489,7 +513,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -513,10 +539,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
CONFIG_SCSI_LOGGING=y
@@ -534,6 +556,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -542,6 +565,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -561,7 +585,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -645,14 +668,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -699,6 +725,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
CONFIG_FS_ENET_HAS_SCC=y
@@ -722,11 +749,13 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_TX_ON_DEMAND is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -901,6 +930,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
CONFIG_I2C_CPM=m
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -931,13 +961,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -991,76 +1025,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MC44S803=m
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-CONFIG_DVB_CAPTURE_DRIVERS=y
-
-#
-# Supported SAA7146 based PCI Adapters
-#
-# CONFIG_TTPCI_EEPROM is not set
-# CONFIG_DVB_BUDGET_CORE is not set
-
-#
-# Supported USB Adapters
-#
-# CONFIG_DVB_USB is not set
-# CONFIG_DVB_TTUSB_BUDGET is not set
-# CONFIG_DVB_TTUSB_DEC is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported BT878 Adapters
-#
-
-#
-# Supported Pluto2 Adapters
-#
-# CONFIG_DVB_PLUTO2 is not set
-
-#
-# Supported SDMC DM1105 Adapters
-#
-# CONFIG_DVB_DM1105 is not set
-
-#
-# Supported DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1100,6 +1067,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
+# 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_AC97_CODEC=y
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
@@ -1126,6 +1098,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
@@ -1156,6 +1129,7 @@ CONFIG_SND_PCI=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -1200,7 +1174,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1217,10 +1191,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1246,6 +1221,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1255,9 +1231,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1356,8 +1332,6 @@ CONFIG_EDAC=y
# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_MPC85XX=y
-# CONFIG_EDAC_AMD8131 is not set
-# CONFIG_EDAC_AMD8111 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
@@ -1389,6 +1363,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1429,6 +1404,10 @@ CONFIG_DMA_ENGINE=y
# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1449,11 +1428,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1528,6 +1508,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -1632,6 +1613,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1662,6 +1644,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1674,7 +1659,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1688,16 +1672,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1706,9 +1689,13 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
# CONFIG_CODE_PATCHING_SELFTEST is not set
# CONFIG_FTR_FIXUP_SELFTEST is not set
# CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig
index 3add6f62b21e..6809b61ed3de 100644
--- a/arch/powerpc/configs/mpc866_ads_defconfig
+++ b/arch/powerpc/configs/mpc866_ads_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:00 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:57 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
CONFIG_PPC_8xx=y
# CONFIG_40x is not set
@@ -27,15 +27,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -48,11 +49,13 @@ CONFIG_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -98,7 +101,6 @@ CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
# CONFIG_BUG is not set
@@ -111,8 +113,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -126,6 +135,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -133,7 +146,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -219,6 +232,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_MATH_EMULATION=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -238,9 +252,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -278,6 +292,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -339,6 +354,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -356,7 +372,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -374,6 +394,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -407,7 +428,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -446,6 +466,7 @@ 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_FS_ENET=y
CONFIG_FS_ENET_HAS_SCC=y
CONFIG_FS_ENET_HAS_FEC=y
@@ -453,6 +474,7 @@ CONFIG_FS_ENET_MDIO_FEC=y
CONFIG_NETDEV_1000=y
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
CONFIG_NETDEV_10000=y
#
@@ -496,11 +518,11 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
@@ -562,6 +584,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -597,22 +624,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -664,6 +676,10 @@ CONFIG_USB_SUPPORT=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -685,10 +701,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -808,6 +826,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -831,22 +850,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_PPC_EARLY_DEBUG is not set
diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig
index 5bb1b8eb0b49..0e8684a3138d 100644
--- a/arch/powerpc/configs/mpc86xx_defconfig
+++ b/arch/powerpc/configs/mpc86xx_defconfig
@@ -1,26 +1,28 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:00 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:58 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_PHYS_64BIT is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_PPC32=y
@@ -32,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -55,11 +58,13 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -114,7 +119,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -127,9 +131,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -144,6 +155,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -157,7 +172,7 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -236,7 +251,9 @@ CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
-# CONFIG_IOMMU_HELPER is not set
+CONFIG_IOMMU_HELPER=y
+CONFIG_SWIOTLB=y
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -258,9 +275,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -403,6 +420,7 @@ CONFIG_SCTP_HMAC_MD5=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
@@ -421,7 +439,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -447,6 +469,7 @@ CONFIG_EXTRA_FIRMWARE=""
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -482,7 +505,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -506,10 +531,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
CONFIG_SCSI_LOGGING=y
@@ -527,6 +548,7 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -535,6 +557,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -554,7 +577,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -638,14 +660,17 @@ CONFIG_PATA_ALI=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -692,6 +717,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -711,8 +737,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_FSL_PQ_MDIO=y
CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -913,13 +941,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -973,76 +1005,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-CONFIG_DVB_CORE=m
-CONFIG_VIDEO_MEDIA=m
-
-#
-# Multimedia drivers
-#
-# CONFIG_MEDIA_ATTACH is not set
-CONFIG_MEDIA_TUNER=m
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_MEDIA_TUNER_SIMPLE=m
-CONFIG_MEDIA_TUNER_TDA8290=m
-CONFIG_MEDIA_TUNER_TDA9887=m
-CONFIG_MEDIA_TUNER_TEA5761=m
-CONFIG_MEDIA_TUNER_TEA5767=m
-CONFIG_MEDIA_TUNER_MT20XX=m
-CONFIG_MEDIA_TUNER_XC2028=m
-CONFIG_MEDIA_TUNER_XC5000=m
-CONFIG_MEDIA_TUNER_MC44S803=m
-# CONFIG_DVB_DYNAMIC_MINORS is not set
-CONFIG_DVB_CAPTURE_DRIVERS=y
-
-#
-# Supported SAA7146 based PCI Adapters
-#
-# CONFIG_TTPCI_EEPROM is not set
-# CONFIG_DVB_BUDGET_CORE is not set
-
-#
-# Supported USB Adapters
-#
-# CONFIG_DVB_USB is not set
-# CONFIG_DVB_TTUSB_BUDGET is not set
-# CONFIG_DVB_TTUSB_DEC is not set
-# CONFIG_DVB_SIANO_SMS1XXX is not set
-
-#
-# Supported FlexCopII (B2C2) Adapters
-#
-# CONFIG_DVB_B2C2_FLEXCOP is not set
-
-#
-# Supported BT878 Adapters
-#
-
-#
-# Supported Pluto2 Adapters
-#
-# CONFIG_DVB_PLUTO2 is not set
-
-#
-# Supported SDMC DM1105 Adapters
-#
-# CONFIG_DVB_DM1105 is not set
-
-#
-# Supported DVB Frontends
-#
-# CONFIG_DVB_FE_CUSTOMISE is not set
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1082,6 +1047,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
CONFIG_SND_VMASTER=y
+# 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_AC97_CODEC=y
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
@@ -1108,6 +1078,7 @@ CONFIG_SND_PCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
@@ -1138,6 +1109,7 @@ CONFIG_SND_PCI=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -1182,7 +1154,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=y
@@ -1199,10 +1171,11 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-CONFIG_THRUSTMASTER_FF=m
-CONFIG_ZEROPLUS_FF=m
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1228,6 +1201,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1237,9 +1211,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1360,6 +1334,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1387,6 +1362,10 @@ CONFIG_RTC_DRV_CMOS=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1406,11 +1385,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1485,6 +1465,7 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -1586,6 +1567,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1616,6 +1598,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1628,7 +1613,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1642,16 +1626,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1659,6 +1642,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig
index 42e64ebc279d..dbe8e869a827 100644
--- a/arch/powerpc/configs/mpc885_ads_defconfig
+++ b/arch/powerpc/configs/mpc885_ads_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:01 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:31:59 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
# CONFIG_PPC_85xx is not set
CONFIG_PPC_8xx=y
# CONFIG_40x is not set
@@ -27,15 +27,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -49,11 +50,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -100,7 +103,6 @@ CONFIG_EMBEDDED=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
@@ -113,8 +115,15 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -128,13 +137,17 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
CONFIG_BASE_SMALL=1
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -227,6 +240,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_MATH_EMULATION is not set
CONFIG_8XX_MINIMAL_FPEMU=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -246,9 +260,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -287,6 +301,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -343,6 +358,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -360,7 +376,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -463,6 +483,7 @@ CONFIG_MTD_PHYSMAP_OF=y
#
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
# CONFIG_MISC_DEVICES is not set
@@ -480,7 +501,6 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -519,6 +539,7 @@ 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_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
CONFIG_FS_ENET_HAS_FEC=y
@@ -590,6 +611,11 @@ CONFIG_GEN_RTC=y
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -613,22 +639,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -653,6 +664,10 @@ CONFIG_DAB=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -664,12 +679,15 @@ CONFIG_DAB=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -786,6 +804,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -814,6 +833,9 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_SLUB_STATS is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -825,7 +847,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -838,16 +859,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -855,6 +875,9 @@ CONFIG_TRACING_SUPPORT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig
index 129d80860f2a..ff96bb43c32d 100644
--- a/arch/powerpc/configs/pq2fads_defconfig
+++ b/arch/powerpc/configs/pq2fads_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:02 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:00 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -53,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -103,7 +108,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -116,9 +120,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -132,6 +143,10 @@ CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -139,7 +154,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_INTEGRITY is not set
#
@@ -219,6 +234,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -234,9 +250,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -307,6 +323,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
@@ -387,7 +404,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
@@ -493,6 +514,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -518,6 +540,7 @@ CONFIG_MISC_DEVICES=y
# EEPROM support
#
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -583,13 +606,17 @@ CONFIG_IDE_PROC_FS=y
#
#
-# A new alternative FireWire stack is available with EXPERIMENTAL=y
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -636,6 +663,7 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
# CONFIG_ATL2 is not set
CONFIG_FS_ENET=y
# CONFIG_FS_ENET_HAS_SCC is not set
@@ -657,8 +685,10 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_JME is not set
@@ -730,12 +760,13 @@ CONFIG_INPUT_EVDEV=y
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
@@ -802,6 +833,10 @@ CONFIG_HW_RANDOM=y
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -845,22 +880,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -903,8 +923,9 @@ CONFIG_USB_GADGET_SELECTED=y
# 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_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
CONFIG_USB_GADGET_M66592=y
CONFIG_USB_M66592=y
# CONFIG_USB_GADGET_AMD5536UDC is not set
@@ -912,9 +933,11 @@ CONFIG_USB_M66592=y
# CONFIG_USB_GADGET_CI13XXX is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=y
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_GADGETFS is not set
@@ -939,6 +962,10 @@ CONFIG_USB_ETH_RNDIS=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -958,9 +985,10 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1110,6 +1138,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1140,6 +1169,9 @@ CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1151,7 +1183,6 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1165,22 +1196,23 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/powerpc/configs/prpmc2800_defconfig b/arch/powerpc/configs/prpmc2800_defconfig
index e9f287f313fa..1293c465d7fa 100644
--- a/arch/powerpc/configs/prpmc2800_defconfig
+++ b/arch/powerpc/configs/prpmc2800_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:03 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:01 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_NOT_COHERENT_CACHE=y
CONFIG_CHECK_CACHE_COHERENCY=y
@@ -32,15 +34,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -54,11 +57,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -114,7 +119,6 @@ CONFIG_ANON_INODES=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -127,9 +131,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -142,6 +153,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -149,7 +164,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -228,6 +243,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_PPC_NEED_DMA_SYNC_OPS=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -249,9 +265,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -296,6 +312,7 @@ CONFIG_PAGE_OFFSET=0xc0000000
CONFIG_KERNEL_START=0xc0000000
CONFIG_PHYSICAL_START=0x00000000
CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
CONFIG_NET=y
#
@@ -357,6 +374,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -374,7 +392,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -479,6 +501,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -514,7 +537,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -591,10 +616,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -611,6 +632,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -619,6 +641,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -638,7 +661,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -721,7 +743,11 @@ CONFIG_SATA_MV=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
@@ -730,7 +756,6 @@ CONFIG_MACINTOSH_DRIVERS=y
# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM 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
@@ -797,6 +822,7 @@ CONFIG_8139TOO=y
# CONFIG_SMSC9420 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
# CONFIG_ATL2 is not set
@@ -818,6 +844,7 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
CONFIG_MV643XX_ETH=y
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
@@ -1007,13 +1034,17 @@ CONFIG_I2C_MV64XXX=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -1068,6 +1099,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1102,23 +1134,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -1163,6 +1181,7 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
# CONFIG_DRAGONRISE_FF is not set
CONFIG_HID_EZKEY=y
CONFIG_HID_KYE=y
@@ -1180,9 +1199,14 @@ CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
CONFIG_ZEROPLUS_FF=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1207,6 +1231,7 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -1215,6 +1240,8 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1322,6 +1349,7 @@ CONFIG_RTC_DRV_MAX6900=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1349,6 +1377,10 @@ CONFIG_RTC_DRV_MAX6900=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1368,11 +1400,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1469,7 +1502,46 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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 is not set
# CONFIG_DLM is not set
# CONFIG_BINARY_PRINTF is not set
@@ -1494,6 +1566,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1519,22 +1592,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig
index bd4a8d435c50..28384dc01003 100644
--- a/arch/powerpc/configs/storcenter_defconfig
+++ b/arch/powerpc/configs/storcenter_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Wed May 13 17:22:04 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 23:32:01 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,16 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +55,13 @@ CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -101,7 +106,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -114,9 +118,16 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
@@ -129,6 +140,10 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -141,7 +156,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -222,6 +237,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
@@ -242,9 +258,9 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -347,6 +363,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -364,7 +381,11 @@ CONFIG_WIRELESS=y
CONFIG_WIRELESS_OLD_REGULATORY=y
# CONFIG_WIRELESS_EXT is not set
# CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -501,7 +522,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
CONFIG_IDE=y
@@ -579,10 +602,6 @@ CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR 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
@@ -599,6 +618,7 @@ CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -607,6 +627,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -626,7 +647,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -660,14 +680,17 @@ CONFIG_MD_RAID6_PQ=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -695,8 +718,10 @@ CONFIG_R8169=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
# CONFIG_FSL_PQ_MDIO is not set
# CONFIG_GIANFAR is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -845,13 +870,17 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
@@ -879,23 +908,9 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -937,6 +952,7 @@ CONFIG_USB_DEVICE_CLASS=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -946,6 +962,8 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1064,6 +1082,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1091,6 +1110,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1110,7 +1133,6 @@ 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
@@ -1119,6 +1141,8 @@ CONFIG_XFS_FS=m
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1273,6 +1297,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1298,22 +1323,11 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h
index 897eade3afbe..56f2f2ea5631 100644
--- a/arch/powerpc/include/asm/bitops.h
+++ b/arch/powerpc/include/asm/bitops.h
@@ -56,174 +56,102 @@
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7)
+/* Macro for generating the ***_bits() functions */
+#define DEFINE_BITOP(fn, op, prefix, postfix) \
+static __inline__ void fn(unsigned long mask, \
+ volatile unsigned long *_p) \
+{ \
+ unsigned long old; \
+ unsigned long *p = (unsigned long *)_p; \
+ __asm__ __volatile__ ( \
+ prefix \
+"1:" PPC_LLARX "%0,0,%3\n" \
+ stringify_in_c(op) "%0,%0,%2\n" \
+ PPC405_ERR77(0,%3) \
+ PPC_STLCX "%0,0,%3\n" \
+ "bne- 1b\n" \
+ postfix \
+ : "=&r" (old), "+m" (*p) \
+ : "r" (mask), "r" (p) \
+ : "cc", "memory"); \
+}
+
+DEFINE_BITOP(set_bits, or, "", "")
+DEFINE_BITOP(clear_bits, andc, "", "")
+DEFINE_BITOP(clear_bits_unlock, andc, LWSYNC_ON_SMP, "")
+DEFINE_BITOP(change_bits, xor, "", "")
+
static __inline__ void set_bit(int nr, volatile unsigned long *addr)
{
- unsigned long old;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%3 # set_bit\n"
- "or %0,%0,%2\n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (mask), "r" (p)
- : "cc" );
+ set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
}
static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
{
- unsigned long old;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%3 # clear_bit\n"
- "andc %0,%0,%2\n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (mask), "r" (p)
- : "cc" );
+ clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
}
static __inline__ void clear_bit_unlock(int nr, volatile unsigned long *addr)
{
- unsigned long old;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
- LWSYNC_ON_SMP
-"1:" PPC_LLARX "%0,0,%3 # clear_bit_unlock\n"
- "andc %0,%0,%2\n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (mask), "r" (p)
- : "cc", "memory");
+ clear_bits_unlock(BITOP_MASK(nr), addr + BITOP_WORD(nr));
}
static __inline__ void change_bit(int nr, volatile unsigned long *addr)
{
- unsigned long old;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%3 # change_bit\n"
- "xor %0,%0,%2\n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (mask), "r" (p)
- : "cc" );
+ change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+}
+
+/* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output
+ * operands. */
+#define DEFINE_TESTOP(fn, op, prefix, postfix) \
+static __inline__ unsigned long fn( \
+ unsigned long mask, \
+ volatile unsigned long *_p) \
+{ \
+ unsigned long old, t; \
+ unsigned long *p = (unsigned long *)_p; \
+ __asm__ __volatile__ ( \
+ prefix \
+"1:" PPC_LLARX "%0,0,%3\n" \
+ stringify_in_c(op) "%1,%0,%2\n" \
+ PPC405_ERR77(0,%3) \
+ PPC_STLCX "%1,0,%3\n" \
+ "bne- 1b\n" \
+ postfix \
+ : "=&r" (old), "=&r" (t) \
+ : "r" (mask), "r" (p) \
+ : "cc", "memory"); \
+ return (old & mask); \
}
+DEFINE_TESTOP(test_and_set_bits, or, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_set_bits_lock, or, "", ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_clear_bits, andc, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_change_bits, xor, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+
static __inline__ int test_and_set_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned long old, t;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
- LWSYNC_ON_SMP
-"1:" PPC_LLARX "%0,0,%3 # test_and_set_bit\n"
- "or %1,%0,%2 \n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%1,0,%3 \n"
- "bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (old), "=&r" (t)
- : "r" (mask), "r" (p)
- : "cc", "memory");
-
- return (old & mask) != 0;
+ return test_and_set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
}
static __inline__ int test_and_set_bit_lock(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned long old, t;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%3 # test_and_set_bit_lock\n"
- "or %1,%0,%2 \n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%1,0,%3 \n"
- "bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (old), "=&r" (t)
- : "r" (mask), "r" (p)
- : "cc", "memory");
-
- return (old & mask) != 0;
+ return test_and_set_bits_lock(BITOP_MASK(nr),
+ addr + BITOP_WORD(nr)) != 0;
}
static __inline__ int test_and_clear_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned long old, t;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
- LWSYNC_ON_SMP
-"1:" PPC_LLARX "%0,0,%3 # test_and_clear_bit\n"
- "andc %1,%0,%2 \n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%1,0,%3 \n"
- "bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (old), "=&r" (t)
- : "r" (mask), "r" (p)
- : "cc", "memory");
-
- return (old & mask) != 0;
+ return test_and_clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
}
static __inline__ int test_and_change_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned long old, t;
- unsigned long mask = BITOP_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
- __asm__ __volatile__(
- LWSYNC_ON_SMP
-"1:" PPC_LLARX "%0,0,%3 # test_and_change_bit\n"
- "xor %1,%0,%2 \n"
- PPC405_ERR77(0,%3)
- PPC_STLCX "%1,0,%3 \n"
- "bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (old), "=&r" (t)
- : "r" (mask), "r" (p)
- : "cc", "memory");
-
- return (old & mask) != 0;
-}
-
-static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
-{
- unsigned long old;
-
- __asm__ __volatile__(
-"1:" PPC_LLARX "%0,0,%3 # set_bits\n"
- "or %0,%0,%2\n"
- PPC_STLCX "%0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*addr)
- : "r" (mask), "r" (addr)
- : "cc");
+ return test_and_change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
}
#include <asm-generic/bitops/non-atomic.h>
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index fb11b0c459b8..a8e18447c62b 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -5,6 +5,15 @@
/*
* Mapping of threads to cores
+ *
+ * Note: This implementation is limited to a power of 2 number of
+ * threads per core and the same number for each core in the system
+ * (though it would work if some processors had less threads as long
+ * as the CPU numbers are still allocated, just not brought offline).
+ *
+ * However, the API allows for a different implementation in the future
+ * if needed, as long as you only use the functions and not the variables
+ * directly.
*/
#ifdef CONFIG_SMP
@@ -67,5 +76,12 @@ static inline int cpu_first_thread_in_core(int cpu)
return cpu & ~(threads_per_core - 1);
}
+static inline int cpu_last_thread_in_core(int cpu)
+{
+ return cpu | (threads_per_core - 1);
+}
+
+
+
#endif /* _ASM_POWERPC_CPUTHREADS_H */
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 7d2277cef09a..e3e06e0f7fc0 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -30,4 +30,7 @@ dev_archdata_get_node(const struct dev_archdata *ad)
return ad->of_node;
}
+struct pdev_archdata {
+};
+
#endif /* _ASM_POWERPC_DEVICE_H */
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
new file mode 100644
index 000000000000..94cb3d79d125
--- /dev/null
+++ b/arch/powerpc/include/asm/exception-64e.h
@@ -0,0 +1,201 @@
+/*
+ * Definitions for use by exception code on Book3-E
+ *
+ * Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_POWERPC_EXCEPTION_64E_H
+#define _ASM_POWERPC_EXCEPTION_64E_H
+
+/*
+ * SPRGs usage an other considerations...
+ *
+ * Since TLB miss and other standard exceptions can be interrupted by
+ * critical exceptions which can themselves be interrupted by machine
+ * checks, and since the two later can themselves cause a TLB miss when
+ * hitting the linear mapping for the kernel stacks, we need to be a bit
+ * creative on how we use SPRGs.
+ *
+ * The base idea is that we have one SRPG reserved for critical and one
+ * for machine check interrupts. Those are used to save a GPR that can
+ * then be used to get the PACA, and store as much context as we need
+ * to save in there. That includes saving the SPRGs used by the TLB miss
+ * handler for linear mapping misses and the associated SRR0/1 due to
+ * the above re-entrancy issue.
+ *
+ * So here's the current usage pattern. It's done regardless of which
+ * SPRGs are user-readable though, thus we might have to change some of
+ * this later. In order to do that more easily, we use special constants
+ * for naming them
+ *
+ * WARNING: Some of these SPRGs are user readable. We need to do something
+ * about it as some point by making sure they can't be used to leak kernel
+ * critical data
+ */
+
+
+/* We are out of SPRGs so we save some things in the PACA. The normal
+ * exception frame is smaller than the CRIT or MC one though
+ */
+#define EX_R1 (0 * 8)
+#define EX_CR (1 * 8)
+#define EX_R10 (2 * 8)
+#define EX_R11 (3 * 8)
+#define EX_R14 (4 * 8)
+#define EX_R15 (5 * 8)
+
+/* The TLB miss exception uses different slots */
+
+#define EX_TLB_R10 ( 0 * 8)
+#define EX_TLB_R11 ( 1 * 8)
+#define EX_TLB_R12 ( 2 * 8)
+#define EX_TLB_R13 ( 3 * 8)
+#define EX_TLB_R14 ( 4 * 8)
+#define EX_TLB_R15 ( 5 * 8)
+#define EX_TLB_R16 ( 6 * 8)
+#define EX_TLB_CR ( 7 * 8)
+#define EX_TLB_DEAR ( 8 * 8) /* Level 0 and 2 only */
+#define EX_TLB_ESR ( 9 * 8) /* Level 0 and 2 only */
+#define EX_TLB_SRR0 (10 * 8)
+#define EX_TLB_SRR1 (11 * 8)
+#define EX_TLB_MMUCR0 (12 * 8) /* Level 0 */
+#define EX_TLB_MAS1 (12 * 8) /* Level 0 */
+#define EX_TLB_MAS2 (13 * 8) /* Level 0 */
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+#define EX_TLB_R8 (14 * 8)
+#define EX_TLB_R9 (15 * 8)
+#define EX_TLB_LR (16 * 8)
+#define EX_TLB_SIZE (17 * 8)
+#else
+#define EX_TLB_SIZE (14 * 8)
+#endif
+
+#define START_EXCEPTION(label) \
+ .globl exc_##label##_book3e; \
+exc_##label##_book3e:
+
+/* TLB miss exception prolog
+ *
+ * This prolog handles re-entrancy (up to 3 levels supported in the PACA
+ * though we currently don't test for overflow). It provides you with a
+ * re-entrancy safe working space of r10...r16 and CR with r12 being used
+ * as the exception area pointer in the PACA for that level of re-entrancy
+ * and r13 containing the PACA pointer.
+ *
+ * SRR0 and SRR1 are saved, but DEAR and ESR are not, since they don't apply
+ * as-is for instruction exceptions. It's up to the actual exception code
+ * to save them as well if required.
+ */
+#define TLB_MISS_PROLOG \
+ mtspr SPRN_SPRG_TLB_SCRATCH,r12; \
+ mfspr r12,SPRN_SPRG_TLB_EXFRAME; \
+ std r10,EX_TLB_R10(r12); \
+ mfcr r10; \
+ std r11,EX_TLB_R11(r12); \
+ mfspr r11,SPRN_SPRG_TLB_SCRATCH; \
+ std r13,EX_TLB_R13(r12); \
+ mfspr r13,SPRN_SPRG_PACA; \
+ std r14,EX_TLB_R14(r12); \
+ addi r14,r12,EX_TLB_SIZE; \
+ std r15,EX_TLB_R15(r12); \
+ mfspr r15,SPRN_SRR1; \
+ std r16,EX_TLB_R16(r12); \
+ mfspr r16,SPRN_SRR0; \
+ std r10,EX_TLB_CR(r12); \
+ std r11,EX_TLB_R12(r12); \
+ mtspr SPRN_SPRG_TLB_EXFRAME,r14; \
+ std r15,EX_TLB_SRR1(r12); \
+ std r16,EX_TLB_SRR0(r12); \
+ TLB_MISS_PROLOG_STATS
+
+/* And these are the matching epilogs that restores things
+ *
+ * There are 3 epilogs:
+ *
+ * - SUCCESS : Unwinds one level
+ * - ERROR : restore from level 0 and reset
+ * - ERROR_SPECIAL : restore from current level and reset
+ *
+ * Normal errors use ERROR, that is, they restore the initial fault context
+ * and trigger a fault. However, there is a special case for linear mapping
+ * errors. Those should basically never happen, but if they do happen, we
+ * want the error to point out the context that did that linear mapping
+ * fault, not the initial level 0 (basically, we got a bogus PGF or something
+ * like that). For userland errors on the linear mapping, there is no
+ * difference since those are always level 0 anyway
+ */
+
+#define TLB_MISS_RESTORE(freg) \
+ ld r14,EX_TLB_CR(r12); \
+ ld r10,EX_TLB_R10(r12); \
+ ld r15,EX_TLB_SRR0(r12); \
+ ld r16,EX_TLB_SRR1(r12); \
+ mtspr SPRN_SPRG_TLB_EXFRAME,freg; \
+ ld r11,EX_TLB_R11(r12); \
+ mtcr r14; \
+ ld r13,EX_TLB_R13(r12); \
+ ld r14,EX_TLB_R14(r12); \
+ mtspr SPRN_SRR0,r15; \
+ ld r15,EX_TLB_R15(r12); \
+ mtspr SPRN_SRR1,r16; \
+ TLB_MISS_RESTORE_STATS \
+ ld r16,EX_TLB_R16(r12); \
+ ld r12,EX_TLB_R12(r12); \
+
+#define TLB_MISS_EPILOG_SUCCESS \
+ TLB_MISS_RESTORE(r12)
+
+#define TLB_MISS_EPILOG_ERROR \
+ addi r12,r13,PACA_EXTLB; \
+ TLB_MISS_RESTORE(r12)
+
+#define TLB_MISS_EPILOG_ERROR_SPECIAL \
+ addi r11,r13,PACA_EXTLB; \
+ TLB_MISS_RESTORE(r11)
+
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+#define TLB_MISS_PROLOG_STATS \
+ mflr r10; \
+ std r8,EX_TLB_R8(r12); \
+ std r9,EX_TLB_R9(r12); \
+ std r10,EX_TLB_LR(r12);
+#define TLB_MISS_RESTORE_STATS \
+ ld r16,EX_TLB_LR(r12); \
+ ld r9,EX_TLB_R9(r12); \
+ ld r8,EX_TLB_R8(r12); \
+ mtlr r16;
+#define TLB_MISS_STATS_D(name) \
+ addi r9,r13,MMSTAT_DSTATS+name; \
+ bl .tlb_stat_inc;
+#define TLB_MISS_STATS_I(name) \
+ addi r9,r13,MMSTAT_ISTATS+name; \
+ bl .tlb_stat_inc;
+#define TLB_MISS_STATS_X(name) \
+ ld r8,PACA_EXTLB+EX_TLB_ESR(r13); \
+ cmpdi cr2,r8,-1; \
+ beq cr2,61f; \
+ addi r9,r13,MMSTAT_DSTATS+name; \
+ b 62f; \
+61: addi r9,r13,MMSTAT_ISTATS+name; \
+62: bl .tlb_stat_inc;
+#define TLB_MISS_STATS_SAVE_INFO \
+ std r14,EX_TLB_ESR(r12); /* save ESR */ \
+
+
+#else
+#define TLB_MISS_PROLOG_STATS
+#define TLB_MISS_RESTORE_STATS
+#define TLB_MISS_STATS_D(name)
+#define TLB_MISS_STATS_I(name)
+#define TLB_MISS_STATS_X(name)
+#define TLB_MISS_STATS_Y(name)
+#define TLB_MISS_STATS_SAVE_INFO
+#endif
+
+
+#endif /* _ASM_POWERPC_EXCEPTION_64E_H */
+
diff --git a/arch/powerpc/include/asm/exception.h b/arch/powerpc/include/asm/exception-64s.h
index d3d4534e3c74..a98653b26231 100644
--- a/arch/powerpc/include/asm/exception.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -57,17 +57,16 @@
addi reg,reg,(label)-_stext; /* virt addr of handler ... */
#define EXCEPTION_PROLOG_1(area) \
- mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
+ mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \
std r9,area+EX_R9(r13); /* save r9 - r12 */ \
std r10,area+EX_R10(r13); \
std r11,area+EX_R11(r13); \
std r12,area+EX_R12(r13); \
- mfspr r9,SPRN_SPRG1; \
+ mfspr r9,SPRN_SPRG_SCRATCH0; \
std r9,area+EX_R13(r13); \
mfcr r9
-#define EXCEPTION_PROLOG_PSERIES(area, label) \
- EXCEPTION_PROLOG_1(area); \
+#define EXCEPTION_PROLOG_PSERIES_1(label) \
ld r12,PACAKBASE(r13); /* get high part of &label */ \
ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
mfspr r11,SPRN_SRR0; /* save SRR0 */ \
@@ -78,6 +77,10 @@
rfid; \
b . /* prevent speculative execution */
+#define EXCEPTION_PROLOG_PSERIES(area, label) \
+ EXCEPTION_PROLOG_1(area); \
+ EXCEPTION_PROLOG_PSERIES_1(label);
+
/*
* The common exception prolog is used for all except a few exceptions
* such as a segment miss on a kernel address. We have to be prepared
@@ -144,7 +147,7 @@
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
#define HSTD_EXCEPTION_PSERIES(n, label) \
@@ -152,13 +155,13 @@ label##_pSeries: \
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r20; /* save r20 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r20; /* save r20 */ \
mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \
mtspr SPRN_SRR0,r20; \
mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \
mtspr SPRN_SRR1,r20; \
- mfspr r20,SPRN_SPRG1; /* restore r20 */ \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ mfspr r20,SPRN_SPRG_SCRATCH0; /* restore r20 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
@@ -167,15 +170,15 @@ label##_pSeries: \
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
- mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
+ mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \
std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \
std r10,PACA_EXGEN+EX_R10(r13); \
lbz r10,PACASOFTIRQEN(r13); \
mfcr r9; \
cmpwi r10,0; \
beq masked_interrupt; \
- mfspr r10,SPRN_SPRG1; \
+ mfspr r10,SPRN_SPRG_SCRATCH0; \
std r10,PACA_EXGEN+EX_R13(r13); \
std r11,PACA_EXGEN+EX_R11(r13); \
std r12,PACA_EXGEN+EX_R12(r13); \
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 8b505eaaa38a..e73d554538dd 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -49,8 +49,13 @@ extern void iseries_handle_interrupts(void);
#define raw_irqs_disabled() (local_get_flags() == 0)
#define raw_irqs_disabled_flags(flags) ((flags) == 0)
+#ifdef CONFIG_PPC_BOOK3E
+#define __hard_irq_enable() __asm__ __volatile__("wrteei 1": : :"memory");
+#define __hard_irq_disable() __asm__ __volatile__("wrteei 0": : :"memory");
+#else
#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
+#endif
#define hard_irq_disable() \
do { \
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index dfdf13c9fefd..c9c930ed11d7 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -34,7 +34,8 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
/* We don't currently support large pages. */
-#define KVM_PAGES_PER_HPAGE (1<<31)
+#define KVM_NR_PAGE_SIZES 1
+#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
struct kvm;
struct kvm_run;
@@ -153,7 +154,6 @@ struct kvm_vcpu_arch {
u32 pid;
u32 swap_pid;
- u32 pvr;
u32 ccr0;
u32 ccr1;
u32 dbcr0;
diff --git a/arch/powerpc/include/asm/mmu-40x.h b/arch/powerpc/include/asm/mmu-40x.h
index 776f415a36aa..34916865eaef 100644
--- a/arch/powerpc/include/asm/mmu-40x.h
+++ b/arch/powerpc/include/asm/mmu-40x.h
@@ -61,4 +61,7 @@ typedef struct {
#endif /* !__ASSEMBLY__ */
+#define mmu_virtual_psize MMU_PAGE_4K
+#define mmu_linear_psize MMU_PAGE_256M
+
#endif /* _ASM_POWERPC_MMU_40X_H_ */
diff --git a/arch/powerpc/include/asm/mmu-44x.h b/arch/powerpc/include/asm/mmu-44x.h
index 3c86576bfefa..0372669383a8 100644
--- a/arch/powerpc/include/asm/mmu-44x.h
+++ b/arch/powerpc/include/asm/mmu-44x.h
@@ -79,16 +79,22 @@ typedef struct {
#if (PAGE_SHIFT == 12)
#define PPC44x_TLBE_SIZE PPC44x_TLB_4K
+#define mmu_virtual_psize MMU_PAGE_4K
#elif (PAGE_SHIFT == 14)
#define PPC44x_TLBE_SIZE PPC44x_TLB_16K
+#define mmu_virtual_psize MMU_PAGE_16K
#elif (PAGE_SHIFT == 16)
#define PPC44x_TLBE_SIZE PPC44x_TLB_64K
+#define mmu_virtual_psize MMU_PAGE_64K
#elif (PAGE_SHIFT == 18)
#define PPC44x_TLBE_SIZE PPC44x_TLB_256K
+#define mmu_virtual_psize MMU_PAGE_256K
#else
#error "Unsupported PAGE_SIZE"
#endif
+#define mmu_linear_psize MMU_PAGE_256M
+
#define PPC44x_PGD_OFF_SHIFT (32 - PGDIR_SHIFT + PGD_T_LOG2)
#define PPC44x_PGD_OFF_MASK_BIT (PGDIR_SHIFT - PGD_T_LOG2)
#define PPC44x_PTE_ADD_SHIFT (32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2)
diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h
index 07865a357848..3d11d3ce79ec 100644
--- a/arch/powerpc/include/asm/mmu-8xx.h
+++ b/arch/powerpc/include/asm/mmu-8xx.h
@@ -143,4 +143,7 @@ typedef struct {
} mm_context_t;
#endif /* !__ASSEMBLY__ */
+#define mmu_virtual_psize MMU_PAGE_4K
+#define mmu_linear_psize MMU_PAGE_8M
+
#endif /* _ASM_POWERPC_MMU_8XX_H_ */
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 7e74cff81d86..d74580469361 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -38,58 +38,128 @@
#define BOOK3E_PAGESZ_1TB 30
#define BOOK3E_PAGESZ_2TB 31
-#define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
-#define MAS0_ESEL(x) ((x << 16) & 0x0FFF0000)
-#define MAS0_NV(x) ((x) & 0x00000FFF)
-
-#define MAS1_VALID 0x80000000
-#define MAS1_IPROT 0x40000000
-#define MAS1_TID(x) ((x << 16) & 0x3FFF0000)
-#define MAS1_IND 0x00002000
-#define MAS1_TS 0x00001000
-#define MAS1_TSIZE(x) ((x << 7) & 0x00000F80)
-
-#define MAS2_EPN 0xFFFFF000
-#define MAS2_X0 0x00000040
-#define MAS2_X1 0x00000020
-#define MAS2_W 0x00000010
-#define MAS2_I 0x00000008
-#define MAS2_M 0x00000004
-#define MAS2_G 0x00000002
-#define MAS2_E 0x00000001
+/* MAS registers bit definitions */
+
+#define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
+#define MAS0_ESEL(x) ((x << 16) & 0x0FFF0000)
+#define MAS0_NV(x) ((x) & 0x00000FFF)
+#define MAS0_HES 0x00004000
+#define MAS0_WQ_ALLWAYS 0x00000000
+#define MAS0_WQ_COND 0x00001000
+#define MAS0_WQ_CLR_RSRV 0x00002000
+
+#define MAS1_VALID 0x80000000
+#define MAS1_IPROT 0x40000000
+#define MAS1_TID(x) ((x << 16) & 0x3FFF0000)
+#define MAS1_IND 0x00002000
+#define MAS1_TS 0x00001000
+#define MAS1_TSIZE_MASK 0x00000f80
+#define MAS1_TSIZE_SHIFT 7
+#define MAS1_TSIZE(x) ((x << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+
+#define MAS2_EPN 0xFFFFF000
+#define MAS2_X0 0x00000040
+#define MAS2_X1 0x00000020
+#define MAS2_W 0x00000010
+#define MAS2_I 0x00000008
+#define MAS2_M 0x00000004
+#define MAS2_G 0x00000002
+#define MAS2_E 0x00000001
#define MAS2_EPN_MASK(size) (~0 << (size + 10))
#define MAS2_VAL(addr, size, flags) ((addr) & MAS2_EPN_MASK(size) | (flags))
-#define MAS3_RPN 0xFFFFF000
-#define MAS3_U0 0x00000200
-#define MAS3_U1 0x00000100
-#define MAS3_U2 0x00000080
-#define MAS3_U3 0x00000040
-#define MAS3_UX 0x00000020
-#define MAS3_SX 0x00000010
-#define MAS3_UW 0x00000008
-#define MAS3_SW 0x00000004
-#define MAS3_UR 0x00000002
-#define MAS3_SR 0x00000001
-
-#define MAS4_TLBSELD(x) MAS0_TLBSEL(x)
-#define MAS4_INDD 0x00008000
-#define MAS4_TSIZED(x) MAS1_TSIZE(x)
-#define MAS4_X0D 0x00000040
-#define MAS4_X1D 0x00000020
-#define MAS4_WD 0x00000010
-#define MAS4_ID 0x00000008
-#define MAS4_MD 0x00000004
-#define MAS4_GD 0x00000002
-#define MAS4_ED 0x00000001
-
-#define MAS6_SPID0 0x3FFF0000
-#define MAS6_SPID1 0x00007FFE
-#define MAS6_ISIZE(x) MAS1_TSIZE(x)
-#define MAS6_SAS 0x00000001
-#define MAS6_SPID MAS6_SPID0
-
-#define MAS7_RPN 0xFFFFFFFF
+#define MAS3_RPN 0xFFFFF000
+#define MAS3_U0 0x00000200
+#define MAS3_U1 0x00000100
+#define MAS3_U2 0x00000080
+#define MAS3_U3 0x00000040
+#define MAS3_UX 0x00000020
+#define MAS3_SX 0x00000010
+#define MAS3_UW 0x00000008
+#define MAS3_SW 0x00000004
+#define MAS3_UR 0x00000002
+#define MAS3_SR 0x00000001
+#define MAS3_SPSIZE 0x0000003e
+#define MAS3_SPSIZE_SHIFT 1
+
+#define MAS4_TLBSELD(x) MAS0_TLBSEL(x)
+#define MAS4_INDD 0x00008000 /* Default IND */
+#define MAS4_TSIZED(x) MAS1_TSIZE(x)
+#define MAS4_X0D 0x00000040
+#define MAS4_X1D 0x00000020
+#define MAS4_WD 0x00000010
+#define MAS4_ID 0x00000008
+#define MAS4_MD 0x00000004
+#define MAS4_GD 0x00000002
+#define MAS4_ED 0x00000001
+#define MAS4_WIMGED_MASK 0x0000001f /* Default WIMGE */
+#define MAS4_WIMGED_SHIFT 0
+#define MAS4_VLED MAS4_X1D /* Default VLE */
+#define MAS4_ACMD 0x000000c0 /* Default ACM */
+#define MAS4_ACMD_SHIFT 6
+#define MAS4_TSIZED_MASK 0x00000f80 /* Default TSIZE */
+#define MAS4_TSIZED_SHIFT 7
+
+#define MAS6_SPID0 0x3FFF0000
+#define MAS6_SPID1 0x00007FFE
+#define MAS6_ISIZE(x) MAS1_TSIZE(x)
+#define MAS6_SAS 0x00000001
+#define MAS6_SPID MAS6_SPID0
+#define MAS6_SIND 0x00000002 /* Indirect page */
+#define MAS6_SIND_SHIFT 1
+#define MAS6_SPID_MASK 0x3fff0000
+#define MAS6_SPID_SHIFT 16
+#define MAS6_ISIZE_MASK 0x00000f80
+#define MAS6_ISIZE_SHIFT 7
+
+#define MAS7_RPN 0xFFFFFFFF
+
+/* TLBnCFG encoding */
+#define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */
+#define TLBnCFG_HES 0x00002000 /* HW select supported */
+#define TLBnCFG_IPROT 0x00008000 /* IPROT supported */
+#define TLBnCFG_GTWE 0x00010000 /* Guest can write */
+#define TLBnCFG_IND 0x00020000 /* IND entries supported */
+#define TLBnCFG_PT 0x00040000 /* Can load from page table */
+#define TLBnCFG_ASSOC 0xff000000 /* Associativity */
+
+/* TLBnPS encoding */
+#define TLBnPS_4K 0x00000004
+#define TLBnPS_8K 0x00000008
+#define TLBnPS_16K 0x00000010
+#define TLBnPS_32K 0x00000020
+#define TLBnPS_64K 0x00000040
+#define TLBnPS_128K 0x00000080
+#define TLBnPS_256K 0x00000100
+#define TLBnPS_512K 0x00000200
+#define TLBnPS_1M 0x00000400
+#define TLBnPS_2M 0x00000800
+#define TLBnPS_4M 0x00001000
+#define TLBnPS_8M 0x00002000
+#define TLBnPS_16M 0x00004000
+#define TLBnPS_32M 0x00008000
+#define TLBnPS_64M 0x00010000
+#define TLBnPS_128M 0x00020000
+#define TLBnPS_256M 0x00040000
+#define TLBnPS_512M 0x00080000
+#define TLBnPS_1G 0x00100000
+#define TLBnPS_2G 0x00200000
+#define TLBnPS_4G 0x00400000
+#define TLBnPS_8G 0x00800000
+#define TLBnPS_16G 0x01000000
+#define TLBnPS_32G 0x02000000
+#define TLBnPS_64G 0x04000000
+#define TLBnPS_128G 0x08000000
+#define TLBnPS_256G 0x10000000
+
+/* tlbilx action encoding */
+#define TLBILX_T_ALL 0
+#define TLBILX_T_TID 1
+#define TLBILX_T_FULLMATCH 3
+#define TLBILX_T_CLASS0 4
+#define TLBILX_T_CLASS1 5
+#define TLBILX_T_CLASS2 6
+#define TLBILX_T_CLASS3 7
#ifndef __ASSEMBLY__
@@ -100,6 +170,34 @@ typedef struct {
unsigned int active;
unsigned long vdso_base;
} mm_context_t;
+
+/* Page size definitions, common between 32 and 64-bit
+ *
+ * shift : is the "PAGE_SHIFT" value for that page size
+ * penc : is the pte encoding mask
+ *
+ */
+struct mmu_psize_def
+{
+ unsigned int shift; /* number of bits */
+ unsigned int enc; /* PTE encoding */
+};
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+
+/* The page sizes use the same names as 64-bit hash but are
+ * constants
+ */
+#if defined(CONFIG_PPC_4K_PAGES)
+#define mmu_virtual_psize MMU_PAGE_4K
+#elif defined(CONFIG_PPC_64K_PAGES)
+#define mmu_virtual_psize MMU_PAGE_64K
+#else
+#error Unsupported page size
+#endif
+
+extern int mmu_linear_psize;
+extern int mmu_vmemmap_psize;
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */
diff --git a/arch/powerpc/include/asm/mmu-hash32.h b/arch/powerpc/include/asm/mmu-hash32.h
index 16b1a1e77e64..382fc689f204 100644
--- a/arch/powerpc/include/asm/mmu-hash32.h
+++ b/arch/powerpc/include/asm/mmu-hash32.h
@@ -80,4 +80,10 @@ typedef struct {
#endif /* !__ASSEMBLY__ */
+/* We happily ignore the smaller BATs on 601, we don't actually use
+ * those definitions on hash32 at the moment anyway
+ */
+#define mmu_virtual_psize MMU_PAGE_4K
+#define mmu_linear_psize MMU_PAGE_256M
+
#endif /* _ASM_POWERPC_MMU_HASH32_H_ */
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 98c104a09961..b537903b9fca 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -139,26 +139,6 @@ struct mmu_psize_def
#endif /* __ASSEMBLY__ */
/*
- * The kernel use the constants below to index in the page sizes array.
- * The use of fixed constants for this purpose is better for performances
- * of the low level hash refill handlers.
- *
- * A non supported page size has a "shift" field set to 0
- *
- * Any new page size being implemented can get a new entry in here. Whether
- * the kernel will use it or not is a different matter though. The actual page
- * size used by hugetlbfs is not defined here and may be made variable
- */
-
-#define MMU_PAGE_4K 0 /* 4K */
-#define MMU_PAGE_64K 1 /* 64K */
-#define MMU_PAGE_64K_AP 2 /* 64K Admixed (in a 4K segment) */
-#define MMU_PAGE_1M 3 /* 1M */
-#define MMU_PAGE_16M 4 /* 16M */
-#define MMU_PAGE_16G 5 /* 16G */
-#define MMU_PAGE_COUNT 6
-
-/*
* Segment sizes.
* These are the values used by hardware in the B field of
* SLB entries and the first dword of MMU hashtable entries.
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index fb57ded592f9..2fcfefc60894 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -17,6 +17,7 @@
#define MMU_FTR_TYPE_40x ASM_CONST(0x00000004)
#define MMU_FTR_TYPE_44x ASM_CONST(0x00000008)
#define MMU_FTR_TYPE_FSL_E ASM_CONST(0x00000010)
+#define MMU_FTR_TYPE_3E ASM_CONST(0x00000020)
/*
* This is individual features
@@ -73,6 +74,41 @@ extern void early_init_mmu_secondary(void);
#endif /* !__ASSEMBLY__ */
+/* The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ *
+ * Note: This array ended up being a false good idea as it's growing to the
+ * point where I wonder if we should replace it with something different,
+ * to think about, feedback welcome. --BenH.
+ */
+
+/* There are #define as they have to be used in assembly
+ *
+ * WARNING: If you change this list, make sure to update the array of
+ * names currently in arch/powerpc/mm/hugetlbpage.c or bad things will
+ * happen
+ */
+#define MMU_PAGE_4K 0
+#define MMU_PAGE_16K 1
+#define MMU_PAGE_64K 2
+#define MMU_PAGE_64K_AP 3 /* "Admixed pages" (hash64 only) */
+#define MMU_PAGE_256K 4
+#define MMU_PAGE_1M 5
+#define MMU_PAGE_8M 6
+#define MMU_PAGE_16M 7
+#define MMU_PAGE_256M 8
+#define MMU_PAGE_1G 9
+#define MMU_PAGE_16G 10
+#define MMU_PAGE_64G 11
+#define MMU_PAGE_COUNT 12
+
#if defined(CONFIG_PPC_STD_MMU_64)
/* 64-bit classic hash table MMU */
@@ -94,5 +130,6 @@ extern void early_init_mmu_secondary(void);
# include <asm/mmu-8xx.h>
#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MMU_H_ */
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index b7063669f972..b34e94d94435 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -14,7 +14,6 @@
/*
* Most if the context management is out of line
*/
-extern void mmu_context_init(void);
extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
extern void destroy_context(struct mm_struct *mm);
@@ -23,6 +22,12 @@ extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm);
extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
extern void set_context(unsigned long id, pgd_t *pgd);
+#ifdef CONFIG_PPC_BOOK3S_64
+static inline void mmu_context_init(void) { }
+#else
+extern void mmu_context_init(void);
+#endif
+
/*
* switch_mm is the entry point called from the architecture independent
* code in kernel/sched.c
@@ -38,6 +43,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
tsk->thread.pgdir = next->pgd;
#endif /* CONFIG_PPC32 */
+ /* 64-bit Book3E keeps track of current PGD in the PACA */
+#ifdef CONFIG_PPC_BOOK3E_64
+ get_paca()->pgd = next->pgd;
+#endif
/* Nothing else to do if we aren't actually switching */
if (prev == next)
return;
@@ -84,6 +93,10 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
{
+ /* 64-bit Book3E keeps track of current PGD in the PACA */
+#ifdef CONFIG_PPC_BOOK3E_64
+ get_paca()->pgd = NULL;
+#endif
}
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index c8a3cbfe02ff..b634456ea893 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -14,9 +14,11 @@
#define _ASM_POWERPC_PACA_H
#ifdef __KERNEL__
-#include <asm/types.h>
-#include <asm/lppaca.h>
-#include <asm/mmu.h>
+#include <asm/types.h>
+#include <asm/lppaca.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/exception-64e.h>
register struct paca_struct *local_paca asm("r13");
@@ -91,6 +93,21 @@ struct paca_struct {
u16 slb_cache[SLB_CACHE_ENTRIES];
#endif /* CONFIG_PPC_STD_MMU_64 */
+#ifdef CONFIG_PPC_BOOK3E
+ pgd_t *pgd; /* Current PGD */
+ pgd_t *kernel_pgd; /* Kernel PGD */
+ u64 exgen[8] __attribute__((aligned(0x80)));
+ u64 extlb[EX_TLB_SIZE*3] __attribute__((aligned(0x80)));
+ u64 exmc[8]; /* used for machine checks */
+ u64 excrit[8]; /* used for crit interrupts */
+ u64 exdbg[8]; /* used for debug interrupts */
+
+ /* Kernel stack pointers for use by special exceptions */
+ void *mc_kstack;
+ void *crit_kstack;
+ void *dbg_kstack;
+#endif /* CONFIG_PPC_BOOK3E */
+
mm_context_t context;
/*
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 4940662ee87e..ff24254990e1 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -139,7 +139,11 @@ extern phys_addr_t kernstart_addr;
* Don't compare things with KERNELBASE or PAGE_OFFSET to test for
* "kernelness", use is_kernel_addr() - it should do what you want.
*/
+#ifdef CONFIG_PPC_BOOK3E_64
+#define is_kernel_addr(x) ((x) >= 0x8000000000000000ul)
+#else
#define is_kernel_addr(x) ((x) >= PAGE_OFFSET)
+#endif
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index 5817a3b747e5..3f17b83f55a1 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -135,12 +135,22 @@ extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
#endif /* __ASSEMBLY__ */
#else
#define slice_init()
+#ifdef CONFIG_PPC_STD_MMU_64
#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
#define slice_set_user_psize(mm, psize) \
do { \
(mm)->context.user_psize = (psize); \
(mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
} while (0)
+#else /* CONFIG_PPC_STD_MMU_64 */
+#ifdef CONFIG_PPC_64K_PAGES
+#define get_slice_psize(mm, addr) MMU_PAGE_64K
+#else /* CONFIG_PPC_64K_PAGES */
+#define get_slice_psize(mm, addr) MMU_PAGE_4K
+#endif /* !CONFIG_PPC_64K_PAGES */
+#define slice_set_user_psize(mm, psize) do { BUG(); } while(0)
+#endif /* !CONFIG_PPC_STD_MMU_64 */
+
#define slice_set_range_psize(mm, start, len, psize) \
slice_set_user_psize((mm), (psize))
#define slice_mm_new_context(mm) 1
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index d9483c504d2d..36057c821ff4 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -40,7 +40,6 @@ struct pci_dev;
*/
#define pcibios_assign_all_busses() \
(ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS))
-#define pcibios_scan_all_fns(a, b) 0
static inline void pcibios_set_master(struct pci_dev *dev)
{
diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h
index 0815eb40acae..c9500d666a1d 100644
--- a/arch/powerpc/include/asm/pgalloc-32.h
+++ b/arch/powerpc/include/asm/pgalloc-32.h
@@ -16,7 +16,7 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
*/
/* #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) */
#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb,x) do { } while (0)
+#define __pmd_free_tlb(tlb,x,a) do { } while (0)
/* #define pgd_populate(mm, pmd, pte) BUG() */
#ifndef CONFIG_BOOKE
diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
index afda2bdd860f..e6f069c4f713 100644
--- a/arch/powerpc/include/asm/pgalloc-64.h
+++ b/arch/powerpc/include/asm/pgalloc-64.h
@@ -118,11 +118,11 @@ static inline void pgtable_free(pgtable_free_t pgf)
kmem_cache_free(pgtable_cache[cachenum], p);
}
-#define __pmd_free_tlb(tlb, pmd) \
+#define __pmd_free_tlb(tlb, pmd,addr) \
pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
#ifndef CONFIG_PPC_64K_PAGES
-#define __pud_free_tlb(tlb, pud) \
+#define __pud_free_tlb(tlb, pud, addr) \
pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
#endif /* CONFIG_PPC_64K_PAGES */
diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h
index 5d8480265a77..34b080671f00 100644
--- a/arch/powerpc/include/asm/pgalloc.h
+++ b/arch/powerpc/include/asm/pgalloc.h
@@ -4,6 +4,15 @@
#include <linux/mm.h>
+#ifdef CONFIG_PPC_BOOK3E
+extern void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address);
+#else /* CONFIG_PPC_BOOK3E */
+static inline void tlb_flush_pgtable(struct mmu_gather *tlb,
+ unsigned long address)
+{
+}
+#endif /* !CONFIG_PPC_BOOK3E */
+
static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
@@ -35,19 +44,27 @@ static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
#include <asm/pgalloc-32.h>
#endif
-extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
-
#ifdef CONFIG_SMP
-#define __pte_free_tlb(tlb,ptepage) \
-do { \
- pgtable_page_dtor(ptepage); \
- pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
- PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
-} while (0)
-#else
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
-#endif
+extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+extern void pte_free_finish(void);
+#else /* CONFIG_SMP */
+static inline void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
+{
+ pgtable_free(pgf);
+}
+static inline void pte_free_finish(void) { }
+#endif /* !CONFIG_SMP */
+static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
+ unsigned long address)
+{
+ pgtable_free_t pgf = pgtable_free_cache(page_address(ptepage),
+ PTE_NONCACHE_NUM,
+ PTE_TABLE_SIZE-1);
+ tlb_flush_pgtable(tlb, address);
+ pgtable_page_dtor(ptepage);
+ pgtable_free_tlb(tlb, pgf);
+}
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64-64k.h b/arch/powerpc/include/asm/pgtable-ppc64-64k.h
index 6cc085b945a5..90533ddcd703 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64-64k.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64-64k.h
@@ -10,10 +10,10 @@
#define PGD_INDEX_SIZE 4
#ifndef __ASSEMBLY__
-
#define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE)
#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
+#endif /* __ASSEMBLY__ */
#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)
#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)
@@ -32,8 +32,6 @@
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
-#endif /* __ASSEMBLY__ */
-
/* Bits to mask out from a PMD to get to the PTE page */
#define PMD_MASKED_BITS 0x1ff
/* Bits to mask out from a PGD/PUD to get to the PMD page */
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 8cd083c61503..200ec2dfa034 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -5,11 +5,6 @@
* the ppc64 hashed page table.
*/
-#ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <asm/tlbflush.h>
-#endif /* __ASSEMBLY__ */
-
#ifdef CONFIG_PPC_64K_PAGES
#include <asm/pgtable-ppc64-64k.h>
#else
@@ -38,26 +33,47 @@
#endif
/*
- * Define the address range of the vmalloc VM area.
+ * Define the address range of the kernel non-linear virtual area
+ */
+
+#ifdef CONFIG_PPC_BOOK3E
+#define KERN_VIRT_START ASM_CONST(0x8000000000000000)
+#else
+#define KERN_VIRT_START ASM_CONST(0xD000000000000000)
+#endif
+#define KERN_VIRT_SIZE PGTABLE_RANGE
+
+/*
+ * The vmalloc space starts at the beginning of that region, and
+ * occupies half of it on hash CPUs and a quarter of it on Book3E
+ * (we keep a quarter for the virtual memmap)
*/
-#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
-#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
+#define VMALLOC_START KERN_VIRT_START
+#ifdef CONFIG_PPC_BOOK3E
+#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 2)
+#else
+#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
+#endif
+#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
/*
- * Define the address ranges for MMIO and IO space :
+ * The second half of the kernel virtual space is used for IO mappings,
+ * it's itself carved into the PIO region (ISA and PHB IO space) and
+ * the ioremap space
*
- * ISA_IO_BASE = VMALLOC_END, 64K reserved area
+ * ISA_IO_BASE = KERN_IO_START, 64K reserved area
* PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
* IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
*/
+#define KERN_IO_START (KERN_VIRT_START + (KERN_VIRT_SIZE >> 1))
#define FULL_IO_SIZE 0x80000000ul
-#define ISA_IO_BASE (VMALLOC_END)
-#define ISA_IO_END (VMALLOC_END + 0x10000ul)
+#define ISA_IO_BASE (KERN_IO_START)
+#define ISA_IO_END (KERN_IO_START + 0x10000ul)
#define PHB_IO_BASE (ISA_IO_END)
-#define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE)
+#define PHB_IO_END (KERN_IO_START + FULL_IO_SIZE)
#define IOREMAP_BASE (PHB_IO_END)
-#define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE)
+#define IOREMAP_END (KERN_VIRT_START + KERN_VIRT_SIZE)
+
/*
* Region IDs
@@ -68,23 +84,32 @@
#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
-#define VMEMMAP_REGION_ID (0xfUL)
+#define VMEMMAP_REGION_ID (0xfUL) /* Server only */
#define USER_REGION_ID (0UL)
/*
- * Defines the address of the vmemap area, in its own region
+ * Defines the address of the vmemap area, in its own region on
+ * hash table CPUs and after the vmalloc space on Book3E
*/
+#ifdef CONFIG_PPC_BOOK3E
+#define VMEMMAP_BASE VMALLOC_END
+#define VMEMMAP_END KERN_IO_START
+#else
#define VMEMMAP_BASE (VMEMMAP_REGION_ID << REGION_SHIFT)
+#endif
#define vmemmap ((struct page *)VMEMMAP_BASE)
/*
* Include the PTE bits definitions
*/
+#ifdef CONFIG_PPC_BOOK3S
#include <asm/pte-hash64.h>
+#else
+#include <asm/pte-book3e.h>
+#endif
#include <asm/pte-common.h>
-
#ifdef CONFIG_PPC_MM_SLICES
#define HAVE_ARCH_UNMAPPED_AREA
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
@@ -92,6 +117,9 @@
#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <asm/tlbflush.h>
+
/*
* This is the default implementation of various PTE accessors, it's
* used in all cases except Book3S with 64K pages where we have a
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index b74f16d45cb4..ef9aa84cac5a 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -48,6 +48,8 @@
#define PPC_INST_TLBIE 0x7c000264
#define PPC_INST_TLBILX 0x7c000024
#define PPC_INST_WAIT 0x7c00007c
+#define PPC_INST_TLBIVAX 0x7c000624
+#define PPC_INST_TLBSRX_DOT 0x7c0006a5
/* macros to insert fields into opcodes */
#define __PPC_RA(a) (((a) & 0x1f) << 16)
@@ -76,6 +78,10 @@
__PPC_WC(w))
#define PPC_TLBIE(lp,a) stringify_in_c(.long PPC_INST_TLBIE | \
__PPC_RB(a) | __PPC_RS(lp))
+#define PPC_TLBSRX_DOT(a,b) stringify_in_c(.long PPC_INST_TLBSRX_DOT | \
+ __PPC_RA(a) | __PPC_RB(b))
+#define PPC_TLBIVAX(a,b) stringify_in_c(.long PPC_INST_TLBIVAX | \
+ __PPC_RA(a) | __PPC_RB(b))
/*
* Define what the VSX XX1 form instructions will look like, then add
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index f9729529c20d..dfae6e916dfb 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -375,8 +375,15 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
#define PPC440EP_ERR42
#endif
-
-#if defined(CONFIG_BOOKE)
+/*
+ * toreal/fromreal/tophys/tovirt macros. 32-bit BookE makes them
+ * keep the address intact to be compatible with code shared with
+ * 32-bit classic.
+ *
+ * On the other hand, I find it useful to have them behave as expected
+ * by their name (ie always do the addition) on 64-bit BookE
+ */
+#if defined(CONFIG_BOOKE) && !defined(CONFIG_PPC64)
#define toreal(rd)
#define fromreal(rd)
@@ -426,10 +433,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
.previous
#endif
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
#define RFI rfid
#define MTMSRD(r) mtmsrd r
-
#else
#define FIX_SRR1(ra, rb)
#ifndef CONFIG_40x
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
new file mode 100644
index 000000000000..1d27c77d7704
--- /dev/null
+++ b/arch/powerpc/include/asm/pte-book3e.h
@@ -0,0 +1,70 @@
+#ifndef _ASM_POWERPC_PTE_BOOK3E_H
+#define _ASM_POWERPC_PTE_BOOK3E_H
+#ifdef __KERNEL__
+
+/* PTE bit definitions for processors compliant to the Book3E
+ * architecture 2.06 or later. The position of the PTE bits
+ * matches the HW definition of the optional Embedded Page Table
+ * category.
+ */
+
+/* Architected bits */
+#define _PAGE_PRESENT 0x000001 /* software: pte contains a translation */
+#define _PAGE_FILE 0x000002 /* (!present only) software: pte holds file offset */
+#define _PAGE_SW1 0x000002
+#define _PAGE_BAP_SR 0x000004
+#define _PAGE_BAP_UR 0x000008
+#define _PAGE_BAP_SW 0x000010
+#define _PAGE_BAP_UW 0x000020
+#define _PAGE_BAP_SX 0x000040
+#define _PAGE_BAP_UX 0x000080
+#define _PAGE_PSIZE_MSK 0x000f00
+#define _PAGE_PSIZE_4K 0x000200
+#define _PAGE_PSIZE_64K 0x000600
+#define _PAGE_PSIZE_1M 0x000a00
+#define _PAGE_PSIZE_16M 0x000e00
+#define _PAGE_DIRTY 0x001000 /* C: page changed */
+#define _PAGE_SW0 0x002000
+#define _PAGE_U3 0x004000
+#define _PAGE_U2 0x008000
+#define _PAGE_U1 0x010000
+#define _PAGE_U0 0x020000
+#define _PAGE_ACCESSED 0x040000
+#define _PAGE_LENDIAN 0x080000
+#define _PAGE_GUARDED 0x100000
+#define _PAGE_COHERENT 0x200000 /* M: enforce memory coherence */
+#define _PAGE_NO_CACHE 0x400000 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */
+
+/* "Higher level" linux bit combinations */
+#define _PAGE_EXEC _PAGE_BAP_SX /* Can be executed from potentially */
+#define _PAGE_HWEXEC _PAGE_BAP_UX /* .. and was cache cleaned */
+#define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
+#define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
+#define _PAGE_KERNEL_RO (_PAGE_BAP_SR)
+#define _PAGE_USER (_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
+
+#define _PAGE_HASHPTE 0
+#define _PAGE_BUSY 0
+
+#define _PAGE_SPECIAL _PAGE_SW0
+
+/* Flags to be preserved on PTE modifications */
+#define _PAGE_HPTEFLAGS _PAGE_BUSY
+
+/* Base page size */
+#ifdef CONFIG_PPC_64K_PAGES
+#define _PAGE_PSIZE _PAGE_PSIZE_64K
+#define PTE_RPN_SHIFT (28)
+#else
+#define _PAGE_PSIZE _PAGE_PSIZE_4K
+#define PTE_RPN_SHIFT (24)
+#endif
+
+/* On 32-bit, we never clear the top part of the PTE */
+#ifdef CONFIG_PPC32
+#define _PTE_NONE_MASK 0xffffffff00000000ULL
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_PTE_FSL_BOOKE_H */
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
index a7e210b6b48c..8bb6464ba619 100644
--- a/arch/powerpc/include/asm/pte-common.h
+++ b/arch/powerpc/include/asm/pte-common.h
@@ -34,6 +34,9 @@
#ifndef _PAGE_4K_PFN
#define _PAGE_4K_PFN 0
#endif
+#ifndef _PAGE_SAO
+#define _PAGE_SAO 0
+#endif
#ifndef _PAGE_PSIZE
#define _PAGE_PSIZE 0
#endif
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 1170267736d3..6315edc205d8 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -98,19 +98,15 @@
#define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */
#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC_BOOK3S_64)
+/* Server variant */
#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV
#define MSR_KERNEL MSR_ | MSR_SF
-
#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
#define MSR_USER64 MSR_USER32 | MSR_SF
-
-#else /* 32-bit */
+#elif defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_8xx)
/* Default MSR for kernel mode. */
-#ifndef MSR_KERNEL /* reg_booke.h also defines this */
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR)
-#endif
-
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
#endif
@@ -646,6 +642,137 @@
#endif
/*
+ * SPRG usage:
+ *
+ * All 64-bit:
+ * - SPRG1 stores PACA pointer
+ *
+ * 64-bit server:
+ * - SPRG0 unused (reserved for HV on Power4)
+ * - SPRG2 scratch for exception vectors
+ * - SPRG3 unused (user visible)
+ *
+ * 64-bit embedded
+ * - SPRG0 generic exception scratch
+ * - SPRG2 TLB exception stack
+ * - SPRG3 unused (user visible)
+ * - SPRG4 unused (user visible)
+ * - SPRG6 TLB miss scratch (user visible, sorry !)
+ * - SPRG7 critical exception scratch
+ * - SPRG8 machine check exception scratch
+ * - SPRG9 debug exception scratch
+ *
+ * All 32-bit:
+ * - SPRG3 current thread_info pointer
+ * (virtual on BookE, physical on others)
+ *
+ * 32-bit classic:
+ * - SPRG0 scratch for exception vectors
+ * - SPRG1 scratch for exception vectors
+ * - SPRG2 indicator that we are in RTAS
+ * - SPRG4 (603 only) pseudo TLB LRU data
+ *
+ * 32-bit 40x:
+ * - SPRG0 scratch for exception vectors
+ * - SPRG1 scratch for exception vectors
+ * - SPRG2 scratch for exception vectors
+ * - SPRG4 scratch for exception vectors (not 403)
+ * - SPRG5 scratch for exception vectors (not 403)
+ * - SPRG6 scratch for exception vectors (not 403)
+ * - SPRG7 scratch for exception vectors (not 403)
+ *
+ * 32-bit 440 and FSL BookE:
+ * - SPRG0 scratch for exception vectors
+ * - SPRG1 scratch for exception vectors (*)
+ * - SPRG2 scratch for crit interrupts handler
+ * - SPRG4 scratch for exception vectors
+ * - SPRG5 scratch for exception vectors
+ * - SPRG6 scratch for machine check handler
+ * - SPRG7 scratch for exception vectors
+ * - SPRG9 scratch for debug vectors (e500 only)
+ *
+ * Additionally, BookE separates "read" and "write"
+ * of those registers. That allows to use the userspace
+ * readable variant for reads, which can avoid a fault
+ * with KVM type virtualization.
+ *
+ * (*) Under KVM, the host SPRG1 is used to point to
+ * the current VCPU data structure
+ *
+ * 32-bit 8xx:
+ * - SPRG0 scratch for exception vectors
+ * - SPRG1 scratch for exception vectors
+ * - SPRG2 apparently unused but initialized
+ *
+ */
+#ifdef CONFIG_PPC64
+#define SPRN_SPRG_PACA SPRN_SPRG1
+#else
+#define SPRN_SPRG_THREAD SPRN_SPRG3
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_64
+#define SPRN_SPRG_SCRATCH0 SPRN_SPRG2
+#endif
+
+#ifdef CONFIG_PPC_BOOK3E_64
+#define SPRN_SPRG_MC_SCRATCH SPRN_SPRG8
+#define SPRN_SPRG_CRIT_SCRATCH SPRN_SPRG7
+#define SPRN_SPRG_DBG_SCRATCH SPRN_SPRG9
+#define SPRN_SPRG_TLB_EXFRAME SPRN_SPRG2
+#define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6
+#define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+#define SPRN_SPRG_SCRATCH0 SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1 SPRN_SPRG1
+#define SPRN_SPRG_RTAS SPRN_SPRG2
+#define SPRN_SPRG_603_LRU SPRN_SPRG4
+#endif
+
+#ifdef CONFIG_40x
+#define SPRN_SPRG_SCRATCH0 SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1 SPRN_SPRG1
+#define SPRN_SPRG_SCRATCH2 SPRN_SPRG2
+#define SPRN_SPRG_SCRATCH3 SPRN_SPRG4
+#define SPRN_SPRG_SCRATCH4 SPRN_SPRG5
+#define SPRN_SPRG_SCRATCH5 SPRN_SPRG6
+#define SPRN_SPRG_SCRATCH6 SPRN_SPRG7
+#endif
+
+#ifdef CONFIG_BOOKE
+#define SPRN_SPRG_RSCRATCH0 SPRN_SPRG0
+#define SPRN_SPRG_WSCRATCH0 SPRN_SPRG0
+#define SPRN_SPRG_RSCRATCH1 SPRN_SPRG1
+#define SPRN_SPRG_WSCRATCH1 SPRN_SPRG1
+#define SPRN_SPRG_RSCRATCH_CRIT SPRN_SPRG2
+#define SPRN_SPRG_WSCRATCH_CRIT SPRN_SPRG2
+#define SPRN_SPRG_RSCRATCH2 SPRN_SPRG4R
+#define SPRN_SPRG_WSCRATCH2 SPRN_SPRG4W
+#define SPRN_SPRG_RSCRATCH3 SPRN_SPRG5R
+#define SPRN_SPRG_WSCRATCH3 SPRN_SPRG5W
+#define SPRN_SPRG_RSCRATCH_MC SPRN_SPRG6R
+#define SPRN_SPRG_WSCRATCH_MC SPRN_SPRG6W
+#define SPRN_SPRG_RSCRATCH4 SPRN_SPRG7R
+#define SPRN_SPRG_WSCRATCH4 SPRN_SPRG7W
+#ifdef CONFIG_E200
+#define SPRN_SPRG_RSCRATCH_DBG SPRN_SPRG6R
+#define SPRN_SPRG_WSCRATCH_DBG SPRN_SPRG6W
+#else
+#define SPRN_SPRG_RSCRATCH_DBG SPRN_SPRG9
+#define SPRN_SPRG_WSCRATCH_DBG SPRN_SPRG9
+#endif
+#define SPRN_SPRG_RVCPU SPRN_SPRG1
+#define SPRN_SPRG_WVCPU SPRN_SPRG1
+#endif
+
+#ifdef CONFIG_8xx
+#define SPRN_SPRG_SCRATCH0 SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1 SPRN_SPRG1
+#endif
+
+/*
* An mtfsf instruction with the L bit set. On CPUs that support this a
* full 64bits of FPSCR is restored and on other CPUs the L bit is ignored.
*
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 6bcf364cbb2f..2c9c706e6448 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -18,18 +18,26 @@
#define MSR_IS MSR_IR /* Instruction Space */
#define MSR_DS MSR_DR /* Data Space */
#define MSR_PMM (1<<2) /* Performance monitor mark bit */
+#define MSR_CM (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */
-/* Default MSR for kernel mode. */
-#if defined (CONFIG_40x)
+#if defined(CONFIG_PPC_BOOK3E_64)
+#define MSR_ MSR_ME | MSR_CE
+#define MSR_KERNEL MSR_ | MSR_CM
+#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
+#define MSR_USER64 MSR_USER32 | MSR_CM
+#elif defined (CONFIG_40x)
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
-#elif defined(CONFIG_BOOKE)
+#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
+#else
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE)
+#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
#endif
/* Special Purpose Registers (SPRNs)*/
#define SPRN_DECAR 0x036 /* Decrementer Auto Reload Register */
#define SPRN_IVPR 0x03F /* Interrupt Vector Prefix Register */
#define SPRN_USPRG0 0x100 /* User Special Purpose Register General 0 */
+#define SPRN_SPRG3R 0x103 /* Special Purpose Register General 3 Read */
#define SPRN_SPRG4R 0x104 /* Special Purpose Register General 4 Read */
#define SPRN_SPRG5R 0x105 /* Special Purpose Register General 5 Read */
#define SPRN_SPRG6R 0x106 /* Special Purpose Register General 6 Read */
@@ -38,11 +46,18 @@
#define SPRN_SPRG5W 0x115 /* Special Purpose Register General 5 Write */
#define SPRN_SPRG6W 0x116 /* Special Purpose Register General 6 Write */
#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */
+#define SPRN_EPCR 0x133 /* Embedded Processor Control Register */
#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */
#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */
#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */
#define SPRN_DVC1 0x13E /* Data Value Compare Register 1 */
#define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */
+#define SPRN_MAS8 0x155 /* MMU Assist Register 8 */
+#define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */
+#define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */
+#define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */
+#define SPRN_MAS7_MAS3 0x174 /* MMU Assist Register 7 || 3 */
+#define SPRN_MAS0_MAS1 0x175 /* MMU Assist Register 0 || 1 */
#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */
#define SPRN_IVOR1 0x191 /* Interrupt Vector Offset Register 1 */
#define SPRN_IVOR2 0x192 /* Interrupt Vector Offset Register 2 */
@@ -425,6 +440,27 @@
#define SGR_NORMAL 0 /* Speculative fetching allowed. */
#define SGR_GUARDED 1 /* Speculative fetching disallowed. */
+/* Bit definitions for EPCR */
+#define SPRN_EPCR_EXTGS 0x80000000 /* External Input interrupt
+ * directed to Guest state */
+#define SPRN_EPCR_DTLBGS 0x40000000 /* Data TLB Error interrupt
+ * directed to guest state */
+#define SPRN_EPCR_ITLBGS 0x20000000 /* Instr. TLB error interrupt
+ * directed to guest state */
+#define SPRN_EPCR_DSIGS 0x10000000 /* Data Storage interrupt
+ * directed to guest state */
+#define SPRN_EPCR_ISIGS 0x08000000 /* Instr. Storage interrupt
+ * directed to guest state */
+#define SPRN_EPCR_DUVD 0x04000000 /* Disable Hypervisor Debug */
+#define SPRN_EPCR_ICM 0x02000000 /* Interrupt computation mode
+ * (copied to MSR:CM on intr) */
+#define SPRN_EPCR_GICM 0x01000000 /* Guest Interrupt Comp. mode */
+#define SPRN_EPCR_DGTMI 0x00800000 /* Disable TLB Guest Management
+ * instructions */
+#define SPRN_EPCR_DMIUH 0x00400000 /* Disable MAS Interrupt updates
+ * for hypervisor */
+
+
/*
* The IBM-403 is an even more odd special case, as it is much
* older than the IBM-405 series. We put these down here incase someone
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index c25f73d1d842..d9ea8d39c342 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -146,7 +146,17 @@ extern void smp_generic_take_timebase(void);
extern struct smp_ops_t *smp_ops;
extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+/* Definitions relative to the secondary CPU spin loop
+ * and entry point. Not all of them exist on both 32 and
+ * 64-bit but defining them all here doesn't harm
+ */
+extern void generic_secondary_smp_init(void);
+extern void generic_secondary_thread_init(void);
+extern unsigned long __secondary_hold_spinloop;
+extern unsigned long __secondary_hold_acknowledge;
+extern char __secondary_hold;
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index 370600ca2765..ed24bd92fe49 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -95,8 +95,8 @@ SYSCALL(reboot)
SYSX(sys_ni_syscall,compat_sys_old_readdir,sys_old_readdir)
SYSCALL_SPU(mmap)
SYSCALL_SPU(munmap)
-SYSCALL_SPU(truncate)
-SYSCALL_SPU(ftruncate)
+COMPAT_SYS_SPU(truncate)
+COMPAT_SYS_SPU(ftruncate)
SYSCALL_SPU(fchmod)
SYSCALL_SPU(fchown)
COMPAT_SYS_SPU(getpriority)
diff --git a/arch/powerpc/include/asm/tlb.h b/arch/powerpc/include/asm/tlb.h
index e20ff7541f36..5db99107883a 100644
--- a/arch/powerpc/include/asm/tlb.h
+++ b/arch/powerpc/include/asm/tlb.h
@@ -25,57 +25,25 @@
#include <linux/pagemap.h>
-struct mmu_gather;
-
#define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0)
-#if !defined(CONFIG_PPC_STD_MMU)
-
-#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
-
-#elif defined(__powerpc64__)
-
-extern void pte_free_finish(void);
-
-static inline void tlb_flush(struct mmu_gather *tlb)
-{
- struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
-
- /* If there's a TLB batch pending, then we must flush it because the
- * pages are going to be freed and we really don't want to have a CPU
- * access a freed page because it has a stale TLB
- */
- if (tlbbatch->index)
- __flush_tlb_pending(tlbbatch);
-
- pte_free_finish();
-}
-
-#else
-
extern void tlb_flush(struct mmu_gather *tlb);
-#endif
-
/* Get the generic bits... */
#include <asm-generic/tlb.h>
-#if !defined(CONFIG_PPC_STD_MMU) || defined(__powerpc64__)
-
-#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
-
-#else
extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
unsigned long address);
static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
- unsigned long address)
+ unsigned long address)
{
+#ifdef PPC_STD_MMU_32
if (pte_val(*ptep) & _PAGE_HASHPTE)
flush_hash_entry(tlb->mm, ptep, address);
+#endif
}
-#endif
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_TLB_H */
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index abbe3419d1dd..d50a380b2b6f 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -6,7 +6,7 @@
*
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
- * - local_flush_tlb_mm(mm) flushes the specified mm context on
+ * - local_flush_tlb_mm(mm, full) flushes the specified mm context on
* the local processor
* - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor
* - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB
@@ -29,7 +29,8 @@
* specific tlbie's
*/
-#include <linux/mm.h>
+struct vm_area_struct;
+struct mm_struct;
#define MMU_NO_CONTEXT ((unsigned int)-1)
@@ -40,12 +41,18 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
extern void local_flush_tlb_mm(struct mm_struct *mm);
extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void __local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+ int tsize, int ind);
+
#ifdef CONFIG_SMP
extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+ int tsize, int ind);
#else
#define flush_tlb_mm(mm) local_flush_tlb_mm(mm)
#define flush_tlb_page(vma,addr) local_flush_tlb_page(vma,addr)
+#define __flush_tlb_page(mm,addr,p,i) __local_flush_tlb_page(mm,addr,p,i)
#endif
#define flush_tlb_page_nohash(vma,addr) flush_tlb_page(vma,addr)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 054a16d68082..0b3a0183df3a 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -17,11 +17,6 @@ static inline int cpu_to_node(int cpu)
#define parent_node(node) (node)
-static inline cpumask_t node_to_cpumask(int node)
-{
- return numa_cpumask_lookup_table[node];
-}
-
#define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
int of_node_to_nid(struct device_node *device);
@@ -36,11 +31,6 @@ static inline int pcibus_to_node(struct pci_bus *bus)
}
#endif
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
- CPU_MASK_ALL : \
- node_to_cpumask(pcibus_to_node(bus)) \
- )
-
#define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \
cpu_all_mask : \
cpumask_of_node(pcibus_to_node(bus)))
@@ -105,8 +95,6 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev,
#ifdef CONFIG_PPC64
#include <asm/smp.h>
-#define topology_thread_siblings(cpu) (per_cpu(cpu_sibling_map, cpu))
-#define topology_core_siblings(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
#define topology_core_cpumask(cpu) (&per_cpu(cpu_core_map, cpu))
#define topology_core_id(cpu) (cpu_to_core_id(cpu))
diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h
index 26fc449bd989..dc0419b66f17 100644
--- a/arch/powerpc/include/asm/vdso.h
+++ b/arch/powerpc/include/asm/vdso.h
@@ -7,9 +7,8 @@
#define VDSO32_LBASE 0x100000
#define VDSO64_LBASE 0x100000
-/* Default map addresses */
+/* Default map addresses for 32bit vDSO */
#define VDSO32_MBASE VDSO32_LBASE
-#define VDSO64_MBASE VDSO64_LBASE
#define VDSO_VERSION_STRING LINUX_2.6.15
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index b73396b93905..035946f9d5fb 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -33,10 +33,10 @@ obj-y := cputable.o ptrace.o syscalls.o \
obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
- paca.o cpu_setup_ppc970.o \
- cpu_setup_pa6t.o \
- firmware.o nvram_64.o
+ paca.o nvram_64.o firmware.o
+obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
+obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
@@ -63,8 +63,8 @@ obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o
-extra-$(CONFIG_PPC_STD_MMU) := head_32.o
-extra-$(CONFIG_PPC64) := head_64.o
+extra-y := head_$(CONFIG_WORD_SIZE).o
+extra-$(CONFIG_PPC_BOOK3E_32) := head_new_booke.o
extra-$(CONFIG_40x) := head_40x.o
extra-$(CONFIG_44x) := head_44x.o
extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 561b64652311..b9e010d0fc91 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -52,9 +52,11 @@
#include <linux/kvm_host.h>
#endif
+#ifdef CONFIG_PPC32
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
#include "head_booke.h"
#endif
+#endif
#if defined(CONFIG_FSL_BOOKE)
#include "../mm/mmu_decl.h"
@@ -138,6 +140,20 @@ int main(void)
context.high_slices_psize));
DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_PPC_BOOK3E
+ DEFINE(PACAPGD, offsetof(struct paca_struct, pgd));
+ DEFINE(PACA_KERNELPGD, offsetof(struct paca_struct, kernel_pgd));
+ DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
+ DEFINE(PACA_EXTLB, offsetof(struct paca_struct, extlb));
+ DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
+ DEFINE(PACA_EXCRIT, offsetof(struct paca_struct, excrit));
+ DEFINE(PACA_EXDBG, offsetof(struct paca_struct, exdbg));
+ DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack));
+ DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack));
+ DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack));
+#endif /* CONFIG_PPC_BOOK3E */
+
#ifdef CONFIG_PPC_STD_MMU_64
DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real));
DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr));
@@ -260,6 +276,7 @@ int main(void)
DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
#endif /* CONFIG_PPC64 */
+#if defined(CONFIG_PPC32)
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
DEFINE(EXC_LVL_SIZE, STACK_EXC_LVL_FRAME_SIZE);
DEFINE(MAS0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0));
@@ -278,7 +295,7 @@ int main(void)
DEFINE(_DSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr1));
DEFINE(SAVED_KSP_LIMIT, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, saved_ksp_limit));
#endif
-
+#endif
DEFINE(CLONE_VM, CLONE_VM);
DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
index 1e9949e68856..55cba4a8a959 100644
--- a/arch/powerpc/kernel/cpu_setup_6xx.S
+++ b/arch/powerpc/kernel/cpu_setup_6xx.S
@@ -21,7 +21,7 @@ _GLOBAL(__setup_cpu_603)
mflr r4
BEGIN_MMU_FTR_SECTION
li r10,0
- mtspr SPRN_SPRG4,r10 /* init SW LRU tracking */
+ mtspr SPRN_SPRG_603_LRU,r10 /* init SW LRU tracking */
END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
BEGIN_FTR_SECTION
bl __init_fpu_registers
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 4a24a2fc4574..9f38ecb17859 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -93,7 +93,7 @@ extern void __restore_cpu_power7(void);
PPC_FEATURE_BOOKE)
static struct cpu_spec __initdata cpu_specs[] = {
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
{ /* Power3 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00400000,
@@ -508,7 +508,30 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_generic,
.platform = "power4",
}
-#endif /* CONFIG_PPC64 */
+#endif /* CONFIG_PPC_BOOK3S_64 */
+#ifdef CONFIG_PPC_BOOK3E_64
+ { /* This is a default entry to get going, to be replaced by
+ * a real one at some stage
+ */
+#define CPU_FTRS_BASE_BOOK3E (CPU_FTR_USE_TB | \
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_SMT | \
+ CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+ .pvr_mask = 0x00000000,
+ .pvr_value = 0x00000000,
+ .cpu_name = "Book3E",
+ .cpu_features = CPU_FTRS_BASE_BOOK3E,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .mmu_features = MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX |
+ MMU_FTR_USE_TLBIVAX_BCAST |
+ MMU_FTR_LOCK_BCAST_INVAL,
+ .icache_bsize = 64,
+ .dcache_bsize = 64,
+ .num_pmcs = 0,
+ .machine_check = machine_check_generic,
+ .platform = "power6",
+ },
+#endif
+
#ifdef CONFIG_PPC32
#if CLASSIC_PPC
{ /* 601 */
@@ -1630,7 +1653,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.platform = "ppc440",
},
{ /* 460EX */
- .pvr_mask = 0xffff0002,
+ .pvr_mask = 0xffff0006,
.pvr_value = 0x13020002,
.cpu_name = "460EX",
.cpu_features = CPU_FTRS_440x6,
@@ -1642,8 +1665,21 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_440A,
.platform = "ppc440",
},
+ { /* 460EX Rev B */
+ .pvr_mask = 0xffff0007,
+ .pvr_value = 0x13020004,
+ .cpu_name = "460EX Rev. B",
+ .cpu_features = CPU_FTRS_440x6,
+ .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+ .mmu_features = MMU_FTR_TYPE_44x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .cpu_setup = __setup_cpu_460ex,
+ .machine_check = machine_check_440A,
+ .platform = "ppc440",
+ },
{ /* 460GT */
- .pvr_mask = 0xffff0002,
+ .pvr_mask = 0xffff0006,
.pvr_value = 0x13020000,
.cpu_name = "460GT",
.cpu_features = CPU_FTRS_440x6,
@@ -1655,6 +1691,19 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_440A,
.platform = "ppc440",
},
+ { /* 460GT Rev B */
+ .pvr_mask = 0xffff0007,
+ .pvr_value = 0x13020005,
+ .cpu_name = "460GT Rev. B",
+ .cpu_features = CPU_FTRS_440x6,
+ .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+ .mmu_features = MMU_FTR_TYPE_44x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .cpu_setup = __setup_cpu_460gt,
+ .machine_check = machine_check_440A,
+ .platform = "ppc440",
+ },
{ /* 460SX */
.pvr_mask = 0xffffff00,
.pvr_value = 0x13541800,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 3cadba60a4b6..1175a8539e6c 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -88,7 +88,7 @@ crit_transfer_to_handler:
mfspr r0,SPRN_SRR1
stw r0,_SRR1(r11)
- mfspr r8,SPRN_SPRG3
+ mfspr r8,SPRN_SPRG_THREAD
lwz r0,KSP_LIMIT(r8)
stw r0,SAVED_KSP_LIMIT(r11)
rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
@@ -108,7 +108,7 @@ crit_transfer_to_handler:
mfspr r0,SPRN_SRR1
stw r0,crit_srr1@l(0)
- mfspr r8,SPRN_SPRG3
+ mfspr r8,SPRN_SPRG_THREAD
lwz r0,KSP_LIMIT(r8)
stw r0,saved_ksp_limit@l(0)
rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
@@ -138,7 +138,7 @@ transfer_to_handler:
mfspr r2,SPRN_XER
stw r12,_CTR(r11)
stw r2,_XER(r11)
- mfspr r12,SPRN_SPRG3
+ mfspr r12,SPRN_SPRG_THREAD
addi r2,r12,-THREAD
tovirt(r2,r2) /* set r2 to current */
beq 2f /* if from user, fix up THREAD.regs */
@@ -680,7 +680,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPE)
tophys(r0,r4)
CLR_TOP32(r0)
- mtspr SPRN_SPRG3,r0 /* Update current THREAD phys addr */
+ mtspr SPRN_SPRG_THREAD,r0 /* Update current THREAD phys addr */
lwz r1,KSP(r4) /* Load new stack pointer */
/* save the old current 'last' for return value */
@@ -1057,7 +1057,7 @@ exc_exit_restart_end:
#ifdef CONFIG_40x
.globl ret_from_crit_exc
ret_from_crit_exc:
- mfspr r9,SPRN_SPRG3
+ mfspr r9,SPRN_SPRG_THREAD
lis r10,saved_ksp_limit@ha;
lwz r10,saved_ksp_limit@l(r10);
tovirt(r9,r9);
@@ -1074,7 +1074,7 @@ ret_from_crit_exc:
#ifdef CONFIG_BOOKE
.globl ret_from_crit_exc
ret_from_crit_exc:
- mfspr r9,SPRN_SPRG3
+ mfspr r9,SPRN_SPRG_THREAD
lwz r10,SAVED_KSP_LIMIT(r1)
stw r10,KSP_LIMIT(r9)
RESTORE_xSRR(SRR0,SRR1);
@@ -1083,7 +1083,7 @@ ret_from_crit_exc:
.globl ret_from_debug_exc
ret_from_debug_exc:
- mfspr r9,SPRN_SPRG3
+ mfspr r9,SPRN_SPRG_THREAD
lwz r10,SAVED_KSP_LIMIT(r1)
stw r10,KSP_LIMIT(r9)
lwz r9,THREAD_INFO-THREAD(r9)
@@ -1097,7 +1097,7 @@ ret_from_debug_exc:
.globl ret_from_mcheck_exc
ret_from_mcheck_exc:
- mfspr r9,SPRN_SPRG3
+ mfspr r9,SPRN_SPRG_THREAD
lwz r10,SAVED_KSP_LIMIT(r1)
stw r10,KSP_LIMIT(r9)
RESTORE_xSRR(SRR0,SRR1);
@@ -1255,7 +1255,7 @@ _GLOBAL(enter_rtas)
MTMSRD(r0) /* don't get trashed */
li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
mtlr r6
- mtspr SPRN_SPRG2,r7
+ mtspr SPRN_SPRG_RTAS,r7
mtspr SPRN_SRR0,r8
mtspr SPRN_SRR1,r9
RFI
@@ -1265,7 +1265,7 @@ _GLOBAL(enter_rtas)
FIX_SRR1(r9,r0)
addi r1,r1,INT_FRAME_SIZE
li r0,0
- mtspr SPRN_SPRG2,r0
+ mtspr SPRN_SPRG_RTAS,r0
mtspr SPRN_SRR0,r8
mtspr SPRN_SRR1,r9
RFI /* return to caller */
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 43e073477c34..66bcda34a6bb 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -120,9 +120,15 @@ BEGIN_FW_FTR_SECTION
2:
END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif /* CONFIG_PPC_ISERIES */
+
+ /* Hard enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 1
+#else
mfmsr r11
ori r11,r11,MSR_EE
mtmsrd r11,1
+#endif /* CONFIG_PPC_BOOK3E */
#ifdef SHOW_SYSCALLS
bl .do_show_syscall
@@ -168,15 +174,25 @@ syscall_exit:
#endif
clrrdi r12,r1,THREAD_SHIFT
- /* disable interrupts so current_thread_info()->flags can't change,
- and so that we don't get interrupted after loading SRR0/1. */
ld r8,_MSR(r1)
+#ifdef CONFIG_PPC_BOOK3S
+ /* No MSR:RI on BookE */
andi. r10,r8,MSR_RI
beq- unrecov_restore
+#endif
+
+ /* Disable interrupts so current_thread_info()->flags can't change,
+ * and so that we don't get interrupted after loading SRR0/1.
+ */
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 0
+#else
mfmsr r10
rldicl r10,r10,48,1
rotldi r10,r10,16
mtmsrd r10,1
+#endif /* CONFIG_PPC_BOOK3E */
+
ld r9,TI_FLAGS(r12)
li r11,-_LAST_ERRNO
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
@@ -194,9 +210,13 @@ syscall_error_cont:
* userspace and we take an exception after restoring r13,
* we end up corrupting the userspace r13 value.
*/
+#ifdef CONFIG_PPC_BOOK3S
+ /* No MSR:RI on BookE */
li r12,MSR_RI
andc r11,r10,r12
mtmsrd r11,1 /* clear MSR.RI */
+#endif /* CONFIG_PPC_BOOK3S */
+
beq- 1f
ACCOUNT_CPU_USER_EXIT(r11, r12)
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
@@ -206,7 +226,7 @@ syscall_error_cont:
mtcr r5
mtspr SPRN_SRR0,r7
mtspr SPRN_SRR1,r8
- rfid
+ RFI
b . /* prevent speculative execution */
syscall_error:
@@ -276,9 +296,13 @@ syscall_exit_work:
beq .ret_from_except_lite
/* Re-enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 1
+#else
mfmsr r10
ori r10,r10,MSR_EE
mtmsrd r10,1
+#endif /* CONFIG_PPC_BOOK3E */
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
@@ -380,7 +404,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
and. r0,r0,r22
beq+ 1f
andc r22,r22,r0
- mtmsrd r22
+ MTMSRD(r22)
isync
1: std r20,_NIP(r1)
mfcr r23
@@ -399,6 +423,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
std r6,PACACURRENT(r13) /* Set new 'current' */
ld r8,KSP(r4) /* new stack pointer */
+#ifdef CONFIG_PPC_BOOK3S
BEGIN_FTR_SECTION
BEGIN_FTR_SECTION_NESTED(95)
clrrdi r6,r8,28 /* get its ESID */
@@ -445,8 +470,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
slbie r6 /* Workaround POWER5 < DD2.1 issue */
slbmte r7,r0
isync
-
2:
+#endif /* !CONFIG_PPC_BOOK3S */
+
clrrdi r7,r8,THREAD_SHIFT /* base of new stack */
/* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE
because we don't need to leave the 288-byte ABI gap at the
@@ -490,10 +516,14 @@ _GLOBAL(ret_from_except_lite)
* can't change between when we test it and when we return
* from the interrupt.
*/
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 0
+#else
mfmsr r10 /* Get current interrupt state */
rldicl r9,r10,48,1 /* clear MSR_EE */
rotldi r9,r9,16
mtmsrd r9,1 /* Update machine state */
+#endif /* CONFIG_PPC_BOOK3E */
#ifdef CONFIG_PREEMPT
clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */
@@ -540,6 +570,9 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
stb r4,PACAHARDIRQEN(r13)
+#ifdef CONFIG_PPC_BOOK3E
+ b .exception_return_book3e
+#else
ld r4,_CTR(r1)
ld r0,_LINK(r1)
mtctr r4
@@ -588,6 +621,8 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
rfid
b . /* prevent speculative execution */
+#endif /* CONFIG_PPC_BOOK3E */
+
iseries_check_pending_irqs:
#ifdef CONFIG_PPC_ISERIES
ld r5,SOFTE(r1)
@@ -638,6 +673,11 @@ do_work:
li r0,1
stb r0,PACASOFTIRQEN(r13)
stb r0,PACAHARDIRQEN(r13)
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 1
+ bl .preempt_schedule
+ wrteei 0
+#else
ori r10,r10,MSR_EE
mtmsrd r10,1 /* reenable interrupts */
bl .preempt_schedule
@@ -646,6 +686,7 @@ do_work:
rldicl r10,r10,48,1 /* disable interrupts again */
rotldi r10,r10,16
mtmsrd r10,1
+#endif /* CONFIG_PPC_BOOK3E */
ld r4,TI_FLAGS(r9)
andi. r0,r4,_TIF_NEED_RESCHED
bne 1b
@@ -654,8 +695,12 @@ do_work:
user_work:
#endif
/* Enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+ wrteei 1
+#else
ori r10,r10,MSR_EE
mtmsrd r10,1
+#endif /* CONFIG_PPC_BOOK3E */
andi. r0,r4,_TIF_NEED_RESCHED
beq 1f
@@ -762,7 +807,7 @@ _GLOBAL(enter_rtas)
_STATIC(rtas_return_loc)
/* relocation is off at this point */
- mfspr r4,SPRN_SPRG3 /* Get PACA */
+ mfspr r4,SPRN_SPRG_PACA /* Get PACA */
clrldi r4,r4,2 /* convert to realmode address */
bcl 20,31,$+4
@@ -793,7 +838,7 @@ _STATIC(rtas_restore_regs)
REST_8GPRS(14, r1) /* Restore the non-volatiles */
REST_10GPRS(22, r1) /* ditto */
- mfspr r13,SPRN_SPRG3
+ mfspr r13,SPRN_SPRG_PACA
ld r4,_CCR(r1)
mtcr r4
@@ -823,33 +868,24 @@ _GLOBAL(enter_prom)
* of all registers that it saves. We therefore save those registers
* PROM might touch to the stack. (r0, r3-r13 are caller saved)
*/
- SAVE_8GPRS(2, r1)
+ SAVE_GPR(2, r1)
SAVE_GPR(13, r1)
SAVE_8GPRS(14, r1)
SAVE_10GPRS(22, r1)
- mfcr r4
- std r4,_CCR(r1)
- mfctr r5
- std r5,_CTR(r1)
- mfspr r6,SPRN_XER
- std r6,_XER(r1)
- mfdar r7
- std r7,_DAR(r1)
- mfdsisr r8
- std r8,_DSISR(r1)
- mfsrr0 r9
- std r9,_SRR0(r1)
- mfsrr1 r10
- std r10,_SRR1(r1)
+ mfcr r10
mfmsr r11
+ std r10,_CCR(r1)
std r11,_MSR(r1)
/* Get the PROM entrypoint */
- ld r0,GPR4(r1)
- mtlr r0
+ mtlr r4
/* Switch MSR to 32 bits mode
*/
+#ifdef CONFIG_PPC_BOOK3E
+ rlwinm r11,r11,0,1,31
+ mtmsr r11
+#else /* CONFIG_PPC_BOOK3E */
mfmsr r11
li r12,1
rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
@@ -858,10 +894,10 @@ _GLOBAL(enter_prom)
rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
andc r11,r11,r12
mtmsrd r11
+#endif /* CONFIG_PPC_BOOK3E */
isync
- /* Restore arguments & enter PROM here... */
- ld r3,GPR3(r1)
+ /* Enter PROM here... */
blrl
/* Just make sure that r1 top 32 bits didn't get
@@ -871,7 +907,7 @@ _GLOBAL(enter_prom)
/* Restore the MSR (back to 64 bits) */
ld r0,_MSR(r1)
- mtmsrd r0
+ MTMSRD(r0)
isync
/* Restore other registers */
@@ -881,18 +917,6 @@ _GLOBAL(enter_prom)
REST_10GPRS(22, r1)
ld r4,_CCR(r1)
mtcr r4
- ld r5,_CTR(r1)
- mtctr r5
- ld r6,_XER(r1)
- mtspr SPRN_XER,r6
- ld r7,_DAR(r1)
- mtdar r7
- ld r8,_DSISR(r1)
- mtdsisr r8
- ld r9,_SRR0(r1)
- mtsrr0 r9
- ld r10,_SRR1(r1)
- mtsrr1 r10
addi r1,r1,PROM_FRAME_SIZE
ld r0,16(r1)
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
new file mode 100644
index 000000000000..695d4847d228
--- /dev/null
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -0,0 +1,784 @@
+/*
+ * Boot code and exception vectors for Book3E processors
+ *
+ * Copyright (C) 2007 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/threads.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cputable.h>
+#include <asm/setup.h>
+#include <asm/thread_info.h>
+#include <asm/reg.h>
+#include <asm/exception-64e.h>
+#include <asm/bug.h>
+#include <asm/irqflags.h>
+#include <asm/ptrace.h>
+#include <asm/ppc-opcode.h>
+#include <asm/mmu.h>
+
+/* XXX This will ultimately add space for a special exception save
+ * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc...
+ * when taking special interrupts. For now we don't support that,
+ * special interrupts from within a non-standard level will probably
+ * blow you up
+ */
+#define SPECIAL_EXC_FRAME_SIZE INT_FRAME_SIZE
+
+/* Exception prolog code for all exceptions */
+#define EXCEPTION_PROLOG(n, type, addition) \
+ mtspr SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */ \
+ mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \
+ std r10,PACA_EX##type+EX_R10(r13); \
+ std r11,PACA_EX##type+EX_R11(r13); \
+ mfcr r10; /* save CR */ \
+ addition; /* additional code for that exc. */ \
+ std r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */ \
+ stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \
+ mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \
+ type##_SET_KSTACK; /* get special stack if necessary */\
+ andi. r10,r11,MSR_PR; /* save stack pointer */ \
+ beq 1f; /* branch around if supervisor */ \
+ ld r1,PACAKSAVE(r13); /* get kernel stack coming from usr */\
+1: cmpdi cr1,r1,0; /* check if SP makes sense */ \
+ bge- cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \
+ mfspr r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */
+
+/* Exception type-specific macros */
+#define GEN_SET_KSTACK \
+ subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */
+#define SPRN_GEN_SRR0 SPRN_SRR0
+#define SPRN_GEN_SRR1 SPRN_SRR1
+
+#define CRIT_SET_KSTACK \
+ ld r1,PACA_CRIT_STACK(r13); \
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_CRIT_SRR0 SPRN_CSRR0
+#define SPRN_CRIT_SRR1 SPRN_CSRR1
+
+#define DBG_SET_KSTACK \
+ ld r1,PACA_DBG_STACK(r13); \
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_DBG_SRR0 SPRN_DSRR0
+#define SPRN_DBG_SRR1 SPRN_DSRR1
+
+#define MC_SET_KSTACK \
+ ld r1,PACA_MC_STACK(r13); \
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_MC_SRR0 SPRN_MCSRR0
+#define SPRN_MC_SRR1 SPRN_MCSRR1
+
+#define NORMAL_EXCEPTION_PROLOG(n, addition) \
+ EXCEPTION_PROLOG(n, GEN, addition##_GEN)
+
+#define CRIT_EXCEPTION_PROLOG(n, addition) \
+ EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)
+
+#define DBG_EXCEPTION_PROLOG(n, addition) \
+ EXCEPTION_PROLOG(n, DBG, addition##_DBG)
+
+#define MC_EXCEPTION_PROLOG(n, addition) \
+ EXCEPTION_PROLOG(n, MC, addition##_MC)
+
+
+/* Variants of the "addition" argument for the prolog
+ */
+#define PROLOG_ADDITION_NONE_GEN
+#define PROLOG_ADDITION_NONE_CRIT
+#define PROLOG_ADDITION_NONE_DBG
+#define PROLOG_ADDITION_NONE_MC
+
+#define PROLOG_ADDITION_MASKABLE_GEN \
+ lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \
+ cmpwi cr0,r11,0; /* yes -> go out of line */ \
+ beq masked_interrupt_book3e;
+
+#define PROLOG_ADDITION_2REGS_GEN \
+ std r14,PACA_EXGEN+EX_R14(r13); \
+ std r15,PACA_EXGEN+EX_R15(r13)
+
+#define PROLOG_ADDITION_1REG_GEN \
+ std r14,PACA_EXGEN+EX_R14(r13);
+
+#define PROLOG_ADDITION_2REGS_CRIT \
+ std r14,PACA_EXCRIT+EX_R14(r13); \
+ std r15,PACA_EXCRIT+EX_R15(r13)
+
+#define PROLOG_ADDITION_2REGS_DBG \
+ std r14,PACA_EXDBG+EX_R14(r13); \
+ std r15,PACA_EXDBG+EX_R15(r13)
+
+#define PROLOG_ADDITION_2REGS_MC \
+ std r14,PACA_EXMC+EX_R14(r13); \
+ std r15,PACA_EXMC+EX_R15(r13)
+
+/* Core exception code for all exceptions except TLB misses.
+ * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
+ */
+#define EXCEPTION_COMMON(n, excf, ints) \
+ std r0,GPR0(r1); /* save r0 in stackframe */ \
+ std r2,GPR2(r1); /* save r2 in stackframe */ \
+ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
+ SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
+ std r9,GPR9(r1); /* save r9 in stackframe */ \
+ std r10,_NIP(r1); /* save SRR0 to stackframe */ \
+ std r11,_MSR(r1); /* save SRR1 to stackframe */ \
+ ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */ \
+ ld r3,excf+EX_R10(r13); /* get back r10 */ \
+ ld r4,excf+EX_R11(r13); /* get back r11 */ \
+ mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */ \
+ std r12,GPR12(r1); /* save r12 in stackframe */ \
+ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \
+ mflr r6; /* save LR in stackframe */ \
+ mfctr r7; /* save CTR in stackframe */ \
+ mfspr r8,SPRN_XER; /* save XER in stackframe */ \
+ ld r9,excf+EX_R1(r13); /* load orig r1 back from PACA */ \
+ lwz r10,excf+EX_CR(r13); /* load orig CR back from PACA */ \
+ lbz r11,PACASOFTIRQEN(r13); /* get current IRQ softe */ \
+ ld r12,exception_marker@toc(r2); \
+ li r0,0; \
+ std r3,GPR10(r1); /* save r10 to stackframe */ \
+ std r4,GPR11(r1); /* save r11 to stackframe */ \
+ std r5,GPR13(r1); /* save it to stackframe */ \
+ std r6,_LINK(r1); \
+ std r7,_CTR(r1); \
+ std r8,_XER(r1); \
+ li r3,(n)+1; /* indicate partial regs in trap */ \
+ std r9,0(r1); /* store stack frame back link */ \
+ std r10,_CCR(r1); /* store orig CR in stackframe */ \
+ std r9,GPR1(r1); /* store stack frame back link */ \
+ std r11,SOFTE(r1); /* and save it to stackframe */ \
+ std r12,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \
+ std r3,_TRAP(r1); /* set trap number */ \
+ std r0,RESULT(r1); /* clear regs->result */ \
+ ints;
+
+/* Variants for the "ints" argument */
+#define INTS_KEEP
+#define INTS_DISABLE_SOFT \
+ stb r0,PACASOFTIRQEN(r13); /* mark interrupts soft-disabled */ \
+ TRACE_DISABLE_INTS;
+#define INTS_DISABLE_HARD \
+ stb r0,PACAHARDIRQEN(r13); /* and hard disabled */
+#define INTS_DISABLE_ALL \
+ INTS_DISABLE_SOFT \
+ INTS_DISABLE_HARD
+
+/* This is called by exceptions that used INTS_KEEP (that is did not clear
+ * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE
+ * to it's previous value
+ *
+ * XXX In the long run, we may want to open-code it in order to separate the
+ * load from the wrtee, thus limiting the latency caused by the dependency
+ * but at this point, I'll favor code clarity until we have a near to final
+ * implementation
+ */
+#define INTS_RESTORE_HARD \
+ ld r11,_MSR(r1); \
+ wrtee r11;
+
+/* XXX FIXME: Restore r14/r15 when necessary */
+#define BAD_STACK_TRAMPOLINE(n) \
+exc_##n##_bad_stack: \
+ li r1,(n); /* get exception number */ \
+ sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \
+ b bad_stack_book3e; /* bad stack error */
+
+#define EXCEPTION_STUB(loc, label) \
+ . = interrupt_base_book3e + loc; \
+ nop; /* To make debug interrupts happy */ \
+ b exc_##label##_book3e;
+
+#define ACK_NONE(r)
+#define ACK_DEC(r) \
+ lis r,TSR_DIS@h; \
+ mtspr SPRN_TSR,r
+#define ACK_FIT(r) \
+ lis r,TSR_FIS@h; \
+ mtspr SPRN_TSR,r
+
+#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \
+ START_EXCEPTION(label); \
+ NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \
+ EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \
+ ack(r8); \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ bl hdlr; \
+ b .ret_from_except_lite;
+
+/* This value is used to mark exception frames on the stack. */
+ .section ".toc","aw"
+exception_marker:
+ .tc ID_EXC_MARKER[TC],STACK_FRAME_REGS_MARKER
+
+
+/*
+ * And here we have the exception vectors !
+ */
+
+ .text
+ .balign 0x1000
+ .globl interrupt_base_book3e
+interrupt_base_book3e: /* fake trap */
+ /* Note: If real debug exceptions are supported by the HW, the vector
+ * below will have to be patched up to point to an appropriate handler
+ */
+ EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */
+ EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */
+ EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */
+ EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */
+ EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */
+ EXCEPTION_STUB(0x0a0, external_input) /* 0x0500 */
+ EXCEPTION_STUB(0x0c0, alignment) /* 0x0600 */
+ EXCEPTION_STUB(0x0e0, program) /* 0x0700 */
+ EXCEPTION_STUB(0x100, fp_unavailable) /* 0x0800 */
+ EXCEPTION_STUB(0x120, system_call) /* 0x0c00 */
+ EXCEPTION_STUB(0x140, ap_unavailable) /* 0x0f20 */
+ EXCEPTION_STUB(0x160, decrementer) /* 0x0900 */
+ EXCEPTION_STUB(0x180, fixed_interval) /* 0x0980 */
+ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */
+ EXCEPTION_STUB(0x1c0, data_tlb_miss)
+ EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
+
+#if 0
+ EXCEPTION_STUB(0x280, processor_doorbell)
+ EXCEPTION_STUB(0x220, processor_doorbell_crit)
+#endif
+ .globl interrupt_end_book3e
+interrupt_end_book3e:
+
+/* Critical Input Interrupt */
+ START_EXCEPTION(critical_input);
+ CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
+// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
+// bl special_reg_save_crit
+// addi r3,r1,STACK_FRAME_OVERHEAD
+// bl .critical_exception
+// b ret_from_crit_except
+ b .
+
+/* Machine Check Interrupt */
+ START_EXCEPTION(machine_check);
+ CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)
+// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
+// bl special_reg_save_mc
+// addi r3,r1,STACK_FRAME_OVERHEAD
+// bl .machine_check_exception
+// b ret_from_mc_except
+ b .
+
+/* Data Storage Interrupt */
+ START_EXCEPTION(data_storage)
+ NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS)
+ mfspr r14,SPRN_DEAR
+ mfspr r15,SPRN_ESR
+ EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP)
+ b storage_fault_common
+
+/* Instruction Storage Interrupt */
+ START_EXCEPTION(instruction_storage);
+ NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS)
+ li r15,0
+ mr r14,r10
+ EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP)
+ b storage_fault_common
+
+/* External Input Interrupt */
+ MASKABLE_EXCEPTION(0x500, external_input, .do_IRQ, ACK_NONE)
+
+/* Alignment */
+ START_EXCEPTION(alignment);
+ NORMAL_EXCEPTION_PROLOG(0x600, PROLOG_ADDITION_2REGS)
+ mfspr r14,SPRN_DEAR
+ mfspr r15,SPRN_ESR
+ EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP)
+ b alignment_more /* no room, go out of line */
+
+/* Program Interrupt */
+ START_EXCEPTION(program);
+ NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)
+ mfspr r14,SPRN_ESR
+ EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)
+ std r14,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ ld r14,PACA_EXGEN+EX_R14(r13)
+ bl .save_nvgprs
+ INTS_RESTORE_HARD
+ bl .program_check_exception
+ b .ret_from_except
+
+/* Floating Point Unavailable Interrupt */
+ START_EXCEPTION(fp_unavailable);
+ NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE)
+ /* we can probably do a shorter exception entry for that one... */
+ EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
+ bne 1f /* if from user, just load it up */
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ INTS_RESTORE_HARD
+ bl .kernel_fp_unavailable_exception
+ BUG_OPCODE
+1: ld r12,_MSR(r1)
+ bl .load_up_fpu
+ b fast_exception_return
+
+/* Decrementer Interrupt */
+ MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC)
+
+/* Fixed Interval Timer Interrupt */
+ MASKABLE_EXCEPTION(0x980, fixed_interval, .unknown_exception, ACK_FIT)
+
+/* Watchdog Timer Interrupt */
+ START_EXCEPTION(watchdog);
+ CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
+// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
+// bl special_reg_save_crit
+// addi r3,r1,STACK_FRAME_OVERHEAD
+// bl .unknown_exception
+// b ret_from_crit_except
+ b .
+
+/* System Call Interrupt */
+ START_EXCEPTION(system_call)
+ mr r9,r13 /* keep a copy of userland r13 */
+ mfspr r11,SPRN_SRR0 /* get return address */
+ mfspr r12,SPRN_SRR1 /* get previous MSR */
+ mfspr r13,SPRN_SPRG_PACA /* get our PACA */
+ b system_call_common
+
+/* Auxillary Processor Unavailable Interrupt */
+ START_EXCEPTION(ap_unavailable);
+ NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE)
+ EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .save_nvgprs
+ INTS_RESTORE_HARD
+ bl .unknown_exception
+ b .ret_from_except
+
+/* Debug exception as a critical interrupt*/
+ START_EXCEPTION(debug_crit);
+ CRIT_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+
+ /*
+ * If there is a single step or branch-taken exception in an
+ * exception entry sequence, it was probably meant to apply to
+ * the code where the exception occurred (since exception entry
+ * doesn't turn off DE automatically). We simulate the effect
+ * of turning off DE on entry to an exception handler by turning
+ * off DE in the CSRR1 value and clearing the debug status.
+ */
+
+ mfspr r14,SPRN_DBSR /* check single-step/branch taken */
+ andis. r15,r14,DBSR_IC@h
+ beq+ 1f
+
+ LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
+ LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)
+ cmpld cr0,r10,r14
+ cmpld cr1,r10,r15
+ blt+ cr0,1f
+ bge+ cr1,1f
+
+ /* here it looks like we got an inappropriate debug exception. */
+ lis r14,DBSR_IC@h /* clear the IC event */
+ rlwinm r11,r11,0,~MSR_DE /* clear DE in the CSRR1 value */
+ mtspr SPRN_DBSR,r14
+ mtspr SPRN_CSRR1,r11
+ lwz r10,PACA_EXCRIT+EX_CR(r13) /* restore registers */
+ ld r1,PACA_EXCRIT+EX_R1(r13)
+ ld r14,PACA_EXCRIT+EX_R14(r13)
+ ld r15,PACA_EXCRIT+EX_R15(r13)
+ mtcr r10
+ ld r10,PACA_EXCRIT+EX_R10(r13) /* restore registers */
+ ld r11,PACA_EXCRIT+EX_R11(r13)
+ mfspr r13,SPRN_SPRG_CRIT_SCRATCH
+ rfci
+
+ /* Normal debug exception */
+ /* XXX We only handle coming from userspace for now since we can't
+ * quite save properly an interrupted kernel state yet
+ */
+1: andi. r14,r11,MSR_PR; /* check for userspace again */
+ beq kernel_dbg_exc; /* if from kernel mode */
+
+ /* Now we mash up things to make it look like we are coming on a
+ * normal exception
+ */
+ mfspr r15,SPRN_SPRG_CRIT_SCRATCH
+ mtspr SPRN_SPRG_GEN_SCRATCH,r15
+ mfspr r14,SPRN_DBSR
+ EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)
+ std r14,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r14
+ ld r14,PACA_EXCRIT+EX_R14(r13)
+ ld r15,PACA_EXCRIT+EX_R15(r13)
+ bl .save_nvgprs
+ bl .DebugException
+ b .ret_from_except
+
+kernel_dbg_exc:
+ b . /* NYI */
+
+
+/*
+ * An interrupt came in while soft-disabled; clear EE in SRR1,
+ * clear paca->hard_enabled and return.
+ */
+masked_interrupt_book3e:
+ mtcr r10
+ stb r11,PACAHARDIRQEN(r13)
+ mfspr r10,SPRN_SRR1
+ rldicl r11,r10,48,1 /* clear MSR_EE */
+ rotldi r10,r11,16
+ mtspr SPRN_SRR1,r10
+ ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */
+ ld r11,PACA_EXGEN+EX_R11(r13);
+ mfspr r13,SPRN_SPRG_GEN_SCRATCH;
+ rfi
+ b .
+
+/*
+ * This is called from 0x300 and 0x400 handlers after the prologs with
+ * r14 and r15 containing the fault address and error code, with the
+ * original values stashed away in the PACA
+ */
+storage_fault_common:
+ std r14,_DAR(r1)
+ std r15,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r14
+ mr r5,r15
+ ld r14,PACA_EXGEN+EX_R14(r13)
+ ld r15,PACA_EXGEN+EX_R15(r13)
+ INTS_RESTORE_HARD
+ bl .do_page_fault
+ cmpdi r3,0
+ bne- 1f
+ b .ret_from_except_lite
+1: bl .save_nvgprs
+ mr r5,r3
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ ld r4,_DAR(r1)
+ bl .bad_page_fault
+ b .ret_from_except
+
+/*
+ * Alignment exception doesn't fit entirely in the 0x100 bytes so it
+ * continues here.
+ */
+alignment_more:
+ std r14,_DAR(r1)
+ std r15,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ ld r14,PACA_EXGEN+EX_R14(r13)
+ ld r15,PACA_EXGEN+EX_R15(r13)
+ bl .save_nvgprs
+ INTS_RESTORE_HARD
+ bl .alignment_exception
+ b .ret_from_except
+
+/*
+ * We branch here from entry_64.S for the last stage of the exception
+ * return code path. MSR:EE is expected to be off at that point
+ */
+_GLOBAL(exception_return_book3e)
+ b 1f
+
+/* This is the return from load_up_fpu fast path which could do with
+ * less GPR restores in fact, but for now we have a single return path
+ */
+ .globl fast_exception_return
+fast_exception_return:
+ wrteei 0
+1: mr r0,r13
+ ld r10,_MSR(r1)
+ REST_4GPRS(2, r1)
+ andi. r6,r10,MSR_PR
+ REST_2GPRS(6, r1)
+ beq 1f
+ ACCOUNT_CPU_USER_EXIT(r10, r11)
+ ld r0,GPR13(r1)
+
+1: stdcx. r0,0,r1 /* to clear the reservation */
+
+ ld r8,_CCR(r1)
+ ld r9,_LINK(r1)
+ ld r10,_CTR(r1)
+ ld r11,_XER(r1)
+ mtcr r8
+ mtlr r9
+ mtctr r10
+ mtxer r11
+ REST_2GPRS(8, r1)
+ ld r10,GPR10(r1)
+ ld r11,GPR11(r1)
+ ld r12,GPR12(r1)
+ mtspr SPRN_SPRG_GEN_SCRATCH,r0
+
+ std r10,PACA_EXGEN+EX_R10(r13);
+ std r11,PACA_EXGEN+EX_R11(r13);
+ ld r10,_NIP(r1)
+ ld r11,_MSR(r1)
+ ld r0,GPR0(r1)
+ ld r1,GPR1(r1)
+ mtspr SPRN_SRR0,r10
+ mtspr SPRN_SRR1,r11
+ ld r10,PACA_EXGEN+EX_R10(r13)
+ ld r11,PACA_EXGEN+EX_R11(r13)
+ mfspr r13,SPRN_SPRG_GEN_SCRATCH
+ rfi
+
+/*
+ * Trampolines used when spotting a bad kernel stack pointer in
+ * the exception entry code.
+ *
+ * TODO: move some bits like SRR0 read to trampoline, pass PACA
+ * index around, etc... to handle crit & mcheck
+ */
+BAD_STACK_TRAMPOLINE(0x000)
+BAD_STACK_TRAMPOLINE(0x100)
+BAD_STACK_TRAMPOLINE(0x200)
+BAD_STACK_TRAMPOLINE(0x300)
+BAD_STACK_TRAMPOLINE(0x400)
+BAD_STACK_TRAMPOLINE(0x500)
+BAD_STACK_TRAMPOLINE(0x600)
+BAD_STACK_TRAMPOLINE(0x700)
+BAD_STACK_TRAMPOLINE(0x800)
+BAD_STACK_TRAMPOLINE(0x900)
+BAD_STACK_TRAMPOLINE(0x980)
+BAD_STACK_TRAMPOLINE(0x9f0)
+BAD_STACK_TRAMPOLINE(0xa00)
+BAD_STACK_TRAMPOLINE(0xb00)
+BAD_STACK_TRAMPOLINE(0xc00)
+BAD_STACK_TRAMPOLINE(0xd00)
+BAD_STACK_TRAMPOLINE(0xe00)
+BAD_STACK_TRAMPOLINE(0xf00)
+BAD_STACK_TRAMPOLINE(0xf20)
+
+ .globl bad_stack_book3e
+bad_stack_book3e:
+ /* XXX: Needs to make SPRN_SPRG_GEN depend on exception type */
+ mfspr r10,SPRN_SRR0; /* read SRR0 before touching stack */
+ ld r1,PACAEMERGSP(r13)
+ subi r1,r1,64+INT_FRAME_SIZE
+ std r10,_NIP(r1)
+ std r11,_MSR(r1)
+ ld r10,PACA_EXGEN+EX_R1(r13) /* FIXME for crit & mcheck */
+ lwz r11,PACA_EXGEN+EX_CR(r13) /* FIXME for crit & mcheck */
+ std r10,GPR1(r1)
+ std r11,_CCR(r1)
+ mfspr r10,SPRN_DEAR
+ mfspr r11,SPRN_ESR
+ std r10,_DAR(r1)
+ std r11,_DSISR(r1)
+ std r0,GPR0(r1); /* save r0 in stackframe */ \
+ std r2,GPR2(r1); /* save r2 in stackframe */ \
+ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
+ SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
+ std r9,GPR9(r1); /* save r9 in stackframe */ \
+ ld r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */ \
+ ld r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */ \
+ mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \
+ std r3,GPR10(r1); /* save r10 to stackframe */ \
+ std r4,GPR11(r1); /* save r11 to stackframe */ \
+ std r12,GPR12(r1); /* save r12 in stackframe */ \
+ std r5,GPR13(r1); /* save it to stackframe */ \
+ mflr r10
+ mfctr r11
+ mfxer r12
+ std r10,_LINK(r1)
+ std r11,_CTR(r1)
+ std r12,_XER(r1)
+ SAVE_10GPRS(14,r1)
+ SAVE_8GPRS(24,r1)
+ lhz r12,PACA_TRAP_SAVE(r13)
+ std r12,_TRAP(r1)
+ addi r11,r1,INT_FRAME_SIZE
+ std r11,0(r1)
+ li r12,0
+ std r12,0(r11)
+ ld r2,PACATOC(r13)
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .kernel_bad_stack
+ b 1b
+
+/*
+ * Setup the initial TLB for a core. This current implementation
+ * assume that whatever we are running off will not conflict with
+ * the new mapping at PAGE_OFFSET.
+ * We also make various assumptions about the processor we run on,
+ * this might have to be made more flexible based on the content
+ * of MMUCFG and friends.
+ */
+_GLOBAL(initial_tlb_book3e)
+
+ /* Setup MAS 0,1,2,3 and 7 for tlbwe of a 1G entry that maps the
+ * kernel linear mapping. We also set MAS8 once for all here though
+ * that will have to be made dependent on whether we are running under
+ * a hypervisor I suppose.
+ */
+ li r3,MAS0_HES | MAS0_WQ_ALLWAYS
+ mtspr SPRN_MAS0,r3
+ lis r3,(MAS1_VALID | MAS1_IPROT)@h
+ ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT
+ mtspr SPRN_MAS1,r3
+ LOAD_REG_IMMEDIATE(r3, PAGE_OFFSET | MAS2_M)
+ mtspr SPRN_MAS2,r3
+ li r3,MAS3_SR | MAS3_SW | MAS3_SX
+ mtspr SPRN_MAS7_MAS3,r3
+ li r3,0
+ mtspr SPRN_MAS8,r3
+
+ /* Write the TLB entry */
+ tlbwe
+
+ /* Now we branch the new virtual address mapped by this entry */
+ LOAD_REG_IMMEDIATE(r3,1f)
+ mtctr r3
+ bctr
+
+1: /* We are now running at PAGE_OFFSET, clean the TLB of everything
+ * else (XXX we should scan for bolted crap from the firmware too)
+ */
+ PPC_TLBILX(0,0,0)
+ sync
+ isync
+
+ /* We translate LR and return */
+ mflr r3
+ tovirt(r3,r3)
+ mtlr r3
+ blr
+
+/*
+ * Main entry (boot CPU, thread 0)
+ *
+ * We enter here from head_64.S, possibly after the prom_init trampoline
+ * with r3 and r4 already saved to r31 and 30 respectively and in 64 bits
+ * mode. Anything else is as it was left by the bootloader
+ *
+ * Initial requirements of this port:
+ *
+ * - Kernel loaded at 0 physical
+ * - A good lump of memory mapped 0:0 by UTLB entry 0
+ * - MSR:IS & MSR:DS set to 0
+ *
+ * Note that some of the above requirements will be relaxed in the future
+ * as the kernel becomes smarter at dealing with different initial conditions
+ * but for now you have to be careful
+ */
+_GLOBAL(start_initialization_book3e)
+ mflr r28
+
+ /* First, we need to setup some initial TLBs to map the kernel
+ * text, data and bss at PAGE_OFFSET. We don't have a real mode
+ * and always use AS 0, so we just set it up to match our link
+ * address and never use 0 based addresses.
+ */
+ bl .initial_tlb_book3e
+
+ /* Init global core bits */
+ bl .init_core_book3e
+
+ /* Init per-thread bits */
+ bl .init_thread_book3e
+
+ /* Return to common init code */
+ tovirt(r28,r28)
+ mtlr r28
+ blr
+
+
+/*
+ * Secondary core/processor entry
+ *
+ * This is entered for thread 0 of a secondary core, all other threads
+ * are expected to be stopped. It's similar to start_initialization_book3e
+ * except that it's generally entered from the holding loop in head_64.S
+ * after CPUs have been gathered by Open Firmware.
+ *
+ * We assume we are in 32 bits mode running with whatever TLB entry was
+ * set for us by the firmware or POR engine.
+ */
+_GLOBAL(book3e_secondary_core_init_tlb_set)
+ li r4,1
+ b .generic_secondary_smp_init
+
+_GLOBAL(book3e_secondary_core_init)
+ mflr r28
+
+ /* Do we need to setup initial TLB entry ? */
+ cmplwi r4,0
+ bne 2f
+
+ /* Setup TLB for this core */
+ bl .initial_tlb_book3e
+
+ /* We can return from the above running at a different
+ * address, so recalculate r2 (TOC)
+ */
+ bl .relative_toc
+
+ /* Init global core bits */
+2: bl .init_core_book3e
+
+ /* Init per-thread bits */
+3: bl .init_thread_book3e
+
+ /* Return to common init code at proper virtual address.
+ *
+ * Due to various previous assumptions, we know we entered this
+ * function at either the final PAGE_OFFSET mapping or using a
+ * 1:1 mapping at 0, so we don't bother doing a complicated check
+ * here, we just ensure the return address has the right top bits.
+ *
+ * Note that if we ever want to be smarter about where we can be
+ * started from, we have to be careful that by the time we reach
+ * the code below we may already be running at a different location
+ * than the one we were called from since initial_tlb_book3e can
+ * have moved us already.
+ */
+ cmpdi cr0,r28,0
+ blt 1f
+ lis r3,PAGE_OFFSET@highest
+ sldi r3,r3,32
+ or r28,r28,r3
+1: mtlr r28
+ blr
+
+_GLOBAL(book3e_secondary_thread_init)
+ mflr r28
+ b 3b
+
+_STATIC(init_core_book3e)
+ /* Establish the interrupt vector base */
+ LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e)
+ mtspr SPRN_IVPR,r3
+ sync
+ blr
+
+_STATIC(init_thread_book3e)
+ lis r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h
+ mtspr SPRN_EPCR,r3
+
+ /* Make sure interrupts are off */
+ wrteei 0
+
+ /* disable watchdog and FIT and enable DEC interrupts */
+ lis r3,TCR_DIE@h
+ mtspr SPRN_TCR,r3
+
+ blr
+
+
+
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index eb898112e577..50f2ad36ed09 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -12,6 +12,8 @@
*
*/
+#include <asm/exception-64s.h>
+
/*
* We layout physical memory as follows:
* 0x0000 - 0x00ff : Secondary processor spin code
@@ -22,18 +24,6 @@
* 0x8000 - : Early init and support code
*/
-
-/*
- * SPRG Usage
- *
- * Register Definition
- *
- * SPRG0 reserved for hypervisor
- * SPRG1 temp - used to save gpr
- * SPRG2 temp - used to save gpr
- * SPRG3 virt addr of paca
- */
-
/*
* This is the start of the interrupt handlers for pSeries
* This code runs with relocation off.
@@ -51,34 +41,44 @@ __start_interrupts:
. = 0x200
_machine_check_pSeries:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
. = 0x300
.globl data_access_pSeries
data_access_pSeries:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
+ mtspr SPRN_SPRG_SCRATCH0,r13
BEGIN_FTR_SECTION
- mtspr SPRN_SPRG2,r12
- mfspr r13,SPRN_DAR
- mfspr r12,SPRN_DSISR
- srdi r13,r13,60
- rlwimi r13,r12,16,0x20
- mfcr r12
- cmpwi r13,0x2c
+ mfspr r13,SPRN_SPRG_PACA
+ std r9,PACA_EXSLB+EX_R9(r13)
+ std r10,PACA_EXSLB+EX_R10(r13)
+ mfspr r10,SPRN_DAR
+ mfspr r9,SPRN_DSISR
+ srdi r10,r10,60
+ rlwimi r10,r9,16,0x20
+ mfcr r9
+ cmpwi r10,0x2c
beq do_stab_bolted_pSeries
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ ld r10,PACA_EXSLB+EX_R10(r13)
+ std r11,PACA_EXGEN+EX_R11(r13)
+ ld r11,PACA_EXSLB+EX_R9(r13)
+ std r12,PACA_EXGEN+EX_R12(r13)
+ mfspr r12,SPRN_SPRG_SCRATCH0
+ std r10,PACA_EXGEN+EX_R10(r13)
+ std r11,PACA_EXGEN+EX_R9(r13)
+ std r12,PACA_EXGEN+EX_R13(r13)
+ EXCEPTION_PROLOG_PSERIES_1(data_access_common)
+FTR_SECTION_ELSE
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common)
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
. = 0x380
.globl data_access_slb_pSeries
data_access_slb_pSeries:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13
+ mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_DAR
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
@@ -91,7 +91,7 @@ data_access_slb_pSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
+ mfspr r10,SPRN_SPRG_SCRATCH0
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
#ifndef CONFIG_RELOCATABLE
@@ -115,8 +115,8 @@ data_access_slb_pSeries:
.globl instruction_access_slb_pSeries
instruction_access_slb_pSeries:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13
+ mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
@@ -129,7 +129,7 @@ instruction_access_slb_pSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
+ mfspr r10,SPRN_SPRG_SCRATCH0
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
#ifndef CONFIG_RELOCATABLE
@@ -159,7 +159,7 @@ BEGIN_FTR_SECTION
beq- 1f
END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
mr r9,r13
- mfspr r13,SPRN_SPRG3
+ mfspr r13,SPRN_SPRG_PACA
mfspr r11,SPRN_SRR0
ld r12,PACAKBASE(r13)
ld r10,PACAKMSR(r13)
@@ -228,15 +228,17 @@ masked_interrupt:
rotldi r10,r10,16
mtspr SPRN_SRR1,r10
ld r10,PACA_EXGEN+EX_R10(r13)
- mfspr r13,SPRN_SPRG1
+ mfspr r13,SPRN_SPRG_SCRATCH0
rfid
b .
.align 7
do_stab_bolted_pSeries:
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
- EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
+ std r11,PACA_EXSLB+EX_R11(r13)
+ std r12,PACA_EXSLB+EX_R12(r13)
+ mfspr r10,SPRN_SPRG_SCRATCH0
+ std r10,PACA_EXSLB+EX_R13(r13)
+ EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted)
#ifdef CONFIG_PPC_PSERIES
/*
@@ -246,14 +248,14 @@ do_stab_bolted_pSeries:
.align 7
system_reset_fwnmi:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi
.align 7
machine_check_fwnmi:
HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
#endif /* CONFIG_PPC_PSERIES */
@@ -268,7 +270,7 @@ slb_miss_user_pseries:
std r10,PACA_EXGEN+EX_R10(r13)
std r11,PACA_EXGEN+EX_R11(r13)
std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r10,SPRG1
+ mfspr r10,SPRG_SCRATCH0
ld r11,PACA_EXSLB+EX_R9(r13)
ld r12,PACA_EXSLB+EX_R3(r13)
std r10,PACA_EXGEN+EX_R13(r13)
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 2436df33c6f4..fc8f5b14019c 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -91,7 +91,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
#endif /* CONFIG_SMP */
/* enable use of FP after return */
#ifdef CONFIG_PPC32
- mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */
+ mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
lwz r4,THREAD_FPEXC_MODE(r5)
ori r9,r9,MSR_FP /* enable FP for current */
or r9,r9,r4
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index fc2132942754..829c3fe7c5a2 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -244,8 +244,8 @@ __secondary_hold_acknowledge:
* task's thread_struct.
*/
#define EXCEPTION_PROLOG \
- mtspr SPRN_SPRG0,r10; \
- mtspr SPRN_SPRG1,r11; \
+ mtspr SPRN_SPRG_SCRATCH0,r10; \
+ mtspr SPRN_SPRG_SCRATCH1,r11; \
mfcr r10; \
EXCEPTION_PROLOG_1; \
EXCEPTION_PROLOG_2
@@ -255,7 +255,7 @@ __secondary_hold_acknowledge:
andi. r11,r11,MSR_PR; \
tophys(r11,r1); /* use tophys(r1) if kernel */ \
beq 1f; \
- mfspr r11,SPRN_SPRG3; \
+ mfspr r11,SPRN_SPRG_THREAD; \
lwz r11,THREAD_INFO-THREAD(r11); \
addi r11,r11,THREAD_SIZE; \
tophys(r11,r11); \
@@ -267,9 +267,9 @@ __secondary_hold_acknowledge:
stw r10,_CCR(r11); /* save registers */ \
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
- mfspr r10,SPRN_SPRG0; \
+ mfspr r10,SPRN_SPRG_SCRATCH0; \
stw r10,GPR10(r11); \
- mfspr r12,SPRN_SPRG1; \
+ mfspr r12,SPRN_SPRG_SCRATCH1; \
stw r12,GPR11(r11); \
mflr r10; \
stw r10,_LINK(r11); \
@@ -355,11 +355,11 @@ i##n: \
* -- paulus.
*/
. = 0x200
- mtspr SPRN_SPRG0,r10
- mtspr SPRN_SPRG1,r11
+ mtspr SPRN_SPRG_SCRATCH0,r10
+ mtspr SPRN_SPRG_SCRATCH1,r11
mfcr r10
#ifdef CONFIG_PPC_CHRP
- mfspr r11,SPRN_SPRG2
+ mfspr r11,SPRN_SPRG_RTAS
cmpwi 0,r11,0
bne 7f
#endif /* CONFIG_PPC_CHRP */
@@ -367,7 +367,7 @@ i##n: \
7: EXCEPTION_PROLOG_2
addi r3,r1,STACK_FRAME_OVERHEAD
#ifdef CONFIG_PPC_CHRP
- mfspr r4,SPRN_SPRG2
+ mfspr r4,SPRN_SPRG_RTAS
cmpwi cr1,r4,0
bne cr1,1f
#endif
@@ -485,7 +485,7 @@ InstructionTLBMiss:
mfspr r3,SPRN_IMISS
lis r1,PAGE_OFFSET@h /* check if kernel address */
cmplw 0,r1,r3
- mfspr r2,SPRN_SPRG3
+ mfspr r2,SPRN_SPRG_THREAD
li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
lwz r2,PGDIR(r2)
bge- 112f
@@ -559,7 +559,7 @@ DataLoadTLBMiss:
mfspr r3,SPRN_DMISS
lis r1,PAGE_OFFSET@h /* check if kernel address */
cmplw 0,r1,r3
- mfspr r2,SPRN_SPRG3
+ mfspr r2,SPRN_SPRG_THREAD
li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
lwz r2,PGDIR(r2)
bge- 112f
@@ -598,12 +598,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
mtcrf 0x80,r2
BEGIN_MMU_FTR_SECTION
li r0,1
- mfspr r1,SPRN_SPRG4
+ mfspr r1,SPRN_SPRG_603_LRU
rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */
slw r0,r0,r2
xor r1,r0,r1
srw r0,r1,r2
- mtspr SPRN_SPRG4,r1
+ mtspr SPRN_SPRG_603_LRU,r1
mfspr r2,SPRN_SRR1
rlwimi r2,r0,31-14,14,14
mtspr SPRN_SRR1,r2
@@ -643,7 +643,7 @@ DataStoreTLBMiss:
mfspr r3,SPRN_DMISS
lis r1,PAGE_OFFSET@h /* check if kernel address */
cmplw 0,r1,r3
- mfspr r2,SPRN_SPRG3
+ mfspr r2,SPRN_SPRG_THREAD
li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
lwz r2,PGDIR(r2)
bge- 112f
@@ -678,12 +678,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
mtcrf 0x80,r2
BEGIN_MMU_FTR_SECTION
li r0,1
- mfspr r1,SPRN_SPRG4
+ mfspr r1,SPRN_SPRG_603_LRU
rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */
slw r0,r0,r2
xor r1,r0,r1
srw r0,r1,r2
- mtspr SPRN_SPRG4,r1
+ mtspr SPRN_SPRG_603_LRU,r1
mfspr r2,SPRN_SRR1
rlwimi r2,r0,31-14,14,14
mtspr SPRN_SRR1,r2
@@ -864,9 +864,9 @@ __secondary_start:
tophys(r4,r2)
addi r4,r4,THREAD /* phys address of our thread_struct */
CLR_TOP32(r4)
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
li r3,0
- mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */
+ mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */
/* enable MMU and jump to start_secondary */
li r4,MSR_KERNEL
@@ -947,9 +947,9 @@ start_here:
tophys(r4,r2)
addi r4,r4,THREAD /* init task's THREAD */
CLR_TOP32(r4)
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
li r3,0
- mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */
+ mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */
/* stack */
lis r1,init_thread_union@ha
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 0c96911d4299..a90625f9b485 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -103,21 +103,21 @@ _ENTRY(saved_ksp_limit)
/*
* Exception vector entry code. This code runs with address translation
- * turned off (i.e. using physical addresses). We assume SPRG3 has the
- * physical address of the current task thread_struct.
+ * turned off (i.e. using physical addresses). We assume SPRG_THREAD has
+ * the physical address of the current task thread_struct.
* Note that we have to have decremented r1 before we write to any fields
* of the exception frame, since a critical interrupt could occur at any
* time, and it will write to the area immediately below the current r1.
*/
#define NORMAL_EXCEPTION_PROLOG \
- mtspr SPRN_SPRG0,r10; /* save two registers to work with */\
- mtspr SPRN_SPRG1,r11; \
- mtspr SPRN_SPRG2,r1; \
+ mtspr SPRN_SPRG_SCRATCH0,r10; /* save two registers to work with */\
+ mtspr SPRN_SPRG_SCRATCH1,r11; \
+ mtspr SPRN_SPRG_SCRATCH2,r1; \
mfcr r10; /* save CR in r10 for now */\
mfspr r11,SPRN_SRR1; /* check whether user or kernel */\
andi. r11,r11,MSR_PR; \
beq 1f; \
- mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\
+ mfspr r1,SPRN_SPRG_THREAD; /* if from user, start at top of */\
lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\
addi r1,r1,THREAD_SIZE; \
1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\
@@ -125,13 +125,13 @@ _ENTRY(saved_ksp_limit)
stw r10,_CCR(r11); /* save various registers */\
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
- mfspr r10,SPRN_SPRG0; \
+ mfspr r10,SPRN_SPRG_SCRATCH0; \
stw r10,GPR10(r11); \
- mfspr r12,SPRN_SPRG1; \
+ mfspr r12,SPRN_SPRG_SCRATCH1; \
stw r12,GPR11(r11); \
mflr r10; \
stw r10,_LINK(r11); \
- mfspr r10,SPRN_SPRG2; \
+ mfspr r10,SPRN_SPRG_SCRATCH2; \
mfspr r12,SPRN_SRR0; \
stw r10,GPR1(r11); \
mfspr r9,SPRN_SRR1; \
@@ -160,7 +160,7 @@ _ENTRY(saved_ksp_limit)
lwz r11,critirq_ctx@l(r11); \
beq 1f; \
/* COMING FROM USER MODE */ \
- mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\
+ mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\
lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
1: addi r11,r11,THREAD_SIZE-INT_FRAME_SIZE; /* Alloc an excpt frm */\
tophys(r11,r11); \
@@ -265,8 +265,8 @@ label:
* and exit. Otherwise, we call heavywight functions to do the work.
*/
START_EXCEPTION(0x0300, DataStorage)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
+ mtspr SPRN_SPRG_SCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_SCRATCH1, r11
#ifdef CONFIG_403GCX
stw r12, 0(r0)
stw r9, 4(r0)
@@ -275,12 +275,12 @@ label:
stw r11, 8(r0)
stw r12, 12(r0)
#else
- mtspr SPRN_SPRG4, r12
- mtspr SPRN_SPRG5, r9
+ mtspr SPRN_SPRG_SCRATCH3, r12
+ mtspr SPRN_SPRG_SCRATCH4, r9
mfcr r11
mfspr r12, SPRN_PID
- mtspr SPRN_SPRG7, r11
- mtspr SPRN_SPRG6, r12
+ mtspr SPRN_SPRG_SCRATCH6, r11
+ mtspr SPRN_SPRG_SCRATCH5, r12
#endif
/* First, check if it was a zone fault (which means a user
@@ -308,7 +308,7 @@ label:
/* Get the PGD for the current thread.
*/
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
4:
tophys(r11, r11)
@@ -355,15 +355,15 @@ label:
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
- mfspr r12, SPRN_SPRG6
- mfspr r11, SPRN_SPRG7
+ mfspr r12, SPRN_SPRG_SCRATCH5
+ mfspr r11, SPRN_SPRG_SCRATCH6
mtspr SPRN_PID, r12
mtcr r11
- mfspr r9, SPRN_SPRG5
- mfspr r12, SPRN_SPRG4
+ mfspr r9, SPRN_SPRG_SCRATCH4
+ mfspr r12, SPRN_SPRG_SCRATCH3
#endif
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ mfspr r10, SPRN_SPRG_SCRATCH0
PPC405_ERR77_SYNC
rfi /* Should sync shadow TLBs */
b . /* prevent prefetch past rfi */
@@ -380,15 +380,15 @@ label:
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
- mfspr r12, SPRN_SPRG6
- mfspr r11, SPRN_SPRG7
+ mfspr r12, SPRN_SPRG_SCRATCH5
+ mfspr r11, SPRN_SPRG_SCRATCH6
mtspr SPRN_PID, r12
mtcr r11
- mfspr r9, SPRN_SPRG5
- mfspr r12, SPRN_SPRG4
+ mfspr r9, SPRN_SPRG_SCRATCH4
+ mfspr r12, SPRN_SPRG_SCRATCH3
#endif
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ mfspr r10, SPRN_SPRG_SCRATCH0
b DataAccess
/*
@@ -466,8 +466,8 @@ label:
* load TLB entries from the page table if they exist.
*/
START_EXCEPTION(0x1100, DTLBMiss)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
+ mtspr SPRN_SPRG_SCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_SCRATCH1, r11
#ifdef CONFIG_403GCX
stw r12, 0(r0)
stw r9, 4(r0)
@@ -476,12 +476,12 @@ label:
stw r11, 8(r0)
stw r12, 12(r0)
#else
- mtspr SPRN_SPRG4, r12
- mtspr SPRN_SPRG5, r9
+ mtspr SPRN_SPRG_SCRATCH3, r12
+ mtspr SPRN_SPRG_SCRATCH4, r9
mfcr r11
mfspr r12, SPRN_PID
- mtspr SPRN_SPRG7, r11
- mtspr SPRN_SPRG6, r12
+ mtspr SPRN_SPRG_SCRATCH6, r11
+ mtspr SPRN_SPRG_SCRATCH5, r12
#endif
mfspr r10, SPRN_DEAR /* Get faulting address */
@@ -500,7 +500,7 @@ label:
/* Get the PGD for the current thread.
*/
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
4:
tophys(r11, r11)
@@ -550,15 +550,15 @@ label:
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
- mfspr r12, SPRN_SPRG6
- mfspr r11, SPRN_SPRG7
+ mfspr r12, SPRN_SPRG_SCRATCH5
+ mfspr r11, SPRN_SPRG_SCRATCH6
mtspr SPRN_PID, r12
mtcr r11
- mfspr r9, SPRN_SPRG5
- mfspr r12, SPRN_SPRG4
+ mfspr r9, SPRN_SPRG_SCRATCH4
+ mfspr r12, SPRN_SPRG_SCRATCH3
#endif
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ mfspr r10, SPRN_SPRG_SCRATCH0
b DataAccess
/* 0x1200 - Instruction TLB Miss Exception
@@ -566,8 +566,8 @@ label:
* registers and bailout to a different point.
*/
START_EXCEPTION(0x1200, ITLBMiss)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
+ mtspr SPRN_SPRG_SCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_SCRATCH1, r11
#ifdef CONFIG_403GCX
stw r12, 0(r0)
stw r9, 4(r0)
@@ -576,12 +576,12 @@ label:
stw r11, 8(r0)
stw r12, 12(r0)
#else
- mtspr SPRN_SPRG4, r12
- mtspr SPRN_SPRG5, r9
+ mtspr SPRN_SPRG_SCRATCH3, r12
+ mtspr SPRN_SPRG_SCRATCH4, r9
mfcr r11
mfspr r12, SPRN_PID
- mtspr SPRN_SPRG7, r11
- mtspr SPRN_SPRG6, r12
+ mtspr SPRN_SPRG_SCRATCH6, r11
+ mtspr SPRN_SPRG_SCRATCH5, r12
#endif
mfspr r10, SPRN_SRR0 /* Get faulting address */
@@ -600,7 +600,7 @@ label:
/* Get the PGD for the current thread.
*/
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
4:
tophys(r11, r11)
@@ -650,15 +650,15 @@ label:
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
- mfspr r12, SPRN_SPRG6
- mfspr r11, SPRN_SPRG7
+ mfspr r12, SPRN_SPRG_SCRATCH5
+ mfspr r11, SPRN_SPRG_SCRATCH6
mtspr SPRN_PID, r12
mtcr r11
- mfspr r9, SPRN_SPRG5
- mfspr r12, SPRN_SPRG4
+ mfspr r9, SPRN_SPRG_SCRATCH4
+ mfspr r12, SPRN_SPRG_SCRATCH3
#endif
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ mfspr r10, SPRN_SPRG_SCRATCH0
b InstructionAccess
EXCEPTION(0x1300, Trap_13, unknown_exception, EXC_XFER_EE)
@@ -803,15 +803,15 @@ finish_tlb_load:
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
- mfspr r12, SPRN_SPRG6
- mfspr r11, SPRN_SPRG7
+ mfspr r12, SPRN_SPRG_SCRATCH5
+ mfspr r11, SPRN_SPRG_SCRATCH6
mtspr SPRN_PID, r12
mtcr r11
- mfspr r9, SPRN_SPRG5
- mfspr r12, SPRN_SPRG4
+ mfspr r9, SPRN_SPRG_SCRATCH4
+ mfspr r12, SPRN_SPRG_SCRATCH3
#endif
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ mfspr r10, SPRN_SPRG_SCRATCH0
PPC405_ERR77_SYNC
rfi /* Should sync shadow TLBs */
b . /* prevent prefetch past rfi */
@@ -835,7 +835,7 @@ start_here:
/* ptr to phys current thread */
tophys(r4,r2)
addi r4,r4,THREAD /* init task's THREAD */
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
/* stack */
lis r1,init_thread_union@ha
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 18d8a1677c4d..656cfb2d6666 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -239,7 +239,7 @@ skpinv: addi r4,r4,1 /* Increment */
/* ptr to current thread */
addi r4,r2,THREAD /* init task's THREAD */
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
/* stack */
lis r1,init_thread_union@h
@@ -350,12 +350,12 @@ interrupt_base:
/* Data TLB Error Interrupt */
START_EXCEPTION(DataTLBError)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
- mtspr SPRN_SPRG4W, r12
- mtspr SPRN_SPRG5W, r13
+ mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_WSCRATCH1, r11
+ mtspr SPRN_SPRG_WSCRATCH2, r12
+ mtspr SPRN_SPRG_WSCRATCH3, r13
mfcr r11
- mtspr SPRN_SPRG7W, r11
+ mtspr SPRN_SPRG_WSCRATCH4, r11
mfspr r10, SPRN_DEAR /* Get faulting address */
/* If we are faulting a kernel address, we have to use the
@@ -374,7 +374,7 @@ interrupt_base:
/* Get the PGD for the current thread */
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
/* Load PID into MMUCR TID */
@@ -446,12 +446,12 @@ tlb_44x_patch_hwater_D:
/* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out.
*/
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
b DataStorage
/* Instruction TLB Error Interrupt */
@@ -461,12 +461,12 @@ tlb_44x_patch_hwater_D:
* to a different point.
*/
START_EXCEPTION(InstructionTLBError)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
- mtspr SPRN_SPRG4W, r12
- mtspr SPRN_SPRG5W, r13
+ mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_WSCRATCH1, r11
+ mtspr SPRN_SPRG_WSCRATCH2, r12
+ mtspr SPRN_SPRG_WSCRATCH3, r13
mfcr r11
- mtspr SPRN_SPRG7W, r11
+ mtspr SPRN_SPRG_WSCRATCH4, r11
mfspr r10, SPRN_SRR0 /* Get faulting address */
/* If we are faulting a kernel address, we have to use the
@@ -485,7 +485,7 @@ tlb_44x_patch_hwater_D:
/* Get the PGD for the current thread */
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
/* Load PID into MMUCR TID */
@@ -542,12 +542,12 @@ tlb_44x_patch_hwater_I:
/* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out.
*/
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
b InstructionStorage
/* Debug Interrupt */
@@ -593,12 +593,12 @@ finish_tlb_load:
/* Done...restore registers and get out of here.
*/
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
rfi /* Force context change */
/*
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 012505ebd9f9..c38afdb45d7b 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -36,7 +36,6 @@
#include <asm/thread_info.h>
#include <asm/firmware.h>
#include <asm/page_64.h>
-#include <asm/exception.h>
#include <asm/irqflags.h>
/* The physical memory is layed out such that the secondary processor
@@ -122,10 +121,11 @@ __run_at_load:
*/
.globl __secondary_hold
__secondary_hold:
+#ifndef CONFIG_PPC_BOOK3E
mfmsr r24
ori r24,r24,MSR_RI
mtmsrd r24 /* RI on */
-
+#endif
/* Grab our physical cpu number */
mr r24,r3
@@ -144,6 +144,7 @@ __secondary_hold:
ld r4,0(r4) /* deref function descriptor */
mtctr r4
mr r3,r24
+ li r4,0
bctr
#else
BUG_OPCODE
@@ -164,21 +165,49 @@ exception_marker:
#include "exceptions-64s.S"
#endif
+_GLOBAL(generic_secondary_thread_init)
+ mr r24,r3
+
+ /* turn on 64-bit mode */
+ bl .enable_64b_mode
+
+ /* get a valid TOC pointer, wherever we're mapped at */
+ bl .relative_toc
+
+#ifdef CONFIG_PPC_BOOK3E
+ /* Book3E initialization */
+ mr r3,r24
+ bl .book3e_secondary_thread_init
+#endif
+ b generic_secondary_common_init
/*
* On pSeries and most other platforms, secondary processors spin
* in the following code.
* At entry, r3 = this processor's number (physical cpu id)
+ *
+ * On Book3E, r4 = 1 to indicate that the initial TLB entry for
+ * this core already exists (setup via some other mechanism such
+ * as SCOM before entry).
*/
_GLOBAL(generic_secondary_smp_init)
mr r24,r3
-
+ mr r25,r4
+
/* turn on 64-bit mode */
bl .enable_64b_mode
- /* get the TOC pointer (real address) */
+ /* get a valid TOC pointer, wherever we're mapped at */
bl .relative_toc
+#ifdef CONFIG_PPC_BOOK3E
+ /* Book3E initialization */
+ mr r3,r24
+ mr r4,r25
+ bl .book3e_secondary_core_init
+#endif
+
+generic_secondary_common_init:
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
* which logical id maps to our physical one.
@@ -196,7 +225,12 @@ _GLOBAL(generic_secondary_smp_init)
mr r3,r24 /* not found, copy phys to r3 */
b .kexec_wait /* next kernel might do better */
-2: mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
+2: mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG */
+#ifdef CONFIG_PPC_BOOK3E
+ addi r12,r13,PACA_EXTLB /* and TLB exc frame in another */
+ mtspr SPRN_SPRG_TLB_EXFRAME,r12
+#endif
+
/* From now on, r24 is expected to be logical cpuid */
mr r24,r5
3: HMT_LOW
@@ -232,6 +266,7 @@ _GLOBAL(generic_secondary_smp_init)
* Turn the MMU off.
* Assumes we're mapped EA == RA if the MMU is on.
*/
+#ifdef CONFIG_PPC_BOOK3S
_STATIC(__mmu_off)
mfmsr r3
andi. r0,r3,MSR_IR|MSR_DR
@@ -243,6 +278,7 @@ _STATIC(__mmu_off)
sync
rfid
b . /* prevent speculative execution */
+#endif
/*
@@ -280,6 +316,10 @@ _GLOBAL(__start_initialization_multiplatform)
mr r31,r3
mr r30,r4
+#ifdef CONFIG_PPC_BOOK3E
+ bl .start_initialization_book3e
+ b .__after_prom_start
+#else
/* Setup some critical 970 SPRs before switching MMU off */
mfspr r0,SPRN_PVR
srwi r0,r0,16
@@ -297,6 +337,7 @@ _GLOBAL(__start_initialization_multiplatform)
/* Switch off MMU if not already off */
bl .__mmu_off
b .__after_prom_start
+#endif /* CONFIG_PPC_BOOK3E */
_INIT_STATIC(__boot_from_prom)
#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
@@ -359,10 +400,16 @@ _STATIC(__after_prom_start)
* Note: This process overwrites the OF exception vectors.
*/
li r3,0 /* target addr */
+#ifdef CONFIG_PPC_BOOK3E
+ tovirt(r3,r3) /* on booke, we already run at PAGE_OFFSET */
+#endif
mr. r4,r26 /* In some cases the loader may */
beq 9f /* have already put us at zero */
li r6,0x100 /* Start offset, the first 0x100 */
/* bytes were copied earlier. */
+#ifdef CONFIG_PPC_BOOK3E
+ tovirt(r6,r6) /* on booke, we already run at PAGE_OFFSET */
+#endif
#ifdef CONFIG_CRASH_DUMP
/*
@@ -485,7 +532,7 @@ _GLOBAL(pmac_secondary_start)
LOAD_REG_ADDR(r4,paca) /* Get base vaddr of paca array */
mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
add r13,r13,r4 /* for this processor. */
- mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
+ mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/
/* Create a temp kernel stack for use before relocation is on. */
ld r1,PACAEMERGSP(r13)
@@ -503,11 +550,14 @@ _GLOBAL(pmac_secondary_start)
* 1. Processor number
* 2. Segment table pointer (virtual address)
* On entry the following are set:
- * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries
- * r24 = cpu# (in Linux terms)
- * r13 = paca virtual address
- * SPRG3 = paca virtual address
+ * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries
+ * r24 = cpu# (in Linux terms)
+ * r13 = paca virtual address
+ * SPRG_PACA = paca virtual address
*/
+ .section ".text";
+ .align 2 ;
+
.globl __secondary_start
__secondary_start:
/* Set thread priority to MEDIUM */
@@ -544,7 +594,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
mtspr SPRN_SRR0,r3
mtspr SPRN_SRR1,r4
- rfid
+ RFI
b . /* prevent speculative execution */
/*
@@ -565,11 +615,16 @@ _GLOBAL(start_secondary_prolog)
*/
_GLOBAL(enable_64b_mode)
mfmsr r11 /* grab the current MSR */
+#ifdef CONFIG_PPC_BOOK3E
+ oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */
+ mtmsr r11
+#else /* CONFIG_PPC_BOOK3E */
li r12,(MSR_SF | MSR_ISF)@highest
sldi r12,r12,48
or r11,r11,r12
mtmsrd r11
isync
+#endif
blr
/*
@@ -613,9 +668,11 @@ _INIT_STATIC(start_here_multiplatform)
bdnz 3b
4:
+#ifndef CONFIG_PPC_BOOK3E
mfmsr r6
ori r6,r6,MSR_RI
mtmsrd r6 /* RI on */
+#endif
#ifdef CONFIG_RELOCATABLE
/* Save the physical address we're running at in kernstart_addr */
@@ -642,13 +699,13 @@ _INIT_STATIC(start_here_multiplatform)
/* Restore parameters passed from prom_init/kexec */
mr r3,r31
- bl .early_setup /* also sets r13 and SPRG3 */
+ bl .early_setup /* also sets r13 and SPRG_PACA */
LOAD_REG_ADDR(r3, .start_here_common)
ld r4,PACAKMSR(r13)
mtspr SPRN_SRR0,r3
mtspr SPRN_SRR1,r4
- rfid
+ RFI
b . /* prevent speculative execution */
/* This is where all platforms converge execution */
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 52ff8c53b93c..6ded19d01891 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -110,8 +110,8 @@ turn_on_mmu:
* task's thread_struct.
*/
#define EXCEPTION_PROLOG \
- mtspr SPRN_SPRG0,r10; \
- mtspr SPRN_SPRG1,r11; \
+ mtspr SPRN_SPRG_SCRATCH0,r10; \
+ mtspr SPRN_SPRG_SCRATCH1,r11; \
mfcr r10; \
EXCEPTION_PROLOG_1; \
EXCEPTION_PROLOG_2
@@ -121,7 +121,7 @@ turn_on_mmu:
andi. r11,r11,MSR_PR; \
tophys(r11,r1); /* use tophys(r1) if kernel */ \
beq 1f; \
- mfspr r11,SPRN_SPRG3; \
+ mfspr r11,SPRN_SPRG_THREAD; \
lwz r11,THREAD_INFO-THREAD(r11); \
addi r11,r11,THREAD_SIZE; \
tophys(r11,r11); \
@@ -133,9 +133,9 @@ turn_on_mmu:
stw r10,_CCR(r11); /* save registers */ \
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
- mfspr r10,SPRN_SPRG0; \
+ mfspr r10,SPRN_SPRG_SCRATCH0; \
stw r10,GPR10(r11); \
- mfspr r12,SPRN_SPRG1; \
+ mfspr r12,SPRN_SPRG_SCRATCH1; \
stw r12,GPR11(r11); \
mflr r10; \
stw r10,_LINK(r11); \
@@ -603,8 +603,9 @@ start_here:
/* ptr to phys current thread */
tophys(r4,r2)
addi r4,r4,THREAD /* init task's THREAD */
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
li r3,0
+ /* XXX What is that for ? SPRG2 appears otherwise unused on 8xx */
mtspr SPRN_SPRG2,r3 /* 0 => r1 has kernel sp */
/* stack */
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index 5f9febc8d143..50504ae39cb7 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -20,14 +20,14 @@
#endif
#define NORMAL_EXCEPTION_PROLOG \
- mtspr SPRN_SPRG0,r10; /* save two registers to work with */\
- mtspr SPRN_SPRG1,r11; \
- mtspr SPRN_SPRG4W,r1; \
+ mtspr SPRN_SPRG_WSCRATCH0,r10;/* save two registers to work with */\
+ mtspr SPRN_SPRG_WSCRATCH1,r11; \
+ mtspr SPRN_SPRG_WSCRATCH2,r1; \
mfcr r10; /* save CR in r10 for now */\
mfspr r11,SPRN_SRR1; /* check whether user or kernel */\
andi. r11,r11,MSR_PR; \
beq 1f; \
- mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\
+ mfspr r1,SPRN_SPRG_THREAD; /* if from user, start at top of */\
lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\
ALLOC_STACK_FRAME(r1, THREAD_SIZE); \
1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\
@@ -35,13 +35,13 @@
stw r10,_CCR(r11); /* save various registers */\
stw r12,GPR12(r11); \
stw r9,GPR9(r11); \
- mfspr r10,SPRN_SPRG0; \
+ mfspr r10,SPRN_SPRG_RSCRATCH0; \
stw r10,GPR10(r11); \
- mfspr r12,SPRN_SPRG1; \
+ mfspr r12,SPRN_SPRG_RSCRATCH1; \
stw r12,GPR11(r11); \
mflr r10; \
stw r10,_LINK(r11); \
- mfspr r10,SPRN_SPRG4R; \
+ mfspr r10,SPRN_SPRG_RSCRATCH2; \
mfspr r12,SPRN_SRR0; \
stw r10,GPR1(r11); \
mfspr r9,SPRN_SRR1; \
@@ -69,21 +69,11 @@
* providing configurations that micro-optimize space usage.
*/
-/* CRIT_SPRG only used in critical exception handling */
-#define CRIT_SPRG SPRN_SPRG2
-/* MCHECK_SPRG only used in machine check exception handling */
-#define MCHECK_SPRG SPRN_SPRG6W
-
-#define MCHECK_STACK_BASE mcheckirq_ctx
+#define MC_STACK_BASE mcheckirq_ctx
#define CRIT_STACK_BASE critirq_ctx
/* only on e500mc/e200 */
-#define DEBUG_STACK_BASE dbgirq_ctx
-#ifdef CONFIG_E200
-#define DEBUG_SPRG SPRN_SPRG6W
-#else
-#define DEBUG_SPRG SPRN_SPRG9
-#endif
+#define DBG_STACK_BASE dbgirq_ctx
#define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)
@@ -110,7 +100,7 @@
* critical/machine check exception stack at low physical addresses.
*/
#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
- mtspr exc_level##_SPRG,r8; \
+ mtspr SPRN_SPRG_WSCRATCH_##exc_level,r8; \
BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
stw r9,GPR9(r8); /* save various registers */\
mfcr r9; /* save CR in r9 for now */\
@@ -119,7 +109,7 @@
stw r9,_CCR(r8); /* save CR on stack */\
mfspr r10,exc_level_srr1; /* check whether user or kernel */\
andi. r10,r10,MSR_PR; \
- mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\
+ mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\
lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\
beq 1f; \
@@ -140,7 +130,7 @@
lwz r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11); \
stw r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8); \
mr r11,r8; \
-2: mfspr r8,exc_level##_SPRG; \
+2: mfspr r8,SPRN_SPRG_RSCRATCH_##exc_level; \
stw r12,GPR12(r11); /* save various registers */\
mflr r10; \
stw r10,_LINK(r11); \
@@ -161,9 +151,9 @@
#define CRITICAL_EXCEPTION_PROLOG \
EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
#define DEBUG_EXCEPTION_PROLOG \
- EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
+ EXC_LEVEL_EXCEPTION_PROLOG(DBG, SPRN_DSRR0, SPRN_DSRR1)
#define MCHECK_EXCEPTION_PROLOG \
- EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
+ EXC_LEVEL_EXCEPTION_PROLOG(MC, SPRN_MCSRR0, SPRN_MCSRR1)
/*
* Exception vectors.
@@ -282,13 +272,13 @@ label:
mtspr SPRN_DSRR1,r9; \
lwz r9,GPR9(r11); \
lwz r12,GPR12(r11); \
- mtspr DEBUG_SPRG,r8; \
- BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+ mtspr SPRN_SPRG_WSCRATCH_DBG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(DBG); /* r8 points to the debug stack */ \
lwz r10,GPR10(r8); \
lwz r11,GPR11(r8); \
- mfspr r8,DEBUG_SPRG; \
+ mfspr r8,SPRN_SPRG_RSCRATCH_DBG; \
\
- PPC_RFDI; \
+ PPC_RFDI; \
b .; \
\
/* continue normal handling for a debug exception... */ \
@@ -335,11 +325,11 @@ label:
mtspr SPRN_CSRR1,r9; \
lwz r9,GPR9(r11); \
lwz r12,GPR12(r11); \
- mtspr CRIT_SPRG,r8; \
+ mtspr SPRN_SPRG_WSCRATCH_CRIT,r8; \
BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \
lwz r10,GPR10(r8); \
lwz r11,GPR11(r8); \
- mfspr r8,CRIT_SPRG; \
+ mfspr r8,SPRN_SPRG_RSCRATCH_CRIT; \
\
rfci; \
b .; \
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 5bdcc06d294c..eca80482ae72 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -361,7 +361,7 @@ skpinv: addi r6,r6,1 /* Increment */
/* ptr to current thread */
addi r4,r2,THREAD /* init task's THREAD */
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
/* stack */
lis r1,init_thread_union@h
@@ -532,12 +532,12 @@ interrupt_base:
/* Data TLB Error Interrupt */
START_EXCEPTION(DataTLBError)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
- mtspr SPRN_SPRG4W, r12
- mtspr SPRN_SPRG5W, r13
+ mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_WSCRATCH1, r11
+ mtspr SPRN_SPRG_WSCRATCH2, r12
+ mtspr SPRN_SPRG_WSCRATCH3, r13
mfcr r11
- mtspr SPRN_SPRG7W, r11
+ mtspr SPRN_SPRG_WSCRATCH4, r11
mfspr r10, SPRN_DEAR /* Get faulting address */
/* If we are faulting a kernel address, we have to use the
@@ -557,7 +557,7 @@ interrupt_base:
/* Get the PGD for the current thread */
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
4:
@@ -598,12 +598,12 @@ interrupt_base:
/* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out.
*/
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
b DataStorage
/* Instruction TLB Error Interrupt */
@@ -613,12 +613,12 @@ interrupt_base:
* to a different point.
*/
START_EXCEPTION(InstructionTLBError)
- mtspr SPRN_SPRG0, r10 /* Save some working registers */
- mtspr SPRN_SPRG1, r11
- mtspr SPRN_SPRG4W, r12
- mtspr SPRN_SPRG5W, r13
+ mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+ mtspr SPRN_SPRG_WSCRATCH1, r11
+ mtspr SPRN_SPRG_WSCRATCH2, r12
+ mtspr SPRN_SPRG_WSCRATCH3, r13
mfcr r11
- mtspr SPRN_SPRG7W, r11
+ mtspr SPRN_SPRG_WSCRATCH4, r11
mfspr r10, SPRN_SRR0 /* Get faulting address */
/* If we are faulting a kernel address, we have to use the
@@ -638,7 +638,7 @@ interrupt_base:
/* Get the PGD for the current thread */
3:
- mfspr r11,SPRN_SPRG3
+ mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
4:
@@ -666,12 +666,12 @@ interrupt_base:
/* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out.
*/
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
b InstructionStorage
#ifdef CONFIG_SPE
@@ -790,12 +790,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
tlbwe
/* Done...restore registers and get out of here. */
- mfspr r11, SPRN_SPRG7R
+ mfspr r11, SPRN_SPRG_RSCRATCH4
mtcr r11
- mfspr r13, SPRN_SPRG5R
- mfspr r12, SPRN_SPRG4R
- mfspr r11, SPRN_SPRG1
- mfspr r10, SPRN_SPRG0
+ mfspr r13, SPRN_SPRG_RSCRATCH3
+ mfspr r12, SPRN_SPRG_RSCRATCH2
+ mfspr r11, SPRN_SPRG_RSCRATCH1
+ mfspr r10, SPRN_SPRG_RSCRATCH0
rfi /* Force context change */
#ifdef CONFIG_SPE
@@ -839,7 +839,7 @@ load_up_spe:
#endif /* !CONFIG_SMP */
/* enable use of SPE after return */
oris r9,r9,MSR_SPE@h
- mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */
+ mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
li r4,1
li r10,THREAD_ACC
stw r4,THREAD_USED_SPE(r5)
@@ -1118,7 +1118,7 @@ __secondary_start:
/* ptr to current thread */
addi r4,r2,THREAD /* address of our thread_struct */
- mtspr SPRN_SPRG3,r4
+ mtspr SPRN_SPRG_THREAD,r4
/* Setup the defaults for TLB entries */
li r4,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index e9962c7f8a09..d16b1ea55d44 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -13,6 +13,7 @@
#include <asm/lppaca.h>
#include <asm/paca.h>
#include <asm/sections.h>
+#include <asm/pgtable.h>
/* This symbol is provided by the linker - let it fill in the paca
* field correctly */
@@ -87,6 +88,8 @@ void __init initialise_pacas(void)
#ifdef CONFIG_PPC_BOOK3S
new_paca->lppaca_ptr = &lppaca[cpu];
+#else
+ new_paca->kernel_pgd = swapper_pg_dir;
#endif
new_paca->lock_token = 0x8000;
new_paca->paca_index = cpu;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 892a9f2e6d76..678ff132e8b0 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -664,6 +664,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
sp_vsid |= SLB_VSID_KERNEL | llp;
p->thread.ksp_vsid = sp_vsid;
}
+#endif /* CONFIG_PPC_STD_MMU_64 */
/*
* The PPC64 ABI makes use of a TOC to contain function
@@ -671,6 +672,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
* to the TOC entry. The first entry is a pointer to the actual
* function.
*/
+#ifdef CONFIG_PPC64
kregs->nip = *((unsigned long *)ret_from_fork);
#else
kregs->nip = (unsigned long)ret_from_fork;
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index a538824616fd..d942404779c1 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1259,10 +1259,6 @@ static void __init prom_initialize_tce_table(void)
*
* -- Cort
*/
-extern char __secondary_hold;
-extern unsigned long __secondary_hold_spinloop;
-extern unsigned long __secondary_hold_acknowledge;
-
/*
* We want to reference the copy of __secondary_hold_* in the
* 0 - 0x100 address range
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 02fed27af7f6..5cf5833fdea0 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -432,9 +432,9 @@ void __init smp_setup_cpu_maps(void)
for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
DBG(" thread %d -> cpu %d (hard id %d)\n",
j, cpu, intserv[j]);
- cpu_set(cpu, cpu_present_map);
+ set_cpu_present(cpu, true);
set_hard_smp_processor_id(cpu, intserv[j]);
- cpu_set(cpu, cpu_possible_map);
+ set_cpu_possible(cpu, true);
cpu++;
}
}
@@ -480,7 +480,7 @@ void __init smp_setup_cpu_maps(void)
maxcpus);
for (cpu = 0; cpu < maxcpus; cpu++)
- cpu_set(cpu, cpu_possible_map);
+ set_cpu_possible(cpu, true);
out:
of_node_put(dn);
}
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 1f6816003ebe..87df51720641 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -62,6 +62,7 @@
#include <asm/udbg.h>
#include <asm/kexec.h>
#include <asm/swiotlb.h>
+#include <asm/mmu_context.h>
#include "setup.h"
@@ -142,11 +143,14 @@ early_param("smt-enabled", early_smt_enabled);
#define check_smt_enabled()
#endif /* CONFIG_SMP */
-/* Put the paca pointer into r13 and SPRG3 */
+/* Put the paca pointer into r13 and SPRG_PACA */
void __init setup_paca(int cpu)
{
local_paca = &paca[cpu];
- mtspr(SPRN_SPRG3, local_paca);
+ mtspr(SPRN_SPRG_PACA, local_paca);
+#ifdef CONFIG_PPC_BOOK3E
+ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
+#endif
}
/*
@@ -230,9 +234,6 @@ void early_setup_secondary(void)
#endif /* CONFIG_SMP */
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
-extern unsigned long __secondary_hold_spinloop;
-extern void generic_secondary_smp_init(void);
-
void smp_release_cpus(void)
{
unsigned long *ptr;
@@ -453,6 +454,24 @@ static void __init irqstack_early_init(void)
#define irqstack_early_init()
#endif
+#ifdef CONFIG_PPC_BOOK3E
+static void __init exc_lvl_early_init(void)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i) {
+ critirq_ctx[i] = (struct thread_info *)
+ __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+ dbgirq_ctx[i] = (struct thread_info *)
+ __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+ mcheckirq_ctx[i] = (struct thread_info *)
+ __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+ }
+}
+#else
+#define exc_lvl_early_init()
+#endif
+
/*
* Stack space used when we detect a bad kernel stack pointer, and
* early in SMP boots before relocation is enabled.
@@ -512,6 +531,7 @@ void __init setup_arch(char **cmdline_p)
init_mm.brk = klimit;
irqstack_early_init();
+ exc_lvl_early_init();
emergency_stack_init();
#ifdef CONFIG_PPC_STD_MMU_64
@@ -534,6 +554,10 @@ void __init setup_arch(char **cmdline_p)
#endif
paging_init();
+
+ /* Initialize the MMU context management stuff */
+ mmu_context_init();
+
ppc64_boot_msg(0x15, "Setup Done");
}
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 0b47de07302d..608c484188b2 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -189,11 +189,11 @@ void arch_send_call_function_single_ipi(int cpu)
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE);
}
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
unsigned int cpu;
- for_each_cpu_mask(cpu, mask)
+ for_each_cpu(cpu, mask)
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
@@ -284,7 +284,7 @@ void __devinit smp_prepare_boot_cpu(void)
{
BUG_ON(smp_processor_id() != boot_cpuid);
- cpu_set(boot_cpuid, cpu_online_map);
+ set_cpu_online(boot_cpuid, true);
cpu_set(boot_cpuid, per_cpu(cpu_sibling_map, boot_cpuid));
cpu_set(boot_cpuid, per_cpu(cpu_core_map, boot_cpuid));
#ifdef CONFIG_PPC64
@@ -304,7 +304,7 @@ int generic_cpu_disable(void)
if (cpu == boot_cpuid)
return -EBUSY;
- cpu_clear(cpu, cpu_online_map);
+ set_cpu_online(cpu, false);
#ifdef CONFIG_PPC64
vdso_data->processorCount--;
fixup_irqs(cpu_online_map);
@@ -358,7 +358,7 @@ void generic_mach_cpu_die(void)
smp_wmb();
while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
cpu_relax();
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
local_irq_enable();
}
#endif
@@ -505,7 +505,7 @@ int __devinit start_secondary(void *unused)
ipi_call_lock();
notify_cpu_starting(cpu);
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
/* Update sibling maps */
base = cpu_first_thread_in_core(cpu);
for (i = 0; i < threads_per_core; i++) {
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index bb1cfcfdbbbb..1cc5e9e5da96 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -343,6 +343,18 @@ off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
return sys_lseek(fd, (int)offset, origin);
}
+long compat_sys_truncate(const char __user * path, u32 length)
+{
+ /* sign extend length */
+ return sys_truncate(path, (int)length);
+}
+
+long compat_sys_ftruncate(int fd, u32 length)
+{
+ /* sign extend length */
+ return sys_ftruncate(fd, (int)length);
+}
+
/* Note: it is necessary to treat bufsiz as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index acb74a17bbbf..b4b167b33643 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -1,5 +1,5 @@
/*
- * udbg for for NS16550 compatable serial ports
+ * udbg for NS16550 compatable serial ports
*
* Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
*
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ad06d5c75b15..a0abce251d0a 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -203,7 +203,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
} else {
vdso_pagelist = vdso64_pagelist;
vdso_pages = vdso64_pages;
- vdso_base = VDSO64_MBASE;
+ /*
+ * On 64bit we don't have a preferred map address. This
+ * allows get_unmapped_area to find an area near other mmaps
+ * and most likely share a SLB entry.
+ */
+ vdso_base = 0;
}
#else
vdso_pagelist = vdso32_pagelist;
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index ea4d64644d02..67b6916f0e94 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -65,7 +65,7 @@ _GLOBAL(load_up_altivec)
1:
/* enable use of VMX after return */
#ifdef CONFIG_PPC32
- mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */
+ mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
oris r9,r9,MSR_VEC@h
#else
ld r4,PACACURRENT(r13)
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 8ef8a14abc95..244e3658983c 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -37,12 +37,6 @@ jiffies = jiffies_64 + 4;
#endif
SECTIONS
{
- /* Sections to be discarded. */
- /DISCARD/ : {
- *(.exitcall.exit)
- EXIT_DATA
- }
-
. = KERNELBASE;
/*
@@ -298,4 +292,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
_end = . ;
PROVIDE32 (end = .);
+
+ /* Sections to be discarded. */
+ DISCARDS
}
diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c
index 0cef809cec21..f4d1b55aa70b 100644
--- a/arch/powerpc/kvm/44x.c
+++ b/arch/powerpc/kvm/44x.c
@@ -138,7 +138,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
}
-static int kvmppc_44x_init(void)
+static int __init kvmppc_44x_init(void)
{
int r;
@@ -149,7 +149,7 @@ static int kvmppc_44x_init(void)
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), THIS_MODULE);
}
-static void kvmppc_44x_exit(void)
+static void __exit kvmppc_44x_exit(void)
{
kvmppc_booke_exit();
}
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 4a16f472cc18..ff3cb63b8117 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -30,6 +30,7 @@
#include "timing.h"
#include "44x_tlb.h"
+#include "trace.h"
#ifndef PPC44x_TLBE_SIZE
#define PPC44x_TLBE_SIZE PPC44x_TLB_4K
@@ -263,7 +264,7 @@ static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x,
/* XXX set tlb_44x_index to stlb_index? */
- KVMTRACE_1D(STLB_INVAL, &vcpu_44x->vcpu, stlb_index, handler);
+ trace_kvm_stlb_inval(stlb_index);
}
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
@@ -365,8 +366,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
/* Insert shadow mapping into hardware TLB. */
kvmppc_44x_tlbe_set_modified(vcpu_44x, victim);
kvmppc_44x_tlbwe(victim, &stlbe);
- KVMTRACE_5D(STLB_WRITE, vcpu, victim, stlbe.tid, stlbe.word0, stlbe.word1,
- stlbe.word2, handler);
+ trace_kvm_stlb_write(victim, stlbe.tid, stlbe.word0, stlbe.word1,
+ stlbe.word2);
}
/* For a particular guest TLB entry, invalidate the corresponding host TLB
@@ -485,8 +486,8 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index);
}
- KVMTRACE_5D(GTLB_WRITE, vcpu, gtlb_index, tlbe->tid, tlbe->word0,
- tlbe->word1, tlbe->word2, handler);
+ trace_kvm_gtlb_write(gtlb_index, tlbe->tid, tlbe->word0, tlbe->word1,
+ tlbe->word2);
kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
return EMULATE_DONE;
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 5a152a52796f..c29926846613 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -2,8 +2,7 @@
# KVM configuration
#
-config HAVE_KVM_IRQCHIP
- bool
+source "virt/kvm/Kconfig"
menuconfig VIRTUALIZATION
bool "Virtualization"
@@ -59,17 +58,6 @@ config KVM_E500
If unsure, say N.
-config KVM_TRACE
- bool "KVM trace support"
- depends on KVM && MARKERS && SYSFS
- select RELAY
- select DEBUG_FS
- default n
- ---help---
- This option allows reading a trace of kvm-related events through
- relayfs. Note the ABI is not considered stable and will be
- modified in future updates.
-
source drivers/virtio/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 459c7ee580f7..37655fe19f2f 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -8,7 +8,9 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
-common-objs-$(CONFIG_KVM_TRACE) += $(addprefix ../../../virt/kvm/, kvm_trace.o)
+CFLAGS_44x_tlb.o := -I.
+CFLAGS_e500_tlb.o := -I.
+CFLAGS_emulate.o := -I.
kvm-objs := $(common-objs-y) powerpc.o emulate.o
obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 642e4204cf25..e7bf4d029484 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -520,7 +520,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
return kvmppc_core_vcpu_translate(vcpu, tr);
}
-int kvmppc_booke_init(void)
+int __init kvmppc_booke_init(void)
{
unsigned long ivor[16];
unsigned long max_ivor = 0;
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index d0c6f841bbd1..380a78cf484d 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -56,8 +56,8 @@
.macro KVM_HANDLER ivor_nr
_GLOBAL(kvmppc_handler_\ivor_nr)
/* Get pointer to vcpu and record exit number. */
- mtspr SPRN_SPRG0, r4
- mfspr r4, SPRN_SPRG1
+ mtspr SPRN_SPRG_WSCRATCH0, r4
+ mfspr r4, SPRN_SPRG_RVCPU
stw r5, VCPU_GPR(r5)(r4)
stw r6, VCPU_GPR(r6)(r4)
mfctr r5
@@ -95,7 +95,7 @@ _GLOBAL(kvmppc_handler_len)
/* Registers:
- * SPRG0: guest r4
+ * SPRG_SCRATCH0: guest r4
* r4: vcpu pointer
* r5: KVM exit number
*/
@@ -181,7 +181,7 @@ _GLOBAL(kvmppc_resume_host)
stw r3, VCPU_LR(r4)
mfxer r3
stw r3, VCPU_XER(r4)
- mfspr r3, SPRN_SPRG0
+ mfspr r3, SPRN_SPRG_RSCRATCH0
stw r3, VCPU_GPR(r4)(r4)
mfspr r3, SPRN_SRR0
stw r3, VCPU_PC(r4)
@@ -374,7 +374,7 @@ lightweight_exit:
mtspr SPRN_IVPR, r8
/* Save vcpu pointer for the exception handlers. */
- mtspr SPRN_SPRG1, r4
+ mtspr SPRN_SPRG_WVCPU, r4
/* Can't switch the stack pointer until after IVPR is switched,
* because host interrupt handlers would get confused. */
@@ -384,13 +384,13 @@ lightweight_exit:
/* Host interrupt handlers may have clobbered these guest-readable
* SPRGs, so we need to reload them here with the guest's values. */
lwz r3, VCPU_SPRG4(r4)
- mtspr SPRN_SPRG4, r3
+ mtspr SPRN_SPRG4W, r3
lwz r3, VCPU_SPRG5(r4)
- mtspr SPRN_SPRG5, r3
+ mtspr SPRN_SPRG5W, r3
lwz r3, VCPU_SPRG6(r4)
- mtspr SPRN_SPRG6, r3
+ mtspr SPRN_SPRG6W, r3
lwz r3, VCPU_SPRG7(r4)
- mtspr SPRN_SPRG7, r3
+ mtspr SPRN_SPRG7W, r3
#ifdef CONFIG_KVM_EXIT_TIMING
/* save enter time */
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index d8067fd81cdd..64949eef43f1 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -60,9 +60,6 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
kvmppc_e500_tlb_setup(vcpu_e500);
- /* Use the same core vertion as host's */
- vcpu->arch.pvr = mfspr(SPRN_PVR);
-
return 0;
}
@@ -132,7 +129,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
}
-static int kvmppc_e500_init(void)
+static int __init kvmppc_e500_init(void)
{
int r, i;
unsigned long ivor[3];
@@ -160,7 +157,7 @@ static int kvmppc_e500_init(void)
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE);
}
-static void kvmppc_e500_exit(void)
+static void __init kvmppc_e500_exit(void)
{
kvmppc_booke_exit();
}
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index 3f760414b9f8..be95b8d8e3b7 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -180,6 +180,9 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
case SPRN_MMUCSR0:
vcpu->arch.gpr[rt] = 0; break;
+ case SPRN_MMUCFG:
+ vcpu->arch.gpr[rt] = mfspr(SPRN_MMUCFG); break;
+
/* extra exceptions */
case SPRN_IVOR32:
vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index 0e773fc2d5e4..fb1e1dc11ba5 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -22,6 +22,7 @@
#include "../mm/mmu_decl.h"
#include "e500_tlb.h"
+#include "trace.h"
#define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1)
@@ -224,9 +225,8 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel);
stlbe->mas1 = 0;
- KVMTRACE_5D(STLB_INVAL, &vcpu_e500->vcpu, index_of(tlbsel, esel),
- stlbe->mas1, stlbe->mas2, stlbe->mas3, stlbe->mas7,
- handler);
+ trace_kvm_stlb_inval(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
+ stlbe->mas3, stlbe->mas7);
}
static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
@@ -269,7 +269,7 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
tlbsel = (vcpu_e500->mas4 >> 28) & 0x1;
victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
pidsel = (vcpu_e500->mas4 >> 16) & 0xf;
- tsized = (vcpu_e500->mas4 >> 8) & 0xf;
+ tsized = (vcpu_e500->mas4 >> 7) & 0x1f;
vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
| MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]);
@@ -309,7 +309,7 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
vcpu_e500->shadow_pages[tlbsel][esel] = new_page;
/* Force TS=1 IPROT=0 TSIZE=4KB for all guest mappings. */
- stlbe->mas1 = MAS1_TSIZE(BOOKE_PAGESZ_4K)
+ stlbe->mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K)
| MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID;
stlbe->mas2 = (gvaddr & MAS2_EPN)
| e500_shadow_mas2_attrib(gtlbe->mas2,
@@ -319,9 +319,8 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
vcpu_e500->vcpu.arch.msr & MSR_PR);
stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN;
- KVMTRACE_5D(STLB_WRITE, &vcpu_e500->vcpu, index_of(tlbsel, esel),
- stlbe->mas1, stlbe->mas2, stlbe->mas3, stlbe->mas7,
- handler);
+ trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
+ stlbe->mas3, stlbe->mas7);
}
/* XXX only map the one-one case, for now use TLB0 */
@@ -535,9 +534,8 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
gtlbe->mas3 = vcpu_e500->mas3;
gtlbe->mas7 = vcpu_e500->mas7;
- KVMTRACE_5D(GTLB_WRITE, vcpu, vcpu_e500->mas0,
- gtlbe->mas1, gtlbe->mas2, gtlbe->mas3, gtlbe->mas7,
- handler);
+ trace_kvm_gtlb_write(vcpu_e500->mas0, gtlbe->mas1, gtlbe->mas2,
+ gtlbe->mas3, gtlbe->mas7);
/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
if (tlbe_is_host_safe(vcpu, gtlbe)) {
@@ -545,7 +543,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
case 0:
/* TLB0 */
gtlbe->mas1 &= ~MAS1_TSIZE(~0);
- gtlbe->mas1 |= MAS1_TSIZE(BOOKE_PAGESZ_4K);
+ gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K);
stlbsel = 0;
sesel = kvmppc_e500_stlbe_map(vcpu_e500, 0, esel);
@@ -679,14 +677,14 @@ void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500)
/* Insert large initial mapping for guest. */
tlbe = &vcpu_e500->guest_tlb[1][0];
- tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOKE_PAGESZ_256M);
+ tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M);
tlbe->mas2 = 0;
tlbe->mas3 = E500_TLB_SUPER_PERM_MASK;
tlbe->mas7 = 0;
/* 4K map for serial output. Used by kernel wrapper. */
tlbe = &vcpu_e500->guest_tlb[1][1];
- tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOKE_PAGESZ_4K);
+ tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K);
tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G;
tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK;
tlbe->mas7 = 0;
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h
index 45b064b76906..d28e3010a5e2 100644
--- a/arch/powerpc/kvm/e500_tlb.h
+++ b/arch/powerpc/kvm/e500_tlb.h
@@ -16,7 +16,7 @@
#define __KVM_E500_TLB_H__
#include <linux/kvm_host.h>
-#include <asm/mmu-fsl-booke.h>
+#include <asm/mmu-book3e.h>
#include <asm/tlb.h>
#include <asm/kvm_e500.h>
@@ -59,7 +59,7 @@ extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *);
/* TLB helper functions */
static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
{
- return (tlbe->mas1 >> 8) & 0xf;
+ return (tlbe->mas1 >> 7) & 0x1f;
}
static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
@@ -70,7 +70,7 @@ static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
static inline u64 get_tlb_bytes(const struct tlbe *tlbe)
{
unsigned int pgsize = get_tlb_size(tlbe);
- return 1ULL << 10 << (pgsize << 1);
+ return 1ULL << 10 << pgsize;
}
static inline gva_t get_tlb_end(const struct tlbe *tlbe)
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index a561d6e8da1c..7737146af3fb 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -29,6 +29,7 @@
#include <asm/kvm_ppc.h>
#include <asm/disassemble.h>
#include "timing.h"
+#include "trace.h"
#define OP_TRAP 3
@@ -187,7 +188,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
case SPRN_SRR1:
vcpu->arch.gpr[rt] = vcpu->arch.srr1; break;
case SPRN_PVR:
- vcpu->arch.gpr[rt] = vcpu->arch.pvr; break;
+ vcpu->arch.gpr[rt] = mfspr(SPRN_PVR); break;
+ case SPRN_PIR:
+ vcpu->arch.gpr[rt] = mfspr(SPRN_PIR); break;
/* Note: mftb and TBRL/TBWL are user-accessible, so
* the guest can always access the real TB anyways.
@@ -417,7 +420,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
}
}
- KVMTRACE_3D(PPC_INSTR, vcpu, inst, (int)vcpu->arch.pc, emulated, entryexit);
+ trace_kvm_ppc_instr(inst, vcpu->arch.pc, emulated);
if (advance)
vcpu->arch.pc += 4; /* Advance past emulated instruction. */
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 2cf915e51e7e..2a4551f78f60 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -31,25 +31,17 @@
#include "timing.h"
#include "../mm/mmu_decl.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
{
return gfn;
}
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
-{
- return !!(v->arch.pending_exceptions);
-}
-
-int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
-{
- /* do real check here */
- return 1;
-}
-
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
- return !(v->arch.msr & MSR_WE);
+ return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
}
@@ -122,13 +114,17 @@ struct kvm *kvm_arch_create_vm(void)
static void kvmppc_free_vcpus(struct kvm *kvm)
{
unsigned int i;
+ struct kvm_vcpu *vcpu;
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- if (kvm->vcpus[i]) {
- kvm_arch_vcpu_free(kvm->vcpus[i]);
- kvm->vcpus[i] = NULL;
- }
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_arch_vcpu_free(vcpu);
+
+ mutex_lock(&kvm->lock);
+ for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
+ kvm->vcpus[i] = NULL;
+
+ atomic_set(&kvm->online_vcpus, 0);
+ mutex_unlock(&kvm->lock);
}
void kvm_arch_sync_events(struct kvm *kvm)
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
new file mode 100644
index 000000000000..67f219de0455
--- /dev/null
+++ b/arch/powerpc/kvm/trace.h
@@ -0,0 +1,104 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+
+/*
+ * Tracepoint for guest mode entry.
+ */
+TRACE_EVENT(kvm_ppc_instr,
+ TP_PROTO(unsigned int inst, unsigned long pc, unsigned int emulate),
+ TP_ARGS(inst, pc, emulate),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, inst )
+ __field( unsigned long, pc )
+ __field( unsigned int, emulate )
+ ),
+
+ TP_fast_assign(
+ __entry->inst = inst;
+ __entry->pc = pc;
+ __entry->emulate = emulate;
+ ),
+
+ TP_printk("inst %u pc 0x%lx emulate %u\n",
+ __entry->inst, __entry->pc, __entry->emulate)
+);
+
+TRACE_EVENT(kvm_stlb_inval,
+ TP_PROTO(unsigned int stlb_index),
+ TP_ARGS(stlb_index),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, stlb_index )
+ ),
+
+ TP_fast_assign(
+ __entry->stlb_index = stlb_index;
+ ),
+
+ TP_printk("stlb_index %u", __entry->stlb_index)
+);
+
+TRACE_EVENT(kvm_stlb_write,
+ TP_PROTO(unsigned int victim, unsigned int tid, unsigned int word0,
+ unsigned int word1, unsigned int word2),
+ TP_ARGS(victim, tid, word0, word1, word2),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, victim )
+ __field( unsigned int, tid )
+ __field( unsigned int, word0 )
+ __field( unsigned int, word1 )
+ __field( unsigned int, word2 )
+ ),
+
+ TP_fast_assign(
+ __entry->victim = victim;
+ __entry->tid = tid;
+ __entry->word0 = word0;
+ __entry->word1 = word1;
+ __entry->word2 = word2;
+ ),
+
+ TP_printk("victim %u tid %u w0 %u w1 %u w2 %u",
+ __entry->victim, __entry->tid, __entry->word0,
+ __entry->word1, __entry->word2)
+);
+
+TRACE_EVENT(kvm_gtlb_write,
+ TP_PROTO(unsigned int gtlb_index, unsigned int tid, unsigned int word0,
+ unsigned int word1, unsigned int word2),
+ TP_ARGS(gtlb_index, tid, word0, word1, word2),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, gtlb_index )
+ __field( unsigned int, tid )
+ __field( unsigned int, word0 )
+ __field( unsigned int, word1 )
+ __field( unsigned int, word2 )
+ ),
+
+ TP_fast_assign(
+ __entry->gtlb_index = gtlb_index;
+ __entry->tid = tid;
+ __entry->word0 = word0;
+ __entry->word1 = word1;
+ __entry->word2 = word2;
+ ),
+
+ TP_printk("gtlb_index %u tid %u w0 %u w1 %u w2 %u",
+ __entry->gtlb_index, __entry->tid, __entry->word0,
+ __entry->word1, __entry->word2)
+);
+
+#endif /* _TRACE_KVM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 3e68363405b7..6fb8fc8d2fea 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -13,6 +13,7 @@ obj-y := fault.o mem.o pgtable.o gup.o \
pgtable_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \
tlb_nohash_low.o
+obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(CONFIG_WORD_SIZE)e.o
obj-$(CONFIG_PPC64) += mmap_64.o
hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC_STD_MMU_64) += hash_utils_64.o \
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index 14af8cedab70..b13d58932bf6 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -40,7 +40,7 @@ mmu_hash_lock:
* The address is in r4, and r3 contains an access flag:
* _PAGE_RW (0x400) if a write.
* r9 contains the SRR1 value, from which we use the MSR_PR bit.
- * SPRG3 contains the physical address of the current task's thread.
+ * SPRG_THREAD contains the physical address of the current task's thread.
*
* Returns to the caller if the access is illegal or there is no
* mapping for the address. Otherwise it places an appropriate PTE
@@ -68,7 +68,7 @@ _GLOBAL(hash_page)
/* Get PTE (linux-style) and check access */
lis r0,KERNELBASE@h /* check if kernel address */
cmplw 0,r4,r0
- mfspr r8,SPRN_SPRG3 /* current task's THREAD (phys) */
+ mfspr r8,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
ori r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
lwz r5,PGDIR(r8) /* virt page-table root */
blt+ 112f /* assume user more likely */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 9920d6a7cf29..90df6ffe3a43 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -57,8 +57,10 @@ unsigned int mmu_huge_psizes[MMU_PAGE_COUNT] = { }; /* initialize all to 0 */
#define HUGEPTE_CACHE_NAME(psize) (huge_pgtable_cache_name[psize])
static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT] = {
- "unused_4K", "hugepte_cache_64K", "unused_64K_AP",
- "hugepte_cache_1M", "hugepte_cache_16M", "hugepte_cache_16G"
+ [MMU_PAGE_64K] = "hugepte_cache_64K",
+ [MMU_PAGE_1M] = "hugepte_cache_1M",
+ [MMU_PAGE_16M] = "hugepte_cache_16M",
+ [MMU_PAGE_16G] = "hugepte_cache_16G",
};
/* Flag to mark huge PD pointers. This means pmd_bad() and pud_bad()
@@ -305,7 +307,7 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
pmd = pmd_offset(pud, start);
pud_clear(pud);
- pmd_free_tlb(tlb, pmd);
+ pmd_free_tlb(tlb, pmd, start);
}
static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
@@ -348,7 +350,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
pud = pud_offset(pgd, start);
pgd_clear(pgd);
- pud_free_tlb(tlb, pud);
+ pud_free_tlb(tlb, pud, start);
}
/*
@@ -700,6 +702,8 @@ static void __init set_huge_psize(int psize)
if (mmu_huge_psizes[psize] ||
mmu_psize_defs[psize].shift == PAGE_SHIFT)
return;
+ if (WARN_ON(HUGEPTE_CACHE_NAME(psize) == NULL))
+ return;
hugetlb_add_hstate(mmu_psize_defs[psize].shift - PAGE_SHIFT);
switch (mmu_psize_defs[psize].shift) {
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 3de6a0d93824..3ef5084b90ca 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -54,8 +54,6 @@
#endif
#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
phys_addr_t total_memory;
phys_addr_t total_lowmem;
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 68a821add28d..31582329cd67 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -205,6 +205,47 @@ static int __meminit vmemmap_populated(unsigned long start, int page_size)
return 0;
}
+/* On hash-based CPUs, the vmemmap is bolted in the hash table.
+ *
+ * On Book3E CPUs, the vmemmap is currently mapped in the top half of
+ * the vmalloc space using normal page tables, though the size of
+ * pages encoded in the PTEs can be different
+ */
+
+#ifdef CONFIG_PPC_BOOK3E
+static void __meminit vmemmap_create_mapping(unsigned long start,
+ unsigned long page_size,
+ unsigned long phys)
+{
+ /* Create a PTE encoding without page size */
+ unsigned long i, flags = _PAGE_PRESENT | _PAGE_ACCESSED |
+ _PAGE_KERNEL_RW;
+
+ /* PTEs only contain page size encodings up to 32M */
+ BUG_ON(mmu_psize_defs[mmu_vmemmap_psize].enc > 0xf);
+
+ /* Encode the size in the PTE */
+ flags |= mmu_psize_defs[mmu_vmemmap_psize].enc << 8;
+
+ /* For each PTE for that area, map things. Note that we don't
+ * increment phys because all PTEs are of the large size and
+ * thus must have the low bits clear
+ */
+ for (i = 0; i < page_size; i += PAGE_SIZE)
+ BUG_ON(map_kernel_page(start + i, phys, flags));
+}
+#else /* CONFIG_PPC_BOOK3E */
+static void __meminit vmemmap_create_mapping(unsigned long start,
+ unsigned long page_size,
+ unsigned long phys)
+{
+ int mapped = htab_bolt_mapping(start, start + page_size, phys,
+ PAGE_KERNEL, mmu_vmemmap_psize,
+ mmu_kernel_ssize);
+ BUG_ON(mapped < 0);
+}
+#endif /* CONFIG_PPC_BOOK3E */
+
int __meminit vmemmap_populate(struct page *start_page,
unsigned long nr_pages, int node)
{
@@ -215,8 +256,11 @@ int __meminit vmemmap_populate(struct page *start_page,
/* Align to the page size of the linear mapping. */
start = _ALIGN_DOWN(start, page_size);
+ pr_debug("vmemmap_populate page %p, %ld pages, node %d\n",
+ start_page, nr_pages, node);
+ pr_debug(" -> map %lx..%lx\n", start, end);
+
for (; start < end; start += page_size) {
- int mapped;
void *p;
if (vmemmap_populated(start, page_size))
@@ -226,13 +270,10 @@ int __meminit vmemmap_populate(struct page *start_page,
if (!p)
return -ENOMEM;
- pr_debug("vmemmap %08lx allocated at %p, physical %08lx.\n",
- start, p, __pa(p));
+ pr_debug(" * %016lx..%016lx allocated at %p\n",
+ start, start + page_size, p);
- mapped = htab_bolt_mapping(start, start + page_size, __pa(p),
- pgprot_val(PAGE_KERNEL),
- mmu_vmemmap_psize, mmu_kernel_ssize);
- BUG_ON(mapped < 0);
+ vmemmap_create_mapping(start, page_size, __pa(p));
}
return 0;
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index 92a197117d5b..834436d6d6b8 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -25,10 +25,20 @@
* also clear mm->cpu_vm_mask bits when processes are migrated
*/
-#undef DEBUG
-#define DEBUG_STEAL_ONLY
-#undef DEBUG_MAP_CONSISTENCY
-/*#define DEBUG_CLAMP_LAST_CONTEXT 15 */
+#define DEBUG_MAP_CONSISTENCY
+#define DEBUG_CLAMP_LAST_CONTEXT 31
+//#define DEBUG_HARDER
+
+/* We don't use DEBUG because it tends to be compiled in always nowadays
+ * and this would generate way too much output
+ */
+#ifdef DEBUG_HARDER
+#define pr_hard(args...) printk(KERN_DEBUG args)
+#define pr_hardcont(args...) printk(KERN_CONT args)
+#else
+#define pr_hard(args...) do { } while(0)
+#define pr_hardcont(args...) do { } while(0)
+#endif
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -71,7 +81,7 @@ static DEFINE_SPINLOCK(context_lock);
static unsigned int steal_context_smp(unsigned int id)
{
struct mm_struct *mm;
- unsigned int cpu, max;
+ unsigned int cpu, max, i;
max = last_context - first_context;
@@ -89,15 +99,22 @@ static unsigned int steal_context_smp(unsigned int id)
id = first_context;
continue;
}
- pr_devel("[%d] steal context %d from mm @%p\n",
- smp_processor_id(), id, mm);
+ pr_hardcont(" | steal %d from 0x%p", id, mm);
/* Mark this mm has having no context anymore */
mm->context.id = MMU_NO_CONTEXT;
- /* Mark it stale on all CPUs that used this mm */
- for_each_cpu(cpu, mm_cpumask(mm))
- __set_bit(id, stale_map[cpu]);
+ /* Mark it stale on all CPUs that used this mm. For threaded
+ * implementations, we set it on all threads on each core
+ * represented in the mask. A future implementation will use
+ * a core map instead but this will do for now.
+ */
+ for_each_cpu(cpu, mm_cpumask(mm)) {
+ for (i = cpu_first_thread_in_core(cpu);
+ i <= cpu_last_thread_in_core(cpu); i++)
+ __set_bit(id, stale_map[i]);
+ cpu = i - 1;
+ }
return id;
}
@@ -126,7 +143,7 @@ static unsigned int steal_context_up(unsigned int id)
/* Pick up the victim mm */
mm = context_mm[id];
- pr_devel("[%d] steal context %d from mm @%p\n", cpu, id, mm);
+ pr_hardcont(" | steal %d from 0x%p", id, mm);
/* Flush the TLB for that context */
local_flush_tlb_mm(mm);
@@ -179,19 +196,14 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
/* No lockless fast path .. yet */
spin_lock(&context_lock);
-#ifndef DEBUG_STEAL_ONLY
- pr_devel("[%d] activating context for mm @%p, active=%d, id=%d\n",
- cpu, next, next->context.active, next->context.id);
-#endif
+ pr_hard("[%d] activating context for mm @%p, active=%d, id=%d",
+ cpu, next, next->context.active, next->context.id);
#ifdef CONFIG_SMP
/* Mark us active and the previous one not anymore */
next->context.active++;
if (prev) {
-#ifndef DEBUG_STEAL_ONLY
- pr_devel(" old context %p active was: %d\n",
- prev, prev->context.active);
-#endif
+ pr_hardcont(" (old=0x%p a=%d)", prev, prev->context.active);
WARN_ON(prev->context.active < 1);
prev->context.active--;
}
@@ -201,8 +213,14 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
/* If we already have a valid assigned context, skip all that */
id = next->context.id;
- if (likely(id != MMU_NO_CONTEXT))
+ if (likely(id != MMU_NO_CONTEXT)) {
+#ifdef DEBUG_MAP_CONSISTENCY
+ if (context_mm[id] != next)
+ pr_err("MMU: mm 0x%p has id %d but context_mm[%d] says 0x%p\n",
+ next, id, id, context_mm[id]);
+#endif
goto ctxt_ok;
+ }
/* We really don't have a context, let's try to acquire one */
id = next_context;
@@ -217,6 +235,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
id = steal_context_smp(id);
if (id == MMU_NO_CONTEXT)
goto again;
+ goto stolen;
}
#endif /* CONFIG_SMP */
id = steal_context_up(id);
@@ -234,11 +253,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
next_context = id + 1;
context_mm[id] = next;
next->context.id = id;
-
-#ifndef DEBUG_STEAL_ONLY
- pr_devel("[%d] picked up new id %d, nrf is now %d\n",
- cpu, id, nr_free_contexts);
-#endif
+ pr_hardcont(" | new id=%d,nrf=%d", id, nr_free_contexts);
context_check_map();
ctxt_ok:
@@ -247,15 +262,20 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
* local TLB for it and unmark it before we use it
*/
if (test_bit(id, stale_map[cpu])) {
- pr_devel("[%d] flushing stale context %d for mm @%p !\n",
- cpu, id, next);
+ pr_hardcont(" | stale flush %d [%d..%d]",
+ id, cpu_first_thread_in_core(cpu),
+ cpu_last_thread_in_core(cpu));
+
local_flush_tlb_mm(next);
/* XXX This clear should ultimately be part of local_flush_tlb_mm */
- __clear_bit(id, stale_map[cpu]);
+ for (cpu = cpu_first_thread_in_core(cpu);
+ cpu <= cpu_last_thread_in_core(cpu); cpu++)
+ __clear_bit(id, stale_map[cpu]);
}
/* Flick the MMU and release lock */
+ pr_hardcont(" -> %d\n", id);
set_context(id, next->pgd);
spin_unlock(&context_lock);
}
@@ -265,6 +285,8 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
*/
int init_new_context(struct task_struct *t, struct mm_struct *mm)
{
+ pr_hard("initing context for mm @%p\n", mm);
+
mm->context.id = MMU_NO_CONTEXT;
mm->context.active = 0;
@@ -304,7 +326,9 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;
-
+#ifdef CONFIG_HOTPLUG_CPU
+ struct task_struct *p;
+#endif
/* We don't touch CPU 0 map, it's allocated at aboot and kept
* around forever
*/
@@ -323,8 +347,16 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu);
kfree(stale_map[cpu]);
stale_map[cpu] = NULL;
- break;
-#endif
+
+ /* We also clear the cpu_vm_mask bits of CPUs going away */
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ if (p->mm)
+ cpu_mask_clear_cpu(cpu, mm_cpumask(p->mm));
+ }
+ read_unlock(&tasklist_lock);
+ break;
+#endif /* CONFIG_HOTPLUG_CPU */
}
return NOTIFY_OK;
}
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index d1f9c62dc177..d2e5321d5ea6 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -36,21 +36,37 @@ static inline void _tlbil_pid(unsigned int pid)
{
asm volatile ("sync; tlbia; isync" : : : "memory");
}
+#define _tlbil_pid_noind(pid) _tlbil_pid(pid)
+
#else /* CONFIG_40x || CONFIG_8xx */
extern void _tlbil_all(void);
extern void _tlbil_pid(unsigned int pid);
+#ifdef CONFIG_PPC_BOOK3E
+extern void _tlbil_pid_noind(unsigned int pid);
+#else
+#define _tlbil_pid_noind(pid) _tlbil_pid(pid)
+#endif
#endif /* !(CONFIG_40x || CONFIG_8xx) */
/*
* On 8xx, we directly inline tlbie, on others, it's extern
*/
#ifdef CONFIG_8xx
-static inline void _tlbil_va(unsigned long address, unsigned int pid)
+static inline void _tlbil_va(unsigned long address, unsigned int pid,
+ unsigned int tsize, unsigned int ind)
{
asm volatile ("tlbie %0; sync" : : "r" (address) : "memory");
}
-#else /* CONFIG_8xx */
-extern void _tlbil_va(unsigned long address, unsigned int pid);
+#elif defined(CONFIG_PPC_BOOK3E)
+extern void _tlbil_va(unsigned long address, unsigned int pid,
+ unsigned int tsize, unsigned int ind);
+#else
+extern void __tlbil_va(unsigned long address, unsigned int pid);
+static inline void _tlbil_va(unsigned long address, unsigned int pid,
+ unsigned int tsize, unsigned int ind)
+{
+ __tlbil_va(address, pid);
+}
#endif /* CONIFG_8xx */
/*
@@ -58,10 +74,16 @@ extern void _tlbil_va(unsigned long address, unsigned int pid);
* implementation. When that becomes the case, this will be
* an extern.
*/
-static inline void _tlbivax_bcast(unsigned long address, unsigned int pid)
+#ifdef CONFIG_PPC_BOOK3E
+extern void _tlbivax_bcast(unsigned long address, unsigned int pid,
+ unsigned int tsize, unsigned int ind);
+#else
+static inline void _tlbivax_bcast(unsigned long address, unsigned int pid,
+ unsigned int tsize, unsigned int ind)
{
BUG();
}
+#endif
#else /* CONFIG_PPC_MMU_NOHASH */
@@ -99,7 +121,12 @@ extern unsigned int rtas_data, rtas_size;
struct hash_pte;
extern struct hash_pte *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
-#endif
+
+#endif /* CONFIG_PPC32 */
+
+#ifdef CONFIG_PPC64
+extern int map_kernel_page(unsigned long ea, unsigned long pa, int flags);
+#endif /* CONFIG_PPC64 */
extern unsigned long ioremap_bot;
extern unsigned long __max_low_memory;
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 627767d6169b..cafb2a269542 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -30,6 +30,16 @@
#include <asm/tlbflush.h>
#include <asm/tlb.h>
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+#ifdef CONFIG_SMP
+
+/*
+ * Handle batching of page table freeing on SMP. Page tables are
+ * queued up and send to be freed later by RCU in order to avoid
+ * freeing a page table page that is being walked without locks
+ */
+
static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
static unsigned long pte_freelist_forced_free;
@@ -116,6 +126,8 @@ void pte_free_finish(void)
*batchp = NULL;
}
+#endif /* CONFIG_SMP */
+
/*
* Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags()
*/
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index bfa7db6b2fd5..853d5565eed5 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -33,6 +33,8 @@
#include <linux/stddef.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lmb.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
@@ -55,19 +57,36 @@
unsigned long ioremap_bot = IOREMAP_BASE;
+
+#ifdef CONFIG_PPC_MMU_NOHASH
+static void *early_alloc_pgtable(unsigned long size)
+{
+ void *pt;
+
+ if (init_bootmem_done)
+ pt = __alloc_bootmem(size, size, __pa(MAX_DMA_ADDRESS));
+ else
+ pt = __va(lmb_alloc_base(size, size,
+ __pa(MAX_DMA_ADDRESS)));
+ memset(pt, 0, size);
+
+ return pt;
+}
+#endif /* CONFIG_PPC_MMU_NOHASH */
+
/*
- * map_io_page currently only called by __ioremap
- * map_io_page adds an entry to the ioremap page table
+ * map_kernel_page currently only called by __ioremap
+ * map_kernel_page adds an entry to the ioremap page table
* and adds an entry to the HPT, possibly bolting it
*/
-static int map_io_page(unsigned long ea, unsigned long pa, int flags)
+int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
{
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
- if (mem_init_done) {
+ if (slab_is_available()) {
pgdp = pgd_offset_k(ea);
pudp = pud_alloc(&init_mm, pgdp, ea);
if (!pudp)
@@ -81,6 +100,35 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
__pgprot(flags)));
} else {
+#ifdef CONFIG_PPC_MMU_NOHASH
+ /* Warning ! This will blow up if bootmem is not initialized
+ * which our ppc64 code is keen to do that, we'll need to
+ * fix it and/or be more careful
+ */
+ pgdp = pgd_offset_k(ea);
+#ifdef PUD_TABLE_SIZE
+ if (pgd_none(*pgdp)) {
+ pudp = early_alloc_pgtable(PUD_TABLE_SIZE);
+ BUG_ON(pudp == NULL);
+ pgd_populate(&init_mm, pgdp, pudp);
+ }
+#endif /* PUD_TABLE_SIZE */
+ pudp = pud_offset(pgdp, ea);
+ if (pud_none(*pudp)) {
+ pmdp = early_alloc_pgtable(PMD_TABLE_SIZE);
+ BUG_ON(pmdp == NULL);
+ pud_populate(&init_mm, pudp, pmdp);
+ }
+ pmdp = pmd_offset(pudp, ea);
+ if (!pmd_present(*pmdp)) {
+ ptep = early_alloc_pgtable(PAGE_SIZE);
+ BUG_ON(ptep == NULL);
+ pmd_populate_kernel(&init_mm, pmdp, ptep);
+ }
+ ptep = pte_offset_kernel(pmdp, ea);
+ set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
+ __pgprot(flags)));
+#else /* CONFIG_PPC_MMU_NOHASH */
/*
* If the mm subsystem is not fully up, we cannot create a
* linux page table entry for this mapping. Simply bolt an
@@ -93,6 +141,7 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
"memory at %016lx !\n", pa);
return -ENOMEM;
}
+#endif /* !CONFIG_PPC_MMU_NOHASH */
}
return 0;
}
@@ -124,7 +173,7 @@ void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
WARN_ON(size & ~PAGE_MASK);
for (i = 0; i < size; i += PAGE_SIZE)
- if (map_io_page((unsigned long)ea+i, pa+i, flags))
+ if (map_kernel_page((unsigned long)ea+i, pa+i, flags))
return NULL;
return (void __iomem *)ea;
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 5b7038f248b6..6bc8b4aeba5c 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -184,7 +184,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
unsigned long slbie_data = 0;
unsigned long pc = KSTK_EIP(tsk);
unsigned long stack = KSTK_ESP(tsk);
- unsigned long unmapped_base;
+ unsigned long exec_base;
if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) &&
offset <= SLB_CACHE_ENTRIES) {
@@ -212,29 +212,23 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
/*
* preload some userspace segments into the SLB.
+ * Almost all 32 and 64bit PowerPC executables are linked at
+ * 0x10000000 so it makes sense to preload this segment.
*/
- if (test_tsk_thread_flag(tsk, TIF_32BIT))
- unmapped_base = TASK_UNMAPPED_BASE_USER32;
- else
- unmapped_base = TASK_UNMAPPED_BASE_USER64;
+ exec_base = 0x10000000;
- if (is_kernel_addr(pc))
- return;
- slb_allocate(pc);
-
- if (esids_match(pc,stack))
+ if (is_kernel_addr(pc) || is_kernel_addr(stack) ||
+ is_kernel_addr(exec_base))
return;
- if (is_kernel_addr(stack))
- return;
- slb_allocate(stack);
+ slb_allocate(pc);
- if (esids_match(pc,unmapped_base) || esids_match(stack,unmapped_base))
- return;
+ if (!esids_match(pc, stack))
+ slb_allocate(stack);
- if (is_kernel_addr(unmapped_base))
- return;
- slb_allocate(unmapped_base);
+ if (!esids_match(pc, exec_base) &&
+ !esids_match(stack, exec_base))
+ slb_allocate(exec_base);
}
static inline void patch_slb_encoding(unsigned int *insn_addr,
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 98cd1dc2ae75..6e9b69c99856 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -31,7 +31,7 @@ struct stab_entry {
#define NR_STAB_CACHE_ENTRIES 8
static DEFINE_PER_CPU(long, stab_cache_ptr);
-static DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]);
+static DEFINE_PER_CPU(long [NR_STAB_CACHE_ENTRIES], stab_cache);
/*
* Create a segment table entry for the given esid/vsid pair.
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
index 65190587a365..8aaa8b7eb324 100644
--- a/arch/powerpc/mm/tlb_hash32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -71,6 +71,9 @@ void tlb_flush(struct mmu_gather *tlb)
*/
_tlbia();
}
+
+ /* Push out batch of freed page tables */
+ pte_free_finish();
}
/*
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
index 937eb90677d9..2b2f35f6985e 100644
--- a/arch/powerpc/mm/tlb_hash64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -33,11 +33,6 @@
DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
-/* This is declared as we are using the more or less generic
- * arch/powerpc/include/asm/tlb.h file -- tgall
- */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* A linux PTE was changed and the corresponding hash table entry
* neesd to be flushed. This function will either perform the flush
@@ -154,6 +149,21 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
batch->index = 0;
}
+void tlb_flush(struct mmu_gather *tlb)
+{
+ struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
+
+ /* If there's a TLB batch pending, then we must flush it because the
+ * pages are going to be freed and we really don't want to have a CPU
+ * access a freed page because it has a stale TLB
+ */
+ if (tlbbatch->index)
+ __flush_tlb_pending(tlbbatch);
+
+ /* Push out batch of freed page tables */
+ pte_free_finish();
+}
+
/**
* __flush_hash_table_range - Flush all HPTEs for a given address range
* from the hash table (and the TLB). But keeps
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
new file mode 100644
index 000000000000..10d524ded7b2
--- /dev/null
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -0,0 +1,734 @@
+/*
+ * Low leve TLB miss handlers for Book3E
+ *
+ * Copyright (C) 2008-2009
+ * Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/processor.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cputable.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+#include <asm/exception-64e.h>
+#include <asm/ppc-opcode.h>
+
+#ifdef CONFIG_PPC_64K_PAGES
+#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE+1)
+#else
+#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE)
+#endif
+#define VPTE_PUD_SHIFT (VPTE_PMD_SHIFT + PMD_INDEX_SIZE)
+#define VPTE_PGD_SHIFT (VPTE_PUD_SHIFT + PUD_INDEX_SIZE)
+#define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE)
+
+
+/**********************************************************************
+ * *
+ * TLB miss handling for Book3E with TLB reservation and HES support *
+ * *
+ **********************************************************************/
+
+
+/* Data TLB miss */
+ START_EXCEPTION(data_tlb_miss)
+ TLB_MISS_PROLOG
+
+ /* Now we handle the fault proper. We only save DEAR in normal
+ * fault case since that's the only interesting values here.
+ * We could probably also optimize by not saving SRR0/1 in the
+ * linear mapping case but I'll leave that for later
+ */
+ mfspr r14,SPRN_ESR
+ mfspr r16,SPRN_DEAR /* get faulting address */
+ srdi r15,r16,60 /* get region */
+ cmpldi cr0,r15,0xc /* linear mapping ? */
+ TLB_MISS_STATS_SAVE_INFO
+ beq tlb_load_linear /* yes -> go to linear map load */
+
+ /* The page tables are mapped virtually linear. At this point, though,
+ * we don't know whether we are trying to fault in a first level
+ * virtual address or a virtual page table address. We can get that
+ * from bit 0x1 of the region ID which we have set for a page table
+ */
+ andi. r10,r15,0x1
+ bne- virt_page_table_tlb_miss
+
+ std r14,EX_TLB_ESR(r12); /* save ESR */
+ std r16,EX_TLB_DEAR(r12); /* save DEAR */
+
+ /* We need _PAGE_PRESENT and _PAGE_ACCESSED set */
+ li r11,_PAGE_PRESENT
+ oris r11,r11,_PAGE_ACCESSED@h
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+ cmpldi cr0,r15,0 /* Check for user region */
+
+ /* We pre-test some combination of permissions to avoid double
+ * faults:
+ *
+ * We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE
+ * ESR_ST is 0x00800000
+ * _PAGE_BAP_SW is 0x00000010
+ * So the shift is >> 19. This tests for supervisor writeability.
+ * If the page happens to be supervisor writeable and not user
+ * writeable, we will take a new fault later, but that should be
+ * a rare enough case.
+ *
+ * We also move ESR_ST in _PAGE_DIRTY position
+ * _PAGE_DIRTY is 0x00001000 so the shift is >> 11
+ *
+ * MAS1 is preset for all we need except for TID that needs to
+ * be cleared for kernel translations
+ */
+ rlwimi r11,r14,32-19,27,27
+ rlwimi r11,r14,32-16,19,19
+ beq normal_tlb_miss
+ /* XXX replace the RMW cycles with immediate loads + writes */
+1: mfspr r10,SPRN_MAS1
+ cmpldi cr0,r15,8 /* Check for vmalloc region */
+ rlwinm r10,r10,0,16,1 /* Clear TID */
+ mtspr SPRN_MAS1,r10
+ beq+ normal_tlb_miss
+
+ /* We got a crappy address, just fault with whatever DEAR and ESR
+ * are here
+ */
+ TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+
+/* Instruction TLB miss */
+ START_EXCEPTION(instruction_tlb_miss)
+ TLB_MISS_PROLOG
+
+ /* If we take a recursive fault, the second level handler may need
+ * to know whether we are handling a data or instruction fault in
+ * order to get to the right store fault handler. We provide that
+ * info by writing a crazy value in ESR in our exception frame
+ */
+ li r14,-1 /* store to exception frame is done later */
+
+ /* Now we handle the fault proper. We only save DEAR in the non
+ * linear mapping case since we know the linear mapping case will
+ * not re-enter. We could indeed optimize and also not save SRR0/1
+ * in the linear mapping case but I'll leave that for later
+ *
+ * Faulting address is SRR0 which is already in r16
+ */
+ srdi r15,r16,60 /* get region */
+ cmpldi cr0,r15,0xc /* linear mapping ? */
+ TLB_MISS_STATS_SAVE_INFO
+ beq tlb_load_linear /* yes -> go to linear map load */
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+ li r11,_PAGE_PRESENT|_PAGE_HWEXEC /* Base perm */
+ oris r11,r11,_PAGE_ACCESSED@h
+
+ cmpldi cr0,r15,0 /* Check for user region */
+ std r14,EX_TLB_ESR(r12) /* write crazy -1 to frame */
+ beq normal_tlb_miss
+ /* XXX replace the RMW cycles with immediate loads + writes */
+1: mfspr r10,SPRN_MAS1
+ cmpldi cr0,r15,8 /* Check for vmalloc region */
+ rlwinm r10,r10,0,16,1 /* Clear TID */
+ mtspr SPRN_MAS1,r10
+ beq+ normal_tlb_miss
+
+ /* We got a crappy address, just fault */
+ TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_instruction_storage_book3e
+
+/*
+ * This is the guts of the first-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = faulting address
+ * r15 = region ID
+ * r14 = crap (free to use)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = PTE permission mask
+ * r10 = crap (free to use)
+ */
+normal_tlb_miss:
+ /* So we first construct the page table address. We do that by
+ * shifting the bottom of the address (not the region ID) by
+ * PAGE_SHIFT-3, clearing the bottom 3 bits (get a PTE ptr) and
+ * or'ing the fourth high bit.
+ *
+ * NOTE: For 64K pages, we do things slightly differently in
+ * order to handle the weird page table format used by linux
+ */
+ ori r10,r15,0x1
+#ifdef CONFIG_PPC_64K_PAGES
+ /* For the top bits, 16 bytes per PTE */
+ rldicl r14,r16,64-(PAGE_SHIFT-4),PAGE_SHIFT-4+4
+ /* Now create the bottom bits as 0 in position 0x8000 and
+ * the rest calculated for 8 bytes per PTE
+ */
+ rldicl r15,r16,64-(PAGE_SHIFT-3),64-15
+ /* Insert the bottom bits in */
+ rlwimi r14,r15,0,16,31
+#else
+ rldicl r14,r16,64-(PAGE_SHIFT-3),PAGE_SHIFT-3+4
+#endif
+ sldi r15,r10,60
+ clrrdi r14,r14,3
+ or r10,r15,r14
+
+ /* Set the TLB reservation and seach for existing entry. Then load
+ * the entry.
+ */
+ PPC_TLBSRX_DOT(0,r16)
+ ld r14,0(r10)
+ beq normal_tlb_miss_done
+
+finish_normal_tlb_miss:
+ /* Check if required permissions are met */
+ andc. r15,r11,r14
+ bne- normal_tlb_miss_access_fault
+
+ /* Now we build the MAS:
+ *
+ * MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG
+ * MAS 1 : Almost fully setup
+ * - PID already updated by caller if necessary
+ * - TSIZE need change if !base page size, not
+ * yet implemented for now
+ * MAS 2 : Defaults not useful, need to be redone
+ * MAS 3+7 : Needs to be done
+ *
+ * TODO: mix up code below for better scheduling
+ */
+ clrrdi r11,r16,12 /* Clear low crap in EA */
+ rlwimi r11,r14,32-19,27,31 /* Insert WIMGE */
+ mtspr SPRN_MAS2,r11
+
+ /* Check page size, if not standard, update MAS1 */
+ rldicl r11,r14,64-8,64-8
+#ifdef CONFIG_PPC_64K_PAGES
+ cmpldi cr0,r11,BOOK3E_PAGESZ_64K
+#else
+ cmpldi cr0,r11,BOOK3E_PAGESZ_4K
+#endif
+ beq- 1f
+ mfspr r11,SPRN_MAS1
+ rlwimi r11,r14,31,21,24
+ rlwinm r11,r11,0,21,19
+ mtspr SPRN_MAS1,r11
+1:
+ /* Move RPN in position */
+ rldicr r11,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
+ clrldi r15,r11,12 /* Clear crap at the top */
+ rlwimi r15,r14,32-8,22,25 /* Move in U bits */
+ rlwimi r15,r14,32-2,26,31 /* Move in BAP bits */
+
+ /* Mask out SW and UW if !DIRTY (XXX optimize this !) */
+ andi. r11,r14,_PAGE_DIRTY
+ bne 1f
+ li r11,MAS3_SW|MAS3_UW
+ andc r15,r15,r11
+1: mtspr SPRN_MAS7_MAS3,r15
+
+ tlbwe
+
+normal_tlb_miss_done:
+ /* We don't bother with restoring DEAR or ESR since we know we are
+ * level 0 and just going back to userland. They are only needed
+ * if you are going to take an access fault
+ */
+ TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK)
+ TLB_MISS_EPILOG_SUCCESS
+ rfi
+
+normal_tlb_miss_access_fault:
+ /* We need to check if it was an instruction miss */
+ andi. r10,r11,_PAGE_HWEXEC
+ bne 1f
+ ld r14,EX_TLB_DEAR(r12)
+ ld r15,EX_TLB_ESR(r12)
+ mtspr SPRN_DEAR,r14
+ mtspr SPRN_ESR,r15
+ TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+1: TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_instruction_storage_book3e
+
+
+/*
+ * This is the guts of the second-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = virtual page table faulting address
+ * r15 = region (top 4 bits of address)
+ * r14 = crap (free to use)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * Note that this should only ever be called as a second level handler
+ * with the current scheme when using SW load.
+ * That means we can always get the original fault DEAR at
+ * EX_TLB_DEAR-EX_TLB_SIZE(r12)
+ *
+ * It can be re-entered by the linear mapping miss handler. However, to
+ * avoid too much complication, it will restart the whole fault at level
+ * 0 so we don't care too much about clobbers
+ *
+ * XXX That code was written back when we couldn't clobber r14. We can now,
+ * so we could probably optimize things a bit
+ */
+virt_page_table_tlb_miss:
+ /* Are we hitting a kernel page table ? */
+ andi. r10,r15,0x8
+
+ /* The cool thing now is that r10 contains 0 for user and 8 for kernel,
+ * and we happen to have the swapper_pg_dir at offset 8 from the user
+ * pgdir in the PACA :-).
+ */
+ add r11,r10,r13
+
+ /* If kernel, we need to clear MAS1 TID */
+ beq 1f
+ /* XXX replace the RMW cycles with immediate loads + writes */
+ mfspr r10,SPRN_MAS1
+ rlwinm r10,r10,0,16,1 /* Clear TID */
+ mtspr SPRN_MAS1,r10
+1:
+ /* Search if we already have a TLB entry for that virtual address, and
+ * if we do, bail out.
+ */
+ PPC_TLBSRX_DOT(0,r16)
+ beq virt_page_table_tlb_miss_done
+
+ /* Now, we need to walk the page tables. First check if we are in
+ * range.
+ */
+ rldicl. r10,r16,64-(VPTE_INDEX_SIZE+3),VPTE_INDEX_SIZE+3+4
+ bne- virt_page_table_tlb_miss_fault
+
+ /* Get the PGD pointer */
+ ld r15,PACAPGD(r11)
+ cmpldi cr0,r15,0
+ beq- virt_page_table_tlb_miss_fault
+
+ /* Get to PGD entry */
+ rldicl r11,r16,64-VPTE_PGD_SHIFT,64-PGD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq virt_page_table_tlb_miss_fault
+
+#ifndef CONFIG_PPC_64K_PAGES
+ /* Get to PUD entry */
+ rldicl r11,r16,64-VPTE_PUD_SHIFT,64-PUD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq virt_page_table_tlb_miss_fault
+#endif /* CONFIG_PPC_64K_PAGES */
+
+ /* Get to PMD entry */
+ rldicl r11,r16,64-VPTE_PMD_SHIFT,64-PMD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq virt_page_table_tlb_miss_fault
+
+ /* Ok, we're all right, we can now create a kernel translation for
+ * a 4K or 64K page from r16 -> r15.
+ */
+ /* Now we build the MAS:
+ *
+ * MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG
+ * MAS 1 : Almost fully setup
+ * - PID already updated by caller if necessary
+ * - TSIZE for now is base page size always
+ * MAS 2 : Use defaults
+ * MAS 3+7 : Needs to be done
+ *
+ * So we only do MAS 2 and 3 for now...
+ */
+ clrldi r11,r15,4 /* remove region ID from RPN */
+ ori r10,r11,1 /* Or-in SR */
+ mtspr SPRN_MAS7_MAS3,r10
+
+ tlbwe
+
+virt_page_table_tlb_miss_done:
+
+ /* We have overriden MAS2:EPN but currently our primary TLB miss
+ * handler will always restore it so that should not be an issue,
+ * if we ever optimize the primary handler to not write MAS2 on
+ * some cases, we'll have to restore MAS2:EPN here based on the
+ * original fault's DEAR. If we do that we have to modify the
+ * ITLB miss handler to also store SRR0 in the exception frame
+ * as DEAR.
+ *
+ * However, one nasty thing we did is we cleared the reservation
+ * (well, potentially we did). We do a trick here thus if we
+ * are not a level 0 exception (we interrupted the TLB miss) we
+ * offset the return address by -4 in order to replay the tlbsrx
+ * instruction there
+ */
+ subf r10,r13,r12
+ cmpldi cr0,r10,PACA_EXTLB+EX_TLB_SIZE
+ bne- 1f
+ ld r11,PACA_EXTLB+EX_TLB_SIZE+EX_TLB_SRR0(r13)
+ addi r10,r11,-4
+ std r10,PACA_EXTLB+EX_TLB_SIZE+EX_TLB_SRR0(r13)
+1:
+ /* Return to caller, normal case */
+ TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_OK);
+ TLB_MISS_EPILOG_SUCCESS
+ rfi
+
+virt_page_table_tlb_miss_fault:
+ /* If we fault here, things are a little bit tricky. We need to call
+ * either data or instruction store fault, and we need to retreive
+ * the original fault address and ESR (for data).
+ *
+ * The thing is, we know that in normal circumstances, this is
+ * always called as a second level tlb miss for SW load or as a first
+ * level TLB miss for HW load, so we should be able to peek at the
+ * relevant informations in the first exception frame in the PACA.
+ *
+ * However, we do need to double check that, because we may just hit
+ * a stray kernel pointer or a userland attack trying to hit those
+ * areas. If that is the case, we do a data fault. (We can't get here
+ * from an instruction tlb miss anyway).
+ *
+ * Note also that when going to a fault, we must unwind the previous
+ * level as well. Since we are doing that, we don't need to clear or
+ * restore the TLB reservation neither.
+ */
+ subf r10,r13,r12
+ cmpldi cr0,r10,PACA_EXTLB+EX_TLB_SIZE
+ bne- virt_page_table_tlb_miss_whacko_fault
+
+ /* We dig the original DEAR and ESR from slot 0 */
+ ld r15,EX_TLB_DEAR+PACA_EXTLB(r13)
+ ld r16,EX_TLB_ESR+PACA_EXTLB(r13)
+
+ /* We check for the "special" ESR value for instruction faults */
+ cmpdi cr0,r16,-1
+ beq 1f
+ mtspr SPRN_DEAR,r15
+ mtspr SPRN_ESR,r16
+ TLB_MISS_STATS_D(MMSTAT_TLB_MISS_PT_FAULT);
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+1: TLB_MISS_STATS_I(MMSTAT_TLB_MISS_PT_FAULT);
+ TLB_MISS_EPILOG_ERROR
+ b exc_instruction_storage_book3e
+
+virt_page_table_tlb_miss_whacko_fault:
+ /* The linear fault will restart everything so ESR and DEAR will
+ * not have been clobbered, let's just fault with what we have
+ */
+ TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_FAULT);
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+
+
+/**************************************************************
+ * *
+ * TLB miss handling for Book3E with hw page table support *
+ * *
+ **************************************************************/
+
+
+/* Data TLB miss */
+ START_EXCEPTION(data_tlb_miss_htw)
+ TLB_MISS_PROLOG
+
+ /* Now we handle the fault proper. We only save DEAR in normal
+ * fault case since that's the only interesting values here.
+ * We could probably also optimize by not saving SRR0/1 in the
+ * linear mapping case but I'll leave that for later
+ */
+ mfspr r14,SPRN_ESR
+ mfspr r16,SPRN_DEAR /* get faulting address */
+ srdi r11,r16,60 /* get region */
+ cmpldi cr0,r11,0xc /* linear mapping ? */
+ TLB_MISS_STATS_SAVE_INFO
+ beq tlb_load_linear /* yes -> go to linear map load */
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+ cmpldi cr0,r11,0 /* Check for user region */
+ ld r15,PACAPGD(r13) /* Load user pgdir */
+ beq htw_tlb_miss
+
+ /* XXX replace the RMW cycles with immediate loads + writes */
+1: mfspr r10,SPRN_MAS1
+ cmpldi cr0,r11,8 /* Check for vmalloc region */
+ rlwinm r10,r10,0,16,1 /* Clear TID */
+ mtspr SPRN_MAS1,r10
+ ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */
+ beq+ htw_tlb_miss
+
+ /* We got a crappy address, just fault with whatever DEAR and ESR
+ * are here
+ */
+ TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+
+/* Instruction TLB miss */
+ START_EXCEPTION(instruction_tlb_miss_htw)
+ TLB_MISS_PROLOG
+
+ /* If we take a recursive fault, the second level handler may need
+ * to know whether we are handling a data or instruction fault in
+ * order to get to the right store fault handler. We provide that
+ * info by keeping a crazy value for ESR in r14
+ */
+ li r14,-1 /* store to exception frame is done later */
+
+ /* Now we handle the fault proper. We only save DEAR in the non
+ * linear mapping case since we know the linear mapping case will
+ * not re-enter. We could indeed optimize and also not save SRR0/1
+ * in the linear mapping case but I'll leave that for later
+ *
+ * Faulting address is SRR0 which is already in r16
+ */
+ srdi r11,r16,60 /* get region */
+ cmpldi cr0,r11,0xc /* linear mapping ? */
+ TLB_MISS_STATS_SAVE_INFO
+ beq tlb_load_linear /* yes -> go to linear map load */
+
+ /* We do the user/kernel test for the PID here along with the RW test
+ */
+ cmpldi cr0,r11,0 /* Check for user region */
+ ld r15,PACAPGD(r13) /* Load user pgdir */
+ beq htw_tlb_miss
+
+ /* XXX replace the RMW cycles with immediate loads + writes */
+1: mfspr r10,SPRN_MAS1
+ cmpldi cr0,r11,8 /* Check for vmalloc region */
+ rlwinm r10,r10,0,16,1 /* Clear TID */
+ mtspr SPRN_MAS1,r10
+ ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */
+ beq+ htw_tlb_miss
+
+ /* We got a crappy address, just fault */
+ TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_instruction_storage_book3e
+
+
+/*
+ * This is the guts of the second-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = virtual page table faulting address
+ * r15 = PGD pointer
+ * r14 = ESR
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * It can be re-entered by the linear mapping miss handler. However, to
+ * avoid too much complication, it will save/restore things for us
+ */
+htw_tlb_miss:
+ /* Search if we already have a TLB entry for that virtual address, and
+ * if we do, bail out.
+ *
+ * MAS1:IND should be already set based on MAS4
+ */
+ PPC_TLBSRX_DOT(0,r16)
+ beq htw_tlb_miss_done
+
+ /* Now, we need to walk the page tables. First check if we are in
+ * range.
+ */
+ rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
+ bne- htw_tlb_miss_fault
+
+ /* Get the PGD pointer */
+ cmpldi cr0,r15,0
+ beq- htw_tlb_miss_fault
+
+ /* Get to PGD entry */
+ rldicl r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq htw_tlb_miss_fault
+
+#ifndef CONFIG_PPC_64K_PAGES
+ /* Get to PUD entry */
+ rldicl r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq htw_tlb_miss_fault
+#endif /* CONFIG_PPC_64K_PAGES */
+
+ /* Get to PMD entry */
+ rldicl r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3
+ clrrdi r10,r11,3
+ ldx r15,r10,r15
+ cmpldi cr0,r15,0
+ beq htw_tlb_miss_fault
+
+ /* Ok, we're all right, we can now create an indirect entry for
+ * a 1M or 256M page.
+ *
+ * The last trick is now that because we use "half" pages for
+ * the HTW (1M IND is 2K and 256M IND is 32K) we need to account
+ * for an added LSB bit to the RPN. For 64K pages, there is no
+ * problem as we already use 32K arrays (half PTE pages), but for
+ * 4K page we need to extract a bit from the virtual address and
+ * insert it into the "PA52" bit of the RPN.
+ */
+#ifndef CONFIG_PPC_64K_PAGES
+ rlwimi r15,r16,32-9,20,20
+#endif
+ /* Now we build the MAS:
+ *
+ * MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG
+ * MAS 1 : Almost fully setup
+ * - PID already updated by caller if necessary
+ * - TSIZE for now is base ind page size always
+ * MAS 2 : Use defaults
+ * MAS 3+7 : Needs to be done
+ */
+#ifdef CONFIG_PPC_64K_PAGES
+ ori r10,r15,(BOOK3E_PAGESZ_64K << MAS3_SPSIZE_SHIFT)
+#else
+ ori r10,r15,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
+#endif
+ mtspr SPRN_MAS7_MAS3,r10
+
+ tlbwe
+
+htw_tlb_miss_done:
+ /* We don't bother with restoring DEAR or ESR since we know we are
+ * level 0 and just going back to userland. They are only needed
+ * if you are going to take an access fault
+ */
+ TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_OK)
+ TLB_MISS_EPILOG_SUCCESS
+ rfi
+
+htw_tlb_miss_fault:
+ /* We need to check if it was an instruction miss. We know this
+ * though because r14 would contain -1
+ */
+ cmpdi cr0,r14,-1
+ beq 1f
+ mtspr SPRN_DEAR,r16
+ mtspr SPRN_ESR,r14
+ TLB_MISS_STATS_D(MMSTAT_TLB_MISS_PT_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_data_storage_book3e
+1: TLB_MISS_STATS_I(MMSTAT_TLB_MISS_PT_FAULT)
+ TLB_MISS_EPILOG_ERROR
+ b exc_instruction_storage_book3e
+
+/*
+ * This is the guts of "any" level TLB miss handler for kernel linear
+ * mapping misses. We are entered with:
+ *
+ *
+ * r16 = faulting address
+ * r15 = crap (free to use)
+ * r14 = ESR (data) or -1 (instruction)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * In addition we know that we will not re-enter, so in theory, we could
+ * use a simpler epilog not restoring SRR0/1 etc.. but we'll do that later.
+ *
+ * We also need to be careful about MAS registers here & TLB reservation,
+ * as we know we'll have clobbered them if we interrupt the main TLB miss
+ * handlers in which case we probably want to do a full restart at level
+ * 0 rather than saving / restoring the MAS.
+ *
+ * Note: If we care about performance of that core, we can easily shuffle
+ * a few things around
+ */
+tlb_load_linear:
+ /* For now, we assume the linear mapping is contiguous and stops at
+ * linear_map_top. We also assume the size is a multiple of 1G, thus
+ * we only use 1G pages for now. That might have to be changed in a
+ * final implementation, especially when dealing with hypervisors
+ */
+ ld r11,PACATOC(r13)
+ ld r11,linear_map_top@got(r11)
+ ld r10,0(r11)
+ cmpld cr0,r10,r16
+ bge tlb_load_linear_fault
+
+ /* MAS1 need whole new setup. */
+ li r15,(BOOK3E_PAGESZ_1GB<<MAS1_TSIZE_SHIFT)
+ oris r15,r15,MAS1_VALID@h /* MAS1 needs V and TSIZE */
+ mtspr SPRN_MAS1,r15
+
+ /* Already somebody there ? */
+ PPC_TLBSRX_DOT(0,r16)
+ beq tlb_load_linear_done
+
+ /* Now we build the remaining MAS. MAS0 and 2 should be fine
+ * with their defaults, which leaves us with MAS 3 and 7. The
+ * mapping is linear, so we just take the address, clear the
+ * region bits, and or in the permission bits which are currently
+ * hard wired
+ */
+ clrrdi r10,r16,30 /* 1G page index */
+ clrldi r10,r10,4 /* clear region bits */
+ ori r10,r10,MAS3_SR|MAS3_SW|MAS3_SX
+ mtspr SPRN_MAS7_MAS3,r10
+
+ tlbwe
+
+tlb_load_linear_done:
+ /* We use the "error" epilog for success as we do want to
+ * restore to the initial faulting context, whatever it was.
+ * We do that because we can't resume a fault within a TLB
+ * miss handler, due to MAS and TLB reservation being clobbered.
+ */
+ TLB_MISS_STATS_X(MMSTAT_TLB_MISS_LINEAR)
+ TLB_MISS_EPILOG_ERROR
+ rfi
+
+tlb_load_linear_fault:
+ /* We keep the DEAR and ESR around, this shouldn't have happened */
+ cmpdi cr0,r14,-1
+ beq 1f
+ TLB_MISS_EPILOG_ERROR_SPECIAL
+ b exc_data_storage_book3e
+1: TLB_MISS_EPILOG_ERROR_SPECIAL
+ b exc_instruction_storage_book3e
+
+
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+.tlb_stat_inc:
+1: ldarx r8,0,r9
+ addi r8,r8,1
+ stdcx. r8,0,r9
+ bne- 1b
+ blr
+#endif
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index ad2eb4d34dd4..2fbc680c2c71 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -7,8 +7,8 @@
*
* -- BenH
*
- * Copyright 2008 Ben Herrenschmidt <benh@kernel.crashing.org>
- * IBM Corp.
+ * Copyright 2008,2009 Ben Herrenschmidt <benh@kernel.crashing.org>
+ * IBM Corp.
*
* Derived from arch/ppc/mm/init.c:
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -34,12 +34,71 @@
#include <linux/pagemap.h>
#include <linux/preempt.h>
#include <linux/spinlock.h>
+#include <linux/lmb.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>
+#include <asm/code-patching.h>
#include "mmu_decl.h"
+#ifdef CONFIG_PPC_BOOK3E
+struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
+ [MMU_PAGE_4K] = {
+ .shift = 12,
+ .enc = BOOK3E_PAGESZ_4K,
+ },
+ [MMU_PAGE_16K] = {
+ .shift = 14,
+ .enc = BOOK3E_PAGESZ_16K,
+ },
+ [MMU_PAGE_64K] = {
+ .shift = 16,
+ .enc = BOOK3E_PAGESZ_64K,
+ },
+ [MMU_PAGE_1M] = {
+ .shift = 20,
+ .enc = BOOK3E_PAGESZ_1M,
+ },
+ [MMU_PAGE_16M] = {
+ .shift = 24,
+ .enc = BOOK3E_PAGESZ_16M,
+ },
+ [MMU_PAGE_256M] = {
+ .shift = 28,
+ .enc = BOOK3E_PAGESZ_256M,
+ },
+ [MMU_PAGE_1G] = {
+ .shift = 30,
+ .enc = BOOK3E_PAGESZ_1GB,
+ },
+};
+static inline int mmu_get_tsize(int psize)
+{
+ return mmu_psize_defs[psize].enc;
+}
+#else
+static inline int mmu_get_tsize(int psize)
+{
+ /* This isn't used on !Book3E for now */
+ return 0;
+}
+#endif
+
+/* The variables below are currently only used on 64-bit Book3E
+ * though this will probably be made common with other nohash
+ * implementations at some point
+ */
+#ifdef CONFIG_PPC64
+
+int mmu_linear_psize; /* Page size used for the linear mapping */
+int mmu_pte_psize; /* Page size used for PTE pages */
+int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
+int book3e_htw_enabled; /* Is HW tablewalk enabled ? */
+unsigned long linear_map_top; /* Top of linear mapping */
+
+#endif /* CONFIG_PPC64 */
+
/*
* Base TLB flushing operations:
*
@@ -67,18 +126,24 @@ void local_flush_tlb_mm(struct mm_struct *mm)
}
EXPORT_SYMBOL(local_flush_tlb_mm);
-void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+void __local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+ int tsize, int ind)
{
unsigned int pid;
preempt_disable();
- pid = vma ? vma->vm_mm->context.id : 0;
+ pid = mm ? mm->context.id : 0;
if (pid != MMU_NO_CONTEXT)
- _tlbil_va(vmaddr, pid);
+ _tlbil_va(vmaddr, pid, tsize, ind);
preempt_enable();
}
-EXPORT_SYMBOL(local_flush_tlb_page);
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ __local_flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
+ mmu_get_tsize(mmu_virtual_psize), 0);
+}
+EXPORT_SYMBOL(local_flush_tlb_page);
/*
* And here are the SMP non-local implementations
@@ -87,9 +152,17 @@ EXPORT_SYMBOL(local_flush_tlb_page);
static DEFINE_SPINLOCK(tlbivax_lock);
+static int mm_is_core_local(struct mm_struct *mm)
+{
+ return cpumask_subset(mm_cpumask(mm),
+ topology_thread_cpumask(smp_processor_id()));
+}
+
struct tlb_flush_param {
unsigned long addr;
unsigned int pid;
+ unsigned int tsize;
+ unsigned int ind;
};
static void do_flush_tlb_mm_ipi(void *param)
@@ -103,7 +176,7 @@ static void do_flush_tlb_page_ipi(void *param)
{
struct tlb_flush_param *p = param;
- _tlbil_va(p->addr, p->pid);
+ _tlbil_va(p->addr, p->pid, p->tsize, p->ind);
}
@@ -131,7 +204,7 @@ void flush_tlb_mm(struct mm_struct *mm)
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
goto no_context;
- if (!cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+ if (!mm_is_core_local(mm)) {
struct tlb_flush_param p = { .pid = pid };
/* Ignores smp_processor_id() even if set. */
smp_call_function_many(mm_cpumask(mm),
@@ -143,37 +216,49 @@ void flush_tlb_mm(struct mm_struct *mm)
}
EXPORT_SYMBOL(flush_tlb_mm);
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+ int tsize, int ind)
{
struct cpumask *cpu_mask;
unsigned int pid;
preempt_disable();
- pid = vma ? vma->vm_mm->context.id : 0;
+ pid = mm ? mm->context.id : 0;
if (unlikely(pid == MMU_NO_CONTEXT))
goto bail;
- cpu_mask = mm_cpumask(vma->vm_mm);
- if (!cpumask_equal(cpu_mask, cpumask_of(smp_processor_id()))) {
+ cpu_mask = mm_cpumask(mm);
+ if (!mm_is_core_local(mm)) {
/* If broadcast tlbivax is supported, use it */
if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) {
int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL);
if (lock)
spin_lock(&tlbivax_lock);
- _tlbivax_bcast(vmaddr, pid);
+ _tlbivax_bcast(vmaddr, pid, tsize, ind);
if (lock)
spin_unlock(&tlbivax_lock);
goto bail;
} else {
- struct tlb_flush_param p = { .pid = pid, .addr = vmaddr };
+ struct tlb_flush_param p = {
+ .pid = pid,
+ .addr = vmaddr,
+ .tsize = tsize,
+ .ind = ind,
+ };
/* Ignores smp_processor_id() even if set in cpu_mask */
smp_call_function_many(cpu_mask,
do_flush_tlb_page_ipi, &p, 1);
}
}
- _tlbil_va(vmaddr, pid);
+ _tlbil_va(vmaddr, pid, tsize, ind);
bail:
preempt_enable();
}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
+ mmu_get_tsize(mmu_virtual_psize), 0);
+}
EXPORT_SYMBOL(flush_tlb_page);
#endif /* CONFIG_SMP */
@@ -207,3 +292,156 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
flush_tlb_mm(vma->vm_mm);
}
EXPORT_SYMBOL(flush_tlb_range);
+
+void tlb_flush(struct mmu_gather *tlb)
+{
+ flush_tlb_mm(tlb->mm);
+
+ /* Push out batch of freed page tables */
+ pte_free_finish();
+}
+
+/*
+ * Below are functions specific to the 64-bit variant of Book3E though that
+ * may change in the future
+ */
+
+#ifdef CONFIG_PPC64
+
+/*
+ * Handling of virtual linear page tables or indirect TLB entries
+ * flushing when PTE pages are freed
+ */
+void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
+{
+ int tsize = mmu_psize_defs[mmu_pte_psize].enc;
+
+ if (book3e_htw_enabled) {
+ unsigned long start = address & PMD_MASK;
+ unsigned long end = address + PMD_SIZE;
+ unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
+
+ /* This isn't the most optimal, ideally we would factor out the
+ * while preempt & CPU mask mucking around, or even the IPI but
+ * it will do for now
+ */
+ while (start < end) {
+ __flush_tlb_page(tlb->mm, start, tsize, 1);
+ start += size;
+ }
+ } else {
+ unsigned long rmask = 0xf000000000000000ul;
+ unsigned long rid = (address & rmask) | 0x1000000000000000ul;
+ unsigned long vpte = address & ~rmask;
+
+#ifdef CONFIG_PPC_64K_PAGES
+ vpte = (vpte >> (PAGE_SHIFT - 4)) & ~0xfffful;
+#else
+ vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful;
+#endif
+ vpte |= rid;
+ __flush_tlb_page(tlb->mm, vpte, tsize, 0);
+ }
+}
+
+/*
+ * Early initialization of the MMU TLB code
+ */
+static void __early_init_mmu(int boot_cpu)
+{
+ extern unsigned int interrupt_base_book3e;
+ extern unsigned int exc_data_tlb_miss_htw_book3e;
+ extern unsigned int exc_instruction_tlb_miss_htw_book3e;
+
+ unsigned int *ibase = &interrupt_base_book3e;
+ unsigned int mas4;
+
+ /* XXX This will have to be decided at runtime, but right
+ * now our boot and TLB miss code hard wires it. Ideally
+ * we should find out a suitable page size and patch the
+ * TLB miss code (either that or use the PACA to store
+ * the value we want)
+ */
+ mmu_linear_psize = MMU_PAGE_1G;
+
+ /* XXX This should be decided at runtime based on supported
+ * page sizes in the TLB, but for now let's assume 16M is
+ * always there and a good fit (which it probably is)
+ */
+ mmu_vmemmap_psize = MMU_PAGE_16M;
+
+ /* Check if HW tablewalk is present, and if yes, enable it by:
+ *
+ * - patching the TLB miss handlers to branch to the
+ * one dedicates to it
+ *
+ * - setting the global book3e_htw_enabled
+ *
+ * - Set MAS4:INDD and default page size
+ */
+
+ /* XXX This code only checks for TLB 0 capabilities and doesn't
+ * check what page size combos are supported by the HW. It
+ * also doesn't handle the case where a separate array holds
+ * the IND entries from the array loaded by the PT.
+ */
+ if (boot_cpu) {
+ unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+
+ /* Check if HW loader is supported */
+ if ((tlb0cfg & TLBnCFG_IND) &&
+ (tlb0cfg & TLBnCFG_PT)) {
+ patch_branch(ibase + (0x1c0 / 4),
+ (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
+ patch_branch(ibase + (0x1e0 / 4),
+ (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
+ book3e_htw_enabled = 1;
+ }
+ pr_info("MMU: Book3E Page Tables %s\n",
+ book3e_htw_enabled ? "Enabled" : "Disabled");
+ }
+
+ /* Set MAS4 based on page table setting */
+
+ mas4 = 0x4 << MAS4_WIMGED_SHIFT;
+ if (book3e_htw_enabled) {
+ mas4 |= mas4 | MAS4_INDD;
+#ifdef CONFIG_PPC_64K_PAGES
+ mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT;
+ mmu_pte_psize = MMU_PAGE_256M;
+#else
+ mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
+ mmu_pte_psize = MMU_PAGE_1M;
+#endif
+ } else {
+#ifdef CONFIG_PPC_64K_PAGES
+ mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT;
+#else
+ mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
+#endif
+ mmu_pte_psize = mmu_virtual_psize;
+ }
+ mtspr(SPRN_MAS4, mas4);
+
+ /* Set the global containing the top of the linear mapping
+ * for use by the TLB miss code
+ */
+ linear_map_top = lmb_end_of_DRAM();
+
+ /* A sync won't hurt us after mucking around with
+ * the MMU configuration
+ */
+ mb();
+}
+
+void __init early_init_mmu(void)
+{
+ __early_init_mmu(1);
+}
+
+void __cpuinit early_init_mmu_secondary(void)
+{
+ __early_init_mmu(0);
+}
+
+#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index 3037911279b1..7bcd9fbf6cc6 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -39,7 +39,7 @@
/*
* 40x implementation needs only tlbil_va
*/
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
/* We run the search with interrupts disabled because we have to change
* the PID and I don't want to preempt when that happens.
*/
@@ -71,7 +71,7 @@ _GLOBAL(_tlbil_va)
* 440 implementation uses tlbsx/we for tlbil_va and a full sweep
* of the TLB for everything else.
*/
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
mfspr r5,SPRN_MMUCR
rlwimi r5,r4,0,24,31 /* Set TID */
@@ -170,7 +170,7 @@ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBILX)
* Flush MMU TLB for a particular address, but only on the local processor
* (no broadcast)
*/
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
mfmsr r10
wrteei 0
slwi r4,r4,16
@@ -191,6 +191,85 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
isync
1: wrtee r10
blr
+#elif defined(CONFIG_PPC_BOOK3E)
+/*
+ * New Book3E (>= 2.06) implementation
+ *
+ * Note: We may be able to get away without the interrupt masking stuff
+ * if we save/restore MAS6 on exceptions that might modify it
+ */
+_GLOBAL(_tlbil_pid)
+ slwi r4,r3,MAS6_SPID_SHIFT
+ mfmsr r10
+ wrteei 0
+ mtspr SPRN_MAS6,r4
+ PPC_TLBILX_PID(0,0)
+ wrtee r10
+ msync
+ isync
+ blr
+
+_GLOBAL(_tlbil_pid_noind)
+ slwi r4,r3,MAS6_SPID_SHIFT
+ mfmsr r10
+ ori r4,r4,MAS6_SIND
+ wrteei 0
+ mtspr SPRN_MAS6,r4
+ PPC_TLBILX_PID(0,0)
+ wrtee r10
+ msync
+ isync
+ blr
+
+_GLOBAL(_tlbil_all)
+ PPC_TLBILX_ALL(0,0)
+ msync
+ isync
+ blr
+
+_GLOBAL(_tlbil_va)
+ mfmsr r10
+ wrteei 0
+ cmpwi cr0,r6,0
+ slwi r4,r4,MAS6_SPID_SHIFT
+ rlwimi r4,r5,MAS6_ISIZE_SHIFT,MAS6_ISIZE_MASK
+ beq 1f
+ rlwimi r4,r6,MAS6_SIND_SHIFT,MAS6_SIND
+1: mtspr SPRN_MAS6,r4 /* assume AS=0 for now */
+ PPC_TLBILX_VA(0,r3)
+ msync
+ isync
+ wrtee r10
+ blr
+
+_GLOBAL(_tlbivax_bcast)
+ mfmsr r10
+ wrteei 0
+ cmpwi cr0,r6,0
+ slwi r4,r4,MAS6_SPID_SHIFT
+ rlwimi r4,r5,MAS6_ISIZE_SHIFT,MAS6_ISIZE_MASK
+ beq 1f
+ rlwimi r4,r6,MAS6_SIND_SHIFT,MAS6_SIND
+1: mtspr SPRN_MAS6,r4 /* assume AS=0 for now */
+ PPC_TLBIVAX(0,r3)
+ eieio
+ tlbsync
+ sync
+ wrtee r10
+ blr
+
+_GLOBAL(set_context)
+#ifdef CONFIG_BDI_SWITCH
+ /* Context switch the PTE pointer for the Abatron BDI2000.
+ * The PGDIR is the second parameter.
+ */
+ lis r5, abatron_pteptrs@h
+ ori r5, r5, abatron_pteptrs@l
+ stw r4, 0x4(r5)
+#endif
+ mtspr SPRN_PID,r3
+ isync /* Force context change */
+ blr
#else
#error Unsupported processor type !
#endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 60ed9c067b1d..bfb32834ab0c 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -233,6 +233,19 @@ static void __init mpc85xx_mds_setup_arch(void)
/* Turn UCC1 & UCC2 on */
setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
+ } else if (machine_is(mpc8569_mds)) {
+#define BCSR7_UCC12_GETHnRST (0x1 << 2)
+#define BCSR8_UEM_MARVELL_RST (0x1 << 1)
+ /*
+ * U-Boot mangles interrupt polarity for Marvell PHYs,
+ * so reset built-in and UEM Marvell PHYs, this puts
+ * the PHYs into their normal state.
+ */
+ clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+ setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
}
iounmap(bcsr_regs);
}
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 62c592ede641..9f526ba31c1e 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -25,7 +25,6 @@
#include <sysdev/fsl_soc.h>
-extern volatile unsigned long __secondary_hold_acknowledge;
extern void __early_start(void);
#define BOOT_ENTRY_ADDR_UPPER 0
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index d84bbb508ee7..eacea0e3fcc8 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -27,7 +27,6 @@
#include "mpc86xx.h"
extern void __secondary_start_mpc86xx(void);
-extern unsigned long __secondary_hold_acknowledge;
#define MCM_PORT_CONFIG_OFFSET 0x10
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 61187bec7506..9efc8bda01b4 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -57,15 +57,35 @@ config E200
endchoice
-config PPC_BOOK3S_64
- def_bool y
+choice
+ prompt "Processor Type"
depends on PPC64
+ help
+ There are two families of 64 bit PowerPC chips supported.
+ The most common ones are the desktop and server CPUs
+ (POWER3, RS64, POWER4, POWER5, POWER5+, POWER6, ...)
+
+ The other are the "embedded" processors compliant with the
+ "Book 3E" variant of the architecture
+
+config PPC_BOOK3S_64
+ bool "Server processors"
select PPC_FPU
+config PPC_BOOK3E_64
+ bool "Embedded processors"
+ select PPC_FPU # Make it a choice ?
+
+endchoice
+
config PPC_BOOK3S
def_bool y
depends on PPC_BOOK3S_32 || PPC_BOOK3S_64
+config PPC_BOOK3E
+ def_bool y
+ depends on PPC_BOOK3E_64
+
config POWER4_ONLY
bool "Optimize for POWER4"
depends on PPC64 && PPC_BOOK3S
@@ -125,7 +145,7 @@ config 4xx
config BOOKE
bool
- depends on E200 || E500 || 44x
+ depends on E200 || E500 || 44x || PPC_BOOK3E
default y
config FSL_BOOKE
@@ -223,9 +243,17 @@ config PPC_MMU_NOHASH
def_bool y
depends on !PPC_STD_MMU
+config PPC_MMU_NOHASH_32
+ def_bool y
+ depends on PPC_MMU_NOHASH && PPC32
+
+config PPC_MMU_NOHASH_64
+ def_bool y
+ depends on PPC_MMU_NOHASH && PPC64
+
config PPC_BOOK3E_MMU
def_bool y
- depends on FSL_BOOKE
+ depends on FSL_BOOKE || PPC_BOOK3E
config PPC_MM_SLICES
bool
@@ -257,7 +285,7 @@ config PPC_PERF_CTRS
This enables the powerpc-specific perf_counter back-end.
config SMP
- depends on PPC_STD_MMU || FSL_BOOKE
+ depends on PPC_BOOK3S || PPC_BOOK3E || FSL_BOOKE
bool "Symmetric multi-processing support"
---help---
This enables support for systems with more than one CPU. If you have
diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c
index 443035366c12..9290a7a442d0 100644
--- a/arch/powerpc/platforms/amigaone/setup.c
+++ b/arch/powerpc/platforms/amigaone/setup.c
@@ -110,13 +110,16 @@ void __init amigaone_init_IRQ(void)
irq_set_default_host(i8259_get_host());
}
-void __init amigaone_init(void)
+static int __init request_isa_regions(void)
{
request_region(0x00, 0x20, "dma1");
request_region(0x40, 0x20, "timer");
request_region(0x80, 0x10, "dma page reg");
request_region(0xc0, 0x20, "dma2");
+
+ return 0;
}
+machine_device_initcall(amigaone, request_isa_regions);
void amigaone_restart(char *cmd)
{
@@ -161,7 +164,6 @@ define_machine(amigaone) {
.name = "AmigaOne",
.probe = amigaone_probe,
.setup_arch = amigaone_setup_arch,
- .init = amigaone_init,
.show_cpuinfo = amigaone_show_cpuinfo,
.init_IRQ = amigaone_init_IRQ,
.restart = amigaone_restart,
diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c
index 07c234f6b2b6..e53845579770 100644
--- a/arch/powerpc/platforms/cell/celleb_setup.c
+++ b/arch/powerpc/platforms/cell/celleb_setup.c
@@ -80,8 +80,7 @@ static void celleb_show_cpuinfo(struct seq_file *m)
static int __init celleb_machine_type_hack(char *ptr)
{
- strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
- celleb_machine_type[sizeof(celleb_machine_type)-1] = 0;
+ strlcpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
return 0;
}
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index bc97fada48c6..f774530075b7 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -58,8 +58,6 @@
*/
static cpumask_t of_spin_map;
-extern void generic_secondary_smp_init(unsigned long);
-
/**
* smp_startup_cpu() - start the given cpu
*
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
index 2f581521eb9b..5369653dcf6a 100644
--- a/arch/powerpc/platforms/iseries/exception.S
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -47,7 +47,7 @@ system_reset_iSeries:
LOAD_REG_ADDR(r13, paca)
mulli r0,r23,PACA_SIZE
add r13,r13,r0
- mtspr SPRN_SPRG3,r13 /* Save it away for the future */
+ mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */
mfmsr r24
ori r24,r24,MSR_RI
mtmsrd r24 /* RI on */
@@ -116,7 +116,7 @@ iSeries_secondary_smp_loop:
#endif /* CONFIG_SMP */
li r0,-1 /* r0=-1 indicates a Hypervisor call */
sc /* Invoke the hypervisor via a system call */
- mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */
+ mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */
b 2b /* If SMP not configured, secondaries
* loop forever */
@@ -126,34 +126,45 @@ iSeries_secondary_smp_loop:
.globl data_access_iSeries
data_access_iSeries:
- mtspr SPRN_SPRG1,r13
+ mtspr SPRN_SPRG_SCRATCH0,r13
BEGIN_FTR_SECTION
- mtspr SPRN_SPRG2,r12
- mfspr r13,SPRN_DAR
- mfspr r12,SPRN_DSISR
- srdi r13,r13,60
- rlwimi r13,r12,16,0x20
- mfcr r12
- cmpwi r13,0x2c
+ mfspr r13,SPRN_SPRG_PACA
+ std r9,PACA_EXSLB+EX_R9(r13)
+ std r10,PACA_EXSLB+EX_R10(r13)
+ mfspr r10,SPRN_DAR
+ mfspr r9,SPRN_DSISR
+ srdi r10,r10,60
+ rlwimi r10,r9,16,0x20
+ mfcr r9
+ cmpwi r10,0x2c
beq .do_stab_bolted_iSeries
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ ld r10,PACA_EXSLB+EX_R10(r13)
+ std r11,PACA_EXGEN+EX_R11(r13)
+ ld r11,PACA_EXSLB+EX_R9(r13)
+ std r12,PACA_EXGEN+EX_R12(r13)
+ mfspr r12,SPRN_SPRG_SCRATCH0
+ std r10,PACA_EXGEN+EX_R10(r13)
+ std r11,PACA_EXGEN+EX_R9(r13)
+ std r12,PACA_EXGEN+EX_R13(r13)
+ EXCEPTION_PROLOG_ISERIES_1
+FTR_SECTION_ELSE
EXCEPTION_PROLOG_1(PACA_EXGEN)
EXCEPTION_PROLOG_ISERIES_1
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
b data_access_common
.do_stab_bolted_iSeries:
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
- EXCEPTION_PROLOG_1(PACA_EXSLB)
+ std r11,PACA_EXSLB+EX_R11(r13)
+ std r12,PACA_EXSLB+EX_R12(r13)
+ mfspr r10,SPRN_SPRG_SCRATCH0
+ std r10,PACA_EXSLB+EX_R13(r13)
EXCEPTION_PROLOG_ISERIES_1
b .do_stab_bolted
.globl data_access_slb_iSeries
data_access_slb_iSeries:
- mtspr SPRN_SPRG1,r13 /* save r13 */
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
+ mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_DAR
std r9,PACA_EXSLB+EX_R9(r13)
@@ -165,7 +176,7 @@ data_access_slb_iSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
+ mfspr r10,SPRN_SPRG_SCRATCH0
std r10,PACA_EXSLB+EX_R13(r13)
ld r12,PACALPPACAPTR(r13)
ld r12,LPPACASRR1(r12)
@@ -175,8 +186,8 @@ data_access_slb_iSeries:
.globl instruction_access_slb_iSeries
instruction_access_slb_iSeries:
- mtspr SPRN_SPRG1,r13 /* save r13 */
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
+ mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
ld r3,PACALPPACAPTR(r13)
ld r3,LPPACASRR0(r3) /* get SRR0 value */
@@ -189,7 +200,7 @@ instruction_access_slb_iSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
+ mfspr r10,SPRN_SPRG_SCRATCH0
std r10,PACA_EXSLB+EX_R13(r13)
ld r12,PACALPPACAPTR(r13)
ld r12,LPPACASRR1(r12)
@@ -200,7 +211,7 @@ slb_miss_user_iseries:
std r10,PACA_EXGEN+EX_R10(r13)
std r11,PACA_EXGEN+EX_R11(r13)
std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r10,SPRG1
+ mfspr r10,SPRG_SCRATCH0
ld r11,PACA_EXSLB+EX_R9(r13)
ld r12,PACA_EXSLB+EX_R3(r13)
std r10,PACA_EXGEN+EX_R13(r13)
@@ -221,7 +232,7 @@ slb_miss_user_iseries:
.globl system_call_iSeries
system_call_iSeries:
mr r9,r13
- mfspr r13,SPRN_SPRG3
+ mfspr r13,SPRN_SPRG_PACA
EXCEPTION_PROLOG_ISERIES_1
b system_call_common
diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h
index ced45a8fa1aa..bae3fba5ad8e 100644
--- a/arch/powerpc/platforms/iseries/exception.h
+++ b/arch/powerpc/platforms/iseries/exception.h
@@ -24,7 +24,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/exception.h>
+#include <asm/exception-64s.h>
#define EXCEPTION_PROLOG_ISERIES_1 \
mfmsr r10; \
@@ -38,7 +38,7 @@
.globl label##_iSeries; \
label##_iSeries: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
EXCEPTION_PROLOG_1(area); \
EXCEPTION_PROLOG_ISERIES_1; \
b label##_common
@@ -47,7 +47,7 @@ label##_iSeries: \
.globl label##_iSeries; \
label##_iSeries: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
EXCEPTION_PROLOG_1(PACA_EXGEN); \
lbz r10,PACASOFTIRQEN(r13); \
cmpwi 0,r10,0; \
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 6d4da7b46b41..b40c22d697f0 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -320,7 +320,7 @@ static int __init smp_psurge_probe(void)
if (ncpus > NR_CPUS)
ncpus = NR_CPUS;
for (i = 1; i < ncpus ; ++i)
- cpu_set(i, cpu_present_map);
+ set_cpu_present(i, true);
if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
@@ -408,7 +408,7 @@ static void __init smp_psurge_setup_cpu(int cpu_nr)
/* reset the entry point so if we get another intr we won't
* try to startup again */
out_be32(psurge_start, 0x100);
- if (setup_irq(30, &psurge_irqaction))
+ if (setup_irq(irq_create_mapping(NULL, 30), &psurge_irqaction))
printk(KERN_ERR "Couldn't get primary IPI interrupt");
}
@@ -867,7 +867,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
int smp_core99_cpu_disable(void)
{
- cpu_clear(smp_processor_id(), cpu_online_map);
+ set_cpu_online(smp_processor_id(), false);
/* XXX reset cpu affinity here */
mpic_cpu_set_priority(0xf);
@@ -952,7 +952,7 @@ void __init pmac_setup_smp(void)
int cpu;
for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
- cpu_set(cpu, cpu_possible_map);
+ set_cpu_possible(cpu, true);
smp_ops = &psurge_smp_ops;
}
#endif /* CONFIG_PPC32 */
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 572771fd8463..9490157da62e 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -1,5 +1,5 @@
/*
- * udbg for for zilog scc ports as found on Apple PowerMacs
+ * udbg for zilog scc ports as found on Apple PowerMacs
*
* Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
*
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index f6e04bcc70ef..51ffde40af2b 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -37,7 +37,7 @@
*/
#define MSG_COUNT 4
-static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]);
+static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
static void do_message_pass(int target, int msg)
{
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index a20ead87153d..ebff6d9a4e39 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -94,7 +94,7 @@ static int pseries_cpu_disable(void)
{
int cpu = smp_processor_id();
- cpu_clear(cpu, cpu_online_map);
+ set_cpu_online(cpu, false);
vdso_data->processorCount--;
/*fix boot_cpuid here*/
@@ -185,7 +185,7 @@ static int pseries_add_processor(struct device_node *np)
for_each_cpu_mask(cpu, tmp) {
BUG_ON(cpu_isset(cpu, cpu_present_map));
- cpu_set(cpu, cpu_present_map);
+ set_cpu_present(cpu, true);
set_hard_smp_processor_id(cpu, *intserv++);
}
err = 0;
@@ -217,7 +217,7 @@ static void pseries_remove_processor(struct device_node *np)
if (get_hard_smp_processor_id(cpu) != intserv[i])
continue;
BUG_ON(cpu_online(cpu));
- cpu_clear(cpu, cpu_present_map);
+ set_cpu_present(cpu, false);
set_hard_smp_processor_id(cpu, -1);
break;
}
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 1f8f6cfb94f7..440000cc7130 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -56,8 +56,6 @@
*/
static cpumask_t of_spin_map;
-extern void generic_secondary_smp_init(unsigned long);
-
/**
* smp_startup_cpu() - start the given cpu
*
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 3981ae4cb58e..30c44e6b0413 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -230,14 +230,16 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne
{
unsigned int isu = src_no >> mpic->isu_shift;
unsigned int idx = src_no & mpic->isu_mask;
+ unsigned int val;
+ val = _mpic_read(mpic->reg_type, &mpic->isus[isu],
+ reg + (idx * MPIC_INFO(IRQ_STRIDE)));
#ifdef CONFIG_MPIC_BROKEN_REGREAD
if (reg == 0)
- return mpic->isu_reg0_shadow[idx];
- else
+ val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) |
+ mpic->isu_reg0_shadow[src_no];
#endif
- return _mpic_read(mpic->reg_type, &mpic->isus[isu],
- reg + (idx * MPIC_INFO(IRQ_STRIDE)));
+ return val;
}
static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
@@ -251,7 +253,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
#ifdef CONFIG_MPIC_BROKEN_REGREAD
if (reg == 0)
- mpic->isu_reg0_shadow[idx] = value;
+ mpic->isu_reg0_shadow[src_no] =
+ value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY);
#endif
}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index e1f33a81e5e1..0e09a45ac79a 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2570,7 +2570,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
printf("%s", after);
}
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
static void dump_slb(void)
{
int i;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 2ae5d72f47ed..47836b945d03 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -95,7 +95,6 @@ config S390
select HAVE_ARCH_TRACEHOOK
select INIT_ALL_POSSIBLE
select HAVE_PERF_COUNTERS
- select GENERIC_ATOMIC64 if !64BIT
config SCHED_OMIT_FRAME_POINTER
bool
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 0ff387cebf88..fc8fb20e7fc0 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -88,8 +88,7 @@ LDFLAGS_vmlinux := -e start
head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
- arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \
- arch/s390/power/
+ arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
libs-y += arch/s390/lib/
drivers-y += drivers/s390/
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 4aba83b31596..2bc479ab3a66 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -250,8 +250,9 @@ static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
const u8 *temp_key = key;
u32 *flags = &tfm->crt_flags;
- if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
- *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE)) &&
+ (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
@@ -411,9 +412,9 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
- DES_KEY_SIZE))) {
-
- *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+ DES_KEY_SIZE)) &&
+ (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index e85ba348722a..4a943789c208 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -46,12 +46,38 @@ static int sha1_init(struct shash_desc *desc)
return 0;
}
+static int sha1_export(struct shash_desc *desc, void *out)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *octx = out;
+
+ octx->count = sctx->count;
+ memcpy(octx->state, sctx->state, sizeof(octx->state));
+ memcpy(octx->buffer, sctx->buf, sizeof(octx->buffer));
+ return 0;
+}
+
+static int sha1_import(struct shash_desc *desc, const u8 *in)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *ictx = in;
+
+ sctx->count = ictx->count;
+ memcpy(sctx->state, ictx->state, sizeof(ictx->state));
+ memcpy(sctx->buf, ictx->buffer, sizeof(ictx->buffer));
+ sctx->func = KIMD_SHA_1;
+ return 0;
+}
+
static struct shash_alg alg = {
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_init,
.update = s390_sha_update,
.final = s390_sha_final,
+ .export = sha1_export,
+ .import = sha1_import,
.descsize = sizeof(struct s390_sha_ctx),
+ .statesize = sizeof(struct sha1_state),
.base = {
.cra_name = "sha1",
.cra_driver_name= "sha1-s390",
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index f9fefc569632..2bab5197789f 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -42,12 +42,38 @@ static int sha256_init(struct shash_desc *desc)
return 0;
}
+static int sha256_export(struct shash_desc *desc, void *out)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *octx = out;
+
+ octx->count = sctx->count;
+ memcpy(octx->state, sctx->state, sizeof(octx->state));
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+ return 0;
+}
+
+static int sha256_import(struct shash_desc *desc, const u8 *in)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *ictx = in;
+
+ sctx->count = ictx->count;
+ memcpy(sctx->state, ictx->state, sizeof(ictx->state));
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+ sctx->func = KIMD_SHA_256;
+ return 0;
+}
+
static struct shash_alg alg = {
.digestsize = SHA256_DIGEST_SIZE,
.init = sha256_init,
.update = s390_sha_update,
.final = s390_sha_final,
+ .export = sha256_export,
+ .import = sha256_import,
.descsize = sizeof(struct s390_sha_ctx),
+ .statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha256",
.cra_driver_name= "sha256-s390",
diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c
index 83192bfc8048..b4b3438ae77e 100644
--- a/arch/s390/crypto/sha512_s390.c
+++ b/arch/s390/crypto/sha512_s390.c
@@ -13,7 +13,10 @@
*
*/
#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include "sha.h"
@@ -37,12 +40,42 @@ static int sha512_init(struct shash_desc *desc)
return 0;
}
+static int sha512_export(struct shash_desc *desc, void *out)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *octx = out;
+
+ octx->count[0] = sctx->count;
+ octx->count[1] = 0;
+ memcpy(octx->state, sctx->state, sizeof(octx->state));
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+ return 0;
+}
+
+static int sha512_import(struct shash_desc *desc, const u8 *in)
+{
+ struct s390_sha_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *ictx = in;
+
+ if (unlikely(ictx->count[1]))
+ return -ERANGE;
+ sctx->count = ictx->count[0];
+
+ memcpy(sctx->state, ictx->state, sizeof(ictx->state));
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+ sctx->func = KIMD_SHA_512;
+ return 0;
+}
+
static struct shash_alg sha512_alg = {
.digestsize = SHA512_DIGEST_SIZE,
.init = sha512_init,
.update = s390_sha_update,
.final = s390_sha_final,
+ .export = sha512_export,
+ .import = sha512_import,
.descsize = sizeof(struct s390_sha_ctx),
+ .statesize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha512",
.cra_driver_name= "sha512-s390",
@@ -78,7 +111,10 @@ static struct shash_alg sha384_alg = {
.init = sha384_init,
.update = s390_sha_update,
.final = s390_sha_final,
+ .export = sha512_export,
+ .import = sha512_import,
.descsize = sizeof(struct s390_sha_ctx),
+ .statesize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha384",
.cra_driver_name= "sha384-s390",
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index c7d0abfb0f00..ae7c8f9f94a5 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -1,33 +1,23 @@
#ifndef __ARCH_S390_ATOMIC__
#define __ARCH_S390_ATOMIC__
-#include <linux/compiler.h>
-#include <linux/types.h>
-
/*
- * include/asm-s390/atomic.h
+ * Copyright 1999,2009 IBM Corp.
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ * Denis Joseph Barrow,
+ * Arnd Bergmann <arndb@de.ibm.com>,
*
- * S390 version
- * Copyright (C) 1999-2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- * Denis Joseph Barrow,
- * Arnd Bergmann (arndb@de.ibm.com)
- *
- * Derived from "include/asm-i386/bitops.h"
- * Copyright (C) 1992, Linus Torvalds
+ * Atomic operations that C can't guarantee us.
+ * Useful for resource counting etc.
+ * s390 uses 'Compare And Swap' for atomicity in SMP enviroment.
*
*/
-/*
- * Atomic operations that C can't guarantee us. Useful for
- * resource counting etc..
- * S390 uses 'Compare And Swap' for atomicity in SMP enviroment
- */
+#include <linux/compiler.h>
+#include <linux/types.h>
#define ATOMIC_INIT(i) { (i) }
-#ifdef __KERNEL__
-
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CS_LOOP(ptr, op_val, op_string) ({ \
@@ -77,7 +67,7 @@ static inline void atomic_set(atomic_t *v, int i)
barrier();
}
-static __inline__ int atomic_add_return(int i, atomic_t * v)
+static inline int atomic_add_return(int i, atomic_t *v)
{
return __CS_LOOP(v, i, "ar");
}
@@ -87,7 +77,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
#define atomic_inc_return(_v) atomic_add_return(1, _v)
#define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0)
-static __inline__ int atomic_sub_return(int i, atomic_t * v)
+static inline int atomic_sub_return(int i, atomic_t *v)
{
return __CS_LOOP(v, i, "sr");
}
@@ -97,19 +87,19 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
#define atomic_dec_return(_v) atomic_sub_return(1, _v)
#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0)
-static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t * v)
+static inline void atomic_clear_mask(unsigned long mask, atomic_t *v)
{
- __CS_LOOP(v, ~mask, "nr");
+ __CS_LOOP(v, ~mask, "nr");
}
-static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v)
+static inline void atomic_set_mask(unsigned long mask, atomic_t *v)
{
- __CS_LOOP(v, mask, "or");
+ __CS_LOOP(v, mask, "or");
}
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new)
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
asm volatile(
@@ -127,7 +117,7 @@ static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new)
return old;
}
-static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
{
int c, old;
c = atomic_read(v);
@@ -146,9 +136,10 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
#undef __CS_LOOP
-#ifdef __s390x__
#define ATOMIC64_INIT(i) { (i) }
+#ifdef CONFIG_64BIT
+
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
@@ -162,7 +153,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
: "=&d" (old_val), "=&d" (new_val), \
"=Q" (((atomic_t *)(ptr))->counter) \
: "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \
- : "cc", "memory" ); \
+ : "cc", "memory"); \
new_val; \
})
@@ -180,7 +171,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
"=m" (((atomic_t *)(ptr))->counter) \
: "a" (ptr), "d" (op_val), \
"m" (((atomic_t *)(ptr))->counter) \
- : "cc", "memory" ); \
+ : "cc", "memory"); \
new_val; \
})
@@ -198,39 +189,29 @@ static inline void atomic64_set(atomic64_t *v, long long i)
barrier();
}
-static __inline__ long long atomic64_add_return(long long i, atomic64_t * v)
+static inline long long atomic64_add_return(long long i, atomic64_t *v)
{
return __CSG_LOOP(v, i, "agr");
}
-#define atomic64_add(_i, _v) atomic64_add_return(_i, _v)
-#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0)
-#define atomic64_inc(_v) atomic64_add_return(1, _v)
-#define atomic64_inc_return(_v) atomic64_add_return(1, _v)
-#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0)
-static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v)
+static inline long long atomic64_sub_return(long long i, atomic64_t *v)
{
return __CSG_LOOP(v, i, "sgr");
}
-#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v)
-#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0)
-#define atomic64_dec(_v) atomic64_sub_return(1, _v)
-#define atomic64_dec_return(_v) atomic64_sub_return(1, _v)
-#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0)
-static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v)
+static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v)
{
- __CSG_LOOP(v, ~mask, "ngr");
+ __CSG_LOOP(v, ~mask, "ngr");
}
-static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v)
+static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v)
{
- __CSG_LOOP(v, mask, "ogr");
+ __CSG_LOOP(v, mask, "ogr");
}
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
-static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
+static inline long long atomic64_cmpxchg(atomic64_t *v,
long long old, long long new)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
@@ -249,8 +230,112 @@ static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
return old;
}
-static __inline__ int atomic64_add_unless(atomic64_t *v,
- long long a, long long u)
+#undef __CSG_LOOP
+
+#else /* CONFIG_64BIT */
+
+typedef struct {
+ long long counter;
+} atomic64_t;
+
+static inline long long atomic64_read(const atomic64_t *v)
+{
+ register_pair rp;
+
+ asm volatile(
+ " lm %0,%N0,0(%1)"
+ : "=&d" (rp)
+ : "a" (&v->counter), "m" (v->counter)
+ );
+ return rp.pair;
+}
+
+static inline void atomic64_set(atomic64_t *v, long long i)
+{
+ register_pair rp = {.pair = i};
+
+ asm volatile(
+ " stm %1,%N1,0(%2)"
+ : "=m" (v->counter)
+ : "d" (rp), "a" (&v->counter)
+ );
+}
+
+static inline long long atomic64_xchg(atomic64_t *v, long long new)
+{
+ register_pair rp_new = {.pair = new};
+ register_pair rp_old;
+
+ asm volatile(
+ " lm %0,%N0,0(%2)\n"
+ "0: cds %0,%3,0(%2)\n"
+ " jl 0b\n"
+ : "=&d" (rp_old), "+m" (v->counter)
+ : "a" (&v->counter), "d" (rp_new)
+ : "cc");
+ return rp_old.pair;
+}
+
+static inline long long atomic64_cmpxchg(atomic64_t *v,
+ long long old, long long new)
+{
+ register_pair rp_old = {.pair = old};
+ register_pair rp_new = {.pair = new};
+
+ asm volatile(
+ " cds %0,%3,0(%2)"
+ : "+&d" (rp_old), "+m" (v->counter)
+ : "a" (&v->counter), "d" (rp_new)
+ : "cc");
+ return rp_old.pair;
+}
+
+
+static inline long long atomic64_add_return(long long i, atomic64_t *v)
+{
+ long long old, new;
+
+ do {
+ old = atomic64_read(v);
+ new = old + i;
+ } while (atomic64_cmpxchg(v, old, new) != old);
+ return new;
+}
+
+static inline long long atomic64_sub_return(long long i, atomic64_t *v)
+{
+ long long old, new;
+
+ do {
+ old = atomic64_read(v);
+ new = old - i;
+ } while (atomic64_cmpxchg(v, old, new) != old);
+ return new;
+}
+
+static inline void atomic64_set_mask(unsigned long long mask, atomic64_t *v)
+{
+ long long old, new;
+
+ do {
+ old = atomic64_read(v);
+ new = old | mask;
+ } while (atomic64_cmpxchg(v, old, new) != old);
+}
+
+static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
+{
+ long long old, new;
+
+ do {
+ old = atomic64_read(v);
+ new = old & mask;
+ } while (atomic64_cmpxchg(v, old, new) != old);
+}
+
+#endif /* CONFIG_64BIT */
+
+static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
{
long long c, old;
c = atomic64_read(v);
@@ -265,15 +350,17 @@ static __inline__ int atomic64_add_unless(atomic64_t *v,
return c != u;
}
-#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
-
-#undef __CSG_LOOP
-
-#else /* __s390x__ */
-
-#include <asm-generic/atomic64.h>
-
-#endif /* __s390x__ */
+#define atomic64_add(_i, _v) atomic64_add_return(_i, _v)
+#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0)
+#define atomic64_inc(_v) atomic64_add_return(1, _v)
+#define atomic64_inc_return(_v) atomic64_add_return(1, _v)
+#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0)
+#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v)
+#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0)
+#define atomic64_dec(_v) atomic64_sub_return(1, _v)
+#define atomic64_dec_return(_v) atomic64_sub_return(1, _v)
+#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0)
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
@@ -281,5 +368,5 @@ static __inline__ int atomic64_add_unless(atomic64_t *v,
#define smp_mb__after_atomic_inc() smp_mb()
#include <asm-generic/atomic-long.h>
-#endif /* __KERNEL__ */
+
#endif /* __ARCH_S390_ATOMIC__ */
diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h
index d5a8e7c1477c..6c00f6800a34 100644
--- a/arch/s390/include/asm/checksum.h
+++ b/arch/s390/include/asm/checksum.h
@@ -78,28 +78,11 @@ csum_partial_copy_nocheck (const void *src, void *dst, int len, __wsum sum)
*/
static inline __sum16 csum_fold(__wsum sum)
{
-#ifndef __s390x__
- register_pair rp;
+ u32 csum = (__force u32) sum;
- asm volatile(
- " slr %N1,%N1\n" /* %0 = H L */
- " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
- " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
- " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
- " alr %0,%1\n" /* %0 = H+L+C L+H */
- " srl %0,16\n" /* %0 = H+L+C */
- : "+&d" (sum), "=d" (rp) : : "cc");
-#else /* __s390x__ */
- asm volatile(
- " sr 3,3\n" /* %0 = H*65536 + L */
- " lr 2,%0\n" /* %0 = H L, 2/3 = H L / 0 0 */
- " srdl 2,16\n" /* %0 = H L, 2/3 = 0 H / L 0 */
- " alr 2,3\n" /* %0 = H L, 2/3 = L H / L 0 */
- " alr %0,2\n" /* %0 = H+L+C L+H */
- " srl %0,16\n" /* %0 = H+L+C */
- : "+&d" (sum) : : "cc", "2", "3");
-#endif /* __s390x__ */
- return (__force __sum16) ~sum;
+ csum += (csum >> 16) + (csum << 16);
+ csum >>= 16;
+ return (__force __sum16) ~csum;
}
/*
diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/asm/chsc.h
index 807997f7414b..4943654ed7fd 100644
--- a/arch/s390/include/asm/chsc.h
+++ b/arch/s390/include/asm/chsc.h
@@ -125,4 +125,32 @@ struct chsc_cpd_info {
#define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info)
#define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal)
+#ifdef __KERNEL__
+
+struct css_general_char {
+ u64 : 12;
+ u32 dynio : 1; /* bit 12 */
+ u32 : 28;
+ u32 aif : 1; /* bit 41 */
+ u32 : 3;
+ u32 mcss : 1; /* bit 45 */
+ u32 fcs : 1; /* bit 46 */
+ u32 : 1;
+ u32 ext_mb : 1; /* bit 48 */
+ u32 : 7;
+ u32 aif_tdd : 1; /* bit 56 */
+ u32 : 1;
+ u32 qebsm : 1; /* bit 58 */
+ u32 : 8;
+ u32 aif_osa : 1; /* bit 67 */
+ u32 : 14;
+ u32 cib : 1; /* bit 82 */
+ u32 : 5;
+ u32 fcx : 1; /* bit 88 */
+ u32 : 7;
+}__attribute__((packed));
+
+extern struct css_general_char css_general_characteristics;
+
+#endif /* __KERNEL__ */
#endif
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index 619bf94b11f1..e85679af54dd 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -15,228 +15,7 @@
#define LPM_ANYPATH 0xff
#define __MAX_CSSID 0
-/**
- * struct cmd_scsw - command-mode subchannel status word
- * @key: subchannel key
- * @sctl: suspend control
- * @eswf: esw format
- * @cc: deferred condition code
- * @fmt: format
- * @pfch: prefetch
- * @isic: initial-status interruption control
- * @alcc: address-limit checking control
- * @ssi: suppress-suspended interruption
- * @zcc: zero condition code
- * @ectl: extended control
- * @pno: path not operational
- * @res: reserved
- * @fctl: function control
- * @actl: activity control
- * @stctl: status control
- * @cpa: channel program address
- * @dstat: device status
- * @cstat: subchannel status
- * @count: residual count
- */
-struct cmd_scsw {
- __u32 key : 4;
- __u32 sctl : 1;
- __u32 eswf : 1;
- __u32 cc : 2;
- __u32 fmt : 1;
- __u32 pfch : 1;
- __u32 isic : 1;
- __u32 alcc : 1;
- __u32 ssi : 1;
- __u32 zcc : 1;
- __u32 ectl : 1;
- __u32 pno : 1;
- __u32 res : 1;
- __u32 fctl : 3;
- __u32 actl : 7;
- __u32 stctl : 5;
- __u32 cpa;
- __u32 dstat : 8;
- __u32 cstat : 8;
- __u32 count : 16;
-} __attribute__ ((packed));
-
-/**
- * struct tm_scsw - transport-mode subchannel status word
- * @key: subchannel key
- * @eswf: esw format
- * @cc: deferred condition code
- * @fmt: format
- * @x: IRB-format control
- * @q: interrogate-complete
- * @ectl: extended control
- * @pno: path not operational
- * @fctl: function control
- * @actl: activity control
- * @stctl: status control
- * @tcw: TCW address
- * @dstat: device status
- * @cstat: subchannel status
- * @fcxs: FCX status
- * @schxs: subchannel-extended status
- */
-struct tm_scsw {
- u32 key:4;
- u32 :1;
- u32 eswf:1;
- u32 cc:2;
- u32 fmt:3;
- u32 x:1;
- u32 q:1;
- u32 :1;
- u32 ectl:1;
- u32 pno:1;
- u32 :1;
- u32 fctl:3;
- u32 actl:7;
- u32 stctl:5;
- u32 tcw;
- u32 dstat:8;
- u32 cstat:8;
- u32 fcxs:8;
- u32 schxs:8;
-} __attribute__ ((packed));
-
-/**
- * union scsw - subchannel status word
- * @cmd: command-mode SCSW
- * @tm: transport-mode SCSW
- */
-union scsw {
- struct cmd_scsw cmd;
- struct tm_scsw tm;
-} __attribute__ ((packed));
-
-int scsw_is_tm(union scsw *scsw);
-u32 scsw_key(union scsw *scsw);
-u32 scsw_eswf(union scsw *scsw);
-u32 scsw_cc(union scsw *scsw);
-u32 scsw_ectl(union scsw *scsw);
-u32 scsw_pno(union scsw *scsw);
-u32 scsw_fctl(union scsw *scsw);
-u32 scsw_actl(union scsw *scsw);
-u32 scsw_stctl(union scsw *scsw);
-u32 scsw_dstat(union scsw *scsw);
-u32 scsw_cstat(union scsw *scsw);
-int scsw_is_solicited(union scsw *scsw);
-int scsw_is_valid_key(union scsw *scsw);
-int scsw_is_valid_eswf(union scsw *scsw);
-int scsw_is_valid_cc(union scsw *scsw);
-int scsw_is_valid_ectl(union scsw *scsw);
-int scsw_is_valid_pno(union scsw *scsw);
-int scsw_is_valid_fctl(union scsw *scsw);
-int scsw_is_valid_actl(union scsw *scsw);
-int scsw_is_valid_stctl(union scsw *scsw);
-int scsw_is_valid_dstat(union scsw *scsw);
-int scsw_is_valid_cstat(union scsw *scsw);
-int scsw_cmd_is_valid_key(union scsw *scsw);
-int scsw_cmd_is_valid_sctl(union scsw *scsw);
-int scsw_cmd_is_valid_eswf(union scsw *scsw);
-int scsw_cmd_is_valid_cc(union scsw *scsw);
-int scsw_cmd_is_valid_fmt(union scsw *scsw);
-int scsw_cmd_is_valid_pfch(union scsw *scsw);
-int scsw_cmd_is_valid_isic(union scsw *scsw);
-int scsw_cmd_is_valid_alcc(union scsw *scsw);
-int scsw_cmd_is_valid_ssi(union scsw *scsw);
-int scsw_cmd_is_valid_zcc(union scsw *scsw);
-int scsw_cmd_is_valid_ectl(union scsw *scsw);
-int scsw_cmd_is_valid_pno(union scsw *scsw);
-int scsw_cmd_is_valid_fctl(union scsw *scsw);
-int scsw_cmd_is_valid_actl(union scsw *scsw);
-int scsw_cmd_is_valid_stctl(union scsw *scsw);
-int scsw_cmd_is_valid_dstat(union scsw *scsw);
-int scsw_cmd_is_valid_cstat(union scsw *scsw);
-int scsw_cmd_is_solicited(union scsw *scsw);
-int scsw_tm_is_valid_key(union scsw *scsw);
-int scsw_tm_is_valid_eswf(union scsw *scsw);
-int scsw_tm_is_valid_cc(union scsw *scsw);
-int scsw_tm_is_valid_fmt(union scsw *scsw);
-int scsw_tm_is_valid_x(union scsw *scsw);
-int scsw_tm_is_valid_q(union scsw *scsw);
-int scsw_tm_is_valid_ectl(union scsw *scsw);
-int scsw_tm_is_valid_pno(union scsw *scsw);
-int scsw_tm_is_valid_fctl(union scsw *scsw);
-int scsw_tm_is_valid_actl(union scsw *scsw);
-int scsw_tm_is_valid_stctl(union scsw *scsw);
-int scsw_tm_is_valid_dstat(union scsw *scsw);
-int scsw_tm_is_valid_cstat(union scsw *scsw);
-int scsw_tm_is_valid_fcxs(union scsw *scsw);
-int scsw_tm_is_valid_schxs(union scsw *scsw);
-int scsw_tm_is_solicited(union scsw *scsw);
-
-#define SCSW_FCTL_CLEAR_FUNC 0x1
-#define SCSW_FCTL_HALT_FUNC 0x2
-#define SCSW_FCTL_START_FUNC 0x4
-
-#define SCSW_ACTL_SUSPENDED 0x1
-#define SCSW_ACTL_DEVACT 0x2
-#define SCSW_ACTL_SCHACT 0x4
-#define SCSW_ACTL_CLEAR_PEND 0x8
-#define SCSW_ACTL_HALT_PEND 0x10
-#define SCSW_ACTL_START_PEND 0x20
-#define SCSW_ACTL_RESUME_PEND 0x40
-
-#define SCSW_STCTL_STATUS_PEND 0x1
-#define SCSW_STCTL_SEC_STATUS 0x2
-#define SCSW_STCTL_PRIM_STATUS 0x4
-#define SCSW_STCTL_INTER_STATUS 0x8
-#define SCSW_STCTL_ALERT_STATUS 0x10
-
-#define DEV_STAT_ATTENTION 0x80
-#define DEV_STAT_STAT_MOD 0x40
-#define DEV_STAT_CU_END 0x20
-#define DEV_STAT_BUSY 0x10
-#define DEV_STAT_CHN_END 0x08
-#define DEV_STAT_DEV_END 0x04
-#define DEV_STAT_UNIT_CHECK 0x02
-#define DEV_STAT_UNIT_EXCEP 0x01
-
-#define SCHN_STAT_PCI 0x80
-#define SCHN_STAT_INCORR_LEN 0x40
-#define SCHN_STAT_PROG_CHECK 0x20
-#define SCHN_STAT_PROT_CHECK 0x10
-#define SCHN_STAT_CHN_DATA_CHK 0x08
-#define SCHN_STAT_CHN_CTRL_CHK 0x04
-#define SCHN_STAT_INTF_CTRL_CHK 0x02
-#define SCHN_STAT_CHAIN_CHECK 0x01
-
-/*
- * architectured values for first sense byte
- */
-#define SNS0_CMD_REJECT 0x80
-#define SNS_CMD_REJECT SNS0_CMD_REJEC
-#define SNS0_INTERVENTION_REQ 0x40
-#define SNS0_BUS_OUT_CHECK 0x20
-#define SNS0_EQUIPMENT_CHECK 0x10
-#define SNS0_DATA_CHECK 0x08
-#define SNS0_OVERRUN 0x04
-#define SNS0_INCOMPL_DOMAIN 0x01
-
-/*
- * architectured values for second sense byte
- */
-#define SNS1_PERM_ERR 0x80
-#define SNS1_INV_TRACK_FORMAT 0x40
-#define SNS1_EOC 0x20
-#define SNS1_MESSAGE_TO_OPER 0x10
-#define SNS1_NO_REC_FOUND 0x08
-#define SNS1_FILE_PROTECTED 0x04
-#define SNS1_WRITE_INHIBITED 0x02
-#define SNS1_INPRECISE_END 0x01
-
-/*
- * architectured values for third sense byte
- */
-#define SNS2_REQ_INH_WRITE 0x80
-#define SNS2_CORRECTABLE 0x40
-#define SNS2_FIRST_LOG_ERR 0x20
-#define SNS2_ENV_DATA_PRESENT 0x10
-#define SNS2_INPRECISE_END 0x04
+#include <asm/scsw.h>
/**
* struct ccw1 - channel command word
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 1171e6d144a3..5e95d95450b3 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -57,6 +57,8 @@ struct ipl_block_fcp {
} __attribute__((packed));
#define DIAG308_VMPARM_SIZE 64
+#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \
+ offsetof(struct ipl_block_fcp, scp_data)))
struct ipl_block_ccw {
u8 load_parm[8];
@@ -91,7 +93,8 @@ extern void do_halt(void);
extern void do_poff(void);
extern void ipl_save_parameters(void);
extern void ipl_update_parameters(void);
-extern void get_ipl_vmparm(char *);
+extern size_t append_ipl_vmparm(char *, size_t);
+extern size_t append_ipl_scpdata(char *, size_t);
enum {
IPL_DEVNO_VALID = 1,
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h
index 0b2f829f6d50..3dfcaeb5d7f4 100644
--- a/arch/s390/include/asm/kvm.h
+++ b/arch/s390/include/asm/kvm.h
@@ -15,15 +15,6 @@
*/
#include <linux/types.h>
-/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
-struct kvm_pic_state {
- /* no PIC for s390 */
-};
-
-struct kvm_ioapic_state {
- /* no IOAPIC for s390 */
-};
-
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 1cd02f6073a0..78e07a622b45 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -1,7 +1,7 @@
/*
* asm-s390/kvm_host.h - definition for kernel virtual machines on s390
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -40,7 +40,11 @@ struct sca_block {
struct sca_entry cpu[64];
} __attribute__((packed));
-#define KVM_PAGES_PER_HPAGE 256
+#define KVM_NR_PAGE_SIZES 2
+#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + ((x) - 1) * 8)
+#define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
+#define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1))
+#define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
#define CPUSTAT_HOST 0x80000000
#define CPUSTAT_WAIT 0x10000000
@@ -182,8 +186,9 @@ struct kvm_s390_interrupt_info {
};
/* for local_interrupt.action_flags */
-#define ACTION_STORE_ON_STOP 1
-#define ACTION_STOP_ON_STOP 2
+#define ACTION_STORE_ON_STOP (1<<0)
+#define ACTION_STOP_ON_STOP (1<<1)
+#define ACTION_RELOADVCPU_ON_STOP (1<<2)
struct kvm_s390_local_interrupt {
spinlock_t lock;
@@ -227,8 +232,6 @@ struct kvm_vm_stat {
};
struct kvm_arch{
- unsigned long guest_origin;
- unsigned long guest_memsize;
struct sca_block *sca;
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h
index 408d60b4f75b..f7ad8719d02d 100644
--- a/arch/s390/include/asm/percpu.h
+++ b/arch/s390/include/asm/percpu.h
@@ -1,37 +1,21 @@
#ifndef __ARCH_S390_PERCPU__
#define __ARCH_S390_PERCPU__
-#include <linux/compiler.h>
-#include <asm/lowcore.h>
-
/*
* s390 uses its own implementation for per cpu data, the offset of
* the cpu local data area is cached in the cpu's lowcore memory.
- * For 64 bit module code s390 forces the use of a GOT slot for the
- * address of the per cpu variable. This is needed because the module
- * may be more than 4G above the per cpu area.
*/
-#if defined(__s390x__) && defined(MODULE)
-
-#define SHIFT_PERCPU_PTR(ptr,offset) (({ \
- extern int simple_identifier_##var(void); \
- unsigned long *__ptr; \
- asm ( "larl %0, %1@GOTENT" \
- : "=a" (__ptr) : "X" (ptr) ); \
- (typeof(ptr))((*__ptr) + (offset)); }))
-
-#else
-
-#define SHIFT_PERCPU_PTR(ptr, offset) (({ \
- extern int simple_identifier_##var(void); \
- unsigned long __ptr; \
- asm ( "" : "=a" (__ptr) : "0" (ptr) ); \
- (typeof(ptr)) (__ptr + (offset)); }))
+#define __my_cpu_offset S390_lowcore.percpu_offset
+/*
+ * For 64 bit module code, the module may be more than 4G above the
+ * per cpu area, use weak definitions to force the compiler to
+ * generate external references.
+ */
+#if defined(CONFIG_SMP) && defined(__s390x__) && defined(MODULE)
+#define ARCH_NEEDS_WEAK_PER_CPU
#endif
-#define __my_cpu_offset S390_lowcore.percpu_offset
-
#include <asm-generic/percpu.h>
#endif /* __ARCH_S390_PERCPU__ */
diff --git a/drivers/s390/cio/scsw.c b/arch/s390/include/asm/scsw.h
index f8da25ab576d..de389cb54d28 100644
--- a/drivers/s390/cio/scsw.c
+++ b/arch/s390/include/asm/scsw.h
@@ -1,15 +1,182 @@
/*
* Helper functions for scsw access.
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
+#ifndef _ASM_S390_SCSW_H_
+#define _ASM_S390_SCSW_H_
+
#include <linux/types.h>
-#include <linux/module.h>
+#include <asm/chsc.h>
#include <asm/cio.h>
-#include "css.h"
-#include "chsc.h"
+
+/**
+ * struct cmd_scsw - command-mode subchannel status word
+ * @key: subchannel key
+ * @sctl: suspend control
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @pfch: prefetch
+ * @isic: initial-status interruption control
+ * @alcc: address-limit checking control
+ * @ssi: suppress-suspended interruption
+ * @zcc: zero condition code
+ * @ectl: extended control
+ * @pno: path not operational
+ * @res: reserved
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @cpa: channel program address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @count: residual count
+ */
+struct cmd_scsw {
+ __u32 key : 4;
+ __u32 sctl : 1;
+ __u32 eswf : 1;
+ __u32 cc : 2;
+ __u32 fmt : 1;
+ __u32 pfch : 1;
+ __u32 isic : 1;
+ __u32 alcc : 1;
+ __u32 ssi : 1;
+ __u32 zcc : 1;
+ __u32 ectl : 1;
+ __u32 pno : 1;
+ __u32 res : 1;
+ __u32 fctl : 3;
+ __u32 actl : 7;
+ __u32 stctl : 5;
+ __u32 cpa;
+ __u32 dstat : 8;
+ __u32 cstat : 8;
+ __u32 count : 16;
+} __attribute__ ((packed));
+
+/**
+ * struct tm_scsw - transport-mode subchannel status word
+ * @key: subchannel key
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @x: IRB-format control
+ * @q: interrogate-complete
+ * @ectl: extended control
+ * @pno: path not operational
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @tcw: TCW address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @fcxs: FCX status
+ * @schxs: subchannel-extended status
+ */
+struct tm_scsw {
+ u32 key:4;
+ u32 :1;
+ u32 eswf:1;
+ u32 cc:2;
+ u32 fmt:3;
+ u32 x:1;
+ u32 q:1;
+ u32 :1;
+ u32 ectl:1;
+ u32 pno:1;
+ u32 :1;
+ u32 fctl:3;
+ u32 actl:7;
+ u32 stctl:5;
+ u32 tcw;
+ u32 dstat:8;
+ u32 cstat:8;
+ u32 fcxs:8;
+ u32 schxs:8;
+} __attribute__ ((packed));
+
+/**
+ * union scsw - subchannel status word
+ * @cmd: command-mode SCSW
+ * @tm: transport-mode SCSW
+ */
+union scsw {
+ struct cmd_scsw cmd;
+ struct tm_scsw tm;
+} __attribute__ ((packed));
+
+#define SCSW_FCTL_CLEAR_FUNC 0x1
+#define SCSW_FCTL_HALT_FUNC 0x2
+#define SCSW_FCTL_START_FUNC 0x4
+
+#define SCSW_ACTL_SUSPENDED 0x1
+#define SCSW_ACTL_DEVACT 0x2
+#define SCSW_ACTL_SCHACT 0x4
+#define SCSW_ACTL_CLEAR_PEND 0x8
+#define SCSW_ACTL_HALT_PEND 0x10
+#define SCSW_ACTL_START_PEND 0x20
+#define SCSW_ACTL_RESUME_PEND 0x40
+
+#define SCSW_STCTL_STATUS_PEND 0x1
+#define SCSW_STCTL_SEC_STATUS 0x2
+#define SCSW_STCTL_PRIM_STATUS 0x4
+#define SCSW_STCTL_INTER_STATUS 0x8
+#define SCSW_STCTL_ALERT_STATUS 0x10
+
+#define DEV_STAT_ATTENTION 0x80
+#define DEV_STAT_STAT_MOD 0x40
+#define DEV_STAT_CU_END 0x20
+#define DEV_STAT_BUSY 0x10
+#define DEV_STAT_CHN_END 0x08
+#define DEV_STAT_DEV_END 0x04
+#define DEV_STAT_UNIT_CHECK 0x02
+#define DEV_STAT_UNIT_EXCEP 0x01
+
+#define SCHN_STAT_PCI 0x80
+#define SCHN_STAT_INCORR_LEN 0x40
+#define SCHN_STAT_PROG_CHECK 0x20
+#define SCHN_STAT_PROT_CHECK 0x10
+#define SCHN_STAT_CHN_DATA_CHK 0x08
+#define SCHN_STAT_CHN_CTRL_CHK 0x04
+#define SCHN_STAT_INTF_CTRL_CHK 0x02
+#define SCHN_STAT_CHAIN_CHECK 0x01
+
+/*
+ * architectured values for first sense byte
+ */
+#define SNS0_CMD_REJECT 0x80
+#define SNS_CMD_REJECT SNS0_CMD_REJEC
+#define SNS0_INTERVENTION_REQ 0x40
+#define SNS0_BUS_OUT_CHECK 0x20
+#define SNS0_EQUIPMENT_CHECK 0x10
+#define SNS0_DATA_CHECK 0x08
+#define SNS0_OVERRUN 0x04
+#define SNS0_INCOMPL_DOMAIN 0x01
+
+/*
+ * architectured values for second sense byte
+ */
+#define SNS1_PERM_ERR 0x80
+#define SNS1_INV_TRACK_FORMAT 0x40
+#define SNS1_EOC 0x20
+#define SNS1_MESSAGE_TO_OPER 0x10
+#define SNS1_NO_REC_FOUND 0x08
+#define SNS1_FILE_PROTECTED 0x04
+#define SNS1_WRITE_INHIBITED 0x02
+#define SNS1_INPRECISE_END 0x01
+
+/*
+ * architectured values for third sense byte
+ */
+#define SNS2_REQ_INH_WRITE 0x80
+#define SNS2_CORRECTABLE 0x40
+#define SNS2_FIRST_LOG_ERR 0x20
+#define SNS2_ENV_DATA_PRESENT 0x10
+#define SNS2_INPRECISE_END 0x04
/**
* scsw_is_tm - check for transport mode scsw
@@ -18,11 +185,10 @@
* Return non-zero if the specified scsw is a transport mode scsw, zero
* otherwise.
*/
-int scsw_is_tm(union scsw *scsw)
+static inline int scsw_is_tm(union scsw *scsw)
{
return css_general_characteristics.fcx && (scsw->tm.x == 1);
}
-EXPORT_SYMBOL(scsw_is_tm);
/**
* scsw_key - return scsw key field
@@ -31,14 +197,13 @@ EXPORT_SYMBOL(scsw_is_tm);
* Return the value of the key field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_key(union scsw *scsw)
+static inline u32 scsw_key(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.key;
else
return scsw->cmd.key;
}
-EXPORT_SYMBOL(scsw_key);
/**
* scsw_eswf - return scsw eswf field
@@ -47,14 +212,13 @@ EXPORT_SYMBOL(scsw_key);
* Return the value of the eswf field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_eswf(union scsw *scsw)
+static inline u32 scsw_eswf(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.eswf;
else
return scsw->cmd.eswf;
}
-EXPORT_SYMBOL(scsw_eswf);
/**
* scsw_cc - return scsw cc field
@@ -63,14 +227,13 @@ EXPORT_SYMBOL(scsw_eswf);
* Return the value of the cc field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_cc(union scsw *scsw)
+static inline u32 scsw_cc(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.cc;
else
return scsw->cmd.cc;
}
-EXPORT_SYMBOL(scsw_cc);
/**
* scsw_ectl - return scsw ectl field
@@ -79,14 +242,13 @@ EXPORT_SYMBOL(scsw_cc);
* Return the value of the ectl field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_ectl(union scsw *scsw)
+static inline u32 scsw_ectl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.ectl;
else
return scsw->cmd.ectl;
}
-EXPORT_SYMBOL(scsw_ectl);
/**
* scsw_pno - return scsw pno field
@@ -95,14 +257,13 @@ EXPORT_SYMBOL(scsw_ectl);
* Return the value of the pno field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_pno(union scsw *scsw)
+static inline u32 scsw_pno(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.pno;
else
return scsw->cmd.pno;
}
-EXPORT_SYMBOL(scsw_pno);
/**
* scsw_fctl - return scsw fctl field
@@ -111,14 +272,13 @@ EXPORT_SYMBOL(scsw_pno);
* Return the value of the fctl field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_fctl(union scsw *scsw)
+static inline u32 scsw_fctl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.fctl;
else
return scsw->cmd.fctl;
}
-EXPORT_SYMBOL(scsw_fctl);
/**
* scsw_actl - return scsw actl field
@@ -127,14 +287,13 @@ EXPORT_SYMBOL(scsw_fctl);
* Return the value of the actl field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_actl(union scsw *scsw)
+static inline u32 scsw_actl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.actl;
else
return scsw->cmd.actl;
}
-EXPORT_SYMBOL(scsw_actl);
/**
* scsw_stctl - return scsw stctl field
@@ -143,14 +302,13 @@ EXPORT_SYMBOL(scsw_actl);
* Return the value of the stctl field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_stctl(union scsw *scsw)
+static inline u32 scsw_stctl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.stctl;
else
return scsw->cmd.stctl;
}
-EXPORT_SYMBOL(scsw_stctl);
/**
* scsw_dstat - return scsw dstat field
@@ -159,14 +317,13 @@ EXPORT_SYMBOL(scsw_stctl);
* Return the value of the dstat field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_dstat(union scsw *scsw)
+static inline u32 scsw_dstat(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.dstat;
else
return scsw->cmd.dstat;
}
-EXPORT_SYMBOL(scsw_dstat);
/**
* scsw_cstat - return scsw cstat field
@@ -175,14 +332,13 @@ EXPORT_SYMBOL(scsw_dstat);
* Return the value of the cstat field of the specified scsw, regardless of
* whether it is a transport mode or command mode scsw.
*/
-u32 scsw_cstat(union scsw *scsw)
+static inline u32 scsw_cstat(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw->tm.cstat;
else
return scsw->cmd.cstat;
}
-EXPORT_SYMBOL(scsw_cstat);
/**
* scsw_cmd_is_valid_key - check key field validity
@@ -191,11 +347,10 @@ EXPORT_SYMBOL(scsw_cstat);
* Return non-zero if the key field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_key(union scsw *scsw)
+static inline int scsw_cmd_is_valid_key(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_key);
/**
* scsw_cmd_is_valid_sctl - check fctl field validity
@@ -204,11 +359,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_key);
* Return non-zero if the fctl field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_sctl(union scsw *scsw)
+static inline int scsw_cmd_is_valid_sctl(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_sctl);
/**
* scsw_cmd_is_valid_eswf - check eswf field validity
@@ -217,11 +371,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_sctl);
* Return non-zero if the eswf field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_eswf(union scsw *scsw)
+static inline int scsw_cmd_is_valid_eswf(union scsw *scsw)
{
return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_eswf);
/**
* scsw_cmd_is_valid_cc - check cc field validity
@@ -230,12 +383,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_eswf);
* Return non-zero if the cc field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_cc(union scsw *scsw)
+static inline int scsw_cmd_is_valid_cc(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
(scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_cc);
/**
* scsw_cmd_is_valid_fmt - check fmt field validity
@@ -244,11 +396,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_cc);
* Return non-zero if the fmt field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_fmt(union scsw *scsw)
+static inline int scsw_cmd_is_valid_fmt(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_fmt);
/**
* scsw_cmd_is_valid_pfch - check pfch field validity
@@ -257,11 +408,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_fmt);
* Return non-zero if the pfch field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_pfch(union scsw *scsw)
+static inline int scsw_cmd_is_valid_pfch(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_pfch);
/**
* scsw_cmd_is_valid_isic - check isic field validity
@@ -270,11 +420,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_pfch);
* Return non-zero if the isic field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_isic(union scsw *scsw)
+static inline int scsw_cmd_is_valid_isic(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_isic);
/**
* scsw_cmd_is_valid_alcc - check alcc field validity
@@ -283,11 +432,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_isic);
* Return non-zero if the alcc field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_alcc(union scsw *scsw)
+static inline int scsw_cmd_is_valid_alcc(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_alcc);
/**
* scsw_cmd_is_valid_ssi - check ssi field validity
@@ -296,11 +444,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_alcc);
* Return non-zero if the ssi field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_ssi(union scsw *scsw)
+static inline int scsw_cmd_is_valid_ssi(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_ssi);
/**
* scsw_cmd_is_valid_zcc - check zcc field validity
@@ -309,12 +456,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_ssi);
* Return non-zero if the zcc field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_zcc(union scsw *scsw)
+static inline int scsw_cmd_is_valid_zcc(union scsw *scsw)
{
return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_zcc);
/**
* scsw_cmd_is_valid_ectl - check ectl field validity
@@ -323,13 +469,12 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_zcc);
* Return non-zero if the ectl field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_ectl(union scsw *scsw)
+static inline int scsw_cmd_is_valid_ectl(union scsw *scsw)
{
return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
(scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_ectl);
/**
* scsw_cmd_is_valid_pno - check pno field validity
@@ -338,7 +483,7 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_ectl);
* Return non-zero if the pno field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_pno(union scsw *scsw)
+static inline int scsw_cmd_is_valid_pno(union scsw *scsw)
{
return (scsw->cmd.fctl != 0) &&
(scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
@@ -346,7 +491,6 @@ int scsw_cmd_is_valid_pno(union scsw *scsw)
((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
(scsw->cmd.actl & SCSW_ACTL_SUSPENDED)));
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_pno);
/**
* scsw_cmd_is_valid_fctl - check fctl field validity
@@ -355,12 +499,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_pno);
* Return non-zero if the fctl field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_fctl(union scsw *scsw)
+static inline int scsw_cmd_is_valid_fctl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_fctl);
/**
* scsw_cmd_is_valid_actl - check actl field validity
@@ -369,12 +512,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_fctl);
* Return non-zero if the actl field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_actl(union scsw *scsw)
+static inline int scsw_cmd_is_valid_actl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_actl);
/**
* scsw_cmd_is_valid_stctl - check stctl field validity
@@ -383,12 +525,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_actl);
* Return non-zero if the stctl field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_stctl(union scsw *scsw)
+static inline int scsw_cmd_is_valid_stctl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_stctl);
/**
* scsw_cmd_is_valid_dstat - check dstat field validity
@@ -397,12 +538,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_stctl);
* Return non-zero if the dstat field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_dstat(union scsw *scsw)
+static inline int scsw_cmd_is_valid_dstat(union scsw *scsw)
{
return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
(scsw->cmd.cc != 3);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_dstat);
/**
* scsw_cmd_is_valid_cstat - check cstat field validity
@@ -411,12 +551,11 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_dstat);
* Return non-zero if the cstat field of the specified command mode scsw is
* valid, zero otherwise.
*/
-int scsw_cmd_is_valid_cstat(union scsw *scsw)
+static inline int scsw_cmd_is_valid_cstat(union scsw *scsw)
{
return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
(scsw->cmd.cc != 3);
}
-EXPORT_SYMBOL(scsw_cmd_is_valid_cstat);
/**
* scsw_tm_is_valid_key - check key field validity
@@ -425,11 +564,10 @@ EXPORT_SYMBOL(scsw_cmd_is_valid_cstat);
* Return non-zero if the key field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_key(union scsw *scsw)
+static inline int scsw_tm_is_valid_key(union scsw *scsw)
{
return (scsw->tm.fctl & SCSW_FCTL_START_FUNC);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_key);
/**
* scsw_tm_is_valid_eswf - check eswf field validity
@@ -438,11 +576,10 @@ EXPORT_SYMBOL(scsw_tm_is_valid_key);
* Return non-zero if the eswf field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_eswf(union scsw *scsw)
+static inline int scsw_tm_is_valid_eswf(union scsw *scsw)
{
return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_eswf);
/**
* scsw_tm_is_valid_cc - check cc field validity
@@ -451,12 +588,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_eswf);
* Return non-zero if the cc field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_cc(union scsw *scsw)
+static inline int scsw_tm_is_valid_cc(union scsw *scsw)
{
return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) &&
(scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_cc);
/**
* scsw_tm_is_valid_fmt - check fmt field validity
@@ -465,11 +601,10 @@ EXPORT_SYMBOL(scsw_tm_is_valid_cc);
* Return non-zero if the fmt field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_fmt(union scsw *scsw)
+static inline int scsw_tm_is_valid_fmt(union scsw *scsw)
{
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_fmt);
/**
* scsw_tm_is_valid_x - check x field validity
@@ -478,11 +613,10 @@ EXPORT_SYMBOL(scsw_tm_is_valid_fmt);
* Return non-zero if the x field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_x(union scsw *scsw)
+static inline int scsw_tm_is_valid_x(union scsw *scsw)
{
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_x);
/**
* scsw_tm_is_valid_q - check q field validity
@@ -491,11 +625,10 @@ EXPORT_SYMBOL(scsw_tm_is_valid_x);
* Return non-zero if the q field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_q(union scsw *scsw)
+static inline int scsw_tm_is_valid_q(union scsw *scsw)
{
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_q);
/**
* scsw_tm_is_valid_ectl - check ectl field validity
@@ -504,13 +637,12 @@ EXPORT_SYMBOL(scsw_tm_is_valid_q);
* Return non-zero if the ectl field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_ectl(union scsw *scsw)
+static inline int scsw_tm_is_valid_ectl(union scsw *scsw)
{
return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
(scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_ectl);
/**
* scsw_tm_is_valid_pno - check pno field validity
@@ -519,7 +651,7 @@ EXPORT_SYMBOL(scsw_tm_is_valid_ectl);
* Return non-zero if the pno field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_pno(union scsw *scsw)
+static inline int scsw_tm_is_valid_pno(union scsw *scsw)
{
return (scsw->tm.fctl != 0) &&
(scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
@@ -527,7 +659,6 @@ int scsw_tm_is_valid_pno(union scsw *scsw)
((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
(scsw->tm.actl & SCSW_ACTL_SUSPENDED)));
}
-EXPORT_SYMBOL(scsw_tm_is_valid_pno);
/**
* scsw_tm_is_valid_fctl - check fctl field validity
@@ -536,12 +667,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_pno);
* Return non-zero if the fctl field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_fctl(union scsw *scsw)
+static inline int scsw_tm_is_valid_fctl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_fctl);
/**
* scsw_tm_is_valid_actl - check actl field validity
@@ -550,12 +680,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_fctl);
* Return non-zero if the actl field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_actl(union scsw *scsw)
+static inline int scsw_tm_is_valid_actl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_actl);
/**
* scsw_tm_is_valid_stctl - check stctl field validity
@@ -564,12 +693,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_actl);
* Return non-zero if the stctl field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_stctl(union scsw *scsw)
+static inline int scsw_tm_is_valid_stctl(union scsw *scsw)
{
/* Only valid if pmcw.dnv == 1*/
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_stctl);
/**
* scsw_tm_is_valid_dstat - check dstat field validity
@@ -578,12 +706,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_stctl);
* Return non-zero if the dstat field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_dstat(union scsw *scsw)
+static inline int scsw_tm_is_valid_dstat(union scsw *scsw)
{
return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
(scsw->tm.cc != 3);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_dstat);
/**
* scsw_tm_is_valid_cstat - check cstat field validity
@@ -592,12 +719,11 @@ EXPORT_SYMBOL(scsw_tm_is_valid_dstat);
* Return non-zero if the cstat field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_cstat(union scsw *scsw)
+static inline int scsw_tm_is_valid_cstat(union scsw *scsw)
{
return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
(scsw->tm.cc != 3);
}
-EXPORT_SYMBOL(scsw_tm_is_valid_cstat);
/**
* scsw_tm_is_valid_fcxs - check fcxs field validity
@@ -606,11 +732,10 @@ EXPORT_SYMBOL(scsw_tm_is_valid_cstat);
* Return non-zero if the fcxs field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_fcxs(union scsw *scsw)
+static inline int scsw_tm_is_valid_fcxs(union scsw *scsw)
{
return 1;
}
-EXPORT_SYMBOL(scsw_tm_is_valid_fcxs);
/**
* scsw_tm_is_valid_schxs - check schxs field validity
@@ -619,14 +744,13 @@ EXPORT_SYMBOL(scsw_tm_is_valid_fcxs);
* Return non-zero if the schxs field of the specified transport mode scsw is
* valid, zero otherwise.
*/
-int scsw_tm_is_valid_schxs(union scsw *scsw)
+static inline int scsw_tm_is_valid_schxs(union scsw *scsw)
{
return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK |
SCHN_STAT_INTF_CTRL_CHK |
SCHN_STAT_PROT_CHECK |
SCHN_STAT_CHN_DATA_CHK));
}
-EXPORT_SYMBOL(scsw_tm_is_valid_schxs);
/**
* scsw_is_valid_actl - check actl field validity
@@ -636,14 +760,13 @@ EXPORT_SYMBOL(scsw_tm_is_valid_schxs);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_actl(union scsw *scsw)
+static inline int scsw_is_valid_actl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_actl(scsw);
else
return scsw_cmd_is_valid_actl(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_actl);
/**
* scsw_is_valid_cc - check cc field validity
@@ -653,14 +776,13 @@ EXPORT_SYMBOL(scsw_is_valid_actl);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_cc(union scsw *scsw)
+static inline int scsw_is_valid_cc(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_cc(scsw);
else
return scsw_cmd_is_valid_cc(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_cc);
/**
* scsw_is_valid_cstat - check cstat field validity
@@ -670,14 +792,13 @@ EXPORT_SYMBOL(scsw_is_valid_cc);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_cstat(union scsw *scsw)
+static inline int scsw_is_valid_cstat(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_cstat(scsw);
else
return scsw_cmd_is_valid_cstat(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_cstat);
/**
* scsw_is_valid_dstat - check dstat field validity
@@ -687,14 +808,13 @@ EXPORT_SYMBOL(scsw_is_valid_cstat);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_dstat(union scsw *scsw)
+static inline int scsw_is_valid_dstat(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_dstat(scsw);
else
return scsw_cmd_is_valid_dstat(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_dstat);
/**
* scsw_is_valid_ectl - check ectl field validity
@@ -704,14 +824,13 @@ EXPORT_SYMBOL(scsw_is_valid_dstat);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_ectl(union scsw *scsw)
+static inline int scsw_is_valid_ectl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_ectl(scsw);
else
return scsw_cmd_is_valid_ectl(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_ectl);
/**
* scsw_is_valid_eswf - check eswf field validity
@@ -721,14 +840,13 @@ EXPORT_SYMBOL(scsw_is_valid_ectl);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_eswf(union scsw *scsw)
+static inline int scsw_is_valid_eswf(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_eswf(scsw);
else
return scsw_cmd_is_valid_eswf(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_eswf);
/**
* scsw_is_valid_fctl - check fctl field validity
@@ -738,14 +856,13 @@ EXPORT_SYMBOL(scsw_is_valid_eswf);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_fctl(union scsw *scsw)
+static inline int scsw_is_valid_fctl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_fctl(scsw);
else
return scsw_cmd_is_valid_fctl(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_fctl);
/**
* scsw_is_valid_key - check key field validity
@@ -755,14 +872,13 @@ EXPORT_SYMBOL(scsw_is_valid_fctl);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_key(union scsw *scsw)
+static inline int scsw_is_valid_key(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_key(scsw);
else
return scsw_cmd_is_valid_key(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_key);
/**
* scsw_is_valid_pno - check pno field validity
@@ -772,14 +888,13 @@ EXPORT_SYMBOL(scsw_is_valid_key);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_pno(union scsw *scsw)
+static inline int scsw_is_valid_pno(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_pno(scsw);
else
return scsw_cmd_is_valid_pno(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_pno);
/**
* scsw_is_valid_stctl - check stctl field validity
@@ -789,14 +904,13 @@ EXPORT_SYMBOL(scsw_is_valid_pno);
* regardless of whether it is a transport mode or command mode scsw.
* Return zero if the field does not contain a valid value.
*/
-int scsw_is_valid_stctl(union scsw *scsw)
+static inline int scsw_is_valid_stctl(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_valid_stctl(scsw);
else
return scsw_cmd_is_valid_stctl(scsw);
}
-EXPORT_SYMBOL(scsw_is_valid_stctl);
/**
* scsw_cmd_is_solicited - check for solicited scsw
@@ -805,12 +919,11 @@ EXPORT_SYMBOL(scsw_is_valid_stctl);
* Return non-zero if the command mode scsw indicates that the associated
* status condition is solicited, zero if it is unsolicited.
*/
-int scsw_cmd_is_solicited(union scsw *scsw)
+static inline int scsw_cmd_is_solicited(union scsw *scsw)
{
return (scsw->cmd.cc != 0) || (scsw->cmd.stctl !=
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
}
-EXPORT_SYMBOL(scsw_cmd_is_solicited);
/**
* scsw_tm_is_solicited - check for solicited scsw
@@ -819,12 +932,11 @@ EXPORT_SYMBOL(scsw_cmd_is_solicited);
* Return non-zero if the transport mode scsw indicates that the associated
* status condition is solicited, zero if it is unsolicited.
*/
-int scsw_tm_is_solicited(union scsw *scsw)
+static inline int scsw_tm_is_solicited(union scsw *scsw)
{
return (scsw->tm.cc != 0) || (scsw->tm.stctl !=
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
}
-EXPORT_SYMBOL(scsw_tm_is_solicited);
/**
* scsw_is_solicited - check for solicited scsw
@@ -833,11 +945,12 @@ EXPORT_SYMBOL(scsw_tm_is_solicited);
* Return non-zero if the transport or command mode scsw indicates that the
* associated status condition is solicited, zero if it is unsolicited.
*/
-int scsw_is_solicited(union scsw *scsw)
+static inline int scsw_is_solicited(union scsw *scsw)
{
if (scsw_is_tm(scsw))
return scsw_tm_is_solicited(scsw);
else
return scsw_cmd_is_solicited(scsw);
}
-EXPORT_SYMBOL(scsw_is_solicited);
+
+#endif /* _ASM_S390_SCSW_H_ */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 38b0fc221ed7..e37478e87286 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -8,7 +8,7 @@
#ifndef _ASM_S390_SETUP_H
#define _ASM_S390_SETUP_H
-#define COMMAND_LINE_SIZE 1024
+#define COMMAND_LINE_SIZE 4096
#define ARCH_COMMAND_LINE_SIZE 896
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index 72137bc907ac..8ebcf8836aec 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -87,7 +87,7 @@ extern struct mutex smp_cpu_state_mutex;
extern int smp_cpu_polarization[];
extern void arch_send_call_function_single_ipi(int cpu);
-extern void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#endif
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index cc21e3e20fd7..e4e7552d8151 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -88,6 +88,20 @@ int get_sync_clock(unsigned long long *clock);
void init_cpu_timer(void);
unsigned long long monotonic_clock(void);
-extern u64 sched_clock_base_cc;
+extern u64 sched_clock_base;
+
+/**
+ * get_clock_monotonic - returns current time in clock rate units
+ *
+ * The caller must ensure that preemption is disabled.
+ * The clock and sched_clock_base get changed via stop_machine.
+ * Therefore preemption must be disabled when calling this
+ * function, otherwise the returned value is not guaranteed to
+ * be monotonic.
+ */
+static inline unsigned long long get_clock_monotonic(void)
+{
+ return get_clock_xt() - sched_clock_base;
+}
#endif
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
index 3d8a96d39d9d..81150b053689 100644
--- a/arch/s390/include/asm/tlb.h
+++ b/arch/s390/include/asm/tlb.h
@@ -96,7 +96,8 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
* pte_free_tlb frees a pte table and clears the CRSTE for the
* page table from the tlb.
*/
-static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte)
+static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+ unsigned long address)
{
if (!tlb->fullmm) {
tlb->array[tlb->nr_ptes++] = pte;
@@ -113,7 +114,8 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte)
* as the pgd. pmd_free_tlb checks the asce_limit against 2GB
* to avoid the double free of the pmd in this case.
*/
-static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+ unsigned long address)
{
#ifdef __s390x__
if (tlb->mm->context.asce_limit <= (1UL << 31))
@@ -134,7 +136,8 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
* as the pgd. pud_free_tlb checks the asce_limit against 4TB
* to avoid the double free of the pud in this case.
*/
-static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
+ unsigned long address)
{
#ifdef __s390x__
if (tlb->mm->context.asce_limit <= (1UL << 42))
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 5e0ad618dc45..6e7211abd950 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -9,7 +9,6 @@ const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
extern cpumask_t cpu_core_map[NR_CPUS];
-#define topology_core_siblings(cpu) (cpu_core_map[cpu])
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
int topology_set_cpu_management(int fc);
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index c75ed43b1a18..c7be8e10b87e 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -32,7 +32,7 @@ extra-y += head.o init_task.o vmlinux.lds
obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
obj-$(CONFIG_SMP) += smp.o topology.o
-
+obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o
obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
@@ -41,7 +41,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
+obj-$(CONFIG_FUNCTION_TRACER) += $(if $(CONFIG_64BIT),mcount64.o,mcount.o)
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index f9b144049dc9..1058fa88abd5 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -52,7 +52,7 @@ static void __init reset_tod_clock(void)
if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
disabled_wait(0);
- sched_clock_base_cc = TOD_UNIX_EPOCH;
+ sched_clock_base = TOD_UNIX_EPOCH;
}
#ifdef CONFIG_SHARED_KERNEL
@@ -81,6 +81,8 @@ asm(
" br 14\n"
" .size savesys_ipl_nss, .-savesys_ipl_nss\n");
+static __initdata char upper_command_line[COMMAND_LINE_SIZE];
+
static noinline __init void create_kernel_nss(void)
{
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
@@ -90,7 +92,6 @@ static noinline __init void create_kernel_nss(void)
int response;
size_t len;
char *savesys_ptr;
- char upper_command_line[COMMAND_LINE_SIZE];
char defsys_cmd[DEFSYS_CMD_SIZE];
char savesys_cmd[SAVESYS_CMD_SIZE];
@@ -210,7 +211,7 @@ static noinline __init void detect_machine_type(void)
machine_flags |= MACHINE_FLAG_VM;
}
-static void early_pgm_check_handler(void)
+static __init void early_pgm_check_handler(void)
{
unsigned long addr;
const struct exception_table_entry *fixup;
@@ -222,7 +223,7 @@ static void early_pgm_check_handler(void)
S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
}
-void setup_lowcore_early(void)
+static noinline __init void setup_lowcore_early(void)
{
psw_t psw;
@@ -364,21 +365,35 @@ static __init void rescue_initrd(void)
}
/* Set up boot command line */
-static void __init setup_boot_command_line(void)
+static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t))
{
- char *parm = NULL;
+ char *parm, *delim;
+ size_t rc, len;
+
+ len = strlen(boot_command_line);
+ delim = boot_command_line + len; /* '\0' character position */
+ parm = boot_command_line + len + 1; /* append right after '\0' */
+
+ rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1);
+ if (rc) {
+ if (*parm == '=')
+ memmove(boot_command_line, parm + 1, rc);
+ else
+ *delim = ' '; /* replace '\0' with space */
+ }
+}
+
+static void __init setup_boot_command_line(void)
+{
/* copy arch command line */
strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
/* append IPL PARM data to the boot command line */
- if (MACHINE_IS_VM) {
- parm = boot_command_line + strlen(boot_command_line);
- *parm++ = ' ';
- get_ipl_vmparm(parm);
- if (parm[0] == '=')
- memmove(boot_command_line, parm + 1, strlen(parm));
- }
+ if (MACHINE_IS_VM)
+ append_to_cmdline(append_ipl_vmparm);
+
+ append_to_cmdline(append_ipl_scpdata);
}
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index ec6882348520..d5e6ee3b2c4f 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -535,7 +535,7 @@ startup:basr %r13,0 # get base
b 0(%r13)
.align 4
4: .long startup_continue
-5: .long sched_clock_base_cc
+5: .long sched_clock_base
.align 8
6: .long 0x7fffffff,0xffffffff
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 371a2d88f4ac..ee57a42e6e93 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -272,17 +272,18 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
/* VM IPL PARM routines */
-static void reipl_get_ascii_vmparm(char *dest,
+size_t reipl_get_ascii_vmparm(char *dest, size_t size,
const struct ipl_parameter_block *ipb)
{
int i;
- int len = 0;
+ size_t len;
char has_lowercase = 0;
+ len = 0;
if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
(ipb->ipl_info.ccw.vm_parm_len > 0)) {
- len = ipb->ipl_info.ccw.vm_parm_len;
+ len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len);
memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
/* If at least one character is lowercase, we assume mixed
* case; otherwise we convert everything to lowercase.
@@ -299,14 +300,20 @@ static void reipl_get_ascii_vmparm(char *dest,
EBCASC(dest, len);
}
dest[len] = 0;
+
+ return len;
}
-void get_ipl_vmparm(char *dest)
+size_t append_ipl_vmparm(char *dest, size_t size)
{
+ size_t rc;
+
+ rc = 0;
if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
- reipl_get_ascii_vmparm(dest, &ipl_block);
+ rc = reipl_get_ascii_vmparm(dest, size, &ipl_block);
else
dest[0] = 0;
+ return rc;
}
static ssize_t ipl_vm_parm_show(struct kobject *kobj,
@@ -314,10 +321,65 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj,
{
char parm[DIAG308_VMPARM_SIZE + 1] = {};
- get_ipl_vmparm(parm);
+ append_ipl_vmparm(parm, sizeof(parm));
return sprintf(page, "%s\n", parm);
}
+static size_t scpdata_length(const char* buf, size_t count)
+{
+ while (count) {
+ if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
+ break;
+ count--;
+ }
+ return count;
+}
+
+size_t reipl_append_ascii_scpdata(char *dest, size_t size,
+ const struct ipl_parameter_block *ipb)
+{
+ size_t count;
+ size_t i;
+ int has_lowercase;
+
+ count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data,
+ ipb->ipl_info.fcp.scp_data_len));
+ if (!count)
+ goto out;
+
+ has_lowercase = 0;
+ for (i = 0; i < count; i++) {
+ if (!isascii(ipb->ipl_info.fcp.scp_data[i])) {
+ count = 0;
+ goto out;
+ }
+ if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i]))
+ has_lowercase = 1;
+ }
+
+ if (has_lowercase)
+ memcpy(dest, ipb->ipl_info.fcp.scp_data, count);
+ else
+ for (i = 0; i < count; i++)
+ dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]);
+out:
+ dest[count] = '\0';
+ return count;
+}
+
+size_t append_ipl_scpdata(char *dest, size_t len)
+{
+ size_t rc;
+
+ rc = 0;
+ if (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP)
+ rc = reipl_append_ascii_scpdata(dest, len, &ipl_block);
+ else
+ dest[0] = 0;
+ return rc;
+}
+
+
static struct kobj_attribute sys_ipl_vm_parm_attr =
__ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
@@ -553,7 +615,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
{
char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
- reipl_get_ascii_vmparm(vmparm, ipb);
+ reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
return sprintf(page, "%s\n", vmparm);
}
@@ -626,6 +688,59 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
/* FCP reipl device attributes */
+static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ size_t size = reipl_block_fcp->ipl_info.fcp.scp_data_len;
+ void *scp_data = reipl_block_fcp->ipl_info.fcp.scp_data;
+
+ return memory_read_from_buffer(buf, count, &off, scp_data, size);
+}
+
+static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ size_t padding;
+ size_t scpdata_len;
+
+ if (off < 0)
+ return -EINVAL;
+
+ if (off >= DIAG308_SCPDATA_SIZE)
+ return -ENOSPC;
+
+ if (count > DIAG308_SCPDATA_SIZE - off)
+ count = DIAG308_SCPDATA_SIZE - off;
+
+ memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
+ scpdata_len = off + count;
+
+ if (scpdata_len % 8) {
+ padding = 8 - (scpdata_len % 8);
+ memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
+ 0, padding);
+ scpdata_len += padding;
+ }
+
+ reipl_block_fcp->ipl_info.fcp.scp_data_len = scpdata_len;
+ reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len;
+ reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len;
+
+ return count;
+}
+
+static struct bin_attribute sys_reipl_fcp_scp_data_attr = {
+ .attr = {
+ .name = "scp_data",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = PAGE_SIZE,
+ .read = reipl_fcp_scpdata_read,
+ .write = reipl_fcp_scpdata_write,
+};
+
DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
reipl_block_fcp->ipl_info.fcp.wwpn);
DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
@@ -647,7 +762,6 @@ static struct attribute *reipl_fcp_attrs[] = {
};
static struct attribute_group reipl_fcp_attr_group = {
- .name = IPL_FCP_STR,
.attrs = reipl_fcp_attrs,
};
@@ -895,6 +1009,7 @@ static struct kobj_attribute reipl_type_attr =
__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
static struct kset *reipl_kset;
+static struct kset *reipl_fcp_kset;
static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
const enum ipl_method m)
@@ -906,7 +1021,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
reipl_get_ascii_loadparm(loadparm, ipb);
reipl_get_ascii_nss_name(nss_name, ipb);
- reipl_get_ascii_vmparm(vmparm, ipb);
+ reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
switch (m) {
case REIPL_METHOD_CCW_VM:
@@ -1076,23 +1191,44 @@ static int __init reipl_fcp_init(void)
int rc;
if (!diag308_set_works) {
- if (ipl_info.type == IPL_TYPE_FCP)
+ if (ipl_info.type == IPL_TYPE_FCP) {
make_attrs_ro(reipl_fcp_attrs);
- else
+ sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO;
+ } else
return 0;
}
reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_fcp)
return -ENOMEM;
- rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
+
+ /* sysfs: create fcp kset for mixing attr group and bin attrs */
+ reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
+ &reipl_kset->kobj);
+ if (!reipl_kset) {
+ free_page((unsigned long) reipl_block_fcp);
+ return -ENOMEM;
+ }
+
+ rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
+ if (rc) {
+ kset_unregister(reipl_fcp_kset);
+ free_page((unsigned long) reipl_block_fcp);
+ return rc;
+ }
+
+ rc = sysfs_create_bin_file(&reipl_fcp_kset->kobj,
+ &sys_reipl_fcp_scp_data_attr);
if (rc) {
- free_page((unsigned long)reipl_block_fcp);
+ sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
+ kset_unregister(reipl_fcp_kset);
+ free_page((unsigned long) reipl_block_fcp);
return rc;
}
- if (ipl_info.type == IPL_TYPE_FCP) {
+
+ if (ipl_info.type == IPL_TYPE_FCP)
memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
- } else {
+ else {
reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
index 2a0a5e97ba8c..dfe015d7398c 100644
--- a/arch/s390/kernel/mcount.S
+++ b/arch/s390/kernel/mcount.S
@@ -11,111 +11,27 @@
ftrace_stub:
br %r14
-#ifdef CONFIG_64BIT
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-
.globl _mcount
_mcount:
- br %r14
-
- .globl ftrace_caller
-ftrace_caller:
- larl %r1,function_trace_stop
- icm %r1,0xf,0(%r1)
- bnzr %r14
- stmg %r2,%r5,32(%r15)
- stg %r14,112(%r15)
- lgr %r1,%r15
- aghi %r15,-160
- stg %r1,__SF_BACKCHAIN(%r15)
- lgr %r2,%r14
- lg %r3,168(%r15)
- larl %r14,ftrace_dyn_func
- lg %r14,0(%r14)
- basr %r14,%r14
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- .globl ftrace_graph_caller
-ftrace_graph_caller:
- # This unconditional branch gets runtime patched. Change only if
- # you know what you are doing. See ftrace_enable_graph_caller().
- j 0f
- lg %r2,272(%r15)
- lg %r3,168(%r15)
- brasl %r14,prepare_ftrace_return
- stg %r2,168(%r15)
-0:
-#endif
- aghi %r15,160
- lmg %r2,%r5,32(%r15)
- lg %r14,112(%r15)
+#ifdef CONFIG_DYNAMIC_FTRACE
br %r14
.data
.globl ftrace_dyn_func
ftrace_dyn_func:
- .quad ftrace_stub
+ .long ftrace_stub
.previous
-#else /* CONFIG_DYNAMIC_FTRACE */
-
- .globl _mcount
-_mcount:
- larl %r1,function_trace_stop
- icm %r1,0xf,0(%r1)
- bnzr %r14
- stmg %r2,%r5,32(%r15)
- stg %r14,112(%r15)
- lgr %r1,%r15
- aghi %r15,-160
- stg %r1,__SF_BACKCHAIN(%r15)
- lgr %r2,%r14
- lg %r3,168(%r15)
- larl %r14,ftrace_trace_function
- lg %r14,0(%r14)
- basr %r14,%r14
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- lg %r2,272(%r15)
- lg %r3,168(%r15)
- brasl %r14,prepare_ftrace_return
- stg %r2,168(%r15)
-#endif
- aghi %r15,160
- lmg %r2,%r5,32(%r15)
- lg %r14,112(%r15)
- br %r14
-
-#endif /* CONFIG_DYNAMIC_FTRACE */
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-
- .globl return_to_handler
-return_to_handler:
- stmg %r2,%r5,32(%r15)
- lgr %r1,%r15
- aghi %r15,-160
- stg %r1,__SF_BACKCHAIN(%r15)
- brasl %r14,ftrace_return_to_handler
- aghi %r15,160
- lgr %r14,%r2
- lmg %r2,%r5,32(%r15)
- br %r14
-
-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-
-#else /* CONFIG_64BIT */
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-
- .globl _mcount
-_mcount:
- br %r14
-
.globl ftrace_caller
ftrace_caller:
+#endif
stm %r2,%r5,16(%r15)
bras %r1,2f
+#ifdef CONFIG_DYNAMIC_FTRACE
+0: .long ftrace_dyn_func
+#else
0: .long ftrace_trace_function
+#endif
1: .long function_trace_stop
2: l %r2,1b-0b(%r1)
icm %r2,0xf,0(%r2)
@@ -131,53 +47,13 @@ ftrace_caller:
l %r14,0(%r14)
basr %r14,%r14
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
.globl ftrace_graph_caller
ftrace_graph_caller:
# This unconditional branch gets runtime patched. Change only if
# you know what you are doing. See ftrace_enable_graph_caller().
j 1f
- bras %r1,0f
- .long prepare_ftrace_return
-0: l %r2,152(%r15)
- l %r4,0(%r1)
- l %r3,100(%r15)
- basr %r14,%r4
- st %r2,100(%r15)
-1:
#endif
- ahi %r15,96
- l %r14,56(%r15)
-3: lm %r2,%r5,16(%r15)
- br %r14
-
- .data
- .globl ftrace_dyn_func
-ftrace_dyn_func:
- .long ftrace_stub
- .previous
-
-#else /* CONFIG_DYNAMIC_FTRACE */
-
- .globl _mcount
-_mcount:
- stm %r2,%r5,16(%r15)
- bras %r1,2f
-0: .long ftrace_trace_function
-1: .long function_trace_stop
-2: l %r2,1b-0b(%r1)
- icm %r2,0xf,0(%r2)
- jnz 3f
- st %r14,56(%r15)
- lr %r0,%r15
- ahi %r15,-96
- l %r3,100(%r15)
- la %r2,0(%r14)
- st %r0,__SF_BACKCHAIN(%r15)
- la %r3,0(%r3)
- l %r14,0b-0b(%r1)
- l %r14,0(%r14)
- basr %r14,%r14
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
bras %r1,0f
.long prepare_ftrace_return
0: l %r2,152(%r15)
@@ -185,14 +61,13 @@ _mcount:
l %r3,100(%r15)
basr %r14,%r4
st %r2,100(%r15)
+1:
#endif
ahi %r15,96
l %r14,56(%r15)
3: lm %r2,%r5,16(%r15)
br %r14
-#endif /* CONFIG_DYNAMIC_FTRACE */
-
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl return_to_handler
@@ -211,6 +86,4 @@ return_to_handler:
lm %r2,%r5,16(%r15)
br %r14
-#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-
-#endif /* CONFIG_64BIT */
+#endif
diff --git a/arch/s390/kernel/mcount64.S b/arch/s390/kernel/mcount64.S
new file mode 100644
index 000000000000..c37211c6092b
--- /dev/null
+++ b/arch/s390/kernel/mcount64.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright IBM Corp. 2008,2009
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#include <asm/asm-offsets.h>
+
+ .globl ftrace_stub
+ftrace_stub:
+ br %r14
+
+ .globl _mcount
+_mcount:
+#ifdef CONFIG_DYNAMIC_FTRACE
+ br %r14
+
+ .data
+ .globl ftrace_dyn_func
+ftrace_dyn_func:
+ .quad ftrace_stub
+ .previous
+
+ .globl ftrace_caller
+ftrace_caller:
+#endif
+ larl %r1,function_trace_stop
+ icm %r1,0xf,0(%r1)
+ bnzr %r14
+ stmg %r2,%r5,32(%r15)
+ stg %r14,112(%r15)
+ lgr %r1,%r15
+ aghi %r15,-160
+ stg %r1,__SF_BACKCHAIN(%r15)
+ lgr %r2,%r14
+ lg %r3,168(%r15)
+#ifdef CONFIG_DYNAMIC_FTRACE
+ larl %r14,ftrace_dyn_func
+#else
+ larl %r14,ftrace_trace_function
+#endif
+ lg %r14,0(%r14)
+ basr %r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+ .globl ftrace_graph_caller
+ftrace_graph_caller:
+ # This unconditional branch gets runtime patched. Change only if
+ # you know what you are doing. See ftrace_enable_graph_caller().
+ j 0f
+#endif
+ lg %r2,272(%r15)
+ lg %r3,168(%r15)
+ brasl %r14,prepare_ftrace_return
+ stg %r2,168(%r15)
+0:
+#endif
+ aghi %r15,160
+ lmg %r2,%r5,32(%r15)
+ lg %r14,112(%r15)
+ br %r14
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+ .globl return_to_handler
+return_to_handler:
+ stmg %r2,%r5,32(%r15)
+ lgr %r1,%r15
+ aghi %r15,-160
+ stg %r1,__SF_BACKCHAIN(%r15)
+ brasl %r14,ftrace_return_to_handler
+ aghi %r15,160
+ lgr %r14,%r2
+ lmg %r2,%r5,32(%r15)
+ br %r14
+
+#endif
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 2270730f5354..f0d4aad0ce9d 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -129,11 +129,11 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
udelay(10);
}
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
int cpu;
- for_each_cpu_mask(cpu, mask)
+ for_each_cpu(cpu, mask)
smp_ext_bitcall(cpu, ec_call_function);
}
@@ -687,13 +687,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
#ifndef CONFIG_64BIT
if (MACHINE_HAS_IEEE)
lowcore->extended_save_area_addr = (u32) save_area;
-#else
- if (vdso_alloc_per_cpu(smp_processor_id(), lowcore))
- BUG();
#endif
set_prefix((u32)(unsigned long) lowcore);
local_mcck_enable();
local_irq_enable();
+#ifdef CONFIG_64BIT
+ if (vdso_alloc_per_cpu(smp_processor_id(), &S390_lowcore))
+ BUG();
+#endif
for_each_possible_cpu(cpu)
if (cpu != smp_processor_id())
smp_create_idle(cpu);
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
new file mode 100644
index 000000000000..086bee970cae
--- /dev/null
+++ b/arch/s390/kernel/suspend.c
@@ -0,0 +1,73 @@
+/*
+ * Suspend support specific for s390.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ */
+
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <asm/sections.h>
+#include <asm/system.h>
+#include <asm/ipl.h>
+
+/*
+ * References to section boundaries
+ */
+extern const void __nosave_begin, __nosave_end;
+
+/*
+ * check if given pfn is in the 'nosave' or in the read only NSS section
+ */
+int pfn_is_nosave(unsigned long pfn)
+{
+ unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end))
+ >> PAGE_SHIFT;
+ unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
+ unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
+
+ if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
+ return 1;
+ if (pfn >= stext_pfn && pfn <= eshared_pfn) {
+ if (ipl_info.type == IPL_TYPE_NSS)
+ return 1;
+ } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0))
+ return 1;
+ return 0;
+}
+
+void save_processor_state(void)
+{
+ /* swsusp_arch_suspend() actually saves all cpu register contents.
+ * Machine checks must be disabled since swsusp_arch_suspend() stores
+ * register contents to their lowcore save areas. That's the same
+ * place where register contents on machine checks would be saved.
+ * To avoid register corruption disable machine checks.
+ * We must also disable machine checks in the new psw mask for
+ * program checks, since swsusp_arch_suspend() may generate program
+ * checks. Disabling machine checks for all other new psw masks is
+ * just paranoia.
+ */
+ local_mcck_disable();
+ /* Disable lowcore protection */
+ __ctl_clear_bit(0,28);
+ S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK;
+ S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK;
+ S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK;
+ S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK;
+}
+
+void restore_processor_state(void)
+{
+ S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK;
+ S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK;
+ S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK;
+ S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK;
+ /* Enable lowcore protection */
+ __ctl_set_bit(0,28);
+ local_mcck_enable();
+}
diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index 76d688da32fa..7cd6b096f0d1 100644
--- a/arch/s390/power/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -21,7 +21,7 @@
* This function runs with disabled interrupts.
*/
.section .text
- .align 2
+ .align 4
.globl swsusp_arch_suspend
swsusp_arch_suspend:
stmg %r6,%r15,__SF_GPRS(%r15)
@@ -32,19 +32,14 @@ swsusp_arch_suspend:
/* Deactivate DAT */
stnsm __SF_EMPTY(%r15),0xfb
- /* Switch off lowcore protection */
- stctg %c0,%c0,__SF_EMPTY(%r15)
- ni __SF_EMPTY+4(%r15),0xef
- lctlg %c0,%c0,__SF_EMPTY(%r15)
-
/* Store prefix register on stack */
stpx __SF_EMPTY(%r15)
- /* Setup base register for lowcore (absolute 0) */
- llgf %r1,__SF_EMPTY(%r15)
+ /* Save prefix register contents for lowcore */
+ llgf %r4,__SF_EMPTY(%r15)
/* Get pointer to save area */
- aghi %r1,0x1000
+ lghi %r1,0x1000
/* Store registers */
mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */
@@ -79,17 +74,15 @@ swsusp_arch_suspend:
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
spx __SF_EMPTY(%r15)
- /* Setup lowcore */
- brasl %r14,setup_lowcore_early
+ lghi %r2,0
+ lghi %r3,2*PAGE_SIZE
+ lghi %r5,2*PAGE_SIZE
+1: mvcle %r2,%r4,0
+ jo 1b
/* Save image */
brasl %r14,swsusp_save
- /* Switch on lowcore protection */
- stctg %c0,%c0,__SF_EMPTY(%r15)
- oi __SF_EMPTY+4(%r15),0x10
- lctlg %c0,%c0,__SF_EMPTY(%r15)
-
/* Restore prefix register and return */
lghi %r1,0x1000
spx 0x318(%r1)
@@ -117,11 +110,6 @@ swsusp_arch_resume:
/* Deactivate DAT */
stnsm __SF_EMPTY(%r15),0xfb
- /* Switch off lowcore protection */
- stctg %c0,%c0,__SF_EMPTY(%r15)
- ni __SF_EMPTY+4(%r15),0xef
- lctlg %c0,%c0,__SF_EMPTY(%r15)
-
/* Set prefix page to zero */
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
spx __SF_EMPTY(%r15)
@@ -175,7 +163,7 @@ swsusp_arch_resume:
/* Load old stack */
lg %r15,0x2f8(%r13)
- /* Pointer to save arae */
+ /* Pointer to save area */
lghi %r13,0x1000
#ifdef CONFIG_SMP
@@ -187,11 +175,6 @@ swsusp_arch_resume:
/* Restore prefix register */
spx 0x318(%r13)
- /* Switch on lowcore protection */
- stctg %c0,%c0,__SF_EMPTY(%r15)
- oi __SF_EMPTY+4(%r15),0x10
- lctlg %c0,%c0,__SF_EMPTY(%r15)
-
/* Activate DAT */
stosm __SF_EMPTY(%r15),0x04
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index d4c8e9c47c81..6f0d86fb2aaa 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -59,7 +59,8 @@
#define TICK_SIZE tick
-u64 sched_clock_base_cc = -1; /* Force to data section. */
+u64 sched_clock_base = -1; /* Force to data section. */
+EXPORT_SYMBOL(sched_clock_base);
static DEFINE_PER_CPU(struct clock_event_device, comparators);
@@ -68,7 +69,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators);
*/
unsigned long long notrace sched_clock(void)
{
- return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9;
+ return (get_clock_monotonic() * 125) >> 9;
}
/*
@@ -277,7 +278,7 @@ void __init time_init(void)
tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime);
clocksource_tod.cycle_last = now;
clocksource_tod.raw_time = xtime;
- tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts);
+ tod_to_timeval(sched_clock_base - TOD_UNIX_EPOCH, &ts);
set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec);
write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -315,7 +316,7 @@ static unsigned long long adjust_time(unsigned long long old,
delta = -delta;
adjust.offset = -ticks * (1000000 / HZ);
}
- sched_clock_base_cc += delta;
+ sched_clock_base += delta;
if (adjust.offset != 0) {
pr_notice("The ETR interface has adjusted the clock "
"by %li microseconds\n", adjust.offset);
diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S
index 79dbfee831ec..49106c6e6f88 100644
--- a/arch/s390/kernel/vdso64/clock_gettime.S
+++ b/arch/s390/kernel/vdso64/clock_gettime.S
@@ -88,10 +88,17 @@ __kernel_clock_gettime:
llilh %r4,0x0100
sar %a4,%r4
lghi %r4,0
+ epsw %r5,0
sacf 512 /* Magic ectg instruction */
.insn ssf,0xc80100000000,__VDSO_ECTG_BASE(4),__VDSO_ECTG_USER(4),4
- sacf 0
- sar %a4,%r2
+ tml %r5,0x4000
+ jo 11f
+ tml %r5,0x8000
+ jno 10f
+ sacf 256
+ j 11f
+10: sacf 0
+11: sar %a4,%r2
algr %r1,%r0 /* r1 = cputime as TOD value */
mghi %r1,1000 /* convert to nanoseconds */
srlg %r1,%r1,12 /* r1 = cputime in nanosec */
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index a53db23ee092..82415c75b996 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -157,13 +157,10 @@ SECTIONS
_end = . ;
- /* Sections to be discarded */
- /DISCARD/ : {
- EXIT_DATA
- *(.exitcall.exit)
- }
-
/* Debugging sections. */
STABS_DEBUG
DWARF_DEBUG
+
+ /* Sections to be discarded */
+ DISCARDS
}
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 3e260b7e37b2..bf164fc21864 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -1,11 +1,7 @@
#
# KVM configuration
#
-config HAVE_KVM
- bool
-
-config HAVE_KVM_IRQCHIP
- bool
+source "virt/kvm/Kconfig"
menuconfig VIRTUALIZATION
bool "Virtualization"
@@ -38,9 +34,6 @@ config KVM
If unsure, say N.
-config KVM_TRACE
- bool
-
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
source drivers/virtio/Kconfig
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
index ed60f3a74a85..03c716a0f01f 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/gaccess.h
@@ -1,7 +1,7 @@
/*
* gaccess.h - access guest memory
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -16,13 +16,14 @@
#include <linux/compiler.h>
#include <linux/kvm_host.h>
#include <asm/uaccess.h>
+#include "kvm-s390.h"
static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
unsigned long guestaddr)
{
unsigned long prefix = vcpu->arch.sie_block->prefix;
- unsigned long origin = vcpu->kvm->arch.guest_origin;
- unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+ unsigned long origin = vcpu->arch.sie_block->gmsor;
+ unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
if (guestaddr < 2 * PAGE_SIZE)
guestaddr += prefix;
@@ -158,8 +159,8 @@ static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
const void *from, unsigned long n)
{
unsigned long prefix = vcpu->arch.sie_block->prefix;
- unsigned long origin = vcpu->kvm->arch.guest_origin;
- unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+ unsigned long origin = vcpu->arch.sie_block->gmsor;
+ unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
goto slowpath;
@@ -209,8 +210,8 @@ static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
unsigned long guestsrc, unsigned long n)
{
unsigned long prefix = vcpu->arch.sie_block->prefix;
- unsigned long origin = vcpu->kvm->arch.guest_origin;
- unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+ unsigned long origin = vcpu->arch.sie_block->gmsor;
+ unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
goto slowpath;
@@ -244,8 +245,8 @@ static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
unsigned long guestdest,
const void *from, unsigned long n)
{
- unsigned long origin = vcpu->kvm->arch.guest_origin;
- unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+ unsigned long origin = vcpu->arch.sie_block->gmsor;
+ unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
if (guestdest + n > memsize)
return -EFAULT;
@@ -262,8 +263,8 @@ static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
unsigned long guestsrc,
unsigned long n)
{
- unsigned long origin = vcpu->kvm->arch.guest_origin;
- unsigned long memsize = vcpu->kvm->arch.guest_memsize;
+ unsigned long origin = vcpu->arch.sie_block->gmsor;
+ unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
if (guestsrc + n > memsize)
return -EFAULT;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 98997ccba501..ba9d8a7bc1ac 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -1,7 +1,7 @@
/*
* intercept.c - in-kernel handling for sie intercepts
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -128,7 +128,7 @@ static int handle_noop(struct kvm_vcpu *vcpu)
static int handle_stop(struct kvm_vcpu *vcpu)
{
- int rc;
+ int rc = 0;
vcpu->stat.exit_stop_request++;
atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
@@ -141,12 +141,18 @@ static int handle_stop(struct kvm_vcpu *vcpu)
rc = -ENOTSUPP;
}
+ if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
+ vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
+ rc = SIE_INTERCEPT_RERUNVCPU;
+ vcpu->run->exit_reason = KVM_EXIT_INTR;
+ }
+
if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
rc = -ENOTSUPP;
- } else
- rc = 0;
+ }
+
spin_unlock_bh(&vcpu->arch.local_int.lock);
return rc;
}
@@ -158,9 +164,9 @@ static int handle_validity(struct kvm_vcpu *vcpu)
vcpu->stat.exit_validity++;
if ((viwhy == 0x37) && (vcpu->arch.sie_block->prefix
- <= vcpu->kvm->arch.guest_memsize - 2*PAGE_SIZE)){
+ <= kvm_s390_vcpu_get_memsize(vcpu) - 2*PAGE_SIZE)) {
rc = fault_in_pages_writeable((char __user *)
- vcpu->kvm->arch.guest_origin +
+ vcpu->arch.sie_block->gmsor +
vcpu->arch.sie_block->prefix,
2*PAGE_SIZE);
if (rc)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index f04f5301b1b4..2c2f98353415 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -283,7 +283,7 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
return 1;
}
-int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
+static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
@@ -320,12 +320,6 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
return rc;
}
-int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
-{
- /* do real check here */
- return 1;
-}
-
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
return 0;
@@ -386,7 +380,7 @@ no_timer:
}
__unset_cpu_idle(vcpu);
__set_current_state(TASK_RUNNING);
- remove_wait_queue(&vcpu->wq, &wait);
+ remove_wait_queue(&vcpu->arch.local_int.wq, &wait);
spin_unlock_bh(&vcpu->arch.local_int.lock);
spin_unlock(&vcpu->arch.local_int.float_int->lock);
hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 90d9d1ba258b..07ced89740d7 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -1,7 +1,7 @@
/*
* s390host.c -- hosting zSeries kernel virtual machines
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -10,6 +10,7 @@
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Christian Ehrhardt <ehrhardt@de.ibm.com>
*/
#include <linux/compiler.h>
@@ -210,13 +211,17 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
+ struct kvm_vcpu *vcpu;
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- if (kvm->vcpus[i]) {
- kvm_arch_vcpu_destroy(kvm->vcpus[i]);
- kvm->vcpus[i] = NULL;
- }
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_arch_vcpu_destroy(vcpu);
+
+ mutex_lock(&kvm->lock);
+ for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
+ kvm->vcpus[i] = NULL;
+
+ atomic_set(&kvm->online_vcpus, 0);
+ mutex_unlock(&kvm->lock);
}
void kvm_arch_sync_events(struct kvm *kvm)
@@ -278,16 +283,10 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->gbea = 1;
}
-/* The current code can have up to 256 pages for virtio */
-#define VIRTIODESCSPACE (256ul * 4096ul)
-
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
- vcpu->arch.sie_block->gmslm = vcpu->kvm->arch.guest_memsize +
- vcpu->kvm->arch.guest_origin +
- VIRTIODESCSPACE - 1ul;
- vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
+ set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests);
vcpu->arch.sie_block->ecb = 2;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) facilities;
@@ -319,8 +318,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
BUG_ON(!kvm->arch.sca);
if (!kvm->arch.sca->cpu[id].sda)
kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
- else
- BUG_ON(!kvm->vcpus[id]); /* vcpu does already exist */
vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
@@ -490,9 +487,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load(vcpu);
+rerun_vcpu:
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
+ kvm_s390_vcpu_set_mem(vcpu);
+
/* verify, that memory has been registered */
- if (!vcpu->kvm->arch.guest_memsize) {
+ if (!vcpu->arch.sie_block->gmslm) {
vcpu_put(vcpu);
+ VCPU_EVENT(vcpu, 3, "%s", "no memory registered to run vcpu");
return -EINVAL;
}
@@ -509,6 +512,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr;
break;
case KVM_EXIT_UNKNOWN:
+ case KVM_EXIT_INTR:
case KVM_EXIT_S390_RESET:
break;
default:
@@ -522,8 +526,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
rc = kvm_handle_sie_intercept(vcpu);
} while (!signal_pending(current) && !rc);
- if (signal_pending(current) && !rc)
+ if (rc == SIE_INTERCEPT_RERUNVCPU)
+ goto rerun_vcpu;
+
+ if (signal_pending(current) && !rc) {
+ kvm_run->exit_reason = KVM_EXIT_INTR;
rc = -EINTR;
+ }
if (rc == -ENOTSUPP) {
/* intercept cannot be handled in-kernel, prepare kvm-run */
@@ -676,6 +685,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
int user_alloc)
{
int i;
+ struct kvm_vcpu *vcpu;
/* A few sanity checks. We can have exactly one memory slot which has
to start at guest virtual zero and which has to be located at a
@@ -684,7 +694,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
vmas. It is okay to mmap() and munmap() stuff in this slot after
doing this call at any time */
- if (mem->slot || kvm->arch.guest_memsize)
+ if (mem->slot)
return -EINVAL;
if (mem->guest_phys_addr)
@@ -699,36 +709,14 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
if (!user_alloc)
return -EINVAL;
- /* lock all vcpus */
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- if (!kvm->vcpus[i])
+ /* request update of sie control block for all available vcpus */
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
continue;
- if (!mutex_trylock(&kvm->vcpus[i]->mutex))
- goto fail_out;
- }
-
- kvm->arch.guest_origin = mem->userspace_addr;
- kvm->arch.guest_memsize = mem->memory_size;
-
- /* update sie control blocks, and unlock all vcpus */
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- if (kvm->vcpus[i]) {
- kvm->vcpus[i]->arch.sie_block->gmsor =
- kvm->arch.guest_origin;
- kvm->vcpus[i]->arch.sie_block->gmslm =
- kvm->arch.guest_memsize +
- kvm->arch.guest_origin +
- VIRTIODESCSPACE - 1ul;
- mutex_unlock(&kvm->vcpus[i]->mutex);
- }
+ kvm_s390_inject_sigp_stop(vcpu, ACTION_RELOADVCPU_ON_STOP);
}
return 0;
-
-fail_out:
- for (; i >= 0; i--)
- mutex_unlock(&kvm->vcpus[i]->mutex);
- return -EINVAL;
}
void kvm_arch_flush_shadow(struct kvm *kvm)
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 748fee872323..ec5eee7c25d8 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -1,7 +1,7 @@
/*
* kvm_s390.h - definition for kvm on s390
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -9,6 +9,7 @@
*
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com>
+ * Christian Ehrhardt <ehrhardt@de.ibm.com>
*/
#ifndef ARCH_S390_KVM_S390_H
@@ -18,8 +19,13 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+/* The current code can have up to 256 pages for virtio */
+#define VIRTIODESCSPACE (256ul * 4096ul)
+
typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
+/* negativ values are error codes, positive values for internal conditions */
+#define SIE_INTERCEPT_RERUNVCPU (1<<0)
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
@@ -50,6 +56,30 @@ int kvm_s390_inject_vm(struct kvm *kvm,
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt *s390int);
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)
+{
+ return vcpu->arch.sie_block->gmslm
+ - vcpu->arch.sie_block->gmsor
+ - VIRTIODESCSPACE + 1ul;
+}
+
+static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu)
+{
+ struct kvm_memory_slot *mem;
+
+ down_read(&vcpu->kvm->slots_lock);
+ mem = &vcpu->kvm->memslots[0];
+
+ vcpu->arch.sie_block->gmsor = mem->userspace_addr;
+ vcpu->arch.sie_block->gmslm =
+ mem->userspace_addr +
+ (mem->npages << PAGE_SHIFT) +
+ VIRTIODESCSPACE - 1ul;
+
+ up_read(&vcpu->kvm->slots_lock);
+}
/* implemented in priv.c */
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 36678835034d..bdbd88ddef82 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -1,7 +1,7 @@
/*
* sigp.c - handlinge interprocessor communication
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -9,6 +9,7 @@
*
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com>
+ * Christian Ehrhardt <ehrhardt@de.ibm.com>
*/
#include <linux/kvm.h>
@@ -107,46 +108,57 @@ unlock:
return rc;
}
-static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store)
+static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
- struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
- int rc;
-
- if (cpu_addr >= KVM_MAX_VCPUS)
- return 3; /* not operational */
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
return -ENOMEM;
-
inti->type = KVM_S390_SIGP_STOP;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = 3; /* not operational */
- kfree(inti);
- goto unlock;
- }
spin_lock_bh(&li->lock);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
- if (store)
- li->action_bits |= ACTION_STORE_ON_STOP;
- li->action_bits |= ACTION_STOP_ON_STOP;
+ li->action_bits |= action;
if (waitqueue_active(&li->wq))
wake_up_interruptible(&li->wq);
spin_unlock_bh(&li->lock);
- rc = 0; /* order accepted */
+
+ return 0; /* order accepted */
+}
+
+static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
+{
+ struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct kvm_s390_local_interrupt *li;
+ int rc;
+
+ if (cpu_addr >= KVM_MAX_VCPUS)
+ return 3; /* not operational */
+
+ spin_lock(&fi->lock);
+ li = fi->local_int[cpu_addr];
+ if (li == NULL) {
+ rc = 3; /* not operational */
+ goto unlock;
+ }
+
+ rc = __inject_sigp_stop(li, action);
+
unlock:
spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
return rc;
}
+int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ return __inject_sigp_stop(li, action);
+}
+
static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
{
int rc;
@@ -177,9 +189,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
/* make sure that the new value is valid memory */
address = address & 0x7fffe000u;
if ((copy_from_guest(vcpu, &tmp,
- (u64) (address + vcpu->kvm->arch.guest_origin) , 1)) ||
+ (u64) (address + vcpu->arch.sie_block->gmsor) , 1)) ||
(copy_from_guest(vcpu, &tmp, (u64) (address +
- vcpu->kvm->arch.guest_origin + PAGE_SIZE), 1))) {
+ vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) {
*reg |= SIGP_STAT_INVALID_PARAMETER;
return 1; /* invalid parameter */
}
@@ -261,11 +273,11 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
break;
case SIGP_STOP:
vcpu->stat.instruction_sigp_stop++;
- rc = __sigp_stop(vcpu, cpu_addr, 0);
+ rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
break;
case SIGP_STOP_STORE_STATUS:
vcpu->stat.instruction_sigp_stop++;
- rc = __sigp_stop(vcpu, cpu_addr, 1);
+ rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
break;
case SIGP_SET_ARCH:
vcpu->stat.instruction_sigp_arch++;
diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile
deleted file mode 100644
index 973bb45a8fec..000000000000
--- a/arch/s390/power/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for s390 PM support
-#
-
-obj-$(CONFIG_HIBERNATION) += suspend.o
-obj-$(CONFIG_HIBERNATION) += swsusp.o
-obj-$(CONFIG_HIBERNATION) += swsusp_64.o
-obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o
diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c
deleted file mode 100644
index b3351eceebbe..000000000000
--- a/arch/s390/power/suspend.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Suspend support specific for s390.
- *
- * Copyright IBM Corp. 2009
- *
- * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
- */
-
-#include <linux/mm.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-#include <linux/pfn.h>
-#include <asm/sections.h>
-#include <asm/ipl.h>
-
-/*
- * References to section boundaries
- */
-extern const void __nosave_begin, __nosave_end;
-
-/*
- * check if given pfn is in the 'nosave' or in the read only NSS section
- */
-int pfn_is_nosave(unsigned long pfn)
-{
- unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
- unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end))
- >> PAGE_SHIFT;
- unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
- unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
-
- if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
- return 1;
- if (pfn >= stext_pfn && pfn <= eshared_pfn) {
- if (ipl_info.type == IPL_TYPE_NSS)
- return 1;
- } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0))
- return 1;
- return 0;
-}
diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c
deleted file mode 100644
index e6a4fe9f5f24..000000000000
--- a/arch/s390/power/swsusp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Support for suspend and resume on s390
- *
- * Copyright IBM Corp. 2009
- *
- * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
- *
- */
-
-
-/*
- * save CPU registers before creating a hibernation image and before
- * restoring the memory state from it
- */
-void save_processor_state(void)
-{
- /* implentation contained in the
- * swsusp_arch_suspend function
- */
-}
-
-/*
- * restore the contents of CPU registers
- */
-void restore_processor_state(void)
-{
- /* implentation contained in the
- * swsusp_arch_resume function
- */
-}
diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c
deleted file mode 100644
index 9516a517d72f..000000000000
--- a/arch/s390/power/swsusp_64.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Support for suspend and resume on s390
- *
- * Copyright IBM Corp. 2009
- *
- * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
- *
- */
-
-#include <asm/system.h>
-#include <linux/interrupt.h>
-
-void do_after_copyback(void)
-{
- mb();
-}
-
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index e2bdd7b94fd9..c4a955d25451 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -10,12 +10,16 @@ config SUPERH
select EMBEDDED
select HAVE_CLK
select HAVE_IDE
+ select HAVE_LMB
select HAVE_OPROFILE
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IOREMAP_PROT if MMU
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
select HAVE_PERF_COUNTERS
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_BZIP2
+ select HAVE_KERNEL_LZMA
select RTC_LIB
select GENERIC_ATOMIC64
help
@@ -31,6 +35,9 @@ config SUPERH32
select HAVE_FUNCTION_TRACER
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
+ select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_FTRACE_SYSCALLS
+ select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 39224b57c6ef..a6dce41296e7 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -38,7 +38,7 @@ config EARLY_SCIF_CONSOLE_PORT
default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763 || \
CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7366 || \
CPU_SUBTYPE_SH7343
- default "0xffea0000" if CPU_SUBTYPE_SH7785
+ default "0xffeb0000" if CPU_SUBTYPE_SH7785
default "0xffeb0000" if CPU_SUBTYPE_SH7786
default "0xfffe8000" if CPU_SUBTYPE_SH7203
default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
@@ -61,12 +61,14 @@ config EARLY_PRINTK
select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using
the kernel command line option to toggle back and forth.
-config DEBUG_STACKOVERFLOW
+config STACK_DEBUG
bool "Check for stack overflows"
depends on DEBUG_KERNEL && SUPERH32
help
This option will cause messages to be printed if free stack space
- drops below a certain limit.
+ drops below a certain limit. Saying Y here will add overhead to
+ every function call and will therefore incur a major
+ performance hit. Most users should say N.
config DEBUG_STACK_USAGE
bool "Stack utilization instrumentation"
@@ -123,4 +125,9 @@ config SH64_SR_WATCH
bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
depends on SUPERH64
+config MCOUNT
+ def_bool y
+ depends on SUPERH32
+ depends on STACK_DEBUG || FUNCTION_TRACER
+
endmenu
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 75d049b03f7e..b6ff337fd856 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -136,6 +136,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += mach-systemh
machdir-$(CONFIG_SH_EDOSK7705) += mach-edosk7705
machdir-$(CONFIG_SH_HIGHLANDER) += mach-highlander
machdir-$(CONFIG_SH_MIGOR) += mach-migor
+machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09
machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780
machdir-$(CONFIG_SH_X3PROTO) += mach-x3proto
machdir-$(CONFIG_SH_SH7763RDP) += mach-sh7763rdp
@@ -186,17 +187,23 @@ KBUILD_CFLAGS += -pipe $(cflags-y)
KBUILD_CPPFLAGS += $(cflags-y)
KBUILD_AFLAGS += $(cflags-y)
+ifeq ($(CONFIG_MCOUNT),y)
+ KBUILD_CFLAGS += -pg
+endif
+
libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y)
libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y)
-PHONY += maketools FORCE
+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
all: $(KBUILD_IMAGE)
-zImage uImage uImage.srec vmlinux.srec: vmlinux
+$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
compressed: zImage
@@ -208,10 +215,14 @@ archclean:
$(Q)$(MAKE) $(clean)=arch/sh/kernel/vsyscall
define archhelp
- @echo '* zImage - Compressed kernel image'
+ @echo ' zImage - Compressed kernel image'
+ @echo ' romImage - Compressed ROM image, if supported'
@echo ' vmlinux.srec - Create an ELF S-record'
- @echo ' uImage - Create a bootable image for U-Boot'
- @echo ' uImage.srec - Create an S-record for U-Boot'
+ @echo '* uImage - Alias to bootable U-Boot image'
+ @echo ' uImage.srec - Create an S-record for U-Boot'
+ @echo '* uImage.gz - Kernel-only image for U-Boot (gzip)'
+ @echo ' uImage.bz2 - Kernel-only image for U-Boot (bzip2)'
+ @echo ' uImage.lzma - Kernel-only image for U-Boot (lzma)'
endef
CLEAN_FILES += include/asm-sh/machtypes.h
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 2b1af0eefa6a..db04c85971ad 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -193,6 +193,13 @@ config SH_AP325RXA
Renesas "AP-325RXA" support.
Compatible with ALGO SYSTEM CO.,LTD. "AP-320A"
+config SH_KFR2R09
+ bool "KFR2R09"
+ depends on CPU_SUBTYPE_SH7724
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ "Kit For R2R for 2009" support.
+
config SH_SH7763RDP
bool "SH7763RDP"
depends on CPU_SUBTYPE_SH7763
diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c
index 1639f8915000..566e69d8d729 100644
--- a/arch/sh/boards/mach-highlander/setup.c
+++ b/arch/sh/boards/mach-highlander/setup.c
@@ -22,6 +22,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/r8a66597.h>
+#include <linux/usb/m66592.h>
#include <net/ax88796.h>
#include <asm/machvec.h>
#include <mach/highlander.h>
@@ -60,6 +61,11 @@ static struct platform_device r8a66597_usb_host_device = {
.resource = r8a66597_usb_host_resources,
};
+static struct m66592_platdata usbf_platdata = {
+ .xtal = M66592_PLATDATA_XTAL_24MHZ,
+ .vif = 1,
+};
+
static struct resource m66592_usb_peripheral_resources[] = {
[0] = {
.name = "m66592_udc",
@@ -81,6 +87,7 @@ static struct platform_device m66592_usb_peripheral_device = {
.dev = {
.dma_mask = NULL, /* don't use dma */
.coherent_dma_mask = 0xffffffff,
+ .platform_data = &usbf_platdata,
},
.num_resources = ARRAY_SIZE(m66592_usb_peripheral_resources),
.resource = m66592_usb_peripheral_resources,
diff --git a/arch/sh/boards/mach-kfr2r09/Makefile b/arch/sh/boards/mach-kfr2r09/Makefile
new file mode 100644
index 000000000000..77037567633b
--- /dev/null
+++ b/arch/sh/boards/mach-kfr2r09/Makefile
@@ -0,0 +1 @@
+obj-y := setup.o
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
new file mode 100644
index 000000000000..bf5f8f8d3b5f
--- /dev/null
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -0,0 +1,153 @@
+/*
+ * KFR2R09 board support code
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/physmap.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <asm/clock.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/sh_keysc.h>
+#include <cpu/sh7724.h>
+
+static struct mtd_partition kfr2r09_nor_flash_partitions[] =
+{
+ {
+ .name = "boot",
+ .offset = 0,
+ .size = (4 * 1024 * 1024),
+ .mask_flags = MTD_WRITEABLE, /* Read-only */
+ },
+ {
+ .name = "other",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct physmap_flash_data kfr2r09_nor_flash_data = {
+ .width = 2,
+ .parts = kfr2r09_nor_flash_partitions,
+ .nr_parts = ARRAY_SIZE(kfr2r09_nor_flash_partitions),
+};
+
+static struct resource kfr2r09_nor_flash_resources[] = {
+ [0] = {
+ .name = "NOR Flash",
+ .start = 0x00000000,
+ .end = 0x03ffffff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device kfr2r09_nor_flash_device = {
+ .name = "physmap-flash",
+ .resource = kfr2r09_nor_flash_resources,
+ .num_resources = ARRAY_SIZE(kfr2r09_nor_flash_resources),
+ .dev = {
+ .platform_data = &kfr2r09_nor_flash_data,
+ },
+};
+
+static struct sh_keysc_info kfr2r09_sh_keysc_info = {
+ .mode = SH_KEYSC_MODE_1, /* KEYOUT0->4, KEYIN0->4 */
+ .scan_timing = 3,
+ .delay = 10,
+ .keycodes = {
+ KEY_PHONE, KEY_CLEAR, KEY_MAIL, KEY_WWW, KEY_ENTER,
+ KEY_1, KEY_2, KEY_3, 0, KEY_UP,
+ KEY_4, KEY_5, KEY_6, 0, KEY_LEFT,
+ KEY_7, KEY_8, KEY_9, KEY_PROG1, KEY_RIGHT,
+ KEY_S, KEY_0, KEY_P, KEY_PROG2, KEY_DOWN,
+ 0, 0, 0, 0, 0
+ },
+};
+
+static struct resource kfr2r09_sh_keysc_resources[] = {
+ [0] = {
+ .name = "KEYSC",
+ .start = 0x044b0000,
+ .end = 0x044b000f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 79,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device kfr2r09_sh_keysc_device = {
+ .name = "sh_keysc",
+ .id = 0, /* "keysc0" clock */
+ .num_resources = ARRAY_SIZE(kfr2r09_sh_keysc_resources),
+ .resource = kfr2r09_sh_keysc_resources,
+ .dev = {
+ .platform_data = &kfr2r09_sh_keysc_info,
+ },
+};
+
+static struct platform_device *kfr2r09_devices[] __initdata = {
+ &kfr2r09_nor_flash_device,
+ &kfr2r09_sh_keysc_device,
+};
+
+#define BSC_CS0BCR 0xfec10004
+#define BSC_CS0WCR 0xfec10024
+
+static int __init kfr2r09_devices_setup(void)
+{
+ /* enable SCIF1 serial port for YC401 console support */
+ gpio_request(GPIO_FN_SCIF1_RXD, NULL);
+ gpio_request(GPIO_FN_SCIF1_TXD, NULL);
+
+ /* setup NOR flash at CS0 */
+ ctrl_outl(0x36db0400, BSC_CS0BCR);
+ ctrl_outl(0x00000500, BSC_CS0WCR);
+
+ /* setup KEYSC pins */
+ gpio_request(GPIO_FN_KEYOUT0, NULL);
+ gpio_request(GPIO_FN_KEYOUT1, NULL);
+ gpio_request(GPIO_FN_KEYOUT2, NULL);
+ gpio_request(GPIO_FN_KEYOUT3, NULL);
+ gpio_request(GPIO_FN_KEYOUT4_IN6, NULL);
+ gpio_request(GPIO_FN_KEYIN0, NULL);
+ gpio_request(GPIO_FN_KEYIN1, NULL);
+ gpio_request(GPIO_FN_KEYIN2, NULL);
+ gpio_request(GPIO_FN_KEYIN3, NULL);
+ gpio_request(GPIO_FN_KEYIN4, NULL);
+ gpio_request(GPIO_FN_KEYOUT5_IN5, NULL);
+
+ return platform_add_devices(kfr2r09_devices,
+ ARRAY_SIZE(kfr2r09_devices));
+}
+device_initcall(kfr2r09_devices_setup);
+
+/* Return the board specific boot mode pin configuration */
+static int kfr2r09_mode_pins(void)
+{
+ /* MD0=1, MD1=1, MD2=0: Clock Mode 3
+ * MD3=0: 16-bit Area0 Bus Width
+ * MD5=1: Little Endian
+ * MD8=1: Test Mode Disabled
+ */
+ return MODE_PIN0 | MODE_PIN1 | MODE_PIN5 | MODE_PIN8;
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_kfr2r09 __initmv = {
+ .mv_name = "kfr2r09",
+ .mv_mode_pins = kfr2r09_mode_pins,
+};
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 8fed45a2fb85..4fb7e48e2843 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -304,6 +304,7 @@ static struct platform_device sh_eth_device = {
};
static struct r8a66597_platdata sh7724_usb0_host_data = {
+ .on_chip = 1,
};
static struct resource sh7724_usb0_host_resources[] = {
diff --git a/arch/sh/boards/mach-x3proto/setup.c b/arch/sh/boards/mach-x3proto/setup.c
index 8913ae39a802..efe4cb9f8a77 100644
--- a/arch/sh/boards/mach-x3proto/setup.c
+++ b/arch/sh/boards/mach-x3proto/setup.c
@@ -17,6 +17,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/r8a66597.h>
+#include <linux/usb/m66592.h>
#include <asm/ilsel.h>
static struct resource heartbeat_resources[] = {
@@ -89,6 +90,11 @@ static struct platform_device r8a66597_usb_host_device = {
.resource = r8a66597_usb_host_resources,
};
+static struct m66592_platdata usbf_platdata = {
+ .xtal = M66592_PLATDATA_XTAL_24MHZ,
+ .vif = 1,
+};
+
static struct resource m66592_usb_peripheral_resources[] = {
[0] = {
.name = "m66592_udc",
@@ -109,6 +115,7 @@ static struct platform_device m66592_usb_peripheral_device = {
.dev = {
.dma_mask = NULL, /* don't use dma */
.coherent_dma_mask = 0xffffffff,
+ .platform_data = &usbf_platdata,
},
.num_resources = ARRAY_SIZE(m66592_usb_peripheral_resources),
.resource = m66592_usb_peripheral_resources,
diff --git a/arch/sh/boot/.gitignore b/arch/sh/boot/.gitignore
index aad5edddf93b..541087d2029c 100644
--- a/arch/sh/boot/.gitignore
+++ b/arch/sh/boot/.gitignore
@@ -1,4 +1,3 @@
zImage
-vmlinux.srec
-uImage
-uImage.srec
+vmlinux*
+uImage*
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index 78efb04c28f3..a1316872be6f 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -20,8 +20,13 @@ CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
CONFIG_ZERO_PAGE_OFFSET ?= 0x00001000
CONFIG_ENTRY_OFFSET ?= 0x00001000
-targets := zImage vmlinux.srec uImage uImage.srec
-subdir- := compressed
+suffix-$(CONFIG_KERNEL_GZIP) := gz
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZMA) := lzma
+
+targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz uImage.bz2 uImage.lzma
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
+subdir- := compressed romimage
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@@ -30,6 +35,13 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(obj)/compressed/vmlinux: FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+$(obj)/romImage: $(obj)/romimage/vmlinux FORCE
+ $(call if_changed,objcopy)
+ @echo ' Kernel: $@ is ready'
+
+$(obj)/romimage/vmlinux: $(obj)/zImage FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/romimage $@
+
KERNEL_MEMORY := 0x00000000
ifeq ($(CONFIG_PMB_FIXED),y)
KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
@@ -40,9 +52,6 @@ KERNEL_MEMORY := $(shell /bin/bash -c 'printf "0x%08x" \
$$[$(CONFIG_MEMORY_START)]')
endif
-export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
- CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET KERNEL_MEMORY
-
KERNEL_LOAD := $(shell /bin/bash -c 'printf "0x%08x" \
$$[$(CONFIG_PAGE_OFFSET) + \
$(KERNEL_MEMORY) + \
@@ -55,19 +64,30 @@ KERNEL_ENTRY := $(shell /bin/bash -c 'printf "0x%08x" \
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
- -C gzip -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
+ -C $(2) -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
-$(obj)/uImage: $(obj)/vmlinux.bin.gz FORCE
- $(call if_changed,uimage)
- @echo ' Image $@ is ready'
-
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,bzip2)
+
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lzma)
+
+$(obj)/uImage.bz2: $(obj)/vmlinux.bin.bz2
+ $(call if_changed,uimage,bzip2)
+
+$(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
+ $(call if_changed,uimage,gzip)
+
+$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
+ $(call if_changed,uimage,lzma)
+
OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
$(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
$(call if_changed,objcopy)
@@ -76,5 +96,9 @@ OBJCOPYFLAGS_uImage.srec := -I binary -O srec
$(obj)/uImage.srec: $(obj)/uImage
$(call if_changed,objcopy)
-clean-files += uImage uImage.srec vmlinux.srec \
- vmlinux.bin vmlinux.bin.gz
+$(obj)/uImage: $(obj)/uImage.$(suffix-y)
+ @ln -sf $(notdir $<) $@
+ @echo ' Image $@ is ready'
+
+export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
+ CONFIG_ZERO_PAGE_OFFSET CONFIG_ENTRY_OFFSET KERNEL_MEMORY suffix-y
diff --git a/arch/sh/boot/compressed/.gitignore b/arch/sh/boot/compressed/.gitignore
new file mode 100644
index 000000000000..2374a83d87b2
--- /dev/null
+++ b/arch/sh/boot/compressed/.gitignore
@@ -0,0 +1 @@
+vmlinux.bin.*
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 9531bf1b7c2f..6182eca5180a 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -5,9 +5,10 @@
#
targets := vmlinux vmlinux.bin vmlinux.bin.gz \
- head_$(BITS).o misc_$(BITS).o piggy.o
+ vmlinux.bin.bz2 vmlinux.bin.lzma \
+ head_$(BITS).o misc.o piggy.o
-OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc_$(BITS).o $(obj)/cache.o
+OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o
ifdef CONFIG_SH_STANDARD_BIOS
OBJECTS += $(obj)/../../kernel/sh_bios.o
@@ -23,7 +24,7 @@ IMAGE_OFFSET := $(shell /bin/bash -c 'printf "0x%08x" \
LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ifeq ($(CONFIG_MCOUNT),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
endif
@@ -38,10 +39,18 @@ $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
-$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+vmlinux.bin.all-y := $(obj)/vmlinux.bin
+
+$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
$(call if_changed,gzip)
+$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
+ $(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
+ $(call if_changed,lzma)
OBJCOPYFLAGS += -R .empty_zero_page
-$(obj)/piggy.o: $(obj)/piggy.S $(obj)/vmlinux.bin.gz FORCE
- $(call if_changed,as_o_S)
+LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
+ $(call if_changed,ld)
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
new file mode 100644
index 000000000000..fd56a71ca9d9
--- /dev/null
+++ b/arch/sh/boot/compressed/misc.c
@@ -0,0 +1,149 @@
+/*
+ * arch/sh/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ */
+
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/sh_bios.h>
+
+/*
+ * gzip declarations
+ */
+
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset ((s), 0, (n))
+
+/* cache.c */
+#define CACHE_ENABLE 0
+#define CACHE_DISABLE 1
+int cache_control(unsigned int command);
+
+extern char input_data[];
+extern int input_len;
+static unsigned char *output;
+
+static void error(char *m);
+
+int puts(const char *);
+
+extern int _text; /* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#ifdef CONFIG_HAVE_KERNEL_BZIP2
+#define HEAP_SIZE 0x400000
+#else
+#define HEAP_SIZE 0x10000
+#endif
+
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_BZIP2
+#include "../../../../lib/decompress_bunzip2.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZMA
+#include "../../../../lib/decompress_unlzma.c"
+#endif
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+size_t strlen(const char *s)
+{
+ int i = 0;
+
+ while (*s++)
+ i++;
+ return i;
+}
+
+int puts(const char *s)
+{
+ int len = strlen(s);
+ sh_bios_console_write(s, len);
+ return len;
+}
+#else
+int puts(const char *s)
+{
+ /* This should be updated to use the sh-sci routines */
+ return 0;
+}
+#endif
+
+void* memset(void* s, int c, size_t n)
+{
+ int i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+ return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+ size_t __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++) d[i] = s[i];
+ return __dest;
+}
+
+static void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+#ifdef CONFIG_SUPERH64
+#define stackalign 8
+#else
+#define stackalign 4
+#endif
+
+#define STACK_SIZE (4096)
+long __attribute__ ((aligned(stackalign))) user_stack[STACK_SIZE];
+long *stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+ unsigned long output_addr;
+
+#ifdef CONFIG_SUPERH64
+ output_addr = (CONFIG_MEMORY_START + 0x2000);
+#else
+ output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+#ifdef CONFIG_29BIT
+ output_addr |= P2SEG;
+#endif
+#endif
+
+ output = (unsigned char *)output_addr;
+ free_mem_ptr = (unsigned long)&_end;
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+ puts("Uncompressing Linux... ");
+ cache_control(CACHE_ENABLE);
+ decompress(input_data, input_len, NULL, NULL, output, NULL, error);
+ cache_control(CACHE_DISABLE);
+ puts("Ok, booting the kernel.\n");
+}
diff --git a/arch/sh/boot/compressed/misc_32.c b/arch/sh/boot/compressed/misc_32.c
deleted file mode 100644
index efdba6b29572..000000000000
--- a/arch/sh/boot/compressed/misc_32.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * arch/sh/boot/compressed/misc.c
- *
- * This is a collection of several routines from gzip-1.0.3
- * adapted for Linux.
- *
- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- *
- * Adapted for SH by Stuart Menefy, Aug 1999
- *
- * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
- */
-
-#include <asm/uaccess.h>
-#include <asm/addrspace.h>
-#include <asm/page.h>
-#ifdef CONFIG_SH_STANDARD_BIOS
-#include <asm/sh_bios.h>
-#endif
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-#define STATIC static
-
-#undef memset
-#undef memcpy
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define WSIZE 0x8000 /* Window size must be at least 32k, */
- /* and a power of two */
-
-static uch *inbuf; /* input buffer */
-static uch window[WSIZE]; /* Sliding window buffer */
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions */
-#ifdef DEBUG
-# define Assert(cond,msg) {if(!(cond)) error(msg);}
-# define Trace(x) fprintf x
-# define Tracev(x) {if (verbose) fprintf x ;}
-# define Tracevv(x) {if (verbose>1) fprintf x ;}
-# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-# define Assert(cond,msg)
-# define Trace(x)
-# define Tracev(x)
-# define Tracevv(x)
-# define Tracec(c,x)
-# define Tracecv(c,x)
-#endif
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-
-extern char input_data[];
-extern int input_len;
-
-static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
-
-static void error(char *m);
-
-int puts(const char *);
-
-extern int _text; /* Defined in vmlinux.lds.S */
-extern int _end;
-static unsigned long free_mem_ptr;
-static unsigned long free_mem_end_ptr;
-
-#define HEAP_SIZE 0x10000
-
-#include "../../../../lib/inflate.c"
-
-#ifdef CONFIG_SH_STANDARD_BIOS
-size_t strlen(const char *s)
-{
- int i = 0;
-
- while (*s++)
- i++;
- return i;
-}
-
-int puts(const char *s)
-{
- int len = strlen(s);
- sh_bios_console_write(s, len);
- return len;
-}
-#else
-int puts(const char *s)
-{
- /* This should be updated to use the sh-sci routines */
- return 0;
-}
-#endif
-
-void* memset(void* s, int c, size_t n)
-{
- int i;
- char *ss = (char*)s;
-
- for (i=0;i<n;i++) ss[i] = c;
- return s;
-}
-
-void* memcpy(void* __dest, __const void* __src,
- size_t __n)
-{
- int i;
- char *d = (char *)__dest, *s = (char *)__src;
-
- for (i=0;i<__n;i++) d[i] = s[i];
- return __dest;
-}
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
- if (insize != 0) {
- error("ran out of input data");
- }
-
- inbuf = input_data;
- insize = input_len;
- inptr = 1;
- return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, *out, ch;
-
- in = window;
- out = &output_data[output_ptr];
- for (n = 0; n < outcnt; n++) {
- ch = *out++ = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- output_ptr += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void error(char *x)
-{
- puts("\n\n");
- puts(x);
- puts("\n\n -- System halted");
-
- while(1); /* Halt */
-}
-
-#define STACK_SIZE (4096)
-long user_stack [STACK_SIZE];
-long* stack_start = &user_stack[STACK_SIZE];
-
-void decompress_kernel(void)
-{
- output_data = NULL;
- output_ptr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
-#ifdef CONFIG_29BIT
- output_ptr |= P2SEG;
-#endif
- free_mem_ptr = (unsigned long)&_end;
- free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-
- makecrc();
- puts("Uncompressing Linux... ");
- gunzip();
- puts("Ok, booting the kernel.\n");
-}
diff --git a/arch/sh/boot/compressed/misc_64.c b/arch/sh/boot/compressed/misc_64.c
deleted file mode 100644
index 2941657e18aa..000000000000
--- a/arch/sh/boot/compressed/misc_64.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * arch/sh/boot/compressed/misc_64.c
- *
- * This is a collection of several routines from gzip-1.0.3
- * adapted for Linux.
- *
- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- *
- * Adapted for SHmedia from sh by Stuart Menefy, May 2002
- */
-
-#include <asm/uaccess.h>
-
-/* cache.c */
-#define CACHE_ENABLE 0
-#define CACHE_DISABLE 1
-int cache_control(unsigned int command);
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-#define STATIC static
-
-#undef memset
-#undef memcpy
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define WSIZE 0x8000 /* Window size must be at least 32k, */
- /* and a power of two */
-
-static uch *inbuf; /* input buffer */
-static uch window[WSIZE]; /* Sliding window buffer */
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions */
-#ifdef DEBUG
-# define Assert(cond,msg) {if(!(cond)) error(msg);}
-# define Trace(x) fprintf x
-# define Tracev(x) {if (verbose) fprintf x ;}
-# define Tracevv(x) {if (verbose>1) fprintf x ;}
-# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-# define Assert(cond,msg)
-# define Trace(x)
-# define Tracev(x)
-# define Tracevv(x)
-# define Tracec(c,x)
-# define Tracecv(c,x)
-#endif
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-
-extern char input_data[];
-extern int input_len;
-
-static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
-
-static void error(char *m);
-
-static void puts(const char *);
-
-extern int _text; /* Defined in vmlinux.lds.S */
-extern int _end;
-static unsigned long free_mem_ptr;
-static unsigned long free_mem_end_ptr;
-
-#define HEAP_SIZE 0x10000
-
-#include "../../../../lib/inflate.c"
-
-void puts(const char *s)
-{
-}
-
-void *memset(void *s, int c, size_t n)
-{
- int i;
- char *ss = (char *) s;
-
- for (i = 0; i < n; i++)
- ss[i] = c;
- return s;
-}
-
-void *memcpy(void *__dest, __const void *__src, size_t __n)
-{
- int i;
- char *d = (char *) __dest, *s = (char *) __src;
-
- for (i = 0; i < __n; i++)
- d[i] = s[i];
- return __dest;
-}
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
- if (insize != 0) {
- error("ran out of input data\n");
- }
-
- inbuf = input_data;
- insize = input_len;
- inptr = 1;
- return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, *out, ch;
-
- in = window;
- out = &output_data[output_ptr];
- for (n = 0; n < outcnt; n++) {
- ch = *out++ = *in++;
- c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg) outcnt;
- output_ptr += (ulg) outcnt;
- outcnt = 0;
- puts(".");
-}
-
-static void error(char *x)
-{
- puts("\n\n");
- puts(x);
- puts("\n\n -- System halted");
-
- while (1) ; /* Halt */
-}
-
-#define STACK_SIZE (4096)
-long __attribute__ ((aligned(8))) user_stack[STACK_SIZE];
-long *stack_start = &user_stack[STACK_SIZE];
-
-void decompress_kernel(void)
-{
- output_data = (uch *) (CONFIG_MEMORY_START + 0x2000);
- free_mem_ptr = (unsigned long) &_end;
- free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-
- makecrc();
- puts("Uncompressing Linux... ");
- cache_control(CACHE_ENABLE);
- gunzip();
- puts("\n");
-
-#if 0
- /* When booting from ROM may want to do something like this if the
- * boot loader doesn't.
- */
-
- /* Set up the parameters and command line */
- {
- volatile unsigned int *parambase =
- (int *) (CONFIG_MEMORY_START + 0x1000);
-
- parambase[0] = 0x1; /* MOUNT_ROOT_RDONLY */
- parambase[1] = 0x0; /* RAMDISK_FLAGS */
- parambase[2] = 0x0200; /* ORIG_ROOT_DEV */
- parambase[3] = 0x0; /* LOADER_TYPE */
- parambase[4] = 0x0; /* INITRD_START */
- parambase[5] = 0x0; /* INITRD_SIZE */
- parambase[6] = 0;
-
- strcpy((char *) ((int) parambase + 0x100),
- "console=ttySC0,38400");
- }
-#endif
-
- puts("Ok, booting the kernel.\n");
-
- cache_control(CACHE_DISABLE);
-}
diff --git a/arch/sh/boot/compressed/piggy.S b/arch/sh/boot/compressed/piggy.S
deleted file mode 100644
index 566071926b13..000000000000
--- a/arch/sh/boot/compressed/piggy.S
+++ /dev/null
@@ -1,8 +0,0 @@
- .global input_len, input_data
- .data
-input_len:
- .long input_data_end - input_data
-input_data:
- .incbin "arch/sh/boot/compressed/vmlinux.bin.gz"
-input_data_end:
- .end
diff --git a/arch/sh/boot/compressed/vmlinux.scr b/arch/sh/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..f02382ae5c48
--- /dev/null
+++ b/arch/sh/boot/compressed/vmlinux.scr
@@ -0,0 +1,10 @@
+SECTIONS
+{
+ .rodata.compressed : {
+ input_len = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ output_len = . - 4;
+ input_data_end = .;
+ }
+}
diff --git a/arch/sh/boot/romimage/Makefile b/arch/sh/boot/romimage/Makefile
new file mode 100644
index 000000000000..5806eee84f6f
--- /dev/null
+++ b/arch/sh/boot/romimage/Makefile
@@ -0,0 +1,19 @@
+#
+# linux/arch/sh/boot/romimage/Makefile
+#
+# create an image suitable for burning to flash from zImage
+#
+
+targets := vmlinux head.o
+
+OBJECTS = $(obj)/head.o
+LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+ $(call if_changed,ld)
+ @:
+
+LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr arch/sh/boot/zImage FORCE
+ $(call if_changed,ld)
diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S
new file mode 100644
index 000000000000..97a087bc9c4a
--- /dev/null
+++ b/arch/sh/boot/romimage/head.S
@@ -0,0 +1,10 @@
+/*
+ * linux/arch/sh/boot/romimage/head.S
+ *
+ * Board specific setup code, executed before zImage loader
+ */
+
+.text
+ .global romstart
+romstart:
+#include <romimage.h>
diff --git a/arch/sh/boot/romimage/vmlinux.scr b/arch/sh/boot/romimage/vmlinux.scr
new file mode 100644
index 000000000000..287c08f8b4bb
--- /dev/null
+++ b/arch/sh/boot/romimage/vmlinux.scr
@@ -0,0 +1,6 @@
+SECTIONS
+{
+ .text : {
+ *(.data)
+ }
+}
diff --git a/arch/sh/configs/kfr2r09_defconfig b/arch/sh/configs/kfr2r09_defconfig
new file mode 100644
index 000000000000..90e575c34d58
--- /dev/null
+++ b/arch/sh/configs/kfr2r09_defconfig
@@ -0,0 +1,877 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc3
+# Thu Jul 23 17:45:09 2009
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+# CONFIG_SUPERH64 is not set
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_SYS_SUPPORTS_CMT=y
+CONFIG_SYS_SUPPORTS_TMU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_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 is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=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
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+CONFIG_ARCH_SHMOBILE=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+CONFIG_CPU_SUBTYPE_SH7724=y
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH7786 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_29BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB 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_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+
+#
+# Cache configuration
+#
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+# CONFIG_SH_7724_SOLUTION_ENGINE is not set
+CONFIG_SH_KFR2R09=y
+
+#
+# Timer and clock configuration
+#
+# CONFIG_SH_TIMER_TMU is not set
+CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_SH_CLK_CPG=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_HIBERNATION is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# 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 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_IEEE802154 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_SH_KEYSC=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+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=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_SH_MOBILE=y
+# 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
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# 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_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# 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 is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_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_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# 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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+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 is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FTRACE_SYSCALLS=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE 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 is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/sh/include/asm/entry-macros.S b/arch/sh/include/asm/entry-macros.S
index 3a4752a65722..1bdd93891cd7 100644
--- a/arch/sh/include/asm/entry-macros.S
+++ b/arch/sh/include/asm/entry-macros.S
@@ -31,6 +31,78 @@
#endif
.endm
+#ifdef CONFIG_TRACE_IRQFLAGS
+
+ .macro TRACE_IRQS_ON
+ mov.l r0, @-r15
+ mov.l r1, @-r15
+ mov.l r2, @-r15
+ mov.l r3, @-r15
+ mov.l r4, @-r15
+ mov.l r5, @-r15
+ mov.l r6, @-r15
+ mov.l r7, @-r15
+
+ mov.l 7834f, r0
+ jsr @r0
+ nop
+
+ mov.l @r15+, r7
+ mov.l @r15+, r6
+ mov.l @r15+, r5
+ mov.l @r15+, r4
+ mov.l @r15+, r3
+ mov.l @r15+, r2
+ mov.l @r15+, r1
+ mov.l @r15+, r0
+ mov.l 7834f, r0
+
+ bra 7835f
+ nop
+ .balign 4
+7834: .long trace_hardirqs_on
+7835:
+ .endm
+ .macro TRACE_IRQS_OFF
+
+ mov.l r0, @-r15
+ mov.l r1, @-r15
+ mov.l r2, @-r15
+ mov.l r3, @-r15
+ mov.l r4, @-r15
+ mov.l r5, @-r15
+ mov.l r6, @-r15
+ mov.l r7, @-r15
+
+ mov.l 7834f, r0
+ jsr @r0
+ nop
+
+ mov.l @r15+, r7
+ mov.l @r15+, r6
+ mov.l @r15+, r5
+ mov.l @r15+, r4
+ mov.l @r15+, r3
+ mov.l @r15+, r2
+ mov.l @r15+, r1
+ mov.l @r15+, r0
+ mov.l 7834f, r0
+
+ bra 7835f
+ nop
+ .balign 4
+7834: .long trace_hardirqs_off
+7835:
+ .endm
+
+#else
+ .macro TRACE_IRQS_ON
+ .endm
+
+ .macro TRACE_IRQS_OFF
+ .endm
+#endif
+
#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
# define PREF(x) pref @x
#else
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h
index 8fea7d8c8258..7e0bcc4d4a96 100644
--- a/arch/sh/include/asm/ftrace.h
+++ b/arch/sh/include/asm/ftrace.h
@@ -11,10 +11,13 @@ extern void mcount(void);
#define MCOUNT_ADDR ((long)(mcount))
#ifdef CONFIG_DYNAMIC_FTRACE
-#define CALLER_ADDR ((long)(ftrace_caller))
+#define CALL_ADDR ((long)(ftrace_call))
#define STUB_ADDR ((long)(ftrace_stub))
+#define GRAPH_ADDR ((long)(ftrace_graph_call))
+#define CALLER_ADDR ((long)(ftrace_caller))
-#define MCOUNT_INSN_OFFSET ((STUB_ADDR - CALLER_ADDR) >> 1)
+#define MCOUNT_INSN_OFFSET ((STUB_ADDR - CALL_ADDR) - 4)
+#define GRAPH_INSN_OFFSET ((CALLER_ADDR - GRAPH_ADDR) - 4)
struct dyn_arch_ftrace {
/* No extra data needed on sh */
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
new file mode 100644
index 000000000000..c01d72cb6757
--- /dev/null
+++ b/arch/sh/include/asm/hwblk.h
@@ -0,0 +1,70 @@
+#ifndef __ASM_SH_HWBLK_H
+#define __ASM_SH_HWBLK_H
+
+#include <asm/clock.h>
+#include <asm/io.h>
+
+#define HWBLK_CNT_USAGE 0
+#define HWBLK_CNT_NR 1
+
+#define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
+
+#define HWBLK_AREA(_flags, _parent) \
+{ \
+ .flags = _flags, \
+ .parent = _parent, \
+}
+
+struct hwblk_area {
+ int cnt[HWBLK_CNT_NR];
+ unsigned char parent;
+ unsigned char flags;
+};
+
+#define HWBLK(_mstp, _bit, _area) \
+{ \
+ .mstp = (void __iomem *)_mstp, \
+ .bit = _bit, \
+ .area = _area, \
+}
+
+struct hwblk {
+ void __iomem *mstp;
+ unsigned char bit;
+ unsigned char area;
+ int cnt[HWBLK_CNT_NR];
+};
+
+struct hwblk_info {
+ struct hwblk_area *areas;
+ int nr_areas;
+ struct hwblk *hwblks;
+ int nr_hwblks;
+};
+
+/* Should be defined by processor-specific code */
+int arch_hwblk_init(void);
+int arch_hwblk_sleep_mode(void);
+
+int hwblk_register(struct hwblk_info *info);
+int hwblk_init(void);
+
+void hwblk_enable(struct hwblk_info *info, int hwblk);
+void hwblk_disable(struct hwblk_info *info, int hwblk);
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
+
+/* allow clocks to enable and disable hardware blocks */
+#define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags) \
+{ \
+ .name = _name, \
+ .id = _id, \
+ .parent = _parent, \
+ .arch_flags = _hwblk, \
+ .flags = _flags, \
+}
+
+int sh_hwblk_clk_register(struct clk *clks, int nr);
+
+#endif /* __ASM_SH_HWBLK_H */
diff --git a/arch/sh/include/asm/lmb.h b/arch/sh/include/asm/lmb.h
new file mode 100644
index 000000000000..9b437f657ffa
--- /dev/null
+++ b/arch/sh/include/asm/lmb.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_SH_LMB_H
+#define __ASM_SH_LMB_H
+
+#define LMB_REAL_LIMIT 0
+
+#endif /* __ASM_SH_LMB_H */
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index d3633f513ebc..4163950cd1c6 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -10,7 +10,6 @@
or architectures with incomplete PCI setup by the loader */
#define pcibios_assign_all_busses() 1
-#define pcibios_scan_all_fns(a, b) 0
/*
* A board can define one or more PCI channels that represent built-in (or
diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h
index 84dd2db7104c..63ca37bd9a95 100644
--- a/arch/sh/include/asm/pgalloc.h
+++ b/arch/sh/include/asm/pgalloc.h
@@ -73,20 +73,12 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
quicklist_free_page(QUICK_PT, NULL, pte);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte,addr) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb), (pte)); \
} while (0)
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-
-#define pmd_free(mm, x) do { } while (0)
-#define __pmd_free_tlb(tlb,x) do { } while (0)
-
static inline void check_pgt_cache(void)
{
quicklist_trim(QUICK_PGD, NULL, 25, 16);
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index 72ea209195bd..0db19db913c7 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -20,7 +20,7 @@
* - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE.
*
* - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages.
- * Bit 10 is used for _PAGE_ACCESSED, bit 11 remains unused.
+ * Bit 10 is used for _PAGE_ACCESSED, and bit 11 is used for _PAGE_SPECIAL.
*
* - On 29 bit platforms, bits 31 to 29 are used for the space attributes
* and timing control which (together with bit 0) are moved into the
@@ -52,6 +52,7 @@
#define _PAGE_PROTNONE 0x200 /* software: if not present */
#define _PAGE_ACCESSED 0x400 /* software: page referenced */
#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
+#define _PAGE_SPECIAL 0x800 /* software: special page */
#define _PAGE_SZ_MASK (_PAGE_SZ0 | _PAGE_SZ1)
#define _PAGE_PR_MASK (_PAGE_RW | _PAGE_USER)
@@ -148,8 +149,12 @@
# define _PAGE_SZHUGE (_PAGE_FLAGS_HARD)
#endif
+/*
+ * Mask of bits that are to be preserved accross pgprot changes.
+ */
#define _PAGE_CHG_MASK \
- (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
+ (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \
+ _PAGE_DIRTY | _PAGE_SPECIAL)
#ifndef __ASSEMBLY__
@@ -328,7 +333,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
#define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY)
#define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED)
#define pte_file(pte) ((pte).pte_low & _PAGE_FILE)
-#define pte_special(pte) (0)
+#define pte_special(pte) ((pte).pte_low & _PAGE_SPECIAL)
#ifdef CONFIG_X2TLB
#define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE)
@@ -358,8 +363,9 @@ PTE_BIT_FUNC(low, mkclean, &= ~_PAGE_DIRTY);
PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY);
PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
+PTE_BIT_FUNC(low, mkspecial, |= _PAGE_SPECIAL);
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+#define __HAVE_ARCH_PTE_SPECIAL
/*
* Macro and implementation to make a page protection as uncachable.
diff --git a/arch/sh/include/asm/smp.h b/arch/sh/include/asm/smp.h
index ca64f43abe67..53ef26ced75f 100644
--- a/arch/sh/include/asm/smp.h
+++ b/arch/sh/include/asm/smp.h
@@ -44,7 +44,6 @@ void plat_send_ipi(unsigned int cpu, unsigned int message);
void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
#else
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
index b1b995370e79..5c8ea28ff7a4 100644
--- a/arch/sh/include/asm/suspend.h
+++ b/arch/sh/include/asm/suspend.h
@@ -10,6 +10,15 @@ struct swsusp_arch_regs {
struct pt_regs user_regs;
unsigned long bank1_regs[8];
};
+
+void sh_mobile_call_standby(unsigned long mode);
+
+#ifdef CONFIG_CPU_IDLE
+void sh_mobile_setup_cpuidle(void);
+#else
+static inline void sh_mobile_setup_cpuidle(void) {}
+#endif
+
#endif
/* flags passed to assembly suspend code */
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index 6f83f2cc45c1..7d80df4f09cb 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -65,6 +65,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
case 3: args[2] = regs->regs[6];
case 2: args[1] = regs->regs[5];
case 1: args[0] = regs->regs[4];
+ case 0:
break;
default:
BUG();
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index d570ac2e5cb9..5123bcaa8509 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -97,7 +97,7 @@ static inline struct thread_info *current_thread_info(void)
extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
extern void free_thread_info(struct thread_info *ti);
-
+
#endif /* THREAD_SHIFT < PAGE_SHIFT */
#endif /* __ASSEMBLY__ */
@@ -116,6 +116,7 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
+#define TIF_SYSCALL_FTRACE 8 /* for ftrace syscall instrumentation */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
@@ -129,25 +130,27 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE)
#define _TIF_USEDFPU (1 << TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_FREEZE (1 << TIF_FREEZE)
/*
- * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within a byte, or we
+ * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
* blow the tst immediate size constraints and need to fix up
* arch/sh/kernel/entry-common.S.
*/
/* work to do in syscall trace */
#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
- _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
+ _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
+ _TIF_SYSCALL_FTRACE)
/* 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_NOTIFY_RESUME | _TIF_SYSCALL_FTRACE)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h
index 9c16f737074a..da8fe7ab8728 100644
--- a/arch/sh/include/asm/tlb.h
+++ b/arch/sh/include/asm/tlb.h
@@ -91,9 +91,9 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
}
#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep) pte_free((tlb)->mm, ptep)
-#define pmd_free_tlb(tlb, pmdp) pmd_free((tlb)->mm, pmdp)
-#define pud_free_tlb(tlb, pudp) pud_free((tlb)->mm, pudp)
+#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp)
+#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
#define tlb_migrate_finish(mm) do { } while (0)
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index b69ee850906d..b2180f8752ce 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -31,7 +31,6 @@
#define cpu_to_node(cpu) ((void)(cpu),0)
#define parent_node(node) ((void)(node),0)
-#define node_to_cpumask(node) ((void)node, cpu_online_map)
#define cpumask_of_node(node) ((void)node, cpu_online_mask)
#define pcibus_to_node(bus) ((void)(bus), -1)
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7722.h b/arch/sh/include/cpu-sh4/cpu/sh7722.h
index 738ea43c5038..48560407cbe1 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7722.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7722.h
@@ -221,4 +221,18 @@ enum {
GPIO_FN_KEYOUT3, GPIO_FN_KEYOUT4_IN6, GPIO_FN_KEYOUT5_IN5,
};
+enum {
+ HWBLK_UNKNOWN = 0,
+ HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_URAM, HWBLK_XYMEM,
+ HWBLK_INTC, HWBLK_DMAC, HWBLK_SHYWAY, HWBLK_HUDI,
+ HWBLK_UBC, HWBLK_TMU, HWBLK_CMT, HWBLK_RWDT, HWBLK_FLCTL,
+ HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_SIO,
+ HWBLK_SIOF0, HWBLK_SIOF1, HWBLK_IIC, HWBLK_RTC,
+ HWBLK_TPU, HWBLK_IRDA, HWBLK_SDHI, HWBLK_SIM, HWBLK_KEYSC,
+ HWBLK_TSIF, HWBLK_USBF, HWBLK_2DG, HWBLK_SIU, HWBLK_VOU,
+ HWBLK_JPU, HWBLK_BEU, HWBLK_CEU, HWBLK_VEU, HWBLK_VPU,
+ HWBLK_LCDC,
+ HWBLK_NR,
+};
+
#endif /* __ASM_SH7722_H__ */
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7723.h b/arch/sh/include/cpu-sh4/cpu/sh7723.h
index 14c8ca936781..9b36fae72324 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7723.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7723.h
@@ -265,4 +265,21 @@ enum {
GPIO_FN_IDEA1, GPIO_FN_IDEA0,
};
+enum {
+ HWBLK_UNKNOWN = 0,
+ HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_L2C, HWBLK_ILMEM, HWBLK_FPU,
+ HWBLK_INTC, HWBLK_DMAC0, HWBLK_SHYWAY,
+ HWBLK_HUDI, HWBLK_DBG, HWBLK_UBC, HWBLK_SUBC,
+ HWBLK_TMU0, HWBLK_CMT, HWBLK_RWDT, HWBLK_DMAC1, HWBLK_TMU1,
+ HWBLK_FLCTL,
+ HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2,
+ HWBLK_SCIF3, HWBLK_SCIF4, HWBLK_SCIF5,
+ HWBLK_MSIOF0, HWBLK_MSIOF1, HWBLK_MERAM, HWBLK_IIC, HWBLK_RTC,
+ HWBLK_ATAPI, HWBLK_ADC, HWBLK_TPU, HWBLK_IRDA, HWBLK_TSIF, HWBLK_ICB,
+ HWBLK_SDHI0, HWBLK_SDHI1, HWBLK_KEYSC, HWBLK_USB,
+ HWBLK_2DG, HWBLK_SIU, HWBLK_VEU2H1, HWBLK_VOU, HWBLK_BEU, HWBLK_CEU,
+ HWBLK_VEU2H0, HWBLK_VPU, HWBLK_LCDC,
+ HWBLK_NR,
+};
+
#endif /* __ASM_SH7723_H__ */
diff --git a/arch/sh/include/mach-common/romimage.h b/arch/sh/include/mach-common/romimage.h
new file mode 100644
index 000000000000..267e24112d82
--- /dev/null
+++ b/arch/sh/include/mach-common/romimage.h
@@ -0,0 +1 @@
+/* do nothing here by default */
diff --git a/arch/sh/include/mach-kfr2r09/partner-jet-setup.txt b/arch/sh/include/mach-kfr2r09/partner-jet-setup.txt
new file mode 100644
index 000000000000..9c85088728a7
--- /dev/null
+++ b/arch/sh/include/mach-kfr2r09/partner-jet-setup.txt
@@ -0,0 +1,134 @@
+LIST "partner-jet-setup.txt - 20090729 Magnus Damm"
+LIST "set up enough of the kfr2r09 hardware to boot the kernel"
+
+LIST "zImage (RAM boot)"
+LIST "This script can be used to boot the kernel from RAM via JTAG:"
+LIST "> < partner-jet-setup.txt"
+LIST "> RD zImage, 0xa8800000"
+LIST "> G=0xa8800000"
+
+LIST "romImage (Flash boot)"
+LIST "Use the following command to burn the zImage to flash via JTAG:"
+LIST "> RD romImage, 0"
+
+LIST "--------------------------------"
+
+LIST "disable watchdog"
+EW 0xa4520004, 0xa507
+
+LIST "select mode for cs5 + cs6"
+ED 0xff800020, 0xa5a50001
+ED 0xfec10000, 0x0000001b
+
+LIST "setup clocks"
+ED 0xa4150004, 0x00000050
+ED 0xa4150000, 0x91053508
+WAIT 1
+ED 0xa4150024, 0x00005000
+
+LIST "setup pins"
+EB 0xa4050120, 0x00
+EB 0xa4050122, 0x00
+EB 0xa4050124, 0x00
+EB 0xa4050126, 0x00
+EB 0xa4050128, 0xA0
+EB 0xa405012A, 0x10
+EB 0xa405012C, 0x00
+EB 0xa405012E, 0x00
+EB 0xa4050130, 0x00
+EB 0xa4050132, 0x00
+EB 0xa4050134, 0x01
+EB 0xa4050136, 0x40
+EB 0xa4050138, 0x00
+EB 0xa405013A, 0x00
+EB 0xa405013C, 0x00
+EB 0xa405013E, 0x20
+EB 0xa4050160, 0x00
+EB 0xa4050162, 0x40
+EB 0xa4050164, 0x03
+EB 0xa4050166, 0x00
+EB 0xa4050168, 0x00
+EB 0xa405016A, 0x00
+EB 0xa405016C, 0x00
+
+EW 0xa405014E, 0x5660
+EW 0xa4050150, 0x0145
+EW 0xa4050152, 0x1550
+EW 0xa4050154, 0x0200
+EW 0xa4050156, 0x0040
+
+EW 0xa4050158, 0x0000
+EW 0xa405015a, 0x0000
+EW 0xa405015c, 0x0000
+EW 0xa405015e, 0x0000
+
+EW 0xa4050180, 0x0000
+EW 0xa4050182, 0x8002
+EW 0xa4050184, 0x0000
+
+EW 0xa405018a, 0x9991
+EW 0xa405018c, 0x8011
+EW 0xa405018e, 0x9550
+
+EW 0xa4050100, 0x0000
+EW 0xa4050102, 0x5540
+EW 0xa4050104, 0x0000
+EW 0xa4050106, 0x0000
+EW 0xa4050108, 0x4550
+EW 0xa405010a, 0x0130
+EW 0xa405010c, 0x0555
+EW 0xa405010e, 0x0000
+EW 0xa4050110, 0x0000
+EW 0xa4050112, 0xAAA8
+EW 0xa4050114, 0x8305
+EW 0xa4050116, 0x10F0
+EW 0xa4050118, 0x0F50
+EW 0xa405011a, 0x0000
+EW 0xa405011c, 0x0000
+EW 0xa405011e, 0x0555
+EW 0xa4050140, 0x0000
+EW 0xa4050142, 0x5141
+EW 0xa4050144, 0x5005
+EW 0xa4050146, 0xAAA9
+EW 0xa4050148, 0xFAA9
+EW 0xa405014a, 0x3000
+EW 0xa405014c, 0x0000
+
+LIST "setup sdram"
+ED 0xFD000108, 0x40000301
+ED 0xFD000020, 0x011B0002
+ED 0xFD000030, 0x03060E02
+ED 0xFD000034, 0x01020102
+ED 0xFD000038, 0x01090406
+ED 0xFD000008, 0x00000004
+ED 0xFD000040, 0x00000001
+ED 0xFD000040, 0x00000000
+ED 0xFD000018, 0x00000001
+
+WAIT 1
+
+ED 0xFD000014, 0x00000002
+ED 0xFD000060, 0x00000032
+ED 0xFD000060, 0x00020000
+ED 0xFD000014, 0x00000004
+ED 0xFD000014, 0x00000004
+ED 0xFD000010, 0x00000001
+ED 0xFD000044, 0x000004AF
+ED 0xFD000048, 0x20CF0037
+
+LIST "read 16 bytes from sdram"
+DD 0xa8000000, 0xa8000000, 1
+DD 0xa8000004, 0xa8000004, 1
+DD 0xa8000008, 0xa8000008, 1
+DD 0xa800000c, 0xa800000c, 1
+
+ED 0xFD000014, 0x00000002
+ED 0xFD000014, 0x00000004
+ED 0xFD000108, 0x40000300
+ED 0xFD000040, 0x00010000
+
+LIST "write to internal ram"
+ED 0xfd8007fc, 0
+
+LIST "setup cache"
+ED 0xff00001c, 0x0000090b
diff --git a/arch/sh/include/mach-kfr2r09/romimage.h b/arch/sh/include/mach-kfr2r09/romimage.h
new file mode 100644
index 000000000000..f5aa8e16770c
--- /dev/null
+++ b/arch/sh/include/mach-kfr2r09/romimage.h
@@ -0,0 +1,75 @@
+/* kfr2r09 board specific boot code:
+ * converts the "partner-jet-script.txt" script into assembly
+ * the assembly code is the first code to be executed in the romImage
+ */
+
+/* The LIST command is used to include comments in the script */
+.macro LIST comment
+.endm
+
+/* The ED command is used to write a 32-bit word */
+.macro ED, addr, data
+ mov.l 1f ,r1
+ mov.l 2f ,r0
+ mov.l r0, @r1
+ bra 3f
+ nop
+ .align 2
+1: .long \addr
+2: .long \data
+3:
+.endm
+
+/* The EW command is used to write a 16-bit word */
+.macro EW, addr, data
+ mov.l 1f ,r1
+ mov.l 2f ,r0
+ mov.w r0, @r1
+ bra 3f
+ nop
+ .align 2
+1: .long \addr
+2: .long \data
+3:
+.endm
+
+/* The EB command is used to write an 8-bit word */
+.macro EB, addr, data
+ mov.l 1f ,r1
+ mov.l 2f ,r0
+ mov.b r0, @r1
+ bra 3f
+ nop
+ .align 2
+1: .long \addr
+2: .long \data
+3:
+.endm
+
+/* The WAIT command is used to delay the execution */
+.macro WAIT, time
+ mov.l 2f ,r3
+1:
+ nop
+ tst r3, r3
+ bf/s 1b
+ dt r3
+ bra 3f
+ nop
+ .align 2
+2: .long \time * 100
+3:
+.endm
+
+/* The DD command is used to read a 32-bit word */
+.macro DD, addr, addr2, nr
+ mov.l 1f ,r1
+ mov.l @r1, r0
+ bra 2f
+ nop
+ .align 2
+1: .long \addr
+2:
+.endm
+
+#include "partner-jet-setup.txt"
diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
index 9411e3e31e68..94ed99b68002 100644
--- a/arch/sh/kernel/Makefile_32
+++ b/arch/sh/kernel/Makefile_32
@@ -29,6 +29,8 @@ obj-$(CONFIG_IO_TRAPPED) += io_trapped.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_GENERIC_GPIO) += gpio.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c
index 99aceb28ee24..d218e808294e 100644
--- a/arch/sh/kernel/asm-offsets.c
+++ b/arch/sh/kernel/asm-offsets.c
@@ -26,6 +26,7 @@ int main(void)
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
+ DEFINE(TI_SIZE, sizeof(struct thread_info));
#ifdef CONFIG_HIBERNATION
DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index eecad7cbd61e..3d6b9312dc47 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -19,4 +19,4 @@ obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
-obj-y += irq/ init.o clock.o
+obj-y += irq/ init.o clock.o hwblk.o
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c
new file mode 100644
index 000000000000..c0ad7d46e784
--- /dev/null
+++ b/arch/sh/kernel/cpu/hwblk.c
@@ -0,0 +1,155 @@
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <asm/clock.h>
+
+static DEFINE_SPINLOCK(hwblk_lock);
+
+static void hwblk_area_mod_cnt(struct hwblk_info *info,
+ int area, int counter, int value, int goal)
+{
+ struct hwblk_area *hap = info->areas + area;
+
+ hap->cnt[counter] += value;
+
+ if (hap->cnt[counter] != goal)
+ return;
+
+ if (hap->flags & HWBLK_AREA_FLAG_PARENT)
+ hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
+}
+
+
+static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+ int counter, int value, int goal)
+{
+ struct hwblk *hp = info->hwblks + hwblk;
+
+ hp->cnt[counter] += value;
+ if (hp->cnt[counter] == goal)
+ hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
+
+ return hp->cnt[counter];
+}
+
+static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+ int counter, int value, int goal)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwblk_lock, flags);
+ __hwblk_mod_cnt(info, hwblk, counter, value, goal);
+ spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
+{
+ hwblk_mod_cnt(info, hwblk, counter, 1, 1);
+}
+
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
+{
+ hwblk_mod_cnt(info, hwblk, counter, -1, 0);
+}
+
+void hwblk_enable(struct hwblk_info *info, int hwblk)
+{
+ struct hwblk *hp = info->hwblks + hwblk;
+ unsigned long tmp;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hwblk_lock, flags);
+
+ ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
+ if (ret == 1) {
+ tmp = __raw_readl(hp->mstp);
+ tmp &= ~(1 << hp->bit);
+ __raw_writel(tmp, hp->mstp);
+ }
+
+ spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_disable(struct hwblk_info *info, int hwblk)
+{
+ struct hwblk *hp = info->hwblks + hwblk;
+ unsigned long tmp;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hwblk_lock, flags);
+
+ ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
+ if (ret == 0) {
+ tmp = __raw_readl(hp->mstp);
+ tmp |= 1 << hp->bit;
+ __raw_writel(tmp, hp->mstp);
+ }
+
+ spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+struct hwblk_info *hwblk_info;
+
+int __init hwblk_register(struct hwblk_info *info)
+{
+ hwblk_info = info;
+ return 0;
+}
+
+int __init __weak arch_hwblk_init(void)
+{
+ return 0;
+}
+
+int __weak arch_hwblk_sleep_mode(void)
+{
+ return SUSP_SH_SLEEP;
+}
+
+int __init hwblk_init(void)
+{
+ return arch_hwblk_init();
+}
+
+/* allow clocks to enable and disable hardware blocks */
+static int sh_hwblk_clk_enable(struct clk *clk)
+{
+ if (!hwblk_info)
+ return -ENOENT;
+
+ hwblk_enable(hwblk_info, clk->arch_flags);
+ return 0;
+}
+
+static void sh_hwblk_clk_disable(struct clk *clk)
+{
+ if (hwblk_info)
+ hwblk_disable(hwblk_info, clk->arch_flags);
+}
+
+static struct clk_ops sh_hwblk_clk_ops = {
+ .enable = sh_hwblk_clk_enable,
+ .disable = sh_hwblk_clk_disable,
+ .recalc = followparent_recalc,
+};
+
+int __init sh_hwblk_clk_register(struct clk *clks, int nr)
+{
+ struct clk *clkp;
+ int ret = 0;
+ int k;
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+ clkp->ops = &sh_hwblk_clk_ops;
+ ret |= clk_register(clkp);
+ }
+
+ return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index 13798733f2db..8555c05e8667 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -187,7 +187,7 @@ static int __init sh7619_devices_setup(void)
return platform_add_devices(sh7619_devices,
ARRAY_SIZE(sh7619_devices));
}
-__initcall(sh7619_devices_setup);
+arch_initcall(sh7619_devices_setup);
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index 869c2da4820b..b67376445315 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -238,7 +238,7 @@ static int __init mxg_devices_setup(void)
return platform_add_devices(mxg_devices,
ARRAY_SIZE(mxg_devices));
}
-__initcall(mxg_devices_setup);
+arch_initcall(mxg_devices_setup);
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index d8febe128066..fbde5b75deb9 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -357,7 +357,7 @@ static int __init sh7201_devices_setup(void)
return platform_add_devices(sh7201_devices,
ARRAY_SIZE(sh7201_devices));
}
-__initcall(sh7201_devices_setup);
+arch_initcall(sh7201_devices_setup);
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index 62e3039d2398..d3fd536c9a84 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -367,7 +367,7 @@ static int __init sh7203_devices_setup(void)
return platform_add_devices(sh7203_devices,
ARRAY_SIZE(sh7203_devices));
}
-__initcall(sh7203_devices_setup);
+arch_initcall(sh7203_devices_setup);
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 3e6f3d7a58be..a9ccc5e8d9e9 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -338,7 +338,7 @@ static int __init sh7206_devices_setup(void)
return platform_add_devices(sh7206_devices,
ARRAY_SIZE(sh7206_devices));
}
-__initcall(sh7206_devices_setup);
+arch_initcall(sh7206_devices_setup);
void __init plat_irq_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index 88f742fed9ed..c23105983878 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -222,7 +222,7 @@ static int __init sh7705_devices_setup(void)
return platform_add_devices(sh7705_devices,
ARRAY_SIZE(sh7705_devices));
}
-__initcall(sh7705_devices_setup);
+arch_initcall(sh7705_devices_setup);
static struct platform_device *sh7705_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index c56306798584..347ab35d0697 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -250,7 +250,7 @@ static int __init sh770x_devices_setup(void)
return platform_add_devices(sh770x_devices,
ARRAY_SIZE(sh770x_devices));
}
-__initcall(sh770x_devices_setup);
+arch_initcall(sh770x_devices_setup);
static struct platform_device *sh770x_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index efa76c8148f4..717e90ae1097 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -226,7 +226,7 @@ static int __init sh7710_devices_setup(void)
return platform_add_devices(sh7710_devices,
ARRAY_SIZE(sh7710_devices));
}
-__initcall(sh7710_devices_setup);
+arch_initcall(sh7710_devices_setup);
static struct platform_device *sh7710_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index 5b2107798edb..74d8baaf8e96 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -388,7 +388,7 @@ static int __init sh7720_devices_setup(void)
return platform_add_devices(sh7720_devices,
ARRAY_SIZE(sh7720_devices));
}
-__initcall(sh7720_devices_setup);
+arch_initcall(sh7720_devices_setup);
static struct platform_device *sh7720_early_devices[] __initdata = {
&cmt0_device,
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 6d088d123591..de4827df19aa 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -138,7 +138,7 @@ static int __init sh4202_devices_setup(void)
return platform_add_devices(sh4202_devices,
ARRAY_SIZE(sh4202_devices));
}
-__initcall(sh4202_devices_setup);
+arch_initcall(sh4202_devices_setup);
static struct platform_device *sh4202_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 851672d15cf4..1b8b122e8f3d 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -239,7 +239,7 @@ static int __init sh7750_devices_setup(void)
return platform_add_devices(sh7750_devices,
ARRAY_SIZE(sh7750_devices));
}
-__initcall(sh7750_devices_setup);
+arch_initcall(sh7750_devices_setup);
static struct platform_device *sh7750_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index 5b822519bd90..7fbb7be9284c 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -265,7 +265,7 @@ static int __init sh7760_devices_setup(void)
return platform_add_devices(sh7760_devices,
ARRAY_SIZE(sh7760_devices));
}
-__initcall(sh7760_devices_setup);
+arch_initcall(sh7760_devices_setup);
static struct platform_device *sh7760_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index ebdd391d5f42..1d7ae38bc611 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -25,8 +25,8 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o hwblk-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o hwblk-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 40f859354f79..1fa9e1dd1cc8 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -22,6 +22,8 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <asm/clock.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7722.h>
/* SH7722 registers */
#define FRQCR 0xa4150000
@@ -140,35 +142,37 @@ struct clk div6_clks[] = {
SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
};
-#define MSTP(_str, _parent, _reg, _bit, _flags) \
- SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
+#define R_CLK &r_clk
+#define P_CLK &div4_clks[DIV4_P]
+#define B_CLK &div4_clks[DIV4_B]
+#define U_CLK &div4_clks[DIV4_U]
static struct clk mstp_clks[] = {
- MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
- MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
- MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
- MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
- MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
- MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
- MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
- MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
- MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
-
- MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
- MSTP("rtc0", &r_clk, MSTPCR1, 8, 0),
-
- MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
- MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
- MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
- MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
- MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
- MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
- MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
- MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
- MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
- MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
- MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
- MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
+ SH_HWBLK_CLK("uram0", -1, U_CLK, HWBLK_URAM, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("xymem0", -1, B_CLK, HWBLK_XYMEM, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU, 0),
+ SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0),
+ SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0),
+ SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0),
+ SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0),
+ SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0),
+ SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0),
+
+ SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0),
+ SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0),
+
+ SH_HWBLK_CLK("sdhi0", -1, P_CLK, HWBLK_SDHI, 0),
+ SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0),
+ SH_HWBLK_CLK("usbf0", -1, P_CLK, HWBLK_USBF, 0),
+ SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
+ SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
+ SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
+ SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
+ SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
+ SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0),
};
int __init arch_clk_init(void)
@@ -191,7 +195,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
if (!ret)
- ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+ ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks));
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
index e67c2678b8ae..bf64c78eee34 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
@@ -22,6 +22,8 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <asm/clock.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7723.h>
/* SH7723 registers */
#define FRQCR 0xa4150000
@@ -140,60 +142,64 @@ struct clk div6_clks[] = {
SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
};
-#define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \
- SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT)
+#define R_CLK (&r_clk)
+#define P_CLK (&div4_clks[DIV4_P])
+#define B_CLK (&div4_clks[DIV4_B])
+#define U_CLK (&div4_clks[DIV4_U])
+#define I_CLK (&div4_clks[DIV4_I])
+#define SH_CLK (&div4_clks[DIV4_SH])
static struct clk mstp_clks[] = {
/* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
- MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0),
- MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0),
- MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0),
- MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 28, 1, 1, 0),
- MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0),
- MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0),
- MSTP("intc0", &div4_clks[DIV4_I], MSTPCR0, 22, 1, 1, 0),
- MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1),
- MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0),
- MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0),
- MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0),
- MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0),
- MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0),
- MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0),
- MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1),
- MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 11, 0, 1, 0),
- MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0),
- MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0),
- MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0),
- MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0),
- MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0),
- MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0),
- MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0),
- MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0),
- MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0),
- MSTP("meram0", &div4_clks[DIV4_SH], MSTPCR0, 0, 1, 1, 0),
-
- MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0),
- MSTP("rtc0", &r_clk, MSTPCR1, 8, 0, 0, 0),
-
- MSTP("atapi0", &div4_clks[DIV4_SH], MSTPCR2, 28, 0, 1, 0),
- MSTP("adc0", &div4_clks[DIV4_P], MSTPCR2, 27, 0, 1, 0),
- MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0),
- MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0),
- MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0),
- MSTP("icb0", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1),
- MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0),
- MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0),
- MSTP("keysc0", &r_clk, MSTPCR2, 14, 0, 0, 0),
- MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 11, 0, 1, 0),
- MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 10, 0, 1, 1),
- MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0, 1, 0),
- MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1),
- MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1),
- MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1),
- MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1),
- MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1),
- MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1),
- MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1),
+ SH_HWBLK_CLK("tlb0", -1, I_CLK, HWBLK_TLB, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("ic0", -1, I_CLK, HWBLK_IC, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("oc0", -1, I_CLK, HWBLK_OC, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("l2c0", -1, SH_CLK, HWBLK_L2C, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("ilmem0", -1, I_CLK, HWBLK_ILMEM, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("fpu0", -1, I_CLK, HWBLK_FPU, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("intc0", -1, I_CLK, HWBLK_INTC, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("dmac0", -1, B_CLK, HWBLK_DMAC0, 0),
+ SH_HWBLK_CLK("sh0", -1, SH_CLK, HWBLK_SHYWAY, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("hudi0", -1, P_CLK, HWBLK_HUDI, 0),
+ SH_HWBLK_CLK("ubc0", -1, I_CLK, HWBLK_UBC, 0),
+ SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU0, 0),
+ SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0),
+ SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0),
+ SH_HWBLK_CLK("dmac1", -1, B_CLK, HWBLK_DMAC1, 0),
+ SH_HWBLK_CLK("tmu1", -1, P_CLK, HWBLK_TMU1, 0),
+ SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0),
+ SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0),
+ SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0),
+ SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0),
+ SH_HWBLK_CLK("scif3", -1, B_CLK, HWBLK_SCIF3, 0),
+ SH_HWBLK_CLK("scif4", -1, B_CLK, HWBLK_SCIF4, 0),
+ SH_HWBLK_CLK("scif5", -1, B_CLK, HWBLK_SCIF5, 0),
+ SH_HWBLK_CLK("msiof0", -1, B_CLK, HWBLK_MSIOF0, 0),
+ SH_HWBLK_CLK("msiof1", -1, B_CLK, HWBLK_MSIOF1, 0),
+ SH_HWBLK_CLK("meram0", -1, SH_CLK, HWBLK_MERAM, 0),
+
+ SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0),
+ SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0),
+
+ SH_HWBLK_CLK("atapi0", -1, SH_CLK, HWBLK_ATAPI, 0),
+ SH_HWBLK_CLK("adc0", -1, P_CLK, HWBLK_ADC, 0),
+ SH_HWBLK_CLK("tpu0", -1, B_CLK, HWBLK_TPU, 0),
+ SH_HWBLK_CLK("irda0", -1, P_CLK, HWBLK_IRDA, 0),
+ SH_HWBLK_CLK("tsif0", -1, B_CLK, HWBLK_TSIF, 0),
+ SH_HWBLK_CLK("icb0", -1, B_CLK, HWBLK_ICB, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0),
+ SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0),
+ SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0),
+ SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB, 0),
+ SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
+ SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
+ SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
+ SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
+ SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
+ SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
+ SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0),
};
int __init arch_clk_init(void)
@@ -216,7 +222,7 @@ int __init arch_clk_init(void)
ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
if (!ret)
- ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
+ ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks));
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
new file mode 100644
index 000000000000..a288b5d92341
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
@@ -0,0 +1,106 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
+ *
+ * SH7722 hardware block support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7722.h>
+
+/* SH7722 registers */
+#define MSTPCR0 0xa4150030
+#define MSTPCR1 0xa4150034
+#define MSTPCR2 0xa4150038
+
+/* SH7722 Power Domains */
+enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
+static struct hwblk_area sh7722_hwblk_area[] = {
+ [CORE_AREA] = HWBLK_AREA(0, 0),
+ [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
+ [SUB_AREA] = HWBLK_AREA(0, 0),
+};
+
+/* Table mapping HWBLK to Module Stop Bit and Power Domain */
+static struct hwblk sh7722_hwblk[HWBLK_NR] = {
+ [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
+ [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
+ [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
+ [HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA),
+ [HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA),
+ [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
+ [HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
+ [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
+ [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
+ [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
+ [HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA),
+ [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
+ [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
+ [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
+ [HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA),
+ [HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA),
+ [HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA),
+ [HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA),
+ [HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
+ [HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
+
+ [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
+ [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
+
+ [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
+ [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
+ [HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA),
+ [HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA),
+ [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
+ [HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA),
+ [HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA),
+ [HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
+ [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
+ [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
+ [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
+ [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
+ [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
+ [HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
+ [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
+ [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
+};
+
+static struct hwblk_info sh7722_hwblk_info = {
+ .areas = sh7722_hwblk_area,
+ .nr_areas = ARRAY_SIZE(sh7722_hwblk_area),
+ .hwblks = sh7722_hwblk,
+ .nr_hwblks = ARRAY_SIZE(sh7722_hwblk),
+};
+
+int arch_hwblk_sleep_mode(void)
+{
+ if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
+ return SUSP_SH_STANDBY | SUSP_SH_SF;
+
+ if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
+ return SUSP_SH_SLEEP | SUSP_SH_SF;
+
+ return SUSP_SH_SLEEP;
+}
+
+int __init arch_hwblk_init(void)
+{
+ return hwblk_register(&sh7722_hwblk_info);
+}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
new file mode 100644
index 000000000000..a7f4684d2032
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
@@ -0,0 +1,117 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
+ *
+ * SH7723 hardware block support
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/suspend.h>
+#include <asm/hwblk.h>
+#include <cpu/sh7723.h>
+
+/* SH7723 registers */
+#define MSTPCR0 0xa4150030
+#define MSTPCR1 0xa4150034
+#define MSTPCR2 0xa4150038
+
+/* SH7723 Power Domains */
+enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
+static struct hwblk_area sh7723_hwblk_area[] = {
+ [CORE_AREA] = HWBLK_AREA(0, 0),
+ [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
+ [SUB_AREA] = HWBLK_AREA(0, 0),
+};
+
+/* Table mapping HWBLK to Module Stop Bit and Power Domain */
+static struct hwblk sh7723_hwblk[HWBLK_NR] = {
+ [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
+ [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
+ [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
+ [HWBLK_L2C] = HWBLK(MSTPCR0, 28, CORE_AREA),
+ [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
+ [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
+ [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
+ [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
+ [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
+ [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
+ [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
+ [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
+ [HWBLK_SUBC] = HWBLK(MSTPCR0, 16, CORE_AREA),
+ [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
+ [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
+ [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
+ [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
+ [HWBLK_TMU1] = HWBLK(MSTPCR0, 11, CORE_AREA),
+ [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
+ [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
+ [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
+ [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
+ [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
+ [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
+ [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
+ [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
+ [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
+ [HWBLK_MERAM] = HWBLK(MSTPCR0, 0, CORE_AREA),
+
+ [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
+ [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
+
+ [HWBLK_ATAPI] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
+ [HWBLK_ADC] = HWBLK(MSTPCR2, 27, CORE_AREA),
+ [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
+ [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
+ [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
+ [HWBLK_ICB] = HWBLK(MSTPCR2, 21, CORE_AREA_BM),
+ [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
+ [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
+ [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
+ [HWBLK_USB] = HWBLK(MSTPCR2, 11, CORE_AREA),
+ [HWBLK_2DG] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
+ [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
+ [HWBLK_VEU2H1] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
+ [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
+ [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
+ [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
+ [HWBLK_VEU2H0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
+ [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
+ [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
+};
+
+static struct hwblk_info sh7723_hwblk_info = {
+ .areas = sh7723_hwblk_area,
+ .nr_areas = ARRAY_SIZE(sh7723_hwblk_area),
+ .hwblks = sh7723_hwblk,
+ .nr_hwblks = ARRAY_SIZE(sh7723_hwblk),
+};
+
+int arch_hwblk_sleep_mode(void)
+{
+ if (!sh7723_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
+ return SUSP_SH_STANDBY | SUSP_SH_SF;
+
+ if (!sh7723_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
+ return SUSP_SH_SLEEP | SUSP_SH_SF;
+
+ return SUSP_SH_SLEEP;
+}
+
+int __init arch_hwblk_init(void)
+{
+ return hwblk_register(&sh7723_hwblk_info);
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 6307e087c864..ac4d5672ec1a 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -325,7 +325,7 @@ static int __init sh7343_devices_setup(void)
return platform_add_devices(sh7343_devices,
ARRAY_SIZE(sh7343_devices));
}
-__initcall(sh7343_devices_setup);
+arch_initcall(sh7343_devices_setup);
static struct platform_device *sh7343_early_devices[] __initdata = {
&cmt_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index c18f7d09281b..4a9010bf4fd3 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -40,7 +40,7 @@ static struct platform_device iic_device = {
};
static struct r8a66597_platdata r8a66597_data = {
- /* This set zero to all members */
+ .on_chip = 1,
};
static struct resource usb_host_resources[] = {
@@ -318,7 +318,7 @@ static int __init sh7366_devices_setup(void)
return platform_add_devices(sh7366_devices,
ARRAY_SIZE(sh7366_devices));
}
-__initcall(sh7366_devices_setup);
+arch_initcall(sh7366_devices_setup);
static struct platform_device *sh7366_early_devices[] __initdata = {
&cmt_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index ea524a2da3e4..67b0d87fcb27 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -13,6 +13,7 @@
#include <linux/serial_sci.h>
#include <linux/mm.h>
#include <linux/uio_driver.h>
+#include <linux/usb/m66592.h>
#include <linux/sh_timer.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
@@ -47,9 +48,13 @@ static struct platform_device rtc_device = {
.resource = rtc_resources,
};
+static struct m66592_platdata usbf_platdata = {
+ .on_chip = 1,
+};
+
static struct resource usbf_resources[] = {
[0] = {
- .name = "m66592_udc",
+ .name = "USBF",
.start = 0x04480000,
.end = 0x044800FF,
.flags = IORESOURCE_MEM,
@@ -67,6 +72,7 @@ static struct platform_device usbf_device = {
.dev = {
.dma_mask = NULL,
.coherent_dma_mask = 0xffffffff,
+ .platform_data = &usbf_platdata,
},
.num_resources = ARRAY_SIZE(usbf_resources),
.resource = usbf_resources,
@@ -359,7 +365,7 @@ static int __init sh7722_devices_setup(void)
return platform_add_devices(sh7722_devices,
ARRAY_SIZE(sh7722_devices));
}
-__initcall(sh7722_devices_setup);
+arch_initcall(sh7722_devices_setup);
static struct platform_device *sh7722_early_devices[] __initdata = {
&cmt_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index e1bb80b2a27b..26dc4d323252 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -398,7 +398,7 @@ static struct platform_device rtc_device = {
};
static struct r8a66597_platdata r8a66597_data = {
- /* This set zero to all members */
+ .on_chip = 1,
};
static struct resource sh7723_usb_host_resources[] = {
@@ -473,7 +473,7 @@ static int __init sh7723_devices_setup(void)
return platform_add_devices(sh7723_devices,
ARRAY_SIZE(sh7723_devices));
}
-__initcall(sh7723_devices_setup);
+arch_initcall(sh7723_devices_setup);
static struct platform_device *sh7723_early_devices[] __initdata = {
&cmt_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index e5ac9eb11c63..a04edaab9a29 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -508,7 +508,7 @@ static int __init sh7724_devices_setup(void)
return platform_add_devices(sh7724_devices,
ARRAY_SIZE(sh7724_devices));
}
-device_initcall(sh7724_devices_setup);
+arch_initcall(sh7724_devices_setup);
static struct platform_device *sh7724_early_devices[] __initdata = {
&cmt_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index f1e0c0d36da7..4659fff6b842 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -314,7 +314,7 @@ static int __init sh7763_devices_setup(void)
return platform_add_devices(sh7763_devices,
ARRAY_SIZE(sh7763_devices));
}
-__initcall(sh7763_devices_setup);
+arch_initcall(sh7763_devices_setup);
static struct platform_device *sh7763_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 1e86209db284..eead08d89d32 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -368,7 +368,7 @@ static int __init sh7770_devices_setup(void)
return platform_add_devices(sh7770_devices,
ARRAY_SIZE(sh7770_devices));
}
-__initcall(sh7770_devices_setup);
+arch_initcall(sh7770_devices_setup);
static struct platform_device *sh7770_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index 715e05b431e5..2c901f446959 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -256,7 +256,7 @@ static int __init sh7780_devices_setup(void)
return platform_add_devices(sh7780_devices,
ARRAY_SIZE(sh7780_devices));
}
-__initcall(sh7780_devices_setup);
+arch_initcall(sh7780_devices_setup);
static struct platform_device *sh7780_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index af561402570b..7f6c718b6c36 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -263,7 +263,7 @@ static int __init sh7785_devices_setup(void)
return platform_add_devices(sh7785_devices,
ARRAY_SIZE(sh7785_devices));
}
-__initcall(sh7785_devices_setup);
+arch_initcall(sh7785_devices_setup);
static struct platform_device *sh7785_early_devices[] __initdata = {
&tmu0_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index b70049470a0b..0104a8ec5369 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -547,7 +547,7 @@ static int __init sh7786_devices_setup(void)
return platform_add_devices(sh7786_devices,
ARRAY_SIZE(sh7786_devices));
}
-device_initcall(sh7786_devices_setup);
+arch_initcall(sh7786_devices_setup);
void __init plat_early_device_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 53c65fd9ccef..07f078961c71 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -256,7 +256,7 @@ static int __init shx3_devices_setup(void)
return platform_add_devices(shx3_devices,
ARRAY_SIZE(shx3_devices));
}
-__initcall(shx3_devices_setup);
+arch_initcall(shx3_devices_setup);
void __init plat_early_device_setup(void)
{
diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c
index f5ff1ac57fc2..6a0f82f70032 100644
--- a/arch/sh/kernel/cpu/sh5/setup-sh5.c
+++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c
@@ -186,7 +186,7 @@ static int __init sh5_devices_setup(void)
return platform_add_devices(sh5_devices,
ARRAY_SIZE(sh5_devices));
}
-__initcall(sh5_devices_setup);
+arch_initcall(sh5_devices_setup);
void __init plat_early_device_setup(void)
{
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile
index 08bfa7c7db29..e8a5111e848a 100644
--- a/arch/sh/kernel/cpu/shmobile/Makefile
+++ b/arch/sh/kernel/cpu/shmobile/Makefile
@@ -4,3 +4,4 @@
# Power Management & Sleep mode
obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
new file mode 100644
index 000000000000..4afdd975cc66
--- /dev/null
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -0,0 +1,102 @@
+/*
+ * arch/sh/kernel/cpu/shmobile/cpuidle.c
+ *
+ * Cpuidle support code for SuperH Mobile
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <linux/cpuidle.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+#include <asm/hwblk.h>
+
+static unsigned long cpuidle_mode[] = {
+ SUSP_SH_SLEEP, /* regular sleep mode */
+ SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
+};
+
+static int cpuidle_sleep_enter(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ unsigned long allowed_mode = arch_hwblk_sleep_mode();
+ ktime_t before, after;
+ int requested_state = state - &dev->states[0];
+ int allowed_state;
+ int k;
+
+ /* convert allowed mode to allowed state */
+ for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
+ if (cpuidle_mode[k] == allowed_mode)
+ break;
+
+ allowed_state = k;
+
+ /* take the following into account for sleep mode selection:
+ * - allowed_state: best mode allowed by hardware (clock deps)
+ * - requested_state: best mode allowed by software (latencies)
+ */
+ k = min_t(int, allowed_state, requested_state);
+
+ dev->last_state = &dev->states[k];
+ before = ktime_get();
+ sh_mobile_call_standby(cpuidle_mode[k]);
+ after = ktime_get();
+ return ktime_to_ns(ktime_sub(after, before)) >> 10;
+}
+
+static struct cpuidle_device cpuidle_dev;
+static struct cpuidle_driver cpuidle_driver = {
+ .name = "sh_idle",
+ .owner = THIS_MODULE,
+};
+
+void sh_mobile_setup_cpuidle(void)
+{
+ struct cpuidle_device *dev = &cpuidle_dev;
+ struct cpuidle_state *state;
+ int i;
+
+ cpuidle_register_driver(&cpuidle_driver);
+
+ for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+ dev->states[i].name[0] = '\0';
+ dev->states[i].desc[0] = '\0';
+ }
+
+ i = CPUIDLE_DRIVER_STATE_START;
+
+ state = &dev->states[i++];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
+ strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
+ state->exit_latency = 1;
+ state->target_residency = 1 * 2;
+ state->power_usage = 3;
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_SHALLOW;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = cpuidle_sleep_enter;
+
+ dev->safe_state = state;
+
+ state = &dev->states[i++];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+ strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
+ state->exit_latency = 100;
+ state->target_residency = 1 * 2;
+ state->power_usage = 1;
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ state->enter = cpuidle_sleep_enter;
+
+ dev->state_count = i;
+
+ cpuidle_register_device(dev);
+}
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index 8c067adf6830..de078d24ce56 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ * arch/sh/kernel/cpu/shmobile/pm.c
*
* Power management support code for SuperH Mobile
*
@@ -32,20 +32,17 @@
*
* R-standby mode is unsupported, but will be added in the future
* U-standby mode is low priority since it needs bootloader hacks
- *
- * All modes should be tied in with cpuidle. But before that can
- * happen we need to keep track of enabled hardware blocks so we
- * can avoid entering sleep modes that stop clocks to hardware
- * blocks that are in use even though the cpu core is idle.
*/
+#define ILRAM_BASE 0xe5200000
+
extern const unsigned char sh_mobile_standby[];
extern const unsigned int sh_mobile_standby_size;
-static void sh_mobile_call_standby(unsigned long mode)
+void sh_mobile_call_standby(unsigned long mode)
{
extern void *vbr_base;
- void *onchip_mem = (void *)0xe5200000; /* ILRAM */
+ void *onchip_mem = (void *)ILRAM_BASE;
void (*standby_onchip_mem)(unsigned long) = onchip_mem;
/* Note: Wake up from sleep may generate exceptions!
@@ -55,11 +52,6 @@ static void sh_mobile_call_standby(unsigned long mode)
if (mode & SUSP_SH_SF)
asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
- /* Copy the assembly snippet to the otherwise ununsed ILRAM */
- memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
- wmb();
- ctrl_barrier();
-
/* Let assembly snippet in on-chip memory handle the rest */
standby_onchip_mem(mode);
@@ -85,7 +77,15 @@ static struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
+ void *onchip_mem = (void *)ILRAM_BASE;
+
+ /* Copy the assembly snippet to the otherwise ununsed ILRAM */
+ memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
+ wmb();
+ ctrl_barrier();
+
suspend_set_ops(&sh_pm_ops);
+ sh_mobile_setup_cpuidle();
return 0;
}
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index d62359cfbbe2..fc26ccd82789 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -45,7 +45,7 @@
*/
#if defined(CONFIG_PREEMPT)
-# define preempt_stop() cli
+# define preempt_stop() cli ; TRACE_IRQS_OFF
#else
# define preempt_stop()
# define resume_kernel __restore_all
@@ -55,11 +55,7 @@
.align 2
ENTRY(exception_error)
!
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 2f, r0
- jsr @r0
- nop
-#endif
+ TRACE_IRQS_ON
sti
mov.l 1f, r0
jmp @r0
@@ -67,22 +63,23 @@ ENTRY(exception_error)
.align 2
1: .long do_exception_error
-#ifdef CONFIG_TRACE_IRQFLAGS
-2: .long trace_hardirqs_on
-#endif
.align 2
ret_from_exception:
preempt_stop()
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 4f, r0
- jsr @r0
- nop
-#endif
ENTRY(ret_from_irq)
!
mov #OFF_SR, r0
mov.l @(r0,r15), r0 ! get status register
+
+ shlr2 r0
+ and #0x3c, r0
+ cmp/eq #0x3c, r0
+ bt 9f
+ TRACE_IRQS_ON
+9:
+ mov #OFF_SR, r0
+ mov.l @(r0,r15), r0 ! get status register
shll r0
shll r0 ! kernel space?
get_current_thread_info r8, r0
@@ -125,13 +122,9 @@ noresched:
ENTRY(resume_userspace)
! r8: current_thread_info
cli
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 5f, r0
- jsr @r0
- nop
-#endif
+ TRACE_IRQS_OfF
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
- tst #_TIF_WORK_MASK, r0
+ tst #(_TIF_WORK_MASK & 0xff), r0
bt/s __restore_all
tst #_TIF_NEED_RESCHED, r0
@@ -156,14 +149,10 @@ work_resched:
jsr @r1 ! schedule
nop
cli
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 5f, r0
- jsr @r0
- nop
-#endif
+ TRACE_IRQS_OFF
!
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
- tst #_TIF_WORK_MASK, r0
+ tst #(_TIF_WORK_MASK & 0xff), r0
bt __restore_all
bra work_pending
tst #_TIF_NEED_RESCHED, r0
@@ -172,23 +161,15 @@ work_resched:
1: .long schedule
2: .long do_notify_resume
3: .long resume_userspace
-#ifdef CONFIG_TRACE_IRQFLAGS
-4: .long trace_hardirqs_on
-5: .long trace_hardirqs_off
-#endif
.align 2
syscall_exit_work:
! r0: current_thread_info->flags
! r8: current_thread_info
- tst #_TIF_WORK_SYSCALL_MASK, r0
+ tst #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
bt/s work_pending
tst #_TIF_NEED_RESCHED, r0
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 5f, r0
- jsr @r0
- nop
-#endif
+ TRACE_IRQS_ON
sti
mov r15, r4
mov.l 8f, r0 ! do_syscall_trace_leave
@@ -321,18 +302,18 @@ ENTRY(system_call)
bt/s debug_trap ! it's a debug trap..
nop
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 5f, r10
- jsr @r10
- nop
-#endif
+ TRACE_IRQS_ON
sti
!
get_current_thread_info r8, r10
mov.l @(TI_FLAGS,r8), r8
- mov #_TIF_WORK_SYSCALL_MASK, r10
+ mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
+ mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9
tst r10, r8
+ shll8 r9
+ bf syscall_trace_entry
+ tst r9, r8
bf syscall_trace_entry
!
mov.l 2f, r8 ! Number of syscalls
@@ -351,15 +332,15 @@ syscall_call:
!
syscall_exit:
cli
-#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 6f, r0
- jsr @r0
- nop
-#endif
+ TRACE_IRQS_OFF
!
get_current_thread_info r8, r0
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
- tst #_TIF_ALLWORK_MASK, r0
+ tst #(_TIF_ALLWORK_MASK & 0xff), r0
+ mov #(_TIF_ALLWORK_MASK >> 8), r1
+ bf syscall_exit_work
+ shlr8 r0
+ tst r0, r1
bf syscall_exit_work
bra __restore_all
nop
@@ -369,9 +350,5 @@ syscall_exit:
#endif
2: .long NR_syscalls
3: .long sys_call_table
-#ifdef CONFIG_TRACE_IRQFLAGS
-5: .long trace_hardirqs_on
-6: .long trace_hardirqs_off
-#endif
7: .long do_syscall_trace_enter
8: .long do_syscall_trace_leave
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 066f37dc32a9..6647dfcb781d 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -16,9 +16,13 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/kernel.h>
#include <asm/ftrace.h>
#include <asm/cacheflush.h>
+#include <asm/unistd.h>
+#include <trace/syscall.h>
+#ifdef CONFIG_DYNAMIC_FTRACE
static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
static unsigned char ftrace_nop[4];
@@ -131,3 +135,189 @@ int __init ftrace_dyn_arch_init(void *data)
return 0;
}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+
+static int ftrace_mod(unsigned long ip, unsigned long old_addr,
+ unsigned long new_addr)
+{
+ unsigned char code[MCOUNT_INSN_SIZE];
+
+ if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
+ return -EFAULT;
+
+ if (old_addr != __raw_readl((unsigned long *)code))
+ return -EINVAL;
+
+ __raw_writel(new_addr, ip);
+ return 0;
+}
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ unsigned long ip, old_addr, new_addr;
+
+ ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
+ old_addr = (unsigned long)(&skip_trace);
+ new_addr = (unsigned long)(&ftrace_graph_caller);
+
+ return ftrace_mod(ip, old_addr, new_addr);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ unsigned long ip, old_addr, new_addr;
+
+ ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET;
+ old_addr = (unsigned long)(&ftrace_graph_caller);
+ new_addr = (unsigned long)(&skip_trace);
+
+ return ftrace_mod(ip, old_addr, new_addr);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in the current thread info.
+ *
+ * This is the main routine for the function graph tracer. The function
+ * graph tracer essentially works like this:
+ *
+ * parent is the stack address containing self_addr's return address.
+ * We pull the real return address out of parent and store it in
+ * current's ret_stack. Then, we replace the return address on the stack
+ * with the address of return_to_handler. self_addr is the function that
+ * called mcount.
+ *
+ * When self_addr returns, it will jump to return_to_handler which calls
+ * ftrace_return_to_handler. ftrace_return_to_handler will pull the real
+ * return address off of current's ret_stack and jump to it.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+ unsigned long old;
+ int faulted, err;
+ struct ftrace_graph_ent trace;
+ unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+ if (unlikely(atomic_read(&current->tracing_graph_pause)))
+ return;
+
+ /*
+ * Protect against fault, even if it shouldn't
+ * happen. This tool is too much intrusive to
+ * ignore such a protection.
+ */
+ __asm__ __volatile__(
+ "1: \n\t"
+ "mov.l @%2, %0 \n\t"
+ "2: \n\t"
+ "mov.l %3, @%2 \n\t"
+ "mov #0, %1 \n\t"
+ "3: \n\t"
+ ".section .fixup, \"ax\" \n\t"
+ "4: \n\t"
+ "mov.l 5f, %0 \n\t"
+ "jmp @%0 \n\t"
+ " mov #1, %1 \n\t"
+ ".balign 4 \n\t"
+ "5: .long 3b \n\t"
+ ".previous \n\t"
+ ".section __ex_table,\"a\" \n\t"
+ ".long 1b, 4b \n\t"
+ ".long 2b, 4b \n\t"
+ ".previous \n\t"
+ : "=&r" (old), "=r" (faulted)
+ : "r" (parent), "r" (return_hooker)
+ );
+
+ if (unlikely(faulted)) {
+ ftrace_graph_stop();
+ WARN_ON(1);
+ return;
+ }
+
+ err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
+ if (err == -EBUSY) {
+ __raw_writel(old, parent);
+ return;
+ }
+
+ trace.func = self_addr;
+
+ /* Only trace if the calling function expects to */
+ if (!ftrace_graph_entry(&trace)) {
+ current->curr_ret_stack--;
+ __raw_writel(old, parent);
+ }
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+extern unsigned long __start_syscalls_metadata[];
+extern unsigned long __stop_syscalls_metadata[];
+extern unsigned long *sys_call_table;
+
+static struct syscall_metadata **syscalls_metadata;
+
+static struct syscall_metadata *find_syscall_meta(unsigned long *syscall)
+{
+ struct syscall_metadata *start;
+ struct syscall_metadata *stop;
+ char str[KSYM_SYMBOL_LEN];
+
+
+ start = (struct syscall_metadata *)__start_syscalls_metadata;
+ stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+ kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str);
+
+ for ( ; start < stop; start++) {
+ if (start->name && !strcmp(start->name, str))
+ return start;
+ }
+
+ return NULL;
+}
+
+#define FTRACE_SYSCALL_MAX (NR_syscalls - 1)
+
+struct syscall_metadata *syscall_nr_to_meta(int nr)
+{
+ if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0)
+ return NULL;
+
+ return syscalls_metadata[nr];
+}
+
+void 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;
+ }
+
+ 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);
+}
+#endif /* CONFIG_FTRACE_SYSCALLS */
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c
index 77dfecb64373..e27a19e1f46e 100644
--- a/arch/sh/kernel/io_trapped.c
+++ b/arch/sh/kernel/io_trapped.c
@@ -112,14 +112,15 @@ void __iomem *match_trapped_io_handler(struct list_head *list,
struct trapped_io *tiop;
struct resource *res;
int k, len;
+ unsigned long flags;
- spin_lock_irq(&trapped_lock);
+ spin_lock_irqsave(&trapped_lock, flags);
list_for_each_entry(tiop, list, list) {
voffs = 0;
for (k = 0; k < tiop->num_resources; k++) {
res = tiop->resource + k;
if (res->start == offset) {
- spin_unlock_irq(&trapped_lock);
+ spin_unlock_irqrestore(&trapped_lock, flags);
return tiop->virt_base + voffs;
}
@@ -127,7 +128,7 @@ void __iomem *match_trapped_io_handler(struct list_head *list,
voffs += roundup(len, PAGE_SIZE);
}
}
- spin_unlock_irq(&trapped_lock);
+ spin_unlock_irqrestore(&trapped_lock, flags);
return NULL;
}
EXPORT_SYMBOL_GPL(match_trapped_io_handler);
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 3d09062f4682..278c68c60488 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -114,23 +114,6 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
#endif
irq_enter();
-
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
- /* Debugging check for stack overflow: is there less than 1KB free? */
- {
- long sp;
-
- __asm__ __volatile__ ("and r15, %0" :
- "=r" (sp) : "0" (THREAD_SIZE - 1));
-
- if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
- printk("do_IRQ: stack overflow: %ld\n",
- sp - sizeof(struct thread_info));
- dump_stack();
- }
- }
-#endif
-
irq = irq_demux(intc_evt2irq(irq));
#ifdef CONFIG_IRQSTACKS
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 92d7740faab1..9fee977f176b 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -23,6 +23,7 @@
#include <linux/tick.h>
#include <linux/reboot.h>
#include <linux/fs.h>
+#include <linux/ftrace.h>
#include <linux/preempt.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -264,8 +265,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
* switch_to(x,y) should switch tasks from x to y.
*
*/
-struct task_struct *__switch_to(struct task_struct *prev,
- struct task_struct *next)
+__notrace_funcgraph struct task_struct *
+__switch_to(struct task_struct *prev, struct task_struct *next)
{
#if defined(CONFIG_SH_FPU)
unlazy_fpu(prev, task_pt_regs(prev));
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 3392e835a374..c198eceaee94 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -34,6 +34,8 @@
#include <asm/syscalls.h>
#include <asm/fpu.h>
+#include <trace/syscall.h>
+
/*
* This routine will get a word off of the process kernel stack.
*/
@@ -459,6 +461,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
*/
ret = -1L;
+ if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+ ftrace_syscall_enter(regs);
+
if (unlikely(current->audit_context))
audit_syscall_entry(audit_arch(), regs->regs[3],
regs->regs[4], regs->regs[5],
@@ -475,6 +480,9 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
regs->regs[0]);
+ if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+ ftrace_syscall_exit(regs);
+
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, step);
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index dd38338553ef..ceb409bf7741 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -30,6 +30,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/lmb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -233,39 +234,45 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
void __init setup_bootmem_allocator(unsigned long free_pfn)
{
unsigned long bootmap_size;
+ unsigned long bootmap_pages, bootmem_paddr;
+ u64 total_pages = (lmb_end_of_DRAM() - __MEMORY_START) >> PAGE_SHIFT;
+ int i;
+
+ bootmap_pages = bootmem_bootmap_pages(total_pages);
+
+ bootmem_paddr = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
/*
* Find a proper area for the bootmem bitmap. After this
* bootstrap step all allocations (until the page allocator
* is intact) must be done via bootmem_alloc().
*/
- bootmap_size = init_bootmem_node(NODE_DATA(0), free_pfn,
+ bootmap_size = init_bootmem_node(NODE_DATA(0),
+ bootmem_paddr >> PAGE_SHIFT,
min_low_pfn, max_low_pfn);
- __add_active_range(0, min_low_pfn, max_low_pfn);
- register_bootmem_low_pages();
-
- node_set_online(0);
+ /* Add active regions with valid PFNs. */
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ unsigned long start_pfn, end_pfn;
+ start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
+ end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
+ __add_active_range(0, start_pfn, end_pfn);
+ }
/*
- * Reserve the kernel text and
- * Reserve the bootmem bitmap. We do this in two steps (first step
- * was init_bootmem()), because this catches the (definitely buggy)
- * case of us accidentally initializing the bootmem allocator with
- * an invalid RAM area.
+ * Add all physical memory to the bootmem map and mark each
+ * area as present.
*/
- reserve_bootmem(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
- (PFN_PHYS(free_pfn) + bootmap_size + PAGE_SIZE - 1) -
- (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET),
- BOOTMEM_DEFAULT);
+ register_bootmem_low_pages();
- /*
- * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
- */
- if (CONFIG_ZERO_PAGE_OFFSET != 0)
- reserve_bootmem(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET,
+ /* Reserve the sections we're already using. */
+ for (i = 0; i < lmb.reserved.cnt; i++)
+ reserve_bootmem(lmb.reserved.region[i].base,
+ lmb_size_bytes(&lmb.reserved, i),
BOOTMEM_DEFAULT);
+ node_set_online(0);
+
sparse_memory_present_with_active_regions(0);
#ifdef CONFIG_BLK_DEV_INITRD
@@ -296,12 +303,37 @@ void __init setup_bootmem_allocator(unsigned long free_pfn)
static void __init setup_memory(void)
{
unsigned long start_pfn;
+ u64 base = min_low_pfn << PAGE_SHIFT;
+ u64 size = (max_low_pfn << PAGE_SHIFT) - base;
/*
* Partially used pages are not usable - thus
* we are rounding upwards:
*/
start_pfn = PFN_UP(__pa(_end));
+
+ lmb_add(base, size);
+
+ /*
+ * Reserve the kernel text and
+ * Reserve the bootmem bitmap. We do this in two steps (first step
+ * was init_bootmem()), because this catches the (definitely buggy)
+ * case of us accidentally initializing the bootmem allocator with
+ * an invalid RAM area.
+ */
+ lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
+ (PFN_PHYS(start_pfn) + PAGE_SIZE - 1) -
+ (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
+
+ /*
+ * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET.
+ */
+ if (CONFIG_ZERO_PAGE_OFFSET != 0)
+ lmb_reserve(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET);
+
+ lmb_analyze();
+ lmb_dump_all();
+
setup_bootmem_allocator(start_pfn);
}
#else
@@ -402,6 +434,7 @@ void __init setup_arch(char **cmdline_p)
nodes_clear(node_online_map);
/* Setup bootmem with available RAM */
+ lmb_init();
setup_memory();
sparse_init();
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index fcc5de31f83b..cec610888e28 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -106,8 +106,8 @@ EXPORT_SYMBOL(flush_dcache_page);
EXPORT_SYMBOL(clear_user_page);
#endif
-#ifdef CONFIG_FUNCTION_TRACER
-EXPORT_SYMBOL(mcount);
+#ifdef CONFIG_MCOUNT
+DECLARE_EXPORT(mcount);
#endif
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index 9b352a1e3fb4..7f95f479060f 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -21,6 +21,7 @@
#include <linux/smp.h>
#include <linux/rtc.h>
#include <asm/clock.h>
+#include <asm/hwblk.h>
#include <asm/rtc.h>
/* Dummy RTC ops */
@@ -91,11 +92,27 @@ module_init(rtc_generic_init);
void (*board_time_init)(void);
+static void __init sh_late_time_init(void)
+{
+ /*
+ * Make sure all compiled-in early timers register themselves.
+ *
+ * Run probe() for two "earlytimer" devices, these will be the
+ * clockevents and clocksource devices respectively. In the event
+ * that only a clockevents device is available, we -ENODEV on the
+ * clocksource and the jiffies clocksource is used transparently
+ * instead. No error handling is necessary here.
+ */
+ early_platform_driver_register_all("earlytimer");
+ early_platform_driver_probe("earlytimer", 2, 0);
+}
+
void __init time_init(void)
{
if (board_time_init)
board_time_init();
+ hwblk_init();
clk_init();
rtc_sh_get_time(&xtime);
@@ -106,15 +123,5 @@ void __init time_init(void)
local_timer_setup(smp_processor_id());
#endif
- /*
- * Make sure all compiled-in early timers register themselves.
- *
- * Run probe() for two "earlytimer" devices, these will be the
- * clockevents and clocksource devices respectively. In the event
- * that only a clockevents device is available, we -ENODEV on the
- * clocksource and the jiffies clocksource is used transparently
- * instead. No error handling is necessary here.
- */
- early_platform_driver_register_all("earlytimer");
- early_platform_driver_probe("earlytimer", 2, 0);
+ late_time_init = sh_late_time_init;
}
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index f53c76acaede..19512be1ee52 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -50,12 +50,7 @@ SECTIONS
_etext = .; /* End of text section */
} = 0x0009
- . = ALIGN(16); /* Exception table */
- __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- }
+ EXCEPTION_TABLE(16)
NOTES
RO_DATA(PAGE_SIZE)
@@ -71,69 +66,14 @@ SECTIONS
__uncached_end = .;
}
- . = ALIGN(THREAD_SIZE);
- .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
- *(.data.init_task)
-
- . = ALIGN(L1_CACHE_BYTES);
- *(.data.cacheline_aligned)
-
- . = ALIGN(L1_CACHE_BYTES);
- *(.data.read_mostly)
-
- . = ALIGN(PAGE_SIZE);
- *(.data.page_aligned)
-
- __nosave_begin = .;
- *(.data.nosave)
- . = ALIGN(PAGE_SIZE);
- __nosave_end = .;
-
- DATA_DATA
- CONSTRUCTORS
- }
+ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
_edata = .; /* End of data section */
. = ALIGN(PAGE_SIZE); /* Init code and data */
- .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
- __init_begin = .;
- _sinittext = .;
- INIT_TEXT
- _einittext = .;
- }
-
- .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { INIT_DATA }
-
- . = ALIGN(16);
- .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- }
-
- .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
- }
-
- .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- }
-
- SECURITY_INIT
-
-#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(PAGE_SIZE);
- .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
- __initramfs_start = .;
- *(.init.ramfs)
- __initramfs_end = .;
- }
-#endif
+ __init_begin = .;
+ INIT_TEXT_SECTION(PAGE_SIZE)
+ INIT_DATA_SECTION(16)
. = ALIGN(4);
.machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) {
@@ -152,16 +92,13 @@ SECTIONS
.exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA }
. = ALIGN(PAGE_SIZE);
- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
- __init_end = .;
- __bss_start = .; /* BSS */
- *(.bss.page_aligned)
- *(.bss)
- *(COMMON)
- . = ALIGN(4);
- _ebss = .; /* uClinux MTD sucks */
- _end = . ;
- }
+ __init_end = .;
+ BSS_SECTION(0, PAGE_SIZE, 4)
+ _ebss = .; /* uClinux MTD sucks */
+ _end = . ;
+
+ STABS_DEBUG
+ DWARF_DEBUG
/*
* When something in the kernel is NOT compiled as a module, the
@@ -169,10 +106,5 @@ SECTIONS
* can then be thrown away, as cleanup code is never called unless
* it's a module.
*/
- /DISCARD/ : {
- *(.exitcall.exit)
- }
-
- STABS_DEBUG
- DWARF_DEBUG
+ DISCARDS
}
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index aaea580b65bb..c2b28d8b2dd1 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -24,7 +24,7 @@ memcpy-y := memcpy.o
memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o
lib-$(CONFIG_MMU) += copy_page.o clear_page.o
-lib-$(CONFIG_FUNCTION_TRACER) += mcount.o
+lib-$(CONFIG_MCOUNT) += mcount.o
lib-y += $(memcpy-y) $(udivsi3-y)
EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S
index 110fbfe1831f..84a57761f17e 100644
--- a/arch/sh/lib/mcount.S
+++ b/arch/sh/lib/mcount.S
@@ -1,14 +1,16 @@
/*
* arch/sh/lib/mcount.S
*
- * Copyright (C) 2008 Paul Mundt
- * Copyright (C) 2008 Matt Fleming
+ * Copyright (C) 2008, 2009 Paul Mundt
+ * Copyright (C) 2008, 2009 Matt Fleming
*
* 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 <asm/ftrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
#define MCOUNT_ENTER() \
mov.l r4, @-r15; \
@@ -28,6 +30,55 @@
rts; \
mov.l @r15+, r4
+#ifdef CONFIG_STACK_DEBUG
+/*
+ * Perform diagnostic checks on the state of the kernel stack.
+ *
+ * Check for stack overflow. If there is less than 1KB free
+ * then it has overflowed.
+ *
+ * Make sure the stack pointer contains a valid address. Valid
+ * addresses for kernel stacks are anywhere after the bss
+ * (after _ebss) and anywhere in init_thread_union (init_stack).
+ */
+#define STACK_CHECK() \
+ mov #(THREAD_SIZE >> 10), r0; \
+ shll8 r0; \
+ shll2 r0; \
+ \
+ /* r1 = sp & (THREAD_SIZE - 1) */ \
+ mov #-1, r1; \
+ add r0, r1; \
+ and r15, r1; \
+ \
+ mov #TI_SIZE, r3; \
+ mov #(STACK_WARN >> 8), r2; \
+ shll8 r2; \
+ add r3, r2; \
+ \
+ /* Is the stack overflowing? */ \
+ cmp/hi r2, r1; \
+ bf stack_panic; \
+ \
+ /* If sp > _ebss then we're OK. */ \
+ mov.l .L_ebss, r1; \
+ cmp/hi r1, r15; \
+ bt 1f; \
+ \
+ /* If sp < init_stack, we're not OK. */ \
+ mov.l .L_init_thread_union, r1; \
+ cmp/hs r1, r15; \
+ bf stack_panic; \
+ \
+ /* If sp > init_stack && sp < _ebss, not OK. */ \
+ add r0, r1; \
+ cmp/hs r1, r15; \
+ bt stack_panic; \
+1:
+#else
+#define STACK_CHECK()
+#endif /* CONFIG_STACK_DEBUG */
+
.align 2
.globl _mcount
.type _mcount,@function
@@ -35,6 +86,19 @@
.type mcount,@function
_mcount:
mcount:
+ STACK_CHECK()
+
+#ifndef CONFIG_FUNCTION_TRACER
+ rts
+ nop
+#else
+#ifndef CONFIG_DYNAMIC_FTRACE
+ mov.l .Lfunction_trace_stop, r0
+ mov.l @r0, r0
+ tst r0, r0
+ bf ftrace_stub
+#endif
+
MCOUNT_ENTER()
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -52,16 +116,69 @@ mcount_call:
jsr @r6
nop
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ mov.l .Lftrace_graph_return, r6
+ mov.l .Lftrace_stub, r7
+ cmp/eq r6, r7
+ bt 1f
+
+ mov.l .Lftrace_graph_caller, r0
+ jmp @r0
+ nop
+
+1:
+ mov.l .Lftrace_graph_entry, r6
+ mov.l .Lftrace_graph_entry_stub, r7
+ cmp/eq r6, r7
+ bt skip_trace
+
+ mov.l .Lftrace_graph_caller, r0
+ jmp @r0
+ nop
+
+ .align 2
+.Lftrace_graph_return:
+ .long ftrace_graph_return
+.Lftrace_graph_entry:
+ .long ftrace_graph_entry
+.Lftrace_graph_entry_stub:
+ .long ftrace_graph_entry_stub
+.Lftrace_graph_caller:
+ .long ftrace_graph_caller
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+ .globl skip_trace
skip_trace:
MCOUNT_LEAVE()
.align 2
.Lftrace_trace_function:
- .long ftrace_trace_function
+ .long ftrace_trace_function
#ifdef CONFIG_DYNAMIC_FTRACE
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/*
+ * NOTE: Do not move either ftrace_graph_call or ftrace_caller
+ * as this will affect the calculation of GRAPH_INSN_OFFSET.
+ */
+ .globl ftrace_graph_call
+ftrace_graph_call:
+ mov.l .Lskip_trace, r0
+ jmp @r0
+ nop
+
+ .align 2
+.Lskip_trace:
+ .long skip_trace
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
.globl ftrace_caller
ftrace_caller:
+ mov.l .Lfunction_trace_stop, r0
+ mov.l @r0, r0
+ tst r0, r0
+ bf ftrace_stub
+
MCOUNT_ENTER()
.globl ftrace_call
@@ -70,9 +187,18 @@ ftrace_call:
jsr @r6
nop
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ bra ftrace_graph_call
+ nop
+#else
MCOUNT_LEAVE()
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#endif /* CONFIG_DYNAMIC_FTRACE */
+ .align 2
+.Lfunction_trace_stop:
+ .long function_trace_stop
+
/*
* NOTE: From here on the locations of the .Lftrace_stub label and
* ftrace_stub itself are fixed. Adding additional data here will skew
@@ -80,7 +206,6 @@ ftrace_call:
* Place new labels either after the ftrace_stub body, or before
* ftrace_caller. You have been warned.
*/
- .align 2
.Lftrace_stub:
.long ftrace_stub
@@ -88,3 +213,98 @@ ftrace_call:
ftrace_stub:
rts
nop
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .globl ftrace_graph_caller
+ftrace_graph_caller:
+ mov.l 2f, r0
+ mov.l @r0, r0
+ tst r0, r0
+ bt 1f
+
+ mov.l 3f, r1
+ jmp @r1
+ nop
+1:
+ /*
+ * MCOUNT_ENTER() pushed 5 registers onto the stack, so
+ * the stack address containing our return address is
+ * r15 + 20.
+ */
+ mov #20, r0
+ add r15, r0
+ mov r0, r4
+
+ mov.l .Lprepare_ftrace_return, r0
+ jsr @r0
+ nop
+
+ MCOUNT_LEAVE()
+
+ .align 2
+2: .long function_trace_stop
+3: .long skip_trace
+.Lprepare_ftrace_return:
+ .long prepare_ftrace_return
+
+ .globl return_to_handler
+return_to_handler:
+ /*
+ * Save the return values.
+ */
+ mov.l r0, @-r15
+ mov.l r1, @-r15
+
+ mov #0, r4
+
+ mov.l .Lftrace_return_to_handler, r0
+ jsr @r0
+ nop
+
+ /*
+ * The return value from ftrace_return_handler has the real
+ * address that we should return to.
+ */
+ lds r0, pr
+ mov.l @r15+, r1
+ rts
+ mov.l @r15+, r0
+
+
+ .align 2
+.Lftrace_return_to_handler:
+ .long ftrace_return_to_handler
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#ifdef CONFIG_STACK_DEBUG
+ .globl stack_panic
+stack_panic:
+ mov.l .Ldump_stack, r0
+ jsr @r0
+ nop
+
+ mov.l .Lpanic, r0
+ jsr @r0
+ mov.l .Lpanic_s, r4
+
+ rts
+ nop
+
+ .align 2
+.L_ebss:
+ .long _ebss
+.L_init_thread_union:
+ .long init_thread_union
+.Lpanic:
+ .long panic
+.Lpanic_s:
+ .long .Lpanic_str
+.Ldump_stack:
+ .long dump_stack
+
+ .section .rodata
+ .align 2
+.Lpanic_str:
+ .string "Stack error"
+#endif /* CONFIG_STACK_DEBUG */
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index 71925946f1e1..dbbdeba2cee5 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU.
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 - 2008 Paul Mundt
+ * Copyright (C) 2003 - 2009 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
@@ -25,18 +25,91 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap)
{
int ret = 0;
-#ifdef CONFIG_KPROBES
- if (!user_mode(regs)) {
+ if (kprobes_built_in() && !user_mode(regs)) {
preempt_disable();
if (kprobe_running() && kprobe_fault_handler(regs, trap))
ret = 1;
preempt_enable();
}
-#endif
return ret;
}
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+ unsigned index = pgd_index(address);
+ pgd_t *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+
+ pgd += index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ return NULL;
+
+ pud = pud_offset(pgd, address);
+ pud_k = pud_offset(pgd_k, address);
+ if (!pud_present(*pud_k))
+ return NULL;
+
+ pmd = pmd_offset(pud, address);
+ pmd_k = pmd_offset(pud_k, address);
+ if (!pmd_present(*pmd_k))
+ return NULL;
+
+ if (!pmd_present(*pmd))
+ set_pmd(pmd, *pmd_k);
+ else {
+ /*
+ * The page tables are fully synchronised so there must
+ * be another reason for the fault. Return NULL here to
+ * signal that we have not taken care of the fault.
+ */
+ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+ return NULL;
+ }
+
+ return pmd_k;
+}
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+ pgd_t *pgd_k;
+ pmd_t *pmd_k;
+ pte_t *pte_k;
+
+ /* Make sure we are in vmalloc area: */
+ if (!(address >= VMALLOC_START && address < VMALLOC_END))
+ return -1;
+
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Do _not_ use "current" here. We might be inside
+ * an interrupt in the middle of a task switch..
+ */
+ pgd_k = get_TTB();
+ pmd_k = vmalloc_sync_one(pgd_k, address);
+ if (!pmd_k)
+ return -1;
+
+ pte_k = pte_offset_kernel(pmd_k, address);
+ if (!pte_present(*pte_k))
+ return -1;
+
+ return 0;
+}
+
+static int fault_in_kernel_space(unsigned long address)
+{
+ return address >= TASK_SIZE;
+}
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -46,6 +119,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long writeaccess,
unsigned long address)
{
+ unsigned long vec;
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
@@ -53,59 +127,30 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
int fault;
siginfo_t info;
- /*
- * We don't bother with any notifier callbacks here, as they are
- * all handled through the __do_page_fault() fast-path.
- */
-
tsk = current;
+ mm = tsk->mm;
si_code = SEGV_MAPERR;
+ vec = lookup_exception_vector();
- if (unlikely(address >= TASK_SIZE)) {
- /*
- * Synchronize this task's top level page-table
- * with the 'reference' page table.
- *
- * Do _not_ use "tsk" here. We might be inside
- * an interrupt in the middle of a task switch..
- */
- int offset = pgd_index(address);
- pgd_t *pgd, *pgd_k;
- pud_t *pud, *pud_k;
- pmd_t *pmd, *pmd_k;
-
- pgd = get_TTB() + offset;
- pgd_k = swapper_pg_dir + offset;
-
- if (!pgd_present(*pgd)) {
- if (!pgd_present(*pgd_k))
- goto bad_area_nosemaphore;
- set_pgd(pgd, *pgd_k);
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ */
+ if (unlikely(fault_in_kernel_space(address))) {
+ if (vmalloc_fault(address) >= 0)
return;
- }
-
- pud = pud_offset(pgd, address);
- pud_k = pud_offset(pgd_k, address);
-
- if (!pud_present(*pud)) {
- if (!pud_present(*pud_k))
- goto bad_area_nosemaphore;
- set_pud(pud, *pud_k);
+ if (notify_page_fault(regs, vec))
return;
- }
- pmd = pmd_offset(pud, address);
- pmd_k = pmd_offset(pud_k, address);
- if (pmd_present(*pmd) || !pmd_present(*pmd_k))
- goto bad_area_nosemaphore;
- set_pmd(pmd, *pmd_k);
-
- return;
+ goto bad_area_nosemaphore;
}
- mm = tsk->mm;
-
- if (unlikely(notify_page_fault(regs, lookup_exception_vector())))
+ if (unlikely(notify_page_fault(regs, vec)))
return;
/* Only enable interrupts if they were on before the fault */
@@ -115,8 +160,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
/*
- * If we're in an interrupt or have no user
- * context, we must not take the fault..
+ * If we're in an interrupt, have no user context or are running
+ * in an atomic region then we must not take the fault:
*/
if (in_atomic() || !mm)
goto no_context;
@@ -132,10 +177,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
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..
- */
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
good_area:
si_code = SEGV_ACCERR;
if (writeaccess) {
@@ -173,10 +219,10 @@ survive:
up_read(&mm->mmap_sem);
return;
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
+ /*
+ * 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:
up_read(&mm->mmap_sem);
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c
index 095d93bec7cd..9b784fdb947c 100644
--- a/arch/sh/mm/numa.c
+++ b/arch/sh/mm/numa.c
@@ -9,6 +9,7 @@
*/
#include <linux/module.h>
#include <linux/bootmem.h>
+#include <linux/lmb.h>
#include <linux/mm.h>
#include <linux/numa.h>
#include <linux/pfn.h>
@@ -26,6 +27,15 @@ EXPORT_SYMBOL_GPL(node_data);
void __init setup_memory(void)
{
unsigned long free_pfn = PFN_UP(__pa(_end));
+ u64 base = min_low_pfn << PAGE_SHIFT;
+ u64 size = (max_low_pfn << PAGE_SHIFT) - min_low_pfn;
+
+ lmb_add(base, size);
+
+ /* Reserve the LMB regions used by the kernel, initrd, etc.. */
+ lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET,
+ (PFN_PHYS(free_pfn) + PAGE_SIZE - 1) -
+ (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET));
/*
* Node 0 sets up its pgdat at the first available pfn,
@@ -45,24 +55,23 @@ void __init setup_memory(void)
void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
{
- unsigned long bootmap_pages, bootmap_start, bootmap_size;
- unsigned long start_pfn, free_pfn, end_pfn;
+ unsigned long bootmap_pages;
+ unsigned long start_pfn, end_pfn;
+ unsigned long bootmem_paddr;
/* Don't allow bogus node assignment */
BUG_ON(nid > MAX_NUMNODES || nid == 0);
- /*
- * The free pfn starts at the beginning of the range, and is
- * advanced as necessary for pgdat and node map allocations.
- */
- free_pfn = start_pfn = start >> PAGE_SHIFT;
+ start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
+ lmb_add(start, end - start);
+
__add_active_range(nid, start_pfn, end_pfn);
/* Node-local pgdat */
- NODE_DATA(nid) = pfn_to_kaddr(free_pfn);
- free_pfn += PFN_UP(sizeof(struct pglist_data));
+ NODE_DATA(nid) = __va(lmb_alloc_base(sizeof(struct pglist_data),
+ SMP_CACHE_BYTES, end_pfn));
memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
@@ -71,16 +80,17 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
/* Node-local bootmap */
bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
- bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn);
- bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn,
- end_pfn);
+ bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT,
+ PAGE_SIZE, end_pfn);
+ init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
+ start_pfn, end_pfn);
free_bootmem_with_active_regions(nid, end_pfn);
/* Reserve the pgdat and bootmap space with the bootmem allocator */
reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
sizeof(struct pglist_data), BOOTMEM_DEFAULT);
- reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
+ reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,
bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT);
/* It's up */
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index fec3a53b8650..09eef360dde1 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -56,3 +56,4 @@ SH7785LCR SH_SH7785LCR
URQUELL SH_URQUELL
ESPT SH_ESPT
POLARIS SH_POLARIS
+KFR2R09 SH_KFR2R09
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3f8b6a92eabd..4f6ed0f113f0 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -95,9 +95,6 @@ config AUDIT_ARCH
config HAVE_SETUP_PER_CPU_AREA
def_bool y if SPARC64
-config HAVE_DYNAMIC_PER_CPU_AREA
- def_bool y if SPARC64
-
config GENERIC_HARDIRQS_NO__DO_IRQ
bool
def_bool y if SPARC64
diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h
index 3702e087df2c..f3b85b6b0b76 100644
--- a/arch/sparc/include/asm/device.h
+++ b/arch/sparc/include/asm/device.h
@@ -32,4 +32,7 @@ dev_archdata_get_node(const struct dev_archdata *ad)
return ad->prom_node;
}
+struct pdev_archdata {
+};
+
#endif /* _ASM_SPARC_DEVICE_H */
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index b41c4c198159..810d9248e23f 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -10,7 +10,6 @@
* or architectures with incomplete PCI setup by the loader.
*/
#define pcibios_assign_all_busses() 0
-#define pcibios_scan_all_fns(a, b) 0
#define PCIBIOS_MIN_IO 0UL
#define PCIBIOS_MIN_MEM 0UL
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 7a1e3566e59c..a32970888287 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -10,7 +10,6 @@
* or architectures with incomplete PCI setup by the loader.
*/
#define pcibios_assign_all_busses() 0
-#define pcibios_scan_all_fns(a, b) 0
#define PCIBIOS_MIN_IO 0UL
#define PCIBIOS_MIN_MEM 0UL
diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h
index 681582d26969..ca2b34456c4b 100644
--- a/arch/sparc/include/asm/pgalloc_32.h
+++ b/arch/sparc/include/asm/pgalloc_32.h
@@ -44,8 +44,8 @@ BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one, struct mm_struct *, unsigned long)
BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *)
#define free_pmd_fast(pmd) BTFIXUP_CALL(free_pmd_fast)(pmd)
-#define pmd_free(mm, pmd) free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
+#define pmd_free(mm, pmd) free_pmd_fast(pmd)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *)
#define pmd_populate(MM, PMD, PTE) BTFIXUP_CALL(pmd_populate)(PMD, PTE)
@@ -62,7 +62,7 @@ BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *)
#define pte_free_kernel(mm, pte) BTFIXUP_CALL(free_pte_fast)(pte)
BTFIXUPDEF_CALL(void, pte_free, pgtable_t )
-#define pte_free(mm, pte) BTFIXUP_CALL(pte_free)(pte)
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
+#define pte_free(mm, pte) BTFIXUP_CALL(pte_free)(pte)
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
#endif /* _SPARC_PGALLOC_H */
diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h
index becb6bf353a9..f49e11cd4ded 100644
--- a/arch/sparc/include/asm/smp_64.h
+++ b/arch/sparc/include/asm/smp_64.h
@@ -36,7 +36,6 @@ extern int sparc64_multi_core;
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
/*
* General functions that each host system must provide.
diff --git a/arch/sparc/include/asm/tlb_64.h b/arch/sparc/include/asm/tlb_64.h
index ee38e731bfa6..dca406b9b6fc 100644
--- a/arch/sparc/include/asm/tlb_64.h
+++ b/arch/sparc/include/asm/tlb_64.h
@@ -100,9 +100,9 @@ static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
}
#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp, ptepage) pte_free((mp)->mm, ptepage)
-#define pmd_free_tlb(mp, pmdp) pmd_free((mp)->mm, pmdp)
-#define pud_free_tlb(tlb,pudp) __pud_free_tlb(tlb,pudp)
+#define pte_free_tlb(mp, ptepage, addr) pte_free((mp)->mm, ptepage)
+#define pmd_free_tlb(mp, pmdp, addr) pmd_free((mp)->mm, pmdp)
+#define pud_free_tlb(tlb,pudp, addr) __pud_free_tlb(tlb,pudp,addr)
#define tlb_migrate_finish(mm) do { } while (0)
#define tlb_start_vma(tlb, vma) do { } while (0)
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index e5ea8d332421..0c35499efe36 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -12,22 +12,8 @@ static inline int cpu_to_node(int cpu)
#define parent_node(node) (node)
-static inline cpumask_t node_to_cpumask(int node)
-{
- return numa_cpumask_lookup_table[node];
-}
#define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
-/*
- * Returns a pointer to the cpumask of CPUs on Node 'node'.
- * Deprecated: use "const struct cpumask *mask = cpumask_of_node(node)"
- */
-#define node_to_cpumask_ptr(v, node) \
- cpumask_t *v = &(numa_cpumask_lookup_table[node])
-
-#define node_to_cpumask_ptr_next(v, node) \
- v = &(numa_cpumask_lookup_table[node])
-
struct pci_bus;
#ifdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *pbus);
@@ -72,8 +58,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
#ifdef CONFIG_SMP
#define topology_physical_package_id(cpu) (cpu_data(cpu).proc_id)
#define topology_core_id(cpu) (cpu_data(cpu).core_id)
-#define topology_core_siblings(cpu) (cpu_core_map[cpu])
-#define topology_thread_siblings(cpu) (per_cpu(cpu_sibling_map, cpu))
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
#define mc_capable() (sparc64_multi_core)
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index fa44eaf8d897..6970333b48b8 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -1415,19 +1415,6 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
#endif
}
-static size_t pcpur_size __initdata;
-static void **pcpur_ptrs __initdata;
-
-static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
-{
- size_t off = (size_t)pageno << PAGE_SHIFT;
-
- if (off >= pcpur_size)
- return NULL;
-
- return virt_to_page(pcpur_ptrs[cpu] + off);
-}
-
#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL)
static void __init pcpu_map_range(unsigned long start, unsigned long end,
@@ -1491,25 +1478,26 @@ void __init setup_per_cpu_areas(void)
size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start;
static struct vm_struct vm;
unsigned long delta, cpu;
- size_t pcpu_unit_size;
+ size_t size_sum, pcpu_unit_size;
size_t ptrs_size;
+ void **ptrs;
- pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
- PERCPU_DYNAMIC_RESERVE);
- dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE;
+ size_sum = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
+ PERCPU_DYNAMIC_RESERVE);
+ dyn_size = size_sum - static_size - PERCPU_MODULE_RESERVE;
- ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0]));
- pcpur_ptrs = alloc_bootmem(ptrs_size);
+ ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(ptrs[0]));
+ ptrs = alloc_bootmem(ptrs_size);
for_each_possible_cpu(cpu) {
- pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE,
- PCPU_CHUNK_SIZE);
+ ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE,
+ PCPU_CHUNK_SIZE);
- free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
- PCPU_CHUNK_SIZE - pcpur_size);
+ free_bootmem(__pa(ptrs[cpu] + size_sum),
+ PCPU_CHUNK_SIZE - size_sum);
- memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
+ memcpy(ptrs[cpu], __per_cpu_load, static_size);
}
/* allocate address and map */
@@ -1523,14 +1511,14 @@ void __init setup_per_cpu_areas(void)
start += cpu * PCPU_CHUNK_SIZE;
end = start + PCPU_CHUNK_SIZE;
- pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu]));
+ pcpu_map_range(start, end, virt_to_page(ptrs[cpu]));
}
- pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size,
+ pcpu_unit_size = pcpu_setup_first_chunk(static_size,
PERCPU_MODULE_RESERVE, dyn_size,
PCPU_CHUNK_SIZE, vm.addr, NULL);
- free_bootmem(__pa(pcpur_ptrs), ptrs_size);
+ free_bootmem(__pa(ptrs), ptrs_size);
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu) {
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index f061c4dda9ef..3762f6c78944 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -121,7 +121,7 @@ SIGN2(sys32_syslog, sys_syslog, %o0, %o2)
SIGN1(sys32_umask, sys_umask, %o0)
SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2)
SIGN1(sys32_sendto, sys_sendto, %o0)
-SIGN1(sys32_recvfrom, sys_recvfrom, %o0)
+SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2)
SIGN2(sys32_connect, sys_connect, %o0, %o2)
SIGN2(sys32_bind, sys_bind, %o0, %o2)
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index fcbbd000ec08..866390feb683 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -171,12 +171,8 @@ SECTIONS
}
_end = . ;
- /DISCARD/ : {
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 3b44b47c7e1d..4c75409bc09c 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -245,7 +245,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void uml_net_set_multicast_list(struct net_device *dev)
diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S
index cb0248616d49..37ecc5577a9a 100644
--- a/arch/um/include/asm/common.lds.S
+++ b/arch/um/include/asm/common.lds.S
@@ -123,8 +123,3 @@
__initramfs_end = .;
}
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exitcall.exit)
- }
-
diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h
index 54f42e8b0105..34d813011b7a 100644
--- a/arch/um/include/asm/mmu_context.h
+++ b/arch/um/include/asm/mmu_context.h
@@ -35,8 +35,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
unsigned cpu = smp_processor_id();
if(prev != next){
- cpu_clear(cpu, prev->cpu_vm_mask);
- cpu_set(cpu, next->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
+ cpumask_set_cpu(cpu, mm_cpumask(next));
if(next != &init_mm)
__switch_mm(&next->context.id);
}
diff --git a/arch/um/include/asm/pci.h b/arch/um/include/asm/pci.h
index 59923199cdc3..b44cf59ede1e 100644
--- a/arch/um/include/asm/pci.h
+++ b/arch/um/include/asm/pci.h
@@ -2,6 +2,5 @@
#define __UM_PCI_H
#define PCI_DMA_BUS_IS_PHYS (1)
-#define pcibios_scan_all_fns(a, b) 0
#endif
diff --git a/arch/um/include/asm/pgalloc.h b/arch/um/include/asm/pgalloc.h
index 718984359f8c..32c8ce4e1515 100644
--- a/arch/um/include/asm/pgalloc.h
+++ b/arch/um/include/asm/pgalloc.h
@@ -40,7 +40,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
__free_page(pte);
}
-#define __pte_free_tlb(tlb,pte) \
+#define __pte_free_tlb(tlb,pte, address) \
do { \
pgtable_page_dtor(pte); \
tlb_remove_page((tlb),(pte)); \
@@ -53,7 +53,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
free_page((unsigned long)pmd);
}
-#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
+#define __pmd_free_tlb(tlb,x, address) tlb_remove_page((tlb),virt_to_page(x))
#endif
#define check_pgt_cache() do { } while (0)
diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h
index 5240fa1c5e08..660caedac9eb 100644
--- a/arch/um/include/asm/tlb.h
+++ b/arch/um/include/asm/tlb.h
@@ -116,11 +116,11 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
__tlb_remove_tlb_entry(tlb, ptep, address); \
} while (0)
-#define pte_free_tlb(tlb, ptep) __pte_free_tlb(tlb, ptep)
+#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
-#define pud_free_tlb(tlb, pudp) __pud_free_tlb(tlb, pudp)
+#define pud_free_tlb(tlb, pudp, addr) __pud_free_tlb(tlb, pudp, addr)
-#define pmd_free_tlb(tlb, pmdp) __pmd_free_tlb(tlb, pmdp)
+#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
#define tlb_migrate_finish(mm) do {} while (0)
diff --git a/arch/um/include/shared/ptrace_user.h b/arch/um/include/shared/ptrace_user.h
index 4bce6e012889..7fd8539bc19a 100644
--- a/arch/um/include/shared/ptrace_user.h
+++ b/arch/um/include/shared/ptrace_user.h
@@ -29,7 +29,7 @@ extern int ptrace_setregs(long pid, unsigned long *regs_in);
* recompilation. So, we use PTRACE_OLDSETOPTIONS in UML.
* We also want to be able to build the kernel on 2.4, which doesn't
* have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare
- * PTRACE_OLDSETOPTIONS to to be the same as PTRACE_SETOPTIONS.
+ * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS.
*
* On architectures, that start to support PTRACE_O_TRACESYSGOOD on
* linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 9975e1ab44fb..715a188c0472 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -156,4 +156,6 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 98351c78bc81..106bf27e2a9a 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -111,7 +111,7 @@ void smp_prepare_cpus(unsigned int maxcpus)
int i;
for (i = 0; i < ncpus; ++i)
- cpu_set(i, cpu_possible_map);
+ set_cpu_possible(i, true);
cpu_clear(me, cpu_online_map);
cpu_set(me, cpu_online_map);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 11b835248b86..2ebd39765db8 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -100,4 +100,6 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 91ff3b6312ad..7f9749f2a8cd 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -149,9 +149,6 @@ config ARCH_HAS_CACHE_LINE_SIZE
config HAVE_SETUP_PER_CPU_AREA
def_bool y
-config HAVE_DYNAMIC_PER_CPU_AREA
- def_bool y
-
config HAVE_CPUMASK_OF_CPU_MAP
def_bool X86_64_SMP
@@ -1247,6 +1244,11 @@ config ARCH_MEMORY_PROBE
def_bool X86_64
depends on MEMORY_HOTPLUG
+config ILLEGAL_POINTER_VALUE
+ hex
+ default 0 if X86_32
+ default 0xdead000000000000 if X86_64
+
source "mm/Kconfig"
config HIGHPTE
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 275dd177f198..11e8c6eb80a1 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -31,7 +31,6 @@ static inline void vesa_store_mode_params_graphics(void) {}
static int vesa_probe(void)
{
-#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
struct biosregs ireg, oreg;
u16 mode;
addr_t mode_ptr;
@@ -49,8 +48,7 @@ static int vesa_probe(void)
vginfo.signature != VESA_MAGIC ||
vginfo.version < 0x0102)
return 0; /* Not present */
-#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
-#ifdef CONFIG_VIDEO_VESA
+
set_fs(vginfo.video_mode_ptr.seg);
mode_ptr = vginfo.video_mode_ptr.off;
@@ -102,9 +100,6 @@ static int vesa_probe(void)
}
return nmodes;
-#else
- return 0;
-#endif /* CONFIG_VIDEO_VESA */
}
static int vesa_set_mode(struct mode_info *mode)
diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c
index 8f8d827e254d..819caa1f2008 100644
--- a/arch/x86/boot/video-vga.c
+++ b/arch/x86/boot/video-vga.c
@@ -47,14 +47,6 @@ static u8 vga_set_basic_mode(void)
initregs(&ireg);
-#ifdef CONFIG_VIDEO_400_HACK
- if (adapter >= ADAPTER_VGA) {
- ireg.ax = 0x1202;
- ireg.bx = 0x0030;
- intcall(0x10, &ireg, NULL);
- }
-#endif
-
ax = 0x0f00;
intcall(0x10, &ireg, &oreg);
mode = oreg.al;
@@ -62,11 +54,9 @@ static u8 vga_set_basic_mode(void)
set_fs(0);
rows = rdfs8(0x484); /* rows minus one */
-#ifndef CONFIG_VIDEO_400_HACK
if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) &&
(rows == 0 || rows == 24))
return mode;
-#endif
if (mode != 3 && mode != 7)
mode = 3;
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
index bad728b76fc2..d42da3802499 100644
--- a/arch/x86/boot/video.c
+++ b/arch/x86/boot/video.c
@@ -221,7 +221,6 @@ static unsigned int mode_menu(void)
}
}
-#ifdef CONFIG_VIDEO_RETAIN
/* Save screen content to the heap */
static struct saved_screen {
int x, y;
@@ -299,10 +298,6 @@ static void restore_screen(void)
ireg.dl = saved.curx;
intcall(0x10, &ireg, NULL);
}
-#else
-#define save_screen() ((void)0)
-#define restore_screen() ((void)0)
-#endif
void set_video(void)
{
diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h
index 5bb174a997fc..ff339c5db311 100644
--- a/arch/x86/boot/video.h
+++ b/arch/x86/boot/video.h
@@ -17,19 +17,8 @@
#include <linux/types.h>
-/* Enable autodetection of SVGA adapters and modes. */
-#undef CONFIG_VIDEO_SVGA
-
-/* Enable autodetection of VESA modes */
-#define CONFIG_VIDEO_VESA
-
-/* Retain screen contents when switching modes */
-#define CONFIG_VIDEO_RETAIN
-
-/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
-#undef CONFIG_VIDEO_400_HACK
-
-/* This code uses an extended set of video mode numbers. These include:
+/*
+ * This code uses an extended set of video mode numbers. These include:
* Aliases for standard modes
* NORMAL_VGA (-1)
* EXTENDED_VGA (-2)
@@ -67,13 +56,8 @@
/* The "recalculate timings" flag */
#define VIDEO_RECALC 0x8000
-/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
-#ifdef CONFIG_VIDEO_RETAIN
void store_screen(void);
#define DO_STORE() store_screen()
-#else
-#define DO_STORE() ((void)0)
-#endif /* CONFIG_VIDEO_RETAIN */
/*
* Mode table structures
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index c580c5ec1cad..d3ec8d588d4b 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -636,7 +636,7 @@ static int __init aesni_init(void)
int err;
if (!cpu_has_aes) {
- printk(KERN_ERR "Intel AES-NI instructions are not detected.\n");
+ printk(KERN_INFO "Intel AES-NI instructions are not detected.\n");
return -ENODEV;
}
if ((err = crypto_register_alg(&aesni_alg)))
diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h
index 7ddb36ab933b..74ca38f6a4de 100644
--- a/arch/x86/include/asm/apicdef.h
+++ b/arch/x86/include/asm/apicdef.h
@@ -14,6 +14,7 @@
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
+#define APIC_LVR_DIRECTED_EOI (1 << 24)
#define GET_APIC_VERSION(x) ((x) & 0xFFu)
#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu)
#ifdef CONFIG_X86_32
@@ -40,6 +41,7 @@
#define APIC_DFR_CLUSTER 0x0FFFFFFFul
#define APIC_DFR_FLAT 0xFFFFFFFFul
#define APIC_SPIV 0xF0
+#define APIC_SPIV_DIRECTED_EOI (1 << 12)
#define APIC_SPIV_FOCUS_DISABLED (1 << 9)
#define APIC_SPIV_APIC_ENABLED (1 << 8)
#define APIC_ISR 0x100
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 4a28d22d4793..847fee6493a2 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -95,6 +95,7 @@
#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
#define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
+#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h
index 4994a20acbcb..cee34e9ca45b 100644
--- a/arch/x86/include/asm/device.h
+++ b/arch/x86/include/asm/device.h
@@ -13,4 +13,7 @@ struct dma_map_ops *dma_ops;
#endif
};
+struct pdev_archdata {
+};
+
#endif /* _ASM_X86_DEVICE_H */
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index 175adf58dd4f..2e7529295f55 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -26,6 +26,7 @@ extern void fpu_init(void);
extern void mxcsr_feature_mask_init(void);
extern int init_fpu(struct task_struct *child);
extern asmlinkage void math_state_restore(void);
+extern void __math_state_restore(void);
extern void init_thread_xstate(void);
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
diff --git a/arch/x86/include/asm/ioctls.h b/arch/x86/include/asm/ioctls.h
index 0d5b23b7b06e..ec34c760665e 100644
--- a/arch/x86/include/asm/ioctls.h
+++ b/arch/x86/include/asm/ioctls.h
@@ -1,94 +1 @@
-#ifndef _ASM_X86_IOCTLS_H
-#define _ASM_X86_IOCTLS_H
-
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS 0x5401
-#define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
-#define TCSETSW 0x5403
-#define TCSETSF 0x5404
-#define TCGETA 0x5405
-#define TCSETA 0x5406
-#define TCSETAW 0x5407
-#define TCSETAF 0x5408
-#define TCSBRK 0x5409
-#define TCXONC 0x540A
-#define TCFLSH 0x540B
-#define TIOCEXCL 0x540C
-#define TIOCNXCL 0x540D
-#define TIOCSCTTY 0x540E
-#define TIOCGPGRP 0x540F
-#define TIOCSPGRP 0x5410
-#define TIOCOUTQ 0x5411
-#define TIOCSTI 0x5412
-#define TIOCGWINSZ 0x5413
-#define TIOCSWINSZ 0x5414
-#define TIOCMGET 0x5415
-#define TIOCMBIS 0x5416
-#define TIOCMBIC 0x5417
-#define TIOCMSET 0x5418
-#define TIOCGSOFTCAR 0x5419
-#define TIOCSSOFTCAR 0x541A
-#define FIONREAD 0x541B
-#define TIOCINQ FIONREAD
-#define TIOCLINUX 0x541C
-#define TIOCCONS 0x541D
-#define TIOCGSERIAL 0x541E
-#define TIOCSSERIAL 0x541F
-#define TIOCPKT 0x5420
-#define FIONBIO 0x5421
-#define TIOCNOTTY 0x5422
-#define TIOCSETD 0x5423
-#define TIOCGETD 0x5424
-#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
-/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
-#define TIOCSBRK 0x5427 /* BSD compatibility */
-#define TIOCCBRK 0x5428 /* BSD compatibility */
-#define TIOCGSID 0x5429 /* Return the session ID of FD */
-#define TCGETS2 _IOR('T', 0x2A, struct termios2)
-#define TCSETS2 _IOW('T', 0x2B, struct termios2)
-#define TCSETSW2 _IOW('T', 0x2C, struct termios2)
-#define TCSETSF2 _IOW('T', 0x2D, struct termios2)
-#define TIOCGRS485 0x542E
-#define TIOCSRS485 0x542F
-#define TIOCGPTN _IOR('T', 0x30, unsigned int)
- /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
-#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */
-#define TCSETX 0x5433
-#define TCSETXF 0x5434
-#define TCSETXW 0x5435
-
-#define FIONCLEX 0x5450
-#define FIOCLEX 0x5451
-#define FIOASYNC 0x5452
-#define TIOCSERCONFIG 0x5453
-#define TIOCSERGWILD 0x5454
-#define TIOCSERSWILD 0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR 0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
-#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
-#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
-#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
-#define FIOQSIZE 0x5460
-
-/* Used for packet mode */
-#define TIOCPKT_DATA 0
-#define TIOCPKT_FLUSHREAD 1
-#define TIOCPKT_FLUSHWRITE 2
-#define TIOCPKT_STOP 4
-#define TIOCPKT_START 8
-#define TIOCPKT_NOSTOP 16
-#define TIOCPKT_DOSTOP 32
-
-#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-#endif /* _ASM_X86_IOCTLS_H */
+#include <asm-generic/ioctls.h>
diff --git a/arch/x86/include/asm/ipcbuf.h b/arch/x86/include/asm/ipcbuf.h
index ee678fd51594..84c7e51cb6d0 100644
--- a/arch/x86/include/asm/ipcbuf.h
+++ b/arch/x86/include/asm/ipcbuf.h
@@ -1,28 +1 @@
-#ifndef _ASM_X86_IPCBUF_H
-#define _ASM_X86_IPCBUF_H
-
-/*
- * The ipc64_perm structure for x86 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 32-bit mode_t and seq
- * - 2 miscellaneous 32-bit values
- */
-
-struct ipc64_perm {
- __kernel_key_t key;
- __kernel_uid32_t uid;
- __kernel_gid32_t gid;
- __kernel_uid32_t cuid;
- __kernel_gid32_t cgid;
- __kernel_mode_t mode;
- unsigned short __pad1;
- unsigned short seq;
- unsigned short __pad2;
- unsigned long __unused1;
- unsigned long __unused2;
-};
-
-#endif /* _ASM_X86_IPCBUF_H */
+#include <asm-generic/ipcbuf.h>
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 125be8b19568..4a5fe914dc59 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -17,6 +17,8 @@
#define __KVM_HAVE_USER_NMI
#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
+#define __KVM_HAVE_PIT_STATE2
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
@@ -236,6 +238,14 @@ struct kvm_pit_state {
struct kvm_pit_channel_state channels[3];
};
+#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001
+
+struct kvm_pit_state2 {
+ struct kvm_pit_channel_state channels[3];
+ __u32 flags;
+ __u32 reserved[9];
+};
+
struct kvm_reinject_control {
__u8 pit_reinject;
__u8 reserved[31];
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index eabdc1cfab5c..e210b218df44 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/mmu_notifier.h>
+#include <linux/tracepoint.h>
#include <linux/kvm.h>
#include <linux/kvm_para.h>
@@ -37,12 +38,14 @@
#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS | \
0xFFFFFF0000000000ULL)
-#define KVM_GUEST_CR0_MASK \
- (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
- | X86_CR0_NW | X86_CR0_CD)
+#define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST \
+ (X86_CR0_WP | X86_CR0_NE | X86_CR0_NW | X86_CR0_CD)
+#define KVM_GUEST_CR0_MASK \
+ (KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
+#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST \
+ (X86_CR0_WP | X86_CR0_NE | X86_CR0_TS | X86_CR0_MP)
#define KVM_VM_CR0_ALWAYS_ON \
- (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
- | X86_CR0_MP)
+ (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
#define KVM_GUEST_CR4_MASK \
(X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
@@ -51,12 +54,12 @@
#define INVALID_PAGE (~(hpa_t)0)
#define UNMAPPED_GVA (~(gpa_t)0)
-/* shadow tables are PAE even on non-PAE hosts */
-#define KVM_HPAGE_SHIFT 21
-#define KVM_HPAGE_SIZE (1UL << KVM_HPAGE_SHIFT)
-#define KVM_HPAGE_MASK (~(KVM_HPAGE_SIZE - 1))
-
-#define KVM_PAGES_PER_HPAGE (KVM_HPAGE_SIZE / PAGE_SIZE)
+/* KVM Hugepage definitions for x86 */
+#define KVM_NR_PAGE_SIZES 2
+#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + (((x) - 1) * 9))
+#define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
+#define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1))
+#define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
#define DE_VECTOR 0
#define DB_VECTOR 1
@@ -120,6 +123,10 @@ enum kvm_reg {
NR_VCPU_REGS
};
+enum kvm_reg_ex {
+ VCPU_EXREG_PDPTR = NR_VCPU_REGS,
+};
+
enum {
VCPU_SREG_ES,
VCPU_SREG_CS,
@@ -334,16 +341,6 @@ struct kvm_vcpu_arch {
u8 nr;
} interrupt;
- struct {
- int vm86_active;
- u8 save_iopl;
- struct kvm_save_segment {
- u16 selector;
- unsigned long base;
- u32 limit;
- u32 ar;
- } tr, es, ds, fs, gs;
- } rmode;
int halt_request; /* real mode on Intel only */
int cpuid_nent;
@@ -373,6 +370,11 @@ struct kvm_vcpu_arch {
unsigned long dr6;
unsigned long dr7;
unsigned long eff_db[KVM_NR_DB_REGS];
+
+ u64 mcg_cap;
+ u64 mcg_status;
+ u64 mcg_ctl;
+ u64 *mce_banks;
};
struct kvm_mem_alias {
@@ -409,6 +411,7 @@ struct kvm_arch{
struct page *ept_identity_pagetable;
bool ept_identity_pagetable_done;
+ gpa_t ept_identity_map_addr;
unsigned long irq_sources_bitmap;
unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
@@ -526,6 +529,7 @@ struct kvm_x86_ops {
int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
int (*get_tdp_level)(void);
u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
+ const struct trace_print_flags *exit_reasons_str;
};
extern struct kvm_x86_ops *kvm_x86_ops;
@@ -752,8 +756,6 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
}
-#define MSR_IA32_TIME_STAMP_COUNTER 0x010
-
#define TSS_IOPB_BASE_OFFSET 0x66
#define TSS_BASE_SIZE 0x68
#define TSS_IOPB_SIZE (65536 / 8)
@@ -796,5 +798,8 @@ asmlinkage void kvm_handle_fault_on_reboot(void);
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
int kvm_age_hva(struct kvm *kvm, unsigned long hva);
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);
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
#endif /* _ASM_X86_KVM_HOST_H */
diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h
index 313389cd50d2..5136dad57cbb 100644
--- a/arch/x86/include/asm/lguest.h
+++ b/arch/x86/include/asm/lguest.h
@@ -17,8 +17,7 @@
/* Pages for switcher itself, then two pages per cpu */
#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * nr_cpu_ids)
-/* We map at -4M (-2M when PAE is activated) for ease of mapping
- * into the guest (one PTE page). */
+/* We map at -4M (-2M for PAE) for ease of mapping (one PTE page). */
#ifdef CONFIG_X86_PAE
#define SWITCHER_ADDR 0xFFE00000
#else
diff --git a/arch/x86/include/asm/lguest_hcall.h b/arch/x86/include/asm/lguest_hcall.h
index 33600a66755f..ba0eed8aa1a6 100644
--- a/arch/x86/include/asm/lguest_hcall.h
+++ b/arch/x86/include/asm/lguest_hcall.h
@@ -30,27 +30,27 @@
#include <asm/hw_irq.h>
#include <asm/kvm_para.h>
-/*G:030 But first, how does our Guest contact the Host to ask for privileged
+/*G:030
+ * But first, how does our Guest contact the Host to ask for privileged
* operations? There are two ways: the direct way is to make a "hypercall",
* to make requests of the Host Itself.
*
- * We use the KVM hypercall mechanism. Seventeen hypercalls are
- * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
- * If a return value makes sense, it's returned in %eax.
+ * We use the KVM hypercall mechanism, though completely different hypercall
+ * numbers. Seventeen hypercalls are available: the hypercall number is put in
+ * the %eax register, and the arguments (when required) are placed in %ebx,
+ * %ecx, %edx and %esi. If a return value makes sense, it's returned in %eax.
*
* Grossly invalid calls result in Sudden Death at the hands of the vengeful
* Host, rather than returning failure. This reflects Winston Churchill's
- * definition of a gentleman: "someone who is only rude intentionally". */
-/*:*/
+ * definition of a gentleman: "someone who is only rude intentionally".
+:*/
/* Can't use our min() macro here: needs to be a constant */
#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
#define LHCALL_RING_SIZE 64
struct hcall_args {
- /* These map directly onto eax, ebx, ecx, edx and esi
- * in struct lguest_regs */
+ /* These map directly onto eax/ebx/ecx/edx/esi in struct lguest_regs */
unsigned long arg0, arg1, arg2, arg3, arg4;
};
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 5cdd8d100ec9..b50b9e9042c4 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -9,7 +9,7 @@
*/
#define MCG_BANKCNT_MASK 0xff /* Number of Banks */
-#define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */
+#define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */
#define MCG_EXT_P (1ULL<<9) /* Extended registers available */
#define MCG_CMCI_P (1ULL<<10) /* CMCI supported */
#define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */
diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h
index 751af2550ed9..593e51d4643f 100644
--- a/arch/x86/include/asm/mman.h
+++ b/arch/x86/include/asm/mman.h
@@ -1,20 +1,8 @@
#ifndef _ASM_X86_MMAN_H
#define _ASM_X86_MMAN_H
-#include <asm-generic/mman-common.h>
-
#define MAP_32BIT 0x40 /* only give out 32bit addresses */
-#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
-#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
-#define MAP_LOCKED 0x2000 /* pages are locked */
-#define MAP_NORESERVE 0x4000 /* don't check for reservations */
-#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
-
-#define MCL_CURRENT 1 /* lock all current mappings */
-#define MCL_FUTURE 2 /* lock all future mappings */
+#include <asm-generic/mman.h>
#endif /* _ASM_X86_MMAN_H */
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index f923203dc39a..4a2d4e0c18d9 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -37,12 +37,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
if (likely(prev != next)) {
/* stop flush ipis for the previous mm */
- cpu_clear(cpu, prev->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
#ifdef CONFIG_SMP
percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
percpu_write(cpu_tlbstate.active_mm, next);
#endif
- cpu_set(cpu, next->cpu_vm_mask);
+ cpumask_set_cpu(cpu, mm_cpumask(next));
/* Re-load page tables */
load_cr3(next->pgd);
@@ -58,7 +58,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
- if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
/* We were in lazy tlb mode and leave_mm disabled
* tlb flush IPI delivery. We must reload CR3
* to make sure to use no freed page tables.
diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
index 47d62743c4d5..555bc12bdcd6 100644
--- a/arch/x86/include/asm/module.h
+++ b/arch/x86/include/asm/module.h
@@ -1,18 +1,7 @@
#ifndef _ASM_X86_MODULE_H
#define _ASM_X86_MODULE_H
-/* x86_32/64 are simple */
-struct mod_arch_specific {};
-
-#ifdef CONFIG_X86_32
-# define Elf_Shdr Elf32_Shdr
-# define Elf_Sym Elf32_Sym
-# define Elf_Ehdr Elf32_Ehdr
-#else
-# define Elf_Shdr Elf64_Shdr
-# define Elf_Sym Elf64_Sym
-# define Elf_Ehdr Elf64_Ehdr
-#endif
+#include <asm-generic/module.h>
#ifdef CONFIG_X86_64
/* X86_64 does not define MODULE_PROC_FAMILY */
diff --git a/arch/x86/include/asm/msgbuf.h b/arch/x86/include/asm/msgbuf.h
index 7e4e9481f51c..809134c644a6 100644
--- a/arch/x86/include/asm/msgbuf.h
+++ b/arch/x86/include/asm/msgbuf.h
@@ -1,39 +1 @@
-#ifndef _ASM_X86_MSGBUF_H
-#define _ASM_X86_MSGBUF_H
-
-/*
- * The msqid64_ds structure for i386 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space on i386 is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- *
- * Pad space on x8664 is left for:
- * - 2 miscellaneous 64-bit values
- */
-struct msqid64_ds {
- struct ipc64_perm msg_perm;
- __kernel_time_t msg_stime; /* last msgsnd time */
-#ifdef __i386__
- unsigned long __unused1;
-#endif
- __kernel_time_t msg_rtime; /* last msgrcv time */
-#ifdef __i386__
- unsigned long __unused2;
-#endif
- __kernel_time_t msg_ctime; /* last change time */
-#ifdef __i386__
- unsigned long __unused3;
-#endif
- unsigned long msg_cbytes; /* current number of bytes on queue */
- unsigned long msg_qnum; /* number of messages in queue */
- unsigned long msg_qbytes; /* max number of bytes on queue */
- __kernel_pid_t msg_lspid; /* pid of last msgsnd */
- __kernel_pid_t msg_lrpid; /* last receive pid */
- unsigned long __unused4;
- unsigned long __unused5;
-};
-
-#endif /* _ASM_X86_MSGBUF_H */
+#include <asm-generic/msgbuf.h>
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 6be7fc254b59..bd5549034a95 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -374,6 +374,7 @@
/* AMD-V MSRs */
#define MSR_VM_CR 0xc0010114
+#define MSR_VM_IGNNE 0xc0010115
#define MSR_VM_HSAVE_PA 0xc0010117
#endif /* _ASM_X86_MSR_INDEX_H */
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 48ad9d29484a..f2f4309e6ad0 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -224,8 +224,8 @@ do { \
#ifdef CONFIG_SMP
int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
#else /* CONFIG_SMP */
diff --git a/arch/x86/include/asm/param.h b/arch/x86/include/asm/param.h
index 6f0d0422f4ca..965d45427975 100644
--- a/arch/x86/include/asm/param.h
+++ b/arch/x86/include/asm/param.h
@@ -1,22 +1 @@
-#ifndef _ASM_X86_PARAM_H
-#define _ASM_X86_PARAM_H
-
-#ifdef __KERNEL__
-# define HZ CONFIG_HZ /* Internal kernel timer frequency */
-# define USER_HZ 100 /* some user interfaces are */
-# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */
-#endif
-
-#ifndef HZ
-#define HZ 100
-#endif
-
-#define EXEC_PAGESIZE 4096
-
-#ifndef NOGROUP
-#define NOGROUP (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64 /* max length of hostname */
-
-#endif /* _ASM_X86_PARAM_H */
+#include <asm-generic/param.h>
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 4fb37c8a0832..6a07af432c81 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -7,689 +7,11 @@
#include <asm/pgtable_types.h>
#include <asm/asm.h>
-/* Bitmask of what can be clobbered: usually at least eax. */
-#define CLBR_NONE 0
-#define CLBR_EAX (1 << 0)
-#define CLBR_ECX (1 << 1)
-#define CLBR_EDX (1 << 2)
-#define CLBR_EDI (1 << 3)
-
-#ifdef CONFIG_X86_32
-/* CLBR_ANY should match all regs platform has. For i386, that's just it */
-#define CLBR_ANY ((1 << 4) - 1)
-
-#define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX)
-#define CLBR_RET_REG (CLBR_EAX | CLBR_EDX)
-#define CLBR_SCRATCH (0)
-#else
-#define CLBR_RAX CLBR_EAX
-#define CLBR_RCX CLBR_ECX
-#define CLBR_RDX CLBR_EDX
-#define CLBR_RDI CLBR_EDI
-#define CLBR_RSI (1 << 4)
-#define CLBR_R8 (1 << 5)
-#define CLBR_R9 (1 << 6)
-#define CLBR_R10 (1 << 7)
-#define CLBR_R11 (1 << 8)
-
-#define CLBR_ANY ((1 << 9) - 1)
-
-#define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \
- CLBR_RCX | CLBR_R8 | CLBR_R9)
-#define CLBR_RET_REG (CLBR_RAX)
-#define CLBR_SCRATCH (CLBR_R10 | CLBR_R11)
-
-#include <asm/desc_defs.h>
-#endif /* X86_64 */
-
-#define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG)
+#include <asm/paravirt_types.h>
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/cpumask.h>
-#include <asm/kmap_types.h>
-#include <asm/desc_defs.h>
-
-struct page;
-struct thread_struct;
-struct desc_ptr;
-struct tss_struct;
-struct mm_struct;
-struct desc_struct;
-struct task_struct;
-
-/*
- * Wrapper type for pointers to code which uses the non-standard
- * calling convention. See PV_CALL_SAVE_REGS_THUNK below.
- */
-struct paravirt_callee_save {
- void *func;
-};
-
-/* general info */
-struct pv_info {
- unsigned int kernel_rpl;
- int shared_kernel_pmd;
- int paravirt_enabled;
- const char *name;
-};
-
-struct pv_init_ops {
- /*
- * Patch may replace one of the defined code sequences with
- * arbitrary code, subject to the same register constraints.
- * This generally means the code is not free to clobber any
- * registers other than EAX. The patch function should return
- * the number of bytes of code generated, as we nop pad the
- * rest in generic code.
- */
- unsigned (*patch)(u8 type, u16 clobber, void *insnbuf,
- unsigned long addr, unsigned len);
-
- /* Basic arch-specific setup */
- void (*arch_setup)(void);
- char *(*memory_setup)(void);
- void (*post_allocator_init)(void);
-
- /* Print a banner to identify the environment */
- void (*banner)(void);
-};
-
-
-struct pv_lazy_ops {
- /* Set deferred update mode, used for batching operations. */
- void (*enter)(void);
- void (*leave)(void);
-};
-
-struct pv_time_ops {
- void (*time_init)(void);
-
- /* Set and set time of day */
- unsigned long (*get_wallclock)(void);
- int (*set_wallclock)(unsigned long);
-
- unsigned long long (*sched_clock)(void);
- unsigned long (*get_tsc_khz)(void);
-};
-
-struct pv_cpu_ops {
- /* hooks for various privileged instructions */
- unsigned long (*get_debugreg)(int regno);
- void (*set_debugreg)(int regno, unsigned long value);
-
- void (*clts)(void);
-
- unsigned long (*read_cr0)(void);
- void (*write_cr0)(unsigned long);
-
- unsigned long (*read_cr4_safe)(void);
- unsigned long (*read_cr4)(void);
- void (*write_cr4)(unsigned long);
-
-#ifdef CONFIG_X86_64
- unsigned long (*read_cr8)(void);
- void (*write_cr8)(unsigned long);
-#endif
-
- /* Segment descriptor handling */
- void (*load_tr_desc)(void);
- void (*load_gdt)(const struct desc_ptr *);
- void (*load_idt)(const struct desc_ptr *);
- void (*store_gdt)(struct desc_ptr *);
- void (*store_idt)(struct desc_ptr *);
- void (*set_ldt)(const void *desc, unsigned entries);
- unsigned long (*store_tr)(void);
- void (*load_tls)(struct thread_struct *t, unsigned int cpu);
-#ifdef CONFIG_X86_64
- void (*load_gs_index)(unsigned int idx);
-#endif
- void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum,
- const void *desc);
- void (*write_gdt_entry)(struct desc_struct *,
- int entrynum, const void *desc, int size);
- void (*write_idt_entry)(gate_desc *,
- int entrynum, const gate_desc *gate);
- void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
- void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
-
- void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
-
- void (*set_iopl_mask)(unsigned mask);
-
- void (*wbinvd)(void);
- void (*io_delay)(void);
-
- /* cpuid emulation, mostly so that caps bits can be disabled */
- void (*cpuid)(unsigned int *eax, unsigned int *ebx,
- unsigned int *ecx, unsigned int *edx);
-
- /* MSR, PMC and TSR operations.
- err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */
- u64 (*read_msr_amd)(unsigned int msr, int *err);
- u64 (*read_msr)(unsigned int msr, int *err);
- int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
-
- u64 (*read_tsc)(void);
- u64 (*read_pmc)(int counter);
- unsigned long long (*read_tscp)(unsigned int *aux);
-
- /*
- * Atomically enable interrupts and return to userspace. This
- * is only ever used to return to 32-bit processes; in a
- * 64-bit kernel, it's used for 32-on-64 compat processes, but
- * never native 64-bit processes. (Jump, not call.)
- */
- void (*irq_enable_sysexit)(void);
-
- /*
- * Switch to usermode gs and return to 64-bit usermode using
- * sysret. Only used in 64-bit kernels to return to 64-bit
- * processes. Usermode register state, including %rsp, must
- * already be restored.
- */
- void (*usergs_sysret64)(void);
-
- /*
- * Switch to usermode gs and return to 32-bit usermode using
- * sysret. Used to return to 32-on-64 compat processes.
- * Other usermode register state, including %esp, must already
- * be restored.
- */
- void (*usergs_sysret32)(void);
-
- /* Normal iret. Jump to this with the standard iret stack
- frame set up. */
- void (*iret)(void);
-
- void (*swapgs)(void);
-
- void (*start_context_switch)(struct task_struct *prev);
- void (*end_context_switch)(struct task_struct *next);
-};
-
-struct pv_irq_ops {
- void (*init_IRQ)(void);
-
- /*
- * Get/set interrupt state. save_fl and restore_fl are only
- * expected to use X86_EFLAGS_IF; all other bits
- * returned from save_fl are undefined, and may be ignored by
- * restore_fl.
- *
- * NOTE: These functions callers expect the callee to preserve
- * more registers than the standard C calling convention.
- */
- struct paravirt_callee_save save_fl;
- struct paravirt_callee_save restore_fl;
- struct paravirt_callee_save irq_disable;
- struct paravirt_callee_save irq_enable;
-
- void (*safe_halt)(void);
- void (*halt)(void);
-
-#ifdef CONFIG_X86_64
- void (*adjust_exception_frame)(void);
-#endif
-};
-
-struct pv_apic_ops {
-#ifdef CONFIG_X86_LOCAL_APIC
- void (*setup_boot_clock)(void);
- void (*setup_secondary_clock)(void);
-
- void (*startup_ipi_hook)(int phys_apicid,
- unsigned long start_eip,
- unsigned long start_esp);
-#endif
-};
-
-struct pv_mmu_ops {
- /*
- * Called before/after init_mm pagetable setup. setup_start
- * may reset %cr3, and may pre-install parts of the pagetable;
- * pagetable setup is expected to preserve any existing
- * mapping.
- */
- void (*pagetable_setup_start)(pgd_t *pgd_base);
- void (*pagetable_setup_done)(pgd_t *pgd_base);
-
- unsigned long (*read_cr2)(void);
- void (*write_cr2)(unsigned long);
-
- unsigned long (*read_cr3)(void);
- void (*write_cr3)(unsigned long);
-
- /*
- * Hooks for intercepting the creation/use/destruction of an
- * mm_struct.
- */
- void (*activate_mm)(struct mm_struct *prev,
- struct mm_struct *next);
- void (*dup_mmap)(struct mm_struct *oldmm,
- struct mm_struct *mm);
- void (*exit_mmap)(struct mm_struct *mm);
-
-
- /* TLB operations */
- void (*flush_tlb_user)(void);
- void (*flush_tlb_kernel)(void);
- void (*flush_tlb_single)(unsigned long addr);
- void (*flush_tlb_others)(const struct cpumask *cpus,
- struct mm_struct *mm,
- unsigned long va);
-
- /* Hooks for allocating and freeing a pagetable top-level */
- int (*pgd_alloc)(struct mm_struct *mm);
- void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd);
-
- /*
- * Hooks for allocating/releasing pagetable pages when they're
- * attached to a pagetable
- */
- void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn);
- void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn);
- void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count);
- void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn);
- void (*release_pte)(unsigned long pfn);
- void (*release_pmd)(unsigned long pfn);
- void (*release_pud)(unsigned long pfn);
-
- /* Pagetable manipulation functions */
- void (*set_pte)(pte_t *ptep, pte_t pteval);
- void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval);
- void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
- void (*pte_update)(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep);
- void (*pte_update_defer)(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep);
-
- pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep);
- void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pte);
-
- struct paravirt_callee_save pte_val;
- struct paravirt_callee_save make_pte;
-
- struct paravirt_callee_save pgd_val;
- struct paravirt_callee_save make_pgd;
-
-#if PAGETABLE_LEVELS >= 3
-#ifdef CONFIG_X86_PAE
- void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
- void (*pte_clear)(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep);
- void (*pmd_clear)(pmd_t *pmdp);
-
-#endif /* CONFIG_X86_PAE */
-
- void (*set_pud)(pud_t *pudp, pud_t pudval);
-
- struct paravirt_callee_save pmd_val;
- struct paravirt_callee_save make_pmd;
-
-#if PAGETABLE_LEVELS == 4
- struct paravirt_callee_save pud_val;
- struct paravirt_callee_save make_pud;
-
- void (*set_pgd)(pgd_t *pudp, pgd_t pgdval);
-#endif /* PAGETABLE_LEVELS == 4 */
-#endif /* PAGETABLE_LEVELS >= 3 */
-
-#ifdef CONFIG_HIGHPTE
- void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
-#endif
-
- struct pv_lazy_ops lazy_mode;
-
- /* dom0 ops */
-
- /* Sometimes the physical address is a pfn, and sometimes its
- an mfn. We can tell which is which from the index. */
- void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
- phys_addr_t phys, pgprot_t flags);
-};
-
-struct raw_spinlock;
-struct pv_lock_ops {
- int (*spin_is_locked)(struct raw_spinlock *lock);
- int (*spin_is_contended)(struct raw_spinlock *lock);
- void (*spin_lock)(struct raw_spinlock *lock);
- void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
- int (*spin_trylock)(struct raw_spinlock *lock);
- void (*spin_unlock)(struct raw_spinlock *lock);
-};
-
-/* This contains all the paravirt structures: we get a convenient
- * number for each function using the offset which we use to indicate
- * what to patch. */
-struct paravirt_patch_template {
- struct pv_init_ops pv_init_ops;
- struct pv_time_ops pv_time_ops;
- struct pv_cpu_ops pv_cpu_ops;
- struct pv_irq_ops pv_irq_ops;
- struct pv_apic_ops pv_apic_ops;
- struct pv_mmu_ops pv_mmu_ops;
- struct pv_lock_ops pv_lock_ops;
-};
-
-extern struct pv_info pv_info;
-extern struct pv_init_ops pv_init_ops;
-extern struct pv_time_ops pv_time_ops;
-extern struct pv_cpu_ops pv_cpu_ops;
-extern struct pv_irq_ops pv_irq_ops;
-extern struct pv_apic_ops pv_apic_ops;
-extern struct pv_mmu_ops pv_mmu_ops;
-extern struct pv_lock_ops pv_lock_ops;
-
-#define PARAVIRT_PATCH(x) \
- (offsetof(struct paravirt_patch_template, x) / sizeof(void *))
-
-#define paravirt_type(op) \
- [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \
- [paravirt_opptr] "i" (&(op))
-#define paravirt_clobber(clobber) \
- [paravirt_clobber] "i" (clobber)
-
-/*
- * Generate some code, and mark it as patchable by the
- * apply_paravirt() alternate instruction patcher.
- */
-#define _paravirt_alt(insn_string, type, clobber) \
- "771:\n\t" insn_string "\n" "772:\n" \
- ".pushsection .parainstructions,\"a\"\n" \
- _ASM_ALIGN "\n" \
- _ASM_PTR " 771b\n" \
- " .byte " type "\n" \
- " .byte 772b-771b\n" \
- " .short " clobber "\n" \
- ".popsection\n"
-
-/* Generate patchable code, with the default asm parameters. */
-#define paravirt_alt(insn_string) \
- _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
-
-/* Simple instruction patching code. */
-#define DEF_NATIVE(ops, name, code) \
- extern const char start_##ops##_##name[], end_##ops##_##name[]; \
- asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
-
-unsigned paravirt_patch_nop(void);
-unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len);
-unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len);
-unsigned paravirt_patch_ignore(unsigned len);
-unsigned paravirt_patch_call(void *insnbuf,
- const void *target, u16 tgt_clobbers,
- unsigned long addr, u16 site_clobbers,
- unsigned len);
-unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
- unsigned long addr, unsigned len);
-unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
- unsigned long addr, unsigned len);
-
-unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
- const char *start, const char *end);
-
-unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
- unsigned long addr, unsigned len);
-
-int paravirt_disable_iospace(void);
-
-/*
- * This generates an indirect call based on the operation type number.
- * The type number, computed in PARAVIRT_PATCH, is derived from the
- * offset into the paravirt_patch_template structure, and can therefore be
- * freely converted back into a structure offset.
- */
-#define PARAVIRT_CALL "call *%c[paravirt_opptr];"
-
-/*
- * These macros are intended to wrap calls through one of the paravirt
- * ops structs, so that they can be later identified and patched at
- * runtime.
- *
- * Normally, a call to a pv_op function is a simple indirect call:
- * (pv_op_struct.operations)(args...).
- *
- * Unfortunately, this is a relatively slow operation for modern CPUs,
- * because it cannot necessarily determine what the destination
- * address is. In this case, the address is a runtime constant, so at
- * the very least we can patch the call to e a simple direct call, or
- * ideally, patch an inline implementation into the callsite. (Direct
- * calls are essentially free, because the call and return addresses
- * are completely predictable.)
- *
- * For i386, these macros rely on the standard gcc "regparm(3)" calling
- * convention, in which the first three arguments are placed in %eax,
- * %edx, %ecx (in that order), and the remaining arguments are placed
- * on the stack. All caller-save registers (eax,edx,ecx) are expected
- * to be modified (either clobbered or used for return values).
- * X86_64, on the other hand, already specifies a register-based calling
- * conventions, returning at %rax, with parameteres going on %rdi, %rsi,
- * %rdx, and %rcx. Note that for this reason, x86_64 does not need any
- * special handling for dealing with 4 arguments, unlike i386.
- * However, x86_64 also have to clobber all caller saved registers, which
- * unfortunately, are quite a bit (r8 - r11)
- *
- * The call instruction itself is marked by placing its start address
- * and size into the .parainstructions section, so that
- * apply_paravirt() in arch/i386/kernel/alternative.c can do the
- * appropriate patching under the control of the backend pv_init_ops
- * implementation.
- *
- * Unfortunately there's no way to get gcc to generate the args setup
- * for the call, and then allow the call itself to be generated by an
- * inline asm. Because of this, we must do the complete arg setup and
- * return value handling from within these macros. This is fairly
- * cumbersome.
- *
- * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments.
- * It could be extended to more arguments, but there would be little
- * to be gained from that. For each number of arguments, there are
- * the two VCALL and CALL variants for void and non-void functions.
- *
- * When there is a return value, the invoker of the macro must specify
- * the return type. The macro then uses sizeof() on that type to
- * determine whether its a 32 or 64 bit value, and places the return
- * in the right register(s) (just %eax for 32-bit, and %edx:%eax for
- * 64-bit). For x86_64 machines, it just returns at %rax regardless of
- * the return value size.
- *
- * 64-bit arguments are passed as a pair of adjacent 32-bit arguments
- * i386 also passes 64-bit arguments as a pair of adjacent 32-bit arguments
- * in low,high order
- *
- * Small structures are passed and returned in registers. The macro
- * calling convention can't directly deal with this, so the wrapper
- * functions must do this.
- *
- * These PVOP_* macros are only defined within this header. This
- * means that all uses must be wrapped in inline functions. This also
- * makes sure the incoming and outgoing types are always correct.
- */
-#ifdef CONFIG_X86_32
-#define PVOP_VCALL_ARGS \
- unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx
-#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
-
-#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x))
-#define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x))
-#define PVOP_CALL_ARG3(x) "c" ((unsigned long)(x))
-
-#define PVOP_VCALL_CLOBBERS "=a" (__eax), "=d" (__edx), \
- "=c" (__ecx)
-#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS
-
-#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), "=d" (__edx)
-#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
-
-#define EXTRA_CLOBBERS
-#define VEXTRA_CLOBBERS
-#else /* CONFIG_X86_64 */
-#define PVOP_VCALL_ARGS \
- unsigned long __edi = __edi, __esi = __esi, \
- __edx = __edx, __ecx = __ecx
-#define PVOP_CALL_ARGS PVOP_VCALL_ARGS, __eax
-
-#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
-#define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x))
-#define PVOP_CALL_ARG3(x) "d" ((unsigned long)(x))
-#define PVOP_CALL_ARG4(x) "c" ((unsigned long)(x))
-
-#define PVOP_VCALL_CLOBBERS "=D" (__edi), \
- "=S" (__esi), "=d" (__edx), \
- "=c" (__ecx)
-#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax)
-
-#define PVOP_VCALLEE_CLOBBERS "=a" (__eax)
-#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
-
-#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11"
-#define VEXTRA_CLOBBERS , "rax", "r8", "r9", "r10", "r11"
-#endif /* CONFIG_X86_32 */
-
-#ifdef CONFIG_PARAVIRT_DEBUG
-#define PVOP_TEST_NULL(op) BUG_ON(op == NULL)
-#else
-#define PVOP_TEST_NULL(op) ((void)op)
-#endif
-
-#define ____PVOP_CALL(rettype, op, clbr, call_clbr, extra_clbr, \
- pre, post, ...) \
- ({ \
- rettype __ret; \
- PVOP_CALL_ARGS; \
- PVOP_TEST_NULL(op); \
- /* This is 32-bit specific, but is okay in 64-bit */ \
- /* since this condition will never hold */ \
- if (sizeof(rettype) > sizeof(unsigned long)) { \
- asm volatile(pre \
- paravirt_alt(PARAVIRT_CALL) \
- post \
- : call_clbr \
- : paravirt_type(op), \
- paravirt_clobber(clbr), \
- ##__VA_ARGS__ \
- : "memory", "cc" extra_clbr); \
- __ret = (rettype)((((u64)__edx) << 32) | __eax); \
- } else { \
- asm volatile(pre \
- paravirt_alt(PARAVIRT_CALL) \
- post \
- : call_clbr \
- : paravirt_type(op), \
- paravirt_clobber(clbr), \
- ##__VA_ARGS__ \
- : "memory", "cc" extra_clbr); \
- __ret = (rettype)__eax; \
- } \
- __ret; \
- })
-
-#define __PVOP_CALL(rettype, op, pre, post, ...) \
- ____PVOP_CALL(rettype, op, CLBR_ANY, PVOP_CALL_CLOBBERS, \
- EXTRA_CLOBBERS, pre, post, ##__VA_ARGS__)
-
-#define __PVOP_CALLEESAVE(rettype, op, pre, post, ...) \
- ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \
- PVOP_CALLEE_CLOBBERS, , \
- pre, post, ##__VA_ARGS__)
-
-
-#define ____PVOP_VCALL(op, clbr, call_clbr, extra_clbr, pre, post, ...) \
- ({ \
- PVOP_VCALL_ARGS; \
- PVOP_TEST_NULL(op); \
- asm volatile(pre \
- paravirt_alt(PARAVIRT_CALL) \
- post \
- : call_clbr \
- : paravirt_type(op), \
- paravirt_clobber(clbr), \
- ##__VA_ARGS__ \
- : "memory", "cc" extra_clbr); \
- })
-
-#define __PVOP_VCALL(op, pre, post, ...) \
- ____PVOP_VCALL(op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \
- VEXTRA_CLOBBERS, \
- pre, post, ##__VA_ARGS__)
-
-#define __PVOP_VCALLEESAVE(rettype, op, pre, post, ...) \
- ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \
- PVOP_VCALLEE_CLOBBERS, , \
- pre, post, ##__VA_ARGS__)
-
-
-
-#define PVOP_CALL0(rettype, op) \
- __PVOP_CALL(rettype, op, "", "")
-#define PVOP_VCALL0(op) \
- __PVOP_VCALL(op, "", "")
-
-#define PVOP_CALLEE0(rettype, op) \
- __PVOP_CALLEESAVE(rettype, op, "", "")
-#define PVOP_VCALLEE0(op) \
- __PVOP_VCALLEESAVE(op, "", "")
-
-
-#define PVOP_CALL1(rettype, op, arg1) \
- __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1))
-#define PVOP_VCALL1(op, arg1) \
- __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1))
-
-#define PVOP_CALLEE1(rettype, op, arg1) \
- __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1))
-#define PVOP_VCALLEE1(op, arg1) \
- __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1))
-
-
-#define PVOP_CALL2(rettype, op, arg1, arg2) \
- __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2))
-#define PVOP_VCALL2(op, arg1, arg2) \
- __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2))
-
-#define PVOP_CALLEE2(rettype, op, arg1, arg2) \
- __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2))
-#define PVOP_VCALLEE2(op, arg1, arg2) \
- __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2))
-
-
-#define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \
- __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3))
-#define PVOP_VCALL3(op, arg1, arg2, arg3) \
- __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \
- PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3))
-
-/* This is the only difference in x86_64. We can make it much simpler */
-#ifdef CONFIG_X86_32
-#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \
- __PVOP_CALL(rettype, op, \
- "push %[_arg4];", "lea 4(%%esp),%%esp;", \
- PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
- PVOP_CALL_ARG3(arg3), [_arg4] "mr" ((u32)(arg4)))
-#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \
- __PVOP_VCALL(op, \
- "push %[_arg4];", "lea 4(%%esp),%%esp;", \
- "0" ((u32)(arg1)), "1" ((u32)(arg2)), \
- "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
-#else
-#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \
- __PVOP_CALL(rettype, op, "", "", \
- PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
- PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
-#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \
- __PVOP_VCALL(op, "", "", \
- PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
- PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
-#endif
static inline int paravirt_enabled(void)
{
@@ -1393,20 +715,6 @@ static inline void pmd_clear(pmd_t *pmdp)
}
#endif /* CONFIG_X86_PAE */
-/* Lazy mode for batching updates / context switch */
-enum paravirt_lazy_mode {
- PARAVIRT_LAZY_NONE,
- PARAVIRT_LAZY_MMU,
- PARAVIRT_LAZY_CPU,
-};
-
-enum paravirt_lazy_mode paravirt_get_lazy_mode(void);
-void paravirt_start_context_switch(struct task_struct *prev);
-void paravirt_end_context_switch(struct task_struct *next);
-
-void paravirt_enter_lazy_mmu(void);
-void paravirt_leave_lazy_mmu(void);
-
#define __HAVE_ARCH_START_CONTEXT_SWITCH
static inline void arch_start_context_switch(struct task_struct *prev)
{
@@ -1437,12 +745,6 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
pv_mmu_ops.set_fixmap(idx, phys, flags);
}
-void _paravirt_nop(void);
-u32 _paravirt_ident_32(u32);
-u64 _paravirt_ident_64(u64);
-
-#define paravirt_nop ((void *)_paravirt_nop)
-
#if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
static inline int __raw_spin_is_locked(struct raw_spinlock *lock)
@@ -1479,17 +781,6 @@ static __always_inline void __raw_spin_unlock(struct raw_spinlock *lock)
#endif
-/* These all sit in the .parainstructions section to tell us what to patch. */
-struct paravirt_patch_site {
- u8 *instr; /* original instructions */
- u8 instrtype; /* type of this instruction */
- u8 len; /* length of original instruction */
- u16 clobbers; /* what registers you may clobber */
-};
-
-extern struct paravirt_patch_site __parainstructions[],
- __parainstructions_end[];
-
#ifdef CONFIG_X86_32
#define PV_SAVE_REGS "pushl %ecx; pushl %edx;"
#define PV_RESTORE_REGS "popl %edx; popl %ecx;"
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
new file mode 100644
index 000000000000..2b3371bae295
--- /dev/null
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -0,0 +1,720 @@
+#ifndef _ASM_X86_PARAVIRT_TYPES_H
+#define _ASM_X86_PARAVIRT_TYPES_H
+
+/* Bitmask of what can be clobbered: usually at least eax. */
+#define CLBR_NONE 0
+#define CLBR_EAX (1 << 0)
+#define CLBR_ECX (1 << 1)
+#define CLBR_EDX (1 << 2)
+#define CLBR_EDI (1 << 3)
+
+#ifdef CONFIG_X86_32
+/* CLBR_ANY should match all regs platform has. For i386, that's just it */
+#define CLBR_ANY ((1 << 4) - 1)
+
+#define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX)
+#define CLBR_RET_REG (CLBR_EAX | CLBR_EDX)
+#define CLBR_SCRATCH (0)
+#else
+#define CLBR_RAX CLBR_EAX
+#define CLBR_RCX CLBR_ECX
+#define CLBR_RDX CLBR_EDX
+#define CLBR_RDI CLBR_EDI
+#define CLBR_RSI (1 << 4)
+#define CLBR_R8 (1 << 5)
+#define CLBR_R9 (1 << 6)
+#define CLBR_R10 (1 << 7)
+#define CLBR_R11 (1 << 8)
+
+#define CLBR_ANY ((1 << 9) - 1)
+
+#define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \
+ CLBR_RCX | CLBR_R8 | CLBR_R9)
+#define CLBR_RET_REG (CLBR_RAX)
+#define CLBR_SCRATCH (CLBR_R10 | CLBR_R11)
+
+#endif /* X86_64 */
+
+#define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG)
+
+#ifndef __ASSEMBLY__
+
+#include <asm/desc_defs.h>
+#include <asm/kmap_types.h>
+
+struct page;
+struct thread_struct;
+struct desc_ptr;
+struct tss_struct;
+struct mm_struct;
+struct desc_struct;
+struct task_struct;
+struct cpumask;
+
+/*
+ * Wrapper type for pointers to code which uses the non-standard
+ * calling convention. See PV_CALL_SAVE_REGS_THUNK below.
+ */
+struct paravirt_callee_save {
+ void *func;
+};
+
+/* general info */
+struct pv_info {
+ unsigned int kernel_rpl;
+ int shared_kernel_pmd;
+ int paravirt_enabled;
+ const char *name;
+};
+
+struct pv_init_ops {
+ /*
+ * Patch may replace one of the defined code sequences with
+ * arbitrary code, subject to the same register constraints.
+ * This generally means the code is not free to clobber any
+ * registers other than EAX. The patch function should return
+ * the number of bytes of code generated, as we nop pad the
+ * rest in generic code.
+ */
+ unsigned (*patch)(u8 type, u16 clobber, void *insnbuf,
+ unsigned long addr, unsigned len);
+
+ /* Basic arch-specific setup */
+ void (*arch_setup)(void);
+ char *(*memory_setup)(void);
+ void (*post_allocator_init)(void);
+
+ /* Print a banner to identify the environment */
+ void (*banner)(void);
+};
+
+
+struct pv_lazy_ops {
+ /* Set deferred update mode, used for batching operations. */
+ void (*enter)(void);
+ void (*leave)(void);
+};
+
+struct pv_time_ops {
+ void (*time_init)(void);
+
+ /* Set and set time of day */
+ unsigned long (*get_wallclock)(void);
+ int (*set_wallclock)(unsigned long);
+
+ unsigned long long (*sched_clock)(void);
+ unsigned long (*get_tsc_khz)(void);
+};
+
+struct pv_cpu_ops {
+ /* hooks for various privileged instructions */
+ unsigned long (*get_debugreg)(int regno);
+ void (*set_debugreg)(int regno, unsigned long value);
+
+ void (*clts)(void);
+
+ unsigned long (*read_cr0)(void);
+ void (*write_cr0)(unsigned long);
+
+ unsigned long (*read_cr4_safe)(void);
+ unsigned long (*read_cr4)(void);
+ void (*write_cr4)(unsigned long);
+
+#ifdef CONFIG_X86_64
+ unsigned long (*read_cr8)(void);
+ void (*write_cr8)(unsigned long);
+#endif
+
+ /* Segment descriptor handling */
+ void (*load_tr_desc)(void);
+ void (*load_gdt)(const struct desc_ptr *);
+ void (*load_idt)(const struct desc_ptr *);
+ void (*store_gdt)(struct desc_ptr *);
+ void (*store_idt)(struct desc_ptr *);
+ void (*set_ldt)(const void *desc, unsigned entries);
+ unsigned long (*store_tr)(void);
+ void (*load_tls)(struct thread_struct *t, unsigned int cpu);
+#ifdef CONFIG_X86_64
+ void (*load_gs_index)(unsigned int idx);
+#endif
+ void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum,
+ const void *desc);
+ void (*write_gdt_entry)(struct desc_struct *,
+ int entrynum, const void *desc, int size);
+ void (*write_idt_entry)(gate_desc *,
+ int entrynum, const gate_desc *gate);
+ void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+ void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
+ void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
+
+ void (*set_iopl_mask)(unsigned mask);
+
+ void (*wbinvd)(void);
+ void (*io_delay)(void);
+
+ /* cpuid emulation, mostly so that caps bits can be disabled */
+ void (*cpuid)(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx);
+
+ /* MSR, PMC and TSR operations.
+ err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */
+ u64 (*read_msr_amd)(unsigned int msr, int *err);
+ u64 (*read_msr)(unsigned int msr, int *err);
+ int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
+
+ u64 (*read_tsc)(void);
+ u64 (*read_pmc)(int counter);
+ unsigned long long (*read_tscp)(unsigned int *aux);
+
+ /*
+ * Atomically enable interrupts and return to userspace. This
+ * is only ever used to return to 32-bit processes; in a
+ * 64-bit kernel, it's used for 32-on-64 compat processes, but
+ * never native 64-bit processes. (Jump, not call.)
+ */
+ void (*irq_enable_sysexit)(void);
+
+ /*
+ * Switch to usermode gs and return to 64-bit usermode using
+ * sysret. Only used in 64-bit kernels to return to 64-bit
+ * processes. Usermode register state, including %rsp, must
+ * already be restored.
+ */
+ void (*usergs_sysret64)(void);
+
+ /*
+ * Switch to usermode gs and return to 32-bit usermode using
+ * sysret. Used to return to 32-on-64 compat processes.
+ * Other usermode register state, including %esp, must already
+ * be restored.
+ */
+ void (*usergs_sysret32)(void);
+
+ /* Normal iret. Jump to this with the standard iret stack
+ frame set up. */
+ void (*iret)(void);
+
+ void (*swapgs)(void);
+
+ void (*start_context_switch)(struct task_struct *prev);
+ void (*end_context_switch)(struct task_struct *next);
+};
+
+struct pv_irq_ops {
+ void (*init_IRQ)(void);
+
+ /*
+ * Get/set interrupt state. save_fl and restore_fl are only
+ * expected to use X86_EFLAGS_IF; all other bits
+ * returned from save_fl are undefined, and may be ignored by
+ * restore_fl.
+ *
+ * NOTE: These functions callers expect the callee to preserve
+ * more registers than the standard C calling convention.
+ */
+ struct paravirt_callee_save save_fl;
+ struct paravirt_callee_save restore_fl;
+ struct paravirt_callee_save irq_disable;
+ struct paravirt_callee_save irq_enable;
+
+ void (*safe_halt)(void);
+ void (*halt)(void);
+
+#ifdef CONFIG_X86_64
+ void (*adjust_exception_frame)(void);
+#endif
+};
+
+struct pv_apic_ops {
+#ifdef CONFIG_X86_LOCAL_APIC
+ void (*setup_boot_clock)(void);
+ void (*setup_secondary_clock)(void);
+
+ void (*startup_ipi_hook)(int phys_apicid,
+ unsigned long start_eip,
+ unsigned long start_esp);
+#endif
+};
+
+struct pv_mmu_ops {
+ /*
+ * Called before/after init_mm pagetable setup. setup_start
+ * may reset %cr3, and may pre-install parts of the pagetable;
+ * pagetable setup is expected to preserve any existing
+ * mapping.
+ */
+ void (*pagetable_setup_start)(pgd_t *pgd_base);
+ void (*pagetable_setup_done)(pgd_t *pgd_base);
+
+ unsigned long (*read_cr2)(void);
+ void (*write_cr2)(unsigned long);
+
+ unsigned long (*read_cr3)(void);
+ void (*write_cr3)(unsigned long);
+
+ /*
+ * Hooks for intercepting the creation/use/destruction of an
+ * mm_struct.
+ */
+ void (*activate_mm)(struct mm_struct *prev,
+ struct mm_struct *next);
+ void (*dup_mmap)(struct mm_struct *oldmm,
+ struct mm_struct *mm);
+ void (*exit_mmap)(struct mm_struct *mm);
+
+
+ /* TLB operations */
+ void (*flush_tlb_user)(void);
+ void (*flush_tlb_kernel)(void);
+ void (*flush_tlb_single)(unsigned long addr);
+ void (*flush_tlb_others)(const struct cpumask *cpus,
+ struct mm_struct *mm,
+ unsigned long va);
+
+ /* Hooks for allocating and freeing a pagetable top-level */
+ int (*pgd_alloc)(struct mm_struct *mm);
+ void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd);
+
+ /*
+ * Hooks for allocating/releasing pagetable pages when they're
+ * attached to a pagetable
+ */
+ void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn);
+ void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn);
+ void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count);
+ void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn);
+ void (*release_pte)(unsigned long pfn);
+ void (*release_pmd)(unsigned long pfn);
+ void (*release_pud)(unsigned long pfn);
+
+ /* Pagetable manipulation functions */
+ void (*set_pte)(pte_t *ptep, pte_t pteval);
+ void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
+ void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
+ void (*pte_update)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+ void (*pte_update_defer)(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
+
+ pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+ void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+
+ struct paravirt_callee_save pte_val;
+ struct paravirt_callee_save make_pte;
+
+ struct paravirt_callee_save pgd_val;
+ struct paravirt_callee_save make_pgd;
+
+#if PAGETABLE_LEVELS >= 3
+#ifdef CONFIG_X86_PAE
+ void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
+ void (*pte_clear)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+ void (*pmd_clear)(pmd_t *pmdp);
+
+#endif /* CONFIG_X86_PAE */
+
+ void (*set_pud)(pud_t *pudp, pud_t pudval);
+
+ struct paravirt_callee_save pmd_val;
+ struct paravirt_callee_save make_pmd;
+
+#if PAGETABLE_LEVELS == 4
+ struct paravirt_callee_save pud_val;
+ struct paravirt_callee_save make_pud;
+
+ void (*set_pgd)(pgd_t *pudp, pgd_t pgdval);
+#endif /* PAGETABLE_LEVELS == 4 */
+#endif /* PAGETABLE_LEVELS >= 3 */
+
+#ifdef CONFIG_HIGHPTE
+ void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
+#endif
+
+ struct pv_lazy_ops lazy_mode;
+
+ /* dom0 ops */
+
+ /* Sometimes the physical address is a pfn, and sometimes its
+ an mfn. We can tell which is which from the index. */
+ void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
+ phys_addr_t phys, pgprot_t flags);
+};
+
+struct raw_spinlock;
+struct pv_lock_ops {
+ int (*spin_is_locked)(struct raw_spinlock *lock);
+ int (*spin_is_contended)(struct raw_spinlock *lock);
+ void (*spin_lock)(struct raw_spinlock *lock);
+ void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
+ int (*spin_trylock)(struct raw_spinlock *lock);
+ void (*spin_unlock)(struct raw_spinlock *lock);
+};
+
+/* This contains all the paravirt structures: we get a convenient
+ * number for each function using the offset which we use to indicate
+ * what to patch. */
+struct paravirt_patch_template {
+ struct pv_init_ops pv_init_ops;
+ struct pv_time_ops pv_time_ops;
+ struct pv_cpu_ops pv_cpu_ops;
+ struct pv_irq_ops pv_irq_ops;
+ struct pv_apic_ops pv_apic_ops;
+ struct pv_mmu_ops pv_mmu_ops;
+ struct pv_lock_ops pv_lock_ops;
+};
+
+extern struct pv_info pv_info;
+extern struct pv_init_ops pv_init_ops;
+extern struct pv_time_ops pv_time_ops;
+extern struct pv_cpu_ops pv_cpu_ops;
+extern struct pv_irq_ops pv_irq_ops;
+extern struct pv_apic_ops pv_apic_ops;
+extern struct pv_mmu_ops pv_mmu_ops;
+extern struct pv_lock_ops pv_lock_ops;
+
+#define PARAVIRT_PATCH(x) \
+ (offsetof(struct paravirt_patch_template, x) / sizeof(void *))
+
+#define paravirt_type(op) \
+ [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \
+ [paravirt_opptr] "i" (&(op))
+#define paravirt_clobber(clobber) \
+ [paravirt_clobber] "i" (clobber)
+
+/*
+ * Generate some code, and mark it as patchable by the
+ * apply_paravirt() alternate instruction patcher.
+ */
+#define _paravirt_alt(insn_string, type, clobber) \
+ "771:\n\t" insn_string "\n" "772:\n" \
+ ".pushsection .parainstructions,\"a\"\n" \
+ _ASM_ALIGN "\n" \
+ _ASM_PTR " 771b\n" \
+ " .byte " type "\n" \
+ " .byte 772b-771b\n" \
+ " .short " clobber "\n" \
+ ".popsection\n"
+
+/* Generate patchable code, with the default asm parameters. */
+#define paravirt_alt(insn_string) \
+ _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
+
+/* Simple instruction patching code. */
+#define DEF_NATIVE(ops, name, code) \
+ extern const char start_##ops##_##name[], end_##ops##_##name[]; \
+ asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
+
+unsigned paravirt_patch_nop(void);
+unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len);
+unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len);
+unsigned paravirt_patch_ignore(unsigned len);
+unsigned paravirt_patch_call(void *insnbuf,
+ const void *target, u16 tgt_clobbers,
+ unsigned long addr, u16 site_clobbers,
+ unsigned len);
+unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
+ unsigned long addr, unsigned len);
+unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
+ unsigned long addr, unsigned len);
+
+unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
+ const char *start, const char *end);
+
+unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
+ unsigned long addr, unsigned len);
+
+int paravirt_disable_iospace(void);
+
+/*
+ * This generates an indirect call based on the operation type number.
+ * The type number, computed in PARAVIRT_PATCH, is derived from the
+ * offset into the paravirt_patch_template structure, and can therefore be
+ * freely converted back into a structure offset.
+ */
+#define PARAVIRT_CALL "call *%c[paravirt_opptr];"
+
+/*
+ * These macros are intended to wrap calls through one of the paravirt
+ * ops structs, so that they can be later identified and patched at
+ * runtime.
+ *
+ * Normally, a call to a pv_op function is a simple indirect call:
+ * (pv_op_struct.operations)(args...).
+ *
+ * Unfortunately, this is a relatively slow operation for modern CPUs,
+ * because it cannot necessarily determine what the destination
+ * address is. In this case, the address is a runtime constant, so at
+ * the very least we can patch the call to e a simple direct call, or
+ * ideally, patch an inline implementation into the callsite. (Direct
+ * calls are essentially free, because the call and return addresses
+ * are completely predictable.)
+ *
+ * For i386, these macros rely on the standard gcc "regparm(3)" calling
+ * convention, in which the first three arguments are placed in %eax,
+ * %edx, %ecx (in that order), and the remaining arguments are placed
+ * on the stack. All caller-save registers (eax,edx,ecx) are expected
+ * to be modified (either clobbered or used for return values).
+ * X86_64, on the other hand, already specifies a register-based calling
+ * conventions, returning at %rax, with parameteres going on %rdi, %rsi,
+ * %rdx, and %rcx. Note that for this reason, x86_64 does not need any
+ * special handling for dealing with 4 arguments, unlike i386.
+ * However, x86_64 also have to clobber all caller saved registers, which
+ * unfortunately, are quite a bit (r8 - r11)
+ *
+ * The call instruction itself is marked by placing its start address
+ * and size into the .parainstructions section, so that
+ * apply_paravirt() in arch/i386/kernel/alternative.c can do the
+ * appropriate patching under the control of the backend pv_init_ops
+ * implementation.
+ *
+ * Unfortunately there's no way to get gcc to generate the args setup
+ * for the call, and then allow the call itself to be generated by an
+ * inline asm. Because of this, we must do the complete arg setup and
+ * return value handling from within these macros. This is fairly
+ * cumbersome.
+ *
+ * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments.
+ * It could be extended to more arguments, but there would be little
+ * to be gained from that. For each number of arguments, there are
+ * the two VCALL and CALL variants for void and non-void functions.
+ *
+ * When there is a return value, the invoker of the macro must specify
+ * the return type. The macro then uses sizeof() on that type to
+ * determine whether its a 32 or 64 bit value, and places the return
+ * in the right register(s) (just %eax for 32-bit, and %edx:%eax for
+ * 64-bit). For x86_64 machines, it just returns at %rax regardless of
+ * the return value size.
+ *
+ * 64-bit arguments are passed as a pair of adjacent 32-bit arguments
+ * i386 also passes 64-bit arguments as a pair of adjacent 32-bit arguments
+ * in low,high order
+ *
+ * Small structures are passed and returned in registers. The macro
+ * calling convention can't directly deal with this, so the wrapper
+ * functions must do this.
+ *
+ * These PVOP_* macros are only defined within this header. This
+ * means that all uses must be wrapped in inline functions. This also
+ * makes sure the incoming and outgoing types are always correct.
+ */
+#ifdef CONFIG_X86_32
+#define PVOP_VCALL_ARGS \
+ unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx
+#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
+
+#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x))
+#define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x))
+#define PVOP_CALL_ARG3(x) "c" ((unsigned long)(x))
+
+#define PVOP_VCALL_CLOBBERS "=a" (__eax), "=d" (__edx), \
+ "=c" (__ecx)
+#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS
+
+#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), "=d" (__edx)
+#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
+
+#define EXTRA_CLOBBERS
+#define VEXTRA_CLOBBERS
+#else /* CONFIG_X86_64 */
+#define PVOP_VCALL_ARGS \
+ unsigned long __edi = __edi, __esi = __esi, \
+ __edx = __edx, __ecx = __ecx
+#define PVOP_CALL_ARGS PVOP_VCALL_ARGS, __eax
+
+#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
+#define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x))
+#define PVOP_CALL_ARG3(x) "d" ((unsigned long)(x))
+#define PVOP_CALL_ARG4(x) "c" ((unsigned long)(x))
+
+#define PVOP_VCALL_CLOBBERS "=D" (__edi), \
+ "=S" (__esi), "=d" (__edx), \
+ "=c" (__ecx)
+#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax)
+
+#define PVOP_VCALLEE_CLOBBERS "=a" (__eax)
+#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
+
+#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11"
+#define VEXTRA_CLOBBERS , "rax", "r8", "r9", "r10", "r11"
+#endif /* CONFIG_X86_32 */
+
+#ifdef CONFIG_PARAVIRT_DEBUG
+#define PVOP_TEST_NULL(op) BUG_ON(op == NULL)
+#else
+#define PVOP_TEST_NULL(op) ((void)op)
+#endif
+
+#define ____PVOP_CALL(rettype, op, clbr, call_clbr, extra_clbr, \
+ pre, post, ...) \
+ ({ \
+ rettype __ret; \
+ PVOP_CALL_ARGS; \
+ PVOP_TEST_NULL(op); \
+ /* This is 32-bit specific, but is okay in 64-bit */ \
+ /* since this condition will never hold */ \
+ if (sizeof(rettype) > sizeof(unsigned long)) { \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : call_clbr \
+ : paravirt_type(op), \
+ paravirt_clobber(clbr), \
+ ##__VA_ARGS__ \
+ : "memory", "cc" extra_clbr); \
+ __ret = (rettype)((((u64)__edx) << 32) | __eax); \
+ } else { \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : call_clbr \
+ : paravirt_type(op), \
+ paravirt_clobber(clbr), \
+ ##__VA_ARGS__ \
+ : "memory", "cc" extra_clbr); \
+ __ret = (rettype)__eax; \
+ } \
+ __ret; \
+ })
+
+#define __PVOP_CALL(rettype, op, pre, post, ...) \
+ ____PVOP_CALL(rettype, op, CLBR_ANY, PVOP_CALL_CLOBBERS, \
+ EXTRA_CLOBBERS, pre, post, ##__VA_ARGS__)
+
+#define __PVOP_CALLEESAVE(rettype, op, pre, post, ...) \
+ ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \
+ PVOP_CALLEE_CLOBBERS, , \
+ pre, post, ##__VA_ARGS__)
+
+
+#define ____PVOP_VCALL(op, clbr, call_clbr, extra_clbr, pre, post, ...) \
+ ({ \
+ PVOP_VCALL_ARGS; \
+ PVOP_TEST_NULL(op); \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : call_clbr \
+ : paravirt_type(op), \
+ paravirt_clobber(clbr), \
+ ##__VA_ARGS__ \
+ : "memory", "cc" extra_clbr); \
+ })
+
+#define __PVOP_VCALL(op, pre, post, ...) \
+ ____PVOP_VCALL(op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \
+ VEXTRA_CLOBBERS, \
+ pre, post, ##__VA_ARGS__)
+
+#define __PVOP_VCALLEESAVE(rettype, op, pre, post, ...) \
+ ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \
+ PVOP_VCALLEE_CLOBBERS, , \
+ pre, post, ##__VA_ARGS__)
+
+
+
+#define PVOP_CALL0(rettype, op) \
+ __PVOP_CALL(rettype, op, "", "")
+#define PVOP_VCALL0(op) \
+ __PVOP_VCALL(op, "", "")
+
+#define PVOP_CALLEE0(rettype, op) \
+ __PVOP_CALLEESAVE(rettype, op, "", "")
+#define PVOP_VCALLEE0(op) \
+ __PVOP_VCALLEESAVE(op, "", "")
+
+
+#define PVOP_CALL1(rettype, op, arg1) \
+ __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1))
+#define PVOP_VCALL1(op, arg1) \
+ __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1))
+
+#define PVOP_CALLEE1(rettype, op, arg1) \
+ __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1))
+#define PVOP_VCALLEE1(op, arg1) \
+ __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1))
+
+
+#define PVOP_CALL2(rettype, op, arg1, arg2) \
+ __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2))
+#define PVOP_VCALL2(op, arg1, arg2) \
+ __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2))
+
+#define PVOP_CALLEE2(rettype, op, arg1, arg2) \
+ __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2))
+#define PVOP_VCALLEE2(op, arg1, arg2) \
+ __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2))
+
+
+#define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \
+ __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3))
+#define PVOP_VCALL3(op, arg1, arg2, arg3) \
+ __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \
+ PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3))
+
+/* This is the only difference in x86_64. We can make it much simpler */
+#ifdef CONFIG_X86_32
+#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \
+ __PVOP_CALL(rettype, op, \
+ "push %[_arg4];", "lea 4(%%esp),%%esp;", \
+ PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
+ PVOP_CALL_ARG3(arg3), [_arg4] "mr" ((u32)(arg4)))
+#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \
+ __PVOP_VCALL(op, \
+ "push %[_arg4];", "lea 4(%%esp),%%esp;", \
+ "0" ((u32)(arg1)), "1" ((u32)(arg2)), \
+ "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+#else
+#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \
+ __PVOP_CALL(rettype, op, "", "", \
+ PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
+ PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
+#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \
+ __PVOP_VCALL(op, "", "", \
+ PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \
+ PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4))
+#endif
+
+/* Lazy mode for batching updates / context switch */
+enum paravirt_lazy_mode {
+ PARAVIRT_LAZY_NONE,
+ PARAVIRT_LAZY_MMU,
+ PARAVIRT_LAZY_CPU,
+};
+
+enum paravirt_lazy_mode paravirt_get_lazy_mode(void);
+void paravirt_start_context_switch(struct task_struct *prev);
+void paravirt_end_context_switch(struct task_struct *next);
+
+void paravirt_enter_lazy_mmu(void);
+void paravirt_leave_lazy_mmu(void);
+
+void _paravirt_nop(void);
+u32 _paravirt_ident_32(u32);
+u64 _paravirt_ident_64(u64);
+
+#define paravirt_nop ((void *)_paravirt_nop)
+
+/* These all sit in the .parainstructions section to tell us what to patch. */
+struct paravirt_patch_site {
+ u8 *instr; /* original instructions */
+ u8 instrtype; /* type of this instruction */
+ u8 len; /* length of original instruction */
+ u16 clobbers; /* what registers you may clobber */
+};
+
+extern struct paravirt_patch_site __parainstructions[],
+ __parainstructions_end[];
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_PARAVIRT_TYPES_H */
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 1ff685ca221c..f76a162c082c 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -48,7 +48,6 @@ extern unsigned int pcibios_assign_all_busses(void);
#else
#define pcibios_assign_all_busses() 0
#endif
-#define pcibios_scan_all_fns(a, b) 0
extern unsigned long pci_mem_start;
#define PCIBIOS_MIN_IO 0x1000
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index 103f1ddb0d85..a18c038a3079 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -156,15 +156,6 @@ do { \
/* We can use this directly for local CPU (faster). */
DECLARE_PER_CPU(unsigned long, this_cpu_off);
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-void *pcpu_lpage_remapped(void *kaddr);
-#else
-static inline void *pcpu_lpage_remapped(void *kaddr)
-{
- return NULL;
-}
-#endif
-
#endif /* !__ASSEMBLY__ */
#ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
index dd14c54ac718..0e8c2a0fd922 100644
--- a/arch/x86/include/asm/pgalloc.h
+++ b/arch/x86/include/asm/pgalloc.h
@@ -46,7 +46,13 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte)
__free_page(pte);
}
-extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
+extern void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
+
+static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
+ unsigned long address)
+{
+ ___pte_free_tlb(tlb, pte);
+}
static inline void pmd_populate_kernel(struct mm_struct *mm,
pmd_t *pmd, pte_t *pte)
@@ -78,7 +84,13 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
free_page((unsigned long)pmd);
}
-extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
+extern void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
+
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+ unsigned long adddress)
+{
+ ___pmd_free_tlb(tlb, pmd);
+}
#ifdef CONFIG_X86_PAE
extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
@@ -108,7 +120,14 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
free_page((unsigned long)pud);
}
-extern void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
+extern void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
+
+static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
+ unsigned long address)
+{
+ ___pud_free_tlb(tlb, pud);
+}
+
#endif /* PAGETABLE_LEVELS > 3 */
#endif /* PAGETABLE_LEVELS > 2 */
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 3cc06e3fceb8..9de8729c1c8f 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -134,6 +134,11 @@ static inline unsigned long pte_pfn(pte_t pte)
return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT;
}
+static inline unsigned long pmd_pfn(pmd_t pmd)
+{
+ return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
+}
+
#define pte_page(pte) pfn_to_page(pte_pfn(pte))
static inline int pmd_large(pmd_t pte)
@@ -351,7 +356,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
* this macro returns the index of the entry in the pmd page which would
* control the given virtual address
*/
-static inline unsigned pmd_index(unsigned long address)
+static inline unsigned long pmd_index(unsigned long address)
{
return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
}
@@ -371,7 +376,7 @@ static inline unsigned pmd_index(unsigned long address)
* this function returns the index of the entry in the pte page which would
* control the given virtual address
*/
-static inline unsigned pte_index(unsigned long address)
+static inline unsigned long pte_index(unsigned long address)
{
return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
}
@@ -422,11 +427,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address);
}
-static inline unsigned long pmd_pfn(pmd_t pmd)
-{
- return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
-}
-
static inline int pud_large(pud_t pud)
{
return (pud_val(pud) & (_PAGE_PSE | _PAGE_PRESENT)) ==
@@ -462,7 +462,7 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd)
#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
/* to find an entry in a page-table-directory. */
-static inline unsigned pud_index(unsigned long address)
+static inline unsigned long pud_index(unsigned long address)
{
return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
}
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index c7768269b1cf..74d925831c05 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -106,6 +106,8 @@ struct cpuinfo_x86 {
u16 booted_cores;
/* Physical processor id: */
u16 phys_proc_id;
+ /* Node id in case of multi-node processor: */
+ u16 cpu_node_id;
/* Core id: */
u16 cpu_core_id;
/* Index into per_cpu list: */
diff --git a/arch/x86/include/asm/scatterlist.h b/arch/x86/include/asm/scatterlist.h
index 263d397d2eef..75af592677ec 100644
--- a/arch/x86/include/asm/scatterlist.h
+++ b/arch/x86/include/asm/scatterlist.h
@@ -1,33 +1,8 @@
#ifndef _ASM_X86_SCATTERLIST_H
#define _ASM_X86_SCATTERLIST_H
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
- unsigned long sg_magic;
-#endif
- unsigned long page_link;
- unsigned int offset;
- unsigned int length;
- dma_addr_t dma_address;
- unsigned int dma_length;
-};
-
-#define ARCH_HAS_SG_CHAIN
#define ISA_DMA_THRESHOLD (0x00ffffff)
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg) ((sg)->dma_address)
-#ifdef CONFIG_X86_32
-# define sg_dma_len(sg) ((sg)->length)
-#else
-# define sg_dma_len(sg) ((sg)->dma_length)
-#endif
+#include <asm-generic/scatterlist.h>
#endif /* _ASM_X86_SCATTERLIST_H */
diff --git a/arch/x86/include/asm/shmbuf.h b/arch/x86/include/asm/shmbuf.h
index b51413b74971..83c05fc2de38 100644
--- a/arch/x86/include/asm/shmbuf.h
+++ b/arch/x86/include/asm/shmbuf.h
@@ -1,51 +1 @@
-#ifndef _ASM_X86_SHMBUF_H
-#define _ASM_X86_SHMBUF_H
-
-/*
- * The shmid64_ds structure for x86 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space on 32 bit is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- *
- * Pad space on 64 bit is left for:
- * - 2 miscellaneous 64-bit values
- */
-
-struct shmid64_ds {
- struct ipc64_perm shm_perm; /* operation perms */
- size_t shm_segsz; /* size of segment (bytes) */
- __kernel_time_t shm_atime; /* last attach time */
-#ifdef __i386__
- unsigned long __unused1;
-#endif
- __kernel_time_t shm_dtime; /* last detach time */
-#ifdef __i386__
- unsigned long __unused2;
-#endif
- __kernel_time_t shm_ctime; /* last change time */
-#ifdef __i386__
- unsigned long __unused3;
-#endif
- __kernel_pid_t shm_cpid; /* pid of creator */
- __kernel_pid_t shm_lpid; /* pid of last operator */
- unsigned long shm_nattch; /* no. of current attaches */
- unsigned long __unused4;
- unsigned long __unused5;
-};
-
-struct shminfo64 {
- unsigned long shmmax;
- unsigned long shmmin;
- unsigned long shmmni;
- unsigned long shmseg;
- unsigned long shmall;
- unsigned long __unused1;
- unsigned long __unused2;
- unsigned long __unused3;
- unsigned long __unused4;
-};
-
-#endif /* _ASM_X86_SHMBUF_H */
+#include <asm-generic/shmbuf.h>
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 6a84ed166aec..1e871e9abde2 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -22,6 +22,7 @@ extern int smp_num_siblings;
extern unsigned int num_processors;
DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map);
+DECLARE_PER_CPU(cpumask_var_t, cpu_node_map);
DECLARE_PER_CPU(cpumask_var_t, cpu_core_map);
DECLARE_PER_CPU(u16, cpu_llc_id);
DECLARE_PER_CPU(int, cpu_number);
@@ -31,6 +32,11 @@ static inline struct cpumask *cpu_sibling_mask(int cpu)
return per_cpu(cpu_sibling_map, cpu);
}
+static inline struct cpumask *cpu_node_mask(int cpu)
+{
+ return per_cpu(cpu_node_map, cpu);
+}
+
static inline struct cpumask *cpu_core_mask(int cpu)
{
return per_cpu(cpu_core_map, cpu);
@@ -121,7 +127,6 @@ static inline void arch_send_call_function_single_ipi(int cpu)
smp_ops.send_call_func_single_ipi(cpu);
}
-#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
smp_ops.send_call_func_ipi(mask);
diff --git a/arch/x86/include/asm/socket.h b/arch/x86/include/asm/socket.h
index ca8bf2cd0ba9..6b71384b9d8b 100644
--- a/arch/x86/include/asm/socket.h
+++ b/arch/x86/include/asm/socket.h
@@ -1,60 +1 @@
-#ifndef _ASM_X86_SOCKET_H
-#define _ASM_X86_SOCKET_H
-
-#include <asm/sockios.h>
-
-/* For setsockopt(2) */
-#define SOL_SOCKET 1
-
-#define SO_DEBUG 1
-#define SO_REUSEADDR 2
-#define SO_TYPE 3
-#define SO_ERROR 4
-#define SO_DONTROUTE 5
-#define SO_BROADCAST 6
-#define SO_SNDBUF 7
-#define SO_RCVBUF 8
-#define SO_SNDBUFFORCE 32
-#define SO_RCVBUFFORCE 33
-#define SO_KEEPALIVE 9
-#define SO_OOBINLINE 10
-#define SO_NO_CHECK 11
-#define SO_PRIORITY 12
-#define SO_LINGER 13
-#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
-#define SO_PASSCRED 16
-#define SO_PEERCRED 17
-#define SO_RCVLOWAT 18
-#define SO_SNDLOWAT 19
-#define SO_RCVTIMEO 20
-#define SO_SNDTIMEO 21
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION 22
-#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
-#define SO_SECURITY_ENCRYPTION_NETWORK 24
-
-#define SO_BINDTODEVICE 25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER 26
-#define SO_DETACH_FILTER 27
-
-#define SO_PEERNAME 28
-#define SO_TIMESTAMP 29
-#define SCM_TIMESTAMP SO_TIMESTAMP
-
-#define SO_ACCEPTCONN 30
-
-#define SO_PEERSEC 31
-#define SO_PASSSEC 34
-#define SO_TIMESTAMPNS 35
-#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
-
-#define SO_MARK 36
-
-#define SO_TIMESTAMPING 37
-#define SCM_TIMESTAMPING SO_TIMESTAMPING
-
-#endif /* _ASM_X86_SOCKET_H */
+#include <asm-generic/socket.h>
diff --git a/arch/x86/include/asm/sockios.h b/arch/x86/include/asm/sockios.h
index 49cc72b5d3c9..def6d4746ee7 100644
--- a/arch/x86/include/asm/sockios.h
+++ b/arch/x86/include/asm/sockios.h
@@ -1,13 +1 @@
-#ifndef _ASM_X86_SOCKIOS_H
-#define _ASM_X86_SOCKIOS_H
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 0x8901
-#define SIOCSPGRP 0x8902
-#define FIOGETOWN 0x8903
-#define SIOCGPGRP 0x8904
-#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
-#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
-
-#endif /* _ASM_X86_SOCKIOS_H */
+#include <asm-generic/sockios.h>
diff --git a/arch/x86/include/asm/termbits.h b/arch/x86/include/asm/termbits.h
index af1b70ea440f..3935b106de79 100644
--- a/arch/x86/include/asm/termbits.h
+++ b/arch/x86/include/asm/termbits.h
@@ -1,198 +1 @@
-#ifndef _ASM_X86_TERMBITS_H
-#define _ASM_X86_TERMBITS_H
-
-#include <linux/posix_types.h>
-
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-typedef unsigned int tcflag_t;
-
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
-};
-
-struct termios2 {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-struct ktermios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IUCLC 0001000
-#define IXON 0002000
-#define IXANY 0004000
-#define IXOFF 0010000
-#define IMAXBEL 0020000
-#define IUTF8 0040000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define OLCUC 0000002
-#define ONLCR 0000004
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-#define OFILL 0000100
-#define OFDEL 0000200
-#define NLDLY 0000400
-#define NL0 0000000
-#define NL1 0000400
-#define CRDLY 0003000
-#define CR0 0000000
-#define CR1 0001000
-#define CR2 0002000
-#define CR3 0003000
-#define TABDLY 0014000
-#define TAB0 0000000
-#define TAB1 0004000
-#define TAB2 0010000
-#define TAB3 0014000
-#define XTABS 0014000
-#define BSDLY 0020000
-#define BS0 0000000
-#define BS1 0020000
-#define VTDLY 0040000
-#define VT0 0000000
-#define VT1 0040000
-#define FFDLY 0100000
-#define FF0 0000000
-#define FF1 0100000
-
-/* c_cflag bit meaning */
-#define CBAUD 0010017
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE 0000060
-#define CS5 0000000
-#define CS6 0000020
-#define CS7 0000040
-#define CS8 0000060
-#define CSTOPB 0000100
-#define CREAD 0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL 0002000
-#define CLOCAL 0004000
-#define CBAUDEX 0010000
-#define BOTHER 0010000 /* non standard rate */
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
-#define B500000 0010005
-#define B576000 0010006
-#define B921600 0010007
-#define B1000000 0010010
-#define B1152000 0010011
-#define B1500000 0010012
-#define B2000000 0010013
-#define B2500000 0010014
-#define B3000000 0010015
-#define B3500000 0010016
-#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate */
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
-#define CRTSCTS 020000000000 /* flow control */
-
-#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
-#endif /* _ASM_X86_TERMBITS_H */
+#include <asm-generic/termbits.h>
diff --git a/arch/x86/include/asm/termios.h b/arch/x86/include/asm/termios.h
index c4ee8056baca..280d78a9d966 100644
--- a/arch/x86/include/asm/termios.h
+++ b/arch/x86/include/asm/termios.h
@@ -1,114 +1 @@
-#ifndef _ASM_X86_TERMIOS_H
-#define _ASM_X86_TERMIOS_H
-
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
-};
-
-/* modem lines */
-#define TIOCM_LE 0x001
-#define TIOCM_DTR 0x002
-#define TIOCM_RTS 0x004
-#define TIOCM_ST 0x008
-#define TIOCM_SR 0x010
-#define TIOCM_CTS 0x020
-#define TIOCM_CAR 0x040
-#define TIOCM_RNG 0x080
-#define TIOCM_DSR 0x100
-#define TIOCM_CD TIOCM_CAR
-#define TIOCM_RI TIOCM_RNG
-#define TIOCM_OUT1 0x2000
-#define TIOCM_OUT2 0x4000
-#define TIOCM_LOOP 0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
-
-#include <asm/uaccess.h>
-
-/* intr=^C quit=^\ erase=del kill=^U
- eof=^D vtime=\0 vmin=\1 sxtc=\0
- start=^Q stop=^S susp=^Z eol=\0
- reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
-*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-
-/*
- * Translate a "termio" structure into a "termios". Ugh.
- */
-#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
- unsigned short __tmp; \
- get_user(__tmp,&(termio)->x); \
- *(unsigned short *) &(termios)->x = __tmp; \
-}
-
-static inline int user_termio_to_kernel_termios(struct ktermios *termios,
- struct termio __user *termio)
-{
- SET_LOW_TERMIOS_BITS(termios, termio, c_iflag);
- SET_LOW_TERMIOS_BITS(termios, termio, c_oflag);
- SET_LOW_TERMIOS_BITS(termios, termio, c_cflag);
- SET_LOW_TERMIOS_BITS(termios, termio, c_lflag);
- get_user(termios->c_line, &termio->c_line);
- return copy_from_user(termios->c_cc, termio->c_cc, NCC);
-}
-
-/*
- * Translate a "termios" structure into a "termio". Ugh.
- */
-static inline int kernel_termios_to_user_termio(struct termio __user *termio,
- struct ktermios *termios)
-{
- put_user((termios)->c_iflag, &(termio)->c_iflag);
- put_user((termios)->c_oflag, &(termio)->c_oflag);
- put_user((termios)->c_cflag, &(termio)->c_cflag);
- put_user((termios)->c_lflag, &(termio)->c_lflag);
- put_user((termios)->c_line, &(termio)->c_line);
- return copy_to_user((termio)->c_cc, (termios)->c_cc, NCC);
-}
-
-static inline int user_termios_to_kernel_termios(struct ktermios *k,
- struct termios2 __user *u)
-{
- return copy_from_user(k, u, sizeof(struct termios2));
-}
-
-static inline int kernel_termios_to_user_termios(struct termios2 __user *u,
- struct ktermios *k)
-{
- return copy_to_user(u, k, sizeof(struct termios2));
-}
-
-static inline int user_termios_to_kernel_termios_1(struct ktermios *k,
- struct termios __user *u)
-{
- return copy_from_user(k, u, sizeof(struct termios));
-}
-
-static inline int kernel_termios_to_user_termios_1(struct termios __user *u,
- struct ktermios *k)
-{
- return copy_to_user(u, k, sizeof(struct termios));
-}
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_X86_TERMIOS_H */
+#include <asm-generic/termios.h>
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index fad7d40b75f8..f26432ac1c57 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -162,7 +162,12 @@ struct thread_info {
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
#define alloc_thread_info(tsk) \
- ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
+({ \
+ struct thread_info *ti = (struct thread_info *) \
+ __get_free_pages(THREAD_FLAGS, THREAD_ORDER); \
+ kmemleak_alloc(ti, THREAD_SIZE, 1, THREAD_FLAGS); \
+ ti; \
+})
#ifdef CONFIG_X86_32
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 066ef590d7e0..9eddb6988116 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -190,6 +190,8 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu);
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
+#define topology_cpu_node_id(cpu) (cpu_data(cpu).cpu_node_id)
+#define topology_cpu_node_cpumask(cpu) (per_cpu(cpu_node_map, cpu))
/* indicates that pointers to the topology cpumask_t maps are valid */
#define arch_provides_topology_pointers yes
diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h
index 09b97745772f..df1da20f4534 100644
--- a/arch/x86/include/asm/types.h
+++ b/arch/x86/include/asm/types.h
@@ -1,19 +1,11 @@
#ifndef _ASM_X86_TYPES_H
#define _ASM_X86_TYPES_H
-#include <asm-generic/int-ll64.h>
+#define dma_addr_t dma_addr_t
-#ifndef __ASSEMBLY__
-
-typedef unsigned short umode_t;
+#include <asm-generic/types.h>
-#endif /* __ASSEMBLY__ */
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
#ifdef __KERNEL__
-
#ifndef __ASSEMBLY__
typedef u64 dma64_addr_t;
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 20e6a795e160..d2c6c930b491 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -212,9 +212,9 @@ extern int __get_user_bad(void);
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
#else
#define __put_user_asm_u64(x, ptr, retval, errret) \
- __put_user_asm(x, ptr, retval, "q", "", "Zr", errret)
+ __put_user_asm(x, ptr, retval, "q", "", "er", errret)
#define __put_user_asm_ex_u64(x, addr) \
- __put_user_asm_ex(x, addr, "q", "", "Zr")
+ __put_user_asm_ex(x, addr, "q", "", "er")
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
#endif
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 8cc687326eb8..db24b215fc50 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -88,11 +88,11 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
ret, "l", "k", "ir", 4);
return ret;
case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
- ret, "q", "", "ir", 8);
+ ret, "q", "", "er", 8);
return ret;
case 10:
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
- ret, "q", "", "ir", 10);
+ ret, "q", "", "er", 10);
if (unlikely(ret))
return ret;
asm("":::"memory");
@@ -101,12 +101,12 @@ int __copy_to_user(void __user *dst, const void *src, unsigned size)
return ret;
case 16:
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
- ret, "q", "", "ir", 16);
+ ret, "q", "", "er", 16);
if (unlikely(ret))
return ret;
asm("":::"memory");
__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
- ret, "q", "", "ir", 8);
+ ret, "q", "", "er", 8);
return ret;
default:
return copy_user_generic((__force void *)dst, src, size);
@@ -157,7 +157,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
ret, "q", "", "=r", 8);
if (likely(!ret))
__put_user_asm(tmp, (u64 __user *)dst,
- ret, "q", "", "ir", 8);
+ ret, "q", "", "er", 8);
return ret;
}
default:
diff --git a/arch/x86/include/asm/ucontext.h b/arch/x86/include/asm/ucontext.h
index 87324cf439d9..b7c29c8017f2 100644
--- a/arch/x86/include/asm/ucontext.h
+++ b/arch/x86/include/asm/ucontext.h
@@ -7,12 +7,6 @@
* sigcontext struct (uc_mcontext).
*/
-struct ucontext {
- unsigned long uc_flags;
- struct ucontext *uc_link;
- stack_t uc_stack;
- struct sigcontext uc_mcontext;
- sigset_t uc_sigmask; /* mask last for extensibility */
-};
+#include <asm-generic/ucontext.h>
#endif /* _ASM_X86_UCONTEXT_H */
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 11be5ad2e0e9..272514c2d456 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -55,6 +55,7 @@
#define SECONDARY_EXEC_ENABLE_EPT 0x00000002
#define SECONDARY_EXEC_ENABLE_VPID 0x00000020
#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040
+#define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080
#define PIN_BASED_EXT_INTR_MASK 0x00000001
@@ -351,9 +352,16 @@ enum vmcs_field {
#define VMX_EPT_EXTENT_INDIVIDUAL_ADDR 0
#define VMX_EPT_EXTENT_CONTEXT 1
#define VMX_EPT_EXTENT_GLOBAL 2
+
+#define VMX_EPT_EXECUTE_ONLY_BIT (1ull)
+#define VMX_EPT_PAGE_WALK_4_BIT (1ull << 6)
+#define VMX_EPTP_UC_BIT (1ull << 8)
+#define VMX_EPTP_WB_BIT (1ull << 14)
+#define VMX_EPT_2MB_PAGE_BIT (1ull << 16)
#define VMX_EPT_EXTENT_INDIVIDUAL_BIT (1ull << 24)
#define VMX_EPT_EXTENT_CONTEXT_BIT (1ull << 25)
#define VMX_EPT_EXTENT_GLOBAL_BIT (1ull << 26)
+
#define VMX_EPT_DEFAULT_GAW 3
#define VMX_EPT_MAX_GAW 0x4
#define VMX_EPT_MT_EPTE_SHIFT 3
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index 8c44c232efcb..827b5207523e 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -63,6 +63,12 @@ struct cstate_entry {
};
static struct cstate_entry *cpu_cstate_entry; /* per CPU ptr */
+/* Used for the cross-CPU calls */
+struct acpi_processor_cx_cross_cpu {
+ struct acpi_processor_cx *cx;
+ long retval;
+};
+
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
#define MWAIT_SUBSTATE_MASK (0xf)
@@ -77,10 +83,10 @@ static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
#define NATIVE_CSTATE_BEYOND_HALT (2)
-static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
+static void acpi_processor_ffh_cstate_probe_cpu(void *_cxcc)
{
- struct acpi_processor_cx *cx = _cx;
- long retval;
+ struct acpi_processor_cx_cross_cpu *cxcc = _cxcc;
+ struct acpi_processor_cx *cx = cxcc->cx;
unsigned int eax, ebx, ecx, edx;
unsigned int edx_part;
unsigned int cstate_type; /* C-state type and not ACPI C-state type */
@@ -94,16 +100,16 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
- retval = 0;
+ cxcc->retval = 0;
if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
- retval = -1;
+ cxcc->retval = -1;
goto out;
}
/* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
!(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
- retval = -1;
+ cxcc->retval = -1;
goto out;
}
@@ -117,7 +123,7 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
ACPI_CX_DESC_LEN, "ACPI FFH INTEL MWAIT 0x%x",
cx->address);
out:
- return retval;
+ return;
}
int acpi_processor_ffh_cstate_probe(unsigned int cpu,
@@ -125,6 +131,7 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu,
{
struct cstate_entry *percpu_entry;
struct cpuinfo_x86 *c = &cpu_data(cpu);
+ struct acpi_processor_cx_cross_cpu cxcc = { .cx = cx, };
long retval;
if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF)
@@ -137,13 +144,18 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu,
percpu_entry->states[cx->index].eax = 0;
percpu_entry->states[cx->index].ecx = 0;
- /* Make sure we are running on right CPU */
+ /* Run acpi_processor_ffh_cstate_probe_cpu() on the target CPU */
- retval = work_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx);
+ retval = smp_call_function_single(cpu,
+ acpi_processor_ffh_cstate_probe_cpu, &cxcc, 1);
if (retval == 0) {
- /* Use the hint in CST */
- percpu_entry->states[cx->index].eax = cx->address;
- percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
+ retval = cxcc.retval;
+ if (retval == 0) {
+ /* Use the hint in CST */
+ percpu_entry->states[cx->index].eax = cx->address;
+ percpu_entry->states[cx->index].ecx =
+ MWAIT_ECX_INTERRUPT_BREAK;
+ }
}
return retval;
}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 4fcd30198faf..d6db676d7cfc 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -215,17 +215,14 @@ static struct irq_cfg *get_one_free_irq_cfg(int node)
cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
if (cfg) {
- if (!alloc_cpumask_var_node(&cfg->domain, GFP_ATOMIC, node)) {
+ if (!zalloc_cpumask_var_node(&cfg->domain, GFP_ATOMIC, node)) {
kfree(cfg);
cfg = NULL;
- } else if (!alloc_cpumask_var_node(&cfg->old_domain,
+ } else if (!zalloc_cpumask_var_node(&cfg->old_domain,
GFP_ATOMIC, node)) {
free_cpumask_var(cfg->domain);
kfree(cfg);
cfg = NULL;
- } else {
- cpumask_clear(cfg->domain);
- cpumask_clear(cfg->old_domain);
}
}
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 28e5f5956042..e06fa7c1edc7 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -183,7 +183,7 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
* approved Athlon
*/
WARN_ONCE(1, "WARNING: This combination of AMD"
- "processors is not suitable for SMP.\n");
+ " processors is not suitable for SMP.\n");
if (!test_taint(TAINT_UNSAFE_SMP))
add_taint(TAINT_UNSAFE_SMP);
@@ -251,6 +251,56 @@ static int __cpuinit nearby_node(int apicid)
#endif
/*
+ * Fixup core topology information for AMD multi-node processors.
+ * Assumption 1: Number of cores in each internal node is the same.
+ * Assumption 2: Mixed systems with both single-node and dual-node
+ * processors are not supported.
+ */
+static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
+{
+ u32 t, cpn;
+ u8 n;
+
+ /* fixup topology information only once for a core */
+ if (cpu_has(c, X86_FEATURE_AMD_DCM))
+ return;
+
+ /* check for multi-node processor on boot cpu */
+ t = read_pci_config(0, 24, 3, 0xe8);
+ if (!(t & (1 << 29)))
+ return;
+
+ set_cpu_cap(c, X86_FEATURE_AMD_DCM);
+
+ /* cores per node: each internal node has half the number of cores */
+ cpn = c->x86_max_cores >> 1;
+
+ /* even-numbered NB_id of this dual-node processor */
+ n = c->phys_proc_id << 1;
+
+ /*
+ * determine internal node id and assign cores fifty-fifty to
+ * each node of the dual-node processor
+ */
+ t = read_pci_config(0, 24 + n, 3, 0xe8);
+ n = (t>>30) & 0x3;
+ if (n == 0) {
+ if (c->cpu_core_id < cpn)
+ c->cpu_node_id = 0;
+ else
+ c->cpu_node_id = 1;
+ } else {
+ if (c->cpu_core_id < cpn)
+ c->cpu_node_id = 1;
+ else
+ c->cpu_node_id = 0;
+ }
+
+ /* fixup core id to be in range from 0 to cpn */
+ c->cpu_core_id = c->cpu_core_id % cpn;
+}
+
+/*
* On a AMD dual core setup the lower bits of the APIC id distingush the cores.
* Assumes number of cores is a power of two.
*/
@@ -267,6 +317,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
c->phys_proc_id = c->initial_apicid >> bits;
/* use socket ID also for last level cache */
per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
+ /* fixup topology information on multi-node processors */
+ if ((c->x86 == 0x10) && (c->x86_model == 9))
+ amd_fixup_dcm(c);
#endif
}
@@ -277,7 +330,11 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
int node;
unsigned apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid;
- node = c->phys_proc_id;
+ if (cpu_has(c, X86_FEATURE_AMD_DCM))
+ node = (c->phys_proc_id << 1) + c->cpu_node_id;
+ else
+ node = c->phys_proc_id;
+
if (apicid_to_node[apicid] != NUMA_NO_NODE)
node = apicid_to_node[apicid];
if (!node_online(node)) {
@@ -356,7 +413,7 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
/* check CPU config space for extended APIC ID */
- if (c->x86 >= 0xf) {
+ if (cpu_has_apic && c->x86 >= 0xf) {
unsigned int val;
val = read_pci_config(0, 24, 0, 0x68);
if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18)))
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f1961c07af9a..60db9b51625a 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -478,6 +478,8 @@ out:
if ((c->x86_max_cores * smp_num_siblings) > 1) {
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
c->phys_proc_id);
+ printk(KERN_INFO "CPU: Processor Node ID: %d\n",
+ c->cpu_node_id);
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
c->cpu_core_id);
}
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index 6b2a52dd0403..dca325c03999 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -30,8 +30,8 @@
#include <asm/apic.h>
#include <asm/desc.h>
-static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]);
-static DEFINE_PER_CPU(struct cpu_private *, priv_arr[MAX_CPU_FILES]);
+static DEFINE_PER_CPU(struct cpu_cpuX_base [CPU_REG_ALL_BIT], cpu_arr);
+static DEFINE_PER_CPU(struct cpu_private * [MAX_CPU_FILES], priv_arr);
static DEFINE_PER_CPU(int, cpu_priv_count);
static DEFINE_MUTEX(cpu_debug_lock);
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 789efe217e1a..3b54a1eab306 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -241,7 +241,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
case 0:
if (!l1->val)
return;
- assoc = l1->assoc;
+ assoc = assocs[l1->assoc];
line_size = l1->line_size;
lines_per_tag = l1->lines_per_tag;
size_in_kb = l1->size_in_kb;
@@ -249,7 +249,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
case 2:
if (!l2.val)
return;
- assoc = l2.assoc;
+ assoc = assocs[l2.assoc];
line_size = l2.line_size;
lines_per_tag = l2.lines_per_tag;
/* cpu_data has errata corrections for K7 applied */
@@ -258,10 +258,14 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
case 3:
if (!l3.val)
return;
- assoc = l3.assoc;
+ assoc = assocs[l3.assoc];
line_size = l3.line_size;
lines_per_tag = l3.lines_per_tag;
size_in_kb = l3.size_encoded * 512;
+ if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
+ size_in_kb = size_in_kb >> 1;
+ assoc = assoc >> 1;
+ }
break;
default:
return;
@@ -278,10 +282,10 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
- if (assoc == 0xf)
+ if (assoc == 0xffff)
eax->split.is_fully_associative = 1;
ebx->split.coherency_line_size = line_size - 1;
- ebx->split.ways_of_associativity = assocs[assoc] - 1;
+ ebx->split.ways_of_associativity = assoc - 1;
ebx->split.physical_line_partition = lines_per_tag - 1;
ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
(ebx->split.ways_of_associativity + 1) - 1;
@@ -598,7 +602,11 @@ static void __cpuinit get_cpu_leaves(void *_retval)
cache_remove_shared_cpu_map(cpu, i);
break;
}
- cache_shared_cpu_map_setup(cpu, j);
+ if (boot_cpu_has(X86_FEATURE_AMD_DCM))
+ cpumask_copy(to_cpumask(this_leaf->shared_cpu_map),
+ topology_cpu_node_cpumask(cpu));
+ else
+ cache_shared_cpu_map_setup(cpu, j);
}
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 484c1e5f658e..b8c6e0d953a1 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -183,6 +183,11 @@ void mce_log(struct mce *mce)
set_bit(0, &mce_need_notify);
}
+void __attribute__((weak)) decode_mce(struct mce *m)
+{
+ return;
+}
+
static void print_mce(struct mce *m)
{
printk(KERN_EMERG
@@ -205,6 +210,8 @@ static void print_mce(struct mce *m)
printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
m->cpuvendor, m->cpuid, m->time, m->socketid,
m->apicid);
+
+ decode_mce(m);
}
static void print_mce_head(void)
@@ -215,7 +222,10 @@ static void print_mce_head(void)
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");
+#if (!defined(CONFIG_EDAC) || !defined(CONFIG_CPU_SUP_AMD))
+ "Run through mcelog --ascii to decode and contact your hardware vendor\n"
+#endif
+ );
}
#define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -242,7 +252,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
/*
* Make sure only one CPU runs in machine check panic
*/
- if (atomic_add_return(1, &mce_paniced) > 1)
+ if (atomic_inc_return(&mce_paniced) > 1)
wait_for_panic();
barrier();
@@ -705,7 +715,7 @@ static int mce_start(int *no_way_out)
* global_nwo should be updated before mce_callin
*/
smp_wmb();
- order = atomic_add_return(1, &mce_callin);
+ order = atomic_inc_return(&mce_callin);
/*
* Wait for everyone.
@@ -1091,7 +1101,7 @@ void mce_log_therm_throt_event(__u64 status)
*/
static int check_interval = 5 * 60; /* 5 minutes */
-static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
+static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */
static DEFINE_PER_CPU(struct timer_list, mce_timer);
static void mcheck_timer(unsigned long data)
@@ -1110,7 +1120,7 @@ static void mcheck_timer(unsigned long data)
* Alert userspace if needed. If we logged an MCE, reduce the
* polling interval, otherwise increase the polling interval.
*/
- n = &__get_cpu_var(next_interval);
+ n = &__get_cpu_var(mce_next_interval);
if (mce_notify_irq())
*n = max(*n/2, HZ/100);
else
@@ -1311,7 +1321,7 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
static void mce_init_timer(void)
{
struct timer_list *t = &__get_cpu_var(mce_timer);
- int *n = &__get_cpu_var(next_interval);
+ int *n = &__get_cpu_var(mce_next_interval);
if (mce_ignore_ce)
return;
@@ -1692,17 +1702,15 @@ static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
const char *buf, size_t siz)
{
char *p;
- int len;
strncpy(mce_helper, buf, sizeof(mce_helper));
mce_helper[sizeof(mce_helper)-1] = 0;
- len = strlen(mce_helper);
p = strchr(mce_helper, '\n');
- if (*p)
+ if (p)
*p = 0;
- return len;
+ return strlen(mce_helper) + !!p;
}
static ssize_t set_ignore_ce(struct sys_device *s,
@@ -1914,7 +1922,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
t->expires = round_jiffies(jiffies +
- __get_cpu_var(next_interval));
+ __get_cpu_var(mce_next_interval));
add_timer_on(t, cpu);
smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
break;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index ddae21620bda..bff14e3d5574 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -69,7 +69,7 @@ struct threshold_bank {
struct threshold_block *blocks;
cpumask_var_t cpus;
};
-static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
+static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
#ifdef CONFIG_SMP
static unsigned char shared_bank[NR_BANKS] = {
@@ -494,7 +494,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
#ifdef CONFIG_SMP
if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) { /* symlink */
- i = cpumask_first(cpu_core_mask(cpu));
+ i = cpumask_first(cpu_node_mask(cpu));
/* first core not up yet */
if (cpu_data(i).cpu_core_id)
@@ -514,7 +514,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
if (err)
goto out;
- cpumask_copy(b->cpus, cpu_core_mask(cpu));
+ cpumask_copy(b->cpus, cpu_node_mask(cpu));
per_cpu(threshold_banks, cpu)[bank] = b;
goto out;
@@ -539,7 +539,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
#ifndef CONFIG_SMP
cpumask_setall(b->cpus);
#else
- cpumask_copy(b->cpus, cpu_core_mask(cpu));
+ cpumask_copy(b->cpus, cpu_node_mask(cpu));
#endif
per_cpu(threshold_banks, cpu)[bank] = b;
diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c
index ee2331b0e58f..33af14110dfd 100644
--- a/arch/x86/kernel/cpu/mtrr/amd.c
+++ b/arch/x86/kernel/cpu/mtrr/amd.c
@@ -7,15 +7,15 @@
static void
amd_get_mtrr(unsigned int reg, unsigned long *base,
- unsigned long *size, mtrr_type * type)
+ unsigned long *size, mtrr_type *type)
{
unsigned long low, high;
rdmsr(MSR_K6_UWCCR, low, high);
- /* Upper dword is region 1, lower is region 0 */
+ /* Upper dword is region 1, lower is region 0 */
if (reg == 1)
low = high;
- /* The base masks off on the right alignment */
+ /* The base masks off on the right alignment */
*base = (low & 0xFFFE0000) >> PAGE_SHIFT;
*type = 0;
if (low & 1)
@@ -27,74 +27,81 @@ amd_get_mtrr(unsigned int reg, unsigned long *base,
return;
}
/*
- * This needs a little explaining. The size is stored as an
- * inverted mask of bits of 128K granularity 15 bits long offset
- * 2 bits
+ * This needs a little explaining. The size is stored as an
+ * inverted mask of bits of 128K granularity 15 bits long offset
+ * 2 bits.
*
- * So to get a size we do invert the mask and add 1 to the lowest
- * mask bit (4 as its 2 bits in). This gives us a size we then shift
- * to turn into 128K blocks
+ * So to get a size we do invert the mask and add 1 to the lowest
+ * mask bit (4 as its 2 bits in). This gives us a size we then shift
+ * to turn into 128K blocks.
*
- * eg 111 1111 1111 1100 is 512K
+ * eg 111 1111 1111 1100 is 512K
*
- * invert 000 0000 0000 0011
- * +1 000 0000 0000 0100
- * *128K ...
+ * invert 000 0000 0000 0011
+ * +1 000 0000 0000 0100
+ * *128K ...
*/
low = (~low) & 0x1FFFC;
*size = (low + 4) << (15 - PAGE_SHIFT);
- return;
}
-static void amd_set_mtrr(unsigned int reg, unsigned long base,
- unsigned long size, mtrr_type type)
-/* [SUMMARY] Set variable MTRR register on the local CPU.
- <reg> The register to set.
- <base> The base address of the region.
- <size> The size of the region. If this is 0 the region is disabled.
- <type> The type of the region.
- [RETURNS] Nothing.
-*/
+/**
+ * amd_set_mtrr - Set variable MTRR register on the local CPU.
+ *
+ * @reg The register to set.
+ * @base The base address of the region.
+ * @size The size of the region. If this is 0 the region is disabled.
+ * @type The type of the region.
+ *
+ * Returns nothing.
+ */
+static void
+amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
{
u32 regs[2];
/*
- * Low is MTRR0 , High MTRR 1
+ * Low is MTRR0, High MTRR 1
*/
rdmsr(MSR_K6_UWCCR, regs[0], regs[1]);
/*
- * Blank to disable
+ * Blank to disable
*/
- if (size == 0)
+ if (size == 0) {
regs[reg] = 0;
- else
- /* Set the register to the base, the type (off by one) and an
- inverted bitmask of the size The size is the only odd
- bit. We are fed say 512K We invert this and we get 111 1111
- 1111 1011 but if you subtract one and invert you get the
- desired 111 1111 1111 1100 mask
-
- But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */
+ } else {
+ /*
+ * Set the register to the base, the type (off by one) and an
+ * inverted bitmask of the size The size is the only odd
+ * bit. We are fed say 512K We invert this and we get 111 1111
+ * 1111 1011 but if you subtract one and invert you get the
+ * desired 111 1111 1111 1100 mask
+ *
+ * But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!
+ */
regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC)
| (base << PAGE_SHIFT) | (type + 1);
+ }
/*
- * The writeback rule is quite specific. See the manual. Its
- * disable local interrupts, write back the cache, set the mtrr
+ * The writeback rule is quite specific. See the manual. Its
+ * disable local interrupts, write back the cache, set the mtrr
*/
wbinvd();
wrmsr(MSR_K6_UWCCR, regs[0], regs[1]);
}
-static int amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
+static int
+amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
{
- /* Apply the K6 block alignment and size rules
- In order
- o Uncached or gathering only
- o 128K or bigger block
- o Power of 2 block
- o base suitably aligned to the power
- */
+ /*
+ * Apply the K6 block alignment and size rules
+ * In order
+ * o Uncached or gathering only
+ * o 128K or bigger block
+ * o Power of 2 block
+ * o base suitably aligned to the power
+ */
if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT))
|| (size & ~(size - 1)) - size || (base & (size - 1)))
return -EINVAL;
@@ -115,5 +122,3 @@ int __init amd_init_mtrr(void)
set_mtrr_ops(&amd_mtrr_ops);
return 0;
}
-
-//arch_initcall(amd_mtrr_init);
diff --git a/arch/x86/kernel/cpu/mtrr/centaur.c b/arch/x86/kernel/cpu/mtrr/centaur.c
index cb9aa3a7a7ab..de89f14eff3a 100644
--- a/arch/x86/kernel/cpu/mtrr/centaur.c
+++ b/arch/x86/kernel/cpu/mtrr/centaur.c
@@ -1,7 +1,9 @@
#include <linux/init.h>
#include <linux/mm.h>
+
#include <asm/mtrr.h>
#include <asm/msr.h>
+
#include "mtrr.h"
static struct {
@@ -12,25 +14,25 @@ static struct {
static u8 centaur_mcr_reserved;
static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */
-/*
- * Report boot time MCR setups
+/**
+ * centaur_get_free_region - Get a free MTRR.
+ *
+ * @base: The starting (base) address of the region.
+ * @size: The size (in bytes) of the region.
+ *
+ * Returns: the index of the region on success, else -1 on error.
*/
-
static int
centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg)
-/* [SUMMARY] Get a free MTRR.
- <base> The starting (base) address of the region.
- <size> The size (in bytes) of the region.
- [RETURNS] The index of the region on success, else -1 on error.
-*/
{
- int i, max;
- mtrr_type ltype;
unsigned long lbase, lsize;
+ mtrr_type ltype;
+ int i, max;
max = num_var_ranges;
if (replace_reg >= 0 && replace_reg < max)
return replace_reg;
+
for (i = 0; i < max; ++i) {
if (centaur_mcr_reserved & (1 << i))
continue;
@@ -38,11 +40,14 @@ centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg)
if (lsize == 0)
return i;
}
+
return -ENOSPC;
}
-void
-mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
+/*
+ * Report boot time MCR setups
+ */
+void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
{
centaur_mcr[mcr].low = lo;
centaur_mcr[mcr].high = hi;
@@ -54,33 +59,35 @@ centaur_get_mcr(unsigned int reg, unsigned long *base,
{
*base = centaur_mcr[reg].high >> PAGE_SHIFT;
*size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
- *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */
+ *type = MTRR_TYPE_WRCOMB; /* write-combining */
+
if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))
*type = MTRR_TYPE_UNCACHABLE;
if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)
*type = MTRR_TYPE_WRBACK;
if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)
*type = MTRR_TYPE_WRBACK;
-
}
-static void centaur_set_mcr(unsigned int reg, unsigned long base,
- unsigned long size, mtrr_type type)
+static void
+centaur_set_mcr(unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type)
{
unsigned long low, high;
if (size == 0) {
- /* Disable */
+ /* Disable */
high = low = 0;
} else {
high = base << PAGE_SHIFT;
- if (centaur_mcr_type == 0)
- low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
- else {
+ if (centaur_mcr_type == 0) {
+ /* Only support write-combining... */
+ low = -size << PAGE_SHIFT | 0x1f;
+ } else {
if (type == MTRR_TYPE_UNCACHABLE)
- low = -size << PAGE_SHIFT | 0x02; /* NC */
+ low = -size << PAGE_SHIFT | 0x02; /* NC */
else
- low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */
+ low = -size << PAGE_SHIFT | 0x09; /* WWO, WC */
}
}
centaur_mcr[reg].high = high;
@@ -88,118 +95,16 @@ static void centaur_set_mcr(unsigned int reg, unsigned long base,
wrmsr(MSR_IDT_MCR0 + reg, low, high);
}
-#if 0
-/*
- * Initialise the later (saner) Winchip MCR variant. In this version
- * the BIOS can pass us the registers it has used (but not their values)
- * and the control register is read/write
- */
-
-static void __init
-centaur_mcr1_init(void)
-{
- unsigned i;
- u32 lo, hi;
-
- /* Unfortunately, MCR's are read-only, so there is no way to
- * find out what the bios might have done.
- */
-
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- if (((lo >> 17) & 7) == 1) { /* Type 1 Winchip2 MCR */
- lo &= ~0x1C0; /* clear key */
- lo |= 0x040; /* set key to 1 */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */
- }
-
- centaur_mcr_type = 1;
-
- /*
- * Clear any unconfigured MCR's.
- */
-
- for (i = 0; i < 8; ++i) {
- if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) {
- if (!(lo & (1 << (9 + i))))
- wrmsr(MSR_IDT_MCR0 + i, 0, 0);
- else
- /*
- * If the BIOS set up an MCR we cannot see it
- * but we don't wish to obliterate it
- */
- centaur_mcr_reserved |= (1 << i);
- }
- }
- /*
- * Throw the main write-combining switch...
- * However if OOSTORE is enabled then people have already done far
- * cleverer things and we should behave.
- */
-
- lo |= 15; /* Write combine enables */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-/*
- * Initialise the original winchip with read only MCR registers
- * no used bitmask for the BIOS to pass on and write only control
- */
-
-static void __init
-centaur_mcr0_init(void)
-{
- unsigned i;
-
- /* Unfortunately, MCR's are read-only, so there is no way to
- * find out what the bios might have done.
- */
-
- /* Clear any unconfigured MCR's.
- * This way we are sure that the centaur_mcr array contains the actual
- * values. The disadvantage is that any BIOS tweaks are thus undone.
- *
- */
- for (i = 0; i < 8; ++i) {
- if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0)
- wrmsr(MSR_IDT_MCR0 + i, 0, 0);
- }
-
- wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */
-}
-
-/*
- * Initialise Winchip series MCR registers
- */
-
-static void __init
-centaur_mcr_init(void)
-{
- struct set_mtrr_context ctxt;
-
- set_mtrr_prepare_save(&ctxt);
- set_mtrr_cache_disable(&ctxt);
-
- if (boot_cpu_data.x86_model == 4)
- centaur_mcr0_init();
- else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9)
- centaur_mcr1_init();
-
- set_mtrr_done(&ctxt);
-}
-#endif
-
-static int centaur_validate_add_page(unsigned long base,
- unsigned long size, unsigned int type)
+static int
+centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
{
/*
- * FIXME: Winchip2 supports uncached
+ * FIXME: Winchip2 supports uncached
*/
- if (type != MTRR_TYPE_WRCOMB &&
+ if (type != MTRR_TYPE_WRCOMB &&
(centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {
- printk(KERN_WARNING
- "mtrr: only write-combining%s supported\n",
- centaur_mcr_type ? " and uncacheable are"
- : " is");
+ pr_warning("mtrr: only write-combining%s supported\n",
+ centaur_mcr_type ? " and uncacheable are" : " is");
return -EINVAL;
}
return 0;
@@ -207,7 +112,6 @@ static int centaur_validate_add_page(unsigned long base,
static struct mtrr_ops centaur_mtrr_ops = {
.vendor = X86_VENDOR_CENTAUR,
-// .init = centaur_mcr_init,
.set = centaur_set_mcr,
.get = centaur_get_mcr,
.get_free_region = centaur_get_free_region,
@@ -220,5 +124,3 @@ int __init centaur_init_mtrr(void)
set_mtrr_ops(&centaur_mtrr_ops);
return 0;
}
-
-//arch_initcall(centaur_init_mtrr);
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index 1d584a18a50d..b8aba811b60e 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -1,51 +1,52 @@
-/* MTRR (Memory Type Range Register) cleanup
-
- Copyright (C) 2009 Yinghai Lu
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
+/*
+ * MTRR (Memory Type Range Register) cleanup
+ *
+ * Copyright (C) 2009 Yinghai Lu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/cpu.h>
-#include <linux/mutex.h>
#include <linux/sort.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/kvm_para.h>
+#include <asm/processor.h>
#include <asm/e820.h>
#include <asm/mtrr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
#include <asm/msr.h>
-#include <asm/kvm_para.h>
+
#include "mtrr.h"
-/* should be related to MTRR_VAR_RANGES nums */
+/* Should be related to MTRR_VAR_RANGES nums */
#define RANGE_NUM 256
struct res_range {
- unsigned long start;
- unsigned long end;
+ unsigned long start;
+ unsigned long end;
};
static int __init
-add_range(struct res_range *range, int nr_range, unsigned long start,
- unsigned long end)
+add_range(struct res_range *range, int nr_range,
+ unsigned long start, unsigned long end)
{
- /* out of slots */
+ /* Out of slots: */
if (nr_range >= RANGE_NUM)
return nr_range;
@@ -58,12 +59,12 @@ add_range(struct res_range *range, int nr_range, unsigned long start,
}
static int __init
-add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
- unsigned long end)
+add_range_with_merge(struct res_range *range, int nr_range,
+ unsigned long start, unsigned long end)
{
int i;
- /* try to merge it with old one */
+ /* Try to merge it with old one: */
for (i = 0; i < nr_range; i++) {
unsigned long final_start, final_end;
unsigned long common_start, common_end;
@@ -84,7 +85,7 @@ add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
return nr_range;
}
- /* need to add that */
+ /* Need to add it: */
return add_range(range, nr_range, start, end);
}
@@ -117,7 +118,7 @@ subtract_range(struct res_range *range, unsigned long start, unsigned long end)
}
if (start > range[j].start && end < range[j].end) {
- /* find the new spare */
+ /* Find the new spare: */
for (i = 0; i < RANGE_NUM; i++) {
if (range[i].end == 0)
break;
@@ -147,13 +148,19 @@ static int __init cmp_range(const void *x1, const void *x2)
}
struct var_mtrr_range_state {
- unsigned long base_pfn;
- unsigned long size_pfn;
- mtrr_type type;
+ unsigned long base_pfn;
+ unsigned long size_pfn;
+ mtrr_type type;
};
static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
+
static int __initdata debug_print;
+#define Dprintk(x...) do { if (debug_print) printk(KERN_DEBUG x); } while (0)
+
+
+#define BIOS_BUG_MSG KERN_WARNING \
+ "WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n"
static int __init
x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
@@ -180,7 +187,7 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
range[i].start, range[i].end + 1);
}
- /* take out UC ranges */
+ /* Take out UC ranges: */
for (i = 0; i < num_var_ranges; i++) {
type = range_state[i].type;
if (type != MTRR_TYPE_UNCACHABLE &&
@@ -244,10 +251,9 @@ static int __initdata nr_range;
static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
{
- unsigned long sum;
+ unsigned long sum = 0;
int i;
- sum = 0;
for (i = 0; i < nr_range; i++)
sum += range[i].end + 1 - range[i].start;
@@ -288,7 +294,7 @@ struct var_mtrr_state {
static void __init
set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
- unsigned char type, unsigned int address_bits)
+ unsigned char type, unsigned int address_bits)
{
u32 base_lo, base_hi, mask_lo, mask_hi;
u64 base, mask;
@@ -301,7 +307,7 @@ set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
mask = (1ULL << address_bits) - 1;
mask &= ~((((u64)sizek) << 10) - 1);
- base = ((u64)basek) << 10;
+ base = ((u64)basek) << 10;
base |= type;
mask |= 0x800;
@@ -317,15 +323,14 @@ set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
static void __init
save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
- unsigned char type)
+ unsigned char type)
{
range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
range_state[reg].type = type;
}
-static void __init
-set_var_mtrr_all(unsigned int address_bits)
+static void __init set_var_mtrr_all(unsigned int address_bits)
{
unsigned long basek, sizek;
unsigned char type;
@@ -342,11 +347,11 @@ set_var_mtrr_all(unsigned int address_bits)
static unsigned long to_size_factor(unsigned long sizek, char *factorp)
{
- char factor;
unsigned long base = sizek;
+ char factor;
if (base & ((1<<10) - 1)) {
- /* not MB alignment */
+ /* Not MB-aligned: */
factor = 'K';
} else if (base & ((1<<20) - 1)) {
factor = 'M';
@@ -372,11 +377,12 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk,
unsigned long max_align, align;
unsigned long sizek;
- /* Compute the maximum size I can make a range */
+ /* Compute the maximum size with which we can make a range: */
if (range_startk)
max_align = ffs(range_startk) - 1;
else
max_align = 32;
+
align = fls(range_sizek) - 1;
if (align > max_align)
align = max_align;
@@ -386,11 +392,10 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk,
char start_factor = 'K', size_factor = 'K';
unsigned long start_base, size_base;
- start_base = to_size_factor(range_startk,
- &start_factor),
- size_base = to_size_factor(sizek, &size_factor),
+ start_base = to_size_factor(range_startk, &start_factor);
+ size_base = to_size_factor(sizek, &size_factor);
- printk(KERN_DEBUG "Setting variable MTRR %d, "
+ Dprintk("Setting variable MTRR %d, "
"base: %ld%cB, range: %ld%cB, type %s\n",
reg, start_base, start_factor,
size_base, size_factor,
@@ -425,10 +430,11 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
chunk_sizek = state->chunk_sizek;
gran_sizek = state->gran_sizek;
- /* align with gran size, prevent small block used up MTRRs */
+ /* Align with gran size, prevent small block used up MTRRs: */
range_basek = ALIGN(state->range_startk, gran_sizek);
if ((range_basek > basek) && basek)
return second_sizek;
+
state->range_sizek -= (range_basek - state->range_startk);
range_sizek = ALIGN(state->range_sizek, gran_sizek);
@@ -439,22 +445,21 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
}
state->range_sizek = range_sizek;
- /* try to append some small hole */
+ /* Try to append some small hole: */
range0_basek = state->range_startk;
range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
- /* no increase */
+ /* No increase: */
if (range0_sizek == state->range_sizek) {
- if (debug_print)
- printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
- range0_basek<<10,
- (range0_basek + state->range_sizek)<<10);
+ Dprintk("rangeX: %016lx - %016lx\n",
+ range0_basek<<10,
+ (range0_basek + state->range_sizek)<<10);
state->reg = range_to_mtrr(state->reg, range0_basek,
state->range_sizek, MTRR_TYPE_WRBACK);
return 0;
}
- /* only cut back, when it is not the last */
+ /* Only cut back when it is not the last: */
if (sizek) {
while (range0_basek + range0_sizek > (basek + sizek)) {
if (range0_sizek >= chunk_sizek)
@@ -470,16 +475,16 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
second_try:
range_basek = range0_basek + range0_sizek;
- /* one hole in the middle */
+ /* One hole in the middle: */
if (range_basek > basek && range_basek <= (basek + sizek))
second_sizek = range_basek - basek;
if (range0_sizek > state->range_sizek) {
- /* one hole in middle or at end */
+ /* One hole in middle or at the end: */
hole_sizek = range0_sizek - state->range_sizek - second_sizek;
- /* hole size should be less than half of range0 size */
+ /* Hole size should be less than half of range0 size: */
if (hole_sizek >= (range0_sizek >> 1) &&
range0_sizek >= chunk_sizek) {
range0_sizek -= chunk_sizek;
@@ -491,32 +496,30 @@ second_try:
}
if (range0_sizek) {
- if (debug_print)
- printk(KERN_DEBUG "range0: %016lx - %016lx\n",
- range0_basek<<10,
- (range0_basek + range0_sizek)<<10);
+ Dprintk("range0: %016lx - %016lx\n",
+ range0_basek<<10,
+ (range0_basek + range0_sizek)<<10);
state->reg = range_to_mtrr(state->reg, range0_basek,
range0_sizek, MTRR_TYPE_WRBACK);
}
if (range0_sizek < state->range_sizek) {
- /* need to handle left over */
+ /* Need to handle left over range: */
range_sizek = state->range_sizek - range0_sizek;
- if (debug_print)
- printk(KERN_DEBUG "range: %016lx - %016lx\n",
- range_basek<<10,
- (range_basek + range_sizek)<<10);
+ Dprintk("range: %016lx - %016lx\n",
+ range_basek<<10,
+ (range_basek + range_sizek)<<10);
+
state->reg = range_to_mtrr(state->reg, range_basek,
range_sizek, MTRR_TYPE_WRBACK);
}
if (hole_sizek) {
hole_basek = range_basek - hole_sizek - second_sizek;
- if (debug_print)
- printk(KERN_DEBUG "hole: %016lx - %016lx\n",
- hole_basek<<10,
- (hole_basek + hole_sizek)<<10);
+ Dprintk("hole: %016lx - %016lx\n",
+ hole_basek<<10,
+ (hole_basek + hole_sizek)<<10);
state->reg = range_to_mtrr(state->reg, hole_basek,
hole_sizek, MTRR_TYPE_UNCACHABLE);
}
@@ -537,23 +540,23 @@ set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
basek = base_pfn << (PAGE_SHIFT - 10);
sizek = size_pfn << (PAGE_SHIFT - 10);
- /* See if I can merge with the last range */
+ /* See if I can merge with the last range: */
if ((basek <= 1024) ||
(state->range_startk + state->range_sizek == basek)) {
unsigned long endk = basek + sizek;
state->range_sizek = endk - state->range_startk;
return;
}
- /* Write the range mtrrs */
+ /* Write the range mtrrs: */
if (state->range_sizek != 0)
second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
- /* Allocate an msr */
+ /* Allocate an msr: */
state->range_startk = basek + second_sizek;
state->range_sizek = sizek - second_sizek;
}
-/* mininum size of mtrr block that can take hole */
+/* Mininum size of mtrr block that can take hole: */
static u64 mtrr_chunk_size __initdata = (256ULL<<20);
static int __init parse_mtrr_chunk_size_opt(char *p)
@@ -565,7 +568,7 @@ static int __init parse_mtrr_chunk_size_opt(char *p)
}
early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
-/* granity of mtrr of block */
+/* Granularity of mtrr of block: */
static u64 mtrr_gran_size __initdata;
static int __init parse_mtrr_gran_size_opt(char *p)
@@ -577,7 +580,7 @@ static int __init parse_mtrr_gran_size_opt(char *p)
}
early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
-static int nr_mtrr_spare_reg __initdata =
+static unsigned long nr_mtrr_spare_reg __initdata =
CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
static int __init parse_mtrr_spare_reg(char *arg)
@@ -586,7 +589,6 @@ static int __init parse_mtrr_spare_reg(char *arg)
nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
return 0;
}
-
early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
static int __init
@@ -594,8 +596,8 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range,
u64 chunk_size, u64 gran_size)
{
struct var_mtrr_state var_state;
- int i;
int num_reg;
+ int i;
var_state.range_startk = 0;
var_state.range_sizek = 0;
@@ -605,17 +607,18 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range,
memset(range_state, 0, sizeof(range_state));
- /* Write the range etc */
- for (i = 0; i < nr_range; i++)
+ /* Write the range: */
+ for (i = 0; i < nr_range; i++) {
set_var_mtrr_range(&var_state, range[i].start,
range[i].end - range[i].start + 1);
+ }
- /* Write the last range */
+ /* Write the last range: */
if (var_state.range_sizek != 0)
range_to_mtrr_with_hole(&var_state, 0, 0);
num_reg = var_state.reg;
- /* Clear out the extra MTRR's */
+ /* Clear out the extra MTRR's: */
while (var_state.reg < num_var_ranges) {
save_var_mtrr(var_state.reg, 0, 0, 0);
var_state.reg++;
@@ -625,11 +628,11 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range,
}
struct mtrr_cleanup_result {
- unsigned long gran_sizek;
- unsigned long chunk_sizek;
- unsigned long lose_cover_sizek;
- unsigned int num_reg;
- int bad;
+ unsigned long gran_sizek;
+ unsigned long chunk_sizek;
+ unsigned long lose_cover_sizek;
+ unsigned int num_reg;
+ int bad;
};
/*
@@ -645,10 +648,10 @@ static unsigned long __initdata min_loss_pfn[RANGE_NUM];
static void __init print_out_mtrr_range_state(void)
{
- int i;
char start_factor = 'K', size_factor = 'K';
unsigned long start_base, size_base;
mtrr_type type;
+ int i;
for (i = 0; i < num_var_ranges; i++) {
@@ -676,10 +679,10 @@ static int __init mtrr_need_cleanup(void)
int i;
mtrr_type type;
unsigned long size;
- /* extra one for all 0 */
+ /* Extra one for all 0: */
int num[MTRR_NUM_TYPES + 1];
- /* check entries number */
+ /* Check entries number: */
memset(num, 0, sizeof(num));
for (i = 0; i < num_var_ranges; i++) {
type = range_state[i].type;
@@ -693,88 +696,86 @@ static int __init mtrr_need_cleanup(void)
num[type]++;
}
- /* check if we got UC entries */
+ /* Check if we got UC entries: */
if (!num[MTRR_TYPE_UNCACHABLE])
return 0;
- /* check if we only had WB and UC */
+ /* Check if we only had WB and UC */
if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
- num_var_ranges - num[MTRR_NUM_TYPES])
+ num_var_ranges - num[MTRR_NUM_TYPES])
return 0;
return 1;
}
static unsigned long __initdata range_sums;
-static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
- unsigned long extra_remove_base,
- unsigned long extra_remove_size,
- int i)
+
+static void __init
+mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
+ unsigned long x_remove_base,
+ unsigned long x_remove_size, int i)
{
- int num_reg;
static struct res_range range_new[RANGE_NUM];
- static int nr_range_new;
unsigned long range_sums_new;
+ static int nr_range_new;
+ int num_reg;
- /* convert ranges to var ranges state */
- num_reg = x86_setup_var_mtrrs(range, nr_range,
- chunk_size, gran_size);
+ /* Convert ranges to var ranges state: */
+ num_reg = x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
- /* we got new setting in range_state, check it */
+ /* We got new setting in range_state, check it: */
memset(range_new, 0, sizeof(range_new));
nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
- extra_remove_base, extra_remove_size);
+ x_remove_base, x_remove_size);
range_sums_new = sum_ranges(range_new, nr_range_new);
result[i].chunk_sizek = chunk_size >> 10;
result[i].gran_sizek = gran_size >> 10;
result[i].num_reg = num_reg;
+
if (range_sums < range_sums_new) {
- result[i].lose_cover_sizek =
- (range_sums_new - range_sums) << PSHIFT;
+ result[i].lose_cover_sizek = (range_sums_new - range_sums) << PSHIFT;
result[i].bad = 1;
- } else
- result[i].lose_cover_sizek =
- (range_sums - range_sums_new) << PSHIFT;
+ } else {
+ result[i].lose_cover_sizek = (range_sums - range_sums_new) << PSHIFT;
+ }
- /* double check it */
+ /* Double check it: */
if (!result[i].bad && !result[i].lose_cover_sizek) {
- if (nr_range_new != nr_range ||
- memcmp(range, range_new, sizeof(range)))
- result[i].bad = 1;
+ if (nr_range_new != nr_range || memcmp(range, range_new, sizeof(range)))
+ result[i].bad = 1;
}
- if (!result[i].bad && (range_sums - range_sums_new <
- min_loss_pfn[num_reg])) {
- min_loss_pfn[num_reg] =
- range_sums - range_sums_new;
- }
+ if (!result[i].bad && (range_sums - range_sums_new < min_loss_pfn[num_reg]))
+ min_loss_pfn[num_reg] = range_sums - range_sums_new;
}
static void __init mtrr_print_out_one_result(int i)
{
- char gran_factor, chunk_factor, lose_factor;
unsigned long gran_base, chunk_base, lose_base;
+ char gran_factor, chunk_factor, lose_factor;
gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
- printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
- result[i].bad ? "*BAD*" : " ",
- gran_base, gran_factor, chunk_base, chunk_factor);
- printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n",
- result[i].num_reg, result[i].bad ? "-" : "",
- lose_base, lose_factor);
+
+ pr_info("%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+ result[i].bad ? "*BAD*" : " ",
+ gran_base, gran_factor, chunk_base, chunk_factor);
+ pr_cont("num_reg: %d \tlose cover RAM: %s%ld%c\n",
+ result[i].num_reg, result[i].bad ? "-" : "",
+ lose_base, lose_factor);
}
static int __init mtrr_search_optimal_index(void)
{
- int i;
int num_reg_good;
int index_good;
+ int i;
if (nr_mtrr_spare_reg >= num_var_ranges)
nr_mtrr_spare_reg = num_var_ranges - 1;
+
num_reg_good = -1;
for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
if (!min_loss_pfn[i])
@@ -796,24 +797,24 @@ static int __init mtrr_search_optimal_index(void)
return index_good;
}
-
int __init mtrr_cleanup(unsigned address_bits)
{
- unsigned long extra_remove_base, extra_remove_size;
+ unsigned long x_remove_base, x_remove_size;
unsigned long base, size, def, dummy;
- mtrr_type type;
u64 chunk_size, gran_size;
+ mtrr_type type;
int index_good;
int i;
if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
return 0;
+
rdmsr(MSR_MTRRdefType, def, dummy);
def &= 0xff;
if (def != MTRR_TYPE_UNCACHABLE)
return 0;
- /* get it and store it aside */
+ /* Get it and store it aside: */
memset(range_state, 0, sizeof(range_state));
for (i = 0; i < num_var_ranges; i++) {
mtrr_if->get(i, &base, &size, &type);
@@ -822,29 +823,28 @@ int __init mtrr_cleanup(unsigned address_bits)
range_state[i].type = type;
}
- /* check if we need handle it and can handle it */
+ /* Check if we need handle it and can handle it: */
if (!mtrr_need_cleanup())
return 0;
- /* print original var MTRRs at first, for debugging: */
+ /* Print original var MTRRs at first, for debugging: */
printk(KERN_DEBUG "original variable MTRRs\n");
print_out_mtrr_range_state();
memset(range, 0, sizeof(range));
- extra_remove_size = 0;
- extra_remove_base = 1 << (32 - PAGE_SHIFT);
+ x_remove_size = 0;
+ x_remove_base = 1 << (32 - PAGE_SHIFT);
if (mtrr_tom2)
- extra_remove_size =
- (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
- nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
- extra_remove_size);
+ x_remove_size = (mtrr_tom2 >> PAGE_SHIFT) - x_remove_base;
+
+ nr_range = x86_get_mtrr_mem_range(range, 0, x_remove_base, x_remove_size);
/*
- * [0, 1M) should always be coverred by var mtrr with WB
- * and fixed mtrrs should take effective before var mtrr for it
+ * [0, 1M) should always be covered by var mtrr with WB
+ * and fixed mtrrs should take effect before var mtrr for it:
*/
nr_range = add_range_with_merge(range, nr_range, 0,
(1ULL<<(20 - PAGE_SHIFT)) - 1);
- /* sort the ranges */
+ /* Sort the ranges: */
sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
range_sums = sum_ranges(range, nr_range);
@@ -854,7 +854,7 @@ int __init mtrr_cleanup(unsigned address_bits)
if (mtrr_chunk_size && mtrr_gran_size) {
i = 0;
mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
- extra_remove_base, extra_remove_size, i);
+ x_remove_base, x_remove_size, i);
mtrr_print_out_one_result(i);
@@ -880,7 +880,7 @@ int __init mtrr_cleanup(unsigned address_bits)
continue;
mtrr_calc_range_state(chunk_size, gran_size,
- extra_remove_base, extra_remove_size, i);
+ x_remove_base, x_remove_size, i);
if (debug_print) {
mtrr_print_out_one_result(i);
printk(KERN_INFO "\n");
@@ -890,7 +890,7 @@ int __init mtrr_cleanup(unsigned address_bits)
}
}
- /* try to find the optimal index */
+ /* Try to find the optimal index: */
index_good = mtrr_search_optimal_index();
if (index_good != -1) {
@@ -898,7 +898,7 @@ int __init mtrr_cleanup(unsigned address_bits)
i = index_good;
mtrr_print_out_one_result(i);
- /* convert ranges to var ranges state */
+ /* Convert ranges to var ranges state: */
chunk_size = result[i].chunk_sizek;
chunk_size <<= 10;
gran_size = result[i].gran_sizek;
@@ -941,8 +941,8 @@ early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
* Note this won't check if the MTRRs < 4GB where the magic bit doesn't
* apply to are wrong, but so far we don't know of any such case in the wild.
*/
-#define Tom2Enabled (1U << 21)
-#define Tom2ForceMemTypeWB (1U << 22)
+#define Tom2Enabled (1U << 21)
+#define Tom2ForceMemTypeWB (1U << 22)
int __init amd_special_default_mtrr(void)
{
@@ -952,7 +952,7 @@ int __init amd_special_default_mtrr(void)
return 0;
if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
return 0;
- /* In case some hypervisor doesn't pass SYSCFG through */
+ /* In case some hypervisor doesn't pass SYSCFG through: */
if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
return 0;
/*
@@ -965,19 +965,21 @@ int __init amd_special_default_mtrr(void)
return 0;
}
-static u64 __init real_trim_memory(unsigned long start_pfn,
- unsigned long limit_pfn)
+static u64 __init
+real_trim_memory(unsigned long start_pfn, unsigned long limit_pfn)
{
u64 trim_start, trim_size;
+
trim_start = start_pfn;
trim_start <<= PAGE_SHIFT;
+
trim_size = limit_pfn;
trim_size <<= PAGE_SHIFT;
trim_size -= trim_start;
- return e820_update_range(trim_start, trim_size, E820_RAM,
- E820_RESERVED);
+ return e820_update_range(trim_start, trim_size, E820_RAM, E820_RESERVED);
}
+
/**
* mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
* @end_pfn: ending page frame number
@@ -985,7 +987,7 @@ static u64 __init real_trim_memory(unsigned long start_pfn,
* Some buggy BIOSes don't setup the MTRRs properly for systems with certain
* memory configurations. This routine checks that the highest MTRR matches
* the end of memory, to make sure the MTRRs having a write back type cover
- * all of the memory the kernel is intending to use. If not, it'll trim any
+ * all of the memory the kernel is intending to use. If not, it'll trim any
* memory off the end by adjusting end_pfn, removing it from the kernel's
* allocation pools, warning the user with an obnoxious message.
*/
@@ -994,21 +996,22 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
unsigned long i, base, size, highest_pfn = 0, def, dummy;
mtrr_type type;
u64 total_trim_size;
-
/* extra one for all 0 */
int num[MTRR_NUM_TYPES + 1];
+
/*
* Make sure we only trim uncachable memory on machines that
* support the Intel MTRR architecture:
*/
if (!is_cpu(INTEL) || disable_mtrr_trim)
return 0;
+
rdmsr(MSR_MTRRdefType, def, dummy);
def &= 0xff;
if (def != MTRR_TYPE_UNCACHABLE)
return 0;
- /* get it and store it aside */
+ /* Get it and store it aside: */
memset(range_state, 0, sizeof(range_state));
for (i = 0; i < num_var_ranges; i++) {
mtrr_if->get(i, &base, &size, &type);
@@ -1017,7 +1020,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
range_state[i].type = type;
}
- /* Find highest cached pfn */
+ /* Find highest cached pfn: */
for (i = 0; i < num_var_ranges; i++) {
type = range_state[i].type;
if (type != MTRR_TYPE_WRBACK)
@@ -1028,13 +1031,13 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
highest_pfn = base + size;
}
- /* kvm/qemu doesn't have mtrr set right, don't trim them all */
+ /* kvm/qemu doesn't have mtrr set right, don't trim them all: */
if (!highest_pfn) {
printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
return 0;
}
- /* check entries number */
+ /* Check entries number: */
memset(num, 0, sizeof(num));
for (i = 0; i < num_var_ranges; i++) {
type = range_state[i].type;
@@ -1046,11 +1049,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
num[type]++;
}
- /* no entry for WB? */
+ /* No entry for WB? */
if (!num[MTRR_TYPE_WRBACK])
return 0;
- /* check if we only had WB and UC */
+ /* Check if we only had WB and UC: */
if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
num_var_ranges - num[MTRR_NUM_TYPES])
return 0;
@@ -1066,31 +1069,31 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
}
nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
+ /* Check the head: */
total_trim_size = 0;
- /* check the head */
if (range[0].start)
total_trim_size += real_trim_memory(0, range[0].start);
- /* check the holes */
+
+ /* Check the holes: */
for (i = 0; i < nr_range - 1; i++) {
if (range[i].end + 1 < range[i+1].start)
total_trim_size += real_trim_memory(range[i].end + 1,
range[i+1].start);
}
- /* check the top */
+
+ /* Check the top: */
i = nr_range - 1;
if (range[i].end + 1 < end_pfn)
total_trim_size += real_trim_memory(range[i].end + 1,
end_pfn);
if (total_trim_size) {
- printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
- " all of memory, losing %lluMB of RAM.\n",
- total_trim_size >> 20);
+ pr_warning("WARNING: BIOS bug: CPU MTRRs don't cover all of memory, losing %lluMB of RAM.\n", total_trim_size >> 20);
if (!changed_by_mtrr_cleanup)
WARN_ON(1);
- printk(KERN_INFO "update e820 for mtrr\n");
+ pr_info("update e820 for mtrr\n");
update_e820();
return 1;
@@ -1098,4 +1101,3 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
return 0;
}
-
diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c
index ff14c320040c..228d982ce09c 100644
--- a/arch/x86/kernel/cpu/mtrr/cyrix.c
+++ b/arch/x86/kernel/cpu/mtrr/cyrix.c
@@ -1,38 +1,40 @@
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/mm.h>
-#include <asm/mtrr.h>
-#include <asm/msr.h>
-#include <asm/io.h>
+
#include <asm/processor-cyrix.h>
#include <asm/processor-flags.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+
#include "mtrr.h"
static void
cyrix_get_arr(unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type * type)
{
- unsigned long flags;
unsigned char arr, ccr3, rcr, shift;
+ unsigned long flags;
arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
- /* Save flags and disable interrupts */
local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
- ((unsigned char *) base)[3] = getCx86(arr);
- ((unsigned char *) base)[2] = getCx86(arr + 1);
- ((unsigned char *) base)[1] = getCx86(arr + 2);
+ ((unsigned char *)base)[3] = getCx86(arr);
+ ((unsigned char *)base)[2] = getCx86(arr + 1);
+ ((unsigned char *)base)[1] = getCx86(arr + 2);
rcr = getCx86(CX86_RCR_BASE + reg);
- setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
+ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
- /* Enable interrupts if it was enabled previously */
local_irq_restore(flags);
+
shift = ((unsigned char *) base)[1] & 0x0f;
*base >>= PAGE_SHIFT;
- /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+ /*
+ * Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
* Note: shift==0xf means 4G, this is unsupported.
*/
if (shift)
@@ -76,17 +78,20 @@ cyrix_get_arr(unsigned int reg, unsigned long *base,
}
}
+/*
+ * cyrix_get_free_region - get a free ARR.
+ *
+ * @base: the starting (base) address of the region.
+ * @size: the size (in bytes) of the region.
+ *
+ * Returns: the index of the region on success, else -1 on error.
+*/
static int
cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
-/* [SUMMARY] Get a free ARR.
- <base> The starting (base) address of the region.
- <size> The size (in bytes) of the region.
- [RETURNS] The index of the region on success, else -1 on error.
-*/
{
- int i;
- mtrr_type ltype;
unsigned long lbase, lsize;
+ mtrr_type ltype;
+ int i;
switch (replace_reg) {
case 7:
@@ -107,14 +112,17 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
cyrix_get_arr(7, &lbase, &lsize, &ltype);
if (lsize == 0)
return 7;
- /* Else try ARR0-ARR6 first */
+ /* Else try ARR0-ARR6 first */
} else {
for (i = 0; i < 7; i++) {
cyrix_get_arr(i, &lbase, &lsize, &ltype);
if (lsize == 0)
return i;
}
- /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+ /*
+ * ARR0-ARR6 isn't free
+ * try ARR7 but its size must be at least 256K
+ */
cyrix_get_arr(i, &lbase, &lsize, &ltype);
if ((lsize == 0) && (size >= 0x40))
return i;
@@ -122,21 +130,22 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
return -ENOSPC;
}
-static u32 cr4 = 0;
-static u32 ccr3;
+static u32 cr4, ccr3;
static void prepare_set(void)
{
u32 cr0;
/* Save value of CR4 and clear Page Global Enable (bit 7) */
- if ( cpu_has_pge ) {
+ if (cpu_has_pge) {
cr4 = read_cr4();
write_cr4(cr4 & ~X86_CR4_PGE);
}
- /* Disable and flush caches. Note that wbinvd flushes the TLBs as
- a side-effect */
+ /*
+ * Disable and flush caches.
+ * Note that wbinvd flushes the TLBs as a side-effect
+ */
cr0 = read_cr0() | X86_CR0_CD;
wbinvd();
write_cr0(cr0);
@@ -147,22 +156,21 @@ static void prepare_set(void)
/* Cyrix ARRs - everything else was excluded at the top */
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
-
}
static void post_set(void)
{
- /* Flush caches and TLBs */
+ /* Flush caches and TLBs */
wbinvd();
/* Cyrix ARRs - everything else was excluded at the top */
setCx86(CX86_CCR3, ccr3);
-
- /* Enable caches */
+
+ /* Enable caches */
write_cr0(read_cr0() & 0xbfffffff);
- /* Restore value of CR4 */
- if ( cpu_has_pge )
+ /* Restore value of CR4 */
+ if (cpu_has_pge)
write_cr4(cr4);
}
@@ -178,7 +186,8 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base,
size >>= 6;
size &= 0x7fff; /* make sure arr_size <= 14 */
- for (arr_size = 0; size; arr_size++, size >>= 1) ;
+ for (arr_size = 0; size; arr_size++, size >>= 1)
+ ;
if (reg < 7) {
switch (type) {
@@ -215,18 +224,18 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base,
prepare_set();
base <<= PAGE_SHIFT;
- setCx86(arr, ((unsigned char *) &base)[3]);
- setCx86(arr + 1, ((unsigned char *) &base)[2]);
- setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size);
+ setCx86(arr + 0, ((unsigned char *)&base)[3]);
+ setCx86(arr + 1, ((unsigned char *)&base)[2]);
+ setCx86(arr + 2, (((unsigned char *)&base)[1]) | arr_size);
setCx86(CX86_RCR_BASE + reg, arr_type);
post_set();
}
typedef struct {
- unsigned long base;
- unsigned long size;
- mtrr_type type;
+ unsigned long base;
+ unsigned long size;
+ mtrr_type type;
} arr_state_t;
static arr_state_t arr_state[8] = {
@@ -247,16 +256,17 @@ static void cyrix_set_all(void)
setCx86(CX86_CCR0 + i, ccr_state[i]);
for (; i < 7; i++)
setCx86(CX86_CCR4 + i, ccr_state[i]);
- for (i = 0; i < 8; i++)
- cyrix_set_arr(i, arr_state[i].base,
+
+ for (i = 0; i < 8; i++) {
+ cyrix_set_arr(i, arr_state[i].base,
arr_state[i].size, arr_state[i].type);
+ }
post_set();
}
static struct mtrr_ops cyrix_mtrr_ops = {
.vendor = X86_VENDOR_CYRIX,
-// .init = cyrix_arr_init,
.set_all = cyrix_set_all,
.set = cyrix_set_arr,
.get = cyrix_get_arr,
@@ -270,5 +280,3 @@ int __init cyrix_init_mtrr(void)
set_mtrr_ops(&cyrix_mtrr_ops);
return 0;
}
-
-//arch_initcall(cyrix_init_mtrr);
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 0543f69f0b27..55da0c5f68dd 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -1,28 +1,34 @@
-/* This only handles 32bit MTRR on 32bit hosts. This is strictly wrong
- because MTRRs can span upto 40 bits (36bits on most modern x86) */
+/*
+ * This only handles 32bit MTRR on 32bit hosts. This is strictly wrong
+ * because MTRRs can span upto 40 bits (36bits on most modern x86)
+ */
+#define DEBUG
+
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/mm.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#include <asm/mtrr.h>
-#include <asm/msr.h>
-#include <asm/system.h>
-#include <asm/cpufeature.h>
+
#include <asm/processor-flags.h>
+#include <asm/cpufeature.h>
#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/mtrr.h>
+#include <asm/msr.h>
#include <asm/pat.h>
+
#include "mtrr.h"
struct fixed_range_block {
- int base_msr; /* start address of an MTRR block */
- int ranges; /* number of MTRRs in this block */
+ int base_msr; /* start address of an MTRR block */
+ int ranges; /* number of MTRRs in this block */
};
static struct fixed_range_block fixed_range_blocks[] = {
- { MSR_MTRRfix64K_00000, 1 }, /* one 64k MTRR */
- { MSR_MTRRfix16K_80000, 2 }, /* two 16k MTRRs */
- { MSR_MTRRfix4K_C0000, 8 }, /* eight 4k MTRRs */
+ { MSR_MTRRfix64K_00000, 1 }, /* one 64k MTRR */
+ { MSR_MTRRfix16K_80000, 2 }, /* two 16k MTRRs */
+ { MSR_MTRRfix4K_C0000, 8 }, /* eight 4k MTRRs */
{}
};
@@ -30,10 +36,10 @@ static unsigned long smp_changes_mask;
static int mtrr_state_set;
u64 mtrr_tom2;
-struct mtrr_state_type mtrr_state = {};
+struct mtrr_state_type mtrr_state;
EXPORT_SYMBOL_GPL(mtrr_state);
-/**
+/*
* BIOS is expected to clear MtrrFixDramModEn bit, see for example
* "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
* Opteron Processors" (26094 Rev. 3.30 February 2006), section
@@ -104,9 +110,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
* Look of multiple ranges matching this address and pick type
* as per MTRR precedence
*/
- if (!(mtrr_state.enabled & 2)) {
+ if (!(mtrr_state.enabled & 2))
return mtrr_state.def_type;
- }
prev_match = 0xFF;
for (i = 0; i < num_var_ranges; ++i) {
@@ -125,9 +130,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
if (start_state != end_state)
return 0xFE;
- if ((start & mask) != (base & mask)) {
+ if ((start & mask) != (base & mask))
continue;
- }
curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
if (prev_match == 0xFF) {
@@ -148,9 +152,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
curr_match = MTRR_TYPE_WRTHROUGH;
}
- if (prev_match != curr_match) {
+ if (prev_match != curr_match)
return MTRR_TYPE_UNCACHABLE;
- }
}
if (mtrr_tom2) {
@@ -164,7 +167,7 @@ u8 mtrr_type_lookup(u64 start, u64 end)
return mtrr_state.def_type;
}
-/* Get the MSR pair relating to a var range */
+/* Get the MSR pair relating to a var range */
static void
get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
{
@@ -172,7 +175,7 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
}
-/* fill the MSR pair relating to a var range */
+/* Fill the MSR pair relating to a var range */
void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi)
{
@@ -186,10 +189,9 @@ void fill_mtrr_var_range(unsigned int index,
vr[index].mask_hi = mask_hi;
}
-static void
-get_fixed_ranges(mtrr_type * frs)
+static void get_fixed_ranges(mtrr_type *frs)
{
- unsigned int *p = (unsigned int *) frs;
+ unsigned int *p = (unsigned int *)frs;
int i;
k8_check_syscfg_dram_mod_en();
@@ -217,22 +219,22 @@ static void __init print_fixed_last(void)
if (!last_fixed_end)
return;
- printk(KERN_DEBUG " %05X-%05X %s\n", last_fixed_start,
- last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type));
+ pr_debug(" %05X-%05X %s\n", last_fixed_start,
+ last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type));
last_fixed_end = 0;
}
static void __init update_fixed_last(unsigned base, unsigned end,
- mtrr_type type)
+ mtrr_type type)
{
last_fixed_start = base;
last_fixed_end = end;
last_fixed_type = type;
}
-static void __init print_fixed(unsigned base, unsigned step,
- const mtrr_type *types)
+static void __init
+print_fixed(unsigned base, unsigned step, const mtrr_type *types)
{
unsigned i;
@@ -259,54 +261,55 @@ static void __init print_mtrr_state(void)
unsigned int i;
int high_width;
- printk(KERN_DEBUG "MTRR default type: %s\n",
- mtrr_attrib_to_str(mtrr_state.def_type));
+ pr_debug("MTRR default type: %s\n",
+ mtrr_attrib_to_str(mtrr_state.def_type));
if (mtrr_state.have_fixed) {
- printk(KERN_DEBUG "MTRR fixed ranges %sabled:\n",
- mtrr_state.enabled & 1 ? "en" : "dis");
+ pr_debug("MTRR fixed ranges %sabled:\n",
+ mtrr_state.enabled & 1 ? "en" : "dis");
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
for (i = 0; i < 2; ++i)
- print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8);
+ print_fixed(0x80000 + i * 0x20000, 0x04000,
+ mtrr_state.fixed_ranges + (i + 1) * 8);
for (i = 0; i < 8; ++i)
- print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8);
+ print_fixed(0xC0000 + i * 0x08000, 0x01000,
+ mtrr_state.fixed_ranges + (i + 3) * 8);
/* tail */
print_fixed_last();
}
- printk(KERN_DEBUG "MTRR variable ranges %sabled:\n",
- mtrr_state.enabled & 2 ? "en" : "dis");
+ pr_debug("MTRR variable ranges %sabled:\n",
+ mtrr_state.enabled & 2 ? "en" : "dis");
if (size_or_mask & 0xffffffffUL)
high_width = ffs(size_or_mask & 0xffffffffUL) - 1;
else
high_width = ffs(size_or_mask>>32) + 32 - 1;
high_width = (high_width - (32 - PAGE_SHIFT) + 3) / 4;
+
for (i = 0; i < num_var_ranges; ++i) {
if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
- printk(KERN_DEBUG " %u base %0*X%05X000 mask %0*X%05X000 %s\n",
- i,
- high_width,
- mtrr_state.var_ranges[i].base_hi,
- mtrr_state.var_ranges[i].base_lo >> 12,
- high_width,
- mtrr_state.var_ranges[i].mask_hi,
- mtrr_state.var_ranges[i].mask_lo >> 12,
- mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
+ pr_debug(" %u base %0*X%05X000 mask %0*X%05X000 %s\n",
+ i,
+ high_width,
+ mtrr_state.var_ranges[i].base_hi,
+ mtrr_state.var_ranges[i].base_lo >> 12,
+ high_width,
+ mtrr_state.var_ranges[i].mask_hi,
+ mtrr_state.var_ranges[i].mask_lo >> 12,
+ mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
else
- printk(KERN_DEBUG " %u disabled\n", i);
- }
- if (mtrr_tom2) {
- printk(KERN_DEBUG "TOM2: %016llx aka %lldM\n",
- mtrr_tom2, mtrr_tom2>>20);
+ pr_debug(" %u disabled\n", i);
}
+ if (mtrr_tom2)
+ pr_debug("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20);
}
-/* Grab all of the MTRR state for this CPU into *state */
+/* Grab all of the MTRR state for this CPU into *state */
void __init get_mtrr_state(void)
{
- unsigned int i;
struct mtrr_var_range *vrs;
- unsigned lo, dummy;
unsigned long flags;
+ unsigned lo, dummy;
+ unsigned int i;
vrs = mtrr_state.var_ranges;
@@ -324,6 +327,7 @@ void __init get_mtrr_state(void)
if (amd_special_default_mtrr()) {
unsigned low, high;
+
/* TOP_MEM2 */
rdmsr(MSR_K8_TOP_MEM2, low, high);
mtrr_tom2 = high;
@@ -344,10 +348,9 @@ void __init get_mtrr_state(void)
post_set();
local_irq_restore(flags);
-
}
-/* Some BIOS's are fucked and don't set all MTRRs the same! */
+/* Some BIOS's are messed up and don't set all MTRRs the same! */
void __init mtrr_state_warn(void)
{
unsigned long mask = smp_changes_mask;
@@ -355,28 +358,33 @@ void __init mtrr_state_warn(void)
if (!mask)
return;
if (mask & MTRR_CHANGE_MASK_FIXED)
- printk(KERN_WARNING "mtrr: your CPUs had inconsistent fixed MTRR settings\n");
+ pr_warning("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
if (mask & MTRR_CHANGE_MASK_VARIABLE)
- printk(KERN_WARNING "mtrr: your CPUs had inconsistent variable MTRR settings\n");
+ pr_warning("mtrr: your CPUs had inconsistent variable MTRR settings\n");
if (mask & MTRR_CHANGE_MASK_DEFTYPE)
- printk(KERN_WARNING "mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+ pr_warning("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+
printk(KERN_INFO "mtrr: probably your BIOS does not setup all CPUs.\n");
printk(KERN_INFO "mtrr: corrected configuration.\n");
}
-/* Doesn't attempt to pass an error out to MTRR users
- because it's quite complicated in some cases and probably not
- worth it because the best error handling is to ignore it. */
+/*
+ * Doesn't attempt to pass an error out to MTRR users
+ * because it's quite complicated in some cases and probably not
+ * worth it because the best error handling is to ignore it.
+ */
void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
{
- if (wrmsr_safe(msr, a, b) < 0)
+ if (wrmsr_safe(msr, a, b) < 0) {
printk(KERN_ERR
"MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
smp_processor_id(), msr, a, b);
+ }
}
/**
- * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have
+ * set_fixed_range - checks & updates a fixed-range MTRR if it
+ * differs from the value it should have
* @msr: MSR address of the MTTR which should be checked and updated
* @changed: pointer which indicates whether the MTRR needed to be changed
* @msrwords: pointer to the MSR values which the MSR should have
@@ -401,20 +409,23 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
*
* Returns: The index of the region on success, else negative on error.
*/
-int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
+int
+generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
{
- int i, max;
- mtrr_type ltype;
unsigned long lbase, lsize;
+ mtrr_type ltype;
+ int i, max;
max = num_var_ranges;
if (replace_reg >= 0 && replace_reg < max)
return replace_reg;
+
for (i = 0; i < max; ++i) {
mtrr_if->get(i, &lbase, &lsize, &ltype);
if (lsize == 0)
return i;
}
+
return -ENOSPC;
}
@@ -434,7 +445,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
if ((mask_lo & 0x800) == 0) {
- /* Invalid (i.e. free) range */
+ /* Invalid (i.e. free) range */
*base = 0;
*size = 0;
*type = 0;
@@ -471,27 +482,31 @@ out_put_cpu:
}
/**
- * set_fixed_ranges - checks & updates the fixed-range MTRRs if they differ from the saved set
+ * set_fixed_ranges - checks & updates the fixed-range MTRRs if they
+ * differ from the saved set
* @frs: pointer to fixed-range MTRR values, saved by get_fixed_ranges()
*/
-static int set_fixed_ranges(mtrr_type * frs)
+static int set_fixed_ranges(mtrr_type *frs)
{
- unsigned long long *saved = (unsigned long long *) frs;
+ unsigned long long *saved = (unsigned long long *)frs;
bool changed = false;
- int block=-1, range;
+ int block = -1, range;
k8_check_syscfg_dram_mod_en();
- while (fixed_range_blocks[++block].ranges)
- for (range=0; range < fixed_range_blocks[block].ranges; range++)
- set_fixed_range(fixed_range_blocks[block].base_msr + range,
- &changed, (unsigned int *) saved++);
+ while (fixed_range_blocks[++block].ranges) {
+ for (range = 0; range < fixed_range_blocks[block].ranges; range++)
+ set_fixed_range(fixed_range_blocks[block].base_msr + range,
+ &changed, (unsigned int *)saved++);
+ }
return changed;
}
-/* Set the MSR pair relating to a var range. Returns TRUE if
- changes are made */
+/*
+ * Set the MSR pair relating to a var range.
+ * Returns true if changes are made.
+ */
static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
{
unsigned int lo, hi;
@@ -501,6 +516,7 @@ static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
|| (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) !=
(hi & (size_and_mask >> (32 - PAGE_SHIFT)))) {
+
mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
changed = true;
}
@@ -526,21 +542,26 @@ static u32 deftype_lo, deftype_hi;
*/
static unsigned long set_mtrr_state(void)
{
- unsigned int i;
unsigned long change_mask = 0;
+ unsigned int i;
- for (i = 0; i < num_var_ranges; i++)
+ for (i = 0; i < num_var_ranges; i++) {
if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
change_mask |= MTRR_CHANGE_MASK_VARIABLE;
+ }
if (mtrr_state.have_fixed && set_fixed_ranges(mtrr_state.fixed_ranges))
change_mask |= MTRR_CHANGE_MASK_FIXED;
- /* Set_mtrr_restore restores the old value of MTRRdefType,
- so to set it we fiddle with the saved value */
+ /*
+ * Set_mtrr_restore restores the old value of MTRRdefType,
+ * so to set it we fiddle with the saved value:
+ */
if ((deftype_lo & 0xff) != mtrr_state.def_type
|| ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
- deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type | (mtrr_state.enabled << 10);
+
+ deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type |
+ (mtrr_state.enabled << 10);
change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
}
@@ -548,33 +569,36 @@ static unsigned long set_mtrr_state(void)
}
-static unsigned long cr4 = 0;
+static unsigned long cr4;
static DEFINE_SPINLOCK(set_atomicity_lock);
/*
- * Since we are disabling the cache don't allow any interrupts - they
- * would run extremely slow and would only increase the pain. The caller must
- * ensure that local interrupts are disabled and are reenabled after post_set()
- * has been called.
+ * Since we are disabling the cache don't allow any interrupts,
+ * they would run extremely slow and would only increase the pain.
+ *
+ * The caller must ensure that local interrupts are disabled and
+ * are reenabled after post_set() has been called.
*/
-
static void prepare_set(void) __acquires(set_atomicity_lock)
{
unsigned long cr0;
- /* Note that this is not ideal, since the cache is only flushed/disabled
- for this CPU while the MTRRs are changed, but changing this requires
- more invasive changes to the way the kernel boots */
+ /*
+ * Note that this is not ideal
+ * since the cache is only flushed/disabled for this CPU while the
+ * MTRRs are changed, but changing this requires more invasive
+ * changes to the way the kernel boots
+ */
spin_lock(&set_atomicity_lock);
- /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
+ /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
cr0 = read_cr0() | X86_CR0_CD;
write_cr0(cr0);
wbinvd();
- /* Save value of CR4 and clear Page Global Enable (bit 7) */
- if ( cpu_has_pge ) {
+ /* Save value of CR4 and clear Page Global Enable (bit 7) */
+ if (cpu_has_pge) {
cr4 = read_cr4();
write_cr4(cr4 & ~X86_CR4_PGE);
}
@@ -582,26 +606,26 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
__flush_tlb();
- /* Save MTRR state */
+ /* Save MTRR state */
rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
- /* Disable MTRRs, and set the default type to uncached */
+ /* Disable MTRRs, and set the default type to uncached */
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
}
static void post_set(void) __releases(set_atomicity_lock)
{
- /* Flush TLBs (no need to flush caches - they are disabled) */
+ /* Flush TLBs (no need to flush caches - they are disabled) */
__flush_tlb();
/* Intel (P6) standard MTRRs */
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
-
- /* Enable caches */
+
+ /* Enable caches */
write_cr0(read_cr0() & 0xbfffffff);
- /* Restore value of CR4 */
- if ( cpu_has_pge )
+ /* Restore value of CR4 */
+ if (cpu_has_pge)
write_cr4(cr4);
spin_unlock(&set_atomicity_lock);
}
@@ -623,24 +647,27 @@ static void generic_set_all(void)
post_set();
local_irq_restore(flags);
- /* Use the atomic bitops to update the global mask */
+ /* Use the atomic bitops to update the global mask */
for (count = 0; count < sizeof mask * 8; ++count) {
if (mask & 0x01)
set_bit(count, &smp_changes_mask);
mask >>= 1;
}
-
+
}
+/**
+ * generic_set_mtrr - set variable MTRR register on the local CPU.
+ *
+ * @reg: The register to set.
+ * @base: The base address of the region.
+ * @size: The size of the region. If this is 0 the region is disabled.
+ * @type: The type of the region.
+ *
+ * Returns nothing.
+ */
static void generic_set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type)
-/* [SUMMARY] Set variable MTRR register on the local CPU.
- <reg> The register to set.
- <base> The base address of the region.
- <size> The size of the region. If this is 0 the region is disabled.
- <type> The type of the region.
- [RETURNS] Nothing.
-*/
{
unsigned long flags;
struct mtrr_var_range *vr;
@@ -651,8 +678,10 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
prepare_set();
if (size == 0) {
- /* The invalid bit is kept in the mask, so we simply clear the
- relevant mask register to disable a range. */
+ /*
+ * The invalid bit is kept in the mask, so we simply
+ * clear the relevant mask register to disable a range.
+ */
mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
memset(vr, 0, sizeof(struct mtrr_var_range));
} else {
@@ -669,46 +698,50 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
local_irq_restore(flags);
}
-int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
+int generic_validate_add_page(unsigned long base, unsigned long size,
+ unsigned int type)
{
unsigned long lbase, last;
- /* For Intel PPro stepping <= 7, must be 4 MiB aligned
- and not touch 0x70000000->0x7003FFFF */
+ /*
+ * For Intel PPro stepping <= 7
+ * must be 4 MiB aligned and not touch 0x70000000 -> 0x7003FFFF
+ */
if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
boot_cpu_data.x86_model == 1 &&
boot_cpu_data.x86_mask <= 7) {
if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
- printk(KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
+ pr_warning("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
return -EINVAL;
}
if (!(base + size < 0x70000 || base > 0x7003F) &&
(type == MTRR_TYPE_WRCOMB
|| type == MTRR_TYPE_WRBACK)) {
- printk(KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
+ pr_warning("mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
return -EINVAL;
}
}
- /* Check upper bits of base and last are equal and lower bits are 0
- for base and 1 for last */
+ /*
+ * Check upper bits of base and last are equal and lower bits are 0
+ * for base and 1 for last
+ */
last = base + size - 1;
for (lbase = base; !(lbase & 1) && (last & 1);
- lbase = lbase >> 1, last = last >> 1) ;
+ lbase = lbase >> 1, last = last >> 1)
+ ;
if (lbase != last) {
- printk(KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
- base, size);
+ pr_warning("mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", base, size);
return -EINVAL;
}
return 0;
}
-
static int generic_have_wrcomb(void)
{
unsigned long config, dummy;
rdmsr(MSR_MTRRcap, config, dummy);
- return (config & (1 << 10));
+ return config & (1 << 10);
}
int positive_have_wrcomb(void)
@@ -716,14 +749,15 @@ int positive_have_wrcomb(void)
return 1;
}
-/* generic structure...
+/*
+ * Generic structure...
*/
struct mtrr_ops generic_mtrr_ops = {
- .use_intel_if = 1,
- .set_all = generic_set_all,
- .get = generic_get_mtrr,
- .get_free_region = generic_get_free_region,
- .set = generic_set_mtrr,
- .validate_add_page = generic_validate_add_page,
- .have_wrcomb = generic_have_wrcomb,
+ .use_intel_if = 1,
+ .set_all = generic_set_all,
+ .get = generic_get_mtrr,
+ .get_free_region = generic_get_free_region,
+ .set = generic_set_mtrr,
+ .validate_add_page = generic_validate_add_page,
+ .have_wrcomb = generic_have_wrcomb,
};
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
index fb73a52913a4..08b6ea4c62b4 100644
--- a/arch/x86/kernel/cpu/mtrr/if.c
+++ b/arch/x86/kernel/cpu/mtrr/if.c
@@ -1,27 +1,28 @@
-#include <linux/init.h>
-#include <linux/proc_fs.h>
#include <linux/capability.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
#include <linux/seq_file.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
#define LINE_SIZE 80
#include <asm/mtrr.h>
+
#include "mtrr.h"
#define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private)
static const char *const mtrr_strings[MTRR_NUM_TYPES] =
{
- "uncachable", /* 0 */
- "write-combining", /* 1 */
- "?", /* 2 */
- "?", /* 3 */
- "write-through", /* 4 */
- "write-protect", /* 5 */
- "write-back", /* 6 */
+ "uncachable", /* 0 */
+ "write-combining", /* 1 */
+ "?", /* 2 */
+ "?", /* 3 */
+ "write-through", /* 4 */
+ "write-protect", /* 5 */
+ "write-back", /* 6 */
};
const char *mtrr_attrib_to_str(int x)
@@ -35,8 +36,8 @@ static int
mtrr_file_add(unsigned long base, unsigned long size,
unsigned int type, bool increment, struct file *file, int page)
{
+ unsigned int *fcount = FILE_FCOUNT(file);
int reg, max;
- unsigned int *fcount = FILE_FCOUNT(file);
max = num_var_ranges;
if (fcount == NULL) {
@@ -61,8 +62,8 @@ static int
mtrr_file_del(unsigned long base, unsigned long size,
struct file *file, int page)
{
- int reg;
unsigned int *fcount = FILE_FCOUNT(file);
+ int reg;
if (!page) {
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)))
@@ -81,13 +82,14 @@ mtrr_file_del(unsigned long base, unsigned long size,
return reg;
}
-/* RED-PEN: seq_file can seek now. this is ignored. */
+/*
+ * seq_file can seek but we ignore it.
+ *
+ * Format of control line:
+ * "base=%Lx size=%Lx type=%s" or "disable=%d"
+ */
static ssize_t
mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
-/* Format of control line:
- "base=%Lx size=%Lx type=%s" OR:
- "disable=%d"
-*/
{
int i, err;
unsigned long reg;
@@ -100,15 +102,18 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
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))
return -EFAULT;
+
linelen = strlen(line);
ptr = line + linelen - 1;
if (linelen && *ptr == '\n')
*ptr = '\0';
+
if (!strncmp(line, "disable=", 8)) {
reg = simple_strtoul(line + 8, &ptr, 0);
err = mtrr_del_page(reg, 0, 0);
@@ -116,28 +121,35 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
return err;
return len;
}
+
if (strncmp(line, "base=", 5))
return -EINVAL;
+
base = simple_strtoull(line + 5, &ptr, 0);
- for (; isspace(*ptr); ++ptr) ;
+ for (; isspace(*ptr); ++ptr)
+ ;
+
if (strncmp(ptr, "size=", 5))
return -EINVAL;
+
size = simple_strtoull(ptr + 5, &ptr, 0);
if ((base & 0xfff) || (size & 0xfff))
return -EINVAL;
- for (; isspace(*ptr); ++ptr) ;
+ for (; isspace(*ptr); ++ptr)
+ ;
+
if (strncmp(ptr, "type=", 5))
return -EINVAL;
ptr += 5;
- for (; isspace(*ptr); ++ptr) ;
+ for (; isspace(*ptr); ++ptr)
+ ;
+
for (i = 0; i < MTRR_NUM_TYPES; ++i) {
if (strcmp(ptr, mtrr_strings[i]))
continue;
base >>= PAGE_SHIFT;
size >>= PAGE_SHIFT;
- err =
- mtrr_add_page((unsigned long) base, (unsigned long) size, i,
- true);
+ err = mtrr_add_page((unsigned long)base, (unsigned long)size, i, true);
if (err < 0)
return err;
return len;
@@ -181,7 +193,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
case MTRRIOC32_SET_PAGE_ENTRY:
case MTRRIOC32_DEL_PAGE_ENTRY:
case MTRRIOC32_KILL_PAGE_ENTRY: {
- struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)__arg;
+ struct mtrr_sentry32 __user *s32;
+
+ s32 = (struct mtrr_sentry32 __user *)__arg;
err = get_user(sentry.base, &s32->base);
err |= get_user(sentry.size, &s32->size);
err |= get_user(sentry.type, &s32->type);
@@ -191,7 +205,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
}
case MTRRIOC32_GET_ENTRY:
case MTRRIOC32_GET_PAGE_ENTRY: {
- struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg;
+ struct mtrr_gentry32 __user *g32;
+
+ g32 = (struct mtrr_gentry32 __user *)__arg;
err = get_user(gentry.regnum, &g32->regnum);
err |= get_user(gentry.base, &g32->base);
err |= get_user(gentry.size, &g32->size);
@@ -314,7 +330,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
if (err)
return err;
- switch(cmd) {
+ switch (cmd) {
case MTRRIOC_GET_ENTRY:
case MTRRIOC_GET_PAGE_ENTRY:
if (copy_to_user(arg, &gentry, sizeof gentry))
@@ -323,7 +339,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
#ifdef CONFIG_COMPAT
case MTRRIOC32_GET_ENTRY:
case MTRRIOC32_GET_PAGE_ENTRY: {
- struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg;
+ struct mtrr_gentry32 __user *g32;
+
+ g32 = (struct mtrr_gentry32 __user *)__arg;
err = put_user(gentry.base, &g32->base);
err |= put_user(gentry.size, &g32->size);
err |= put_user(gentry.regnum, &g32->regnum);
@@ -335,11 +353,10 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
return err;
}
-static int
-mtrr_close(struct inode *ino, struct file *file)
+static int mtrr_close(struct inode *ino, struct file *file)
{
- int i, max;
unsigned int *fcount = FILE_FCOUNT(file);
+ int i, max;
if (fcount != NULL) {
max = num_var_ranges;
@@ -359,22 +376,22 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset);
static int mtrr_open(struct inode *inode, struct file *file)
{
- if (!mtrr_if)
+ if (!mtrr_if)
return -EIO;
- if (!mtrr_if->get)
- return -ENXIO;
+ if (!mtrr_if->get)
+ return -ENXIO;
return single_open(file, mtrr_seq_show, NULL);
}
static const struct file_operations mtrr_fops = {
- .owner = THIS_MODULE,
- .open = mtrr_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .write = mtrr_write,
- .unlocked_ioctl = mtrr_ioctl,
- .compat_ioctl = mtrr_ioctl,
- .release = mtrr_close,
+ .owner = THIS_MODULE,
+ .open = mtrr_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = mtrr_write,
+ .unlocked_ioctl = mtrr_ioctl,
+ .compat_ioctl = mtrr_ioctl,
+ .release = mtrr_close,
};
static int mtrr_seq_show(struct seq_file *seq, void *offset)
@@ -388,23 +405,24 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset)
max = num_var_ranges;
for (i = 0; i < max; i++) {
mtrr_if->get(i, &base, &size, &type);
- if (size == 0)
+ if (size == 0) {
mtrr_usage_table[i] = 0;
- else {
- if (size < (0x100000 >> PAGE_SHIFT)) {
- /* less than 1MB */
- factor = 'K';
- size <<= PAGE_SHIFT - 10;
- } else {
- factor = 'M';
- size >>= 20 - PAGE_SHIFT;
- }
- /* RED-PEN: base can be > 32bit */
- len += seq_printf(seq,
- "reg%02i: base=0x%06lx000 (%5luMB), size=%5lu%cB, count=%d: %s\n",
- i, base, base >> (20 - PAGE_SHIFT), size, factor,
- mtrr_usage_table[i], mtrr_attrib_to_str(type));
+ continue;
}
+ if (size < (0x100000 >> PAGE_SHIFT)) {
+ /* less than 1MB */
+ factor = 'K';
+ size <<= PAGE_SHIFT - 10;
+ } else {
+ factor = 'M';
+ size >>= 20 - PAGE_SHIFT;
+ }
+ /* Base can be > 32bit */
+ len += seq_printf(seq, "reg%02i: base=0x%06lx000 "
+ "(%5luMB), size=%5lu%cB, count=%d: %s\n",
+ i, base, base >> (20 - PAGE_SHIFT), size,
+ factor, mtrr_usage_table[i],
+ mtrr_attrib_to_str(type));
}
return 0;
}
@@ -422,6 +440,5 @@ static int __init mtrr_if_init(void)
proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
return 0;
}
-
arch_initcall(mtrr_if_init);
#endif /* CONFIG_PROC_FS */
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 8fc248b5aeaf..7af0f88a4163 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -25,43 +25,48 @@
Operating System Writer's Guide" (Intel document number 242692),
section 11.11.7
- This was cleaned and made readable by Patrick Mochel <mochel@osdl.org>
- on 6-7 March 2002.
- Source: Intel Architecture Software Developers Manual, Volume 3:
+ This was cleaned and made readable by Patrick Mochel <mochel@osdl.org>
+ on 6-7 March 2002.
+ Source: Intel Architecture Software Developers Manual, Volume 3:
System Programming Guide; Section 9.11. (1997 edition - PPro).
*/
+#define DEBUG
+
+#include <linux/types.h> /* FIXME: kvm_para.h needs this */
+
+#include <linux/kvm_para.h>
+#include <linux/uaccess.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/init.h>
+#include <linux/sort.h>
+#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/mutex.h>
-#include <linux/sort.h>
+#include <asm/processor.h>
#include <asm/e820.h>
#include <asm/mtrr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
#include <asm/msr.h>
-#include <asm/kvm_para.h>
+
#include "mtrr.h"
-u32 num_var_ranges = 0;
+u32 num_var_ranges;
unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
static DEFINE_MUTEX(mtrr_mutex);
u64 size_or_mask, size_and_mask;
-static struct mtrr_ops * mtrr_ops[X86_VENDOR_NUM] = {};
+static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM];
-struct mtrr_ops * mtrr_if = NULL;
+struct mtrr_ops *mtrr_if;
static void set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type);
-void set_mtrr_ops(struct mtrr_ops * ops)
+void set_mtrr_ops(struct mtrr_ops *ops)
{
if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
mtrr_ops[ops->vendor] = ops;
@@ -72,30 +77,36 @@ static int have_wrcomb(void)
{
struct pci_dev *dev;
u8 rev;
-
- if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
- /* ServerWorks LE chipsets < rev 6 have problems with write-combining
- Don't allow it and leave room for other chipsets to be tagged */
+
+ dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL);
+ if (dev != NULL) {
+ /*
+ * ServerWorks LE chipsets < rev 6 have problems with
+ * write-combining. Don't allow it and leave room for other
+ * chipsets to be tagged
+ */
if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) {
pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
if (rev <= 5) {
- printk(KERN_INFO "mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n");
+ pr_info("mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n");
pci_dev_put(dev);
return 0;
}
}
- /* Intel 450NX errata # 23. Non ascending cacheline evictions to
- write combining memory may resulting in data corruption */
+ /*
+ * Intel 450NX errata # 23. Non ascending cacheline evictions to
+ * write combining memory may resulting in data corruption
+ */
if (dev->vendor == PCI_VENDOR_ID_INTEL &&
dev->device == PCI_DEVICE_ID_INTEL_82451NX) {
- printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
+ pr_info("mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
pci_dev_put(dev);
return 0;
}
pci_dev_put(dev);
- }
- return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0);
+ }
+ return mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0;
}
/* This function returns the number of variable MTRRs */
@@ -103,12 +114,13 @@ static void __init set_num_var_ranges(void)
{
unsigned long config = 0, dummy;
- if (use_intel()) {
+ if (use_intel())
rdmsr(MSR_MTRRcap, config, dummy);
- } else if (is_cpu(AMD))
+ else if (is_cpu(AMD))
config = 2;
else if (is_cpu(CYRIX) || is_cpu(CENTAUR))
config = 8;
+
num_var_ranges = config & 0xff;
}
@@ -130,10 +142,12 @@ struct set_mtrr_data {
mtrr_type smp_type;
};
+/**
+ * ipi_handler - Synchronisation handler. Executed by "other" CPUs.
+ *
+ * Returns nothing.
+ */
static void ipi_handler(void *info)
-/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
- [RETURNS] Nothing.
-*/
{
#ifdef CONFIG_SMP
struct set_mtrr_data *data = info;
@@ -142,18 +156,19 @@ static void ipi_handler(void *info)
local_irq_save(flags);
atomic_dec(&data->count);
- while(!atomic_read(&data->gate))
+ while (!atomic_read(&data->gate))
cpu_relax();
/* The master has cleared me to execute */
- if (data->smp_reg != ~0U)
- mtrr_if->set(data->smp_reg, data->smp_base,
+ if (data->smp_reg != ~0U) {
+ mtrr_if->set(data->smp_reg, data->smp_base,
data->smp_size, data->smp_type);
- else
+ } else {
mtrr_if->set_all();
+ }
atomic_dec(&data->count);
- while(atomic_read(&data->gate))
+ while (atomic_read(&data->gate))
cpu_relax();
atomic_dec(&data->count);
@@ -161,7 +176,8 @@ static void ipi_handler(void *info)
#endif
}
-static inline int types_compatible(mtrr_type type1, mtrr_type type2) {
+static inline int types_compatible(mtrr_type type1, mtrr_type type2)
+{
return type1 == MTRR_TYPE_UNCACHABLE ||
type2 == MTRR_TYPE_UNCACHABLE ||
(type1 == MTRR_TYPE_WRTHROUGH && type2 == MTRR_TYPE_WRBACK) ||
@@ -176,10 +192,10 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) {
* @type: mtrr type
*
* This is kinda tricky, but fortunately, Intel spelled it out for us cleanly:
- *
+ *
* 1. Send IPI to do the following:
* 2. Disable Interrupts
- * 3. Wait for all procs to do so
+ * 3. Wait for all procs to do so
* 4. Enter no-fill cache mode
* 5. Flush caches
* 6. Clear PGE bit
@@ -189,26 +205,27 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) {
* 10. Enable all range registers
* 11. Flush all TLBs and caches again
* 12. Enter normal cache mode and reenable caching
- * 13. Set PGE
+ * 13. Set PGE
* 14. Wait for buddies to catch up
* 15. Enable interrupts.
- *
+ *
* What does that mean for us? Well, first we set data.count to the number
* of CPUs. As each CPU disables interrupts, it'll decrement it once. We wait
* until it hits 0 and proceed. We set the data.gate flag and reset data.count.
- * Meanwhile, they are waiting for that flag to be set. Once it's set, each
- * CPU goes through the transition of updating MTRRs. The CPU vendors may each do it
- * differently, so we call mtrr_if->set() callback and let them take care of it.
- * When they're done, they again decrement data->count and wait for data.gate to
- * be reset.
- * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag.
+ * Meanwhile, they are waiting for that flag to be set. Once it's set, each
+ * CPU goes through the transition of updating MTRRs.
+ * The CPU vendors may each do it differently,
+ * so we call mtrr_if->set() callback and let them take care of it.
+ * When they're done, they again decrement data->count and wait for data.gate
+ * to be reset.
+ * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag
* Everyone then enables interrupts and we all continue on.
*
* Note that the mechanism is the same for UP systems, too; all the SMP stuff
* becomes nops.
*/
-static void set_mtrr(unsigned int reg, unsigned long base,
- unsigned long size, mtrr_type type)
+static void
+set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
{
struct set_mtrr_data data;
unsigned long flags;
@@ -218,121 +235,122 @@ static void set_mtrr(unsigned int reg, unsigned long base,
data.smp_size = size;
data.smp_type = type;
atomic_set(&data.count, num_booting_cpus() - 1);
- /* make sure data.count is visible before unleashing other CPUs */
+
+ /* Make sure data.count is visible before unleashing other CPUs */
smp_wmb();
- atomic_set(&data.gate,0);
+ atomic_set(&data.gate, 0);
- /* Start the ball rolling on other CPUs */
+ /* Start the ball rolling on other CPUs */
if (smp_call_function(ipi_handler, &data, 0) != 0)
panic("mtrr: timed out waiting for other CPUs\n");
local_irq_save(flags);
- while(atomic_read(&data.count))
+ while (atomic_read(&data.count))
cpu_relax();
- /* ok, reset count and toggle gate */
+ /* Ok, reset count and toggle gate */
atomic_set(&data.count, num_booting_cpus() - 1);
smp_wmb();
- atomic_set(&data.gate,1);
+ atomic_set(&data.gate, 1);
- /* do our MTRR business */
+ /* Do our MTRR business */
- /* HACK!
+ /*
+ * HACK!
* We use this same function to initialize the mtrrs on boot.
* The state of the boot cpu's mtrrs has been saved, and we want
- * to replicate across all the APs.
+ * to replicate across all the APs.
* If we're doing that @reg is set to something special...
*/
- if (reg != ~0U)
- mtrr_if->set(reg,base,size,type);
+ if (reg != ~0U)
+ mtrr_if->set(reg, base, size, type);
- /* wait for the others */
- while(atomic_read(&data.count))
+ /* Wait for the others */
+ while (atomic_read(&data.count))
cpu_relax();
atomic_set(&data.count, num_booting_cpus() - 1);
smp_wmb();
- atomic_set(&data.gate,0);
+ atomic_set(&data.gate, 0);
/*
* Wait here for everyone to have seen the gate change
* So we're the last ones to touch 'data'
*/
- while(atomic_read(&data.count))
+ while (atomic_read(&data.count))
cpu_relax();
local_irq_restore(flags);
}
/**
- * mtrr_add_page - Add a memory type region
- * @base: Physical base address of region in pages (in units of 4 kB!)
- * @size: Physical size of region in pages (4 kB)
- * @type: Type of MTRR desired
- * @increment: If this is true do usage counting on the region
+ * mtrr_add_page - Add a memory type region
+ * @base: Physical base address of region in pages (in units of 4 kB!)
+ * @size: Physical size of region in pages (4 kB)
+ * @type: Type of MTRR desired
+ * @increment: If this is true do usage counting on the region
*
- * Memory type region registers control the caching on newer Intel and
- * non Intel processors. This function allows drivers to request an
- * MTRR is added. The details and hardware specifics of each processor's
- * implementation are hidden from the caller, but nevertheless the
- * caller should expect to need to provide a power of two size on an
- * equivalent power of two boundary.
+ * Memory type region registers control the caching on newer Intel and
+ * non Intel processors. This function allows drivers to request an
+ * MTRR is added. The details and hardware specifics of each processor's
+ * implementation are hidden from the caller, but nevertheless the
+ * caller should expect to need to provide a power of two size on an
+ * equivalent power of two boundary.
*
- * If the region cannot be added either because all regions are in use
- * or the CPU cannot support it a negative value is returned. On success
- * the register number for this entry is returned, but should be treated
- * as a cookie only.
+ * If the region cannot be added either because all regions are in use
+ * or the CPU cannot support it a negative value is returned. On success
+ * the register number for this entry is returned, but should be treated
+ * as a cookie only.
*
- * On a multiprocessor machine the changes are made to all processors.
- * This is required on x86 by the Intel processors.
+ * On a multiprocessor machine the changes are made to all processors.
+ * This is required on x86 by the Intel processors.
*
- * The available types are
+ * The available types are
*
- * %MTRR_TYPE_UNCACHABLE - No caching
+ * %MTRR_TYPE_UNCACHABLE - No caching
*
- * %MTRR_TYPE_WRBACK - Write data back in bursts whenever
+ * %MTRR_TYPE_WRBACK - Write data back in bursts whenever
*
- * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
+ * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
*
- * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
+ * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
*
- * BUGS: Needs a quiet flag for the cases where drivers do not mind
- * failures and do not wish system log messages to be sent.
+ * BUGS: Needs a quiet flag for the cases where drivers do not mind
+ * failures and do not wish system log messages to be sent.
*/
-
-int mtrr_add_page(unsigned long base, unsigned long size,
+int mtrr_add_page(unsigned long base, unsigned long size,
unsigned int type, bool increment)
{
+ unsigned long lbase, lsize;
int i, replace, error;
mtrr_type ltype;
- unsigned long lbase, lsize;
if (!mtrr_if)
return -ENXIO;
-
- if ((error = mtrr_if->validate_add_page(base,size,type)))
+
+ error = mtrr_if->validate_add_page(base, size, type);
+ if (error)
return error;
if (type >= MTRR_NUM_TYPES) {
- printk(KERN_WARNING "mtrr: type: %u invalid\n", type);
+ pr_warning("mtrr: type: %u invalid\n", type);
return -EINVAL;
}
- /* If the type is WC, check that this processor supports it */
+ /* If the type is WC, check that this processor supports it */
if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {
- printk(KERN_WARNING
- "mtrr: your processor doesn't support write-combining\n");
+ pr_warning("mtrr: your processor doesn't support write-combining\n");
return -ENOSYS;
}
if (!size) {
- printk(KERN_WARNING "mtrr: zero sized request\n");
+ pr_warning("mtrr: zero sized request\n");
return -EINVAL;
}
if (base & size_or_mask || size & size_or_mask) {
- printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n");
+ pr_warning("mtrr: base or size exceeds the MTRR width\n");
return -EINVAL;
}
@@ -341,36 +359,40 @@ int mtrr_add_page(unsigned long base, unsigned long size,
/* No CPU hotplug when we change MTRR entries */
get_online_cpus();
- /* Search for existing MTRR */
+
+ /* Search for existing MTRR */
mutex_lock(&mtrr_mutex);
for (i = 0; i < num_var_ranges; ++i) {
mtrr_if->get(i, &lbase, &lsize, &ltype);
- if (!lsize || base > lbase + lsize - 1 || base + size - 1 < lbase)
+ if (!lsize || base > lbase + lsize - 1 ||
+ base + size - 1 < lbase)
continue;
- /* At this point we know there is some kind of overlap/enclosure */
+ /*
+ * At this point we know there is some kind of
+ * overlap/enclosure
+ */
if (base < lbase || base + size - 1 > lbase + lsize - 1) {
- if (base <= lbase && base + size - 1 >= lbase + lsize - 1) {
+ if (base <= lbase &&
+ base + size - 1 >= lbase + lsize - 1) {
/* New region encloses an existing region */
if (type == ltype) {
replace = replace == -1 ? i : -2;
continue;
- }
- else if (types_compatible(type, ltype))
+ } else if (types_compatible(type, ltype))
continue;
}
- printk(KERN_WARNING
- "mtrr: 0x%lx000,0x%lx000 overlaps existing"
- " 0x%lx000,0x%lx000\n", base, size, lbase,
- lsize);
+ pr_warning("mtrr: 0x%lx000,0x%lx000 overlaps existing"
+ " 0x%lx000,0x%lx000\n", base, size, lbase,
+ lsize);
goto out;
}
- /* New region is enclosed by an existing region */
+ /* New region is enclosed by an existing region */
if (ltype != type) {
if (types_compatible(type, ltype))
continue;
- printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
- base, size, mtrr_attrib_to_str(ltype),
- mtrr_attrib_to_str(type));
+ pr_warning("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
+ base, size, mtrr_attrib_to_str(ltype),
+ mtrr_attrib_to_str(type));
goto out;
}
if (increment)
@@ -378,7 +400,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = i;
goto out;
}
- /* Search for an empty MTRR */
+ /* Search for an empty MTRR */
i = mtrr_if->get_free_region(base, size, replace);
if (i >= 0) {
set_mtrr(i, base, size, type);
@@ -393,8 +415,9 @@ int mtrr_add_page(unsigned long base, unsigned long size,
mtrr_usage_table[replace] = 0;
}
}
- } else
- printk(KERN_INFO "mtrr: no more MTRRs available\n");
+ } else {
+ pr_info("mtrr: no more MTRRs available\n");
+ }
error = i;
out:
mutex_unlock(&mtrr_mutex);
@@ -405,10 +428,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
static int mtrr_check(unsigned long base, unsigned long size)
{
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
- printk(KERN_WARNING
- "mtrr: size and base must be multiples of 4 kiB\n");
- printk(KERN_DEBUG
- "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ pr_warning("mtrr: size and base must be multiples of 4 kiB\n");
+ pr_debug("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
dump_stack();
return -1;
}
@@ -416,66 +437,64 @@ static int mtrr_check(unsigned long base, unsigned long size)
}
/**
- * mtrr_add - Add a memory type region
- * @base: Physical base address of region
- * @size: Physical size of region
- * @type: Type of MTRR desired
- * @increment: If this is true do usage counting on the region
+ * mtrr_add - Add a memory type region
+ * @base: Physical base address of region
+ * @size: Physical size of region
+ * @type: Type of MTRR desired
+ * @increment: If this is true do usage counting on the region
*
- * Memory type region registers control the caching on newer Intel and
- * non Intel processors. This function allows drivers to request an
- * MTRR is added. The details and hardware specifics of each processor's
- * implementation are hidden from the caller, but nevertheless the
- * caller should expect to need to provide a power of two size on an
- * equivalent power of two boundary.
+ * Memory type region registers control the caching on newer Intel and
+ * non Intel processors. This function allows drivers to request an
+ * MTRR is added. The details and hardware specifics of each processor's
+ * implementation are hidden from the caller, but nevertheless the
+ * caller should expect to need to provide a power of two size on an
+ * equivalent power of two boundary.
*
- * If the region cannot be added either because all regions are in use
- * or the CPU cannot support it a negative value is returned. On success
- * the register number for this entry is returned, but should be treated
- * as a cookie only.
+ * If the region cannot be added either because all regions are in use
+ * or the CPU cannot support it a negative value is returned. On success
+ * the register number for this entry is returned, but should be treated
+ * as a cookie only.
*
- * On a multiprocessor machine the changes are made to all processors.
- * This is required on x86 by the Intel processors.
+ * On a multiprocessor machine the changes are made to all processors.
+ * This is required on x86 by the Intel processors.
*
- * The available types are
+ * The available types are
*
- * %MTRR_TYPE_UNCACHABLE - No caching
+ * %MTRR_TYPE_UNCACHABLE - No caching
*
- * %MTRR_TYPE_WRBACK - Write data back in bursts whenever
+ * %MTRR_TYPE_WRBACK - Write data back in bursts whenever
*
- * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
+ * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
*
- * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
+ * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
*
- * BUGS: Needs a quiet flag for the cases where drivers do not mind
- * failures and do not wish system log messages to be sent.
+ * BUGS: Needs a quiet flag for the cases where drivers do not mind
+ * failures and do not wish system log messages to be sent.
*/
-
-int
-mtrr_add(unsigned long base, unsigned long size, unsigned int type,
- bool increment)
+int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
+ bool increment)
{
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
increment);
}
+EXPORT_SYMBOL(mtrr_add);
/**
- * mtrr_del_page - delete a memory type region
- * @reg: Register returned by mtrr_add
- * @base: Physical base address
- * @size: Size of region
+ * mtrr_del_page - delete a memory type region
+ * @reg: Register returned by mtrr_add
+ * @base: Physical base address
+ * @size: Size of region
*
- * If register is supplied then base and size are ignored. This is
- * how drivers should call it.
+ * If register is supplied then base and size are ignored. This is
+ * how drivers should call it.
*
- * Releases an MTRR region. If the usage count drops to zero the
- * register is freed and the region returns to default state.
- * On success the register is returned, on failure a negative error
- * code.
+ * Releases an MTRR region. If the usage count drops to zero the
+ * register is freed and the region returns to default state.
+ * On success the register is returned, on failure a negative error
+ * code.
*/
-
int mtrr_del_page(int reg, unsigned long base, unsigned long size)
{
int i, max;
@@ -500,22 +519,22 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
}
}
if (reg < 0) {
- printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
- size);
+ pr_debug("mtrr: no MTRR for %lx000,%lx000 found\n",
+ base, size);
goto out;
}
}
if (reg >= max) {
- printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
+ pr_warning("mtrr: register: %d too big\n", reg);
goto out;
}
mtrr_if->get(reg, &lbase, &lsize, &ltype);
if (lsize < 1) {
- printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
+ pr_warning("mtrr: MTRR %d not used\n", reg);
goto out;
}
if (mtrr_usage_table[reg] < 1) {
- printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
+ pr_warning("mtrr: reg: %d has count=0\n", reg);
goto out;
}
if (--mtrr_usage_table[reg] < 1)
@@ -526,33 +545,31 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
put_online_cpus();
return error;
}
+
/**
- * mtrr_del - delete a memory type region
- * @reg: Register returned by mtrr_add
- * @base: Physical base address
- * @size: Size of region
+ * mtrr_del - delete a memory type region
+ * @reg: Register returned by mtrr_add
+ * @base: Physical base address
+ * @size: Size of region
*
- * If register is supplied then base and size are ignored. This is
- * how drivers should call it.
+ * If register is supplied then base and size are ignored. This is
+ * how drivers should call it.
*
- * Releases an MTRR region. If the usage count drops to zero the
- * register is freed and the region returns to default state.
- * On success the register is returned, on failure a negative error
- * code.
+ * Releases an MTRR region. If the usage count drops to zero the
+ * register is freed and the region returns to default state.
+ * On success the register is returned, on failure a negative error
+ * code.
*/
-
-int
-mtrr_del(int reg, unsigned long base, unsigned long size)
+int mtrr_del(int reg, unsigned long base, unsigned long size)
{
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
}
-
-EXPORT_SYMBOL(mtrr_add);
EXPORT_SYMBOL(mtrr_del);
-/* HACK ALERT!
+/*
+ * HACK ALERT!
* These should be called implicitly, but we can't yet until all the initcall
* stuff is done...
*/
@@ -576,29 +593,28 @@ struct mtrr_value {
static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];
-static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
+static int mtrr_save(struct sys_device *sysdev, pm_message_t state)
{
int i;
for (i = 0; i < num_var_ranges; i++) {
- mtrr_if->get(i,
- &mtrr_value[i].lbase,
- &mtrr_value[i].lsize,
- &mtrr_value[i].ltype);
+ mtrr_if->get(i, &mtrr_value[i].lbase,
+ &mtrr_value[i].lsize,
+ &mtrr_value[i].ltype);
}
return 0;
}
-static int mtrr_restore(struct sys_device * sysdev)
+static int mtrr_restore(struct sys_device *sysdev)
{
int i;
for (i = 0; i < num_var_ranges; i++) {
- if (mtrr_value[i].lsize)
- set_mtrr(i,
- mtrr_value[i].lbase,
- mtrr_value[i].lsize,
- mtrr_value[i].ltype);
+ if (mtrr_value[i].lsize) {
+ set_mtrr(i, mtrr_value[i].lbase,
+ mtrr_value[i].lsize,
+ mtrr_value[i].ltype);
+ }
}
return 0;
}
@@ -615,26 +631,29 @@ int __initdata changed_by_mtrr_cleanup;
/**
* mtrr_bp_init - initialize mtrrs on the boot CPU
*
- * This needs to be called early; before any of the other CPUs are
+ * This needs to be called early; before any of the other CPUs are
* initialized (i.e. before smp_init()).
- *
+ *
*/
void __init mtrr_bp_init(void)
{
u32 phys_addr;
+
init_ifs();
phys_addr = 32;
if (cpu_has_mtrr) {
mtrr_if = &generic_mtrr_ops;
- size_or_mask = 0xff000000; /* 36 bits */
+ size_or_mask = 0xff000000; /* 36 bits */
size_and_mask = 0x00f00000;
phys_addr = 36;
- /* This is an AMD specific MSR, but we assume(hope?) that
- Intel will implement it to when they extend the address
- bus of the Xeon. */
+ /*
+ * This is an AMD specific MSR, but we assume(hope?) that
+ * Intel will implement it to when they extend the address
+ * bus of the Xeon.
+ */
if (cpuid_eax(0x80000000) >= 0x80000008) {
phys_addr = cpuid_eax(0x80000008) & 0xff;
/* CPUID workaround for Intel 0F33/0F34 CPU */
@@ -649,9 +668,11 @@ void __init mtrr_bp_init(void)
size_and_mask = ~size_or_mask & 0xfffff00000ULL;
} else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
boot_cpu_data.x86 == 6) {
- /* VIA C* family have Intel style MTRRs, but
- don't support PAE */
- size_or_mask = 0xfff00000; /* 32 bits */
+ /*
+ * VIA C* family have Intel style MTRRs,
+ * but don't support PAE
+ */
+ size_or_mask = 0xfff00000; /* 32 bits */
size_and_mask = 0;
phys_addr = 32;
}
@@ -694,7 +715,6 @@ void __init mtrr_bp_init(void)
changed_by_mtrr_cleanup = 1;
mtrr_if->set_all();
}
-
}
}
}
@@ -706,12 +726,17 @@ void mtrr_ap_init(void)
if (!mtrr_if || !use_intel())
return;
/*
- * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
- * but this routine will be called in cpu boot time, holding the lock
- * breaks it. This routine is called in two cases: 1.very earily time
- * of software resume, when there absolutely isn't mtrr entry changes;
- * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
- * prevent mtrr entry changes
+ * Ideally we should hold mtrr_mutex here to avoid mtrr entries
+ * changed, but this routine will be called in cpu boot time,
+ * holding the lock breaks it.
+ *
+ * This routine is called in two cases:
+ *
+ * 1. very earily time of software resume, when there absolutely
+ * isn't mtrr entry changes;
+ *
+ * 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug
+ * lock to prevent mtrr entry changes
*/
local_irq_save(flags);
@@ -732,19 +757,23 @@ static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
return 0;
+
if (use_intel()) {
if (!changed_by_mtrr_cleanup)
mtrr_state_warn();
- } else {
- /* The CPUs haven't MTRR and seem to not support SMP. They have
- * specific drivers, we use a tricky method to support
- * suspend/resume for them.
- * TBD: is there any system with such CPU which supports
- * suspend/resume? if no, we should remove the code.
- */
- sysdev_driver_register(&cpu_sysdev_class,
- &mtrr_sysdev_driver);
+ return 0;
}
+
+ /*
+ * The CPU has no MTRR and seems to not support SMP. They have
+ * specific drivers, we use a tricky method to support
+ * suspend/resume for them.
+ *
+ * TBD: is there any system with such CPU which supports
+ * suspend/resume? If no, we should remove the code.
+ */
+ sysdev_driver_register(&cpu_sysdev_class, &mtrr_sysdev_driver);
+
return 0;
}
subsys_initcall(mtrr_init_finialize);
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h
index 7538b767f206..a501dee9a87a 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -1,5 +1,5 @@
/*
- * local mtrr defines.
+ * local MTRR defines.
*/
#include <linux/types.h>
@@ -14,13 +14,12 @@ extern unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
struct mtrr_ops {
u32 vendor;
u32 use_intel_if;
-// void (*init)(void);
void (*set)(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type);
void (*set_all)(void);
void (*get)(unsigned int reg, unsigned long *base,
- unsigned long *size, mtrr_type * type);
+ unsigned long *size, mtrr_type *type);
int (*get_free_region)(unsigned long base, unsigned long size,
int replace_reg);
int (*validate_add_page)(unsigned long base, unsigned long size,
@@ -39,11 +38,11 @@ extern int positive_have_wrcomb(void);
/* library functions for processor-specific routines */
struct set_mtrr_context {
- unsigned long flags;
- unsigned long cr4val;
- u32 deftype_lo;
- u32 deftype_hi;
- u32 ccr3;
+ unsigned long flags;
+ unsigned long cr4val;
+ u32 deftype_lo;
+ u32 deftype_hi;
+ u32 ccr3;
};
void set_mtrr_done(struct set_mtrr_context *ctxt);
@@ -54,10 +53,10 @@ void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
void get_mtrr_state(void);
-extern void set_mtrr_ops(struct mtrr_ops * ops);
+extern void set_mtrr_ops(struct mtrr_ops *ops);
extern u64 size_or_mask, size_and_mask;
-extern struct mtrr_ops * mtrr_if;
+extern struct mtrr_ops *mtrr_if;
#define is_cpu(vnd) (mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd)
#define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1)
diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c
index 1f5fb1588d1f..dfc80b4e6b0d 100644
--- a/arch/x86/kernel/cpu/mtrr/state.c
+++ b/arch/x86/kernel/cpu/mtrr/state.c
@@ -1,24 +1,25 @@
-#include <linux/mm.h>
#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mtrr.h>
-#include <asm/msr.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
#include <asm/processor-cyrix.h>
#include <asm/processor-flags.h>
-#include "mtrr.h"
+#include <asm/mtrr.h>
+#include <asm/msr.h>
+#include "mtrr.h"
-/* Put the processor into a state where MTRRs can be safely set */
+/* Put the processor into a state where MTRRs can be safely set */
void set_mtrr_prepare_save(struct set_mtrr_context *ctxt)
{
unsigned int cr0;
- /* Disable interrupts locally */
+ /* Disable interrupts locally */
local_irq_save(ctxt->flags);
if (use_intel() || is_cpu(CYRIX)) {
- /* Save value of CR4 and clear Page Global Enable (bit 7) */
+ /* Save value of CR4 and clear Page Global Enable (bit 7) */
if (cpu_has_pge) {
ctxt->cr4val = read_cr4();
write_cr4(ctxt->cr4val & ~X86_CR4_PGE);
@@ -33,50 +34,61 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt)
write_cr0(cr0);
wbinvd();
- if (use_intel())
- /* Save MTRR state */
+ if (use_intel()) {
+ /* Save MTRR state */
rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
- else
- /* Cyrix ARRs - everything else were excluded at the top */
+ } else {
+ /*
+ * Cyrix ARRs -
+ * everything else were excluded at the top
+ */
ctxt->ccr3 = getCx86(CX86_CCR3);
+ }
}
}
void set_mtrr_cache_disable(struct set_mtrr_context *ctxt)
{
- if (use_intel())
- /* Disable MTRRs, and set the default type to uncached */
+ if (use_intel()) {
+ /* Disable MTRRs, and set the default type to uncached */
mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL,
ctxt->deftype_hi);
- else if (is_cpu(CYRIX))
- /* Cyrix ARRs - everything else were excluded at the top */
- setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
+ } else {
+ if (is_cpu(CYRIX)) {
+ /* Cyrix ARRs - everything else were excluded at the top */
+ setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
+ }
+ }
}
-/* Restore the processor after a set_mtrr_prepare */
+/* Restore the processor after a set_mtrr_prepare */
void set_mtrr_done(struct set_mtrr_context *ctxt)
{
if (use_intel() || is_cpu(CYRIX)) {
- /* Flush caches and TLBs */
+ /* Flush caches and TLBs */
wbinvd();
- /* Restore MTRRdefType */
- if (use_intel())
+ /* Restore MTRRdefType */
+ if (use_intel()) {
/* Intel (P6) standard MTRRs */
- mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);
- else
- /* Cyrix ARRs - everything else was excluded at the top */
+ mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo,
+ ctxt->deftype_hi);
+ } else {
+ /*
+ * Cyrix ARRs -
+ * everything else was excluded at the top
+ */
setCx86(CX86_CCR3, ctxt->ccr3);
+ }
- /* Enable caches */
+ /* Enable caches */
write_cr0(read_cr0() & 0xbfffffff);
- /* Restore value of CR4 */
+ /* Restore value of CR4 */
if (cpu_has_pge)
write_cr4(ctxt->cr4val);
}
- /* Re-enable interrupts locally (if enabled previously) */
+ /* Re-enable interrupts locally (if enabled previously) */
local_irq_restore(ctxt->flags);
}
-
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index a7aa8f900954..3f8556cb9a05 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -960,7 +960,7 @@ amd_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
x86_pmu_disable_counter(hwc, idx);
}
-static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]);
+static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
/*
* Set the next IRQ period, based on the hwc->period_left value.
@@ -999,7 +999,7 @@ x86_perf_counter_set_period(struct perf_counter *counter,
if (left > x86_pmu.max_period)
left = x86_pmu.max_period;
- per_cpu(prev_left[idx], smp_processor_id()) = left;
+ per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
/*
* The hw counter starts counting from this counter offset,
@@ -1195,7 +1195,7 @@ void perf_counter_print_debug(void)
rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl);
rdmsrl(x86_pmu.perfctr + idx, pmc_count);
- prev_left = per_cpu(prev_left[idx], cpu);
+ prev_left = per_cpu(pmc_prev_left[idx], cpu);
pr_info("CPU#%d: gen-PMC%d ctrl: %016llx\n",
cpu, idx, pmc_ctrl);
@@ -1772,8 +1772,8 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip)
entry->ip[entry->nr++] = ip;
}
-static DEFINE_PER_CPU(struct perf_callchain_entry, irq_entry);
-static DEFINE_PER_CPU(struct perf_callchain_entry, nmi_entry);
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry);
static DEFINE_PER_CPU(int, in_nmi_frame);
@@ -1926,9 +1926,9 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
struct perf_callchain_entry *entry;
if (in_nmi())
- entry = &__get_cpu_var(nmi_entry);
+ entry = &__get_cpu_var(pmc_nmi_entry);
else
- entry = &__get_cpu_var(irq_entry);
+ entry = &__get_cpu_var(pmc_irq_entry);
entry->nr = 0;
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index d5e30397246b..1990d4b5691b 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -15,6 +15,7 @@ static void show_cpuinfo_core(struct seq_file *m, struct cpuinfo_x86 *c,
seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
seq_printf(m, "siblings\t: %d\n",
cpumask_weight(cpu_core_mask(cpu)));
+ seq_printf(m, "node id\t\t: %d\n", c->cpu_node_id);
seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
seq_printf(m, "apicid\t\t: %d\n", c->apicid);
@@ -116,11 +117,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
#endif
seq_printf(m, "clflush size\t: %u\n", c->x86_clflush_size);
-#ifdef CONFIG_X86_64
seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
c->x86_phys_bits, c->x86_virt_bits);
-#endif
seq_printf(m, "power management:");
for (i = 0; i < 32; i++) {
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 48bfe1386038..ef42a038f1a6 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -509,15 +509,15 @@ enum bts_field {
bts_escape = ((unsigned long)-1 & ~bts_qual_mask)
};
-static inline unsigned long bts_get(const char *base, enum bts_field field)
+static inline unsigned long bts_get(const char *base, unsigned long field)
{
base += (ds_cfg.sizeof_ptr_field * field);
return *(unsigned long *)base;
}
-static inline void bts_set(char *base, enum bts_field field, unsigned long val)
+static inline void bts_set(char *base, unsigned long field, unsigned long val)
{
- base += (ds_cfg.sizeof_ptr_field * field);;
+ base += (ds_cfg.sizeof_ptr_field * field);
(*(unsigned long *)base) = val;
}
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 8663afb56535..0d98a01cbdb2 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -602,7 +602,11 @@ ignore_int:
#endif
iret
-.section .cpuinit.data,"wa"
+#ifndef CONFIG_HOTPLUG_CPU
+ __CPUINITDATA
+#else
+ __REFDATA
+#endif
.align 4
ENTRY(initial_code)
.long i386_start_kernel
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 696f0e475c2d..92b7703d3d58 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -187,7 +187,7 @@ static void __init apic_intr_init(void)
#ifdef CONFIG_X86_THERMAL_VECTOR
alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
#endif
-#ifdef CONFIG_X86_THRESHOLD
+#ifdef CONFIG_X86_MCE_THRESHOLD
alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
#endif
#if defined(CONFIG_X86_NEW_MCE) && defined(CONFIG_X86_LOCAL_APIC)
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 8d82a77a3f3b..8352c0b9643f 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;
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 71f1d99a635d..ec6ef60cbd17 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -67,8 +67,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
#ifdef CONFIG_SMP
preempt_disable();
load_LDT(pc);
- if (!cpus_equal(current->mm->cpu_vm_mask,
- cpumask_of_cpu(smp_processor_id())))
+ if (!cpumask_equal(mm_cpumask(current->mm),
+ cpumask_of(smp_processor_id())))
smp_call_function(flush_ldt, current->mm, 1);
preempt_enable();
#else
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
index 846510b78a09..2a62d843f015 100644
--- a/arch/x86/kernel/mfgpt_32.c
+++ b/arch/x86/kernel/mfgpt_32.c
@@ -347,7 +347,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
static struct irqaction mfgptirq = {
.handler = mfgpt_tick,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
.name = "mfgpt-timer"
};
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 994dd6a4a2a0..bd997dccaff3 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -9,6 +9,7 @@
#include <linux/pm.h>
#include <linux/clockchips.h>
#include <linux/random.h>
+#include <linux/kmemleak.h>
#include <trace/power.h>
#include <asm/system.h>
#include <asm/apic.h>
@@ -55,6 +56,7 @@ void free_thread_xstate(struct task_struct *tsk)
void free_thread_info(struct thread_info *ti)
{
free_thread_xstate(ti->task);
+ kmemleak_free(ti);
free_pages((unsigned long)ti, get_order(THREAD_SIZE));
}
@@ -572,10 +574,8 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
void __init init_c1e_mask(void)
{
/* If we're using c1e_idle, we need to allocate c1e_mask. */
- if (pm_idle == c1e_idle) {
- alloc_cpumask_var(&c1e_mask, GFP_KERNEL);
- cpumask_clear(c1e_mask);
- }
+ if (pm_idle == c1e_idle)
+ zalloc_cpumask_var(&c1e_mask, GFP_KERNEL);
}
static int __init idle_setup(char *str)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 59f4524984af..a80eddd41658 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -350,14 +350,21 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*next = &next_p->thread;
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
+ bool preload_fpu;
/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
- __unlazy_fpu(prev_p);
+ /*
+ * If the task has used fpu the last 5 timeslices, just do a full
+ * restore of the math state immediately to avoid the trap; the
+ * chances of needing FPU soon are obviously high now
+ */
+ preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
+ __unlazy_fpu(prev_p);
/* we're going to use this soon, after a few expensive things */
- if (next_p->fpu_counter > 5)
+ if (preload_fpu)
prefetch(next->xstate);
/*
@@ -398,6 +405,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT))
__switch_to_xtra(prev_p, next_p, tss);
+ /* If we're going to preload the fpu context, make sure clts
+ is run while we're batching the cpu state updates. */
+ if (preload_fpu)
+ clts();
+
/*
* Leave lazy mode, flushing any hypercalls made here.
* This must be done before restoring TLS segments so
@@ -407,15 +419,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*/
arch_end_context_switch(next_p);
- /* If the task has used fpu the last 5 timeslices, just do a full
- * restore of the math state immediately to avoid the trap; the
- * chances of needing FPU soon are obviously high now
- *
- * tsk_used_math() checks prevent calling math_state_restore(),
- * which can sleep in the case of !tsk_used_math()
- */
- if (tsk_used_math(next_p) && next_p->fpu_counter > 5)
- math_state_restore();
+ if (preload_fpu)
+ __math_state_restore();
/*
* Restore %gs if needed (which is common)
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ebefb5407b9d..a28279dbb07c 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -386,9 +386,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
unsigned fsindex, gsindex;
+ bool preload_fpu;
+
+ /*
+ * If the task has used fpu the last 5 timeslices, just do a full
+ * restore of the math state immediately to avoid the trap; the
+ * chances of needing FPU soon are obviously high now
+ */
+ preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
/* we're going to use this soon, after a few expensive things */
- if (next_p->fpu_counter > 5)
+ if (preload_fpu)
prefetch(next->xstate);
/*
@@ -419,6 +427,13 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
load_TLS(next, cpu);
+ /* Must be after DS reload */
+ unlazy_fpu(prev_p);
+
+ /* Make sure cpu is ready for new context */
+ if (preload_fpu)
+ clts();
+
/*
* Leave lazy mode, flushing any hypercalls made here.
* This must be done before restoring TLS segments so
@@ -459,9 +474,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
prev->gsindex = gsindex;
- /* Must be after DS reload */
- unlazy_fpu(prev_p);
-
/*
* Switch the PDA and FPU contexts.
*/
@@ -480,15 +492,12 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV))
__switch_to_xtra(prev_p, next_p, tss);
- /* If the task has used fpu the last 5 timeslices, just do a full
- * restore of the math state immediately to avoid the trap; the
- * chances of needing FPU soon are obviously high now
- *
- * tsk_used_math() checks prevent calling math_state_restore(),
- * which can sleep in the case of !tsk_used_math()
+ /*
+ * Preload the FPU context, now that we've determined that the
+ * task is likely to be using it.
*/
- if (tsk_used_math(next_p) && next_p->fpu_counter > 5)
- math_state_restore();
+ if (preload_fpu)
+ __math_state_restore();
return prev_p;
}
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d2d1ce8170f0..508e982dd072 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -249,6 +249,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
},
},
+ { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */
+ .callback = set_bios_reboot,
+ .ident = "CompuLab SBC-FITPC2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
+ },
+ },
{ }
};
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 94ad296d2730..5b0ff4b18022 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -673,6 +673,19 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
},
},
+ {
+ /*
+ * AMI BIOS with low memory corruption was found on Intel DG45ID board.
+ * It hase different DMI_BIOS_VENDOR = "Intel Corp.", for now we will
+ * match only DMI_BOARD_NAME and see if there is more bad products
+ * with this vendor.
+ */
+ .callback = dmi_low_memory_corruption,
+ .ident = "AMI BIOS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "DG45ID"),
+ },
+ },
#endif
{}
};
@@ -1091,7 +1104,6 @@ void __init x86_quirk_time_init(void)
return;
}
- irq0.mask = cpumask_of_cpu(0);
setup_irq(0, &irq0);
}
#endif /* CONFIG_X86_32 */
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 29a3eef7cf4a..7501bb14bd51 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -124,60 +124,51 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
}
/*
- * Large page remap allocator
- *
- * This allocator uses PMD page as unit. A PMD page is allocated for
- * each cpu and each is remapped into vmalloc area using PMD mapping.
- * As PMD page is quite large, only part of it is used for the first
- * chunk. Unused part is returned to the bootmem allocator.
- *
- * So, the PMD pages are mapped twice - once to the physical mapping
- * and to the vmalloc area for the first percpu chunk. The double
- * mapping does add one more PMD TLB entry pressure but still is much
- * better than only using 4k mappings while still being NUMA friendly.
+ * Helpers for first chunk memory allocation
*/
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-struct pcpul_ent {
- unsigned int cpu;
- void *ptr;
-};
+static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size)
+{
+ return pcpu_alloc_bootmem(cpu, size, size);
+}
-static size_t pcpul_size;
-static struct pcpul_ent *pcpul_map;
-static struct vm_struct pcpul_vm;
+static void __init pcpu_fc_free(void *ptr, size_t size)
+{
+ free_bootmem(__pa(ptr), size);
+}
-static struct page * __init pcpul_get_page(unsigned int cpu, int pageno)
+/*
+ * Large page remapping allocator
+ */
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+static void __init pcpul_map(void *ptr, size_t size, void *addr)
{
- size_t off = (size_t)pageno << PAGE_SHIFT;
+ pmd_t *pmd, pmd_v;
- if (off >= pcpul_size)
- return NULL;
+ pmd = populate_extra_pmd((unsigned long)addr);
+ pmd_v = pfn_pmd(page_to_pfn(virt_to_page(ptr)), PAGE_KERNEL_LARGE);
+ set_pmd(pmd, pmd_v);
+}
- return virt_to_page(pcpul_map[cpu].ptr + off);
+static int pcpu_lpage_cpu_distance(unsigned int from, unsigned int to)
+{
+ if (early_cpu_to_node(from) == early_cpu_to_node(to))
+ return LOCAL_DISTANCE;
+ else
+ return REMOTE_DISTANCE;
}
static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
{
- size_t map_size, dyn_size;
- unsigned int cpu;
- int i, j;
+ size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
+ size_t dyn_size = reserve - PERCPU_FIRST_CHUNK_RESERVE;
+ size_t unit_map_size, unit_size;
+ int *unit_map;
+ int nr_units;
ssize_t ret;
- if (!chosen) {
- size_t vm_size = VMALLOC_END - VMALLOC_START;
- size_t tot_size = num_possible_cpus() * PMD_SIZE;
-
- /* on non-NUMA, embedding is better */
- if (!pcpu_need_numa())
- return -EINVAL;
-
- /* don't consume more than 20% of vmalloc area */
- if (tot_size > vm_size / 5) {
- pr_info("PERCPU: too large chunk size %zuMB for "
- "large page remap\n", tot_size >> 20);
- return -EINVAL;
- }
- }
+ /* on non-NUMA, embedding is better */
+ if (!chosen && !pcpu_need_numa())
+ return -EINVAL;
/* need PSE */
if (!cpu_has_pse) {
@@ -185,134 +176,46 @@ static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
return -EINVAL;
}
- /*
- * Currently supports only single page. Supporting multiple
- * pages won't be too difficult if it ever becomes necessary.
- */
- pcpul_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
- PERCPU_DYNAMIC_RESERVE);
- if (pcpul_size > PMD_SIZE) {
- pr_warning("PERCPU: static data is larger than large page, "
- "can't use large page\n");
- return -EINVAL;
- }
- dyn_size = pcpul_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
-
- /* allocate pointer array and alloc large pages */
- map_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpul_map[0]));
- pcpul_map = alloc_bootmem(map_size);
-
- for_each_possible_cpu(cpu) {
- pcpul_map[cpu].cpu = cpu;
- pcpul_map[cpu].ptr = pcpu_alloc_bootmem(cpu, PMD_SIZE,
- PMD_SIZE);
- if (!pcpul_map[cpu].ptr) {
- pr_warning("PERCPU: failed to allocate large page "
- "for cpu%u\n", cpu);
- goto enomem;
- }
-
- /*
- * Only use pcpul_size bytes and give back the rest.
- *
- * Ingo: The 2MB up-rounding bootmem is needed to make
- * sure the partial 2MB page is still fully RAM - it's
- * not well-specified to have a PAT-incompatible area
- * (unmapped RAM, device memory, etc.) in that hole.
- */
- free_bootmem(__pa(pcpul_map[cpu].ptr + pcpul_size),
- PMD_SIZE - pcpul_size);
-
- memcpy(pcpul_map[cpu].ptr, __per_cpu_load, static_size);
+ /* allocate and build unit_map */
+ unit_map_size = num_possible_cpus() * sizeof(int);
+ unit_map = alloc_bootmem_nopanic(unit_map_size);
+ if (!unit_map) {
+ pr_warning("PERCPU: failed to allocate unit_map\n");
+ return -ENOMEM;
}
- /* allocate address and map */
- pcpul_vm.flags = VM_ALLOC;
- pcpul_vm.size = num_possible_cpus() * PMD_SIZE;
- vm_area_register_early(&pcpul_vm, PMD_SIZE);
-
- for_each_possible_cpu(cpu) {
- pmd_t *pmd, pmd_v;
-
- pmd = populate_extra_pmd((unsigned long)pcpul_vm.addr +
- cpu * PMD_SIZE);
- pmd_v = pfn_pmd(page_to_pfn(virt_to_page(pcpul_map[cpu].ptr)),
- PAGE_KERNEL_LARGE);
- set_pmd(pmd, pmd_v);
+ ret = pcpu_lpage_build_unit_map(static_size,
+ PERCPU_FIRST_CHUNK_RESERVE,
+ &dyn_size, &unit_size, PMD_SIZE,
+ unit_map, pcpu_lpage_cpu_distance);
+ if (ret < 0) {
+ pr_warning("PERCPU: failed to build unit_map\n");
+ goto out_free;
}
+ nr_units = ret;
- /* we're ready, commit */
- pr_info("PERCPU: Remapped at %p with large pages, static data "
- "%zu bytes\n", pcpul_vm.addr, static_size);
-
- ret = pcpu_setup_first_chunk(pcpul_get_page, static_size,
- PERCPU_FIRST_CHUNK_RESERVE, dyn_size,
- PMD_SIZE, pcpul_vm.addr, NULL);
-
- /* sort pcpul_map array for pcpu_lpage_remapped() */
- for (i = 0; i < num_possible_cpus() - 1; i++)
- for (j = i + 1; j < num_possible_cpus(); j++)
- if (pcpul_map[i].ptr > pcpul_map[j].ptr) {
- struct pcpul_ent tmp = pcpul_map[i];
- pcpul_map[i] = pcpul_map[j];
- pcpul_map[j] = tmp;
- }
-
- return ret;
-
-enomem:
- for_each_possible_cpu(cpu)
- if (pcpul_map[cpu].ptr)
- free_bootmem(__pa(pcpul_map[cpu].ptr), pcpul_size);
- free_bootmem(__pa(pcpul_map), map_size);
- return -ENOMEM;
-}
+ /* do the parameters look okay? */
+ if (!chosen) {
+ size_t vm_size = VMALLOC_END - VMALLOC_START;
+ size_t tot_size = nr_units * unit_size;
-/**
- * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area
- * @kaddr: the kernel address in question
- *
- * Determine whether @kaddr falls in the pcpul recycled area. This is
- * used by pageattr to detect VM aliases and break up the pcpu PMD
- * mapping such that the same physical page is not mapped under
- * different attributes.
- *
- * The recycled area is always at the tail of a partially used PMD
- * page.
- *
- * RETURNS:
- * Address of corresponding remapped pcpu address if match is found;
- * otherwise, NULL.
- */
-void *pcpu_lpage_remapped(void *kaddr)
-{
- void *pmd_addr = (void *)((unsigned long)kaddr & PMD_MASK);
- unsigned long offset = (unsigned long)kaddr & ~PMD_MASK;
- int left = 0, right = num_possible_cpus() - 1;
- int pos;
-
- /* pcpul in use at all? */
- if (!pcpul_map)
- return NULL;
-
- /* okay, perform binary search */
- while (left <= right) {
- pos = (left + right) / 2;
-
- if (pcpul_map[pos].ptr < pmd_addr)
- left = pos + 1;
- else if (pcpul_map[pos].ptr > pmd_addr)
- right = pos - 1;
- else {
- /* it shouldn't be in the area for the first chunk */
- WARN_ON(offset < pcpul_size);
-
- return pcpul_vm.addr +
- pcpul_map[pos].cpu * PMD_SIZE + offset;
+ /* don't consume more than 20% of vmalloc area */
+ if (tot_size > vm_size / 5) {
+ pr_info("PERCPU: too large chunk size %zuMB for "
+ "large page remap\n", tot_size >> 20);
+ ret = -EINVAL;
+ goto out_free;
}
}
- return NULL;
+ ret = pcpu_lpage_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
+ dyn_size, unit_size, PMD_SIZE,
+ unit_map, nr_units,
+ pcpu_fc_alloc, pcpu_fc_free, pcpul_map);
+out_free:
+ if (ret < 0)
+ free_bootmem(__pa(unit_map), unit_map_size);
+ return ret;
}
#else
static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
@@ -342,26 +245,15 @@ static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen)
return -EINVAL;
return pcpu_embed_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
- reserve - PERCPU_FIRST_CHUNK_RESERVE, -1);
+ reserve - PERCPU_FIRST_CHUNK_RESERVE);
}
/*
- * 4k page allocator
+ * 4k allocator
*
- * This is the basic allocator. Static percpu area is allocated
- * page-by-page and most of initialization is done by the generic
- * setup function.
+ * Boring fallback 4k allocator. This allocator puts more pressure on
+ * PTE TLBs but other than that behaves nicely on both UMA and NUMA.
*/
-static struct page **pcpu4k_pages __initdata;
-static int pcpu4k_nr_static_pages __initdata;
-
-static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno)
-{
- if (pageno < pcpu4k_nr_static_pages)
- return pcpu4k_pages[cpu * pcpu4k_nr_static_pages + pageno];
- return NULL;
-}
-
static void __init pcpu4k_populate_pte(unsigned long addr)
{
populate_extra_pte(addr);
@@ -369,51 +261,9 @@ static void __init pcpu4k_populate_pte(unsigned long addr)
static ssize_t __init setup_pcpu_4k(size_t static_size)
{
- size_t pages_size;
- unsigned int cpu;
- int i, j;
- ssize_t ret;
-
- pcpu4k_nr_static_pages = PFN_UP(static_size);
-
- /* unaligned allocations can't be freed, round up to page size */
- pages_size = PFN_ALIGN(pcpu4k_nr_static_pages * num_possible_cpus()
- * sizeof(pcpu4k_pages[0]));
- pcpu4k_pages = alloc_bootmem(pages_size);
-
- /* allocate and copy */
- j = 0;
- for_each_possible_cpu(cpu)
- for (i = 0; i < pcpu4k_nr_static_pages; i++) {
- void *ptr;
-
- ptr = pcpu_alloc_bootmem(cpu, PAGE_SIZE, PAGE_SIZE);
- if (!ptr) {
- pr_warning("PERCPU: failed to allocate "
- "4k page for cpu%u\n", cpu);
- goto enomem;
- }
-
- memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE);
- pcpu4k_pages[j++] = virt_to_page(ptr);
- }
-
- /* we're ready, commit */
- pr_info("PERCPU: Allocated %d 4k pages, static data %zu bytes\n",
- pcpu4k_nr_static_pages, static_size);
-
- ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size,
- PERCPU_FIRST_CHUNK_RESERVE, -1,
- -1, NULL, pcpu4k_populate_pte);
- goto out_free_ar;
-
-enomem:
- while (--j >= 0)
- free_bootmem(__pa(page_address(pcpu4k_pages[j])), PAGE_SIZE);
- ret = -ENOMEM;
-out_free_ar:
- free_bootmem(__pa(pcpu4k_pages), pages_size);
- return ret;
+ return pcpu_4k_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
+ pcpu_fc_alloc, pcpu_fc_free,
+ pcpu4k_populate_pte);
}
/* for explicit first chunk allocator selection */
@@ -486,7 +336,8 @@ void __init setup_per_cpu_areas(void)
/* alrighty, percpu areas up and running */
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu) {
- per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size;
+ per_cpu_offset(cpu) =
+ delta + pcpu_unit_map[cpu] * pcpu_unit_size;
per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu);
per_cpu(cpu_number, cpu) = cpu;
setup_percpu_segment(cpu);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2fecda69ee64..3ede593b14c4 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -108,6 +108,10 @@ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
DEFINE_PER_CPU(cpumask_var_t, cpu_core_map);
EXPORT_PER_CPU_SYMBOL(cpu_core_map);
+/* representing node silbings on multi-node CPU */
+DEFINE_PER_CPU(cpumask_var_t, cpu_node_map);
+EXPORT_PER_CPU_SYMBOL(cpu_node_map);
+
/* Per CPU bogomips and other parameters */
DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
EXPORT_PER_CPU_SYMBOL(cpu_info);
@@ -396,12 +400,19 @@ void __cpuinit set_cpu_sibling_map(int cpu)
}
for_each_cpu(i, cpu_sibling_setup_mask) {
+ struct cpuinfo_x86 *o = &cpu_data(i);
+
if (per_cpu(cpu_llc_id, cpu) != BAD_APICID &&
per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) {
cpumask_set_cpu(i, c->llc_shared_map);
- cpumask_set_cpu(cpu, cpu_data(i).llc_shared_map);
+ cpumask_set_cpu(cpu, o->llc_shared_map);
+ }
+ if ((c->phys_proc_id == o->phys_proc_id) &&
+ (c->cpu_node_id == o->cpu_node_id)) {
+ cpumask_set_cpu(i, cpu_node_mask(cpu));
+ cpumask_set_cpu(cpu, cpu_node_mask(i));
}
- if (c->phys_proc_id == cpu_data(i).phys_proc_id) {
+ if (c->phys_proc_id == o->phys_proc_id) {
cpumask_set_cpu(i, cpu_core_mask(cpu));
cpumask_set_cpu(cpu, cpu_core_mask(i));
/*
@@ -419,9 +430,9 @@ void __cpuinit set_cpu_sibling_map(int cpu)
* the other cpus in this package
*/
if (i != cpu)
- cpu_data(i).booted_cores++;
+ o->booted_cores++;
} else if (i != cpu && !c->booted_cores)
- c->booted_cores = cpu_data(i).booted_cores;
+ c->booted_cores = o->booted_cores;
}
}
}
@@ -1057,12 +1068,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
#endif
current_thread_info()->cpu = 0; /* needed? */
for_each_possible_cpu(i) {
- alloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
- alloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
- alloc_cpumask_var(&cpu_data(i).llc_shared_map, GFP_KERNEL);
- cpumask_clear(per_cpu(cpu_core_map, i));
- cpumask_clear(per_cpu(cpu_sibling_map, i));
- cpumask_clear(cpu_data(i).llc_shared_map);
+ zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
+ zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
+ zalloc_cpumask_var(&cpu_data(i).llc_shared_map, GFP_KERNEL);
}
set_cpu_sibling_map(0);
@@ -1220,6 +1228,7 @@ static void remove_siblinginfo(int cpu)
cpumask_clear(cpu_sibling_mask(cpu));
cpumask_clear(cpu_core_mask(cpu));
c->phys_proc_id = 0;
+ c->cpu_node_id = 0;
c->cpu_core_id = 0;
cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 5204332f475d..22a5a6d9d371 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -816,6 +816,28 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void)
}
/*
+ * __math_state_restore assumes that cr0.TS is already clear and the
+ * fpu state is all ready for use. Used during context switch.
+ */
+void __math_state_restore(void)
+{
+ struct thread_info *thread = current_thread_info();
+ struct task_struct *tsk = thread->task;
+
+ /*
+ * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+ */
+ if (unlikely(restore_fpu_checking(tsk))) {
+ stts();
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
+
+ thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
+ tsk->fpu_counter++;
+}
+
+/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
*
@@ -846,17 +868,8 @@ asmlinkage void math_state_restore(void)
}
clts(); /* Allow maths ops (or we recurse) */
- /*
- * Paranoid restore. send a SIGSEGV if we fail to restore the state.
- */
- if (unlikely(restore_fpu_checking(tsk))) {
- stts();
- force_sig(SIGSEGV, tsk);
- return;
- }
- thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
- tsk->fpu_counter++;
+ __math_state_restore();
}
EXPORT_SYMBOL_GPL(math_state_restore);
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 367e87882041..93923725c336 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -112,11 +112,6 @@ SECTIONS
_sdata = .;
DATA_DATA
CONSTRUCTORS
-
-#ifdef CONFIG_X86_64
- /* End of data section */
- _edata = .;
-#endif
} :data
#ifdef CONFIG_X86_32
@@ -156,10 +151,8 @@ SECTIONS
.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
*(.data.read_mostly)
-#ifdef CONFIG_X86_32
/* End of data section */
_edata = .;
-#endif
}
#ifdef CONFIG_X86_64
@@ -387,15 +380,12 @@ SECTIONS
_end = .;
}
- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exitcall.exit)
- *(.eh_frame)
- *(.discard)
- }
-
STABS_DEBUG
DWARF_DEBUG
+
+ /* Sections to be discarded */
+ DISCARDS
+ /DISCARD/ : { *(.eh_frame) }
}
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 8600a09e0c6c..b84e571f4175 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -1,12 +1,8 @@
#
# KVM configuration
#
-config HAVE_KVM
- bool
-config HAVE_KVM_IRQCHIP
- bool
- default y
+source "virt/kvm/Kconfig"
menuconfig VIRTUALIZATION
bool "Virtualization"
@@ -29,6 +25,9 @@ config KVM
select PREEMPT_NOTIFIERS
select MMU_NOTIFIER
select ANON_INODES
+ select HAVE_KVM_IRQCHIP
+ select HAVE_KVM_EVENTFD
+ select KVM_APIC_ARCHITECTURE
---help---
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
@@ -63,18 +62,6 @@ config KVM_AMD
To compile this as a module, choose M here: the module
will be called kvm-amd.
-config KVM_TRACE
- bool "KVM trace support"
- depends on KVM && SYSFS
- select MARKERS
- select RELAY
- select DEBUG_FS
- default n
- ---help---
- This option allows reading a trace of kvm-related events through
- relayfs. Note the ABI is not considered stable and will be
- modified in future updates.
-
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
source drivers/lguest/Kconfig
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index b43c4efafe80..afaaa7627d95 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -1,22 +1,19 @@
-#
-# Makefile for Kernel-based Virtual Machine module
-#
-
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
- coalesced_mmio.o irq_comm.o)
-ifeq ($(CONFIG_KVM_TRACE),y)
-common-objs += $(addprefix ../../../virt/kvm/, kvm_trace.o)
-endif
-ifeq ($(CONFIG_IOMMU_API),y)
-common-objs += $(addprefix ../../../virt/kvm/, iommu.o)
-endif
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
-kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
- i8254.o timer.o
-obj-$(CONFIG_KVM) += kvm.o
-kvm-intel-objs = vmx.o
-obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
-kvm-amd-objs = svm.o
-obj-$(CONFIG_KVM_AMD) += kvm-amd.o
+CFLAGS_x86.o := -I.
+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)
+kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o)
+
+kvm-y += x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
+ i8254.o timer.o
+kvm-intel-y += vmx.o
+kvm-amd-y += svm.o
+
+obj-$(CONFIG_KVM) += kvm.o
+obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
+obj-$(CONFIG_KVM_AMD) += kvm-amd.o
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 4d6f0d293ee2..472653c15a2a 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -104,6 +104,9 @@ static s64 __kpit_elapsed(struct kvm *kvm)
ktime_t remaining;
struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
+ if (!ps->pit_timer.period)
+ return 0;
+
/*
* The Counter does not stop when it reaches zero. In
* Modes 0, 1, 4, and 5 the Counter ``wraps around'' to
@@ -228,7 +231,7 @@ int pit_has_pending_timer(struct kvm_vcpu *vcpu)
{
struct kvm_pit *pit = vcpu->kvm->arch.vpit;
- if (pit && vcpu->vcpu_id == 0 && pit->pit_state.irq_ack)
+ if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack)
return atomic_read(&pit->pit_state.pit_timer.pending);
return 0;
}
@@ -249,7 +252,7 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
struct kvm_pit *pit = vcpu->kvm->arch.vpit;
struct hrtimer *timer;
- if (vcpu->vcpu_id != 0 || !pit)
+ if (!kvm_vcpu_is_bsp(vcpu) || !pit)
return;
timer = &pit->pit_state.pit_timer.timer;
@@ -291,7 +294,7 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
pt->timer.function = kvm_timer_fn;
pt->t_ops = &kpit_ops;
pt->kvm = ps->pit->kvm;
- pt->vcpu_id = 0;
+ pt->vcpu = pt->kvm->bsp_vcpu;
atomic_set(&pt->pending, 0);
ps->irq_ack = 1;
@@ -329,33 +332,62 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
case 1:
/* FIXME: enhance mode 4 precision */
case 4:
- create_pit_timer(ps, val, 0);
+ if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)) {
+ create_pit_timer(ps, val, 0);
+ }
break;
case 2:
case 3:
- create_pit_timer(ps, val, 1);
+ if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)){
+ create_pit_timer(ps, val, 1);
+ }
break;
default:
destroy_pit_timer(&ps->pit_timer);
}
}
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val)
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start)
+{
+ u8 saved_mode;
+ if (hpet_legacy_start) {
+ /* save existing mode for later reenablement */
+ saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
+ kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
+ pit_load_count(kvm, channel, val);
+ kvm->arch.vpit->pit_state.channels[0].mode = saved_mode;
+ } else {
+ pit_load_count(kvm, channel, val);
+ }
+}
+
+static inline struct kvm_pit *dev_to_pit(struct kvm_io_device *dev)
+{
+ return container_of(dev, struct kvm_pit, dev);
+}
+
+static inline struct kvm_pit *speaker_to_pit(struct kvm_io_device *dev)
{
- mutex_lock(&kvm->arch.vpit->pit_state.lock);
- pit_load_count(kvm, channel, val);
- mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+ return container_of(dev, struct kvm_pit, speaker_dev);
}
-static void pit_ioport_write(struct kvm_io_device *this,
- gpa_t addr, int len, const void *data)
+static inline int pit_in_range(gpa_t addr)
{
- struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ return ((addr >= KVM_PIT_BASE_ADDRESS) &&
+ (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
+}
+
+static int pit_ioport_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *data)
+{
+ struct kvm_pit *pit = dev_to_pit(this);
struct kvm_kpit_state *pit_state = &pit->pit_state;
struct kvm *kvm = pit->kvm;
int channel, access;
struct kvm_kpit_channel_state *s;
u32 val = *(u32 *) data;
+ if (!pit_in_range(addr))
+ return -EOPNOTSUPP;
val &= 0xff;
addr &= KVM_PIT_CHANNEL_MASK;
@@ -418,16 +450,19 @@ static void pit_ioport_write(struct kvm_io_device *this,
}
mutex_unlock(&pit_state->lock);
+ return 0;
}
-static void pit_ioport_read(struct kvm_io_device *this,
- gpa_t addr, int len, void *data)
+static int pit_ioport_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *data)
{
- struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_pit *pit = dev_to_pit(this);
struct kvm_kpit_state *pit_state = &pit->pit_state;
struct kvm *kvm = pit->kvm;
int ret, count;
struct kvm_kpit_channel_state *s;
+ if (!pit_in_range(addr))
+ return -EOPNOTSUPP;
addr &= KVM_PIT_CHANNEL_MASK;
s = &pit_state->channels[addr];
@@ -482,37 +517,36 @@ static void pit_ioport_read(struct kvm_io_device *this,
memcpy(data, (char *)&ret, len);
mutex_unlock(&pit_state->lock);
+ return 0;
}
-static int pit_in_range(struct kvm_io_device *this, gpa_t addr,
- int len, int is_write)
-{
- return ((addr >= KVM_PIT_BASE_ADDRESS) &&
- (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
-}
-
-static void speaker_ioport_write(struct kvm_io_device *this,
- gpa_t addr, int len, const void *data)
+static int speaker_ioport_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *data)
{
- struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_pit *pit = speaker_to_pit(this);
struct kvm_kpit_state *pit_state = &pit->pit_state;
struct kvm *kvm = pit->kvm;
u32 val = *(u32 *) data;
+ if (addr != KVM_SPEAKER_BASE_ADDRESS)
+ return -EOPNOTSUPP;
mutex_lock(&pit_state->lock);
pit_state->speaker_data_on = (val >> 1) & 1;
pit_set_gate(kvm, 2, val & 1);
mutex_unlock(&pit_state->lock);
+ return 0;
}
-static void speaker_ioport_read(struct kvm_io_device *this,
- gpa_t addr, int len, void *data)
+static int speaker_ioport_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *data)
{
- struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_pit *pit = speaker_to_pit(this);
struct kvm_kpit_state *pit_state = &pit->pit_state;
struct kvm *kvm = pit->kvm;
unsigned int refresh_clock;
int ret;
+ if (addr != KVM_SPEAKER_BASE_ADDRESS)
+ return -EOPNOTSUPP;
/* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1;
@@ -524,12 +558,7 @@ static void speaker_ioport_read(struct kvm_io_device *this,
len = sizeof(ret);
memcpy(data, (char *)&ret, len);
mutex_unlock(&pit_state->lock);
-}
-
-static int speaker_in_range(struct kvm_io_device *this, gpa_t addr,
- int len, int is_write)
-{
- return (addr == KVM_SPEAKER_BASE_ADDRESS);
+ return 0;
}
void kvm_pit_reset(struct kvm_pit *pit)
@@ -538,6 +567,7 @@ void kvm_pit_reset(struct kvm_pit *pit)
struct kvm_kpit_channel_state *c;
mutex_lock(&pit->pit_state.lock);
+ pit->pit_state.flags = 0;
for (i = 0; i < 3; i++) {
c = &pit->pit_state.channels[i];
c->mode = 0xff;
@@ -560,10 +590,22 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
}
}
-struct kvm_pit *kvm_create_pit(struct kvm *kvm)
+static const struct kvm_io_device_ops pit_dev_ops = {
+ .read = pit_ioport_read,
+ .write = pit_ioport_write,
+};
+
+static const struct kvm_io_device_ops speaker_dev_ops = {
+ .read = speaker_ioport_read,
+ .write = speaker_ioport_write,
+};
+
+/* Caller must have writers lock on slots_lock */
+struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
{
struct kvm_pit *pit;
struct kvm_kpit_state *pit_state;
+ int ret;
pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
if (!pit)
@@ -579,19 +621,6 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm)
mutex_lock(&pit->pit_state.lock);
spin_lock_init(&pit->pit_state.inject_lock);
- /* Initialize PIO device */
- pit->dev.read = pit_ioport_read;
- pit->dev.write = pit_ioport_write;
- pit->dev.in_range = pit_in_range;
- pit->dev.private = pit;
- kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
-
- pit->speaker_dev.read = speaker_ioport_read;
- pit->speaker_dev.write = speaker_ioport_write;
- pit->speaker_dev.in_range = speaker_in_range;
- pit->speaker_dev.private = pit;
- kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
-
kvm->arch.vpit = pit;
pit->kvm = kvm;
@@ -610,7 +639,30 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm)
pit->mask_notifier.func = pit_mask_notifer;
kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
+ kvm_iodevice_init(&pit->dev, &pit_dev_ops);
+ ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+ if (ret < 0)
+ goto fail;
+
+ if (flags & KVM_PIT_SPEAKER_DUMMY) {
+ kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
+ ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
+ &pit->speaker_dev);
+ if (ret < 0)
+ goto fail_unregister;
+ }
+
return pit;
+
+fail_unregister:
+ __kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);
+
+fail:
+ if (pit->irq_source_id >= 0)
+ kvm_free_irq_source_id(kvm, pit->irq_source_id);
+
+ kfree(pit);
+ return NULL;
}
void kvm_free_pit(struct kvm *kvm)
@@ -620,6 +672,8 @@ void kvm_free_pit(struct kvm *kvm)
if (kvm->arch.vpit) {
kvm_unregister_irq_mask_notifier(kvm, 0,
&kvm->arch.vpit->mask_notifier);
+ kvm_unregister_irq_ack_notifier(kvm,
+ &kvm->arch.vpit->pit_state.irq_ack_notifier);
mutex_lock(&kvm->arch.vpit->pit_state.lock);
timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
hrtimer_cancel(timer);
@@ -634,10 +688,10 @@ static void __inject_pit_timer_intr(struct kvm *kvm)
struct kvm_vcpu *vcpu;
int i;
- mutex_lock(&kvm->lock);
+ 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->lock);
+ mutex_unlock(&kvm->irq_lock);
/*
* Provides NMI watchdog support via Virtual Wire mode.
@@ -649,11 +703,8 @@ static void __inject_pit_timer_intr(struct kvm *kvm)
* VCPU0, and only if its LVT0 is in EXTINT mode.
*/
if (kvm->arch.vapics_in_nmi_mode > 0)
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (vcpu)
- kvm_apic_nmi_wd_deliver(vcpu);
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_apic_nmi_wd_deliver(vcpu);
}
void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index bbd863ff60b7..d4c1c7ffdc09 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -21,6 +21,7 @@ struct kvm_kpit_channel_state {
struct kvm_kpit_state {
struct kvm_kpit_channel_state channels[3];
+ u32 flags;
struct kvm_timer pit_timer;
bool is_periodic;
u32 speaker_data_on;
@@ -49,8 +50,8 @@ struct kvm_pit {
#define KVM_PIT_CHANNEL_MASK 0x3
void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val);
-struct kvm_pit *kvm_create_pit(struct kvm *kvm);
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start);
+struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags);
void kvm_free_pit(struct kvm *kvm);
void kvm_pit_reset(struct kvm_pit *pit);
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 1ccb50c74f18..daf4606b0293 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -30,6 +30,7 @@
#include "irq.h"
#include <linux/kvm_host.h>
+#include "trace.h"
static void pic_lock(struct kvm_pic *s)
__acquires(&s->lock)
@@ -57,7 +58,7 @@ static void pic_unlock(struct kvm_pic *s)
}
if (wakeup) {
- vcpu = s->kvm->vcpus[0];
+ vcpu = s->kvm->bsp_vcpu;
if (vcpu)
kvm_vcpu_kick(vcpu);
}
@@ -72,8 +73,10 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
void kvm_pic_clear_isr_ack(struct kvm *kvm)
{
struct kvm_pic *s = pic_irqchip(kvm);
+ pic_lock(s);
s->pics[0].isr_ack = 0xff;
s->pics[1].isr_ack = 0xff;
+ pic_unlock(s);
}
/*
@@ -188,6 +191,8 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
if (irq >= 0 && irq < PIC_NUM_PINS) {
ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
pic_update_irq(s);
+ trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr,
+ s->pics[irq >> 3].imr, ret == 0);
}
pic_unlock(s);
@@ -252,7 +257,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s)
{
int irq, irqbase, n;
struct kvm *kvm = s->pics_state->irq_request_opaque;
- struct kvm_vcpu *vcpu0 = kvm->vcpus[0];
+ struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
if (s == &s->pics_state->pics[0])
irqbase = 0;
@@ -428,8 +433,7 @@ static u32 elcr_ioport_read(void *opaque, u32 addr1)
return s->elcr;
}
-static int picdev_in_range(struct kvm_io_device *this, gpa_t addr,
- int len, int is_write)
+static int picdev_in_range(gpa_t addr)
{
switch (addr) {
case 0x20:
@@ -444,16 +448,23 @@ static int picdev_in_range(struct kvm_io_device *this, gpa_t addr,
}
}
-static void picdev_write(struct kvm_io_device *this,
+static inline struct kvm_pic *to_pic(struct kvm_io_device *dev)
+{
+ return container_of(dev, struct kvm_pic, dev);
+}
+
+static int picdev_write(struct kvm_io_device *this,
gpa_t addr, int len, const void *val)
{
- struct kvm_pic *s = this->private;
+ struct kvm_pic *s = to_pic(this);
unsigned char data = *(unsigned char *)val;
+ if (!picdev_in_range(addr))
+ return -EOPNOTSUPP;
if (len != 1) {
if (printk_ratelimit())
printk(KERN_ERR "PIC: non byte write\n");
- return;
+ return 0;
}
pic_lock(s);
switch (addr) {
@@ -469,18 +480,21 @@ static void picdev_write(struct kvm_io_device *this,
break;
}
pic_unlock(s);
+ return 0;
}
-static void picdev_read(struct kvm_io_device *this,
- gpa_t addr, int len, void *val)
+static int picdev_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *val)
{
- struct kvm_pic *s = this->private;
+ struct kvm_pic *s = to_pic(this);
unsigned char data = 0;
+ if (!picdev_in_range(addr))
+ return -EOPNOTSUPP;
if (len != 1) {
if (printk_ratelimit())
printk(KERN_ERR "PIC: non byte read\n");
- return;
+ return 0;
}
pic_lock(s);
switch (addr) {
@@ -497,6 +511,7 @@ static void picdev_read(struct kvm_io_device *this,
}
*(unsigned char *)val = data;
pic_unlock(s);
+ return 0;
}
/*
@@ -505,7 +520,7 @@ static void picdev_read(struct kvm_io_device *this,
static void pic_irq_request(void *opaque, int level)
{
struct kvm *kvm = opaque;
- struct kvm_vcpu *vcpu = kvm->vcpus[0];
+ struct kvm_vcpu *vcpu = kvm->bsp_vcpu;
struct kvm_pic *s = pic_irqchip(kvm);
int irq = pic_get_irq(&s->pics[0]);
@@ -516,9 +531,16 @@ static void pic_irq_request(void *opaque, int level)
}
}
+static const struct kvm_io_device_ops picdev_ops = {
+ .read = picdev_read,
+ .write = picdev_write,
+};
+
struct kvm_pic *kvm_create_pic(struct kvm *kvm)
{
struct kvm_pic *s;
+ int ret;
+
s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
if (!s)
return NULL;
@@ -534,10 +556,12 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
/*
* Initialize PIO device
*/
- s->dev.read = picdev_read;
- s->dev.write = picdev_write;
- s->dev.in_range = picdev_in_range;
- s->dev.private = s;
- kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev);
+ kvm_iodevice_init(&s->dev, &picdev_ops);
+ ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+ if (ret < 0) {
+ kfree(s);
+ return NULL;
+ }
+
return s;
}
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h
index 1ff819dce7d3..7bcc5b6a4403 100644
--- a/arch/x86/kvm/kvm_cache_regs.h
+++ b/arch/x86/kvm/kvm_cache_regs.h
@@ -29,4 +29,13 @@ static inline void kvm_rip_write(struct kvm_vcpu *vcpu, unsigned long val)
kvm_register_write(vcpu, VCPU_REGS_RIP, val);
}
+static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
+{
+ if (!test_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_avail))
+ kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR);
+
+ return vcpu->arch.pdptrs[index];
+}
+
#endif
diff --git a/arch/x86/kvm/kvm_svm.h b/arch/x86/kvm/kvm_svm.h
deleted file mode 100644
index ed66e4c078dc..000000000000
--- a/arch/x86/kvm/kvm_svm.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __KVM_SVM_H
-#define __KVM_SVM_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/kvm_host.h>
-#include <asm/msr.h>
-
-#include <asm/svm.h>
-
-static const u32 host_save_user_msrs[] = {
-#ifdef CONFIG_X86_64
- MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
- MSR_FS_BASE,
-#endif
- MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-};
-
-#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
-
-struct kvm_vcpu;
-
-struct vcpu_svm {
- struct kvm_vcpu vcpu;
- struct vmcb *vmcb;
- unsigned long vmcb_pa;
- struct svm_cpu_data *svm_data;
- uint64_t asid_generation;
-
- u64 next_rip;
-
- u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
- u64 host_gs_base;
- unsigned long host_cr2;
-
- u32 *msrpm;
- struct vmcb *hsave;
- u64 hsave_msr;
-
- u64 nested_vmcb;
-
- /* These are the merged vectors */
- u32 *nested_msrpm;
-
- /* gpa pointers to the real vectors */
- u64 nested_vmcb_msrpm;
-};
-
-#endif
-
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
index 26bd6ba74e1c..55c7524dda54 100644
--- a/arch/x86/kvm/kvm_timer.h
+++ b/arch/x86/kvm/kvm_timer.h
@@ -6,7 +6,7 @@ struct kvm_timer {
bool reinject;
struct kvm_timer_ops *t_ops;
struct kvm *kvm;
- int vcpu_id;
+ struct kvm_vcpu *vcpu;
};
struct kvm_timer_ops {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ae99d83f81a3..6c3cd2cc8be5 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,8 +32,11 @@
#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"
+#include "x86.h"
#ifndef CONFIG_X86_64
#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -141,6 +144,26 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val)
return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI;
}
+void kvm_apic_set_version(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+ struct kvm_cpuid_entry2 *feat;
+ u32 v = APIC_VERSION;
+
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return;
+
+ feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
+ if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))))
+ v |= APIC_LVR_DIRECTED_EOI;
+ apic_set_reg(apic, APIC_LVR, v);
+}
+
+static inline int apic_x2apic_mode(struct kvm_lapic *apic)
+{
+ return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
+}
+
static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
@@ -165,36 +188,52 @@ static int find_highest_vector(void *bitmap)
static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
{
+ apic->irr_pending = true;
return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
}
-static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
+static inline int apic_search_irr(struct kvm_lapic *apic)
{
- apic_clear_vector(vec, apic->regs + APIC_IRR);
+ return find_highest_vector(apic->regs + APIC_IRR);
}
static inline int apic_find_highest_irr(struct kvm_lapic *apic)
{
int result;
- result = find_highest_vector(apic->regs + APIC_IRR);
+ if (!apic->irr_pending)
+ return -1;
+
+ result = apic_search_irr(apic);
ASSERT(result == -1 || result >= 16);
return result;
}
+static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
+{
+ apic->irr_pending = false;
+ apic_clear_vector(vec, apic->regs + APIC_IRR);
+ if (apic_search_irr(apic) != -1)
+ apic->irr_pending = true;
+}
+
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
int highest_irr;
+ /* This may race with setting of irr in __apic_accept_irq() and
+ * value returned may be wrong, but kvm_vcpu_kick() in __apic_accept_irq
+ * will cause vmexit immediately and the value will be recalculated
+ * on the next vmentry.
+ */
if (!apic)
return 0;
highest_irr = apic_find_highest_irr(apic);
return highest_irr;
}
-EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
int vector, int level, int trig_mode);
@@ -251,7 +290,12 @@ int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
{
int result = 0;
- u8 logical_id;
+ u32 logical_id;
+
+ if (apic_x2apic_mode(apic)) {
+ logical_id = apic_get_reg(apic, APIC_LDR);
+ return logical_id & mda;
+ }
logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
@@ -331,6 +375,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
break;
result = !apic_test_and_set_irr(vector, apic);
+ trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode,
+ trig_mode, vector, result);
if (!result) {
if (trig_mode)
apic_debug("level trig mode repeatedly for "
@@ -425,7 +471,11 @@ static void apic_set_eoi(struct kvm_lapic *apic)
trigger_mode = IOAPIC_LEVEL_TRIG;
else
trigger_mode = IOAPIC_EDGE_TRIG;
- kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
+ if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
+ mutex_lock(&apic->vcpu->kvm->irq_lock);
+ 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)
@@ -440,7 +490,12 @@ static void apic_send_ipi(struct kvm_lapic *apic)
irq.level = icr_low & APIC_INT_ASSERT;
irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
irq.shorthand = icr_low & APIC_SHORT_MASK;
- irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
+ if (apic_x2apic_mode(apic))
+ irq.dest_id = icr_high;
+ else
+ irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
+
+ trace_kvm_apic_ipi(icr_low, irq.dest_id);
apic_debug("icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
@@ -449,7 +504,9 @@ 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)
@@ -495,12 +552,13 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
{
u32 val = 0;
- KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler);
-
if (offset >= LAPIC_MMIO_LENGTH)
return 0;
switch (offset) {
+ case APIC_ID:
+ apic_get_reg(apic, offset);
+ break;
case APIC_ARBPRI:
printk(KERN_WARNING "Access APIC ARBPRI register "
"which is for P6\n");
@@ -522,21 +580,35 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
return val;
}
-static void apic_mmio_read(struct kvm_io_device *this,
- gpa_t address, int len, void *data)
+static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
+{
+ return container_of(dev, struct kvm_lapic, dev);
+}
+
+static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
+ void *data)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
- unsigned int offset = address - apic->base_address;
unsigned char alignment = offset & 0xf;
u32 result;
+ /* this bitmask has a bit cleared for each reserver register */
+ static const u64 rmask = 0x43ff01ffffffe70cULL;
if ((alignment + len) > 4) {
- printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
- (unsigned long)address, len);
- return;
+ apic_debug("KVM_APIC_READ: alignment error %x %d\n",
+ offset, len);
+ return 1;
}
+
+ if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) {
+ apic_debug("KVM_APIC_READ: read reserved register %x\n",
+ offset);
+ return 1;
+ }
+
result = __apic_read(apic, offset & ~0xf);
+ trace_kvm_apic_read(offset, result);
+
switch (len) {
case 1:
case 2:
@@ -548,6 +620,28 @@ static void apic_mmio_read(struct kvm_io_device *this,
"should be 1,2, or 4 instead\n", len);
break;
}
+ return 0;
+}
+
+static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
+{
+ return apic_hw_enabled(apic) &&
+ addr >= apic->base_address &&
+ addr < apic->base_address + LAPIC_MMIO_LENGTH;
+}
+
+static int apic_mmio_read(struct kvm_io_device *this,
+ gpa_t address, int len, void *data)
+{
+ struct kvm_lapic *apic = to_lapic(this);
+ u32 offset = address - apic->base_address;
+
+ if (!apic_mmio_in_range(apic, address))
+ return -EOPNOTSUPP;
+
+ apic_reg_read(apic, offset, len, data);
+
+ return 0;
}
static void update_divide_count(struct kvm_lapic *apic)
@@ -603,40 +697,18 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
apic->vcpu->kvm->arch.vapics_in_nmi_mode--;
}
-static void apic_mmio_write(struct kvm_io_device *this,
- gpa_t address, int len, const void *data)
+static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
- unsigned int offset = address - apic->base_address;
- unsigned char alignment = offset & 0xf;
- u32 val;
-
- /*
- * APIC register must be aligned on 128-bits boundary.
- * 32/64/128 bits registers must be accessed thru 32 bits.
- * Refer SDM 8.4.1
- */
- if (len != 4 || alignment) {
- /* Don't shout loud, $infamous_os would cause only noise. */
- apic_debug("apic write: bad size=%d %lx\n",
- len, (long)address);
- return;
- }
-
- val = *(u32 *) data;
-
- /* too common printing */
- if (offset != APIC_EOI)
- apic_debug("%s: offset 0x%x with length 0x%x, and value is "
- "0x%x\n", __func__, offset, len, val);
-
- offset &= 0xff0;
+ int ret = 0;
- KVMTRACE_1D(APIC_ACCESS, apic->vcpu, (u32)offset, handler);
+ trace_kvm_apic_write(reg, val);
- switch (offset) {
+ switch (reg) {
case APIC_ID: /* Local APIC ID */
- apic_set_reg(apic, APIC_ID, val);
+ if (!apic_x2apic_mode(apic))
+ apic_set_reg(apic, APIC_ID, val);
+ else
+ ret = 1;
break;
case APIC_TASKPRI:
@@ -649,15 +721,24 @@ static void apic_mmio_write(struct kvm_io_device *this,
break;
case APIC_LDR:
- apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
+ if (!apic_x2apic_mode(apic))
+ apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
+ else
+ ret = 1;
break;
case APIC_DFR:
- apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+ if (!apic_x2apic_mode(apic))
+ apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+ else
+ ret = 1;
break;
- case APIC_SPIV:
- apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
+ case APIC_SPIV: {
+ u32 mask = 0x3ff;
+ if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
+ mask |= APIC_SPIV_DIRECTED_EOI;
+ apic_set_reg(apic, APIC_SPIV, val & mask);
if (!(val & APIC_SPIV_APIC_ENABLED)) {
int i;
u32 lvt_val;
@@ -672,7 +753,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
}
break;
-
+ }
case APIC_ICR:
/* No delay here, so we always clear the pending bit */
apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
@@ -680,7 +761,9 @@ static void apic_mmio_write(struct kvm_io_device *this,
break;
case APIC_ICR2:
- apic_set_reg(apic, APIC_ICR2, val & 0xff000000);
+ if (!apic_x2apic_mode(apic))
+ val &= 0xff000000;
+ apic_set_reg(apic, APIC_ICR2, val);
break;
case APIC_LVT0:
@@ -694,8 +777,8 @@ static void apic_mmio_write(struct kvm_io_device *this,
if (!apic_sw_enabled(apic))
val |= APIC_LVT_MASKED;
- val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4];
- apic_set_reg(apic, offset, val);
+ val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
+ apic_set_reg(apic, reg, val);
break;
@@ -703,7 +786,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
hrtimer_cancel(&apic->lapic_timer.timer);
apic_set_reg(apic, APIC_TMICT, val);
start_apic_timer(apic);
- return;
+ break;
case APIC_TDCR:
if (val & 4)
@@ -712,27 +795,59 @@ static void apic_mmio_write(struct kvm_io_device *this,
update_divide_count(apic);
break;
+ case APIC_ESR:
+ if (apic_x2apic_mode(apic) && val != 0) {
+ printk(KERN_ERR "KVM_WRITE:ESR not zero %x\n", val);
+ ret = 1;
+ }
+ break;
+
+ case APIC_SELF_IPI:
+ if (apic_x2apic_mode(apic)) {
+ apic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff));
+ } else
+ ret = 1;
+ break;
default:
- apic_debug("Local APIC Write to read-only register %x\n",
- offset);
+ ret = 1;
break;
}
-
+ if (ret)
+ apic_debug("Local APIC Write to read-only register %x\n", reg);
+ return ret;
}
-static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr,
- int len, int size)
+static int apic_mmio_write(struct kvm_io_device *this,
+ gpa_t address, int len, const void *data)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
- int ret = 0;
+ struct kvm_lapic *apic = to_lapic(this);
+ unsigned int offset = address - apic->base_address;
+ u32 val;
+ if (!apic_mmio_in_range(apic, address))
+ return -EOPNOTSUPP;
- if (apic_hw_enabled(apic) &&
- (addr >= apic->base_address) &&
- (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
- ret = 1;
+ /*
+ * APIC register must be aligned on 128-bits boundary.
+ * 32/64/128 bits registers must be accessed thru 32 bits.
+ * Refer SDM 8.4.1
+ */
+ if (len != 4 || (offset & 0xf)) {
+ /* Don't shout loud, $infamous_os would cause only noise. */
+ apic_debug("apic write: bad size=%d %lx\n", len, (long)address);
+ return 0;
+ }
- return ret;
+ val = *(u32*)data;
+
+ /* too common printing */
+ if (offset != APIC_EOI)
+ apic_debug("%s: offset 0x%x with length 0x%x, and value is "
+ "0x%x\n", __func__, offset, len, val);
+
+ apic_reg_write(apic, offset & 0xff0, val);
+
+ return 0;
}
void kvm_free_lapic(struct kvm_vcpu *vcpu)
@@ -763,7 +878,6 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
| (apic_get_reg(apic, APIC_TASKPRI) & 4));
}
-EXPORT_SYMBOL_GPL(kvm_lapic_set_tpr);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
{
@@ -776,7 +890,6 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
return (tpr & 0xf0) >> 4;
}
-EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
{
@@ -787,10 +900,16 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
vcpu->arch.apic_base = value;
return;
}
- if (apic->vcpu->vcpu_id)
+
+ if (!kvm_vcpu_is_bsp(apic->vcpu))
value &= ~MSR_IA32_APICBASE_BSP;
vcpu->arch.apic_base = value;
+ if (apic_x2apic_mode(apic)) {
+ u32 id = kvm_apic_id(apic);
+ u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
+ apic_set_reg(apic, APIC_LDR, ldr);
+ }
apic->base_address = apic->vcpu->arch.apic_base &
MSR_IA32_APICBASE_BASE;
@@ -800,12 +919,6 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
}
-u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
-{
- return vcpu->arch.apic_base;
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
-
void kvm_lapic_reset(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic;
@@ -821,7 +934,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
hrtimer_cancel(&apic->lapic_timer.timer);
apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
- apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+ kvm_apic_set_version(apic->vcpu);
for (i = 0; i < APIC_LVT_NUM; i++)
apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
@@ -842,9 +955,10 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
}
+ apic->irr_pending = false;
update_divide_count(apic);
atomic_set(&apic->lapic_timer.pending, 0);
- if (vcpu->vcpu_id == 0)
+ if (kvm_vcpu_is_bsp(vcpu))
vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
apic_update_ppr(apic);
@@ -855,7 +969,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
vcpu, kvm_apic_id(apic),
vcpu->arch.apic_base, apic->base_address);
}
-EXPORT_SYMBOL_GPL(kvm_lapic_reset);
bool kvm_apic_present(struct kvm_vcpu *vcpu)
{
@@ -866,7 +979,6 @@ int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
{
return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
}
-EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
/*
*----------------------------------------------------------------------
@@ -917,6 +1029,11 @@ static struct kvm_timer_ops lapic_timer_ops = {
.is_periodic = lapic_is_periodic,
};
+static const struct kvm_io_device_ops apic_mmio_ops = {
+ .read = apic_mmio_read,
+ .write = apic_mmio_write,
+};
+
int kvm_create_lapic(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic;
@@ -945,16 +1062,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
apic->lapic_timer.timer.function = kvm_timer_fn;
apic->lapic_timer.t_ops = &lapic_timer_ops;
apic->lapic_timer.kvm = vcpu->kvm;
- apic->lapic_timer.vcpu_id = vcpu->vcpu_id;
+ apic->lapic_timer.vcpu = vcpu;
apic->base_address = APIC_DEFAULT_PHYS_BASE;
vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
kvm_lapic_reset(vcpu);
- apic->dev.read = apic_mmio_read;
- apic->dev.write = apic_mmio_write;
- apic->dev.in_range = apic_mmio_range;
- apic->dev.private = apic;
+ kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
return 0;
nomem_free_apic:
@@ -962,7 +1076,6 @@ nomem_free_apic:
nomem:
return -ENOMEM;
}
-EXPORT_SYMBOL_GPL(kvm_create_lapic);
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
{
@@ -985,7 +1098,7 @@ int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
int r = 0;
- if (vcpu->vcpu_id == 0) {
+ if (kvm_vcpu_is_bsp(vcpu)) {
if (!apic_hw_enabled(vcpu->arch.apic))
r = 1;
if ((lvt0 & APIC_LVT_MASKED) == 0 &&
@@ -1025,7 +1138,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
apic->base_address = vcpu->arch.apic_base &
MSR_IA32_APICBASE_BASE;
- apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+ kvm_apic_set_version(vcpu);
+
apic_update_ppr(apic);
hrtimer_cancel(&apic->lapic_timer.timer);
update_divide_count(apic);
@@ -1092,3 +1206,35 @@ void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
vcpu->arch.apic->vapic_addr = vapic_addr;
}
+
+int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+ u32 reg = (msr - APIC_BASE_MSR) << 4;
+
+ if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
+ return 1;
+
+ /* if this is ICR write vector before command */
+ if (msr == 0x830)
+ apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+ return apic_reg_write(apic, reg, (u32)data);
+}
+
+int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+ u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
+
+ if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
+ return 1;
+
+ if (apic_reg_read(apic, reg, 4, &low))
+ return 1;
+ if (msr == 0x830)
+ apic_reg_read(apic, APIC_ICR2, 4, &high);
+
+ *data = (((u64)high) << 32) | low;
+
+ return 0;
+}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index a587f8349c46..40010b09c4aa 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -12,6 +12,7 @@ struct kvm_lapic {
struct kvm_timer lapic_timer;
u32 divide_count;
struct kvm_vcpu *vcpu;
+ bool irr_pending;
struct page *regs_page;
void *regs;
gpa_t vapic_addr;
@@ -28,6 +29,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
+void kvm_apic_set_version(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
@@ -44,4 +46,6 @@ void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
+int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
#endif
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 7030b5f911bf..9abea8e915b7 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -18,6 +18,7 @@
*/
#include "mmu.h"
+#include "kvm_cache_regs.h"
#include <linux/kvm_host.h>
#include <linux/types.h>
@@ -139,10 +140,13 @@ module_param(oos_shadow, bool, 0644);
#define ACC_USER_MASK PT_USER_MASK
#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK)
+#define CREATE_TRACE_POINTS
+#include "mmutrace.h"
+
#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
struct kvm_rmap_desc {
- u64 *shadow_ptes[RMAP_EXT];
+ u64 *sptes[RMAP_EXT];
struct kvm_rmap_desc *more;
};
@@ -239,16 +243,25 @@ static int is_writeble_pte(unsigned long pte)
return pte & PT_WRITABLE_MASK;
}
-static int is_dirty_pte(unsigned long pte)
+static int is_dirty_gpte(unsigned long pte)
{
- return pte & shadow_dirty_mask;
+ return pte & PT_DIRTY_MASK;
}
-static int is_rmap_pte(u64 pte)
+static int is_rmap_spte(u64 pte)
{
return is_shadow_present_pte(pte);
}
+static int is_last_spte(u64 pte, int level)
+{
+ if (level == PT_PAGE_TABLE_LEVEL)
+ return 1;
+ if (level == PT_DIRECTORY_LEVEL && is_large_pte(pte))
+ return 1;
+ return 0;
+}
+
static pfn_t spte_to_pfn(u64 pte)
{
return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
@@ -261,7 +274,7 @@ static gfn_t pse36_gfn_delta(u32 gpte)
return (gpte & PT32_DIR_PSE36_MASK) << shift;
}
-static void set_shadow_pte(u64 *sptep, u64 spte)
+static void __set_spte(u64 *sptep, u64 spte)
{
#ifdef CONFIG_X86_64
set_64bit((unsigned long *)sptep, spte);
@@ -384,9 +397,9 @@ static int *slot_largepage_idx(gfn_t gfn, struct kvm_memory_slot *slot)
{
unsigned long idx;
- idx = (gfn / KVM_PAGES_PER_HPAGE) -
- (slot->base_gfn / KVM_PAGES_PER_HPAGE);
- return &slot->lpage_info[idx].write_count;
+ idx = (gfn / KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL)) -
+ (slot->base_gfn / KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL));
+ return &slot->lpage_info[0][idx].write_count;
}
static void account_shadowed(struct kvm *kvm, gfn_t gfn)
@@ -475,10 +488,10 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage)
if (!lpage)
return &slot->rmap[gfn - slot->base_gfn];
- idx = (gfn / KVM_PAGES_PER_HPAGE) -
- (slot->base_gfn / KVM_PAGES_PER_HPAGE);
+ idx = (gfn / KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL)) -
+ (slot->base_gfn / KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL));
- return &slot->lpage_info[idx].rmap_pde;
+ return &slot->lpage_info[0][idx].rmap_pde;
}
/*
@@ -497,7 +510,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage)
unsigned long *rmapp;
int i;
- if (!is_rmap_pte(*spte))
+ if (!is_rmap_spte(*spte))
return;
gfn = unalias_gfn(vcpu->kvm, gfn);
sp = page_header(__pa(spte));
@@ -509,21 +522,21 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage)
} else if (!(*rmapp & 1)) {
rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
desc = mmu_alloc_rmap_desc(vcpu);
- desc->shadow_ptes[0] = (u64 *)*rmapp;
- desc->shadow_ptes[1] = spte;
+ desc->sptes[0] = (u64 *)*rmapp;
+ desc->sptes[1] = spte;
*rmapp = (unsigned long)desc | 1;
} else {
rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
- while (desc->shadow_ptes[RMAP_EXT-1] && desc->more)
+ while (desc->sptes[RMAP_EXT-1] && desc->more)
desc = desc->more;
- if (desc->shadow_ptes[RMAP_EXT-1]) {
+ if (desc->sptes[RMAP_EXT-1]) {
desc->more = mmu_alloc_rmap_desc(vcpu);
desc = desc->more;
}
- for (i = 0; desc->shadow_ptes[i]; ++i)
+ for (i = 0; desc->sptes[i]; ++i)
;
- desc->shadow_ptes[i] = spte;
+ desc->sptes[i] = spte;
}
}
@@ -534,14 +547,14 @@ static void rmap_desc_remove_entry(unsigned long *rmapp,
{
int j;
- for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
+ for (j = RMAP_EXT - 1; !desc->sptes[j] && j > i; --j)
;
- desc->shadow_ptes[i] = desc->shadow_ptes[j];
- desc->shadow_ptes[j] = NULL;
+ desc->sptes[i] = desc->sptes[j];
+ desc->sptes[j] = NULL;
if (j != 0)
return;
if (!prev_desc && !desc->more)
- *rmapp = (unsigned long)desc->shadow_ptes[0];
+ *rmapp = (unsigned long)desc->sptes[0];
else
if (prev_desc)
prev_desc->more = desc->more;
@@ -559,7 +572,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
unsigned long *rmapp;
int i;
- if (!is_rmap_pte(*spte))
+ if (!is_rmap_spte(*spte))
return;
sp = page_header(__pa(spte));
pfn = spte_to_pfn(*spte);
@@ -586,8 +599,8 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
prev_desc = NULL;
while (desc) {
- for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
- if (desc->shadow_ptes[i] == spte) {
+ for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i)
+ if (desc->sptes[i] == spte) {
rmap_desc_remove_entry(rmapp,
desc, i,
prev_desc);
@@ -618,10 +631,10 @@ static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
prev_desc = NULL;
prev_spte = NULL;
while (desc) {
- for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) {
+ for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i) {
if (prev_spte == spte)
- return desc->shadow_ptes[i];
- prev_spte = desc->shadow_ptes[i];
+ return desc->sptes[i];
+ prev_spte = desc->sptes[i];
}
desc = desc->more;
}
@@ -643,7 +656,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
BUG_ON(!(*spte & PT_PRESENT_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
if (is_writeble_pte(*spte)) {
- set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
+ __set_spte(spte, *spte & ~PT_WRITABLE_MASK);
write_protected = 1;
}
spte = rmap_next(kvm, rmapp, spte);
@@ -667,7 +680,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
if (is_writeble_pte(*spte)) {
rmap_remove(kvm, spte);
--kvm->stat.lpages;
- set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+ __set_spte(spte, shadow_trap_nonpresent_pte);
spte = NULL;
write_protected = 1;
}
@@ -686,7 +699,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp)
BUG_ON(!(*spte & PT_PRESENT_MASK));
rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte);
rmap_remove(kvm, spte);
- set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+ __set_spte(spte, shadow_trap_nonpresent_pte);
need_tlb_flush = 1;
}
return need_tlb_flush;
@@ -714,11 +727,11 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
end = start + (memslot->npages << PAGE_SHIFT);
if (hva >= start && hva < end) {
gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
+ int idx = gfn_offset /
+ KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL);
retval |= handler(kvm, &memslot->rmap[gfn_offset]);
retval |= handler(kvm,
- &memslot->lpage_info[
- gfn_offset /
- KVM_PAGES_PER_HPAGE].rmap_pde);
+ &memslot->lpage_info[0][idx].rmap_pde);
}
}
@@ -1089,6 +1102,7 @@ static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
return 1;
}
+ trace_kvm_mmu_sync_page(sp);
if (rmap_write_protect(vcpu->kvm, sp->gfn))
kvm_flush_remote_tlbs(vcpu->kvm);
kvm_unlink_unsync_page(vcpu->kvm, sp);
@@ -1211,8 +1225,6 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
role.quadrant = quadrant;
}
- pgprintk("%s: looking gfn %lx role %x\n", __func__,
- gfn, role.word);
index = kvm_page_table_hashfn(gfn);
bucket = &vcpu->kvm->arch.mmu_page_hash[index];
hlist_for_each_entry_safe(sp, node, tmp, bucket, hash_link)
@@ -1229,14 +1241,13 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
kvm_mmu_mark_parents_unsync(vcpu, sp);
}
- pgprintk("%s: found\n", __func__);
+ trace_kvm_mmu_get_page(sp, false);
return sp;
}
++vcpu->kvm->stat.mmu_cache_miss;
sp = kvm_mmu_alloc_page(vcpu, parent_pte);
if (!sp)
return sp;
- pgprintk("%s: adding gfn %lx role %x\n", __func__, gfn, role.word);
sp->gfn = gfn;
sp->role = role;
hlist_add_head(&sp->hash_link, bucket);
@@ -1249,6 +1260,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
vcpu->arch.mmu.prefetch_page(vcpu, sp);
else
nonpaging_prefetch_page(vcpu, sp);
+ trace_kvm_mmu_get_page(sp, true);
return sp;
}
@@ -1272,6 +1284,11 @@ static bool shadow_walk_okay(struct kvm_shadow_walk_iterator *iterator)
{
if (iterator->level < PT_PAGE_TABLE_LEVEL)
return false;
+
+ if (iterator->level == PT_PAGE_TABLE_LEVEL)
+ if (is_large_pte(*iterator->sptep))
+ return false;
+
iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level);
iterator->sptep = ((u64 *)__va(iterator->shadow_addr)) + iterator->index;
return true;
@@ -1292,25 +1309,17 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm,
pt = sp->spt;
- if (sp->role.level == PT_PAGE_TABLE_LEVEL) {
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
- if (is_shadow_present_pte(pt[i]))
- rmap_remove(kvm, &pt[i]);
- pt[i] = shadow_trap_nonpresent_pte;
- }
- return;
- }
-
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
ent = pt[i];
if (is_shadow_present_pte(ent)) {
- if (!is_large_pte(ent)) {
+ if (!is_last_spte(ent, sp->role.level)) {
ent &= PT64_BASE_ADDR_MASK;
mmu_page_remove_parent_pte(page_header(ent),
&pt[i]);
} else {
- --kvm->stat.lpages;
+ if (is_large_pte(ent))
+ --kvm->stat.lpages;
rmap_remove(kvm, &pt[i]);
}
}
@@ -1326,10 +1335,10 @@ static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte)
static void kvm_mmu_reset_last_pte_updated(struct kvm *kvm)
{
int i;
+ struct kvm_vcpu *vcpu;
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- if (kvm->vcpus[i])
- kvm->vcpus[i]->arch.last_pte_updated = NULL;
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ vcpu->arch.last_pte_updated = NULL;
}
static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
@@ -1348,7 +1357,7 @@ static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
}
BUG_ON(!parent_pte);
kvm_mmu_put_page(sp, parent_pte);
- set_shadow_pte(parent_pte, shadow_trap_nonpresent_pte);
+ __set_spte(parent_pte, shadow_trap_nonpresent_pte);
}
}
@@ -1380,6 +1389,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm,
static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
{
int ret;
+
+ trace_kvm_mmu_zap_page(sp);
++kvm->stat.mmu_shadow_zapped;
ret = mmu_zap_unsync_children(kvm, sp);
kvm_mmu_page_unlink_children(kvm, sp);
@@ -1407,24 +1418,25 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
*/
void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
{
+ int used_pages;
+
+ used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
+ used_pages = max(0, used_pages);
+
/*
* If we set the number of mmu pages to be smaller be than the
* number of actived pages , we must to free some mmu pages before we
* change the value
*/
- if ((kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages) >
- kvm_nr_mmu_pages) {
- int n_used_mmu_pages = kvm->arch.n_alloc_mmu_pages
- - kvm->arch.n_free_mmu_pages;
-
- while (n_used_mmu_pages > kvm_nr_mmu_pages) {
+ if (used_pages > kvm_nr_mmu_pages) {
+ while (used_pages > kvm_nr_mmu_pages) {
struct kvm_mmu_page *page;
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
kvm_mmu_zap_page(kvm, page);
- n_used_mmu_pages--;
+ used_pages--;
}
kvm->arch.n_free_mmu_pages = 0;
}
@@ -1495,7 +1507,7 @@ static void mmu_convert_notrap(struct kvm_mmu_page *sp)
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
if (pt[i] == shadow_notrap_nonpresent_pte)
- set_shadow_pte(&pt[i], shadow_trap_nonpresent_pte);
+ __set_spte(&pt[i], shadow_trap_nonpresent_pte);
}
}
@@ -1625,6 +1637,7 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
struct kvm_mmu_page *s;
struct hlist_node *node, *n;
+ trace_kvm_mmu_unsync_page(sp);
index = kvm_page_table_hashfn(sp->gfn);
bucket = &vcpu->kvm->arch.mmu_page_hash[index];
/* don't unsync if pagetable is shadowed with multiple roles */
@@ -1661,7 +1674,7 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
return 0;
}
-static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
+static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
unsigned pte_access, int user_fault,
int write_fault, int dirty, int largepage,
gfn_t gfn, pfn_t pfn, bool speculative,
@@ -1711,7 +1724,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
* is responsibility of mmu_get_page / kvm_sync_page.
* Same reasoning can be applied to dirty page accounting.
*/
- if (!can_unsync && is_writeble_pte(*shadow_pte))
+ if (!can_unsync && is_writeble_pte(*sptep))
goto set_pte;
if (mmu_need_write_protect(vcpu, gfn, can_unsync)) {
@@ -1728,61 +1741,61 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
mark_page_dirty(vcpu->kvm, gfn);
set_pte:
- set_shadow_pte(shadow_pte, spte);
+ __set_spte(sptep, spte);
return ret;
}
-static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
+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 largepage, gfn_t gfn,
pfn_t pfn, bool speculative)
{
int was_rmapped = 0;
- int was_writeble = is_writeble_pte(*shadow_pte);
+ int was_writeble = is_writeble_pte(*sptep);
pgprintk("%s: spte %llx access %x write_fault %d"
" user_fault %d gfn %lx\n",
- __func__, *shadow_pte, pt_access,
+ __func__, *sptep, pt_access,
write_fault, user_fault, gfn);
- if (is_rmap_pte(*shadow_pte)) {
+ if (is_rmap_spte(*sptep)) {
/*
* If we overwrite a PTE page pointer with a 2MB PMD, unlink
* the parent of the now unreachable PTE.
*/
- if (largepage && !is_large_pte(*shadow_pte)) {
+ if (largepage && !is_large_pte(*sptep)) {
struct kvm_mmu_page *child;
- u64 pte = *shadow_pte;
+ u64 pte = *sptep;
child = page_header(pte & PT64_BASE_ADDR_MASK);
- mmu_page_remove_parent_pte(child, shadow_pte);
- } else if (pfn != spte_to_pfn(*shadow_pte)) {
+ mmu_page_remove_parent_pte(child, sptep);
+ } else if (pfn != spte_to_pfn(*sptep)) {
pgprintk("hfn old %lx new %lx\n",
- spte_to_pfn(*shadow_pte), pfn);
- rmap_remove(vcpu->kvm, shadow_pte);
+ spte_to_pfn(*sptep), pfn);
+ rmap_remove(vcpu->kvm, sptep);
} else
was_rmapped = 1;
}
- if (set_spte(vcpu, shadow_pte, pte_access, user_fault, write_fault,
+ if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault,
dirty, largepage, gfn, pfn, speculative, true)) {
if (write_fault)
*ptwrite = 1;
kvm_x86_ops->tlb_flush(vcpu);
}
- pgprintk("%s: setting spte %llx\n", __func__, *shadow_pte);
+ pgprintk("%s: setting spte %llx\n", __func__, *sptep);
pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n",
- is_large_pte(*shadow_pte)? "2MB" : "4kB",
- is_present_pte(*shadow_pte)?"RW":"R", gfn,
- *shadow_pte, shadow_pte);
- if (!was_rmapped && is_large_pte(*shadow_pte))
+ is_large_pte(*sptep)? "2MB" : "4kB",
+ *sptep & PT_PRESENT_MASK ?"RW":"R", gfn,
+ *sptep, sptep);
+ if (!was_rmapped && is_large_pte(*sptep))
++vcpu->kvm->stat.lpages;
- page_header_update_slot(vcpu->kvm, shadow_pte, gfn);
+ page_header_update_slot(vcpu->kvm, sptep, gfn);
if (!was_rmapped) {
- rmap_add(vcpu, shadow_pte, gfn, largepage);
- if (!is_rmap_pte(*shadow_pte))
+ rmap_add(vcpu, sptep, gfn, largepage);
+ if (!is_rmap_spte(*sptep))
kvm_release_pfn_clean(pfn);
} else {
if (was_writeble)
@@ -1791,7 +1804,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
kvm_release_pfn_clean(pfn);
}
if (speculative) {
- vcpu->arch.last_pte_updated = shadow_pte;
+ vcpu->arch.last_pte_updated = sptep;
vcpu->arch.last_pte_gfn = gfn;
}
}
@@ -1829,10 +1842,10 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
return -ENOMEM;
}
- set_shadow_pte(iterator.sptep,
- __pa(sp->spt)
- | PT_PRESENT_MASK | PT_WRITABLE_MASK
- | shadow_user_mask | shadow_x_mask);
+ __set_spte(iterator.sptep,
+ __pa(sp->spt)
+ | PT_PRESENT_MASK | PT_WRITABLE_MASK
+ | shadow_user_mask | shadow_x_mask);
}
}
return pt_write;
@@ -1845,8 +1858,9 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)
pfn_t pfn;
unsigned long mmu_seq;
- if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) {
- gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ if (is_largepage_backed(vcpu, gfn &
+ ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1))) {
+ gfn &= ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1);
largepage = 1;
}
@@ -1930,6 +1944,7 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
gfn_t root_gfn;
struct kvm_mmu_page *sp;
int direct = 0;
+ u64 pdptr;
root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT;
@@ -1957,11 +1972,12 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
ASSERT(!VALID_PAGE(root));
if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
- if (!is_present_pte(vcpu->arch.pdptrs[i])) {
+ pdptr = kvm_pdptr_read(vcpu, i);
+ if (!is_present_gpte(pdptr)) {
vcpu->arch.mmu.pae_root[i] = 0;
continue;
}
- root_gfn = vcpu->arch.pdptrs[i] >> PAGE_SHIFT;
+ root_gfn = pdptr >> PAGE_SHIFT;
} else if (vcpu->arch.mmu.root_level == 0)
root_gfn = 0;
if (mmu_check_root(vcpu, root_gfn))
@@ -2049,8 +2065,9 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
if (r)
return r;
- if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) {
- gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ if (is_largepage_backed(vcpu, gfn &
+ ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1))) {
+ gfn &= ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1);
largepage = 1;
}
mmu_seq = vcpu->kvm->mmu_notifier_seq;
@@ -2333,8 +2350,8 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
spin_unlock(&vcpu->kvm->mmu_lock);
if (r)
goto out;
+ /* set_cr3() should ensure TLB has been flushed */
kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
- kvm_mmu_flush_tlb(vcpu);
out:
return r;
}
@@ -2354,15 +2371,14 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_shadow_present_pte(pte)) {
- if (sp->role.level == PT_PAGE_TABLE_LEVEL ||
- is_large_pte(pte))
+ if (is_last_spte(pte, sp->role.level))
rmap_remove(vcpu->kvm, spte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
mmu_page_remove_parent_pte(child, spte);
}
}
- set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+ __set_spte(spte, shadow_trap_nonpresent_pte);
if (is_large_pte(pte))
--vcpu->kvm->stat.lpages;
}
@@ -2448,12 +2464,12 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
if ((bytes == 4) && (gpa % 4 == 0))
memcpy((void *)&gpte, new, 4);
}
- if (!is_present_pte(gpte))
+ if (!is_present_gpte(gpte))
return;
gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) {
- gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ gfn &= ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1);
vcpu->arch.update_pte.largepage = 1;
}
vcpu->arch.update_pte.mmu_seq = vcpu->kvm->mmu_notifier_seq;
@@ -2646,8 +2662,9 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
++vcpu->stat.mmio_exits;
return 0;
case EMULATE_FAIL:
- kvm_report_emulation_failure(vcpu, "pagetable");
- return 1;
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+ return 0;
default:
BUG();
}
@@ -2688,12 +2705,14 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
ASSERT(vcpu);
+ spin_lock(&vcpu->kvm->mmu_lock);
if (vcpu->kvm->arch.n_requested_mmu_pages)
vcpu->kvm->arch.n_free_mmu_pages =
vcpu->kvm->arch.n_requested_mmu_pages;
else
vcpu->kvm->arch.n_free_mmu_pages =
vcpu->kvm->arch.n_alloc_mmu_pages;
+ spin_unlock(&vcpu->kvm->mmu_lock);
/*
* When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
* Therefore we need to allocate shadow page tables in the first
@@ -3005,6 +3024,24 @@ out:
return r;
}
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4])
+{
+ struct kvm_shadow_walk_iterator iterator;
+ int nr_sptes = 0;
+
+ spin_lock(&vcpu->kvm->mmu_lock);
+ for_each_shadow_entry(vcpu, addr, iterator) {
+ sptes[iterator.level-1] = *iterator.sptep;
+ nr_sptes++;
+ if (!is_shadow_present_pte(*iterator.sptep))
+ break;
+ }
+ spin_unlock(&vcpu->kvm->mmu_lock);
+
+ return nr_sptes;
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
+
#ifdef AUDIT
static const char *audit_msg;
@@ -3017,6 +3054,54 @@ static gva_t canonicalize(gva_t gva)
return gva;
}
+
+typedef void (*inspect_spte_fn) (struct kvm *kvm, struct kvm_mmu_page *sp,
+ u64 *sptep);
+
+static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
+ inspect_spte_fn fn)
+{
+ int i;
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ u64 ent = sp->spt[i];
+
+ if (is_shadow_present_pte(ent)) {
+ if (!is_last_spte(ent, sp->role.level)) {
+ struct kvm_mmu_page *child;
+ child = page_header(ent & PT64_BASE_ADDR_MASK);
+ __mmu_spte_walk(kvm, child, fn);
+ } else
+ fn(kvm, sp, &sp->spt[i]);
+ }
+ }
+}
+
+static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
+{
+ int i;
+ struct kvm_mmu_page *sp;
+
+ if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
+ return;
+ if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ hpa_t root = vcpu->arch.mmu.root_hpa;
+ sp = page_header(root);
+ __mmu_spte_walk(vcpu->kvm, sp, fn);
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ hpa_t root = vcpu->arch.mmu.pae_root[i];
+
+ if (root && VALID_PAGE(root)) {
+ root &= PT64_BASE_ADDR_MASK;
+ sp = page_header(root);
+ __mmu_spte_walk(vcpu->kvm, sp, fn);
+ }
+ }
+ return;
+}
+
static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
gva_t va, int level)
{
@@ -3031,20 +3116,19 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
continue;
va = canonicalize(va);
- if (level > 1) {
- if (ent == shadow_notrap_nonpresent_pte)
- printk(KERN_ERR "audit: (%s) nontrapping pte"
- " in nonleaf level: levels %d gva %lx"
- " level %d pte %llx\n", audit_msg,
- vcpu->arch.mmu.root_level, va, level, ent);
- else
- audit_mappings_page(vcpu, ent, va, level - 1);
- } else {
+ if (is_shadow_present_pte(ent) && !is_last_spte(ent, level))
+ audit_mappings_page(vcpu, ent, va, level - 1);
+ else {
gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va);
gfn_t gfn = gpa >> PAGE_SHIFT;
pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ continue;
+ }
+
if (is_shadow_present_pte(ent)
&& (ent & PT64_BASE_ADDR_MASK) != hpa)
printk(KERN_ERR "xx audit error: (%s) levels %d"
@@ -3098,7 +3182,7 @@ static int count_rmaps(struct kvm_vcpu *vcpu)
d = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
while (d) {
for (k = 0; k < RMAP_EXT; ++k)
- if (d->shadow_ptes[k])
+ if (d->sptes[k])
++nmaps;
else
break;
@@ -3109,9 +3193,48 @@ static int count_rmaps(struct kvm_vcpu *vcpu)
return nmaps;
}
-static int count_writable_mappings(struct kvm_vcpu *vcpu)
+void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep)
+{
+ unsigned long *rmapp;
+ struct kvm_mmu_page *rev_sp;
+ gfn_t gfn;
+
+ if (*sptep & PT_WRITABLE_MASK) {
+ rev_sp = page_header(__pa(sptep));
+ gfn = rev_sp->gfns[sptep - rev_sp->spt];
+
+ if (!gfn_to_memslot(kvm, gfn)) {
+ if (!printk_ratelimit())
+ return;
+ printk(KERN_ERR "%s: no memslot for gfn %ld\n",
+ audit_msg, gfn);
+ printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n",
+ audit_msg, sptep - rev_sp->spt,
+ rev_sp->gfn);
+ dump_stack();
+ return;
+ }
+
+ rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt],
+ is_large_pte(*sptep));
+ if (!*rmapp) {
+ if (!printk_ratelimit())
+ return;
+ printk(KERN_ERR "%s: no rmap for writable spte %llx\n",
+ audit_msg, *sptep);
+ dump_stack();
+ }
+ }
+
+}
+
+void audit_writable_sptes_have_rmaps(struct kvm_vcpu *vcpu)
+{
+ mmu_spte_walk(vcpu, inspect_spte_has_rmap);
+}
+
+static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu)
{
- int nmaps = 0;
struct kvm_mmu_page *sp;
int i;
@@ -3128,20 +3251,16 @@ static int count_writable_mappings(struct kvm_vcpu *vcpu)
continue;
if (!(ent & PT_WRITABLE_MASK))
continue;
- ++nmaps;
+ inspect_spte_has_rmap(vcpu->kvm, sp, &pt[i]);
}
}
- return nmaps;
+ return;
}
static void audit_rmap(struct kvm_vcpu *vcpu)
{
- int n_rmap = count_rmaps(vcpu);
- int n_actual = count_writable_mappings(vcpu);
-
- if (n_rmap != n_actual)
- printk(KERN_ERR "%s: (%s) rmap %d actual %d\n",
- __func__, audit_msg, n_rmap, n_actual);
+ check_writable_mappings_rmap(vcpu);
+ count_rmaps(vcpu);
}
static void audit_write_protection(struct kvm_vcpu *vcpu)
@@ -3149,20 +3268,28 @@ static void audit_write_protection(struct kvm_vcpu *vcpu)
struct kvm_mmu_page *sp;
struct kvm_memory_slot *slot;
unsigned long *rmapp;
+ u64 *spte;
gfn_t gfn;
list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) {
if (sp->role.direct)
continue;
+ if (sp->unsync)
+ continue;
gfn = unalias_gfn(vcpu->kvm, sp->gfn);
slot = gfn_to_memslot_unaliased(vcpu->kvm, sp->gfn);
rmapp = &slot->rmap[gfn - slot->base_gfn];
- if (*rmapp)
- printk(KERN_ERR "%s: (%s) shadow page has writable"
- " mappings: gfn %lx role %x\n",
+
+ spte = rmap_next(vcpu->kvm, rmapp, NULL);
+ while (spte) {
+ if (*spte & PT_WRITABLE_MASK)
+ printk(KERN_ERR "%s: (%s) shadow page has "
+ "writable mappings: gfn %lx role %x\n",
__func__, audit_msg, sp->gfn,
sp->role.word);
+ spte = rmap_next(vcpu->kvm, rmapp, spte);
+ }
}
}
@@ -3174,7 +3301,9 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
audit_msg = msg;
audit_rmap(vcpu);
audit_write_protection(vcpu);
- audit_mappings(vcpu);
+ if (strcmp("pre pte write", audit_msg) != 0)
+ audit_mappings(vcpu);
+ audit_writable_sptes_have_rmaps(vcpu);
dbg = olddbg;
}
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 3494a2fb136e..61a1b3884b49 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -37,6 +37,8 @@
#define PT32_ROOT_LEVEL 2
#define PT32E_ROOT_LEVEL 3
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
+
static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
@@ -75,7 +77,7 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
return vcpu->arch.cr0 & X86_CR0_PG;
}
-static inline int is_present_pte(unsigned long pte)
+static inline int is_present_gpte(unsigned long pte)
{
return pte & PT_PRESENT_MASK;
}
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
new file mode 100644
index 000000000000..3e4a5c6ca2a9
--- /dev/null
+++ b/arch/x86/kvm/mmutrace.h
@@ -0,0 +1,220 @@
+#if !defined(_TRACE_KVMMMU_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVMMMU_H
+
+#include <linux/tracepoint.h>
+#include <linux/ftrace_event.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvmmmu
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE mmutrace
+
+#define KVM_MMU_PAGE_FIELDS \
+ __field(__u64, gfn) \
+ __field(__u32, role) \
+ __field(__u32, root_count) \
+ __field(__u32, unsync)
+
+#define KVM_MMU_PAGE_ASSIGN(sp) \
+ __entry->gfn = sp->gfn; \
+ __entry->role = sp->role.word; \
+ __entry->root_count = sp->root_count; \
+ __entry->unsync = sp->unsync;
+
+#define KVM_MMU_PAGE_PRINTK() ({ \
+ const char *ret = p->buffer + p->len; \
+ static const char *access_str[] = { \
+ "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" \
+ }; \
+ union kvm_mmu_page_role role; \
+ \
+ role.word = __entry->role; \
+ \
+ trace_seq_printf(p, "sp gfn %llx %u/%u q%u%s %s%s %spge" \
+ " %snxe root %u %s%c", \
+ __entry->gfn, role.level, role.glevels, \
+ role.quadrant, \
+ role.direct ? " direct" : "", \
+ access_str[role.access], \
+ role.invalid ? " invalid" : "", \
+ role.cr4_pge ? "" : "!", \
+ role.nxe ? "" : "!", \
+ __entry->root_count, \
+ __entry->unsync ? "unsync" : "sync", 0); \
+ ret; \
+ })
+
+#define kvm_mmu_trace_pferr_flags \
+ { PFERR_PRESENT_MASK, "P" }, \
+ { PFERR_WRITE_MASK, "W" }, \
+ { PFERR_USER_MASK, "U" }, \
+ { PFERR_RSVD_MASK, "RSVD" }, \
+ { PFERR_FETCH_MASK, "F" }
+
+/*
+ * A pagetable walk has started
+ */
+TRACE_EVENT(
+ kvm_mmu_pagetable_walk,
+ TP_PROTO(u64 addr, int write_fault, int user_fault, int fetch_fault),
+ TP_ARGS(addr, write_fault, user_fault, fetch_fault),
+
+ TP_STRUCT__entry(
+ __field(__u64, addr)
+ __field(__u32, pferr)
+ ),
+
+ TP_fast_assign(
+ __entry->addr = addr;
+ __entry->pferr = (!!write_fault << 1) | (!!user_fault << 2)
+ | (!!fetch_fault << 4);
+ ),
+
+ TP_printk("addr %llx pferr %x %s", __entry->addr, __entry->pferr,
+ __print_flags(__entry->pferr, "|", kvm_mmu_trace_pferr_flags))
+);
+
+
+/* We just walked a paging element */
+TRACE_EVENT(
+ kvm_mmu_paging_element,
+ TP_PROTO(u64 pte, int level),
+ TP_ARGS(pte, level),
+
+ TP_STRUCT__entry(
+ __field(__u64, pte)
+ __field(__u32, level)
+ ),
+
+ TP_fast_assign(
+ __entry->pte = pte;
+ __entry->level = level;
+ ),
+
+ TP_printk("pte %llx level %u", __entry->pte, __entry->level)
+);
+
+/* We set a pte accessed bit */
+TRACE_EVENT(
+ kvm_mmu_set_accessed_bit,
+ TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size),
+ TP_ARGS(table_gfn, index, size),
+
+ TP_STRUCT__entry(
+ __field(__u64, gpa)
+ ),
+
+ TP_fast_assign(
+ __entry->gpa = ((u64)table_gfn << PAGE_SHIFT)
+ + index * size;
+ ),
+
+ TP_printk("gpa %llx", __entry->gpa)
+);
+
+/* We set a pte dirty bit */
+TRACE_EVENT(
+ kvm_mmu_set_dirty_bit,
+ TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size),
+ TP_ARGS(table_gfn, index, size),
+
+ TP_STRUCT__entry(
+ __field(__u64, gpa)
+ ),
+
+ TP_fast_assign(
+ __entry->gpa = ((u64)table_gfn << PAGE_SHIFT)
+ + index * size;
+ ),
+
+ TP_printk("gpa %llx", __entry->gpa)
+);
+
+TRACE_EVENT(
+ kvm_mmu_walker_error,
+ TP_PROTO(u32 pferr),
+ TP_ARGS(pferr),
+
+ TP_STRUCT__entry(
+ __field(__u32, pferr)
+ ),
+
+ TP_fast_assign(
+ __entry->pferr = pferr;
+ ),
+
+ TP_printk("pferr %x %s", __entry->pferr,
+ __print_flags(__entry->pferr, "|", kvm_mmu_trace_pferr_flags))
+);
+
+TRACE_EVENT(
+ kvm_mmu_get_page,
+ TP_PROTO(struct kvm_mmu_page *sp, bool created),
+ TP_ARGS(sp, created),
+
+ TP_STRUCT__entry(
+ KVM_MMU_PAGE_FIELDS
+ __field(bool, created)
+ ),
+
+ TP_fast_assign(
+ KVM_MMU_PAGE_ASSIGN(sp)
+ __entry->created = created;
+ ),
+
+ TP_printk("%s %s", KVM_MMU_PAGE_PRINTK(),
+ __entry->created ? "new" : "existing")
+);
+
+TRACE_EVENT(
+ kvm_mmu_sync_page,
+ TP_PROTO(struct kvm_mmu_page *sp),
+ TP_ARGS(sp),
+
+ TP_STRUCT__entry(
+ KVM_MMU_PAGE_FIELDS
+ ),
+
+ TP_fast_assign(
+ KVM_MMU_PAGE_ASSIGN(sp)
+ ),
+
+ TP_printk("%s", KVM_MMU_PAGE_PRINTK())
+);
+
+TRACE_EVENT(
+ kvm_mmu_unsync_page,
+ TP_PROTO(struct kvm_mmu_page *sp),
+ TP_ARGS(sp),
+
+ TP_STRUCT__entry(
+ KVM_MMU_PAGE_FIELDS
+ ),
+
+ TP_fast_assign(
+ KVM_MMU_PAGE_ASSIGN(sp)
+ ),
+
+ TP_printk("%s", KVM_MMU_PAGE_PRINTK())
+);
+
+TRACE_EVENT(
+ kvm_mmu_zap_page,
+ TP_PROTO(struct kvm_mmu_page *sp),
+ TP_ARGS(sp),
+
+ TP_STRUCT__entry(
+ KVM_MMU_PAGE_FIELDS
+ ),
+
+ TP_fast_assign(
+ KVM_MMU_PAGE_ASSIGN(sp)
+ ),
+
+ TP_printk("%s", KVM_MMU_PAGE_PRINTK())
+);
+
+#endif /* _TRACE_KVMMMU_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 67785f635399..36ac6d70a847 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -125,14 +125,16 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
gpa_t pte_gpa;
int rsvd_fault = 0;
- pgprintk("%s: addr %lx\n", __func__, addr);
+ trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault,
+ fetch_fault);
walk:
walker->level = vcpu->arch.mmu.root_level;
pte = vcpu->arch.cr3;
#if PTTYPE == 64
if (!is_long_mode(vcpu)) {
- pte = vcpu->arch.pdptrs[(addr >> 30) & 3];
- if (!is_present_pte(pte))
+ pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3);
+ trace_kvm_mmu_paging_element(pte, walker->level);
+ if (!is_present_gpte(pte))
goto not_present;
--walker->level;
}
@@ -150,12 +152,11 @@ walk:
pte_gpa += index * sizeof(pt_element_t);
walker->table_gfn[walker->level - 1] = table_gfn;
walker->pte_gpa[walker->level - 1] = pte_gpa;
- pgprintk("%s: table_gfn[%d] %lx\n", __func__,
- walker->level - 1, table_gfn);
kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte));
+ trace_kvm_mmu_paging_element(pte, walker->level);
- if (!is_present_pte(pte))
+ if (!is_present_gpte(pte))
goto not_present;
rsvd_fault = is_rsvd_bits_set(vcpu, pte, walker->level);
@@ -175,6 +176,8 @@ walk:
#endif
if (!(pte & PT_ACCESSED_MASK)) {
+ trace_kvm_mmu_set_accessed_bit(table_gfn, index,
+ sizeof(pte));
mark_page_dirty(vcpu->kvm, table_gfn);
if (FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn,
index, pte, pte|PT_ACCESSED_MASK))
@@ -205,9 +208,10 @@ walk:
--walker->level;
}
- if (write_fault && !is_dirty_pte(pte)) {
+ if (write_fault && !is_dirty_gpte(pte)) {
bool ret;
+ trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
mark_page_dirty(vcpu->kvm, table_gfn);
ret = FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, index, pte,
pte|PT_DIRTY_MASK);
@@ -239,6 +243,7 @@ err:
walker->error_code |= PFERR_FETCH_MASK;
if (rsvd_fault)
walker->error_code |= PFERR_RSVD_MASK;
+ trace_kvm_mmu_walker_error(walker->error_code);
return 0;
}
@@ -252,8 +257,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
gpte = *(const pt_element_t *)pte;
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
- if (!is_present_pte(gpte))
- set_shadow_pte(spte, shadow_notrap_nonpresent_pte);
+ if (!is_present_gpte(gpte))
+ __set_spte(spte, shadow_notrap_nonpresent_pte);
return;
}
pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
@@ -289,7 +294,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
pt_element_t curr_pte;
struct kvm_shadow_walk_iterator iterator;
- if (!is_present_pte(gw->ptes[gw->level - 1]))
+ if (!is_present_gpte(gw->ptes[gw->level - 1]))
return NULL;
for_each_shadow_entry(vcpu, addr, iterator) {
@@ -311,14 +316,14 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
if (is_large_pte(*sptep)) {
rmap_remove(vcpu->kvm, sptep);
- set_shadow_pte(sptep, shadow_trap_nonpresent_pte);
+ __set_spte(sptep, shadow_trap_nonpresent_pte);
kvm_flush_remote_tlbs(vcpu->kvm);
}
if (level == PT_DIRECTORY_LEVEL
&& gw->level == PT_DIRECTORY_LEVEL) {
direct = 1;
- if (!is_dirty_pte(gw->ptes[level - 1]))
+ if (!is_dirty_gpte(gw->ptes[level - 1]))
access &= ~ACC_WRITE_MASK;
table_gfn = gpte_to_gfn(gw->ptes[level - 1]);
} else {
@@ -369,7 +374,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
int user_fault = error_code & PFERR_USER_MASK;
int fetch_fault = error_code & PFERR_FETCH_MASK;
struct guest_walker walker;
- u64 *shadow_pte;
+ u64 *sptep;
int write_pt = 0;
int r;
pfn_t pfn;
@@ -401,7 +406,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
if (walker.level == PT_DIRECTORY_LEVEL) {
gfn_t large_gfn;
- large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1);
+ large_gfn = walker.gfn &
+ ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1);
if (is_largepage_backed(vcpu, large_gfn)) {
walker.gfn = large_gfn;
largepage = 1;
@@ -422,11 +428,11 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
if (mmu_notifier_retry(vcpu, mmu_seq))
goto out_unlock;
kvm_mmu_free_some_pages(vcpu);
- shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
- largepage, &write_pt, pfn);
+ sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
+ largepage, &write_pt, pfn);
pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
- shadow_pte, *shadow_pte, write_pt);
+ sptep, *sptep, write_pt);
if (!write_pt)
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
@@ -472,7 +478,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
--vcpu->kvm->stat.lpages;
need_flush = 1;
}
- set_shadow_pte(sptep, shadow_trap_nonpresent_pte);
+ __set_spte(sptep, shadow_trap_nonpresent_pte);
break;
}
@@ -489,7 +495,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte,
sizeof(pt_element_t)))
return;
- if (is_present_pte(gpte) && (gpte & PT_ACCESSED_MASK)) {
+ if (is_present_gpte(gpte) && (gpte & PT_ACCESSED_MASK)) {
if (mmu_topup_memory_caches(vcpu))
return;
kvm_mmu_pte_write(vcpu, pte_gpa, (const u8 *)&gpte,
@@ -536,7 +542,7 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu,
r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa, pt, sizeof pt);
pte_gpa += ARRAY_SIZE(pt) * sizeof(pt_element_t);
for (j = 0; j < ARRAY_SIZE(pt); ++j)
- if (r || is_present_pte(pt[j]))
+ if (r || is_present_gpte(pt[j]))
sp->spt[i+j] = shadow_trap_nonpresent_pte;
else
sp->spt[i+j] = shadow_notrap_nonpresent_pte;
@@ -574,23 +580,23 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
sizeof(pt_element_t)))
return -EINVAL;
- if (gpte_to_gfn(gpte) != gfn || !is_present_pte(gpte) ||
+ if (gpte_to_gfn(gpte) != gfn || !is_present_gpte(gpte) ||
!(gpte & PT_ACCESSED_MASK)) {
u64 nonpresent;
rmap_remove(vcpu->kvm, &sp->spt[i]);
- if (is_present_pte(gpte))
+ if (is_present_gpte(gpte))
nonpresent = shadow_trap_nonpresent_pte;
else
nonpresent = shadow_notrap_nonpresent_pte;
- set_shadow_pte(&sp->spt[i], nonpresent);
+ __set_spte(&sp->spt[i], nonpresent);
continue;
}
nr_present++;
pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
- is_dirty_pte(gpte), 0, gfn,
+ is_dirty_gpte(gpte), 0, gfn,
spte_to_pfn(sp->spt[i]), true, false);
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 71510e07e69e..b720b02c4d6c 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -15,7 +15,6 @@
*/
#include <linux/kvm_host.h>
-#include "kvm_svm.h"
#include "irq.h"
#include "mmu.h"
#include "kvm_cache_regs.h"
@@ -26,10 +25,12 @@
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/sched.h>
+#include <linux/ftrace_event.h>
#include <asm/desc.h>
#include <asm/virtext.h>
+#include "trace.h"
#define __ex(x) __kvm_handle_fault_on_reboot(x)
@@ -57,6 +58,46 @@ MODULE_LICENSE("GPL");
#define nsvm_printk(fmt, args...) do {} while(0)
#endif
+static const u32 host_save_user_msrs[] = {
+#ifdef CONFIG_X86_64
+ MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
+ MSR_FS_BASE,
+#endif
+ MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+};
+
+#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
+
+struct kvm_vcpu;
+
+struct vcpu_svm {
+ struct kvm_vcpu vcpu;
+ struct vmcb *vmcb;
+ unsigned long vmcb_pa;
+ struct svm_cpu_data *svm_data;
+ uint64_t asid_generation;
+ uint64_t sysenter_cs;
+ uint64_t sysenter_esp;
+ uint64_t sysenter_eip;
+
+ u64 next_rip;
+
+ u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
+ u64 host_gs_base;
+
+ u32 *msrpm;
+ struct vmcb *hsave;
+ u64 hsave_msr;
+
+ u64 nested_vmcb;
+
+ /* These are the merged vectors */
+ u32 *nested_msrpm;
+
+ /* gpa pointers to the real vectors */
+ u64 nested_vmcb_msrpm;
+};
+
/* enable NPT for AMD64 and X86 with PAE */
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
static bool npt_enabled = true;
@@ -147,19 +188,6 @@ static inline void invlpga(unsigned long addr, u32 asid)
asm volatile (__ex(SVM_INVLPGA) :: "a"(addr), "c"(asid));
}
-static inline unsigned long kvm_read_cr2(void)
-{
- unsigned long cr2;
-
- asm volatile ("mov %%cr2, %0" : "=r" (cr2));
- return cr2;
-}
-
-static inline void kvm_write_cr2(unsigned long val)
-{
- asm volatile ("mov %0, %%cr2" :: "r" (val));
-}
-
static inline void force_new_asid(struct kvm_vcpu *vcpu)
{
to_svm(vcpu)->asid_generation--;
@@ -263,7 +291,7 @@ static void svm_hardware_enable(void *garbage)
struct svm_cpu_data *svm_data;
uint64_t efer;
- struct desc_ptr gdt_descr;
+ struct descriptor_table gdt_descr;
struct desc_struct *gdt;
int me = raw_smp_processor_id();
@@ -283,8 +311,8 @@ static void svm_hardware_enable(void *garbage)
svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
svm_data->next_asid = svm_data->max_asid + 1;
- asm volatile ("sgdt %0" : "=m"(gdt_descr));
- gdt = (struct desc_struct *)gdt_descr.address;
+ kvm_get_gdt(&gdt_descr);
+ gdt = (struct desc_struct *)gdt_descr.base;
svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
rdmsrl(MSR_EFER, efer);
@@ -605,7 +633,7 @@ static int svm_vcpu_reset(struct kvm_vcpu *vcpu)
init_vmcb(svm);
- if (vcpu->vcpu_id != 0) {
+ if (!kvm_vcpu_is_bsp(vcpu)) {
kvm_rip_write(vcpu, 0);
svm->vmcb->save.cs.base = svm->vcpu.arch.sipi_vector << 12;
svm->vmcb->save.cs.selector = svm->vcpu.arch.sipi_vector << 8;
@@ -669,7 +697,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
fx_init(&svm->vcpu);
svm->vcpu.fpu_active = 1;
svm->vcpu.arch.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (svm->vcpu.vcpu_id == 0)
+ if (kvm_vcpu_is_bsp(&svm->vcpu))
svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
return &svm->vcpu;
@@ -711,6 +739,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
svm->vmcb->control.tsc_offset += delta;
vcpu->cpu = cpu;
kvm_migrate_timers(vcpu);
+ svm->asid_generation = 0;
}
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
@@ -739,6 +768,18 @@ static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
to_svm(vcpu)->vmcb->save.rflags = rflags;
}
+static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
+{
+ switch (reg) {
+ case VCPU_EXREG_PDPTR:
+ BUG_ON(!npt_enabled);
+ load_pdptrs(vcpu, vcpu->arch.cr3);
+ break;
+ default:
+ BUG();
+ }
+}
+
static void svm_set_vintr(struct vcpu_svm *svm)
{
svm->vmcb->control.intercept |= 1ULL << INTERCEPT_VINTR;
@@ -1031,7 +1072,6 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
}
- svm->vcpu.cpu = svm_data->cpu;
svm->asid_generation = svm_data->asid_generation;
svm->vmcb->control.asid = svm_data->next_asid++;
}
@@ -1061,7 +1101,6 @@ static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
val = 0;
}
- KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
return val;
}
@@ -1070,8 +1109,6 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
{
struct vcpu_svm *svm = to_svm(vcpu);
- KVMTRACE_2D(DR_WRITE, vcpu, (u32)dr, (u32)value, handler);
-
*exception = 0;
switch (dr) {
@@ -1119,14 +1156,7 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
fault_address = svm->vmcb->control.exit_info_2;
error_code = svm->vmcb->control.exit_info_1;
- if (!npt_enabled)
- KVMTRACE_3D(PAGE_FAULT, &svm->vcpu, error_code,
- (u32)fault_address, (u32)(fault_address >> 32),
- handler);
- else
- KVMTRACE_3D(TDP_FAULT, &svm->vcpu, error_code,
- (u32)fault_address, (u32)(fault_address >> 32),
- handler);
+ trace_kvm_page_fault(fault_address, error_code);
/*
* FIXME: Tis shouldn't be necessary here, but there is a flush
* missing in the MMU code. Until we find this bug, flush the
@@ -1253,14 +1283,12 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- KVMTRACE_0D(NMI, &svm->vcpu, handler);
return 1;
}
static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
++svm->vcpu.stat.irq_exits;
- KVMTRACE_0D(INTR, &svm->vcpu, handler);
return 1;
}
@@ -1577,7 +1605,8 @@ static int nested_svm_vmexit_real(struct vcpu_svm *svm, void *arg1,
/* Kill any pending exceptions */
if (svm->vcpu.arch.exception.pending == true)
nsvm_printk("WARNING: Pending Exception\n");
- svm->vcpu.arch.exception.pending = false;
+ kvm_clear_exception_queue(&svm->vcpu);
+ kvm_clear_interrupt_queue(&svm->vcpu);
/* Restore selected save entries */
svm->vmcb->save.es = hsave->save.es;
@@ -1645,7 +1674,8 @@ static int nested_svm_vmrun(struct vcpu_svm *svm, void *arg1,
svm->nested_vmcb = svm->vmcb->save.rax;
/* Clear internal status */
- svm->vcpu.arch.exception.pending = false;
+ kvm_clear_exception_queue(&svm->vcpu);
+ kvm_clear_interrupt_queue(&svm->vcpu);
/* Save the old vmcb, so we don't need to pick what we save, but
can restore everything when a VMEXIT occurs */
@@ -1845,6 +1875,19 @@ 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)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ nsvm_printk("INVLPGA\n");
+
+ /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */
+ kvm_mmu_invlpg(vcpu, vcpu->arch.regs[VCPU_REGS_RAX]);
+
+ svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
+ skip_emulated_instruction(&svm->vcpu);
+ return 1;
+}
+
static int invalid_op_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
@@ -1953,7 +1996,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
struct vcpu_svm *svm = to_svm(vcpu);
switch (ecx) {
- case MSR_IA32_TIME_STAMP_COUNTER: {
+ case MSR_IA32_TSC: {
u64 tsc;
rdtscll(tsc);
@@ -1978,13 +2021,13 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
break;
#endif
case MSR_IA32_SYSENTER_CS:
- *data = svm->vmcb->save.sysenter_cs;
+ *data = svm->sysenter_cs;
break;
case MSR_IA32_SYSENTER_EIP:
- *data = svm->vmcb->save.sysenter_eip;
+ *data = svm->sysenter_eip;
break;
case MSR_IA32_SYSENTER_ESP:
- *data = svm->vmcb->save.sysenter_esp;
+ *data = svm->sysenter_esp;
break;
/* Nobody will change the following 5 values in the VMCB so
we can safely return them on rdmsr. They will always be 0
@@ -2027,8 +2070,7 @@ static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
if (svm_get_msr(&svm->vcpu, ecx, &data))
kvm_inject_gp(&svm->vcpu, 0);
else {
- KVMTRACE_3D(MSR_READ, &svm->vcpu, ecx, (u32)data,
- (u32)(data >> 32), handler);
+ trace_kvm_msr_read(ecx, data);
svm->vcpu.arch.regs[VCPU_REGS_RAX] = data & 0xffffffff;
svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32;
@@ -2043,7 +2085,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
struct vcpu_svm *svm = to_svm(vcpu);
switch (ecx) {
- case MSR_IA32_TIME_STAMP_COUNTER: {
+ case MSR_IA32_TSC: {
u64 tsc;
rdtscll(tsc);
@@ -2068,13 +2110,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
break;
#endif
case MSR_IA32_SYSENTER_CS:
- svm->vmcb->save.sysenter_cs = data;
+ svm->sysenter_cs = data;
break;
case MSR_IA32_SYSENTER_EIP:
- svm->vmcb->save.sysenter_eip = data;
+ svm->sysenter_eip = data;
break;
case MSR_IA32_SYSENTER_ESP:
- svm->vmcb->save.sysenter_esp = data;
+ svm->sysenter_esp = data;
break;
case MSR_IA32_DEBUGCTLMSR:
if (!svm_has(SVM_FEATURE_LBRV)) {
@@ -2091,25 +2133,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
else
svm_disable_lbrv(svm);
break;
- case MSR_K7_EVNTSEL0:
- case MSR_K7_EVNTSEL1:
- case MSR_K7_EVNTSEL2:
- case MSR_K7_EVNTSEL3:
- case MSR_K7_PERFCTR0:
- case MSR_K7_PERFCTR1:
- case MSR_K7_PERFCTR2:
- case MSR_K7_PERFCTR3:
- /*
- * Just discard all writes to the performance counters; this
- * should keep both older linux and windows 64-bit guests
- * happy
- */
- pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", ecx, data);
-
- break;
case MSR_VM_HSAVE_PA:
svm->hsave_msr = data;
break;
+ case MSR_VM_CR:
+ case MSR_VM_IGNNE:
+ pr_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
+ break;
default:
return kvm_set_msr_common(vcpu, ecx, data);
}
@@ -2122,8 +2152,7 @@ static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
u64 data = (svm->vcpu.arch.regs[VCPU_REGS_RAX] & -1u)
| ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32);
- KVMTRACE_3D(MSR_WRITE, &svm->vcpu, ecx, (u32)data, (u32)(data >> 32),
- handler);
+ trace_kvm_msr_write(ecx, data);
svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
if (svm_set_msr(&svm->vcpu, ecx, data))
@@ -2144,8 +2173,6 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
static int interrupt_window_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
- KVMTRACE_0D(PEND_INTR, &svm->vcpu, handler);
-
svm_clear_vintr(svm);
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
@@ -2201,7 +2228,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
[SVM_EXIT_INVD] = emulate_on_interception,
[SVM_EXIT_HLT] = halt_interception,
[SVM_EXIT_INVLPG] = invlpg_interception,
- [SVM_EXIT_INVLPGA] = invalid_op_interception,
+ [SVM_EXIT_INVLPGA] = invlpga_interception,
[SVM_EXIT_IOIO] = io_interception,
[SVM_EXIT_MSR] = msr_interception,
[SVM_EXIT_TASK_SWITCH] = task_switch_interception,
@@ -2224,8 +2251,7 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
u32 exit_code = svm->vmcb->control.exit_code;
- KVMTRACE_3D(VMEXIT, vcpu, exit_code, (u32)svm->vmcb->save.rip,
- (u32)((u64)svm->vmcb->save.rip >> 32), entryexit);
+ trace_kvm_exit(exit_code, svm->vmcb->save.rip);
if (is_nested(svm)) {
nsvm_printk("nested handle_exit: 0x%x | 0x%lx | 0x%lx | 0x%lx\n",
@@ -2246,12 +2272,6 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
}
vcpu->arch.cr0 = svm->vmcb->save.cr0;
vcpu->arch.cr3 = svm->vmcb->save.cr3;
- if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
- if (!load_pdptrs(vcpu, vcpu->arch.cr3)) {
- kvm_inject_gp(vcpu, 0);
- return 1;
- }
- }
if (mmu_reload) {
kvm_mmu_reset_context(vcpu);
kvm_mmu_load(vcpu);
@@ -2300,8 +2320,8 @@ static void pre_svm_run(struct vcpu_svm *svm)
struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
- if (svm->vcpu.cpu != cpu ||
- svm->asid_generation != svm_data->asid_generation)
+ /* FIXME: handle wraparound of asid_generation */
+ if (svm->asid_generation != svm_data->asid_generation)
new_asid(svm, svm_data);
}
@@ -2319,7 +2339,7 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
{
struct vmcb_control_area *control;
- KVMTRACE_1D(INJ_VIRQ, &svm->vcpu, (u32)irq, handler);
+ trace_kvm_inj_virq(irq);
++svm->vcpu.stat.irq_injections;
control = &svm->vmcb->control;
@@ -2329,21 +2349,14 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
}
-static void svm_queue_irq(struct kvm_vcpu *vcpu, unsigned nr)
-{
- struct vcpu_svm *svm = to_svm(vcpu);
-
- svm->vmcb->control.event_inj = nr |
- SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
-}
-
static void svm_set_irq(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- nested_svm_intr(svm);
+ BUG_ON(!(svm->vcpu.arch.hflags & HF_GIF_MASK));
- svm_queue_irq(vcpu, vcpu->arch.interrupt.nr);
+ svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
+ SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
}
static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
@@ -2371,13 +2384,25 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
struct vmcb *vmcb = svm->vmcb;
return (vmcb->save.rflags & X86_EFLAGS_IF) &&
!(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
- (svm->vcpu.arch.hflags & HF_GIF_MASK);
+ (svm->vcpu.arch.hflags & HF_GIF_MASK) &&
+ !is_nested(svm);
}
static void enable_irq_window(struct kvm_vcpu *vcpu)
{
- svm_set_vintr(to_svm(vcpu));
- svm_inject_irq(to_svm(vcpu), 0x0);
+ struct vcpu_svm *svm = to_svm(vcpu);
+ nsvm_printk("Trying to open IRQ window\n");
+
+ nested_svm_intr(svm);
+
+ /* In case GIF=0 we can't rely on the CPU to tell us when
+ * GIF becomes 1, because that's a separate STGI/VMRUN intercept.
+ * The next time we get that intercept, this function will be
+ * called again though and we'll get the vintr intercept. */
+ if (svm->vcpu.arch.hflags & HF_GIF_MASK) {
+ svm_set_vintr(svm);
+ svm_inject_irq(svm, 0x0);
+ }
}
static void enable_nmi_window(struct kvm_vcpu *vcpu)
@@ -2456,6 +2481,8 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
case SVM_EXITINTINFO_TYPE_EXEPT:
/* In case of software exception do not reinject an exception
vector, but re-execute and instruction instead */
+ if (is_nested(svm))
+ break;
if (kvm_exception_is_soft(vector))
break;
if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
@@ -2498,7 +2525,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
fs_selector = kvm_read_fs();
gs_selector = kvm_read_gs();
ldt_selector = kvm_read_ldt();
- svm->host_cr2 = kvm_read_cr2();
if (!is_nested(svm))
svm->vmcb->save.cr2 = vcpu->arch.cr2;
/* required for live migration with NPT */
@@ -2585,8 +2611,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
- kvm_write_cr2(svm->host_cr2);
-
kvm_load_fs(fs_selector);
kvm_load_gs(gs_selector);
kvm_load_ldt(ldt_selector);
@@ -2602,6 +2626,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
svm->next_rip = 0;
+ if (npt_enabled) {
+ vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
+ vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR);
+ }
+
svm_complete_interrupts(svm);
}
@@ -2673,6 +2702,59 @@ static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
return 0;
}
+static const struct trace_print_flags svm_exit_reasons_str[] = {
+ { SVM_EXIT_READ_CR0, "read_cr0" },
+ { SVM_EXIT_READ_CR3, "read_cr3" },
+ { SVM_EXIT_READ_CR4, "read_cr4" },
+ { SVM_EXIT_READ_CR8, "read_cr8" },
+ { SVM_EXIT_WRITE_CR0, "write_cr0" },
+ { SVM_EXIT_WRITE_CR3, "write_cr3" },
+ { SVM_EXIT_WRITE_CR4, "write_cr4" },
+ { SVM_EXIT_WRITE_CR8, "write_cr8" },
+ { SVM_EXIT_READ_DR0, "read_dr0" },
+ { SVM_EXIT_READ_DR1, "read_dr1" },
+ { SVM_EXIT_READ_DR2, "read_dr2" },
+ { SVM_EXIT_READ_DR3, "read_dr3" },
+ { SVM_EXIT_WRITE_DR0, "write_dr0" },
+ { SVM_EXIT_WRITE_DR1, "write_dr1" },
+ { SVM_EXIT_WRITE_DR2, "write_dr2" },
+ { SVM_EXIT_WRITE_DR3, "write_dr3" },
+ { SVM_EXIT_WRITE_DR5, "write_dr5" },
+ { SVM_EXIT_WRITE_DR7, "write_dr7" },
+ { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" },
+ { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" },
+ { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" },
+ { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" },
+ { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" },
+ { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" },
+ { SVM_EXIT_INTR, "interrupt" },
+ { SVM_EXIT_NMI, "nmi" },
+ { SVM_EXIT_SMI, "smi" },
+ { SVM_EXIT_INIT, "init" },
+ { SVM_EXIT_VINTR, "vintr" },
+ { SVM_EXIT_CPUID, "cpuid" },
+ { SVM_EXIT_INVD, "invd" },
+ { SVM_EXIT_HLT, "hlt" },
+ { SVM_EXIT_INVLPG, "invlpg" },
+ { SVM_EXIT_INVLPGA, "invlpga" },
+ { SVM_EXIT_IOIO, "io" },
+ { SVM_EXIT_MSR, "msr" },
+ { SVM_EXIT_TASK_SWITCH, "task_switch" },
+ { SVM_EXIT_SHUTDOWN, "shutdown" },
+ { SVM_EXIT_VMRUN, "vmrun" },
+ { SVM_EXIT_VMMCALL, "hypercall" },
+ { SVM_EXIT_VMLOAD, "vmload" },
+ { SVM_EXIT_VMSAVE, "vmsave" },
+ { SVM_EXIT_STGI, "stgi" },
+ { SVM_EXIT_CLGI, "clgi" },
+ { SVM_EXIT_SKINIT, "skinit" },
+ { SVM_EXIT_WBINVD, "wbinvd" },
+ { SVM_EXIT_MONITOR, "monitor" },
+ { SVM_EXIT_MWAIT, "mwait" },
+ { SVM_EXIT_NPF, "npf" },
+ { -1, NULL }
+};
+
static struct kvm_x86_ops svm_x86_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
@@ -2710,6 +2792,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_gdt = svm_set_gdt,
.get_dr = svm_get_dr,
.set_dr = svm_set_dr,
+ .cache_reg = svm_cache_reg,
.get_rflags = svm_get_rflags,
.set_rflags = svm_set_rflags,
@@ -2733,6 +2816,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_tss_addr = svm_set_tss_addr,
.get_tdp_level = get_npt_level,
.get_mt_mask = svm_get_mt_mask,
+
+ .exit_reasons_str = svm_exit_reasons_str,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
index 86dbac072d0c..eea40439066c 100644
--- a/arch/x86/kvm/timer.c
+++ b/arch/x86/kvm/timer.c
@@ -9,12 +9,16 @@ static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
int restart_timer = 0;
wait_queue_head_t *q = &vcpu->wq;
- /* FIXME: this code should not know anything about vcpus */
- if (!atomic_inc_and_test(&ktimer->pending))
+ /*
+ * There is a race window between reading and incrementing, but we do
+ * not care about potentially loosing timer events in the !reinject
+ * case anyway.
+ */
+ if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
+ atomic_inc(&ktimer->pending);
+ /* FIXME: this code should not know anything about vcpus */
set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
-
- if (!ktimer->reinject)
- atomic_set(&ktimer->pending, 1);
+ }
if (waitqueue_active(q))
wake_up_interruptible(q);
@@ -33,7 +37,7 @@ enum hrtimer_restart kvm_timer_fn(struct hrtimer *data)
struct kvm_vcpu *vcpu;
struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
- vcpu = ktimer->kvm->vcpus[ktimer->vcpu_id];
+ vcpu = ktimer->vcpu;
if (!vcpu)
return HRTIMER_NORESTART;
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
new file mode 100644
index 000000000000..0d480e77eacf
--- /dev/null
+++ b/arch/x86/kvm/trace.h
@@ -0,0 +1,355 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_PATH arch/x86/kvm
+#define TRACE_INCLUDE_FILE trace
+
+/*
+ * Tracepoint for guest mode entry.
+ */
+TRACE_EVENT(kvm_entry,
+ TP_PROTO(unsigned int vcpu_id),
+ TP_ARGS(vcpu_id),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, vcpu_id )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ ),
+
+ TP_printk("vcpu %u", __entry->vcpu_id)
+);
+
+/*
+ * Tracepoint for hypercall.
+ */
+TRACE_EVENT(kvm_hypercall,
+ TP_PROTO(unsigned long nr, unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3),
+ TP_ARGS(nr, a0, a1, a2, a3),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, nr )
+ __field( unsigned long, a0 )
+ __field( unsigned long, a1 )
+ __field( unsigned long, a2 )
+ __field( unsigned long, a3 )
+ ),
+
+ TP_fast_assign(
+ __entry->nr = nr;
+ __entry->a0 = a0;
+ __entry->a1 = a1;
+ __entry->a2 = a2;
+ __entry->a3 = a3;
+ ),
+
+ TP_printk("nr 0x%lx a0 0x%lx a1 0x%lx a2 0x%lx a3 0x%lx",
+ __entry->nr, __entry->a0, __entry->a1, __entry->a2,
+ __entry->a3)
+);
+
+/*
+ * Tracepoint for PIO.
+ */
+TRACE_EVENT(kvm_pio,
+ TP_PROTO(unsigned int rw, unsigned int port, unsigned int size,
+ unsigned int count),
+ TP_ARGS(rw, port, size, count),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, rw )
+ __field( unsigned int, port )
+ __field( unsigned int, size )
+ __field( unsigned int, count )
+ ),
+
+ TP_fast_assign(
+ __entry->rw = rw;
+ __entry->port = port;
+ __entry->size = size;
+ __entry->count = count;
+ ),
+
+ TP_printk("pio_%s at 0x%x size %d count %d",
+ __entry->rw ? "write" : "read",
+ __entry->port, __entry->size, __entry->count)
+);
+
+/*
+ * Tracepoint for cpuid.
+ */
+TRACE_EVENT(kvm_cpuid,
+ TP_PROTO(unsigned int function, unsigned long rax, unsigned long rbx,
+ unsigned long rcx, unsigned long rdx),
+ TP_ARGS(function, rax, rbx, rcx, rdx),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, function )
+ __field( unsigned long, rax )
+ __field( unsigned long, rbx )
+ __field( unsigned long, rcx )
+ __field( unsigned long, rdx )
+ ),
+
+ TP_fast_assign(
+ __entry->function = function;
+ __entry->rax = rax;
+ __entry->rbx = rbx;
+ __entry->rcx = rcx;
+ __entry->rdx = rdx;
+ ),
+
+ TP_printk("func %x rax %lx rbx %lx rcx %lx rdx %lx",
+ __entry->function, __entry->rax,
+ __entry->rbx, __entry->rcx, __entry->rdx)
+);
+
+#define AREG(x) { APIC_##x, "APIC_" #x }
+
+#define kvm_trace_symbol_apic \
+ AREG(ID), AREG(LVR), AREG(TASKPRI), AREG(ARBPRI), AREG(PROCPRI), \
+ AREG(EOI), AREG(RRR), AREG(LDR), AREG(DFR), AREG(SPIV), AREG(ISR), \
+ AREG(TMR), AREG(IRR), AREG(ESR), AREG(ICR), AREG(ICR2), AREG(LVTT), \
+ AREG(LVTTHMR), AREG(LVTPC), AREG(LVT0), AREG(LVT1), AREG(LVTERR), \
+ AREG(TMICT), AREG(TMCCT), AREG(TDCR), AREG(SELF_IPI), AREG(EFEAT), \
+ AREG(ECTRL)
+/*
+ * Tracepoint for apic access.
+ */
+TRACE_EVENT(kvm_apic,
+ TP_PROTO(unsigned int rw, unsigned int reg, unsigned int val),
+ TP_ARGS(rw, reg, val),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, rw )
+ __field( unsigned int, reg )
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __entry->rw = rw;
+ __entry->reg = reg;
+ __entry->val = val;
+ ),
+
+ TP_printk("apic_%s %s = 0x%x",
+ __entry->rw ? "write" : "read",
+ __print_symbolic(__entry->reg, kvm_trace_symbol_apic),
+ __entry->val)
+);
+
+#define trace_kvm_apic_read(reg, val) trace_kvm_apic(0, reg, val)
+#define trace_kvm_apic_write(reg, val) trace_kvm_apic(1, reg, val)
+
+/*
+ * Tracepoint for kvm guest exit:
+ */
+TRACE_EVENT(kvm_exit,
+ TP_PROTO(unsigned int exit_reason, unsigned long guest_rip),
+ TP_ARGS(exit_reason, guest_rip),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, exit_reason )
+ __field( unsigned long, guest_rip )
+ ),
+
+ TP_fast_assign(
+ __entry->exit_reason = exit_reason;
+ __entry->guest_rip = guest_rip;
+ ),
+
+ TP_printk("reason %s rip 0x%lx",
+ ftrace_print_symbols_seq(p, __entry->exit_reason,
+ kvm_x86_ops->exit_reasons_str),
+ __entry->guest_rip)
+);
+
+/*
+ * Tracepoint for kvm interrupt injection:
+ */
+TRACE_EVENT(kvm_inj_virq,
+ TP_PROTO(unsigned int irq),
+ TP_ARGS(irq),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, irq )
+ ),
+
+ TP_fast_assign(
+ __entry->irq = irq;
+ ),
+
+ TP_printk("irq %u", __entry->irq)
+);
+
+/*
+ * Tracepoint for page fault.
+ */
+TRACE_EVENT(kvm_page_fault,
+ TP_PROTO(unsigned long fault_address, unsigned int error_code),
+ TP_ARGS(fault_address, error_code),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, fault_address )
+ __field( unsigned int, error_code )
+ ),
+
+ TP_fast_assign(
+ __entry->fault_address = fault_address;
+ __entry->error_code = error_code;
+ ),
+
+ TP_printk("address %lx error_code %x",
+ __entry->fault_address, __entry->error_code)
+);
+
+/*
+ * Tracepoint for guest MSR access.
+ */
+TRACE_EVENT(kvm_msr,
+ TP_PROTO(unsigned int rw, unsigned int ecx, unsigned long data),
+ TP_ARGS(rw, ecx, data),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, rw )
+ __field( unsigned int, ecx )
+ __field( unsigned long, data )
+ ),
+
+ TP_fast_assign(
+ __entry->rw = rw;
+ __entry->ecx = ecx;
+ __entry->data = data;
+ ),
+
+ TP_printk("msr_%s %x = 0x%lx",
+ __entry->rw ? "write" : "read",
+ __entry->ecx, __entry->data)
+);
+
+#define trace_kvm_msr_read(ecx, data) trace_kvm_msr(0, ecx, data)
+#define trace_kvm_msr_write(ecx, data) trace_kvm_msr(1, ecx, data)
+
+/*
+ * Tracepoint for guest CR access.
+ */
+TRACE_EVENT(kvm_cr,
+ TP_PROTO(unsigned int rw, unsigned int cr, unsigned long val),
+ TP_ARGS(rw, cr, val),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, rw )
+ __field( unsigned int, cr )
+ __field( unsigned long, val )
+ ),
+
+ TP_fast_assign(
+ __entry->rw = rw;
+ __entry->cr = cr;
+ __entry->val = val;
+ ),
+
+ TP_printk("cr_%s %x = 0x%lx",
+ __entry->rw ? "write" : "read",
+ __entry->cr, __entry->val)
+);
+
+#define trace_kvm_cr_read(cr, val) trace_kvm_cr(0, cr, val)
+#define trace_kvm_cr_write(cr, val) trace_kvm_cr(1, cr, val)
+
+TRACE_EVENT(kvm_pic_set_irq,
+ TP_PROTO(__u8 chip, __u8 pin, __u8 elcr, __u8 imr, bool coalesced),
+ TP_ARGS(chip, pin, elcr, imr, coalesced),
+
+ TP_STRUCT__entry(
+ __field( __u8, chip )
+ __field( __u8, pin )
+ __field( __u8, elcr )
+ __field( __u8, imr )
+ __field( bool, coalesced )
+ ),
+
+ TP_fast_assign(
+ __entry->chip = chip;
+ __entry->pin = pin;
+ __entry->elcr = elcr;
+ __entry->imr = imr;
+ __entry->coalesced = coalesced;
+ ),
+
+ TP_printk("chip %u pin %u (%s%s)%s",
+ __entry->chip, __entry->pin,
+ (__entry->elcr & (1 << __entry->pin)) ? "level":"edge",
+ (__entry->imr & (1 << __entry->pin)) ? "|masked":"",
+ __entry->coalesced ? " (coalesced)" : "")
+);
+
+#define kvm_apic_dst_shorthand \
+ {0x0, "dst"}, \
+ {0x1, "self"}, \
+ {0x2, "all"}, \
+ {0x3, "all-but-self"}
+
+TRACE_EVENT(kvm_apic_ipi,
+ TP_PROTO(__u32 icr_low, __u32 dest_id),
+ TP_ARGS(icr_low, dest_id),
+
+ TP_STRUCT__entry(
+ __field( __u32, icr_low )
+ __field( __u32, dest_id )
+ ),
+
+ TP_fast_assign(
+ __entry->icr_low = icr_low;
+ __entry->dest_id = dest_id;
+ ),
+
+ TP_printk("dst %x vec %u (%s|%s|%s|%s|%s)",
+ __entry->dest_id, (u8)__entry->icr_low,
+ __print_symbolic((__entry->icr_low >> 8 & 0x7),
+ kvm_deliver_mode),
+ (__entry->icr_low & (1<<11)) ? "logical" : "physical",
+ (__entry->icr_low & (1<<14)) ? "assert" : "de-assert",
+ (__entry->icr_low & (1<<15)) ? "level" : "edge",
+ __print_symbolic((__entry->icr_low >> 18 & 0x3),
+ kvm_apic_dst_shorthand))
+);
+
+TRACE_EVENT(kvm_apic_accept_irq,
+ TP_PROTO(__u32 apicid, __u16 dm, __u8 tm, __u8 vec, bool coalesced),
+ TP_ARGS(apicid, dm, tm, vec, coalesced),
+
+ TP_STRUCT__entry(
+ __field( __u32, apicid )
+ __field( __u16, dm )
+ __field( __u8, tm )
+ __field( __u8, vec )
+ __field( bool, coalesced )
+ ),
+
+ TP_fast_assign(
+ __entry->apicid = apicid;
+ __entry->dm = dm;
+ __entry->tm = tm;
+ __entry->vec = vec;
+ __entry->coalesced = coalesced;
+ ),
+
+ TP_printk("apicid %x vec %u (%s|%s)%s",
+ __entry->apicid, __entry->vec,
+ __print_symbolic((__entry->dm >> 8 & 0x7), kvm_deliver_mode),
+ __entry->tm ? "level" : "edge",
+ __entry->coalesced ? " (coalesced)" : "")
+);
+
+#endif /* _TRACE_KVM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 356a0ce85c68..7931c72a9165 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -25,6 +25,7 @@
#include <linux/highmem.h>
#include <linux/sched.h>
#include <linux/moduleparam.h>
+#include <linux/ftrace_event.h>
#include "kvm_cache_regs.h"
#include "x86.h"
@@ -34,6 +35,8 @@
#include <asm/virtext.h>
#include <asm/mce.h>
+#include "trace.h"
+
#define __ex(x) __kvm_handle_fault_on_reboot(x)
MODULE_AUTHOR("Qumranet");
@@ -51,6 +54,10 @@ module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
static int __read_mostly enable_ept = 1;
module_param_named(ept, enable_ept, bool, S_IRUGO);
+static int __read_mostly enable_unrestricted_guest = 1;
+module_param_named(unrestricted_guest,
+ enable_unrestricted_guest, bool, S_IRUGO);
+
static int __read_mostly emulate_invalid_guest_state = 0;
module_param(emulate_invalid_guest_state, bool, S_IRUGO);
@@ -84,6 +91,14 @@ struct vcpu_vmx {
int guest_efer_loaded;
} host_state;
struct {
+ int vm86_active;
+ u8 save_iopl;
+ struct kvm_save_segment {
+ u16 selector;
+ unsigned long base;
+ u32 limit;
+ u32 ar;
+ } tr, es, ds, fs, gs;
struct {
bool pending;
u8 vector;
@@ -161,6 +176,8 @@ static struct kvm_vmx_segment_field {
VMX_SEGMENT_FIELD(LDTR),
};
+static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
+
/*
* Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
* away by decrementing the array size.
@@ -256,6 +273,26 @@ static inline bool cpu_has_vmx_flexpriority(void)
cpu_has_vmx_virtualize_apic_accesses();
}
+static inline bool cpu_has_vmx_ept_execute_only(void)
+{
+ return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_uncacheable(void)
+{
+ return !!(vmx_capability.ept & VMX_EPTP_UC_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_writeback(void)
+{
+ return !!(vmx_capability.ept & VMX_EPTP_WB_BIT);
+}
+
+static inline bool cpu_has_vmx_ept_2m_page(void)
+{
+ return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT);
+}
+
static inline int cpu_has_vmx_invept_individual_addr(void)
{
return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
@@ -277,6 +314,12 @@ static inline int cpu_has_vmx_ept(void)
SECONDARY_EXEC_ENABLE_EPT;
}
+static inline int cpu_has_vmx_unrestricted_guest(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_UNRESTRICTED_GUEST;
+}
+
static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
{
return flexpriority_enabled &&
@@ -504,7 +547,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
eb |= 1u << BP_VECTOR;
}
- if (vcpu->arch.rmode.vm86_active)
+ if (to_vmx(vcpu)->rmode.vm86_active)
eb = ~0;
if (enable_ept)
eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */
@@ -740,7 +783,7 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
- if (vcpu->arch.rmode.vm86_active)
+ if (to_vmx(vcpu)->rmode.vm86_active)
rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
vmcs_writel(GUEST_RFLAGS, rflags);
}
@@ -797,12 +840,13 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
intr_info |= INTR_INFO_DELIVER_CODE_MASK;
}
- if (vcpu->arch.rmode.vm86_active) {
+ if (vmx->rmode.vm86_active) {
vmx->rmode.irq.pending = true;
vmx->rmode.irq.vector = nr;
vmx->rmode.irq.rip = kvm_rip_read(vcpu);
- if (nr == BP_VECTOR || nr == OF_VECTOR)
- vmx->rmode.irq.rip++;
+ if (kvm_exception_is_soft(nr))
+ vmx->rmode.irq.rip +=
+ vmx->vcpu.arch.event_exit_inst_len;
intr_info |= INTR_TYPE_SOFT_INTR;
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
@@ -940,7 +984,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
case MSR_EFER:
return kvm_get_msr_common(vcpu, msr_index, pdata);
#endif
- case MSR_IA32_TIME_STAMP_COUNTER:
+ case MSR_IA32_TSC:
data = guest_read_tsc();
break;
case MSR_IA32_SYSENTER_CS:
@@ -1000,22 +1044,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
case MSR_IA32_SYSENTER_ESP:
vmcs_writel(GUEST_SYSENTER_ESP, data);
break;
- case MSR_IA32_TIME_STAMP_COUNTER:
+ case MSR_IA32_TSC:
rdtscll(host_tsc);
guest_write_tsc(data, host_tsc);
break;
- case MSR_P6_PERFCTR0:
- case MSR_P6_PERFCTR1:
- case MSR_P6_EVNTSEL0:
- case MSR_P6_EVNTSEL1:
- /*
- * Just discard all writes to the performance counters; this
- * should keep both older linux and windows 64-bit guests
- * happy
- */
- pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", msr_index, data);
-
- break;
case MSR_IA32_CR_PAT:
if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
vmcs_write64(GUEST_IA32_PAT, data);
@@ -1046,6 +1078,10 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
case VCPU_REGS_RIP:
vcpu->arch.regs[VCPU_REGS_RIP] = vmcs_readl(GUEST_RIP);
break;
+ case VCPU_EXREG_PDPTR:
+ if (enable_ept)
+ ept_save_pdptrs(vcpu);
+ break;
default:
break;
}
@@ -1203,7 +1239,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
opt2 = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
SECONDARY_EXEC_WBINVD_EXITING |
SECONDARY_EXEC_ENABLE_VPID |
- SECONDARY_EXEC_ENABLE_EPT;
+ SECONDARY_EXEC_ENABLE_EPT |
+ SECONDARY_EXEC_UNRESTRICTED_GUEST;
if (adjust_vmx_controls(min2, opt2,
MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
@@ -1333,8 +1370,13 @@ static __init int hardware_setup(void)
if (!cpu_has_vmx_vpid())
enable_vpid = 0;
- if (!cpu_has_vmx_ept())
+ if (!cpu_has_vmx_ept()) {
enable_ept = 0;
+ enable_unrestricted_guest = 0;
+ }
+
+ if (!cpu_has_vmx_unrestricted_guest())
+ enable_unrestricted_guest = 0;
if (!cpu_has_vmx_flexpriority())
flexpriority_enabled = 0;
@@ -1342,6 +1384,9 @@ static __init int hardware_setup(void)
if (!cpu_has_vmx_tpr_shadow())
kvm_x86_ops->update_cr8_intercept = NULL;
+ if (enable_ept && !cpu_has_vmx_ept_2m_page())
+ kvm_disable_largepages();
+
return alloc_kvm_area();
}
@@ -1372,15 +1417,15 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu);
vmx->emulation_required = 1;
- vcpu->arch.rmode.vm86_active = 0;
+ vmx->rmode.vm86_active = 0;
- vmcs_writel(GUEST_TR_BASE, vcpu->arch.rmode.tr.base);
- vmcs_write32(GUEST_TR_LIMIT, vcpu->arch.rmode.tr.limit);
- vmcs_write32(GUEST_TR_AR_BYTES, vcpu->arch.rmode.tr.ar);
+ vmcs_writel(GUEST_TR_BASE, vmx->rmode.tr.base);
+ vmcs_write32(GUEST_TR_LIMIT, vmx->rmode.tr.limit);
+ vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar);
flags = vmcs_readl(GUEST_RFLAGS);
flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
- flags |= (vcpu->arch.rmode.save_iopl << IOPL_SHIFT);
+ flags |= (vmx->rmode.save_iopl << IOPL_SHIFT);
vmcs_writel(GUEST_RFLAGS, flags);
vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
@@ -1391,10 +1436,10 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
if (emulate_invalid_guest_state)
return;
- fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->arch.rmode.es);
- fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->arch.rmode.ds);
- fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->arch.rmode.gs);
- fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->arch.rmode.fs);
+ fix_pmode_dataseg(VCPU_SREG_ES, &vmx->rmode.es);
+ fix_pmode_dataseg(VCPU_SREG_DS, &vmx->rmode.ds);
+ fix_pmode_dataseg(VCPU_SREG_GS, &vmx->rmode.gs);
+ fix_pmode_dataseg(VCPU_SREG_FS, &vmx->rmode.fs);
vmcs_write16(GUEST_SS_SELECTOR, 0);
vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
@@ -1433,20 +1478,23 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
unsigned long flags;
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ if (enable_unrestricted_guest)
+ return;
+
vmx->emulation_required = 1;
- vcpu->arch.rmode.vm86_active = 1;
+ vmx->rmode.vm86_active = 1;
- vcpu->arch.rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
+ vmx->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
- vcpu->arch.rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT);
+ vmx->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT);
vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1);
- vcpu->arch.rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES);
+ vmx->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES);
vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
flags = vmcs_readl(GUEST_RFLAGS);
- vcpu->arch.rmode.save_iopl
+ vmx->rmode.save_iopl
= (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
@@ -1468,10 +1516,10 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_CS_BASE, 0xf0000);
vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
- fix_rmode_seg(VCPU_SREG_ES, &vcpu->arch.rmode.es);
- fix_rmode_seg(VCPU_SREG_DS, &vcpu->arch.rmode.ds);
- fix_rmode_seg(VCPU_SREG_GS, &vcpu->arch.rmode.gs);
- fix_rmode_seg(VCPU_SREG_FS, &vcpu->arch.rmode.fs);
+ fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es);
+ fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds);
+ fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs);
+ fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs);
continue_rmode:
kvm_mmu_reset_context(vcpu);
@@ -1545,11 +1593,11 @@ static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
{
+ if (!test_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_dirty))
+ return;
+
if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
- if (!load_pdptrs(vcpu, vcpu->arch.cr3)) {
- printk(KERN_ERR "EPT: Fail to load pdptrs!\n");
- return;
- }
vmcs_write64(GUEST_PDPTR0, vcpu->arch.pdptrs[0]);
vmcs_write64(GUEST_PDPTR1, vcpu->arch.pdptrs[1]);
vmcs_write64(GUEST_PDPTR2, vcpu->arch.pdptrs[2]);
@@ -1557,6 +1605,21 @@ static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
}
}
+static void ept_save_pdptrs(struct kvm_vcpu *vcpu)
+{
+ if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
+ vcpu->arch.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+ vcpu->arch.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+ vcpu->arch.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+ vcpu->arch.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+ }
+
+ __set_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_avail);
+ __set_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_dirty);
+}
+
static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
@@ -1571,7 +1634,6 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
CPU_BASED_CR3_STORE_EXITING));
vcpu->arch.cr0 = cr0;
vmx_set_cr4(vcpu, vcpu->arch.cr4);
- *hw_cr0 |= X86_CR0_PE | X86_CR0_PG;
*hw_cr0 &= ~X86_CR0_WP;
} else if (!is_paging(vcpu)) {
/* From nonpaging to paging */
@@ -1598,15 +1660,21 @@ static void ept_update_paging_mode_cr4(unsigned long *hw_cr4,
static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
- unsigned long hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK) |
- KVM_VM_CR0_ALWAYS_ON;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ unsigned long hw_cr0;
+
+ if (enable_unrestricted_guest)
+ hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST)
+ | KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST;
+ else
+ hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON;
vmx_fpu_deactivate(vcpu);
- if (vcpu->arch.rmode.vm86_active && (cr0 & X86_CR0_PE))
+ if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE))
enter_pmode(vcpu);
- if (!vcpu->arch.rmode.vm86_active && !(cr0 & X86_CR0_PE))
+ if (!vmx->rmode.vm86_active && !(cr0 & X86_CR0_PE))
enter_rmode(vcpu);
#ifdef CONFIG_X86_64
@@ -1650,10 +1718,8 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
if (enable_ept) {
eptp = construct_eptp(cr3);
vmcs_write64(EPT_POINTER, eptp);
- ept_sync_context(eptp);
- ept_load_pdptrs(vcpu);
guest_cr3 = is_paging(vcpu) ? vcpu->arch.cr3 :
- VMX_EPT_IDENTITY_PAGETABLE_ADDR;
+ vcpu->kvm->arch.ept_identity_map_addr;
}
vmx_flush_tlb(vcpu);
@@ -1664,7 +1730,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
- unsigned long hw_cr4 = cr4 | (vcpu->arch.rmode.vm86_active ?
+ unsigned long hw_cr4 = cr4 | (to_vmx(vcpu)->rmode.vm86_active ?
KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON);
vcpu->arch.cr4 = cr4;
@@ -1744,20 +1810,21 @@ static u32 vmx_segment_access_rights(struct kvm_segment *var)
static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
u32 ar;
- if (vcpu->arch.rmode.vm86_active && seg == VCPU_SREG_TR) {
- vcpu->arch.rmode.tr.selector = var->selector;
- vcpu->arch.rmode.tr.base = var->base;
- vcpu->arch.rmode.tr.limit = var->limit;
- vcpu->arch.rmode.tr.ar = vmx_segment_access_rights(var);
+ if (vmx->rmode.vm86_active && seg == VCPU_SREG_TR) {
+ vmx->rmode.tr.selector = var->selector;
+ vmx->rmode.tr.base = var->base;
+ vmx->rmode.tr.limit = var->limit;
+ vmx->rmode.tr.ar = vmx_segment_access_rights(var);
return;
}
vmcs_writel(sf->base, var->base);
vmcs_write32(sf->limit, var->limit);
vmcs_write16(sf->selector, var->selector);
- if (vcpu->arch.rmode.vm86_active && var->s) {
+ if (vmx->rmode.vm86_active && var->s) {
/*
* Hack real-mode segments into vm86 compatibility.
*/
@@ -1766,6 +1833,21 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
ar = 0xf3;
} else
ar = vmx_segment_access_rights(var);
+
+ /*
+ * Fix the "Accessed" bit in AR field of segment registers for older
+ * qemu binaries.
+ * IA32 arch specifies that at the time of processor reset the
+ * "Accessed" bit in the AR field of segment registers is 1. And qemu
+ * is setting it to 0 in the usedland code. This causes invalid guest
+ * state vmexit when "unrestricted guest" mode is turned on.
+ * Fix for this setup issue in cpu_reset is being pushed in the qemu
+ * tree. Newer qemu binaries with that qemu fix would not need this
+ * kvm hack.
+ */
+ if (enable_unrestricted_guest && (seg != VCPU_SREG_LDTR))
+ ar |= 0x1; /* Accessed */
+
vmcs_write32(sf->ar_bytes, ar);
}
@@ -2040,7 +2122,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
if (likely(kvm->arch.ept_identity_pagetable_done))
return 1;
ret = 0;
- identity_map_pfn = VMX_EPT_IDENTITY_PAGETABLE_ADDR >> PAGE_SHIFT;
+ identity_map_pfn = kvm->arch.ept_identity_map_addr >> PAGE_SHIFT;
r = kvm_clear_guest_page(kvm, identity_map_pfn, 0, PAGE_SIZE);
if (r < 0)
goto out;
@@ -2062,11 +2144,19 @@ out:
static void seg_setup(int seg)
{
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ unsigned int ar;
vmcs_write16(sf->selector, 0);
vmcs_writel(sf->base, 0);
vmcs_write32(sf->limit, 0xffff);
- vmcs_write32(sf->ar_bytes, 0xf3);
+ if (enable_unrestricted_guest) {
+ ar = 0x93;
+ if (seg == VCPU_SREG_CS)
+ ar |= 0x08; /* code segment */
+ } else
+ ar = 0xf3;
+
+ vmcs_write32(sf->ar_bytes, ar);
}
static int alloc_apic_access_page(struct kvm *kvm)
@@ -2101,7 +2191,8 @@ static int alloc_identity_pagetable(struct kvm *kvm)
goto out;
kvm_userspace_mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT;
kvm_userspace_mem.flags = 0;
- kvm_userspace_mem.guest_phys_addr = VMX_EPT_IDENTITY_PAGETABLE_ADDR;
+ kvm_userspace_mem.guest_phys_addr =
+ kvm->arch.ept_identity_map_addr;
kvm_userspace_mem.memory_size = PAGE_SIZE;
r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
if (r)
@@ -2209,6 +2300,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
if (!enable_ept)
exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
+ if (!enable_unrestricted_guest)
+ exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
}
@@ -2326,14 +2419,14 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
goto out;
}
- vmx->vcpu.arch.rmode.vm86_active = 0;
+ vmx->rmode.vm86_active = 0;
vmx->soft_vnmi_blocked = 0;
vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
kvm_set_cr8(&vmx->vcpu, 0);
msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (vmx->vcpu.vcpu_id == 0)
+ if (kvm_vcpu_is_bsp(&vmx->vcpu))
msr |= MSR_IA32_APICBASE_BSP;
kvm_set_apic_base(&vmx->vcpu, msr);
@@ -2344,7 +2437,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
* GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
* insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh.
*/
- if (vmx->vcpu.vcpu_id == 0) {
+ if (kvm_vcpu_is_bsp(&vmx->vcpu)) {
vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
vmcs_writel(GUEST_CS_BASE, 0x000f0000);
} else {
@@ -2373,7 +2466,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_SYSENTER_EIP, 0);
vmcs_writel(GUEST_RFLAGS, 0x02);
- if (vmx->vcpu.vcpu_id == 0)
+ if (kvm_vcpu_is_bsp(&vmx->vcpu))
kvm_rip_write(vcpu, 0xfff0);
else
kvm_rip_write(vcpu, 0);
@@ -2461,13 +2554,16 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu)
uint32_t intr;
int irq = vcpu->arch.interrupt.nr;
- KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler);
+ trace_kvm_inj_virq(irq);
++vcpu->stat.irq_injections;
- if (vcpu->arch.rmode.vm86_active) {
+ if (vmx->rmode.vm86_active) {
vmx->rmode.irq.pending = true;
vmx->rmode.irq.vector = irq;
vmx->rmode.irq.rip = kvm_rip_read(vcpu);
+ if (vcpu->arch.interrupt.soft)
+ vmx->rmode.irq.rip +=
+ vmx->vcpu.arch.event_exit_inst_len;
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK);
vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
@@ -2502,7 +2598,7 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
}
++vcpu->stat.nmi_injections;
- if (vcpu->arch.rmode.vm86_active) {
+ if (vmx->rmode.vm86_active) {
vmx->rmode.irq.pending = true;
vmx->rmode.irq.vector = NMI_VECTOR;
vmx->rmode.irq.rip = kvm_rip_read(vcpu);
@@ -2659,14 +2755,14 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (enable_ept)
BUG();
cr2 = vmcs_readl(EXIT_QUALIFICATION);
- KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
- (u32)((u64)cr2 >> 32), handler);
+ trace_kvm_page_fault(cr2, error_code);
+
if (kvm_event_needs_reinjection(vcpu))
kvm_mmu_unprotect_page_virt(vcpu, cr2);
return kvm_mmu_page_fault(vcpu, cr2, error_code);
}
- if (vcpu->arch.rmode.vm86_active &&
+ if (vmx->rmode.vm86_active &&
handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
error_code)) {
if (vcpu->arch.halt_request) {
@@ -2707,7 +2803,6 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
++vcpu->stat.irq_exits;
- KVMTRACE_1D(INTR, vcpu, vmcs_read32(VM_EXIT_INTR_INFO), handler);
return 1;
}
@@ -2755,7 +2850,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- unsigned long exit_qualification;
+ unsigned long exit_qualification, val;
int cr;
int reg;
@@ -2764,21 +2859,19 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
reg = (exit_qualification >> 8) & 15;
switch ((exit_qualification >> 4) & 3) {
case 0: /* mov to cr */
- KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr,
- (u32)kvm_register_read(vcpu, reg),
- (u32)((u64)kvm_register_read(vcpu, reg) >> 32),
- handler);
+ val = kvm_register_read(vcpu, reg);
+ trace_kvm_cr_write(cr, val);
switch (cr) {
case 0:
- kvm_set_cr0(vcpu, kvm_register_read(vcpu, reg));
+ kvm_set_cr0(vcpu, val);
skip_emulated_instruction(vcpu);
return 1;
case 3:
- kvm_set_cr3(vcpu, kvm_register_read(vcpu, reg));
+ kvm_set_cr3(vcpu, val);
skip_emulated_instruction(vcpu);
return 1;
case 4:
- kvm_set_cr4(vcpu, kvm_register_read(vcpu, reg));
+ kvm_set_cr4(vcpu, val);
skip_emulated_instruction(vcpu);
return 1;
case 8: {
@@ -2800,23 +2893,19 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->arch.cr0 &= ~X86_CR0_TS;
vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0);
vmx_fpu_activate(vcpu);
- KVMTRACE_0D(CLTS, vcpu, handler);
skip_emulated_instruction(vcpu);
return 1;
case 1: /*mov from cr*/
switch (cr) {
case 3:
kvm_register_write(vcpu, reg, vcpu->arch.cr3);
- KVMTRACE_3D(CR_READ, vcpu, (u32)cr,
- (u32)kvm_register_read(vcpu, reg),
- (u32)((u64)kvm_register_read(vcpu, reg) >> 32),
- handler);
+ trace_kvm_cr_read(cr, vcpu->arch.cr3);
skip_emulated_instruction(vcpu);
return 1;
case 8:
- kvm_register_write(vcpu, reg, kvm_get_cr8(vcpu));
- KVMTRACE_2D(CR_READ, vcpu, (u32)cr,
- (u32)kvm_register_read(vcpu, reg), handler);
+ val = kvm_get_cr8(vcpu);
+ kvm_register_write(vcpu, reg, val);
+ trace_kvm_cr_read(cr, val);
skip_emulated_instruction(vcpu);
return 1;
}
@@ -2884,7 +2973,6 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
val = 0;
}
kvm_register_write(vcpu, reg, val);
- KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
} else {
val = vcpu->arch.regs[reg];
switch (dr) {
@@ -2917,7 +3005,6 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
break;
}
- KVMTRACE_2D(DR_WRITE, vcpu, (u32)dr, (u32)val, handler);
}
skip_emulated_instruction(vcpu);
return 1;
@@ -2939,8 +3026,7 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
- KVMTRACE_3D(MSR_READ, vcpu, ecx, (u32)data, (u32)(data >> 32),
- handler);
+ trace_kvm_msr_read(ecx, data);
/* FIXME: handling of bits 32:63 of rax, rdx */
vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u;
@@ -2955,8 +3041,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u)
| ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32);
- KVMTRACE_3D(MSR_WRITE, vcpu, ecx, (u32)data, (u32)(data >> 32),
- handler);
+ trace_kvm_msr_write(ecx, data);
if (vmx_set_msr(vcpu, ecx, data) != 0) {
kvm_inject_gp(vcpu, 0);
@@ -2983,7 +3068,6 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
- KVMTRACE_0D(PEND_INTR, vcpu, handler);
++vcpu->stat.irq_window_exits;
/*
@@ -3049,7 +3133,7 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
printk(KERN_ERR
"Fail to handle apic access vmexit! Offset is 0x%lx\n",
offset);
- return -ENOTSUPP;
+ return -ENOEXEC;
}
return 1;
}
@@ -3118,7 +3202,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (exit_qualification & (1 << 6)) {
printk(KERN_ERR "EPT: GPA exceeds GAW!\n");
- return -ENOTSUPP;
+ return -EINVAL;
}
gla_validity = (exit_qualification >> 7) & 0x3;
@@ -3130,14 +3214,98 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
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 = 0;
- return -ENOTSUPP;
+ kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_VIOLATION;
+ return 0;
}
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+ trace_kvm_page_fault(gpa, exit_qualification);
return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0);
}
+static u64 ept_rsvd_mask(u64 spte, int level)
+{
+ int i;
+ u64 mask = 0;
+
+ for (i = 51; i > boot_cpu_data.x86_phys_bits; i--)
+ mask |= (1ULL << i);
+
+ if (level > 2)
+ /* bits 7:3 reserved */
+ mask |= 0xf8;
+ else if (level == 2) {
+ if (spte & (1ULL << 7))
+ /* 2MB ref, bits 20:12 reserved */
+ mask |= 0x1ff000;
+ else
+ /* bits 6:3 reserved */
+ mask |= 0x78;
+ }
+
+ return mask;
+}
+
+static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte,
+ int level)
+{
+ printk(KERN_ERR "%s: spte 0x%llx level %d\n", __func__, spte, level);
+
+ /* 010b (write-only) */
+ WARN_ON((spte & 0x7) == 0x2);
+
+ /* 110b (write/execute) */
+ WARN_ON((spte & 0x7) == 0x6);
+
+ /* 100b (execute-only) and value not supported by logical processor */
+ if (!cpu_has_vmx_ept_execute_only())
+ WARN_ON((spte & 0x7) == 0x4);
+
+ /* not 000b */
+ if ((spte & 0x7)) {
+ u64 rsvd_bits = spte & ept_rsvd_mask(spte, level);
+
+ if (rsvd_bits != 0) {
+ printk(KERN_ERR "%s: rsvd_bits = 0x%llx\n",
+ __func__, rsvd_bits);
+ WARN_ON(1);
+ }
+
+ if (level == 1 || (level == 2 && (spte & (1ULL << 7)))) {
+ u64 ept_mem_type = (spte & 0x38) >> 3;
+
+ if (ept_mem_type == 2 || ept_mem_type == 3 ||
+ ept_mem_type == 7) {
+ printk(KERN_ERR "%s: ept_mem_type=0x%llx\n",
+ __func__, ept_mem_type);
+ WARN_ON(1);
+ }
+ }
+ }
+}
+
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u64 sptes[4];
+ int nr_sptes, i;
+ gpa_t gpa;
+
+ gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+
+ printk(KERN_ERR "EPT: Misconfiguration.\n");
+ printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa);
+
+ nr_sptes = kvm_mmu_get_spte_hierarchy(vcpu, gpa, sptes);
+
+ 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;
+
+ return 0;
+}
+
static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u32 cpu_based_vm_exec_control;
@@ -3157,8 +3325,8 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
struct vcpu_vmx *vmx = to_vmx(vcpu);
enum emulation_result err = EMULATE_DONE;
- preempt_enable();
local_irq_enable();
+ preempt_enable();
while (!guest_state_valid(vcpu)) {
err = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
@@ -3168,7 +3336,7 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
if (err != EMULATE_DONE) {
kvm_report_emulation_failure(vcpu, "emulation failure");
- return;
+ break;
}
if (signal_pending(current))
@@ -3177,8 +3345,8 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
schedule();
}
- local_irq_disable();
preempt_disable();
+ local_irq_disable();
vmx->invalid_state_emulation_result = err;
}
@@ -3217,8 +3385,9 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
[EXIT_REASON_WBINVD] = handle_wbinvd,
[EXIT_REASON_TASK_SWITCH] = handle_task_switch,
- [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
[EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check,
+ [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
+ [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig,
};
static const int kvm_vmx_max_exit_handlers =
@@ -3234,8 +3403,7 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
u32 exit_reason = vmx->exit_reason;
u32 vectoring_info = vmx->idt_vectoring_info;
- KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)kvm_rip_read(vcpu),
- (u32)((u64)kvm_rip_read(vcpu) >> 32), entryexit);
+ 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 */
@@ -3247,10 +3415,8 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
/* Access CR3 don't cause VMExit in paging mode, so we need
* to sync with guest real CR3. */
- if (enable_ept && is_paging(vcpu)) {
+ if (enable_ept && is_paging(vcpu))
vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
- ept_load_pdptrs(vcpu);
- }
if (unlikely(vmx->fail)) {
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
@@ -3326,10 +3492,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
/* We need to handle NMIs before interrupts are enabled */
if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
- (exit_intr_info & INTR_INFO_VALID_MASK)) {
- KVMTRACE_0D(NMI, &vmx->vcpu, handler);
+ (exit_intr_info & INTR_INFO_VALID_MASK))
asm("int $2");
- }
idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
@@ -3434,6 +3598,10 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ if (enable_ept && is_paging(vcpu)) {
+ vmcs_writel(GUEST_CR3, vcpu->arch.cr3);
+ ept_load_pdptrs(vcpu);
+ }
/* Record the guest's net vcpu time for enforced NMI injections. */
if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
vmx->entry_time = ktime_get();
@@ -3449,6 +3617,14 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty))
vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);
+ /* When single-stepping over STI and MOV SS, we must clear the
+ * corresponding interruptibility bits in the guest state. Otherwise
+ * vmentry fails as it then expects bit 14 (BS) in pending debug
+ * exceptions being set, but that's not correct for the guest debugging
+ * case. */
+ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+ vmx_set_interrupt_shadow(vcpu, 0);
+
/*
* Loading guest fpu may have cleared host cr0.ts
*/
@@ -3465,11 +3641,16 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
"mov %%"R"sp, %c[host_rsp](%0) \n\t"
__ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
"1: \n\t"
+ /* Reload cr2 if changed */
+ "mov %c[cr2](%0), %%"R"ax \n\t"
+ "mov %%cr2, %%"R"dx \n\t"
+ "cmp %%"R"ax, %%"R"dx \n\t"
+ "je 2f \n\t"
+ "mov %%"R"ax, %%cr2 \n\t"
+ "2: \n\t"
/* Check if vmlaunch of vmresume is needed */
"cmpl $0, %c[launched](%0) \n\t"
/* Load guest registers. Don't clobber flags. */
- "mov %c[cr2](%0), %%"R"ax \n\t"
- "mov %%"R"ax, %%cr2 \n\t"
"mov %c[rax](%0), %%"R"ax \n\t"
"mov %c[rbx](%0), %%"R"bx \n\t"
"mov %c[rdx](%0), %%"R"dx \n\t"
@@ -3547,7 +3728,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
#endif
);
- vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP));
+ vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
+ | (1 << VCPU_EXREG_PDPTR));
vcpu->arch.regs_dirty = 0;
get_debugreg(vcpu->arch.dr6, 6);
@@ -3633,9 +3815,13 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (alloc_apic_access_page(kvm) != 0)
goto free_vmcs;
- if (enable_ept)
+ if (enable_ept) {
+ if (!kvm->arch.ept_identity_map_addr)
+ kvm->arch.ept_identity_map_addr =
+ VMX_EPT_IDENTITY_PAGETABLE_ADDR;
if (alloc_identity_pagetable(kvm) != 0)
goto free_vmcs;
+ }
return &vmx->vcpu;
@@ -3699,6 +3885,29 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
return ret;
}
+static const struct trace_print_flags vmx_exit_reasons_str[] = {
+ { EXIT_REASON_EXCEPTION_NMI, "exception" },
+ { EXIT_REASON_EXTERNAL_INTERRUPT, "ext_irq" },
+ { EXIT_REASON_TRIPLE_FAULT, "triple_fault" },
+ { EXIT_REASON_NMI_WINDOW, "nmi_window" },
+ { EXIT_REASON_IO_INSTRUCTION, "io_instruction" },
+ { EXIT_REASON_CR_ACCESS, "cr_access" },
+ { EXIT_REASON_DR_ACCESS, "dr_access" },
+ { EXIT_REASON_CPUID, "cpuid" },
+ { EXIT_REASON_MSR_READ, "rdmsr" },
+ { EXIT_REASON_MSR_WRITE, "wrmsr" },
+ { EXIT_REASON_PENDING_INTERRUPT, "interrupt_window" },
+ { EXIT_REASON_HLT, "halt" },
+ { EXIT_REASON_INVLPG, "invlpg" },
+ { EXIT_REASON_VMCALL, "hypercall" },
+ { EXIT_REASON_TPR_BELOW_THRESHOLD, "tpr_below_thres" },
+ { EXIT_REASON_APIC_ACCESS, "apic_access" },
+ { EXIT_REASON_WBINVD, "wbinvd" },
+ { EXIT_REASON_TASK_SWITCH, "task_switch" },
+ { EXIT_REASON_EPT_VIOLATION, "ept_violation" },
+ { -1, NULL }
+};
+
static struct kvm_x86_ops vmx_x86_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios,
@@ -3758,6 +3967,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.set_tss_addr = vmx_set_tss_addr,
.get_tdp_level = get_ept_level,
.get_mt_mask = vmx_get_mt_mask,
+
+ .exit_reasons_str = vmx_exit_reasons_str,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index fe5474aec41a..2539e9a7ab26 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -37,11 +37,16 @@
#include <linux/iommu.h>
#include <linux/intel-iommu.h>
#include <linux/cpufreq.h>
+#include <trace/events/kvm.h>
+#undef TRACE_INCLUDE_FILE
+#define CREATE_TRACE_POINTS
+#include "trace.h"
#include <asm/uaccess.h>
#include <asm/msr.h>
#include <asm/desc.h>
#include <asm/mtrr.h>
+#include <asm/mce.h>
#define MAX_IO_MSRS 256
#define CR0_RESERVED_BITS \
@@ -55,6 +60,10 @@
| X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
+
+#define KVM_MAX_MCE_BANKS 32
+#define KVM_MCE_CAP_SUPPORTED MCG_CTL_P
+
/* EFER defaults:
* - enable syscall per default because its emulated by KVM
* - enable LME and LMA per default on 64 bit KVM
@@ -70,12 +79,13 @@ static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL;
static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
struct kvm_cpuid_entry2 __user *entries);
-struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
- u32 function, u32 index);
struct kvm_x86_ops *kvm_x86_ops;
EXPORT_SYMBOL_GPL(kvm_x86_ops);
+int ignore_msrs = 0;
+module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
+
struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "pf_fixed", VCPU_STAT(pf_fixed) },
{ "pf_guest", VCPU_STAT(pf_guest) },
@@ -122,18 +132,16 @@ unsigned long segment_base(u16 selector)
if (selector == 0)
return 0;
- asm("sgdt %0" : "=m"(gdt));
+ kvm_get_gdt(&gdt);
table_base = gdt.base;
if (selector & 4) { /* from ldt */
- u16 ldt_selector;
+ u16 ldt_selector = kvm_read_ldt();
- asm("sldt %0" : "=g"(ldt_selector));
table_base = segment_base(ldt_selector);
}
d = (struct desc_struct *)(table_base + (selector & ~7));
- v = d->base0 | ((unsigned long)d->base1 << 16) |
- ((unsigned long)d->base2 << 24);
+ v = get_desc_base(d);
#ifdef CONFIG_X86_64
if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32;
@@ -176,16 +184,22 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
++vcpu->stat.pf_guest;
if (vcpu->arch.exception.pending) {
- if (vcpu->arch.exception.nr == PF_VECTOR) {
- printk(KERN_DEBUG "kvm: inject_page_fault:"
- " double fault 0x%lx\n", addr);
- vcpu->arch.exception.nr = DF_VECTOR;
- vcpu->arch.exception.error_code = 0;
- } else if (vcpu->arch.exception.nr == DF_VECTOR) {
+ switch(vcpu->arch.exception.nr) {
+ case DF_VECTOR:
/* triple fault -> shutdown */
set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ return;
+ case PF_VECTOR:
+ vcpu->arch.exception.nr = DF_VECTOR;
+ vcpu->arch.exception.error_code = 0;
+ return;
+ default:
+ /* replace previous exception with a new one in a hope
+ that instruction re-execution will regenerate lost
+ exception */
+ vcpu->arch.exception.pending = false;
+ break;
}
- return;
}
vcpu->arch.cr2 = addr;
kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
@@ -207,13 +221,6 @@ void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
}
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
-static void __queue_exception(struct kvm_vcpu *vcpu)
-{
- kvm_x86_ops->queue_exception(vcpu, vcpu->arch.exception.nr,
- vcpu->arch.exception.has_error_code,
- vcpu->arch.exception.error_code);
-}
-
/*
* Load the pae pdptrs. Return true is they are all valid.
*/
@@ -232,7 +239,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
goto out;
}
for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
- if (is_present_pte(pdpte[i]) &&
+ if (is_present_gpte(pdpte[i]) &&
(pdpte[i] & vcpu->arch.mmu.rsvd_bits_mask[0][2])) {
ret = 0;
goto out;
@@ -241,6 +248,10 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
ret = 1;
memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
+ __set_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_avail);
+ __set_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_dirty);
out:
return ret;
@@ -256,6 +267,10 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu)
if (is_long_mode(vcpu) || !is_pae(vcpu))
return false;
+ if (!test_bit(VCPU_EXREG_PDPTR,
+ (unsigned long *)&vcpu->arch.regs_avail))
+ return true;
+
r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte));
if (r < 0)
goto out;
@@ -328,9 +343,6 @@ EXPORT_SYMBOL_GPL(kvm_set_cr0);
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
{
kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f));
- KVMTRACE_1D(LMSW, vcpu,
- (u32)((vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)),
- handler);
}
EXPORT_SYMBOL_GPL(kvm_lmsw);
@@ -466,7 +478,7 @@ static u32 msrs_to_save[] = {
#ifdef CONFIG_X86_64
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
- MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
+ MSR_IA32_TSC, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
};
@@ -644,8 +656,7 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
/* Keep irq disabled to prevent changes to the clock */
local_irq_save(flags);
- kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
- &vcpu->hv_clock.tsc_timestamp);
+ kvm_get_msr(v, MSR_IA32_TSC, &vcpu->hv_clock.tsc_timestamp);
ktime_get_ts(&ts);
local_irq_restore(flags);
@@ -704,11 +715,48 @@ static bool msr_mtrr_valid(unsigned msr)
return false;
}
+static bool valid_pat_type(unsigned t)
+{
+ return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */
+}
+
+static bool valid_mtrr_type(unsigned t)
+{
+ return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
+}
+
+static bool mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ int i;
+
+ if (!msr_mtrr_valid(msr))
+ return false;
+
+ if (msr == MSR_IA32_CR_PAT) {
+ for (i = 0; i < 8; i++)
+ if (!valid_pat_type((data >> (i * 8)) & 0xff))
+ return false;
+ return true;
+ } else if (msr == MSR_MTRRdefType) {
+ if (data & ~0xcff)
+ return false;
+ return valid_mtrr_type(data & 0xff);
+ } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) {
+ for (i = 0; i < 8 ; i++)
+ if (!valid_mtrr_type((data >> (i * 8)) & 0xff))
+ return false;
+ return true;
+ }
+
+ /* variable MTRRs */
+ return valid_mtrr_type(data & 0xff);
+}
+
static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
{
u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges;
- if (!msr_mtrr_valid(msr))
+ if (!mtrr_valid(vcpu, msr, data))
return 1;
if (msr == MSR_MTRRdefType) {
@@ -741,23 +789,60 @@ static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
return 0;
}
+static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ u64 mcg_cap = vcpu->arch.mcg_cap;
+ unsigned bank_num = mcg_cap & 0xff;
+
+ switch (msr) {
+ case MSR_IA32_MCG_STATUS:
+ vcpu->arch.mcg_status = data;
+ break;
+ case MSR_IA32_MCG_CTL:
+ if (!(mcg_cap & MCG_CTL_P))
+ return 1;
+ if (data != 0 && data != ~(u64)0)
+ return -1;
+ vcpu->arch.mcg_ctl = data;
+ break;
+ default:
+ if (msr >= MSR_IA32_MC0_CTL &&
+ msr < MSR_IA32_MC0_CTL + 4 * bank_num) {
+ u32 offset = msr - MSR_IA32_MC0_CTL;
+ /* only 0 or all 1s can be written to IA32_MCi_CTL */
+ if ((offset & 0x3) == 0 &&
+ data != 0 && data != ~(u64)0)
+ return -1;
+ vcpu->arch.mce_banks[offset] = data;
+ break;
+ }
+ return 1;
+ }
+ return 0;
+}
+
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
{
switch (msr) {
case MSR_EFER:
set_efer(vcpu, data);
break;
- case MSR_IA32_MC0_STATUS:
- pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
- __func__, data);
+ case MSR_K7_HWCR:
+ data &= ~(u64)0x40; /* ignore flush filter disable */
+ if (data != 0) {
+ pr_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
+ data);
+ return 1;
+ }
break;
- case MSR_IA32_MCG_STATUS:
- pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
- __func__, data);
+ case MSR_FAM10H_MMIO_CONF_BASE:
+ if (data != 0) {
+ pr_unimpl(vcpu, "unimplemented MMIO_CONF_BASE wrmsr: "
+ "0x%llx\n", data);
+ return 1;
+ }
break;
- case MSR_IA32_MCG_CTL:
- pr_unimpl(vcpu, "%s: MSR_IA32_MCG_CTL 0x%llx, nop\n",
- __func__, data);
+ case MSR_AMD64_NB_CFG:
break;
case MSR_IA32_DEBUGCTLMSR:
if (!data) {
@@ -774,12 +859,15 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
case MSR_IA32_UCODE_REV:
case MSR_IA32_UCODE_WRITE:
case MSR_VM_HSAVE_PA:
+ case MSR_AMD64_PATCH_LOADER:
break;
case 0x200 ... 0x2ff:
return set_msr_mtrr(vcpu, msr, data);
case MSR_IA32_APICBASE:
kvm_set_apic_base(vcpu, data);
break;
+ case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
+ return kvm_x2apic_msr_write(vcpu, msr, data);
case MSR_IA32_MISC_ENABLE:
vcpu->arch.ia32_misc_enable_msr = data;
break;
@@ -813,9 +901,50 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
kvm_request_guest_time_update(vcpu);
break;
}
+ case MSR_IA32_MCG_CTL:
+ case MSR_IA32_MCG_STATUS:
+ case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
+ return set_msr_mce(vcpu, msr, data);
+
+ /* Performance counters are not protected by a CPUID bit,
+ * so we should check all of them in the generic path for the sake of
+ * cross vendor migration.
+ * Writing a zero into the event select MSRs disables them,
+ * which we perfectly emulate ;-). Any other value should be at least
+ * reported, some guests depend on them.
+ */
+ case MSR_P6_EVNTSEL0:
+ case MSR_P6_EVNTSEL1:
+ case MSR_K7_EVNTSEL0:
+ case MSR_K7_EVNTSEL1:
+ case MSR_K7_EVNTSEL2:
+ case MSR_K7_EVNTSEL3:
+ if (data != 0)
+ pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
+ "0x%x data 0x%llx\n", msr, data);
+ break;
+ /* at least RHEL 4 unconditionally writes to the perfctr registers,
+ * so we ignore writes to make it happy.
+ */
+ case MSR_P6_PERFCTR0:
+ case MSR_P6_PERFCTR1:
+ case MSR_K7_PERFCTR0:
+ case MSR_K7_PERFCTR1:
+ case MSR_K7_PERFCTR2:
+ case MSR_K7_PERFCTR3:
+ pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
+ "0x%x data 0x%llx\n", msr, data);
+ break;
default:
- pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data);
- return 1;
+ if (!ignore_msrs) {
+ pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
+ msr, data);
+ return 1;
+ } else {
+ pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n",
+ msr, data);
+ break;
+ }
}
return 0;
}
@@ -868,26 +997,47 @@ static int get_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
return 0;
}
-int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
{
u64 data;
+ u64 mcg_cap = vcpu->arch.mcg_cap;
+ unsigned bank_num = mcg_cap & 0xff;
switch (msr) {
- case 0xc0010010: /* SYSCFG */
- case 0xc0010015: /* HWCR */
- case MSR_IA32_PLATFORM_ID:
case MSR_IA32_P5_MC_ADDR:
case MSR_IA32_P5_MC_TYPE:
- case MSR_IA32_MC0_CTL:
- case MSR_IA32_MCG_STATUS:
+ data = 0;
+ break;
case MSR_IA32_MCG_CAP:
+ data = vcpu->arch.mcg_cap;
+ break;
case MSR_IA32_MCG_CTL:
- case MSR_IA32_MC0_MISC:
- case MSR_IA32_MC0_MISC+4:
- case MSR_IA32_MC0_MISC+8:
- case MSR_IA32_MC0_MISC+12:
- case MSR_IA32_MC0_MISC+16:
- case MSR_IA32_MC0_MISC+20:
+ if (!(mcg_cap & MCG_CTL_P))
+ return 1;
+ data = vcpu->arch.mcg_ctl;
+ break;
+ case MSR_IA32_MCG_STATUS:
+ data = vcpu->arch.mcg_status;
+ break;
+ default:
+ if (msr >= MSR_IA32_MC0_CTL &&
+ msr < MSR_IA32_MC0_CTL + 4 * bank_num) {
+ u32 offset = msr - MSR_IA32_MC0_CTL;
+ data = vcpu->arch.mce_banks[offset];
+ break;
+ }
+ return 1;
+ }
+ *pdata = data;
+ return 0;
+}
+
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+{
+ u64 data;
+
+ switch (msr) {
+ case MSR_IA32_PLATFORM_ID:
case MSR_IA32_UCODE_REV:
case MSR_IA32_EBL_CR_POWERON:
case MSR_IA32_DEBUGCTLMSR:
@@ -895,10 +1045,15 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_LASTBRANCHTOIP:
case MSR_IA32_LASTINTFROMIP:
case MSR_IA32_LASTINTTOIP:
+ case MSR_K8_SYSCFG:
+ case MSR_K7_HWCR:
case MSR_VM_HSAVE_PA:
case MSR_P6_EVNTSEL0:
case MSR_P6_EVNTSEL1:
case MSR_K7_EVNTSEL0:
+ case MSR_K8_INT_PENDING_MSG:
+ case MSR_AMD64_NB_CFG:
+ case MSR_FAM10H_MMIO_CONF_BASE:
data = 0;
break;
case MSR_MTRRcap:
@@ -912,6 +1067,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_APICBASE:
data = kvm_get_apic_base(vcpu);
break;
+ case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
+ return kvm_x2apic_msr_read(vcpu, msr, pdata);
+ break;
case MSR_IA32_MISC_ENABLE:
data = vcpu->arch.ia32_misc_enable_msr;
break;
@@ -930,9 +1088,22 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_KVM_SYSTEM_TIME:
data = vcpu->arch.time;
break;
+ case MSR_IA32_P5_MC_ADDR:
+ case MSR_IA32_P5_MC_TYPE:
+ case MSR_IA32_MCG_CAP:
+ case MSR_IA32_MCG_CTL:
+ case MSR_IA32_MCG_STATUS:
+ case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
+ return get_msr_mce(vcpu, msr, pdata);
default:
- pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
- return 1;
+ if (!ignore_msrs) {
+ pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
+ return 1;
+ } else {
+ pr_unimpl(vcpu, "ignored rdmsr: 0x%x\n", msr);
+ data = 0;
+ }
+ break;
}
*pdata = data;
return 0;
@@ -1031,6 +1202,11 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_REINJECT_CONTROL:
case KVM_CAP_IRQ_INJECT_STATUS:
case KVM_CAP_ASSIGN_DEV_IRQ:
+ case KVM_CAP_IRQFD:
+ case KVM_CAP_IOEVENTFD:
+ case KVM_CAP_PIT2:
+ case KVM_CAP_PIT_STATE2:
+ case KVM_CAP_SET_IDENTITY_MAP_ADDR:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -1051,6 +1227,9 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_IOMMU:
r = iommu_found();
break;
+ case KVM_CAP_MCE:
+ r = KVM_MAX_MCE_BANKS;
+ break;
default:
r = 0;
break;
@@ -1079,14 +1258,13 @@ long kvm_arch_dev_ioctl(struct file *filp,
if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
goto out;
r = -E2BIG;
- if (n < num_msrs_to_save)
+ if (n < msr_list.nmsrs)
goto out;
r = -EFAULT;
if (copy_to_user(user_msr_list->indices, &msrs_to_save,
num_msrs_to_save * sizeof(u32)))
goto out;
- if (copy_to_user(user_msr_list->indices
- + num_msrs_to_save * sizeof(u32),
+ if (copy_to_user(user_msr_list->indices + num_msrs_to_save,
&emulated_msrs,
ARRAY_SIZE(emulated_msrs) * sizeof(u32)))
goto out;
@@ -1111,6 +1289,16 @@ long kvm_arch_dev_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_X86_GET_MCE_CAP_SUPPORTED: {
+ u64 mce_cap;
+
+ mce_cap = KVM_MCE_CAP_SUPPORTED;
+ r = -EFAULT;
+ if (copy_to_user(argp, &mce_cap, sizeof mce_cap))
+ goto out;
+ r = 0;
+ break;
+ }
default:
r = -EINVAL;
}
@@ -1191,6 +1379,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
vcpu->arch.cpuid_nent = cpuid->nent;
cpuid_fix_nx_cap(vcpu);
r = 0;
+ kvm_apic_set_version(vcpu);
out_free:
vfree(cpuid_entries);
@@ -1212,6 +1401,7 @@ static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
goto out;
vcpu->arch.cpuid_nent = cpuid->nent;
+ kvm_apic_set_version(vcpu);
return 0;
out:
@@ -1287,7 +1477,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
0 /* Reserved, DCA */ | F(XMM4_1) |
- F(XMM4_2) | 0 /* x2APIC */ | F(MOVBE) | F(POPCNT) |
+ F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
0 /* Reserved, XSAVE, OSXSAVE */;
/* cpuid 0x80000001.ecx */
const u32 kvm_supported_word6_x86_features =
@@ -1308,6 +1498,9 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
case 1:
entry->edx &= kvm_supported_word0_x86_features;
entry->ecx &= kvm_supported_word4_x86_features;
+ /* we support x2apic emulation even if host does not support
+ * it since we emulate x2apic in software */
+ entry->ecx |= F(X2APIC);
break;
/* function 2 entries are STATEFUL. That is, repeated cpuid commands
* may return different values. This forces us to get_cpu() before
@@ -1399,6 +1592,10 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
do_cpuid_ent(&cpuid_entries[nent], func, 0,
&nent, cpuid->nent);
+ r = -E2BIG;
+ if (nent >= cpuid->nent)
+ goto out_free;
+
r = -EFAULT;
if (copy_to_user(entries, cpuid_entries,
nent * sizeof(struct kvm_cpuid_entry2)))
@@ -1467,6 +1664,80 @@ static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
return 0;
}
+static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
+ u64 mcg_cap)
+{
+ int r;
+ unsigned bank_num = mcg_cap & 0xff, bank;
+
+ r = -EINVAL;
+ if (!bank_num)
+ goto out;
+ if (mcg_cap & ~(KVM_MCE_CAP_SUPPORTED | 0xff | 0xff0000))
+ goto out;
+ r = 0;
+ vcpu->arch.mcg_cap = mcg_cap;
+ /* Init IA32_MCG_CTL to all 1s */
+ if (mcg_cap & MCG_CTL_P)
+ vcpu->arch.mcg_ctl = ~(u64)0;
+ /* Init IA32_MCi_CTL to all 1s */
+ for (bank = 0; bank < bank_num; bank++)
+ vcpu->arch.mce_banks[bank*4] = ~(u64)0;
+out:
+ return r;
+}
+
+static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
+ struct kvm_x86_mce *mce)
+{
+ u64 mcg_cap = vcpu->arch.mcg_cap;
+ unsigned bank_num = mcg_cap & 0xff;
+ u64 *banks = vcpu->arch.mce_banks;
+
+ if (mce->bank >= bank_num || !(mce->status & MCI_STATUS_VAL))
+ return -EINVAL;
+ /*
+ * if IA32_MCG_CTL is not all 1s, the uncorrected error
+ * reporting is disabled
+ */
+ if ((mce->status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) &&
+ vcpu->arch.mcg_ctl != ~(u64)0)
+ return 0;
+ banks += 4 * mce->bank;
+ /*
+ * if IA32_MCi_CTL is not all 1s, the uncorrected error
+ * reporting is disabled for the bank
+ */
+ if ((mce->status & MCI_STATUS_UC) && banks[0] != ~(u64)0)
+ return 0;
+ if (mce->status & MCI_STATUS_UC) {
+ if ((vcpu->arch.mcg_status & MCG_STATUS_MCIP) ||
+ !(vcpu->arch.cr4 & X86_CR4_MCE)) {
+ printk(KERN_DEBUG "kvm: set_mce: "
+ "injects mce exception while "
+ "previous one is in progress!\n");
+ set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ return 0;
+ }
+ if (banks[1] & MCI_STATUS_VAL)
+ mce->status |= MCI_STATUS_OVER;
+ banks[2] = mce->addr;
+ banks[3] = mce->misc;
+ vcpu->arch.mcg_status = mce->mcg_status;
+ banks[1] = mce->status;
+ kvm_queue_exception(vcpu, MC_VECTOR);
+ } else if (!(banks[1] & MCI_STATUS_VAL)
+ || !(banks[1] & MCI_STATUS_UC)) {
+ if (banks[1] & MCI_STATUS_VAL)
+ mce->status |= MCI_STATUS_OVER;
+ banks[2] = mce->addr;
+ banks[3] = mce->misc;
+ banks[1] = mce->status;
+ } else
+ banks[1] |= MCI_STATUS_OVER;
+ return 0;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -1600,6 +1871,24 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
break;
}
+ case KVM_X86_SETUP_MCE: {
+ u64 mcg_cap;
+
+ r = -EFAULT;
+ if (copy_from_user(&mcg_cap, argp, sizeof mcg_cap))
+ goto out;
+ r = kvm_vcpu_ioctl_x86_setup_mce(vcpu, mcg_cap);
+ break;
+ }
+ case KVM_X86_SET_MCE: {
+ struct kvm_x86_mce mce;
+
+ r = -EFAULT;
+ if (copy_from_user(&mce, argp, sizeof mce))
+ goto out;
+ r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
+ break;
+ }
default:
r = -EINVAL;
}
@@ -1618,6 +1907,13 @@ static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
return ret;
}
+static int kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm,
+ u64 ident_addr)
+{
+ kvm->arch.ept_identity_map_addr = ident_addr;
+ return 0;
+}
+
static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
u32 kvm_nr_mmu_pages)
{
@@ -1739,19 +2035,25 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
r = 0;
switch (chip->chip_id) {
case KVM_IRQCHIP_PIC_MASTER:
+ spin_lock(&pic_irqchip(kvm)->lock);
memcpy(&pic_irqchip(kvm)->pics[0],
&chip->chip.pic,
sizeof(struct kvm_pic_state));
+ spin_unlock(&pic_irqchip(kvm)->lock);
break;
case KVM_IRQCHIP_PIC_SLAVE:
+ spin_lock(&pic_irqchip(kvm)->lock);
memcpy(&pic_irqchip(kvm)->pics[1],
&chip->chip.pic,
sizeof(struct kvm_pic_state));
+ 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);
break;
default:
r = -EINVAL;
@@ -1765,7 +2067,9 @@ static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
{
int r = 0;
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state));
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
return r;
}
@@ -1773,8 +2077,35 @@ static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
{
int r = 0;
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
- kvm_pit_load_count(kvm, 0, ps->channels[0].count);
+ kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
+{
+ int r = 0;
+
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
+ memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state2));
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
+{
+ int r = 0, start = 0;
+ u32 prev_legacy, cur_legacy;
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
+ prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
+ cur_legacy = ps->flags & KVM_PIT_FLAGS_HPET_LEGACY;
+ if (!prev_legacy && cur_legacy)
+ start = 1;
+ memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state2));
+ kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
return r;
}
@@ -1783,7 +2114,9 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
{
if (!kvm->arch.vpit)
return -ENXIO;
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject;
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
return 0;
}
@@ -1833,7 +2166,9 @@ long kvm_arch_vm_ioctl(struct file *filp,
*/
union {
struct kvm_pit_state ps;
+ struct kvm_pit_state2 ps2;
struct kvm_memory_alias alias;
+ struct kvm_pit_config pit_config;
} u;
switch (ioctl) {
@@ -1842,6 +2177,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
if (r < 0)
goto out;
break;
+ case KVM_SET_IDENTITY_MAP_ADDR: {
+ u64 ident_addr;
+
+ r = -EFAULT;
+ if (copy_from_user(&ident_addr, argp, sizeof ident_addr))
+ goto out;
+ r = kvm_vm_ioctl_set_identity_map_addr(kvm, ident_addr);
+ if (r < 0)
+ goto out;
+ break;
+ }
case KVM_SET_MEMORY_REGION: {
struct kvm_memory_region kvm_mem;
struct kvm_userspace_memory_region kvm_userspace_mem;
@@ -1894,16 +2240,24 @@ long kvm_arch_vm_ioctl(struct file *filp,
}
break;
case KVM_CREATE_PIT:
- mutex_lock(&kvm->lock);
+ u.pit_config.flags = KVM_PIT_SPEAKER_DUMMY;
+ goto create_pit;
+ case KVM_CREATE_PIT2:
+ r = -EFAULT;
+ if (copy_from_user(&u.pit_config, argp,
+ sizeof(struct kvm_pit_config)))
+ goto out;
+ create_pit:
+ down_write(&kvm->slots_lock);
r = -EEXIST;
if (kvm->arch.vpit)
goto create_pit_unlock;
r = -ENOMEM;
- kvm->arch.vpit = kvm_create_pit(kvm);
+ kvm->arch.vpit = kvm_create_pit(kvm, u.pit_config.flags);
if (kvm->arch.vpit)
r = 0;
create_pit_unlock:
- mutex_unlock(&kvm->lock);
+ up_write(&kvm->slots_lock);
break;
case KVM_IRQ_LINE_STATUS:
case KVM_IRQ_LINE: {
@@ -1914,10 +2268,10 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
if (irqchip_in_kernel(kvm)) {
__s32 status;
- mutex_lock(&kvm->lock);
+ mutex_lock(&kvm->irq_lock);
status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
irq_event.irq, irq_event.level);
- mutex_unlock(&kvm->lock);
+ mutex_unlock(&kvm->irq_lock);
if (ioctl == KVM_IRQ_LINE_STATUS) {
irq_event.status = status;
if (copy_to_user(argp, &irq_event,
@@ -2006,6 +2360,32 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_GET_PIT2: {
+ r = -ENXIO;
+ if (!kvm->arch.vpit)
+ goto out;
+ r = kvm_vm_ioctl_get_pit2(kvm, &u.ps2);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &u.ps2, sizeof(u.ps2)))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_PIT2: {
+ r = -EFAULT;
+ if (copy_from_user(&u.ps2, argp, sizeof(u.ps2)))
+ goto out;
+ r = -ENXIO;
+ if (!kvm->arch.vpit)
+ goto out;
+ r = kvm_vm_ioctl_set_pit2(kvm, &u.ps2);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
case KVM_REINJECT_CONTROL: {
struct kvm_reinject_control control;
r = -EFAULT;
@@ -2039,35 +2419,23 @@ static void kvm_init_msr_list(void)
num_msrs_to_save = j;
}
-/*
- * Only apic need an MMIO device hook, so shortcut now..
- */
-static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
- gpa_t addr, int len,
- int is_write)
+static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
+ const void *v)
{
- struct kvm_io_device *dev;
+ if (vcpu->arch.apic &&
+ !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
+ return 0;
- if (vcpu->arch.apic) {
- dev = &vcpu->arch.apic->dev;
- if (dev->in_range(dev, addr, len, is_write))
- return dev;
- }
- return NULL;
+ return kvm_io_bus_write(&vcpu->kvm->mmio_bus, addr, len, v);
}
-
-static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
- gpa_t addr, int len,
- int is_write)
+static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
{
- struct kvm_io_device *dev;
+ if (vcpu->arch.apic &&
+ !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
+ return 0;
- dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write);
- if (dev == NULL)
- dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len,
- is_write);
- return dev;
+ return kvm_io_bus_read(&vcpu->kvm->mmio_bus, addr, len, v);
}
static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
@@ -2136,11 +2504,12 @@ static int emulator_read_emulated(unsigned long addr,
unsigned int bytes,
struct kvm_vcpu *vcpu)
{
- struct kvm_io_device *mmio_dev;
gpa_t gpa;
if (vcpu->mmio_read_completed) {
memcpy(val, vcpu->mmio_data, bytes);
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
+ vcpu->mmio_phys_addr, *(u64 *)val);
vcpu->mmio_read_completed = 0;
return X86EMUL_CONTINUE;
}
@@ -2161,14 +2530,12 @@ mmio:
/*
* Is this MMIO handled locally?
*/
- mutex_lock(&vcpu->kvm->lock);
- mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0);
- if (mmio_dev) {
- kvm_iodevice_read(mmio_dev, gpa, bytes, val);
- mutex_unlock(&vcpu->kvm->lock);
+ if (!vcpu_mmio_read(vcpu, gpa, bytes, val)) {
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, gpa, *(u64 *)val);
return X86EMUL_CONTINUE;
}
- mutex_unlock(&vcpu->kvm->lock);
+
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
vcpu->mmio_needed = 1;
vcpu->mmio_phys_addr = gpa;
@@ -2195,7 +2562,6 @@ static int emulator_write_emulated_onepage(unsigned long addr,
unsigned int bytes,
struct kvm_vcpu *vcpu)
{
- struct kvm_io_device *mmio_dev;
gpa_t gpa;
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
@@ -2213,17 +2579,12 @@ static int emulator_write_emulated_onepage(unsigned long addr,
return X86EMUL_CONTINUE;
mmio:
+ trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
/*
* Is this MMIO handled locally?
*/
- mutex_lock(&vcpu->kvm->lock);
- mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1);
- if (mmio_dev) {
- kvm_iodevice_write(mmio_dev, gpa, bytes, val);
- mutex_unlock(&vcpu->kvm->lock);
+ if (!vcpu_mmio_write(vcpu, gpa, bytes, val))
return X86EMUL_CONTINUE;
- }
- mutex_unlock(&vcpu->kvm->lock);
vcpu->mmio_needed = 1;
vcpu->mmio_phys_addr = gpa;
@@ -2312,7 +2673,6 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
int emulate_clts(struct kvm_vcpu *vcpu)
{
- KVMTRACE_0D(CLTS, vcpu, handler);
kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS);
return X86EMUL_CONTINUE;
}
@@ -2413,14 +2773,33 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
- /* Reject the instructions other than VMCALL/VMMCALL when
- * try to emulate invalid opcode */
+ /* Only allow emulation of specific instructions on #UD
+ * (namely VMMCALL, sysenter, sysexit, syscall)*/
c = &vcpu->arch.emulate_ctxt.decode;
- if ((emulation_type & EMULTYPE_TRAP_UD) &&
- (!(c->twobyte && c->b == 0x01 &&
- (c->modrm_reg == 0 || c->modrm_reg == 3) &&
- c->modrm_mod == 3 && c->modrm_rm == 1)))
- return EMULATE_FAIL;
+ if (emulation_type & EMULTYPE_TRAP_UD) {
+ if (!c->twobyte)
+ return EMULATE_FAIL;
+ switch (c->b) {
+ case 0x01: /* VMMCALL */
+ if (c->modrm_mod != 3 || c->modrm_rm != 1)
+ return EMULATE_FAIL;
+ break;
+ case 0x34: /* sysenter */
+ case 0x35: /* sysexit */
+ if (c->modrm_mod != 0 || c->modrm_rm != 0)
+ return EMULATE_FAIL;
+ break;
+ case 0x05: /* syscall */
+ if (c->modrm_mod != 0 || c->modrm_rm != 0)
+ return EMULATE_FAIL;
+ break;
+ default:
+ return EMULATE_FAIL;
+ }
+
+ if (!(c->modrm_reg == 0 || c->modrm_reg == 3))
+ return EMULATE_FAIL;
+ }
++vcpu->stat.insn_emulation;
if (r) {
@@ -2540,52 +2919,40 @@ int complete_pio(struct kvm_vcpu *vcpu)
return 0;
}
-static void kernel_pio(struct kvm_io_device *pio_dev,
- struct kvm_vcpu *vcpu,
- void *pd)
+static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
{
/* TODO: String I/O for in kernel device */
+ int r;
- mutex_lock(&vcpu->kvm->lock);
if (vcpu->arch.pio.in)
- kvm_iodevice_read(pio_dev, vcpu->arch.pio.port,
- vcpu->arch.pio.size,
- pd);
+ r = kvm_io_bus_read(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
+ vcpu->arch.pio.size, pd);
else
- kvm_iodevice_write(pio_dev, vcpu->arch.pio.port,
- vcpu->arch.pio.size,
- pd);
- mutex_unlock(&vcpu->kvm->lock);
+ r = kvm_io_bus_write(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
+ vcpu->arch.pio.size, pd);
+ return r;
}
-static void pio_string_write(struct kvm_io_device *pio_dev,
- struct kvm_vcpu *vcpu)
+static int pio_string_write(struct kvm_vcpu *vcpu)
{
struct kvm_pio_request *io = &vcpu->arch.pio;
void *pd = vcpu->arch.pio_data;
- int i;
+ int i, r = 0;
- mutex_lock(&vcpu->kvm->lock);
for (i = 0; i < io->cur_count; i++) {
- kvm_iodevice_write(pio_dev, io->port,
- io->size,
- pd);
+ if (kvm_io_bus_write(&vcpu->kvm->pio_bus,
+ io->port, io->size, pd)) {
+ r = -EOPNOTSUPP;
+ break;
+ }
pd += io->size;
}
- mutex_unlock(&vcpu->kvm->lock);
-}
-
-static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
- gpa_t addr, int len,
- int is_write)
-{
- return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr, len, is_write);
+ return r;
}
int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int size, unsigned port)
{
- struct kvm_io_device *pio_dev;
unsigned long val;
vcpu->run->exit_reason = KVM_EXIT_IO;
@@ -2599,19 +2966,13 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->arch.pio.down = 0;
vcpu->arch.pio.rep = 0;
- if (vcpu->run->io.direction == KVM_EXIT_IO_IN)
- KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size,
- handler);
- else
- KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size,
- handler);
+ trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
+ size, 1);
val = kvm_register_read(vcpu, VCPU_REGS_RAX);
memcpy(vcpu->arch.pio_data, &val, 4);
- pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in);
- if (pio_dev) {
- kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data);
+ if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
complete_pio(vcpu);
return 1;
}
@@ -2625,7 +2986,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
{
unsigned now, in_page;
int ret = 0;
- struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -2638,12 +2998,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->arch.pio.down = down;
vcpu->arch.pio.rep = rep;
- if (vcpu->run->io.direction == KVM_EXIT_IO_IN)
- KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size,
- handler);
- else
- KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size,
- handler);
+ trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
+ size, count);
if (!count) {
kvm_x86_ops->skip_emulated_instruction(vcpu);
@@ -2673,9 +3029,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->arch.pio.guest_gva = address;
- pio_dev = vcpu_find_pio_dev(vcpu, port,
- vcpu->arch.pio.cur_count,
- !vcpu->arch.pio.in);
if (!vcpu->arch.pio.in) {
/* string PIO write */
ret = pio_copy_data(vcpu);
@@ -2683,16 +3036,13 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
kvm_inject_gp(vcpu, 0);
return 1;
}
- if (ret == 0 && pio_dev) {
- pio_string_write(pio_dev, vcpu);
+ if (ret == 0 && !pio_string_write(vcpu)) {
complete_pio(vcpu);
if (vcpu->arch.pio.count == 0)
ret = 1;
}
- } else if (pio_dev)
- pr_unimpl(vcpu, "no string pio read support yet, "
- "port %x size %d count %ld\n",
- port, size, count);
+ }
+ /* no string PIO read support yet */
return ret;
}
@@ -2725,10 +3075,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
+ kvm_for_each_vcpu(i, vcpu, kvm) {
if (vcpu->cpu != freq->cpu)
continue;
if (!kvm_request_guest_time_update(vcpu))
@@ -2821,7 +3168,6 @@ void kvm_arch_exit(void)
int kvm_emulate_halt(struct kvm_vcpu *vcpu)
{
++vcpu->stat.halt_exits;
- KVMTRACE_0D(HLT, vcpu, handler);
if (irqchip_in_kernel(vcpu->kvm)) {
vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
return 1;
@@ -2852,7 +3198,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
a2 = kvm_register_read(vcpu, VCPU_REGS_RDX);
a3 = kvm_register_read(vcpu, VCPU_REGS_RSI);
- KVMTRACE_1D(VMMCALL, vcpu, (u32)nr, handler);
+ trace_kvm_hypercall(nr, a0, a1, a2, a3);
if (!is_long_mode(vcpu)) {
nr &= 0xFFFFFFFF;
@@ -2952,8 +3298,6 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
return 0;
}
- KVMTRACE_3D(CR_READ, vcpu, (u32)cr, (u32)value,
- (u32)((u64)value >> 32), handler);
return value;
}
@@ -2961,9 +3305,6 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
unsigned long *rflags)
{
- KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)val,
- (u32)((u64)val >> 32), handler);
-
switch (cr) {
case 0:
kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
@@ -3073,11 +3414,11 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
kvm_register_write(vcpu, VCPU_REGS_RDX, best->edx);
}
kvm_x86_ops->skip_emulated_instruction(vcpu);
- KVMTRACE_5D(CPUID, vcpu, function,
- (u32)kvm_register_read(vcpu, VCPU_REGS_RAX),
- (u32)kvm_register_read(vcpu, VCPU_REGS_RBX),
- (u32)kvm_register_read(vcpu, VCPU_REGS_RCX),
- (u32)kvm_register_read(vcpu, VCPU_REGS_RDX), handler);
+ trace_kvm_cpuid(function,
+ kvm_register_read(vcpu, VCPU_REGS_RAX),
+ kvm_register_read(vcpu, VCPU_REGS_RBX),
+ kvm_register_read(vcpu, VCPU_REGS_RCX),
+ kvm_register_read(vcpu, VCPU_REGS_RDX));
}
EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
@@ -3156,12 +3497,16 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
}
-static void inject_pending_irq(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void inject_pending_event(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
- kvm_x86_ops->set_interrupt_shadow(vcpu, 0);
-
/* try to reinject previous events if any */
+ if (vcpu->arch.exception.pending) {
+ kvm_x86_ops->queue_exception(vcpu, vcpu->arch.exception.nr,
+ vcpu->arch.exception.has_error_code,
+ vcpu->arch.exception.error_code);
+ return;
+ }
+
if (vcpu->arch.nmi_injected) {
kvm_x86_ops->set_nmi(vcpu);
return;
@@ -3235,16 +3580,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
smp_mb__after_clear_bit();
if (vcpu->requests || need_resched() || signal_pending(current)) {
+ set_bit(KVM_REQ_KICK, &vcpu->requests);
local_irq_enable();
preempt_enable();
r = 1;
goto out;
}
- if (vcpu->arch.exception.pending)
- __queue_exception(vcpu);
- else
- inject_pending_irq(vcpu, kvm_run);
+ inject_pending_event(vcpu, kvm_run);
/* enable NMI/IRQ window open exits if needed */
if (vcpu->arch.nmi_pending)
@@ -3276,7 +3619,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
set_debugreg(vcpu->arch.eff_db[3], 3);
}
- KVMTRACE_0D(VMENTRY, vcpu, entryexit);
+ trace_kvm_entry(vcpu->vcpu_id);
kvm_x86_ops->run(vcpu, kvm_run);
if (unlikely(vcpu->arch.switch_db_regs)) {
@@ -3617,11 +3960,8 @@ static void kvm_set_segment(struct kvm_vcpu *vcpu,
static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
struct kvm_segment *kvm_desct)
{
- kvm_desct->base = seg_desc->base0;
- kvm_desct->base |= seg_desc->base1 << 16;
- kvm_desct->base |= seg_desc->base2 << 24;
- kvm_desct->limit = seg_desc->limit0;
- kvm_desct->limit |= seg_desc->limit << 16;
+ kvm_desct->base = get_desc_base(seg_desc);
+ kvm_desct->limit = get_desc_limit(seg_desc);
if (seg_desc->g) {
kvm_desct->limit <<= 12;
kvm_desct->limit |= 0xfff;
@@ -3700,11 +4040,7 @@ static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
struct desc_struct *seg_desc)
{
- u32 base_addr;
-
- base_addr = seg_desc->base0;
- base_addr |= (seg_desc->base1 << 16);
- base_addr |= (seg_desc->base2 << 24);
+ u32 base_addr = get_desc_base(seg_desc);
return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
}
@@ -3993,7 +4329,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
}
}
- if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) {
+ if (!nseg_desc.p || get_desc_limit(&nseg_desc) < 0x67) {
kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
return 1;
}
@@ -4063,13 +4399,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
vcpu->arch.cr2 = sregs->cr2;
mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
-
- down_read(&vcpu->kvm->slots_lock);
- if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
- vcpu->arch.cr3 = sregs->cr3;
- else
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
- up_read(&vcpu->kvm->slots_lock);
+ vcpu->arch.cr3 = sregs->cr3;
kvm_set_cr8(vcpu, sregs->cr8);
@@ -4112,7 +4442,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
/* Older userspace won't unhalt the vcpu on reset. */
- if (vcpu->vcpu_id == 0 && kvm_rip_read(vcpu) == 0xfff0 &&
+ if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 &&
!(vcpu->arch.cr0 & X86_CR0_PE))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
@@ -4383,7 +4713,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
kvm = vcpu->kvm;
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
- if (!irqchip_in_kernel(kvm) || vcpu->vcpu_id == 0)
+ if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
else
vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
@@ -4405,6 +4735,14 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
goto fail_mmu_destroy;
}
+ vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4,
+ GFP_KERNEL);
+ if (!vcpu->arch.mce_banks) {
+ r = -ENOMEM;
+ goto fail_mmu_destroy;
+ }
+ vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS;
+
return 0;
fail_mmu_destroy:
@@ -4452,20 +4790,22 @@ static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
+ struct kvm_vcpu *vcpu;
/*
* Unpin any mmu pages first.
*/
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- if (kvm->vcpus[i])
- kvm_unload_vcpu_mmu(kvm->vcpus[i]);
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- if (kvm->vcpus[i]) {
- kvm_arch_vcpu_free(kvm->vcpus[i]);
- kvm->vcpus[i] = NULL;
- }
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_unload_vcpu_mmu(vcpu);
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_arch_vcpu_free(vcpu);
+
+ mutex_lock(&kvm->lock);
+ for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
+ kvm->vcpus[i] = NULL;
+ atomic_set(&kvm->online_vcpus, 0);
+ mutex_unlock(&kvm->lock);
}
void kvm_arch_sync_events(struct kvm *kvm)
@@ -4556,8 +4896,10 @@ void kvm_arch_flush_shadow(struct kvm *kvm)
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE
- || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED
- || vcpu->arch.nmi_pending;
+ || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED
+ || vcpu->arch.nmi_pending ||
+ (kvm_arch_interrupt_allowed(vcpu) &&
+ kvm_cpu_has_interrupt(vcpu));
}
void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
@@ -4581,3 +4923,9 @@ int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
{
return kvm_x86_ops->interrupt_allowed(vcpu);
}
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_msr);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_cr);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 4c8e10af78e8..5eadea585d2a 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -31,4 +31,8 @@ static inline bool kvm_exception_is_soft(unsigned int nr)
{
return (nr == BP_VECTOR) || (nr == OF_VECTOR);
}
+
+struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
+ u32 function, u32 index);
+
#endif
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c
index 616de4628d60..c6663d46f328 100644
--- a/arch/x86/kvm/x86_emulate.c
+++ b/arch/x86/kvm/x86_emulate.c
@@ -32,6 +32,8 @@
#include <linux/module.h>
#include <asm/kvm_x86_emulate.h>
+#include "mmu.h" /* for is_long_mode() */
+
/*
* Opcode effective-address decode tables.
* Note that we only emulate instructions that have at least one memory
@@ -60,6 +62,7 @@
#define SrcImmByte (6<<4) /* 8-bit sign-extended immediate operand. */
#define SrcOne (7<<4) /* Implied '1' */
#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */
+#define SrcImmU (9<<4) /* Immediate operand, unsigned */
#define SrcMask (0xf<<4)
/* Generic ModRM decode. */
#define ModRM (1<<8)
@@ -195,7 +198,7 @@ static u32 opcode_table[256] = {
ByteOp | SrcImmUByte, SrcImmUByte,
/* 0xE8 - 0xEF */
SrcImm | Stack, SrcImm | ImplicitOps,
- SrcImm | Src2Imm16, SrcImmByte | ImplicitOps,
+ SrcImmU | Src2Imm16, SrcImmByte | ImplicitOps,
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
/* 0xF0 - 0xF7 */
@@ -208,7 +211,7 @@ static u32 opcode_table[256] = {
static u32 twobyte_table[256] = {
/* 0x00 - 0x0F */
- 0, Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0,
+ 0, Group | GroupDual | Group7, 0, 0, 0, ImplicitOps, ImplicitOps, 0,
ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
/* 0x10 - 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
@@ -216,7 +219,9 @@ static u32 twobyte_table[256] = {
ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
- ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, 0, ImplicitOps, 0,
+ ImplicitOps, ImplicitOps, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -319,8 +324,11 @@ static u32 group2_table[] = {
};
/* EFLAGS bit definitions. */
+#define EFLG_VM (1<<17)
+#define EFLG_RF (1<<16)
#define EFLG_OF (1<<11)
#define EFLG_DF (1<<10)
+#define EFLG_IF (1<<9)
#define EFLG_SF (1<<7)
#define EFLG_ZF (1<<6)
#define EFLG_AF (1<<4)
@@ -1027,6 +1035,7 @@ done_prefixes:
c->src.type = OP_MEM;
break;
case SrcImm:
+ case SrcImmU:
c->src.type = OP_IMM;
c->src.ptr = (unsigned long *)c->eip;
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
@@ -1044,6 +1053,19 @@ done_prefixes:
c->src.val = insn_fetch(s32, 4, c->eip);
break;
}
+ if ((c->d & SrcMask) == SrcImmU) {
+ switch (c->src.bytes) {
+ case 1:
+ c->src.val &= 0xff;
+ break;
+ case 2:
+ c->src.val &= 0xffff;
+ break;
+ case 4:
+ c->src.val &= 0xffffffff;
+ break;
+ }
+ }
break;
case SrcImmByte:
case SrcImmUByte:
@@ -1375,6 +1397,217 @@ static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
ctxt->interruptibility = mask;
}
+static inline void
+setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
+ struct kvm_segment *cs, struct kvm_segment *ss)
+{
+ memset(cs, 0, sizeof(struct kvm_segment));
+ kvm_x86_ops->get_segment(ctxt->vcpu, cs, VCPU_SREG_CS);
+ memset(ss, 0, sizeof(struct kvm_segment));
+
+ cs->l = 0; /* will be adjusted later */
+ cs->base = 0; /* flat segment */
+ cs->g = 1; /* 4kb granularity */
+ cs->limit = 0xffffffff; /* 4GB limit */
+ cs->type = 0x0b; /* Read, Execute, Accessed */
+ cs->s = 1;
+ cs->dpl = 0; /* will be adjusted later */
+ cs->present = 1;
+ cs->db = 1;
+
+ ss->unusable = 0;
+ ss->base = 0; /* flat segment */
+ ss->limit = 0xffffffff; /* 4GB limit */
+ ss->g = 1; /* 4kb granularity */
+ ss->s = 1;
+ ss->type = 0x03; /* Read/Write, Accessed */
+ ss->db = 1; /* 32bit stack segment */
+ ss->dpl = 0;
+ ss->present = 1;
+}
+
+static int
+emulate_syscall(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct kvm_segment cs, ss;
+ u64 msr_data;
+
+ /* syscall is not available in real mode */
+ if (c->lock_prefix || ctxt->mode == X86EMUL_MODE_REAL
+ || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE))
+ return -1;
+
+ setup_syscalls_segments(ctxt, &cs, &ss);
+
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ msr_data >>= 32;
+ cs.selector = (u16)(msr_data & 0xfffc);
+ ss.selector = (u16)(msr_data + 8);
+
+ if (is_long_mode(ctxt->vcpu)) {
+ cs.db = 0;
+ cs.l = 1;
+ }
+ kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
+ kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+
+ c->regs[VCPU_REGS_RCX] = c->eip;
+ if (is_long_mode(ctxt->vcpu)) {
+#ifdef CONFIG_X86_64
+ c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF;
+
+ kvm_x86_ops->get_msr(ctxt->vcpu,
+ ctxt->mode == X86EMUL_MODE_PROT64 ?
+ MSR_LSTAR : MSR_CSTAR, &msr_data);
+ c->eip = msr_data;
+
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
+ ctxt->eflags &= ~(msr_data | EFLG_RF);
+#endif
+ } else {
+ /* legacy mode */
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ c->eip = (u32)msr_data;
+
+ ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
+ }
+
+ return 0;
+}
+
+static int
+emulate_sysenter(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct kvm_segment cs, ss;
+ u64 msr_data;
+
+ /* inject #UD if LOCK prefix is used */
+ if (c->lock_prefix)
+ return -1;
+
+ /* inject #GP if in real mode or paging is disabled */
+ if (ctxt->mode == X86EMUL_MODE_REAL ||
+ !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+
+ /* XXX sysenter/sysexit have not been tested in 64bit mode.
+ * Therefore, we inject an #UD.
+ */
+ if (ctxt->mode == X86EMUL_MODE_PROT64)
+ return -1;
+
+ setup_syscalls_segments(ctxt, &cs, &ss);
+
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ switch (ctxt->mode) {
+ case X86EMUL_MODE_PROT32:
+ if ((msr_data & 0xfffc) == 0x0) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+ break;
+ case X86EMUL_MODE_PROT64:
+ if (msr_data == 0x0) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+ break;
+ }
+
+ ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
+ cs.selector = (u16)msr_data;
+ cs.selector &= ~SELECTOR_RPL_MASK;
+ ss.selector = cs.selector + 8;
+ ss.selector &= ~SELECTOR_RPL_MASK;
+ if (ctxt->mode == X86EMUL_MODE_PROT64
+ || is_long_mode(ctxt->vcpu)) {
+ cs.db = 0;
+ cs.l = 1;
+ }
+
+ kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
+ kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
+ c->eip = msr_data;
+
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
+ c->regs[VCPU_REGS_RSP] = msr_data;
+
+ return 0;
+}
+
+static int
+emulate_sysexit(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct kvm_segment cs, ss;
+ u64 msr_data;
+ int usermode;
+
+ /* inject #UD if LOCK prefix is used */
+ if (c->lock_prefix)
+ return -1;
+
+ /* inject #GP if in real mode or paging is disabled */
+ if (ctxt->mode == X86EMUL_MODE_REAL
+ || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+
+ /* sysexit must be called from CPL 0 */
+ if (kvm_x86_ops->get_cpl(ctxt->vcpu) != 0) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+
+ setup_syscalls_segments(ctxt, &cs, &ss);
+
+ if ((c->rex_prefix & 0x8) != 0x0)
+ usermode = X86EMUL_MODE_PROT64;
+ else
+ usermode = X86EMUL_MODE_PROT32;
+
+ cs.dpl = 3;
+ ss.dpl = 3;
+ kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ switch (usermode) {
+ case X86EMUL_MODE_PROT32:
+ cs.selector = (u16)(msr_data + 16);
+ if ((msr_data & 0xfffc) == 0x0) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+ ss.selector = (u16)(msr_data + 24);
+ break;
+ case X86EMUL_MODE_PROT64:
+ cs.selector = (u16)(msr_data + 32);
+ if (msr_data == 0x0) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+ ss.selector = cs.selector + 8;
+ cs.db = 0;
+ cs.l = 1;
+ break;
+ }
+ cs.selector |= SELECTOR_RPL_MASK;
+ ss.selector |= SELECTOR_RPL_MASK;
+
+ kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
+ kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+
+ c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
+ c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
+
+ return 0;
+}
+
int
x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
@@ -1970,6 +2203,12 @@ twobyte_insn:
goto cannot_emulate;
}
break;
+ case 0x05: /* syscall */
+ if (emulate_syscall(ctxt) == -1)
+ goto cannot_emulate;
+ else
+ goto writeback;
+ break;
case 0x06:
emulate_clts(ctxt->vcpu);
c->dst.type = OP_NONE;
@@ -2036,6 +2275,18 @@ twobyte_insn:
rc = X86EMUL_CONTINUE;
c->dst.type = OP_NONE;
break;
+ case 0x34: /* sysenter */
+ if (emulate_sysenter(ctxt) == -1)
+ goto cannot_emulate;
+ else
+ goto writeback;
+ break;
+ case 0x35: /* sysexit */
+ if (emulate_sysexit(ctxt) == -1)
+ goto cannot_emulate;
+ else
+ goto writeback;
+ break;
case 0x40 ... 0x4f: /* cmov */
c->dst.val = c->dst.orig_val = c->src.val;
if (!test_cc(c->b, ctxt->eflags))
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index f2bf1f73d468..7a096c4808bd 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -22,7 +22,8 @@
*
* So how does the kernel know it's a Guest? We'll see that later, but let's
* just say that we end up here where we replace the native functions various
- * "paravirt" structures with our Guest versions, then boot like normal. :*/
+ * "paravirt" structures with our Guest versions, then boot like normal.
+:*/
/*
* Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
@@ -74,7 +75,8 @@
*
* The Guest in our tale is a simple creature: identical to the Host but
* behaving in simplified but equivalent ways. In particular, the Guest is the
- * same kernel as the Host (or at least, built from the same source code). :*/
+ * same kernel as the Host (or at least, built from the same source code).
+:*/
struct lguest_data lguest_data = {
.hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
@@ -85,7 +87,8 @@ struct lguest_data lguest_data = {
.syscall_vec = SYSCALL_VECTOR,
};
-/*G:037 async_hcall() is pretty simple: I'm quite proud of it really. We have a
+/*G:037
+ * async_hcall() is pretty simple: I'm quite proud of it really. We have a
* ring buffer of stored hypercalls which the Host will run though next time we
* do a normal hypercall. Each entry in the ring has 5 slots for the hypercall
* arguments, and a "hcall_status" word which is 0 if the call is ready to go,
@@ -94,7 +97,8 @@ struct lguest_data lguest_data = {
* If we come around to a slot which hasn't been finished, then the table is
* full and we just make the hypercall directly. This has the nice side
* effect of causing the Host to run all the stored calls in the ring buffer
- * which empties it for next time! */
+ * which empties it for next time!
+ */
static void async_hcall(unsigned long call, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
@@ -103,9 +107,11 @@ static void async_hcall(unsigned long call, unsigned long arg1,
static unsigned int next_call;
unsigned long flags;
- /* Disable interrupts if not already disabled: we don't want an
+ /*
+ * Disable interrupts if not already disabled: we don't want an
* interrupt handler making a hypercall while we're already doing
- * one! */
+ * one!
+ */
local_irq_save(flags);
if (lguest_data.hcall_status[next_call] != 0xFF) {
/* Table full, so do normal hcall which will flush table. */
@@ -125,8 +131,9 @@ static void async_hcall(unsigned long call, unsigned long arg1,
local_irq_restore(flags);
}
-/*G:035 Notice the lazy_hcall() above, rather than hcall(). This is our first
- * real optimization trick!
+/*G:035
+ * Notice the lazy_hcall() above, rather than hcall(). This is our first real
+ * optimization trick!
*
* When lazy_mode is set, it means we're allowed to defer all hypercalls and do
* them as a batch when lazy_mode is eventually turned off. Because hypercalls
@@ -136,7 +143,8 @@ static void async_hcall(unsigned long call, unsigned long arg1,
* lguest_leave_lazy_mode().
*
* So, when we're in lazy mode, we call async_hcall() to store the call for
- * future processing: */
+ * future processing:
+ */
static void lazy_hcall1(unsigned long call,
unsigned long arg1)
{
@@ -146,6 +154,7 @@ static void lazy_hcall1(unsigned long call,
async_hcall(call, arg1, 0, 0, 0);
}
+/* You can imagine what lazy_hcall2, 3 and 4 look like. :*/
static void lazy_hcall2(unsigned long call,
unsigned long arg1,
unsigned long arg2)
@@ -181,8 +190,10 @@ static void lazy_hcall4(unsigned long call,
}
#endif
-/* When lazy mode is turned off reset the per-cpu lazy mode variable and then
- * issue the do-nothing hypercall to flush any stored calls. */
+/*G:036
+ * When lazy mode is turned off reset the per-cpu lazy mode variable and then
+ * issue the do-nothing hypercall to flush any stored calls.
+:*/
static void lguest_leave_lazy_mmu_mode(void)
{
kvm_hypercall0(LHCALL_FLUSH_ASYNC);
@@ -208,9 +219,11 @@ static void lguest_end_context_switch(struct task_struct *next)
* check there before it tries to deliver an interrupt.
*/
-/* save_flags() is expected to return the processor state (ie. "flags"). The
+/*
+ * save_flags() is expected to return the processor state (ie. "flags"). The
* flags word contains all kind of stuff, but in practice Linux only cares
- * about the interrupt flag. Our "save_flags()" just returns that. */
+ * about the interrupt flag. Our "save_flags()" just returns that.
+ */
static unsigned long save_fl(void)
{
return lguest_data.irq_enabled;
@@ -222,13 +235,15 @@ static void irq_disable(void)
lguest_data.irq_enabled = 0;
}
-/* Let's pause a moment. Remember how I said these are called so often?
+/*
+ * Let's pause a moment. Remember how I said these are called so often?
* Jeremy Fitzhardinge optimized them so hard early in 2009 that he had to
* break some rules. In particular, these functions are assumed to save their
* own registers if they need to: normal C functions assume they can trash the
* eax register. To use normal C functions, we use
* PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the
- * C function, then restores it. */
+ * C function, then restores it.
+ */
PV_CALLEE_SAVE_REGS_THUNK(save_fl);
PV_CALLEE_SAVE_REGS_THUNK(irq_disable);
/*:*/
@@ -237,18 +252,18 @@ PV_CALLEE_SAVE_REGS_THUNK(irq_disable);
extern void lg_irq_enable(void);
extern void lg_restore_fl(unsigned long flags);
-/*M:003 Note that we don't check for outstanding interrupts when we re-enable
- * them (or when we unmask an interrupt). This seems to work for the moment,
- * since interrupts are rare and we'll just get the interrupt on the next timer
- * tick, but now we can run with CONFIG_NO_HZ, we should revisit this. One way
- * would be to put the "irq_enabled" field in a page by itself, and have the
- * Host write-protect it when an interrupt comes in when irqs are disabled.
- * There will then be a page fault as soon as interrupts are re-enabled.
+/*M:003
+ * We could be more efficient in our checking of outstanding interrupts, rather
+ * than using a branch. One way would be to put the "irq_enabled" field in a
+ * page by itself, and have the Host write-protect it when an interrupt comes
+ * in when irqs are disabled. There will then be a page fault as soon as
+ * interrupts are re-enabled.
*
* A better method is to implement soft interrupt disable generally for x86:
* instead of disabling interrupts, we set a flag. If an interrupt does come
* in, we then disable them for real. This is uncommon, so we could simply use
- * a hypercall for interrupt control and not worry about efficiency. :*/
+ * a hypercall for interrupt control and not worry about efficiency.
+:*/
/*G:034
* The Interrupt Descriptor Table (IDT).
@@ -261,10 +276,12 @@ extern void lg_restore_fl(unsigned long flags);
static void lguest_write_idt_entry(gate_desc *dt,
int entrynum, const gate_desc *g)
{
- /* The gate_desc structure is 8 bytes long: we hand it to the Host in
+ /*
+ * The gate_desc structure is 8 bytes long: we hand it to the Host in
* two 32-bit chunks. The whole 32-bit kernel used to hand descriptors
* around like this; typesafety wasn't a big concern in Linux's early
- * years. */
+ * years.
+ */
u32 *desc = (u32 *)g;
/* Keep the local copy up to date. */
native_write_idt_entry(dt, entrynum, g);
@@ -272,9 +289,11 @@ static void lguest_write_idt_entry(gate_desc *dt,
kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
}
-/* Changing to a different IDT is very rare: we keep the IDT up-to-date every
+/*
+ * Changing to a different IDT is very rare: we keep the IDT up-to-date every
* time it is written, so we can simply loop through all entries and tell the
- * Host about them. */
+ * Host about them.
+ */
static void lguest_load_idt(const struct desc_ptr *desc)
{
unsigned int i;
@@ -305,9 +324,11 @@ static void lguest_load_gdt(const struct desc_ptr *desc)
kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b);
}
-/* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
+/*
+ * For a single GDT entry which changes, we do the lazy thing: alter our GDT,
* then tell the Host to reload the entire thing. This operation is so rare
- * that this naive implementation is reasonable. */
+ * that this naive implementation is reasonable.
+ */
static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum,
const void *desc, int type)
{
@@ -317,29 +338,36 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum,
dt[entrynum].a, dt[entrynum].b);
}
-/* OK, I lied. There are three "thread local storage" GDT entries which change
+/*
+ * OK, I lied. There are three "thread local storage" GDT entries which change
* on every context switch (these three entries are how glibc implements
- * __thread variables). So we have a hypercall specifically for this case. */
+ * __thread variables). So we have a hypercall specifically for this case.
+ */
static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
{
- /* There's one problem which normal hardware doesn't have: the Host
+ /*
+ * There's one problem which normal hardware doesn't have: the Host
* can't handle us removing entries we're currently using. So we clear
- * the GS register here: if it's needed it'll be reloaded anyway. */
+ * the GS register here: if it's needed it'll be reloaded anyway.
+ */
lazy_load_gs(0);
lazy_hcall2(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu);
}
-/*G:038 That's enough excitement for now, back to ploughing through each of
- * the different pv_ops structures (we're about 1/3 of the way through).
+/*G:038
+ * That's enough excitement for now, back to ploughing through each of the
+ * different pv_ops structures (we're about 1/3 of the way through).
*
* This is the Local Descriptor Table, another weird Intel thingy. Linux only
* uses this for some strange applications like Wine. We don't do anything
- * here, so they'll get an informative and friendly Segmentation Fault. */
+ * here, so they'll get an informative and friendly Segmentation Fault.
+ */
static void lguest_set_ldt(const void *addr, unsigned entries)
{
}
-/* This loads a GDT entry into the "Task Register": that entry points to a
+/*
+ * This loads a GDT entry into the "Task Register": that entry points to a
* structure called the Task State Segment. Some comments scattered though the
* kernel code indicate that this used for task switching in ages past, along
* with blood sacrifice and astrology.
@@ -347,19 +375,21 @@ static void lguest_set_ldt(const void *addr, unsigned entries)
* Now there's nothing interesting in here that we don't get told elsewhere.
* But the native version uses the "ltr" instruction, which makes the Host
* complain to the Guest about a Segmentation Fault and it'll oops. So we
- * override the native version with a do-nothing version. */
+ * override the native version with a do-nothing version.
+ */
static void lguest_load_tr_desc(void)
{
}
-/* The "cpuid" instruction is a way of querying both the CPU identity
+/*
+ * The "cpuid" instruction is a way of querying both the CPU identity
* (manufacturer, model, etc) and its features. It was introduced before the
* Pentium in 1993 and keeps getting extended by both Intel, AMD and others.
* As you might imagine, after a decade and a half this treatment, it is now a
* giant ball of hair. Its entry in the current Intel manual runs to 28 pages.
*
* This instruction even it has its own Wikipedia entry. The Wikipedia entry
- * has been translated into 4 languages. I am not making this up!
+ * has been translated into 5 languages. I am not making this up!
*
* We could get funky here and identify ourselves as "GenuineLguest", but
* instead we just use the real "cpuid" instruction. Then I pretty much turned
@@ -371,7 +401,8 @@ static void lguest_load_tr_desc(void)
* Replacing the cpuid so we can turn features off is great for the kernel, but
* anyone (including userspace) can just use the raw "cpuid" instruction and
* the Host won't even notice since it isn't privileged. So we try not to get
- * too worked up about it. */
+ * too worked up about it.
+ */
static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
unsigned int *cx, unsigned int *dx)
{
@@ -379,43 +410,63 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
native_cpuid(ax, bx, cx, dx);
switch (function) {
- case 0: /* ID and highest CPUID. Futureproof a little by sticking to
- * older ones. */
+ /*
+ * CPUID 0 gives the highest legal CPUID number (and the ID string).
+ * We futureproof our code a little by sticking to known CPUID values.
+ */
+ case 0:
if (*ax > 5)
*ax = 5;
break;
- case 1: /* Basic feature request. */
- /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
+
+ /*
+ * CPUID 1 is a basic feature request.
+ *
+ * CX: we only allow kernel to see SSE3, CMPXCHG16B and SSSE3
+ * DX: SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU and PAE.
+ */
+ case 1:
*cx &= 0x00002201;
- /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU, PAE. */
*dx &= 0x07808151;
- /* The Host can do a nice optimization if it knows that the
+ /*
+ * The Host can do a nice optimization if it knows that the
* kernel mappings (addresses above 0xC0000000 or whatever
* PAGE_OFFSET is set to) haven't changed. But Linux calls
* flush_tlb_user() for both user and kernel mappings unless
- * the Page Global Enable (PGE) feature bit is set. */
+ * the Page Global Enable (PGE) feature bit is set.
+ */
*dx |= 0x00002000;
- /* We also lie, and say we're family id 5. 6 or greater
+ /*
+ * We also lie, and say we're family id 5. 6 or greater
* leads to a rdmsr in early_init_intel which we can't handle.
- * Family ID is returned as bits 8-12 in ax. */
+ * Family ID is returned as bits 8-12 in ax.
+ */
*ax &= 0xFFFFF0FF;
*ax |= 0x00000500;
break;
+ /*
+ * 0x80000000 returns the highest Extended Function, so we futureproof
+ * like we do above by limiting it to known fields.
+ */
case 0x80000000:
- /* Futureproof this a little: if they ask how much extended
- * processor information there is, limit it to known fields. */
if (*ax > 0x80000008)
*ax = 0x80000008;
break;
+
+ /*
+ * PAE systems can mark pages as non-executable. Linux calls this the
+ * NX bit. Intel calls it XD (eXecute Disable), AMD EVP (Enhanced
+ * Virus Protection). We just switch turn if off here, since we don't
+ * support it.
+ */
case 0x80000001:
- /* Here we should fix nx cap depending on host. */
- /* For this version of PAE, we just clear NX bit. */
*dx &= ~(1 << 20);
break;
}
}
-/* Intel has four control registers, imaginatively named cr0, cr2, cr3 and cr4.
+/*
+ * Intel has four control registers, imaginatively named cr0, cr2, cr3 and cr4.
* I assume there's a cr1, but it hasn't bothered us yet, so we'll not bother
* it. The Host needs to know when the Guest wants to change them, so we have
* a whole series of functions like read_cr0() and write_cr0().
@@ -430,7 +481,8 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
* name like "FPUTRAP bit" be a little less cryptic?
*
* We store cr0 locally because the Host never changes it. The Guest sometimes
- * wants to read it and we'd prefer not to bother the Host unnecessarily. */
+ * wants to read it and we'd prefer not to bother the Host unnecessarily.
+ */
static unsigned long current_cr0;
static void lguest_write_cr0(unsigned long val)
{
@@ -443,18 +495,22 @@ static unsigned long lguest_read_cr0(void)
return current_cr0;
}
-/* Intel provided a special instruction to clear the TS bit for people too cool
+/*
+ * Intel provided a special instruction to clear the TS bit for people too cool
* to use write_cr0() to do it. This "clts" instruction is faster, because all
- * the vowels have been optimized out. */
+ * the vowels have been optimized out.
+ */
static void lguest_clts(void)
{
lazy_hcall1(LHCALL_TS, 0);
current_cr0 &= ~X86_CR0_TS;
}
-/* cr2 is the virtual address of the last page fault, which the Guest only ever
+/*
+ * cr2 is the virtual address of the last page fault, which the Guest only ever
* reads. The Host kindly writes this into our "struct lguest_data", so we
- * just read it out of there. */
+ * just read it out of there.
+ */
static unsigned long lguest_read_cr2(void)
{
return lguest_data.cr2;
@@ -463,10 +519,12 @@ static unsigned long lguest_read_cr2(void)
/* See lguest_set_pte() below. */
static bool cr3_changed = false;
-/* cr3 is the current toplevel pagetable page: the principle is the same as
+/*
+ * cr3 is the current toplevel pagetable page: the principle is the same as
* cr0. Keep a local copy, and tell the Host when it changes. The only
* difference is that our local copy is in lguest_data because the Host needs
- * to set it upon our initial hypercall. */
+ * to set it upon our initial hypercall.
+ */
static void lguest_write_cr3(unsigned long cr3)
{
lguest_data.pgdir = cr3;
@@ -511,7 +569,7 @@ static void lguest_write_cr4(unsigned long val)
* cr3 ---> +---------+
* | --------->+---------+
* | | | PADDR1 |
- * Top-level | | PADDR2 |
+ * Mid-level | | PADDR2 |
* (PMD) page | | |
* | | Lower-level |
* | | (PTE) page |
@@ -531,21 +589,62 @@ static void lguest_write_cr4(unsigned long val)
* Index into top Index into second Offset within page
* page directory page pagetable page
*
- * The kernel spends a lot of time changing both the top-level page directory
- * and lower-level pagetable pages. The Guest doesn't know physical addresses,
- * so while it maintains these page tables exactly like normal, it also needs
- * to keep the Host informed whenever it makes a change: the Host will create
- * the real page tables based on the Guests'.
+ * Now, unfortunately, this isn't the whole story: Intel added Physical Address
+ * Extension (PAE) to allow 32 bit systems to use 64GB of memory (ie. 36 bits).
+ * These are held in 64-bit page table entries, so we can now only fit 512
+ * entries in a page, and the neat three-level tree breaks down.
+ *
+ * The result is a four level page table:
+ *
+ * cr3 --> [ 4 Upper ]
+ * [ Level ]
+ * [ Entries ]
+ * [(PUD Page)]---> +---------+
+ * | --------->+---------+
+ * | | | PADDR1 |
+ * Mid-level | | PADDR2 |
+ * (PMD) page | | |
+ * | | Lower-level |
+ * | | (PTE) page |
+ * | | | |
+ * .... ....
+ *
+ *
+ * And the virtual address is decoded as:
+ *
+ * 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ * |<-2->|<--- 9 bits ---->|<---- 9 bits --->|<------ 12 bits ------>|
+ * Index into Index into mid Index into lower Offset within page
+ * top entries directory page pagetable page
+ *
+ * It's too hard to switch between these two formats at runtime, so Linux only
+ * supports one or the other depending on whether CONFIG_X86_PAE is set. Many
+ * distributions turn it on, and not just for people with silly amounts of
+ * memory: the larger PTE entries allow room for the NX bit, which lets the
+ * kernel disable execution of pages and increase security.
+ *
+ * This was a problem for lguest, which couldn't run on these distributions;
+ * then Matias Zabaljauregui figured it all out and implemented it, and only a
+ * handful of puppies were crushed in the process!
+ *
+ * Back to our point: the kernel spends a lot of time changing both the
+ * top-level page directory and lower-level pagetable pages. The Guest doesn't
+ * know physical addresses, so while it maintains these page tables exactly
+ * like normal, it also needs to keep the Host informed whenever it makes a
+ * change: the Host will create the real page tables based on the Guests'.
*/
-/* The Guest calls this to set a second-level entry (pte), ie. to map a page
- * into a process' address space. We set the entry then tell the Host the
- * toplevel and address this corresponds to. The Guest uses one pagetable per
- * process, so we need to tell the Host which one we're changing (mm->pgd). */
+/*
+ * The Guest calls this after it has set a second-level entry (pte), ie. to map
+ * a page into a process' address space. Wetell the Host the toplevel and
+ * address this corresponds to. The Guest uses one pagetable per process, so
+ * we need to tell the Host which one we're changing (mm->pgd).
+ */
static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
#ifdef CONFIG_X86_PAE
+ /* PAE needs to hand a 64 bit page table entry, so it uses two args. */
lazy_hcall4(LHCALL_SET_PTE, __pa(mm->pgd), addr,
ptep->pte_low, ptep->pte_high);
#else
@@ -553,6 +652,7 @@ static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
#endif
}
+/* This is the "set and update" combo-meal-deal version. */
static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval)
{
@@ -560,10 +660,13 @@ static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
lguest_pte_update(mm, addr, ptep);
}
-/* The Guest calls lguest_set_pud to set a top-level entry and lguest_set_pmd
+/*
+ * The Guest calls lguest_set_pud to set a top-level entry and lguest_set_pmd
* to set a middle-level entry when PAE is activated.
+ *
* Again, we set the entry then tell the Host which page we changed,
- * and the index of the entry we changed. */
+ * and the index of the entry we changed.
+ */
#ifdef CONFIG_X86_PAE
static void lguest_set_pud(pud_t *pudp, pud_t pudval)
{
@@ -582,8 +685,7 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
}
#else
-/* The Guest calls lguest_set_pmd to set a top-level entry when PAE is not
- * activated. */
+/* The Guest calls lguest_set_pmd to set a top-level entry when !PAE. */
static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
{
native_set_pmd(pmdp, pmdval);
@@ -592,7 +694,8 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
}
#endif
-/* There are a couple of legacy places where the kernel sets a PTE, but we
+/*
+ * There are a couple of legacy places where the kernel sets a PTE, but we
* don't know the top level any more. This is useless for us, since we don't
* know which pagetable is changing or what address, so we just tell the Host
* to forget all of them. Fortunately, this is very rare.
@@ -600,7 +703,8 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
* ... except in early boot when the kernel sets up the initial pagetables,
* which makes booting astonishingly slow: 1.83 seconds! So we don't even tell
* the Host anything changed until we've done the first page table switch,
- * which brings boot back to 0.25 seconds. */
+ * which brings boot back to 0.25 seconds.
+ */
static void lguest_set_pte(pte_t *ptep, pte_t pteval)
{
native_set_pte(ptep, pteval);
@@ -609,6 +713,11 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
}
#ifdef CONFIG_X86_PAE
+/*
+ * With 64-bit PTE values, we need to be careful setting them: if we set 32
+ * bits at a time, the hardware could see a weird half-set entry. These
+ * versions ensure we update all 64 bits at once.
+ */
static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
{
native_set_pte_atomic(ptep, pte);
@@ -616,19 +725,21 @@ static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
lazy_hcall1(LHCALL_FLUSH_TLB, 1);
}
-void lguest_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static void lguest_pte_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
{
native_pte_clear(mm, addr, ptep);
lguest_pte_update(mm, addr, ptep);
}
-void lguest_pmd_clear(pmd_t *pmdp)
+static void lguest_pmd_clear(pmd_t *pmdp)
{
lguest_set_pmd(pmdp, __pmd(0));
}
#endif
-/* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
+/*
+ * Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
* native page table operations. On native hardware you can set a new page
* table entry whenever you want, but if you want to remove one you have to do
* a TLB flush (a TLB is a little cache of page table entries kept by the CPU).
@@ -637,24 +748,29 @@ void lguest_pmd_clear(pmd_t *pmdp)
* called when a valid entry is written, not when it's removed (ie. marked not
* present). Instead, this is where we come when the Guest wants to remove a
* page table entry: we tell the Host to set that entry to 0 (ie. the present
- * bit is zero). */
+ * bit is zero).
+ */
static void lguest_flush_tlb_single(unsigned long addr)
{
/* Simply set it to zero: if it was not, it will fault back in. */
lazy_hcall3(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0);
}
-/* This is what happens after the Guest has removed a large number of entries.
+/*
+ * This is what happens after the Guest has removed a large number of entries.
* This tells the Host that any of the page table entries for userspace might
- * have changed, ie. virtual addresses below PAGE_OFFSET. */
+ * have changed, ie. virtual addresses below PAGE_OFFSET.
+ */
static void lguest_flush_tlb_user(void)
{
lazy_hcall1(LHCALL_FLUSH_TLB, 0);
}
-/* This is called when the kernel page tables have changed. That's not very
+/*
+ * This is called when the kernel page tables have changed. That's not very
* common (unless the Guest is using highmem, which makes the Guest extremely
- * slow), so it's worth separating this from the user flushing above. */
+ * slow), so it's worth separating this from the user flushing above.
+ */
static void lguest_flush_tlb_kernel(void)
{
lazy_hcall1(LHCALL_FLUSH_TLB, 1);
@@ -691,26 +807,38 @@ static struct irq_chip lguest_irq_controller = {
.unmask = enable_lguest_irq,
};
-/* This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
+/*
+ * This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
* interrupt (except 128, which is used for system calls), and then tells the
* Linux infrastructure that each interrupt is controlled by our level-based
- * lguest interrupt controller. */
+ * lguest interrupt controller.
+ */
static void __init lguest_init_IRQ(void)
{
unsigned int i;
for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
- /* Some systems map "vectors" to interrupts weirdly. Lguest has
- * a straightforward 1 to 1 mapping, so force that here. */
+ /* Some systems map "vectors" to interrupts weirdly. Not us! */
__get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR;
if (i != SYSCALL_VECTOR)
set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
}
- /* This call is required to set up for 4k stacks, where we have
- * separate stacks for hard and soft interrupts. */
+
+ /*
+ * This call is required to set up for 4k stacks, where we have
+ * separate stacks for hard and soft interrupts.
+ */
irq_ctx_init(smp_processor_id());
}
+/*
+ * With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so
+ * rather than set them in lguest_init_IRQ we are called here every time an
+ * lguest device needs an interrupt.
+ *
+ * FIXME: irq_to_desc_alloc_node() can fail due to lack of memory, we should
+ * pass that up!
+ */
void lguest_setup_irq(unsigned int irq)
{
irq_to_desc_alloc_node(irq, 0);
@@ -729,31 +857,39 @@ static unsigned long lguest_get_wallclock(void)
return lguest_data.time.tv_sec;
}
-/* The TSC is an Intel thing called the Time Stamp Counter. The Host tells us
+/*
+ * The TSC is an Intel thing called the Time Stamp Counter. The Host tells us
* what speed it runs at, or 0 if it's unusable as a reliable clock source.
* This matches what we want here: if we return 0 from this function, the x86
- * TSC clock will give up and not register itself. */
+ * TSC clock will give up and not register itself.
+ */
static unsigned long lguest_tsc_khz(void)
{
return lguest_data.tsc_khz;
}
-/* If we can't use the TSC, the kernel falls back to our lower-priority
- * "lguest_clock", where we read the time value given to us by the Host. */
+/*
+ * If we can't use the TSC, the kernel falls back to our lower-priority
+ * "lguest_clock", where we read the time value given to us by the Host.
+ */
static cycle_t lguest_clock_read(struct clocksource *cs)
{
unsigned long sec, nsec;
- /* Since the time is in two parts (seconds and nanoseconds), we risk
+ /*
+ * Since the time is in two parts (seconds and nanoseconds), we risk
* reading it just as it's changing from 99 & 0.999999999 to 100 and 0,
* and getting 99 and 0. As Linux tends to come apart under the stress
- * of time travel, we must be careful: */
+ * of time travel, we must be careful:
+ */
do {
/* First we read the seconds part. */
sec = lguest_data.time.tv_sec;
- /* This read memory barrier tells the compiler and the CPU that
+ /*
+ * This read memory barrier tells the compiler and the CPU that
* this can't be reordered: we have to complete the above
- * before going on. */
+ * before going on.
+ */
rmb();
/* Now we read the nanoseconds part. */
nsec = lguest_data.time.tv_nsec;
@@ -777,9 +913,11 @@ static struct clocksource lguest_clock = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-/* We also need a "struct clock_event_device": Linux asks us to set it to go
+/*
+ * We also need a "struct clock_event_device": Linux asks us to set it to go
* off some time in the future. Actually, James Morris figured all this out, I
- * just applied the patch. */
+ * just applied the patch.
+ */
static int lguest_clockevent_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -829,8 +967,10 @@ static struct clock_event_device lguest_clockevent = {
.max_delta_ns = LG_CLOCK_MAX_DELTA,
};
-/* This is the Guest timer interrupt handler (hardware interrupt 0). We just
- * call the clockevent infrastructure and it does whatever needs doing. */
+/*
+ * This is the Guest timer interrupt handler (hardware interrupt 0). We just
+ * call the clockevent infrastructure and it does whatever needs doing.
+ */
static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned long flags;
@@ -841,10 +981,12 @@ static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
local_irq_restore(flags);
}
-/* At some point in the boot process, we get asked to set up our timing
+/*
+ * At some point in the boot process, we get asked to set up our timing
* infrastructure. The kernel doesn't expect timer interrupts before this, but
* we cleverly initialized the "blocked_interrupts" field of "struct
- * lguest_data" so that timer interrupts were blocked until now. */
+ * lguest_data" so that timer interrupts were blocked until now.
+ */
static void lguest_time_init(void)
{
/* Set up the timer interrupt (0) to go to our simple timer routine */
@@ -868,14 +1010,16 @@ static void lguest_time_init(void)
* to work. They're pretty simple.
*/
-/* The Guest needs to tell the Host what stack it expects traps to use. For
+/*
+ * The Guest needs to tell the Host what stack it expects traps to use. For
* native hardware, this is part of the Task State Segment mentioned above in
* lguest_load_tr_desc(), but to help hypervisors there's this special call.
*
* We tell the Host the segment we want to use (__KERNEL_DS is the kernel data
* segment), the privilege level (we're privilege level 1, the Host is 0 and
* will not tolerate us trying to use that), the stack pointer, and the number
- * of pages in the stack. */
+ * of pages in the stack.
+ */
static void lguest_load_sp0(struct tss_struct *tss,
struct thread_struct *thread)
{
@@ -889,7 +1033,8 @@ static void lguest_set_debugreg(int regno, unsigned long value)
/* FIXME: Implement */
}
-/* There are times when the kernel wants to make sure that no memory writes are
+/*
+ * There are times when the kernel wants to make sure that no memory writes are
* caught in the cache (that they've all reached real hardware devices). This
* doesn't matter for the Guest which has virtual hardware.
*
@@ -903,11 +1048,13 @@ static void lguest_wbinvd(void)
{
}
-/* If the Guest expects to have an Advanced Programmable Interrupt Controller,
+/*
+ * If the Guest expects to have an Advanced Programmable Interrupt Controller,
* we play dumb by ignoring writes and returning 0 for reads. So it's no
* longer Programmable nor Controlling anything, and I don't think 8 lines of
* code qualifies for Advanced. It will also never interrupt anything. It
- * does, however, allow us to get through the Linux boot code. */
+ * does, however, allow us to get through the Linux boot code.
+ */
#ifdef CONFIG_X86_LOCAL_APIC
static void lguest_apic_write(u32 reg, u32 v)
{
@@ -956,11 +1103,13 @@ static void lguest_safe_halt(void)
kvm_hypercall0(LHCALL_HALT);
}
-/* The SHUTDOWN hypercall takes a string to describe what's happening, and
+/*
+ * The SHUTDOWN hypercall takes a string to describe what's happening, and
* an argument which says whether this to restart (reboot) the Guest or not.
*
* Note that the Host always prefers that the Guest speak in physical addresses
- * rather than virtual addresses, so we use __pa() here. */
+ * rather than virtual addresses, so we use __pa() here.
+ */
static void lguest_power_off(void)
{
kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"),
@@ -986,13 +1135,10 @@ static struct notifier_block paniced = {
/* Setting up memory is fairly easy. */
static __init char *lguest_memory_setup(void)
{
- /* We do this here and not earlier because lockcheck used to barf if we
- * did it before start_kernel(). I think we fixed that, so it'd be
- * nice to move it back to lguest_init. Patch welcome... */
- atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-
- /* The Linux bootloader header contains an "e820" memory map: the
- * Launcher populated the first entry with our memory limit. */
+ /*
+ *The Linux bootloader header contains an "e820" memory map: the
+ * Launcher populated the first entry with our memory limit.
+ */
e820_add_region(boot_params.e820_map[0].addr,
boot_params.e820_map[0].size,
boot_params.e820_map[0].type);
@@ -1001,16 +1147,17 @@ static __init char *lguest_memory_setup(void)
return "LGUEST";
}
-/* We will eventually use the virtio console device to produce console output,
+/*
+ * We will eventually use the virtio console device to produce console output,
* but before that is set up we use LHCALL_NOTIFY on normal memory to produce
- * console output. */
+ * console output.
+ */
static __init int early_put_chars(u32 vtermno, const char *buf, int count)
{
char scratch[17];
unsigned int len = count;
- /* We use a nul-terminated string, so we have to make a copy. Icky,
- * huh? */
+ /* We use a nul-terminated string, so we make a copy. Icky, huh? */
if (len > sizeof(scratch) - 1)
len = sizeof(scratch) - 1;
scratch[len] = '\0';
@@ -1021,8 +1168,10 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
return len;
}
-/* Rebooting also tells the Host we're finished, but the RESTART flag tells the
- * Launcher to reboot us. */
+/*
+ * Rebooting also tells the Host we're finished, but the RESTART flag tells the
+ * Launcher to reboot us.
+ */
static void lguest_restart(char *reason)
{
kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART);
@@ -1049,7 +1198,8 @@ static void lguest_restart(char *reason)
* fit comfortably.
*
* First we need assembly templates of each of the patchable Guest operations,
- * and these are in i386_head.S. */
+ * and these are in i386_head.S.
+ */
/*G:060 We construct a table from the assembler templates: */
static const struct lguest_insns
@@ -1060,9 +1210,11 @@ static const struct lguest_insns
[PARAVIRT_PATCH(pv_irq_ops.save_fl)] = { lgstart_pushf, lgend_pushf },
};
-/* Now our patch routine is fairly simple (based on the native one in
+/*
+ * Now our patch routine is fairly simple (based on the native one in
* paravirt.c). If we have a replacement, we copy it in and return how much of
- * the available space we used. */
+ * the available space we used.
+ */
static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
unsigned long addr, unsigned len)
{
@@ -1074,8 +1226,7 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
insn_len = lguest_insns[type].end - lguest_insns[type].start;
- /* Similarly if we can't fit replacement (shouldn't happen, but let's
- * be thorough). */
+ /* Similarly if it can't fit (doesn't happen, but let's be thorough). */
if (len < insn_len)
return paravirt_patch_default(type, clobber, ibuf, addr, len);
@@ -1084,22 +1235,28 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
return insn_len;
}
-/*G:029 Once we get to lguest_init(), we know we're a Guest. The various
+/*G:029
+ * Once we get to lguest_init(), we know we're a Guest. The various
* pv_ops structures in the kernel provide points for (almost) every routine we
- * have to override to avoid privileged instructions. */
+ * have to override to avoid privileged instructions.
+ */
__init void lguest_init(void)
{
- /* We're under lguest, paravirt is enabled, and we're running at
- * privilege level 1, not 0 as normal. */
+ /* We're under lguest. */
pv_info.name = "lguest";
+ /* Paravirt is enabled. */
pv_info.paravirt_enabled = 1;
+ /* We're running at privilege level 1, not 0 as normal. */
pv_info.kernel_rpl = 1;
+ /* Everyone except Xen runs with this set. */
pv_info.shared_kernel_pmd = 1;
- /* We set up all the lguest overrides for sensitive operations. These
- * are detailed with the operations themselves. */
+ /*
+ * We set up all the lguest overrides for sensitive operations. These
+ * are detailed with the operations themselves.
+ */
- /* interrupt-related operations */
+ /* Interrupt-related operations */
pv_irq_ops.init_IRQ = lguest_init_IRQ;
pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl);
pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl);
@@ -1107,11 +1264,11 @@ __init void lguest_init(void)
pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable);
pv_irq_ops.safe_halt = lguest_safe_halt;
- /* init-time operations */
+ /* Setup operations */
pv_init_ops.memory_setup = lguest_memory_setup;
pv_init_ops.patch = lguest_patch;
- /* Intercepts of various cpu instructions */
+ /* Intercepts of various CPU instructions */
pv_cpu_ops.load_gdt = lguest_load_gdt;
pv_cpu_ops.cpuid = lguest_cpuid;
pv_cpu_ops.load_idt = lguest_load_idt;
@@ -1132,7 +1289,7 @@ __init void lguest_init(void)
pv_cpu_ops.start_context_switch = paravirt_start_context_switch;
pv_cpu_ops.end_context_switch = lguest_end_context_switch;
- /* pagetable management */
+ /* Pagetable management */
pv_mmu_ops.write_cr3 = lguest_write_cr3;
pv_mmu_ops.flush_tlb_user = lguest_flush_tlb_user;
pv_mmu_ops.flush_tlb_single = lguest_flush_tlb_single;
@@ -1154,54 +1311,74 @@ __init void lguest_init(void)
pv_mmu_ops.pte_update_defer = lguest_pte_update;
#ifdef CONFIG_X86_LOCAL_APIC
- /* apic read/write intercepts */
+ /* APIC read/write intercepts */
set_lguest_basic_apic_ops();
#endif
- /* time operations */
+ /* Time operations */
pv_time_ops.get_wallclock = lguest_get_wallclock;
pv_time_ops.time_init = lguest_time_init;
pv_time_ops.get_tsc_khz = lguest_tsc_khz;
- /* Now is a good time to look at the implementations of these functions
- * before returning to the rest of lguest_init(). */
+ /*
+ * Now is a good time to look at the implementations of these functions
+ * before returning to the rest of lguest_init().
+ */
- /*G:070 Now we've seen all the paravirt_ops, we return to
+ /*G:070
+ * Now we've seen all the paravirt_ops, we return to
* lguest_init() where the rest of the fairly chaotic boot setup
- * occurs. */
+ * occurs.
+ */
- /* The stack protector is a weird thing where gcc places a canary
+ /*
+ * The stack protector is a weird thing where gcc places a canary
* value on the stack and then checks it on return. This file is
* compiled with -fno-stack-protector it, so we got this far without
* problems. The value of the canary is kept at offset 20 from the
* %gs register, so we need to set that up before calling C functions
- * in other files. */
+ * in other files.
+ */
setup_stack_canary_segment(0);
- /* We could just call load_stack_canary_segment(), but we might as
- * call switch_to_new_gdt() which loads the whole table and sets up
- * the per-cpu segment descriptor register %fs as well. */
+
+ /*
+ * We could just call load_stack_canary_segment(), but we might as well
+ * call switch_to_new_gdt() which loads the whole table and sets up the
+ * per-cpu segment descriptor register %fs as well.
+ */
switch_to_new_gdt(0);
- /* As described in head_32.S, we map the first 128M of memory. */
+ /* We actually boot with all memory mapped, but let's say 128MB. */
max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT;
- /* The Host<->Guest Switcher lives at the top of our address space, and
+ /*
+ * The Host<->Guest Switcher lives at the top of our address space, and
* the Host told us how big it is when we made LGUEST_INIT hypercall:
- * it put the answer in lguest_data.reserve_mem */
+ * it put the answer in lguest_data.reserve_mem
+ */
reserve_top_address(lguest_data.reserve_mem);
- /* If we don't initialize the lock dependency checker now, it crashes
- * paravirt_disable_iospace. */
+ /*
+ * If we don't initialize the lock dependency checker now, it crashes
+ * atomic_notifier_chain_register, then paravirt_disable_iospace.
+ */
lockdep_init();
- /* The IDE code spends about 3 seconds probing for disks: if we reserve
+ /* Hook in our special panic hypercall code. */
+ atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+
+ /*
+ * The IDE code spends about 3 seconds probing for disks: if we reserve
* all the I/O ports up front it can't get them and so doesn't probe.
* Other device drivers are similar (but less severe). This cuts the
- * kernel boot time on my machine from 4.1 seconds to 0.45 seconds. */
+ * kernel boot time on my machine from 4.1 seconds to 0.45 seconds.
+ */
paravirt_disable_iospace();
- /* This is messy CPU setup stuff which the native boot code does before
- * start_kernel, so we have to do, too: */
+ /*
+ * This is messy CPU setup stuff which the native boot code does before
+ * start_kernel, so we have to do, too:
+ */
cpu_detect(&new_cpu_data);
/* head.S usually sets up the first capability word, so do it here. */
new_cpu_data.x86_capability[0] = cpuid_edx(1);
@@ -1218,22 +1395,28 @@ __init void lguest_init(void)
acpi_ht = 0;
#endif
- /* We set the preferred console to "hvc". This is the "hypervisor
+ /*
+ * We set the preferred console to "hvc". This is the "hypervisor
* virtual console" driver written by the PowerPC people, which we also
- * adapted for lguest's use. */
+ * adapted for lguest's use.
+ */
add_preferred_console("hvc", 0, NULL);
/* Register our very early console. */
virtio_cons_early_init(early_put_chars);
- /* Last of all, we set the power management poweroff hook to point to
+ /*
+ * Last of all, we set the power management poweroff hook to point to
* the Guest routine to power off, and the reboot hook to our restart
- * routine. */
+ * routine.
+ */
pm_power_off = lguest_power_off;
machine_ops.restart = lguest_restart;
- /* Now we're set up, call i386_start_kernel() in head32.c and we proceed
- * to boot as normal. It never returns. */
+ /*
+ * Now we're set up, call i386_start_kernel() in head32.c and we proceed
+ * to boot as normal. It never returns.
+ */
i386_start_kernel();
}
/*
diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S
index a9c8cfe61cd4..27eac0faee48 100644
--- a/arch/x86/lguest/i386_head.S
+++ b/arch/x86/lguest/i386_head.S
@@ -5,7 +5,8 @@
#include <asm/thread_info.h>
#include <asm/processor-flags.h>
-/*G:020 Our story starts with the kernel booting into startup_32 in
+/*G:020
+ * Our story starts with the kernel booting into startup_32 in
* arch/x86/kernel/head_32.S. It expects a boot header, which is created by
* the bootloader (the Launcher in our case).
*
@@ -21,11 +22,14 @@
* data without remembering to subtract __PAGE_OFFSET!
*
* The .section line puts this code in .init.text so it will be discarded after
- * boot. */
+ * boot.
+ */
.section .init.text, "ax", @progbits
ENTRY(lguest_entry)
- /* We make the "initialization" hypercall now to tell the Host about
- * us, and also find out where it put our page tables. */
+ /*
+ * We make the "initialization" hypercall now to tell the Host about
+ * us, and also find out where it put our page tables.
+ */
movl $LHCALL_LGUEST_INIT, %eax
movl $lguest_data - __PAGE_OFFSET, %ebx
.byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
@@ -33,13 +37,14 @@ ENTRY(lguest_entry)
/* Set up the initial stack so we can run C code. */
movl $(init_thread_union+THREAD_SIZE),%esp
- /* Jumps are relative, and we're running __PAGE_OFFSET too low at the
- * moment. */
+ /* Jumps are relative: we're running __PAGE_OFFSET too low. */
jmp lguest_init+__PAGE_OFFSET
-/*G:055 We create a macro which puts the assembler code between lgstart_ and
- * lgend_ markers. These templates are put in the .text section: they can't be
- * discarded after boot as we may need to patch modules, too. */
+/*G:055
+ * We create a macro which puts the assembler code between lgstart_ and lgend_
+ * markers. These templates are put in the .text section: they can't be
+ * discarded after boot as we may need to patch modules, too.
+ */
.text
#define LGUEST_PATCH(name, insns...) \
lgstart_##name: insns; lgend_##name:; \
@@ -48,83 +53,103 @@ ENTRY(lguest_entry)
LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
-/*G:033 But using those wrappers is inefficient (we'll see why that doesn't
- * matter for save_fl and irq_disable later). If we write our routines
- * carefully in assembler, we can avoid clobbering any registers and avoid
- * jumping through the wrapper functions.
+/*G:033
+ * But using those wrappers is inefficient (we'll see why that doesn't matter
+ * for save_fl and irq_disable later). If we write our routines carefully in
+ * assembler, we can avoid clobbering any registers and avoid jumping through
+ * the wrapper functions.
*
* I skipped over our first piece of assembler, but this one is worth studying
- * in a bit more detail so I'll describe in easy stages. First, the routine
- * to enable interrupts: */
+ * in a bit more detail so I'll describe in easy stages. First, the routine to
+ * enable interrupts:
+ */
ENTRY(lg_irq_enable)
- /* The reverse of irq_disable, this sets lguest_data.irq_enabled to
- * X86_EFLAGS_IF (ie. "Interrupts enabled"). */
+ /*
+ * The reverse of irq_disable, this sets lguest_data.irq_enabled to
+ * X86_EFLAGS_IF (ie. "Interrupts enabled").
+ */
movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled
- /* But now we need to check if the Host wants to know: there might have
+ /*
+ * But now we need to check if the Host wants to know: there might have
* been interrupts waiting to be delivered, in which case it will have
* set lguest_data.irq_pending to X86_EFLAGS_IF. If it's not zero, we
- * jump to send_interrupts, otherwise we're done. */
+ * jump to send_interrupts, otherwise we're done.
+ */
testl $0, lguest_data+LGUEST_DATA_irq_pending
jnz send_interrupts
- /* One cool thing about x86 is that you can do many things without using
+ /*
+ * One cool thing about x86 is that you can do many things without using
* a register. In this case, the normal path hasn't needed to save or
- * restore any registers at all! */
+ * restore any registers at all!
+ */
ret
send_interrupts:
- /* OK, now we need a register: eax is used for the hypercall number,
+ /*
+ * OK, now we need a register: eax is used for the hypercall number,
* which is LHCALL_SEND_INTERRUPTS.
*
* We used not to bother with this pending detection at all, which was
* much simpler. Sooner or later the Host would realize it had to
* send us an interrupt. But that turns out to make performance 7
* times worse on a simple tcp benchmark. So now we do this the hard
- * way. */
+ * way.
+ */
pushl %eax
movl $LHCALL_SEND_INTERRUPTS, %eax
- /* This is a vmcall instruction (same thing that KVM uses). Older
+ /*
+ * This is a vmcall instruction (same thing that KVM uses). Older
* assembler versions might not know the "vmcall" instruction, so we
- * create one manually here. */
+ * create one manually here.
+ */
.byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
+ /* Put eax back the way we found it. */
popl %eax
ret
-/* Finally, the "popf" or "restore flags" routine. The %eax register holds the
+/*
+ * Finally, the "popf" or "restore flags" routine. The %eax register holds the
* flags (in practice, either X86_EFLAGS_IF or 0): if it's X86_EFLAGS_IF we're
- * enabling interrupts again, if it's 0 we're leaving them off. */
+ * enabling interrupts again, if it's 0 we're leaving them off.
+ */
ENTRY(lg_restore_fl)
/* This is just "lguest_data.irq_enabled = flags;" */
movl %eax, lguest_data+LGUEST_DATA_irq_enabled
- /* Now, if the %eax value has enabled interrupts and
+ /*
+ * Now, if the %eax value has enabled interrupts and
* lguest_data.irq_pending is set, we want to tell the Host so it can
* deliver any outstanding interrupts. Fortunately, both values will
* be X86_EFLAGS_IF (ie. 512) in that case, and the "testl"
* instruction will AND them together for us. If both are set, we
- * jump to send_interrupts. */
+ * jump to send_interrupts.
+ */
testl lguest_data+LGUEST_DATA_irq_pending, %eax
jnz send_interrupts
/* Again, the normal path has used no extra registers. Clever, huh? */
ret
+/*:*/
/* These demark the EIP range where host should never deliver interrupts. */
.global lguest_noirq_start
.global lguest_noirq_end
-/*M:004 When the Host reflects a trap or injects an interrupt into the Guest,
- * it sets the eflags interrupt bit on the stack based on
- * lguest_data.irq_enabled, so the Guest iret logic does the right thing when
- * restoring it. However, when the Host sets the Guest up for direct traps,
- * such as system calls, the processor is the one to push eflags onto the
- * stack, and the interrupt bit will be 1 (in reality, interrupts are always
- * enabled in the Guest).
+/*M:004
+ * When the Host reflects a trap or injects an interrupt into the Guest, it
+ * sets the eflags interrupt bit on the stack based on lguest_data.irq_enabled,
+ * so the Guest iret logic does the right thing when restoring it. However,
+ * when the Host sets the Guest up for direct traps, such as system calls, the
+ * processor is the one to push eflags onto the stack, and the interrupt bit
+ * will be 1 (in reality, interrupts are always enabled in the Guest).
*
* This turns out to be harmless: the only trap which should happen under Linux
* with interrupts disabled is Page Fault (due to our lazy mapping of vmalloc
* regions), which has to be reflected through the Host anyway. If another
* trap *does* go off when interrupts are disabled, the Guest will panic, and
- * we'll never get to this iret! :*/
+ * we'll never get to this iret!
+:*/
-/*G:045 There is one final paravirt_op that the Guest implements, and glancing
- * at it you can see why I left it to last. It's *cool*! It's in *assembler*!
+/*G:045
+ * There is one final paravirt_op that the Guest implements, and glancing at it
+ * you can see why I left it to last. It's *cool*! It's in *assembler*!
*
* The "iret" instruction is used to return from an interrupt or trap. The
* stack looks like this:
@@ -148,15 +173,18 @@ ENTRY(lg_restore_fl)
* return to userspace or wherever. Our solution to this is to surround the
* code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the
* Host that it is *never* to interrupt us there, even if interrupts seem to be
- * enabled. */
+ * enabled.
+ */
ENTRY(lguest_iret)
pushl %eax
movl 12(%esp), %eax
lguest_noirq_start:
- /* Note the %ss: segment prefix here. Normal data accesses use the
+ /*
+ * Note the %ss: segment prefix here. Normal data accesses use the
* "ds" segment, but that will have already been restored for whatever
* we're returning to (such as userspace): we can't trust it. The %ss:
- * prefix makes sure we use the stack segment, which is still valid. */
+ * prefix makes sure we use the stack segment, which is still valid.
+ */
movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
popl %eax
iret
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 1440b9c0547e..2f26cf4c1e85 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -71,14 +71,9 @@ int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
}
EXPORT_SYMBOL(wrmsr_on_cpu);
-/* rdmsr on a bunch of CPUs
- *
- * @mask: which CPUs
- * @msr_no: which MSR
- * @msrs: array of MSR values
- *
- */
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+ struct msr *msrs,
+ void (*msr_func) (void *info))
{
struct msr_info rv;
int this_cpu;
@@ -89,16 +84,25 @@ void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
rv.msrs = msrs;
rv.msr_no = msr_no;
- preempt_disable();
- /*
- * FIXME: handle the CPU we're executing on separately for now until
- * smp_call_function_many has been fixed to not skip it.
- */
- this_cpu = raw_smp_processor_id();
- smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1);
+ this_cpu = get_cpu();
- smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
- preempt_enable();
+ if (cpumask_test_cpu(this_cpu, mask))
+ msr_func(&rv);
+
+ smp_call_function_many(mask, msr_func, &rv, 1);
+ put_cpu();
+}
+
+/* rdmsr on a bunch of CPUs
+ *
+ * @mask: which CPUs
+ * @msr_no: which MSR
+ * @msrs: array of MSR values
+ *
+ */
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+{
+ __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
}
EXPORT_SYMBOL(rdmsr_on_cpus);
@@ -110,27 +114,9 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
* @msrs: array of MSR values
*
*/
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
{
- struct msr_info rv;
- int this_cpu;
-
- memset(&rv, 0, sizeof(rv));
-
- rv.off = cpumask_first(mask);
- rv.msrs = msrs;
- rv.msr_no = msr_no;
-
- preempt_disable();
- /*
- * FIXME: handle the CPU we're executing on separately for now until
- * smp_call_function_many has been fixed to not skip it.
- */
- this_cpu = raw_smp_processor_id();
- smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1);
-
- smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
- preempt_enable();
+ __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
}
EXPORT_SYMBOL(wrmsr_on_cpus);
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index bfae139182ff..775a020990a5 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -285,26 +285,25 @@ check_v8086_mode(struct pt_regs *regs, unsigned long address,
tsk->thread.screen_bitmap |= 1 << bit;
}
-static void dump_pagetable(unsigned long address)
+static bool low_pfn(unsigned long pfn)
{
- __typeof__(pte_val(__pte(0))) page;
+ return pfn < max_low_pfn;
+}
- page = read_cr3();
- page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT];
+static void dump_pagetable(unsigned long address)
+{
+ pgd_t *base = __va(read_cr3());
+ pgd_t *pgd = &base[pgd_index(address)];
+ pmd_t *pmd;
+ pte_t *pte;
#ifdef CONFIG_X86_PAE
- printk("*pdpt = %016Lx ", page);
- if ((page >> PAGE_SHIFT) < max_low_pfn
- && page & _PAGE_PRESENT) {
- page &= PAGE_MASK;
- page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT)
- & (PTRS_PER_PMD - 1)];
- printk(KERN_CONT "*pde = %016Lx ", page);
- page &= ~_PAGE_NX;
- }
-#else
- printk("*pde = %08lx ", page);
+ printk("*pdpt = %016Lx ", pgd_val(*pgd));
+ if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd))
+ goto out;
#endif
+ pmd = pmd_offset(pud_offset(pgd, address), address);
+ printk(KERN_CONT "*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd));
/*
* We must not directly access the pte in the highpte
@@ -312,16 +311,12 @@ static void dump_pagetable(unsigned long address)
* And let's rather not kmap-atomic the pte, just in case
* it's allocated already:
*/
- if ((page >> PAGE_SHIFT) < max_low_pfn
- && (page & _PAGE_PRESENT)
- && !(page & _PAGE_PSE)) {
-
- page &= PAGE_MASK;
- page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT)
- & (PTRS_PER_PTE - 1)];
- printk("*pte = %0*Lx ", sizeof(page)*2, (u64)page);
- }
+ if (!low_pfn(pmd_pfn(*pmd)) || !pmd_present(*pmd) || pmd_large(*pmd))
+ goto out;
+ pte = pte_offset_kernel(pmd, address);
+ printk("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte));
+out:
printk("\n");
}
@@ -450,16 +445,12 @@ static int bad_address(void *p)
static void dump_pagetable(unsigned long address)
{
- pgd_t *pgd;
+ pgd_t *base = __va(read_cr3() & PHYSICAL_PAGE_MASK);
+ pgd_t *pgd = base + pgd_index(address);
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- pgd = (pgd_t *)read_cr3();
-
- pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK);
-
- pgd += pgd_index(address);
if (bad_address(pgd))
goto bad;
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 58f621e81919..1617958a3805 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -24,7 +24,7 @@ void kunmap(struct page *page)
* no global lock is needed and because the kmap code must perform a global TLB
* invalidation when the kmap pool wraps.
*
- * However when holding an atomic kmap is is not legal to sleep, so atomic
+ * However when holding an atomic kmap it is not legal to sleep, so atomic
* kmaps are appropriate for short, tight code paths only.
*/
void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
@@ -103,6 +103,7 @@ EXPORT_SYMBOL(kmap);
EXPORT_SYMBOL(kunmap);
EXPORT_SYMBOL(kmap_atomic);
EXPORT_SYMBOL(kunmap_atomic);
+EXPORT_SYMBOL(kmap_atomic_prot);
void __init set_highmem_pages_init(void)
{
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 1b734d7a8966..c106f7852424 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -12,6 +12,7 @@
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/pfn.h>
+#include <linux/percpu.h>
#include <asm/e820.h>
#include <asm/processor.h>
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 8e43bdd45456..af8f9650058c 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -25,7 +25,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
return pte;
}
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
+void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
{
pgtable_page_dtor(pte);
paravirt_release_pte(page_to_pfn(pte));
@@ -33,14 +33,14 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
}
#if PAGETABLE_LEVELS > 2
-void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
{
paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT);
tlb_remove_page(tlb, virt_to_page(pmd));
}
#if PAGETABLE_LEVELS > 3
-void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+void ___pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
{
paravirt_release_pud(__pa(pud) >> PAGE_SHIFT);
tlb_remove_page(tlb, virt_to_page(pud));
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index 2dfcbf9df2ae..dbb5381f7b3b 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -79,8 +79,10 @@ static __init void bad_srat(void)
acpi_numa = -1;
for (i = 0; i < MAX_LOCAL_APIC; i++)
apicid_to_node[i] = NUMA_NO_NODE;
- for (i = 0; i < MAX_NUMNODES; i++)
- nodes_add[i].start = nodes[i].end = 0;
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ nodes[i].start = nodes[i].end = 0;
+ nodes_add[i].start = nodes_add[i].end = 0;
+ }
remove_all_active_ranges();
}
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 821e97017e95..010b2e575002 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -59,7 +59,8 @@ void leave_mm(int cpu)
{
if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
BUG();
- cpu_clear(cpu, percpu_read(cpu_tlbstate.active_mm)->cpu_vm_mask);
+ cpumask_clear_cpu(cpu,
+ mm_cpumask(percpu_read(cpu_tlbstate.active_mm)));
load_cr3(swapper_pg_dir);
}
EXPORT_SYMBOL_GPL(leave_mm);
@@ -235,8 +236,8 @@ void flush_tlb_current_task(void)
preempt_disable();
local_flush_tlb();
- if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
- flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL);
+ if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
+ flush_tlb_others(mm_cpumask(mm), mm, TLB_FLUSH_ALL);
preempt_enable();
}
@@ -250,8 +251,8 @@ void flush_tlb_mm(struct mm_struct *mm)
else
leave_mm(smp_processor_id());
}
- if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
- flush_tlb_others(&mm->cpu_vm_mask, mm, TLB_FLUSH_ALL);
+ if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
+ flush_tlb_others(mm_cpumask(mm), mm, TLB_FLUSH_ALL);
preempt_enable();
}
@@ -269,8 +270,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
leave_mm(smp_processor_id());
}
- if (cpumask_any_but(&mm->cpu_vm_mask, smp_processor_id()) < nr_cpu_ids)
- flush_tlb_others(&mm->cpu_vm_mask, mm, va);
+ if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
+ flush_tlb_others(mm_cpumask(mm), mm, va);
preempt_enable();
}
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index 89b9a5cd63da..cb88b1a0bd5f 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -1,11 +1,14 @@
/**
* @file nmi_int.c
*
- * @remark Copyright 2002-2008 OProfile authors
+ * @remark Copyright 2002-2009 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
* @author Robert Richter <robert.richter@amd.com>
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
+ * @author Jason Yeh <jason.yeh@amd.com>
+ * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
*/
#include <linux/init.h>
@@ -24,13 +27,35 @@
#include "op_counter.h"
#include "op_x86_model.h"
-static struct op_x86_model_spec const *model;
+static struct op_x86_model_spec *model;
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
/* 0 == registered but off, 1 == registered and on */
static int nmi_enabled = 0;
+struct op_counter_config counter_config[OP_MAX_COUNTER];
+
+/* common functions */
+
+u64 op_x86_get_ctrl(struct op_x86_model_spec const *model,
+ struct op_counter_config *counter_config)
+{
+ u64 val = 0;
+ u16 event = (u16)counter_config->event;
+
+ val |= ARCH_PERFMON_EVENTSEL_INT;
+ val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0;
+ val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0;
+ val |= (counter_config->unit_mask & 0xFF) << 8;
+ event &= model->event_mask ? model->event_mask : 0xFF;
+ val |= event & 0xFF;
+ val |= (event & 0x0F00) << 24;
+
+ return val;
+}
+
+
static int profile_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
@@ -52,36 +77,214 @@ static int profile_exceptions_notify(struct notifier_block *self,
static void nmi_cpu_save_registers(struct op_msrs *msrs)
{
- unsigned int const nr_ctrs = model->num_counters;
- unsigned int const nr_ctrls = model->num_controls;
struct op_msr *counters = msrs->counters;
struct op_msr *controls = msrs->controls;
unsigned int i;
- for (i = 0; i < nr_ctrs; ++i) {
- if (counters[i].addr) {
- rdmsr(counters[i].addr,
- counters[i].saved.low,
- counters[i].saved.high);
- }
+ for (i = 0; i < model->num_counters; ++i) {
+ if (counters[i].addr)
+ rdmsrl(counters[i].addr, counters[i].saved);
+ }
+
+ for (i = 0; i < model->num_controls; ++i) {
+ if (controls[i].addr)
+ rdmsrl(controls[i].addr, controls[i].saved);
+ }
+}
+
+static void nmi_cpu_start(void *dummy)
+{
+ struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
+ model->start(msrs);
+}
+
+static int nmi_start(void)
+{
+ on_each_cpu(nmi_cpu_start, NULL, 1);
+ return 0;
+}
+
+static void nmi_cpu_stop(void *dummy)
+{
+ struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
+ model->stop(msrs);
+}
+
+static void nmi_stop(void)
+{
+ on_each_cpu(nmi_cpu_stop, NULL, 1);
+}
+
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+
+static DEFINE_PER_CPU(int, switch_index);
+
+static inline int has_mux(void)
+{
+ return !!model->switch_ctrl;
+}
+
+inline int op_x86_phys_to_virt(int phys)
+{
+ return __get_cpu_var(switch_index) + phys;
+}
+
+inline int op_x86_virt_to_phys(int virt)
+{
+ return virt % model->num_counters;
+}
+
+static void nmi_shutdown_mux(void)
+{
+ int i;
+
+ if (!has_mux())
+ return;
+
+ for_each_possible_cpu(i) {
+ kfree(per_cpu(cpu_msrs, i).multiplex);
+ per_cpu(cpu_msrs, i).multiplex = NULL;
+ per_cpu(switch_index, i) = 0;
}
+}
+
+static int nmi_setup_mux(void)
+{
+ size_t multiplex_size =
+ sizeof(struct op_msr) * model->num_virt_counters;
+ int i;
+
+ if (!has_mux())
+ return 1;
+
+ for_each_possible_cpu(i) {
+ per_cpu(cpu_msrs, i).multiplex =
+ kmalloc(multiplex_size, GFP_KERNEL);
+ if (!per_cpu(cpu_msrs, i).multiplex)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
+{
+ int i;
+ struct op_msr *multiplex = msrs->multiplex;
+
+ if (!has_mux())
+ return;
- for (i = 0; i < nr_ctrls; ++i) {
- if (controls[i].addr) {
- rdmsr(controls[i].addr,
- controls[i].saved.low,
- controls[i].saved.high);
+ for (i = 0; i < model->num_virt_counters; ++i) {
+ if (counter_config[i].enabled) {
+ multiplex[i].saved = -(u64)counter_config[i].count;
+ } else {
+ multiplex[i].addr = 0;
+ multiplex[i].saved = 0;
}
}
+
+ per_cpu(switch_index, cpu) = 0;
+}
+
+static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs)
+{
+ struct op_msr *multiplex = msrs->multiplex;
+ int i;
+
+ for (i = 0; i < model->num_counters; ++i) {
+ int virt = op_x86_phys_to_virt(i);
+ if (multiplex[virt].addr)
+ rdmsrl(multiplex[virt].addr, multiplex[virt].saved);
+ }
+}
+
+static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs)
+{
+ struct op_msr *multiplex = msrs->multiplex;
+ int i;
+
+ for (i = 0; i < model->num_counters; ++i) {
+ int virt = op_x86_phys_to_virt(i);
+ if (multiplex[virt].addr)
+ wrmsrl(multiplex[virt].addr, multiplex[virt].saved);
+ }
}
-static void nmi_save_registers(void *dummy)
+static void nmi_cpu_switch(void *dummy)
{
int cpu = smp_processor_id();
+ int si = per_cpu(switch_index, cpu);
struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
- nmi_cpu_save_registers(msrs);
+
+ nmi_cpu_stop(NULL);
+ nmi_cpu_save_mpx_registers(msrs);
+
+ /* move to next set */
+ si += model->num_counters;
+ if ((si > model->num_virt_counters) || (counter_config[si].count == 0))
+ per_cpu(switch_index, cpu) = 0;
+ else
+ per_cpu(switch_index, cpu) = si;
+
+ model->switch_ctrl(model, msrs);
+ nmi_cpu_restore_mpx_registers(msrs);
+
+ nmi_cpu_start(NULL);
+}
+
+
+/*
+ * Quick check to see if multiplexing is necessary.
+ * The check should be sufficient since counters are used
+ * in ordre.
+ */
+static int nmi_multiplex_on(void)
+{
+ return counter_config[model->num_counters].count ? 0 : -EINVAL;
+}
+
+static int nmi_switch_event(void)
+{
+ if (!has_mux())
+ return -ENOSYS; /* not implemented */
+ if (nmi_multiplex_on() < 0)
+ return -EINVAL; /* not necessary */
+
+ on_each_cpu(nmi_cpu_switch, NULL, 1);
+
+ return 0;
+}
+
+static inline void mux_init(struct oprofile_operations *ops)
+{
+ if (has_mux())
+ ops->switch_events = nmi_switch_event;
+}
+
+static void mux_clone(int cpu)
+{
+ if (!has_mux())
+ return;
+
+ memcpy(per_cpu(cpu_msrs, cpu).multiplex,
+ per_cpu(cpu_msrs, 0).multiplex,
+ sizeof(struct op_msr) * model->num_virt_counters);
}
+#else
+
+inline int op_x86_phys_to_virt(int phys) { return phys; }
+inline int op_x86_virt_to_phys(int virt) { return virt; }
+static inline void nmi_shutdown_mux(void) { }
+static inline int nmi_setup_mux(void) { return 1; }
+static inline void
+nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { }
+static inline void mux_init(struct oprofile_operations *ops) { }
+static void mux_clone(int cpu) { }
+
+#endif
+
static void free_msrs(void)
{
int i;
@@ -95,38 +298,32 @@ static void free_msrs(void)
static int allocate_msrs(void)
{
- int success = 1;
size_t controls_size = sizeof(struct op_msr) * model->num_controls;
size_t counters_size = sizeof(struct op_msr) * model->num_counters;
int i;
for_each_possible_cpu(i) {
per_cpu(cpu_msrs, i).counters = kmalloc(counters_size,
- GFP_KERNEL);
- if (!per_cpu(cpu_msrs, i).counters) {
- success = 0;
- break;
- }
+ GFP_KERNEL);
+ if (!per_cpu(cpu_msrs, i).counters)
+ return 0;
per_cpu(cpu_msrs, i).controls = kmalloc(controls_size,
- GFP_KERNEL);
- if (!per_cpu(cpu_msrs, i).controls) {
- success = 0;
- break;
- }
+ GFP_KERNEL);
+ if (!per_cpu(cpu_msrs, i).controls)
+ return 0;
}
- if (!success)
- free_msrs();
-
- return success;
+ return 1;
}
static void nmi_cpu_setup(void *dummy)
{
int cpu = smp_processor_id();
struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
+ nmi_cpu_save_registers(msrs);
spin_lock(&oprofilefs_lock);
- model->setup_ctrs(msrs);
+ model->setup_ctrs(model, msrs);
+ nmi_cpu_setup_mux(cpu, msrs);
spin_unlock(&oprofilefs_lock);
per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC);
apic_write(APIC_LVTPC, APIC_DM_NMI);
@@ -144,11 +341,15 @@ static int nmi_setup(void)
int cpu;
if (!allocate_msrs())
- return -ENOMEM;
+ err = -ENOMEM;
+ else if (!nmi_setup_mux())
+ err = -ENOMEM;
+ else
+ err = register_die_notifier(&profile_exceptions_nb);
- err = register_die_notifier(&profile_exceptions_nb);
if (err) {
free_msrs();
+ nmi_shutdown_mux();
return err;
}
@@ -159,45 +360,38 @@ static int nmi_setup(void)
/* Assume saved/restored counters are the same on all CPUs */
model->fill_in_addresses(&per_cpu(cpu_msrs, 0));
for_each_possible_cpu(cpu) {
- if (cpu != 0) {
- memcpy(per_cpu(cpu_msrs, cpu).counters,
- per_cpu(cpu_msrs, 0).counters,
- sizeof(struct op_msr) * model->num_counters);
-
- memcpy(per_cpu(cpu_msrs, cpu).controls,
- per_cpu(cpu_msrs, 0).controls,
- sizeof(struct op_msr) * model->num_controls);
- }
+ if (!cpu)
+ continue;
+
+ memcpy(per_cpu(cpu_msrs, cpu).counters,
+ per_cpu(cpu_msrs, 0).counters,
+ sizeof(struct op_msr) * model->num_counters);
+
+ memcpy(per_cpu(cpu_msrs, cpu).controls,
+ per_cpu(cpu_msrs, 0).controls,
+ sizeof(struct op_msr) * model->num_controls);
+ mux_clone(cpu);
}
- on_each_cpu(nmi_save_registers, NULL, 1);
on_each_cpu(nmi_cpu_setup, NULL, 1);
nmi_enabled = 1;
return 0;
}
-static void nmi_restore_registers(struct op_msrs *msrs)
+static void nmi_cpu_restore_registers(struct op_msrs *msrs)
{
- unsigned int const nr_ctrs = model->num_counters;
- unsigned int const nr_ctrls = model->num_controls;
struct op_msr *counters = msrs->counters;
struct op_msr *controls = msrs->controls;
unsigned int i;
- for (i = 0; i < nr_ctrls; ++i) {
- if (controls[i].addr) {
- wrmsr(controls[i].addr,
- controls[i].saved.low,
- controls[i].saved.high);
- }
+ for (i = 0; i < model->num_controls; ++i) {
+ if (controls[i].addr)
+ wrmsrl(controls[i].addr, controls[i].saved);
}
- for (i = 0; i < nr_ctrs; ++i) {
- if (counters[i].addr) {
- wrmsr(counters[i].addr,
- counters[i].saved.low,
- counters[i].saved.high);
- }
+ for (i = 0; i < model->num_counters; ++i) {
+ if (counters[i].addr)
+ wrmsrl(counters[i].addr, counters[i].saved);
}
}
@@ -205,7 +399,7 @@ static void nmi_cpu_shutdown(void *dummy)
{
unsigned int v;
int cpu = smp_processor_id();
- struct op_msrs *msrs = &__get_cpu_var(cpu_msrs);
+ struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
/* restoring APIC_LVTPC can trigger an apic error because the delivery
* mode and vector nr combination can be illegal. That's by design: on
@@ -216,7 +410,7 @@ static void nmi_cpu_shutdown(void *dummy)
apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu));
apic_write(APIC_LVTERR, v);
- nmi_restore_registers(msrs);
+ nmi_cpu_restore_registers(msrs);
}
static void nmi_shutdown(void)
@@ -226,42 +420,18 @@ static void nmi_shutdown(void)
nmi_enabled = 0;
on_each_cpu(nmi_cpu_shutdown, NULL, 1);
unregister_die_notifier(&profile_exceptions_nb);
+ nmi_shutdown_mux();
msrs = &get_cpu_var(cpu_msrs);
model->shutdown(msrs);
free_msrs();
put_cpu_var(cpu_msrs);
}
-static void nmi_cpu_start(void *dummy)
-{
- struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
- model->start(msrs);
-}
-
-static int nmi_start(void)
-{
- on_each_cpu(nmi_cpu_start, NULL, 1);
- return 0;
-}
-
-static void nmi_cpu_stop(void *dummy)
-{
- struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
- model->stop(msrs);
-}
-
-static void nmi_stop(void)
-{
- on_each_cpu(nmi_cpu_stop, NULL, 1);
-}
-
-struct op_counter_config counter_config[OP_MAX_COUNTER];
-
static int nmi_create_files(struct super_block *sb, struct dentry *root)
{
unsigned int i;
- for (i = 0; i < model->num_counters; ++i) {
+ for (i = 0; i < model->num_virt_counters; ++i) {
struct dentry *dir;
char buf[4];
@@ -270,7 +440,7 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root)
* NOTE: assumes 1:1 mapping here (that counters are organized
* sequentially in their struct assignment).
*/
- if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
+ if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i)))
continue;
snprintf(buf, sizeof(buf), "%d", i);
@@ -402,6 +572,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0);
static int __init ppro_init(char **cpu_type)
{
__u8 cpu_model = boot_cpu_data.x86_model;
+ struct op_x86_model_spec *spec = &op_ppro_spec; /* default */
if (force_arch_perfmon && cpu_has_arch_perfmon)
return 0;
@@ -428,7 +599,7 @@ static int __init ppro_init(char **cpu_type)
*cpu_type = "i386/core_2";
break;
case 26:
- arch_perfmon_setup_counters();
+ spec = &op_arch_perfmon_spec;
*cpu_type = "i386/core_i7";
break;
case 28:
@@ -439,17 +610,7 @@ static int __init ppro_init(char **cpu_type)
return 0;
}
- model = &op_ppro_spec;
- return 1;
-}
-
-static int __init arch_perfmon_init(char **cpu_type)
-{
- if (!cpu_has_arch_perfmon)
- return 0;
- *cpu_type = "i386/arch_perfmon";
- model = &op_arch_perfmon_spec;
- arch_perfmon_setup_counters();
+ model = spec;
return 1;
}
@@ -471,27 +632,26 @@ int __init op_nmi_init(struct oprofile_operations *ops)
/* Needs to be at least an Athlon (or hammer in 32bit mode) */
switch (family) {
- default:
- return -ENODEV;
case 6:
- model = &op_amd_spec;
cpu_type = "i386/athlon";
break;
case 0xf:
- model = &op_amd_spec;
- /* Actually it could be i386/hammer too, but give
- user space an consistent name. */
+ /*
+ * Actually it could be i386/hammer too, but
+ * give user space an consistent name.
+ */
cpu_type = "x86-64/hammer";
break;
case 0x10:
- model = &op_amd_spec;
cpu_type = "x86-64/family10";
break;
case 0x11:
- model = &op_amd_spec;
cpu_type = "x86-64/family11h";
break;
+ default:
+ return -ENODEV;
}
+ model = &op_amd_spec;
break;
case X86_VENDOR_INTEL:
@@ -510,8 +670,15 @@ int __init op_nmi_init(struct oprofile_operations *ops)
break;
}
- if (!cpu_type && !arch_perfmon_init(&cpu_type))
+ if (cpu_type)
+ break;
+
+ if (!cpu_has_arch_perfmon)
return -ENODEV;
+
+ /* use arch perfmon as fallback */
+ cpu_type = "i386/arch_perfmon";
+ model = &op_arch_perfmon_spec;
break;
default:
@@ -522,18 +689,23 @@ int __init op_nmi_init(struct oprofile_operations *ops)
register_cpu_notifier(&oprofile_cpu_nb);
#endif
/* default values, can be overwritten by model */
- ops->create_files = nmi_create_files;
- ops->setup = nmi_setup;
- ops->shutdown = nmi_shutdown;
- ops->start = nmi_start;
- ops->stop = nmi_stop;
- ops->cpu_type = cpu_type;
+ ops->create_files = nmi_create_files;
+ ops->setup = nmi_setup;
+ ops->shutdown = nmi_shutdown;
+ ops->start = nmi_start;
+ ops->stop = nmi_stop;
+ ops->cpu_type = cpu_type;
if (model->init)
ret = model->init(ops);
if (ret)
return ret;
+ if (!model->num_virt_counters)
+ model->num_virt_counters = model->num_counters;
+
+ mux_init(ops);
+
init_sysfs();
using_nmi = 1;
printk(KERN_INFO "oprofile: using NMI interrupt.\n");
diff --git a/arch/x86/oprofile/op_counter.h b/arch/x86/oprofile/op_counter.h
index 91b6a116165e..e28398df0df2 100644
--- a/arch/x86/oprofile/op_counter.h
+++ b/arch/x86/oprofile/op_counter.h
@@ -10,7 +10,7 @@
#ifndef OP_COUNTER_H
#define OP_COUNTER_H
-#define OP_MAX_COUNTER 8
+#define OP_MAX_COUNTER 32
/* Per-perfctr configuration as set via
* oprofilefs.
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index 8fdf06e4edf9..827beecb67a4 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -9,12 +9,15 @@
* @author Philippe Elie
* @author Graydon Hoare
* @author Robert Richter <robert.richter@amd.com>
- * @author Barry Kasindorf
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
+ * @author Jason Yeh <jason.yeh@amd.com>
+ * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
*/
#include <linux/oprofile.h>
#include <linux/device.h>
#include <linux/pci.h>
+#include <linux/percpu.h>
#include <asm/ptrace.h>
#include <asm/msr.h>
@@ -25,43 +28,36 @@
#define NUM_COUNTERS 4
#define NUM_CONTROLS 4
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+#define NUM_VIRT_COUNTERS 32
+#define NUM_VIRT_CONTROLS 32
+#else
+#define NUM_VIRT_COUNTERS NUM_COUNTERS
+#define NUM_VIRT_CONTROLS NUM_CONTROLS
+#endif
+
+#define OP_EVENT_MASK 0x0FFF
+#define OP_CTR_OVERFLOW (1ULL<<31)
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
-#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR_LO(x) (x &= (1<<21))
-#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
-#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
-#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
-#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
-
-static unsigned long reset_value[NUM_COUNTERS];
+#define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21))
+
+static unsigned long reset_value[NUM_VIRT_COUNTERS];
#ifdef CONFIG_OPROFILE_IBS
/* IbsFetchCtl bits/masks */
-#define IBS_FETCH_HIGH_VALID_BIT (1UL << 17) /* bit 49 */
-#define IBS_FETCH_HIGH_ENABLE (1UL << 16) /* bit 48 */
-#define IBS_FETCH_LOW_MAX_CNT_MASK 0x0000FFFFUL /* MaxCnt mask */
+#define IBS_FETCH_RAND_EN (1ULL<<57)
+#define IBS_FETCH_VAL (1ULL<<49)
+#define IBS_FETCH_ENABLE (1ULL<<48)
+#define IBS_FETCH_CNT_MASK 0xFFFF0000ULL
/*IbsOpCtl bits */
-#define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */
-#define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */
+#define IBS_OP_CNT_CTL (1ULL<<19)
+#define IBS_OP_VAL (1ULL<<18)
+#define IBS_OP_ENABLE (1ULL<<17)
-#define IBS_FETCH_SIZE 6
-#define IBS_OP_SIZE 12
+#define IBS_FETCH_SIZE 6
+#define IBS_OP_SIZE 12
static int has_ibs; /* AMD Family10h and later */
@@ -78,6 +74,45 @@ static struct op_ibs_config ibs_config;
#endif
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+
+static void op_mux_fill_in_addresses(struct op_msrs * const msrs)
+{
+ int i;
+
+ for (i = 0; i < NUM_VIRT_COUNTERS; i++) {
+ int hw_counter = op_x86_virt_to_phys(i);
+ if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
+ msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter;
+ else
+ msrs->multiplex[i].addr = 0;
+ }
+}
+
+static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs)
+{
+ u64 val;
+ int i;
+
+ /* enable active counters */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ int virt = op_x86_phys_to_virt(i);
+ if (!counter_config[virt].enabled)
+ continue;
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= model->reserved;
+ val |= op_x86_get_ctrl(model, &counter_config[virt]);
+ wrmsrl(msrs->controls[i].addr, val);
+ }
+}
+
+#else
+
+static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { }
+
+#endif
+
/* functions for op_amd_spec */
static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
@@ -97,54 +132,56 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
else
msrs->controls[i].addr = 0;
}
-}
+ op_mux_fill_in_addresses(msrs);
+}
-static void op_amd_setup_ctrs(struct op_msrs const * const msrs)
+static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
+ /* setup reset_value */
+ for (i = 0; i < NUM_VIRT_COUNTERS; ++i) {
+ if (counter_config[i].enabled)
+ reset_value[i] = counter_config[i].count;
+ else
+ reset_value[i] = 0;
+ }
+
/* clear all counters */
- for (i = 0 ; i < NUM_CONTROLS; ++i) {
- if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+ for (i = 0; i < NUM_CONTROLS; ++i) {
+ if (unlikely(!msrs->controls[i].addr))
continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR_LO(low);
- CTRL_CLEAR_HI(high);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= model->reserved;
+ wrmsrl(msrs->controls[i].addr, val);
}
/* avoid a false detection of ctr overflows in NMI handler */
for (i = 0; i < NUM_COUNTERS; ++i) {
- if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+ if (unlikely(!msrs->counters[i].addr))
continue;
- CTR_WRITE(1, msrs, i);
+ wrmsrl(msrs->counters[i].addr, -1LL);
}
/* enable active counters */
for (i = 0; i < NUM_COUNTERS; ++i) {
- if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
- reset_value[i] = counter_config[i].count;
+ int virt = op_x86_phys_to_virt(i);
+ if (!counter_config[virt].enabled)
+ continue;
+ if (!msrs->counters[i].addr)
+ continue;
- CTR_WRITE(counter_config[i].count, msrs, i);
-
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR_LO(low);
- CTRL_CLEAR_HI(high);
- CTRL_SET_ENABLE(low);
- CTRL_SET_USR(low, counter_config[i].user);
- CTRL_SET_KERN(low, counter_config[i].kernel);
- CTRL_SET_UM(low, counter_config[i].unit_mask);
- CTRL_SET_EVENT_LOW(low, counter_config[i].event);
- CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
- CTRL_SET_HOST_ONLY(high, 0);
- CTRL_SET_GUEST_ONLY(high, 0);
-
- CTRL_WRITE(low, high, msrs, i);
- } else {
- reset_value[i] = 0;
- }
+ /* setup counter registers */
+ wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
+
+ /* setup control registers */
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= model->reserved;
+ val |= op_x86_get_ctrl(model, &counter_config[virt]);
+ wrmsrl(msrs->controls[i].addr, val);
}
}
@@ -154,93 +191,120 @@ static inline int
op_amd_handle_ibs(struct pt_regs * const regs,
struct op_msrs const * const msrs)
{
- u32 low, high;
- u64 msr;
+ u64 val, ctl;
struct op_entry entry;
if (!has_ibs)
- return 1;
+ return 0;
if (ibs_config.fetch_enabled) {
- rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
- if (high & IBS_FETCH_HIGH_VALID_BIT) {
- rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr);
- oprofile_write_reserve(&entry, regs, msr,
+ rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
+ if (ctl & IBS_FETCH_VAL) {
+ rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
+ oprofile_write_reserve(&entry, regs, val,
IBS_FETCH_CODE, IBS_FETCH_SIZE);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- oprofile_add_data(&entry, low);
- oprofile_add_data(&entry, high);
- rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
+ oprofile_add_data64(&entry, val);
+ oprofile_add_data64(&entry, ctl);
+ rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
+ oprofile_add_data64(&entry, val);
oprofile_write_commit(&entry);
/* reenable the IRQ */
- high &= ~IBS_FETCH_HIGH_VALID_BIT;
- high |= IBS_FETCH_HIGH_ENABLE;
- low &= IBS_FETCH_LOW_MAX_CNT_MASK;
- wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT_MASK);
+ ctl |= IBS_FETCH_ENABLE;
+ wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
}
}
if (ibs_config.op_enabled) {
- rdmsr(MSR_AMD64_IBSOPCTL, low, high);
- if (low & IBS_OP_LOW_VALID_BIT) {
- rdmsrl(MSR_AMD64_IBSOPRIP, msr);
- oprofile_write_reserve(&entry, regs, msr,
+ rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
+ if (ctl & IBS_OP_VAL) {
+ rdmsrl(MSR_AMD64_IBSOPRIP, val);
+ oprofile_write_reserve(&entry, regs, val,
IBS_OP_CODE, IBS_OP_SIZE);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- rdmsrl(MSR_AMD64_IBSOPDATA, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- rdmsrl(MSR_AMD64_IBSOPDATA2, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- rdmsrl(MSR_AMD64_IBSOPDATA3, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- rdmsrl(MSR_AMD64_IBSDCLINAD, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
- rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr);
- oprofile_add_data(&entry, (u32)msr);
- oprofile_add_data(&entry, (u32)(msr >> 32));
+ oprofile_add_data64(&entry, val);
+ rdmsrl(MSR_AMD64_IBSOPDATA, val);
+ oprofile_add_data64(&entry, val);
+ rdmsrl(MSR_AMD64_IBSOPDATA2, val);
+ oprofile_add_data64(&entry, val);
+ rdmsrl(MSR_AMD64_IBSOPDATA3, val);
+ oprofile_add_data64(&entry, val);
+ rdmsrl(MSR_AMD64_IBSDCLINAD, val);
+ oprofile_add_data64(&entry, val);
+ rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
+ oprofile_add_data64(&entry, val);
oprofile_write_commit(&entry);
/* reenable the IRQ */
- high = 0;
- low &= ~IBS_OP_LOW_VALID_BIT;
- low |= IBS_OP_LOW_ENABLE;
- wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+ ctl &= ~IBS_OP_VAL & 0xFFFFFFFF;
+ ctl |= IBS_OP_ENABLE;
+ wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
}
}
return 1;
}
+static inline void op_amd_start_ibs(void)
+{
+ u64 val;
+ if (has_ibs && ibs_config.fetch_enabled) {
+ val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
+ val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
+ val |= IBS_FETCH_ENABLE;
+ wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+ }
+
+ if (has_ibs && ibs_config.op_enabled) {
+ val = (ibs_config.max_cnt_op >> 4) & 0xFFFF;
+ val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
+ val |= IBS_OP_ENABLE;
+ wrmsrl(MSR_AMD64_IBSOPCTL, val);
+ }
+}
+
+static void op_amd_stop_ibs(void)
+{
+ if (has_ibs && ibs_config.fetch_enabled)
+ /* clear max count and enable */
+ wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
+
+ if (has_ibs && ibs_config.op_enabled)
+ /* clear max count and enable */
+ wrmsrl(MSR_AMD64_IBSOPCTL, 0);
+}
+
+#else
+
+static inline int op_amd_handle_ibs(struct pt_regs * const regs,
+ struct op_msrs const * const msrs)
+{
+ return 0;
+}
+static inline void op_amd_start_ibs(void) { }
+static inline void op_amd_stop_ibs(void) { }
+
#endif
static int op_amd_check_ctrs(struct pt_regs * const regs,
struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
- for (i = 0 ; i < NUM_COUNTERS; ++i) {
- if (!reset_value[i])
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ int virt = op_x86_phys_to_virt(i);
+ if (!reset_value[virt])
continue;
- CTR_READ(low, high, msrs, i);
- if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(regs, i);
- CTR_WRITE(reset_value[i], msrs, i);
- }
+ rdmsrl(msrs->counters[i].addr, val);
+ /* bit is clear if overflowed: */
+ if (val & OP_CTR_OVERFLOW)
+ continue;
+ oprofile_add_sample(regs, virt);
+ wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
}
-#ifdef CONFIG_OPROFILE_IBS
op_amd_handle_ibs(regs, msrs);
-#endif
/* See op_model_ppro.c */
return 1;
@@ -248,79 +312,50 @@ static int op_amd_check_ctrs(struct pt_regs * const regs,
static void op_amd_start(struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (reset_value[i]) {
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_ACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
- }
- }
-#ifdef CONFIG_OPROFILE_IBS
- if (has_ibs && ibs_config.fetch_enabled) {
- low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
- high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */
- + IBS_FETCH_HIGH_ENABLE;
- wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (!reset_value[op_x86_phys_to_virt(i)])
+ continue;
+ rdmsrl(msrs->controls[i].addr, val);
+ val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(msrs->controls[i].addr, val);
}
- if (has_ibs && ibs_config.op_enabled) {
- low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF)
- + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */
- + IBS_OP_LOW_ENABLE;
- high = 0;
- wrmsr(MSR_AMD64_IBSOPCTL, low, high);
- }
-#endif
+ op_amd_start_ibs();
}
-
static void op_amd_stop(struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
/*
* Subtle: stop on all counters to avoid race with setting our
* pm callback
*/
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (!reset_value[i])
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (!reset_value[op_x86_phys_to_virt(i)])
continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_INACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(msrs->controls[i].addr, val);
}
-#ifdef CONFIG_OPROFILE_IBS
- if (has_ibs && ibs_config.fetch_enabled) {
- /* clear max count and enable */
- low = 0;
- high = 0;
- wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
- }
-
- if (has_ibs && ibs_config.op_enabled) {
- /* clear max count and enable */
- low = 0;
- high = 0;
- wrmsr(MSR_AMD64_IBSOPCTL, low, high);
- }
-#endif
+ op_amd_stop_ibs();
}
static void op_amd_shutdown(struct op_msrs const * const msrs)
{
int i;
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (CTR_IS_RESERVED(msrs, i))
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (msrs->counters[i].addr)
release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
}
- for (i = 0 ; i < NUM_CONTROLS ; ++i) {
- if (CTRL_IS_RESERVED(msrs, i))
+ for (i = 0; i < NUM_CONTROLS; ++i) {
+ if (msrs->controls[i].addr)
release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
}
}
@@ -490,15 +525,21 @@ static void op_amd_exit(void) {}
#endif /* CONFIG_OPROFILE_IBS */
-struct op_x86_model_spec const op_amd_spec = {
- .init = op_amd_init,
- .exit = op_amd_exit,
+struct op_x86_model_spec op_amd_spec = {
.num_counters = NUM_COUNTERS,
.num_controls = NUM_CONTROLS,
+ .num_virt_counters = NUM_VIRT_COUNTERS,
+ .reserved = MSR_AMD_EVENTSEL_RESERVED,
+ .event_mask = OP_EVENT_MASK,
+ .init = op_amd_init,
+ .exit = op_amd_exit,
.fill_in_addresses = &op_amd_fill_in_addresses,
.setup_ctrs = &op_amd_setup_ctrs,
.check_ctrs = &op_amd_check_ctrs,
.start = &op_amd_start,
.stop = &op_amd_stop,
- .shutdown = &op_amd_shutdown
+ .shutdown = &op_amd_shutdown,
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+ .switch_ctrl = &op_mux_switch_ctrl,
+#endif
};
diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c
index 819b131fd752..ac6b354becdf 100644
--- a/arch/x86/oprofile/op_model_p4.c
+++ b/arch/x86/oprofile/op_model_p4.c
@@ -32,6 +32,8 @@
#define NUM_CCCRS_HT2 9
#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
+#define OP_CTR_OVERFLOW (1ULL<<31)
+
static unsigned int num_counters = NUM_COUNTERS_NON_HT;
static unsigned int num_controls = NUM_CONTROLS_NON_HT;
@@ -350,8 +352,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
#define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
#define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
-#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
-#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
#define CCCR_RESERVED_BITS 0x38030FFF
#define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
@@ -361,17 +361,9 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
#define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
#define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
#define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
-#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
-#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0)
-#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0)
-#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
-
/* this assigns a "stagger" to the current CPU, which is used throughout
the code in this module as an extra array offset, to select the "even"
@@ -515,7 +507,7 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
if (ev->bindings[i].virt_counter & counter_bit) {
/* modify ESCR */
- ESCR_READ(escr, high, ev, i);
+ rdmsr(ev->bindings[i].escr_address, escr, high);
ESCR_CLEAR(escr);
if (stag == 0) {
ESCR_SET_USR_0(escr, counter_config[ctr].user);
@@ -526,10 +518,11 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
}
ESCR_SET_EVENT_SELECT(escr, ev->event_select);
ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
- ESCR_WRITE(escr, high, ev, i);
+ wrmsr(ev->bindings[i].escr_address, escr, high);
/* modify CCCR */
- CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
+ rdmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
+ cccr, high);
CCCR_CLEAR(cccr);
CCCR_SET_REQUIRED_BITS(cccr);
CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
@@ -537,7 +530,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
CCCR_SET_PMI_OVF_0(cccr);
else
CCCR_SET_PMI_OVF_1(cccr);
- CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
+ wrmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
+ cccr, high);
return;
}
}
@@ -548,7 +542,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
}
-static void p4_setup_ctrs(struct op_msrs const * const msrs)
+static void p4_setup_ctrs(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs)
{
unsigned int i;
unsigned int low, high;
@@ -563,8 +558,8 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
}
/* clear the cccrs we will use */
- for (i = 0 ; i < num_counters ; i++) {
- if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+ for (i = 0; i < num_counters; i++) {
+ if (unlikely(!msrs->controls[i].addr))
continue;
rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
CCCR_CLEAR(low);
@@ -574,17 +569,18 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
/* clear all escrs (including those outside our concern) */
for (i = num_counters; i < num_controls; i++) {
- if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+ if (unlikely(!msrs->controls[i].addr))
continue;
wrmsr(msrs->controls[i].addr, 0, 0);
}
/* setup all counters */
- for (i = 0 ; i < num_counters ; ++i) {
- if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) {
+ for (i = 0; i < num_counters; ++i) {
+ if (counter_config[i].enabled && msrs->controls[i].addr) {
reset_value[i] = counter_config[i].count;
pmc_setup_one_p4_counter(i);
- CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
+ wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address,
+ -(u64)counter_config[i].count);
} else {
reset_value[i] = 0;
}
@@ -624,14 +620,16 @@ static int p4_check_ctrs(struct pt_regs * const regs,
real = VIRT_CTR(stag, i);
- CCCR_READ(low, high, real);
- CTR_READ(ctr, high, real);
- if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
+ rdmsr(p4_counters[real].cccr_address, low, high);
+ rdmsr(p4_counters[real].counter_address, ctr, high);
+ if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) {
oprofile_add_sample(regs, i);
- CTR_WRITE(reset_value[i], real);
+ wrmsrl(p4_counters[real].counter_address,
+ -(u64)reset_value[i]);
CCCR_CLEAR_OVF(low);
- CCCR_WRITE(low, high, real);
- CTR_WRITE(reset_value[i], real);
+ wrmsr(p4_counters[real].cccr_address, low, high);
+ wrmsrl(p4_counters[real].counter_address,
+ -(u64)reset_value[i]);
}
}
@@ -653,9 +651,9 @@ static void p4_start(struct op_msrs const * const msrs)
for (i = 0; i < num_counters; ++i) {
if (!reset_value[i])
continue;
- CCCR_READ(low, high, VIRT_CTR(stag, i));
+ rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
CCCR_SET_ENABLE(low);
- CCCR_WRITE(low, high, VIRT_CTR(stag, i));
+ wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
}
}
@@ -670,9 +668,9 @@ static void p4_stop(struct op_msrs const * const msrs)
for (i = 0; i < num_counters; ++i) {
if (!reset_value[i])
continue;
- CCCR_READ(low, high, VIRT_CTR(stag, i));
+ rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
CCCR_SET_DISABLE(low);
- CCCR_WRITE(low, high, VIRT_CTR(stag, i));
+ wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
}
}
@@ -680,8 +678,8 @@ static void p4_shutdown(struct op_msrs const * const msrs)
{
int i;
- for (i = 0 ; i < num_counters ; ++i) {
- if (CTR_IS_RESERVED(msrs, i))
+ for (i = 0; i < num_counters; ++i) {
+ if (msrs->counters[i].addr)
release_perfctr_nmi(msrs->counters[i].addr);
}
/*
@@ -689,15 +687,15 @@ static void p4_shutdown(struct op_msrs const * const msrs)
* conjunction with the counter registers (hence the starting offset).
* This saves a few bits.
*/
- for (i = num_counters ; i < num_controls ; ++i) {
- if (CTRL_IS_RESERVED(msrs, i))
+ for (i = num_counters; i < num_controls; ++i) {
+ if (msrs->controls[i].addr)
release_evntsel_nmi(msrs->controls[i].addr);
}
}
#ifdef CONFIG_SMP
-struct op_x86_model_spec const op_p4_ht2_spec = {
+struct op_x86_model_spec op_p4_ht2_spec = {
.num_counters = NUM_COUNTERS_HT2,
.num_controls = NUM_CONTROLS_HT2,
.fill_in_addresses = &p4_fill_in_addresses,
@@ -709,7 +707,7 @@ struct op_x86_model_spec const op_p4_ht2_spec = {
};
#endif
-struct op_x86_model_spec const op_p4_spec = {
+struct op_x86_model_spec op_p4_spec = {
.num_counters = NUM_COUNTERS_NON_HT,
.num_controls = NUM_CONTROLS_NON_HT,
.fill_in_addresses = &p4_fill_in_addresses,
diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c
index 4da7230b3d17..4899215999de 100644
--- a/arch/x86/oprofile/op_model_ppro.c
+++ b/arch/x86/oprofile/op_model_ppro.c
@@ -10,6 +10,7 @@
* @author Philippe Elie
* @author Graydon Hoare
* @author Andi Kleen
+ * @author Robert Richter <robert.richter@amd.com>
*/
#include <linux/oprofile.h>
@@ -18,7 +19,6 @@
#include <asm/msr.h>
#include <asm/apic.h>
#include <asm/nmi.h>
-#include <asm/perf_counter.h>
#include "op_x86_model.h"
#include "op_counter.h"
@@ -26,20 +26,7 @@
static int num_counters = 2;
static int counter_width = 32;
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1))))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR(x) (x &= (1<<21))
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT(val, e) (val |= e)
+#define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21))
static u64 *reset_value;
@@ -63,9 +50,10 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs)
}
-static void ppro_setup_ctrs(struct op_msrs const * const msrs)
+static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
if (!reset_value) {
@@ -93,36 +81,30 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
}
/* clear all counters */
- for (i = 0 ; i < num_counters; ++i) {
- if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+ for (i = 0; i < num_counters; ++i) {
+ if (unlikely(!msrs->controls[i].addr))
continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR(low);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= model->reserved;
+ wrmsrl(msrs->controls[i].addr, val);
}
/* avoid a false detection of ctr overflows in NMI handler */
for (i = 0; i < num_counters; ++i) {
- if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+ if (unlikely(!msrs->counters[i].addr))
continue;
wrmsrl(msrs->counters[i].addr, -1LL);
}
/* enable active counters */
for (i = 0; i < num_counters; ++i) {
- if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
+ if (counter_config[i].enabled && msrs->counters[i].addr) {
reset_value[i] = counter_config[i].count;
-
wrmsrl(msrs->counters[i].addr, -reset_value[i]);
-
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR(low);
- CTRL_SET_ENABLE(low);
- CTRL_SET_USR(low, counter_config[i].user);
- CTRL_SET_KERN(low, counter_config[i].kernel);
- CTRL_SET_UM(low, counter_config[i].unit_mask);
- CTRL_SET_EVENT(low, counter_config[i].event);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= model->reserved;
+ val |= op_x86_get_ctrl(model, &counter_config[i]);
+ wrmsrl(msrs->controls[i].addr, val);
} else {
reset_value[i] = 0;
}
@@ -143,14 +125,14 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
if (unlikely(!reset_value))
goto out;
- for (i = 0 ; i < num_counters; ++i) {
+ for (i = 0; i < num_counters; ++i) {
if (!reset_value[i])
continue;
rdmsrl(msrs->counters[i].addr, val);
- if (CTR_OVERFLOWED(val)) {
- oprofile_add_sample(regs, i);
- wrmsrl(msrs->counters[i].addr, -reset_value[i]);
- }
+ if (val & (1ULL << (counter_width - 1)))
+ continue;
+ oprofile_add_sample(regs, i);
+ wrmsrl(msrs->counters[i].addr, -reset_value[i]);
}
out:
@@ -171,16 +153,16 @@ out:
static void ppro_start(struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
if (!reset_value)
return;
for (i = 0; i < num_counters; ++i) {
if (reset_value[i]) {
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_ACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(msrs->controls[i].addr, val);
}
}
}
@@ -188,7 +170,7 @@ static void ppro_start(struct op_msrs const * const msrs)
static void ppro_stop(struct op_msrs const * const msrs)
{
- unsigned int low, high;
+ u64 val;
int i;
if (!reset_value)
@@ -196,9 +178,9 @@ static void ppro_stop(struct op_msrs const * const msrs)
for (i = 0; i < num_counters; ++i) {
if (!reset_value[i])
continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_INACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
+ rdmsrl(msrs->controls[i].addr, val);
+ val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(msrs->controls[i].addr, val);
}
}
@@ -206,12 +188,12 @@ static void ppro_shutdown(struct op_msrs const * const msrs)
{
int i;
- for (i = 0 ; i < num_counters ; ++i) {
- if (CTR_IS_RESERVED(msrs, i))
+ for (i = 0; i < num_counters; ++i) {
+ if (msrs->counters[i].addr)
release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
}
- for (i = 0 ; i < num_counters ; ++i) {
- if (CTRL_IS_RESERVED(msrs, i))
+ for (i = 0; i < num_counters; ++i) {
+ if (msrs->controls[i].addr)
release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
}
if (reset_value) {
@@ -222,8 +204,9 @@ static void ppro_shutdown(struct op_msrs const * const msrs)
struct op_x86_model_spec op_ppro_spec = {
- .num_counters = 2, /* can be overriden */
- .num_controls = 2, /* dito */
+ .num_counters = 2,
+ .num_controls = 2,
+ .reserved = MSR_PPRO_EVENTSEL_RESERVED,
.fill_in_addresses = &ppro_fill_in_addresses,
.setup_ctrs = &ppro_setup_ctrs,
.check_ctrs = &ppro_check_ctrs,
@@ -241,7 +224,7 @@ struct op_x86_model_spec op_ppro_spec = {
* the specific CPU.
*/
-void arch_perfmon_setup_counters(void)
+static void arch_perfmon_setup_counters(void)
{
union cpuid10_eax eax;
@@ -259,11 +242,17 @@ void arch_perfmon_setup_counters(void)
op_arch_perfmon_spec.num_counters = num_counters;
op_arch_perfmon_spec.num_controls = num_counters;
- op_ppro_spec.num_counters = num_counters;
- op_ppro_spec.num_controls = num_counters;
+}
+
+static int arch_perfmon_init(struct oprofile_operations *ignore)
+{
+ arch_perfmon_setup_counters();
+ return 0;
}
struct op_x86_model_spec op_arch_perfmon_spec = {
+ .reserved = MSR_PPRO_EVENTSEL_RESERVED,
+ .init = &arch_perfmon_init,
/* num_counters/num_controls filled in at runtime */
.fill_in_addresses = &ppro_fill_in_addresses,
/* user space does the cpuid check for available events */
diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h
index 825e79064d64..b83776180c7f 100644
--- a/arch/x86/oprofile/op_x86_model.h
+++ b/arch/x86/oprofile/op_x86_model.h
@@ -6,51 +6,66 @@
* @remark Read the file COPYING
*
* @author Graydon Hoare
+ * @author Robert Richter <robert.richter@amd.com>
*/
#ifndef OP_X86_MODEL_H
#define OP_X86_MODEL_H
-struct op_saved_msr {
- unsigned int high;
- unsigned int low;
-};
+#include <asm/types.h>
+#include <asm/perf_counter.h>
struct op_msr {
- unsigned long addr;
- struct op_saved_msr saved;
+ unsigned long addr;
+ u64 saved;
};
struct op_msrs {
struct op_msr *counters;
struct op_msr *controls;
+ struct op_msr *multiplex;
};
struct pt_regs;
+struct oprofile_operations;
+
/* The model vtable abstracts the differences between
* various x86 CPU models' perfctr support.
*/
struct op_x86_model_spec {
- int (*init)(struct oprofile_operations *ops);
- void (*exit)(void);
- unsigned int num_counters;
- unsigned int num_controls;
- void (*fill_in_addresses)(struct op_msrs * const msrs);
- void (*setup_ctrs)(struct op_msrs const * const msrs);
- int (*check_ctrs)(struct pt_regs * const regs,
- struct op_msrs const * const msrs);
- void (*start)(struct op_msrs const * const msrs);
- void (*stop)(struct op_msrs const * const msrs);
- void (*shutdown)(struct op_msrs const * const msrs);
+ unsigned int num_counters;
+ unsigned int num_controls;
+ unsigned int num_virt_counters;
+ u64 reserved;
+ u16 event_mask;
+ int (*init)(struct oprofile_operations *ops);
+ void (*exit)(void);
+ void (*fill_in_addresses)(struct op_msrs * const msrs);
+ void (*setup_ctrs)(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs);
+ int (*check_ctrs)(struct pt_regs * const regs,
+ struct op_msrs const * const msrs);
+ void (*start)(struct op_msrs const * const msrs);
+ void (*stop)(struct op_msrs const * const msrs);
+ void (*shutdown)(struct op_msrs const * const msrs);
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+ void (*switch_ctrl)(struct op_x86_model_spec const *model,
+ struct op_msrs const * const msrs);
+#endif
};
+struct op_counter_config;
+
+extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model,
+ struct op_counter_config *counter_config);
+extern int op_x86_phys_to_virt(int phys);
+extern int op_x86_virt_to_phys(int virt);
+
extern struct op_x86_model_spec op_ppro_spec;
-extern struct op_x86_model_spec const op_p4_spec;
-extern struct op_x86_model_spec const op_p4_ht2_spec;
-extern struct op_x86_model_spec const op_amd_spec;
+extern struct op_x86_model_spec op_p4_spec;
+extern struct op_x86_model_spec op_p4_ht2_spec;
+extern struct op_x86_model_spec op_amd_spec;
extern struct op_x86_model_spec op_arch_perfmon_spec;
-extern void arch_perfmon_setup_counters(void);
-
#endif /* OP_X86_MODEL_H */
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 3ffa10df20b9..572ee9782f2a 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -15,63 +15,6 @@
* also get peer root bus resource for io,mmio
*/
-#ifdef CONFIG_NUMA
-
-#define BUS_NR 256
-
-#ifdef CONFIG_X86_64
-
-static int mp_bus_to_node[BUS_NR];
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node = -1;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return node;
-
- node = mp_bus_to_node[busnum];
-
- /*
- * let numa_node_id to decide it later in dma_alloc_pages
- * if there is no ram on that node
- */
- if (node != -1 && !node_online(node))
- node = -1;
-
- return node;
-}
-
-#else /* CONFIG_X86_32 */
-
-static unsigned char mp_bus_to_node[BUS_NR];
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = (unsigned char) node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return 0;
- node = mp_bus_to_node[busnum];
- return node;
-}
-
-#endif /* CONFIG_X86_32 */
-
-#endif /* CONFIG_NUMA */
-
#ifdef CONFIG_X86_64
/*
@@ -301,11 +244,6 @@ static int __init early_fill_mp_bus_info(void)
u64 val;
u32 address;
-#ifdef CONFIG_NUMA
- for (i = 0; i < BUS_NR; i++)
- mp_bus_to_node[i] = -1;
-#endif
-
if (!early_pci_allowed())
return -1;
@@ -346,7 +284,7 @@ static int __init early_fill_mp_bus_info(void)
node = (reg >> 4) & 0x07;
#ifdef CONFIG_NUMA
for (j = min_bus; j <= max_bus; j++)
- mp_bus_to_node[j] = (unsigned char) node;
+ set_mp_bus_to_node(j, node);
#endif
link = (reg >> 8) & 0x03;
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 2202b6257b82..5db96d4304de 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -600,3 +600,72 @@ struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno)
{
return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
}
+
+/*
+ * NUMA info for PCI busses
+ *
+ * Early arch code is responsible for filling in reasonable values here.
+ * A node id of "-1" means "use current node". In other words, if a bus
+ * has a -1 node id, it's not tightly coupled to any particular chunk
+ * of memory (as is the case on some Nehalem systems).
+ */
+#ifdef CONFIG_NUMA
+
+#define BUS_NR 256
+
+#ifdef CONFIG_X86_64
+
+static int mp_bus_to_node[BUS_NR] = {
+ [0 ... BUS_NR - 1] = -1
+};
+
+void set_mp_bus_to_node(int busnum, int node)
+{
+ if (busnum >= 0 && busnum < BUS_NR)
+ mp_bus_to_node[busnum] = node;
+}
+
+int get_mp_bus_to_node(int busnum)
+{
+ int node = -1;
+
+ if (busnum < 0 || busnum > (BUS_NR - 1))
+ return node;
+
+ node = mp_bus_to_node[busnum];
+
+ /*
+ * let numa_node_id to decide it later in dma_alloc_pages
+ * if there is no ram on that node
+ */
+ if (node != -1 && !node_online(node))
+ node = -1;
+
+ return node;
+}
+
+#else /* CONFIG_X86_32 */
+
+static unsigned char mp_bus_to_node[BUS_NR] = {
+ [0 ... BUS_NR - 1] = -1
+};
+
+void set_mp_bus_to_node(int busnum, int node)
+{
+ if (busnum >= 0 && busnum < BUS_NR)
+ mp_bus_to_node[busnum] = (unsigned char) node;
+}
+
+int get_mp_bus_to_node(int busnum)
+{
+ int node;
+
+ if (busnum < 0 || busnum > (BUS_NR - 1))
+ return 0;
+ node = mp_bus_to_node[busnum];
+ return node;
+}
+
+#endif /* CONFIG_X86_32 */
+
+#endif /* CONFIG_NUMA */
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 4ceb28581652..6fa64cb1b01e 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1165,14 +1165,14 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
/* Get the "official" set of cpus referring to our pagetable. */
if (!alloc_cpumask_var(&mask, GFP_ATOMIC)) {
for_each_online_cpu(cpu) {
- if (!cpumask_test_cpu(cpu, &mm->cpu_vm_mask)
+ if (!cpumask_test_cpu(cpu, mm_cpumask(mm))
&& per_cpu(xen_current_cr3, cpu) != __pa(mm->pgd))
continue;
smp_call_function_single(cpu, drop_other_mm_ref, mm, 1);
}
return;
}
- cpumask_copy(mask, &mm->cpu_vm_mask);
+ cpumask_copy(mask, mm_cpumask(mm));
/* It's possible that a vcpu may have a stale reference to our
cr3, because its in lazy mode, and it hasn't yet flushed
diff --git a/arch/xtensa/include/asm/tlb.h b/arch/xtensa/include/asm/tlb.h
index 31c220faca02..0d766f9c1083 100644
--- a/arch/xtensa/include/asm/tlb.h
+++ b/arch/xtensa/include/asm/tlb.h
@@ -42,6 +42,6 @@
#include <asm-generic/tlb.h>
-#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
+#define __pte_free_tlb(tlb, pte, address) pte_free((tlb)->mm, pte)
#endif /* _XTENSA_TLB_H */
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index 41c159cd872f..921b6ff3b645 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -280,15 +280,6 @@ SECTIONS
*(.ResetVector.text)
}
- /* Sections to be discarded */
- /DISCARD/ :
- {
- *(.exit.literal)
- EXIT_TEXT
- EXIT_DATA
- *(.exitcall.exit)
- }
-
.xt.lit : { *(.xt.lit) }
.xt.prop : { *(.xt.prop) }
@@ -321,4 +312,8 @@ SECTIONS
*(.xt.lit)
*(.gnu.linkonce.p*)
}
+
+ /* Sections to be discarded */
+ DISCARDS
+ /DISCARD/ : { *(.exit.literal) }
}
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index edad4156d89a..2f0b86b37cf9 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -545,7 +545,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 7a12cf6ee1d3..ce8ba57c6557 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -146,7 +146,7 @@ enum arq_state {
#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, ioc_count);
+static DEFINE_PER_CPU(unsigned long, as_ioc_count);
static struct completion *ioc_gone;
static DEFINE_SPINLOCK(ioc_gone_lock);
@@ -161,7 +161,7 @@ static void as_antic_stop(struct as_data *ad);
static void free_as_io_context(struct as_io_context *aic)
{
kfree(aic);
- elv_ioc_count_dec(ioc_count);
+ elv_ioc_count_dec(as_ioc_count);
if (ioc_gone) {
/*
* AS scheduler is exiting, grab exit lock and check
@@ -169,7 +169,7 @@ static void free_as_io_context(struct as_io_context *aic)
* complete ioc_gone and set it back to NULL.
*/
spin_lock(&ioc_gone_lock);
- if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+ if (ioc_gone && !elv_ioc_count_read(as_ioc_count)) {
complete(ioc_gone);
ioc_gone = NULL;
}
@@ -211,7 +211,7 @@ static struct as_io_context *alloc_as_io_context(void)
ret->seek_total = 0;
ret->seek_samples = 0;
ret->seek_mean = 0;
- elv_ioc_count_inc(ioc_count);
+ elv_ioc_count_inc(as_ioc_count);
}
return ret;
@@ -1507,7 +1507,7 @@ static void __exit as_exit(void)
ioc_gone = &all_gone;
/* ioc_gone's update must be visible before reading ioc_count */
smp_wmb();
- if (elv_ioc_count_read(ioc_count))
+ if (elv_ioc_count_read(as_ioc_count))
wait_for_completion(&all_gone);
synchronize_rcu();
}
diff --git a/block/blk-core.c b/block/blk-core.c
index 4b45435c6eaf..754e7e1c23bc 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -501,6 +501,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
q->backing_dev_info.state = 0;
q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
+ q->backing_dev_info.name = "block";
err = bdi_init(&q->backing_dev_info);
if (err) {
@@ -575,13 +576,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
return NULL;
}
- /*
- * if caller didn't supply a lock, they get per-queue locking with
- * our embedded lock
- */
- if (!lock)
- lock = &q->__queue_lock;
-
q->request_fn = rfn;
q->prep_rq_fn = NULL;
q->unplug_fn = generic_unplug_device;
@@ -1118,31 +1112,27 @@ void init_request_from_bio(struct request *req, struct bio *bio)
req->cmd_type = REQ_TYPE_FS;
/*
- * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
+ * Inherit FAILFAST from bio (for read-ahead, and explicit
+ * FAILFAST). FAILFAST flags are identical for req and bio.
*/
- if (bio_rw_ahead(bio))
- req->cmd_flags |= (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER);
- if (bio_failfast_dev(bio))
- req->cmd_flags |= REQ_FAILFAST_DEV;
- if (bio_failfast_transport(bio))
- req->cmd_flags |= REQ_FAILFAST_TRANSPORT;
- if (bio_failfast_driver(bio))
- req->cmd_flags |= REQ_FAILFAST_DRIVER;
-
- if (unlikely(bio_discard(bio))) {
+ if (bio_rw_flagged(bio, BIO_RW_AHEAD))
+ req->cmd_flags |= REQ_FAILFAST_MASK;
+ else
+ req->cmd_flags |= bio->bi_rw & REQ_FAILFAST_MASK;
+
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) {
req->cmd_flags |= REQ_DISCARD;
- if (bio_barrier(bio))
+ if (bio_rw_flagged(bio, BIO_RW_BARRIER))
req->cmd_flags |= REQ_SOFTBARRIER;
req->q->prepare_discard_fn(req->q, req);
- } else if (unlikely(bio_barrier(bio)))
+ } else if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER)))
req->cmd_flags |= REQ_HARDBARRIER;
- if (bio_sync(bio))
+ if (bio_rw_flagged(bio, BIO_RW_SYNCIO))
req->cmd_flags |= REQ_RW_SYNC;
- if (bio_rw_meta(bio))
+ if (bio_rw_flagged(bio, BIO_RW_META))
req->cmd_flags |= REQ_RW_META;
- if (bio_noidle(bio))
+ if (bio_rw_flagged(bio, BIO_RW_NOIDLE))
req->cmd_flags |= REQ_NOIDLE;
req->errors = 0;
@@ -1166,11 +1156,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
int el_ret;
unsigned int bytes = bio->bi_size;
const unsigned short prio = bio_prio(bio);
- const int sync = bio_sync(bio);
- const int unplug = bio_unplug(bio);
+ const bool sync = bio_rw_flagged(bio, BIO_RW_SYNCIO);
+ const bool unplug = bio_rw_flagged(bio, BIO_RW_UNPLUG);
+ const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK;
int rw_flags;
- if (bio_barrier(bio) && bio_has_data(bio) &&
+ if (bio_rw_flagged(bio, BIO_RW_BARRIER) && bio_has_data(bio) &&
(q->next_ordered == QUEUE_ORDERED_NONE)) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
@@ -1184,7 +1175,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
spin_lock_irq(q->queue_lock);
- if (unlikely(bio_barrier(bio)) || elv_queue_empty(q))
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER)) || elv_queue_empty(q))
goto get_rq;
el_ret = elv_merge(q, &req, bio);
@@ -1197,6 +1188,9 @@ static int __make_request(struct request_queue *q, struct bio *bio)
trace_block_bio_backmerge(q, bio);
+ if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
+ blk_rq_set_mixed_merge(req);
+
req->biotail->bi_next = bio;
req->biotail = bio;
req->__data_len += bytes;
@@ -1216,6 +1210,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
trace_block_bio_frontmerge(q, bio);
+ if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) {
+ blk_rq_set_mixed_merge(req);
+ req->cmd_flags &= ~REQ_FAILFAST_MASK;
+ req->cmd_flags |= ff;
+ }
+
bio->bi_next = req->bio;
req->bio = bio;
@@ -1471,7 +1471,8 @@ static inline void __generic_make_request(struct bio *bio)
if (bio_check_eod(bio, nr_sectors))
goto end_io;
- if (bio_discard(bio) && !q->prepare_discard_fn) {
+ if (bio_rw_flagged(bio, BIO_RW_DISCARD) &&
+ !q->prepare_discard_fn) {
err = -EOPNOTSUPP;
goto end_io;
}
@@ -1660,6 +1661,50 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
}
EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
+/**
+ * blk_rq_err_bytes - determine number of bytes till the next failure boundary
+ * @rq: request to examine
+ *
+ * Description:
+ * A request could be merge of IOs which require different failure
+ * handling. This function determines the number of bytes which
+ * can be failed from the beginning of the request without
+ * crossing into area which need to be retried further.
+ *
+ * Return:
+ * The number of bytes to fail.
+ *
+ * Context:
+ * queue_lock must be held.
+ */
+unsigned int blk_rq_err_bytes(const struct request *rq)
+{
+ unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+ unsigned int bytes = 0;
+ struct bio *bio;
+
+ if (!(rq->cmd_flags & REQ_MIXED_MERGE))
+ return blk_rq_bytes(rq);
+
+ /*
+ * Currently the only 'mixing' which can happen is between
+ * different fastfail types. We can safely fail portions
+ * which have all the failfast bits that the first one has -
+ * the ones which are at least as eager to fail as the first
+ * one.
+ */
+ for (bio = rq->bio; bio; bio = bio->bi_next) {
+ if ((bio->bi_rw & ff) != ff)
+ break;
+ bytes += bio->bi_size;
+ }
+
+ /* this could lead to infinite loop */
+ BUG_ON(blk_rq_bytes(rq) && !bytes);
+ return bytes;
+}
+EXPORT_SYMBOL_GPL(blk_rq_err_bytes);
+
static void blk_account_io_completion(struct request *req, unsigned int bytes)
{
if (blk_do_io_stat(req)) {
@@ -2006,6 +2051,12 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
if (blk_fs_request(req) || blk_discard_rq(req))
req->__sector += total_bytes >> 9;
+ /* mixed attributes always follow the first bio */
+ if (req->cmd_flags & REQ_MIXED_MERGE) {
+ req->cmd_flags &= ~REQ_FAILFAST_MASK;
+ req->cmd_flags |= req->bio->bi_rw & REQ_FAILFAST_MASK;
+ }
+
/*
* If total number of sectors is less than the first segment
* size, something has gone terribly wrong.
@@ -2143,7 +2194,7 @@ bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
{
return blk_end_bidi_request(rq, error, nr_bytes, 0);
}
-EXPORT_SYMBOL_GPL(blk_end_request);
+EXPORT_SYMBOL(blk_end_request);
/**
* blk_end_request_all - Helper function for drives to finish the request.
@@ -2164,7 +2215,7 @@ void blk_end_request_all(struct request *rq, int error)
pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes);
BUG_ON(pending);
}
-EXPORT_SYMBOL_GPL(blk_end_request_all);
+EXPORT_SYMBOL(blk_end_request_all);
/**
* blk_end_request_cur - Helper function to finish the current request chunk.
@@ -2182,7 +2233,26 @@ bool blk_end_request_cur(struct request *rq, int error)
{
return blk_end_request(rq, error, blk_rq_cur_bytes(rq));
}
-EXPORT_SYMBOL_GPL(blk_end_request_cur);
+EXPORT_SYMBOL(blk_end_request_cur);
+
+/**
+ * blk_end_request_err - Finish a request till the next failure boundary.
+ * @rq: the request to finish till the next failure boundary for
+ * @error: must be negative errno
+ *
+ * Description:
+ * Complete @rq till the next failure boundary.
+ *
+ * Return:
+ * %false - we are done with this request
+ * %true - still buffers pending for this request
+ */
+bool blk_end_request_err(struct request *rq, int error)
+{
+ WARN_ON(error >= 0);
+ return blk_end_request(rq, error, blk_rq_err_bytes(rq));
+}
+EXPORT_SYMBOL_GPL(blk_end_request_err);
/**
* __blk_end_request - Helper function for drivers to complete the request.
@@ -2201,7 +2271,7 @@ bool __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
{
return __blk_end_bidi_request(rq, error, nr_bytes, 0);
}
-EXPORT_SYMBOL_GPL(__blk_end_request);
+EXPORT_SYMBOL(__blk_end_request);
/**
* __blk_end_request_all - Helper function for drives to finish the request.
@@ -2222,7 +2292,7 @@ void __blk_end_request_all(struct request *rq, int error)
pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes);
BUG_ON(pending);
}
-EXPORT_SYMBOL_GPL(__blk_end_request_all);
+EXPORT_SYMBOL(__blk_end_request_all);
/**
* __blk_end_request_cur - Helper function to finish the current request chunk.
@@ -2241,14 +2311,33 @@ bool __blk_end_request_cur(struct request *rq, int error)
{
return __blk_end_request(rq, error, blk_rq_cur_bytes(rq));
}
-EXPORT_SYMBOL_GPL(__blk_end_request_cur);
+EXPORT_SYMBOL(__blk_end_request_cur);
+
+/**
+ * __blk_end_request_err - Finish a request till the next failure boundary.
+ * @rq: the request to finish till the next failure boundary for
+ * @error: must be negative errno
+ *
+ * Description:
+ * Complete @rq till the next failure boundary. Must be called
+ * with queue lock held.
+ *
+ * Return:
+ * %false - we are done with this request
+ * %true - still buffers pending for this request
+ */
+bool __blk_end_request_err(struct request *rq, int error)
+{
+ WARN_ON(error >= 0);
+ return __blk_end_request(rq, error, blk_rq_err_bytes(rq));
+}
+EXPORT_SYMBOL_GPL(__blk_end_request_err);
void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
struct bio *bio)
{
- /* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw, and
- we want BIO_RW_AHEAD (bit 1) to imply REQ_FAILFAST (bit 1). */
- rq->cmd_flags |= (bio->bi_rw & 3);
+ /* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw */
+ rq->cmd_flags |= bio->bi_rw & REQ_RW;
if (bio_has_data(bio)) {
rq->nr_phys_segments = bio_phys_segments(q, bio);
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 73e28d355688..15c630813b1c 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -379,6 +379,7 @@ void blk_integrity_unregister(struct gendisk *disk)
kobject_uevent(&bi->kobj, KOBJ_REMOVE);
kobject_del(&bi->kobj);
+ kobject_put(&bi->kobj);
kmem_cache_free(integrity_cachep, bi);
disk->integrity = NULL;
}
diff --git a/block/blk-merge.c b/block/blk-merge.c
index e1999679a4d5..b0de8574fdc8 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -311,6 +311,36 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
return 1;
}
+/**
+ * blk_rq_set_mixed_merge - mark a request as mixed merge
+ * @rq: request to mark as mixed merge
+ *
+ * Description:
+ * @rq is about to be mixed merged. Make sure the attributes
+ * which can be mixed are set in each bio and mark @rq as mixed
+ * merged.
+ */
+void blk_rq_set_mixed_merge(struct request *rq)
+{
+ unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+ struct bio *bio;
+
+ if (rq->cmd_flags & REQ_MIXED_MERGE)
+ return;
+
+ /*
+ * @rq will no longer represent mixable attributes for all the
+ * contained bios. It will just track those of the first one.
+ * Distributes the attributs to each bio.
+ */
+ for (bio = rq->bio; bio; bio = bio->bi_next) {
+ WARN_ON_ONCE((bio->bi_rw & REQ_FAILFAST_MASK) &&
+ (bio->bi_rw & REQ_FAILFAST_MASK) != ff);
+ bio->bi_rw |= ff;
+ }
+ rq->cmd_flags |= REQ_MIXED_MERGE;
+}
+
static void blk_account_io_merge(struct request *req)
{
if (blk_do_io_stat(req)) {
@@ -350,12 +380,6 @@ static int attempt_merge(struct request_queue *q, struct request *req,
if (blk_integrity_rq(req) != blk_integrity_rq(next))
return 0;
- /* don't merge requests of different failfast settings */
- if (blk_failfast_dev(req) != blk_failfast_dev(next) ||
- blk_failfast_transport(req) != blk_failfast_transport(next) ||
- blk_failfast_driver(req) != blk_failfast_driver(next))
- return 0;
-
/*
* If we are allowed to merge, then append bio list
* from next to rq and release next. merge_requests_fn
@@ -366,6 +390,19 @@ static int attempt_merge(struct request_queue *q, struct request *req,
return 0;
/*
+ * If failfast settings disagree or any of the two is already
+ * a mixed merge, mark both as mixed before proceeding. This
+ * makes sure that all involved bios have mixable attributes
+ * set properly.
+ */
+ if ((req->cmd_flags | next->cmd_flags) & REQ_MIXED_MERGE ||
+ (req->cmd_flags & REQ_FAILFAST_MASK) !=
+ (next->cmd_flags & REQ_FAILFAST_MASK)) {
+ blk_rq_set_mixed_merge(req);
+ blk_rq_set_mixed_merge(next);
+ }
+
+ /*
* At this point we have either done a back merge
* or front merge. We need the smaller start_time of
* the merged requests to be the current request
diff --git a/block/blk-settings.c b/block/blk-settings.c
index bd582a7f5310..27e57cb796ae 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -7,6 +7,7 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/bootmem.h> /* for max_pfn/max_low_pfn */
+#include <linux/gcd.h>
#include "blk.h"
@@ -165,6 +166,13 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
blk_set_default_limits(&q->limits);
/*
+ * If the caller didn't supply a lock, fall back to our embedded
+ * per-queue locks
+ */
+ if (!q->queue_lock)
+ q->queue_lock = &q->__queue_lock;
+
+ /*
* by default assume old behaviour and bounce for any highmem page
*/
blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
@@ -377,8 +385,8 @@ void blk_queue_alignment_offset(struct request_queue *q, unsigned int offset)
EXPORT_SYMBOL(blk_queue_alignment_offset);
/**
- * blk_queue_io_min - set minimum request size for the queue
- * @q: the request queue for the device
+ * blk_limits_io_min - set minimum request size for a device
+ * @limits: the queue limits
* @min: smallest I/O size in bytes
*
* Description:
@@ -387,15 +395,35 @@ EXPORT_SYMBOL(blk_queue_alignment_offset);
* smallest I/O the device can perform without incurring a performance
* penalty.
*/
-void blk_queue_io_min(struct request_queue *q, unsigned int min)
+void blk_limits_io_min(struct queue_limits *limits, unsigned int min)
{
- q->limits.io_min = min;
+ limits->io_min = min;
- if (q->limits.io_min < q->limits.logical_block_size)
- q->limits.io_min = q->limits.logical_block_size;
+ if (limits->io_min < limits->logical_block_size)
+ limits->io_min = limits->logical_block_size;
- if (q->limits.io_min < q->limits.physical_block_size)
- q->limits.io_min = q->limits.physical_block_size;
+ if (limits->io_min < limits->physical_block_size)
+ limits->io_min = limits->physical_block_size;
+}
+EXPORT_SYMBOL(blk_limits_io_min);
+
+/**
+ * blk_queue_io_min - set minimum request size for the queue
+ * @q: the request queue for the device
+ * @min: smallest I/O size in bytes
+ *
+ * Description:
+ * Storage devices may report a granularity or preferred minimum I/O
+ * size which is the smallest request the device can perform without
+ * incurring a performance penalty. For disk drives this is often the
+ * physical block size. For RAID arrays it is often the stripe chunk
+ * size. A properly aligned multiple of minimum_io_size is the
+ * preferred request size for workloads where a high number of I/O
+ * operations is desired.
+ */
+void blk_queue_io_min(struct request_queue *q, unsigned int min)
+{
+ blk_limits_io_min(&q->limits, min);
}
EXPORT_SYMBOL(blk_queue_io_min);
@@ -405,8 +433,12 @@ EXPORT_SYMBOL(blk_queue_io_min);
* @opt: optimal request size in bytes
*
* Description:
- * Drivers can call this function to set the preferred I/O request
- * size for devices that report such a value.
+ * Storage devices may report an optimal I/O size, which is the
+ * device's preferred unit for sustained I/O. This is rarely reported
+ * for disk drives. For RAID arrays it is usually the stripe width or
+ * the internal track size. A properly aligned multiple of
+ * optimal_io_size is the preferred request size for workloads where
+ * sustained throughput is desired.
*/
void blk_queue_io_opt(struct request_queue *q, unsigned int opt)
{
@@ -420,46 +452,6 @@ EXPORT_SYMBOL(blk_queue_io_opt);
#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
/**
- * blk_queue_stack_limits - inherit underlying queue limits for stacked drivers
- * @t: the stacking driver (top)
- * @b: the underlying device (bottom)
- **/
-void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
-{
- /* zero is "infinity" */
- t->limits.max_sectors = min_not_zero(queue_max_sectors(t),
- queue_max_sectors(b));
-
- t->limits.max_hw_sectors = min_not_zero(queue_max_hw_sectors(t),
- queue_max_hw_sectors(b));
-
- t->limits.seg_boundary_mask = min_not_zero(queue_segment_boundary(t),
- queue_segment_boundary(b));
-
- t->limits.max_phys_segments = min_not_zero(queue_max_phys_segments(t),
- queue_max_phys_segments(b));
-
- t->limits.max_hw_segments = min_not_zero(queue_max_hw_segments(t),
- queue_max_hw_segments(b));
-
- t->limits.max_segment_size = min_not_zero(queue_max_segment_size(t),
- queue_max_segment_size(b));
-
- t->limits.logical_block_size = max(queue_logical_block_size(t),
- queue_logical_block_size(b));
-
- if (!t->queue_lock)
- WARN_ON_ONCE(1);
- else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
- unsigned long flags;
- spin_lock_irqsave(t->queue_lock, flags);
- queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
- spin_unlock_irqrestore(t->queue_lock, flags);
- }
-}
-EXPORT_SYMBOL(blk_queue_stack_limits);
-
-/**
* blk_stack_limits - adjust queue_limits for stacked devices
* @t: the stacking driver limits (top)
* @b: the underlying queue limits (bottom)
@@ -516,6 +508,16 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
return -1;
}
+ /* Find lcm() of optimal I/O size */
+ if (t->io_opt && b->io_opt)
+ t->io_opt = (t->io_opt * b->io_opt) / gcd(t->io_opt, b->io_opt);
+ else if (b->io_opt)
+ t->io_opt = b->io_opt;
+
+ /* Verify that optimal I/O size is a multiple of io_min */
+ if (t->io_min && t->io_opt % t->io_min)
+ return -1;
+
return 0;
}
EXPORT_SYMBOL(blk_stack_limits);
diff --git a/block/blk.h b/block/blk.h
index 3fae6add5430..5ee3d7e72feb 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -104,6 +104,7 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
int attempt_back_merge(struct request_queue *q, struct request *rq);
int attempt_front_merge(struct request_queue *q, struct request *rq);
void blk_recalc_rq_segments(struct request *rq);
+void blk_rq_set_mixed_merge(struct request *rq);
void blk_queue_congestion_threshold(struct request_queue *q);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index fd7080ed7935..ca315f8baa51 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -48,7 +48,7 @@ static int cfq_slice_idle = HZ / 125;
static struct kmem_cache *cfq_pool;
static struct kmem_cache *cfq_ioc_pool;
-static DEFINE_PER_CPU(unsigned long, ioc_count);
+static DEFINE_PER_CPU(unsigned long, cfq_ioc_count);
static struct completion *ioc_gone;
static DEFINE_SPINLOCK(ioc_gone_lock);
@@ -134,13 +134,8 @@ struct cfq_data {
struct rb_root prio_trees[CFQ_PRIO_LISTS];
unsigned int busy_queues;
- /*
- * Used to track any pending rt requests so we can pre-empt current
- * non-RT cfqq in service when this value is non-zero.
- */
- unsigned int busy_rt_queues;
- int rq_in_driver;
+ int rq_in_driver[2];
int sync_flight;
/*
@@ -239,6 +234,11 @@ static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
struct io_context *);
+static inline int rq_in_driver(struct cfq_data *cfqd)
+{
+ return cfqd->rq_in_driver[0] + cfqd->rq_in_driver[1];
+}
+
static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
int is_sync)
{
@@ -257,7 +257,7 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic,
*/
static inline int cfq_bio_sync(struct bio *bio)
{
- if (bio_data_dir(bio) == READ || bio_sync(bio))
+ if (bio_data_dir(bio) == READ || bio_rw_flagged(bio, BIO_RW_SYNCIO))
return 1;
return 0;
@@ -648,8 +648,6 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
BUG_ON(cfq_cfqq_on_rr(cfqq));
cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- if (cfq_class_rt(cfqq))
- cfqd->busy_rt_queues++;
cfq_resort_rr_list(cfqd, cfqq);
}
@@ -673,8 +671,6 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
- if (cfq_class_rt(cfqq))
- cfqd->busy_rt_queues--;
}
/*
@@ -760,9 +756,9 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- cfqd->rq_in_driver++;
+ cfqd->rq_in_driver[rq_is_sync(rq)]++;
cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
- cfqd->rq_in_driver);
+ rq_in_driver(cfqd));
cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq);
}
@@ -770,11 +766,12 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
static void cfq_deactivate_request(struct request_queue *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
+ const int sync = rq_is_sync(rq);
- WARN_ON(!cfqd->rq_in_driver);
- cfqd->rq_in_driver--;
+ WARN_ON(!cfqd->rq_in_driver[sync]);
+ cfqd->rq_in_driver[sync]--;
cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d",
- cfqd->rq_in_driver);
+ rq_in_driver(cfqd));
}
static void cfq_remove_request(struct request *rq)
@@ -1080,7 +1077,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
/*
* still requests with the driver, don't idle
*/
- if (cfqd->rq_in_driver)
+ if (rq_in_driver(cfqd))
return;
/*
@@ -1179,20 +1176,6 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
goto expire;
/*
- * If we have a RT cfqq waiting, then we pre-empt the current non-rt
- * cfqq.
- */
- if (!cfq_class_rt(cfqq) && cfqd->busy_rt_queues) {
- /*
- * We simulate this as cfqq timed out so that it gets to bank
- * the remaining of its time slice.
- */
- cfq_log_cfqq(cfqd, cfqq, "preempt");
- cfq_slice_expired(cfqd, 1);
- goto new_queue;
- }
-
- /*
* The active queue has requests and isn't expired, allow it to
* dispatch.
*/
@@ -1312,6 +1295,12 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
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;
+
+ /*
* If this is an async queue and we have sync IO in flight, let it wait
*/
if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
@@ -1427,7 +1416,7 @@ static void cfq_cic_free_rcu(struct rcu_head *head)
cic = container_of(head, struct cfq_io_context, rcu_head);
kmem_cache_free(cfq_ioc_pool, cic);
- elv_ioc_count_dec(ioc_count);
+ elv_ioc_count_dec(cfq_ioc_count);
if (ioc_gone) {
/*
@@ -1436,7 +1425,7 @@ static void cfq_cic_free_rcu(struct rcu_head *head)
* complete ioc_gone and set it back to NULL
*/
spin_lock(&ioc_gone_lock);
- if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+ if (ioc_gone && !elv_ioc_count_read(cfq_ioc_count)) {
complete(ioc_gone);
ioc_gone = NULL;
}
@@ -1562,7 +1551,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
INIT_HLIST_NODE(&cic->cic_list);
cic->dtor = cfq_free_io_context;
cic->exit = cfq_exit_io_context;
- elv_ioc_count_inc(ioc_count);
+ elv_ioc_count_inc(cfq_ioc_count);
}
return cic;
@@ -2130,11 +2119,11 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
*/
static void cfq_update_hw_tag(struct cfq_data *cfqd)
{
- if (cfqd->rq_in_driver > cfqd->rq_in_driver_peak)
- cfqd->rq_in_driver_peak = cfqd->rq_in_driver;
+ if (rq_in_driver(cfqd) > cfqd->rq_in_driver_peak)
+ cfqd->rq_in_driver_peak = rq_in_driver(cfqd);
if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
- cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN)
+ rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN)
return;
if (cfqd->hw_tag_samples++ < 50)
@@ -2161,9 +2150,9 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
cfq_update_hw_tag(cfqd);
- WARN_ON(!cfqd->rq_in_driver);
+ WARN_ON(!cfqd->rq_in_driver[sync]);
WARN_ON(!cfqq->dispatched);
- cfqd->rq_in_driver--;
+ cfqd->rq_in_driver[sync]--;
cfqq->dispatched--;
if (cfq_cfqq_sync(cfqq))
@@ -2197,7 +2186,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
cfq_arm_slice_timer(cfqd);
}
- if (!cfqd->rq_in_driver)
+ if (!rq_in_driver(cfqd))
cfq_schedule_dispatch(cfqd);
}
@@ -2668,7 +2657,7 @@ static void __exit cfq_exit(void)
* this also protects us from entering cfq_slab_kill() with
* pending RCU callbacks
*/
- if (elv_ioc_count_read(ioc_count))
+ if (elv_ioc_count_read(cfq_ioc_count))
wait_for_completion(&all_gone);
cfq_slab_kill();
}
diff --git a/block/elevator.c b/block/elevator.c
index 2d511f9105e1..51bb66236ebb 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -79,7 +79,8 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
/*
* Don't merge file system requests and discard requests
*/
- if (bio_discard(bio) != bio_discard(rq->bio))
+ if (bio_rw_flagged(bio, BIO_RW_DISCARD) !=
+ bio_rw_flagged(rq->bio, BIO_RW_DISCARD))
return 0;
/*
@@ -101,16 +102,11 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
return 0;
/*
- * Don't merge if failfast settings don't match.
- *
- * FIXME: The negation in front of each condition is necessary
- * because bio and request flags use different bit positions
- * and the accessors return those bits directly. This
- * ugliness will soon go away.
+ * Don't merge if failfast settings don't match. Just check the
+ * first four bits, they have identical mappings in the bio->bi_rw
+ * and rq->cmd_flags bits.
*/
- if (!bio_failfast_dev(bio) != !blk_failfast_dev(rq) ||
- !bio_failfast_transport(bio) != !blk_failfast_transport(rq) ||
- !bio_failfast_driver(bio) != !blk_failfast_driver(rq))
+ if ((bio->bi_rw & BIO_RW_RQ_MASK) != (rq->cmd_flags & BIO_RW_RQ_MASK))
return 0;
if (!elv_iosched_allow_merge(rq, bio))
diff --git a/block/genhd.c b/block/genhd.c
index f4c64c2b303a..b89328eceee2 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1215,6 +1215,16 @@ void put_disk(struct gendisk *disk)
EXPORT_SYMBOL(put_disk);
+static void set_disk_ro_uevent(struct gendisk *gd, int ro)
+{
+ char event[] = "DISK_RO=1";
+ char *envp[] = { event, NULL };
+
+ if (!ro)
+ event[8] = '0';
+ kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
+}
+
void set_device_ro(struct block_device *bdev, int flag)
{
bdev->bd_part->policy = flag;
@@ -1227,8 +1237,12 @@ void set_disk_ro(struct gendisk *disk, int flag)
struct disk_part_iter piter;
struct hd_struct *part;
- disk_part_iter_init(&piter, disk,
- DISK_PITER_INCL_EMPTY | DISK_PITER_INCL_PART0);
+ if (disk->part0.policy != flag) {
+ set_disk_ro_uevent(disk, flag);
+ disk->part0.policy = flag;
+ }
+
+ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
while ((part = disk_part_iter_next(&piter)))
part->policy = flag;
disk_part_iter_exit(&piter);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 4dfdd03e708f..f2002d8e5f67 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -23,6 +23,7 @@ comment "Crypto core or helper"
config CRYPTO_FIPS
bool "FIPS 200 compliance"
+ select CRYPTO_ANSI_CPRNG
help
This options enables the fips boot option which is
required if you want to system to operate in a FIPS 200
@@ -782,7 +783,6 @@ config CRYPTO_ANSI_CPRNG
tristate "Pseudo Random Number Generation for Cryptographic modules"
select CRYPTO_AES
select CRYPTO_RNG
- select CRYPTO_FIPS
help
This option enables the generic pseudo random number generator
for cryptographic modules. Uses the Algorithm specified in
diff --git a/crypto/Makefile b/crypto/Makefile
index 673d9f7c1bda..3c961b4d8046 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -3,7 +3,7 @@
#
obj-$(CONFIG_CRYPTO) += crypto.o
-crypto-objs := api.o cipher.o digest.o compress.o
+crypto-objs := api.o cipher.o compress.o
obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
@@ -22,7 +22,6 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER2) += chainiv.o
obj-$(CONFIG_CRYPTO_BLKCIPHER2) += eseqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
-crypto_hash-objs := hash.o
crypto_hash-objs += ahash.o
crypto_hash-objs += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index e11ce37c7104..03fb5facf0b4 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -14,6 +14,7 @@
*/
#include <crypto/internal/skcipher.h>
+#include <linux/cpumask.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -25,6 +26,8 @@
#include "internal.h"
+static const char *skcipher_default_geniv __read_mostly;
+
static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key,
unsigned int keylen)
{
@@ -180,7 +183,8 @@ EXPORT_SYMBOL_GPL(crypto_givcipher_type);
const char *crypto_default_geniv(const struct crypto_alg *alg)
{
- return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv";
+ return alg->cra_flags & CRYPTO_ALG_ASYNC ?
+ "eseqiv" : skcipher_default_geniv;
}
static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
@@ -201,8 +205,9 @@ static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
int err;
larval = crypto_larval_lookup(alg->cra_driver_name,
+ (type & ~CRYPTO_ALG_TYPE_MASK) |
CRYPTO_ALG_TYPE_GIVCIPHER,
- CRYPTO_ALG_TYPE_MASK);
+ mask | CRYPTO_ALG_TYPE_MASK);
err = PTR_ERR(larval);
if (IS_ERR(larval))
goto out;
@@ -360,3 +365,17 @@ err:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
+
+static int __init skcipher_module_init(void)
+{
+ skcipher_default_geniv = num_possible_cpus() > 1 ?
+ "eseqiv" : "chainiv";
+ return 0;
+}
+
+static void skcipher_module_exit(void)
+{
+}
+
+module_init(skcipher_module_init);
+module_exit(skcipher_module_exit);
diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c
index b8b66ec3883b..e78b7ee44a74 100644
--- a/crypto/aes_generic.c
+++ b/crypto/aes_generic.c
@@ -1174,7 +1174,7 @@ EXPORT_SYMBOL_GPL(crypto_il_tab);
ctx->key_enc[6 * i + 11] = t; \
} while (0)
-#define loop8(i) do { \
+#define loop8tophalf(i) do { \
t = ror32(t, 8); \
t = ls_box(t) ^ rco_tab[i]; \
t ^= ctx->key_enc[8 * i]; \
@@ -1185,6 +1185,10 @@ EXPORT_SYMBOL_GPL(crypto_il_tab);
ctx->key_enc[8 * i + 10] = t; \
t ^= ctx->key_enc[8 * i + 3]; \
ctx->key_enc[8 * i + 11] = t; \
+} while (0)
+
+#define loop8(i) do { \
+ loop8tophalf(i); \
t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \
ctx->key_enc[8 * i + 12] = t; \
t ^= ctx->key_enc[8 * i + 5]; \
@@ -1245,8 +1249,9 @@ int crypto_aes_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
ctx->key_enc[5] = le32_to_cpu(key[5]);
ctx->key_enc[6] = le32_to_cpu(key[6]);
t = ctx->key_enc[7] = le32_to_cpu(key[7]);
- for (i = 0; i < 7; ++i)
+ for (i = 0; i < 6; ++i)
loop8(i);
+ loop8tophalf(i);
break;
}
diff --git a/crypto/ahash.c b/crypto/ahash.c
index f3476374f764..33a4ff45f842 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -24,6 +24,19 @@
#include "internal.h"
+struct ahash_request_priv {
+ crypto_completion_t complete;
+ void *data;
+ u8 *result;
+ void *ubuf[] CRYPTO_MINALIGN_ATTR;
+};
+
+static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash)
+{
+ return container_of(crypto_hash_alg_common(hash), struct ahash_alg,
+ halg);
+}
+
static int hash_walk_next(struct crypto_hash_walk *walk)
{
unsigned int alignmask = walk->alignmask;
@@ -132,36 +145,34 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
- struct ahash_alg *ahash = crypto_ahash_alg(tfm);
unsigned long alignmask = crypto_ahash_alignmask(tfm);
int ret;
u8 *buffer, *alignbuffer;
unsigned long absize;
absize = keylen + alignmask;
- buffer = kmalloc(absize, GFP_ATOMIC);
+ buffer = kmalloc(absize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
memcpy(alignbuffer, key, keylen);
- ret = ahash->setkey(tfm, alignbuffer, keylen);
- memset(alignbuffer, 0, keylen);
- kfree(buffer);
+ ret = tfm->setkey(tfm, alignbuffer, keylen);
+ kzfree(buffer);
return ret;
}
-static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
- struct ahash_alg *ahash = crypto_ahash_alg(tfm);
unsigned long alignmask = crypto_ahash_alignmask(tfm);
if ((unsigned long)key & alignmask)
return ahash_setkey_unaligned(tfm, key, keylen);
- return ahash->setkey(tfm, key, keylen);
+ return tfm->setkey(tfm, key, keylen);
}
+EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
@@ -169,44 +180,221 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
return -ENOSYS;
}
-int crypto_ahash_import(struct ahash_request *req, const u8 *in)
+static inline unsigned int ahash_align_buffer_size(unsigned len,
+ unsigned long mask)
+{
+ return len + (mask & ~(crypto_tfm_ctx_alignment() - 1));
+}
+
+static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
+{
+ struct ahash_request_priv *priv = req->priv;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ if (!err)
+ memcpy(priv->result, req->result,
+ crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+
+ kzfree(priv);
+}
+
+static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
+{
+ struct ahash_request *areq = req->data;
+ struct ahash_request_priv *priv = areq->priv;
+ crypto_completion_t complete = priv->complete;
+ void *data = priv->data;
+
+ ahash_op_unaligned_finish(areq, err);
+
+ complete(data, err);
+}
+
+static int ahash_op_unaligned(struct ahash_request *req,
+ int (*op)(struct ahash_request *))
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ unsigned long alignmask = crypto_ahash_alignmask(tfm);
+ unsigned int ds = crypto_ahash_digestsize(tfm);
+ struct ahash_request_priv *priv;
+ int err;
+
+ priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
+ (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC);
+ if (!priv)
+ return -ENOMEM;
- memcpy(ahash_request_ctx(req), in, crypto_ahash_reqsize(tfm));
+ priv->result = req->result;
+ priv->complete = req->base.complete;
+ priv->data = req->base.data;
- if (alg->reinit)
- alg->reinit(req);
+ req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
+ req->base.complete = ahash_op_unaligned_done;
+ req->base.data = req;
+ req->priv = priv;
- return 0;
+ err = op(req);
+ ahash_op_unaligned_finish(req, err);
+
+ return err;
}
-EXPORT_SYMBOL_GPL(crypto_ahash_import);
-static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
+static int crypto_ahash_op(struct ahash_request *req,
+ int (*op)(struct ahash_request *))
{
- return alg->cra_ctxsize;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ unsigned long alignmask = crypto_ahash_alignmask(tfm);
+
+ if ((unsigned long)req->result & alignmask)
+ return ahash_op_unaligned(req, op);
+
+ return op(req);
}
-static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+int crypto_ahash_final(struct ahash_request *req)
{
- struct ahash_alg *alg = &tfm->__crt_alg->cra_ahash;
- struct ahash_tfm *crt = &tfm->crt_ahash;
+ return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
+}
+EXPORT_SYMBOL_GPL(crypto_ahash_final);
- if (alg->digestsize > PAGE_SIZE / 8)
- return -EINVAL;
+int crypto_ahash_finup(struct ahash_request *req)
+{
+ return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
+}
+EXPORT_SYMBOL_GPL(crypto_ahash_finup);
+
+int crypto_ahash_digest(struct ahash_request *req)
+{
+ return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
+}
+EXPORT_SYMBOL_GPL(crypto_ahash_digest);
+
+static void ahash_def_finup_finish2(struct ahash_request *req, int err)
+{
+ struct ahash_request_priv *priv = req->priv;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ if (!err)
+ memcpy(priv->result, req->result,
+ crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
- crt->init = alg->init;
- crt->update = alg->update;
- crt->final = alg->final;
- crt->digest = alg->digest;
- crt->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey;
- crt->digestsize = alg->digestsize;
+ kzfree(priv);
+}
+
+static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
+{
+ struct ahash_request *areq = req->data;
+ struct ahash_request_priv *priv = areq->priv;
+ crypto_completion_t complete = priv->complete;
+ void *data = priv->data;
+
+ ahash_def_finup_finish2(areq, err);
+
+ complete(data, err);
+}
+
+static int ahash_def_finup_finish1(struct ahash_request *req, int err)
+{
+ if (err)
+ goto out;
+
+ req->base.complete = ahash_def_finup_done2;
+ req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = crypto_ahash_reqtfm(req)->final(req);
+
+out:
+ ahash_def_finup_finish2(req, err);
+ return err;
+}
+
+static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
+{
+ struct ahash_request *areq = req->data;
+ struct ahash_request_priv *priv = areq->priv;
+ crypto_completion_t complete = priv->complete;
+ void *data = priv->data;
+
+ err = ahash_def_finup_finish1(areq, err);
+
+ complete(data, err);
+}
+
+static int ahash_def_finup(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ unsigned long alignmask = crypto_ahash_alignmask(tfm);
+ unsigned int ds = crypto_ahash_digestsize(tfm);
+ struct ahash_request_priv *priv;
+
+ priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
+ (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->result = req->result;
+ priv->complete = req->base.complete;
+ priv->data = req->base.data;
+
+ req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
+ req->base.complete = ahash_def_finup_done1;
+ req->base.data = req;
+ req->priv = priv;
+
+ return ahash_def_finup_finish1(req, tfm->update(req));
+}
+
+static int ahash_no_export(struct ahash_request *req, void *out)
+{
+ return -ENOSYS;
+}
+
+static int ahash_no_import(struct ahash_request *req, const void *in)
+{
+ return -ENOSYS;
+}
+
+static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(hash);
+
+ hash->setkey = ahash_nosetkey;
+ hash->export = ahash_no_export;
+ hash->import = ahash_no_import;
+
+ if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
+ return crypto_init_shash_ops_async(tfm);
+
+ hash->init = alg->init;
+ hash->update = alg->update;
+ hash->final = alg->final;
+ hash->finup = alg->finup ?: ahash_def_finup;
+ hash->digest = alg->digest;
+
+ if (alg->setkey)
+ hash->setkey = alg->setkey;
+ if (alg->export)
+ hash->export = alg->export;
+ if (alg->import)
+ hash->import = alg->import;
return 0;
}
+static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
+{
+ if (alg->cra_type == &crypto_ahash_type)
+ return alg->cra_ctxsize;
+
+ return sizeof(struct crypto_shash *);
+}
+
static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
__attribute__ ((unused));
static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
@@ -215,17 +403,101 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
"yes" : "no");
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n", alg->cra_ahash.digestsize);
+ seq_printf(m, "digestsize : %u\n",
+ __crypto_hash_alg_common(alg)->digestsize);
}
const struct crypto_type crypto_ahash_type = {
- .ctxsize = crypto_ahash_ctxsize,
- .init = crypto_init_ahash_ops,
+ .extsize = crypto_ahash_extsize,
+ .init_tfm = crypto_ahash_init_tfm,
#ifdef CONFIG_PROC_FS
.show = crypto_ahash_show,
#endif
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .tfmsize = offsetof(struct crypto_ahash, base),
};
EXPORT_SYMBOL_GPL(crypto_ahash_type);
+struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
+ u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
+
+static int ahash_prepare_alg(struct ahash_alg *alg)
+{
+ struct crypto_alg *base = &alg->halg.base;
+
+ if (alg->halg.digestsize > PAGE_SIZE / 8 ||
+ alg->halg.statesize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ base->cra_type = &crypto_ahash_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;
+
+ return 0;
+}
+
+int crypto_register_ahash(struct ahash_alg *alg)
+{
+ struct crypto_alg *base = &alg->halg.base;
+ int err;
+
+ err = ahash_prepare_alg(alg);
+ if (err)
+ return err;
+
+ return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_ahash);
+
+int crypto_unregister_ahash(struct ahash_alg *alg)
+{
+ return crypto_unregister_alg(&alg->halg.base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_ahash);
+
+int ahash_register_instance(struct crypto_template *tmpl,
+ struct ahash_instance *inst)
+{
+ int err;
+
+ err = ahash_prepare_alg(&inst->alg);
+ if (err)
+ return err;
+
+ return crypto_register_instance(tmpl, ahash_crypto_instance(inst));
+}
+EXPORT_SYMBOL_GPL(ahash_register_instance);
+
+void ahash_free_instance(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(ahash_instance(inst));
+}
+EXPORT_SYMBOL_GPL(ahash_free_instance);
+
+int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
+ struct hash_alg_common *alg,
+ struct crypto_instance *inst)
+{
+ return crypto_init_spawn2(&spawn->base, &alg->base, inst,
+ &crypto_ahash_type);
+}
+EXPORT_SYMBOL_GPL(crypto_init_ahash_spawn);
+
+struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+{
+ struct crypto_alg *alg;
+
+ alg = crypto_attr_alg2(rta, &crypto_ahash_type, type, mask);
+ return IS_ERR(alg) ? ERR_CAST(alg) : __crypto_hash_alg_common(alg);
+}
+EXPORT_SYMBOL_GPL(ahash_attr_alg);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 56c62e2858d5..6a98076d9d2a 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -488,20 +488,38 @@ int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
}
EXPORT_SYMBOL_GPL(crypto_init_spawn);
+int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg,
+ struct crypto_instance *inst,
+ const struct crypto_type *frontend)
+{
+ int err = -EINVAL;
+
+ if (frontend && (alg->cra_flags ^ frontend->type) & frontend->maskset)
+ goto out;
+
+ spawn->frontend = frontend;
+ err = crypto_init_spawn(spawn, alg, inst, frontend->maskset);
+
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_init_spawn2);
+
void crypto_drop_spawn(struct crypto_spawn *spawn)
{
+ if (!spawn->alg)
+ return;
+
down_write(&crypto_alg_sem);
list_del(&spawn->list);
up_write(&crypto_alg_sem);
}
EXPORT_SYMBOL_GPL(crypto_drop_spawn);
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
- u32 mask)
+static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
{
struct crypto_alg *alg;
struct crypto_alg *alg2;
- struct crypto_tfm *tfm;
down_read(&crypto_alg_sem);
alg = spawn->alg;
@@ -516,6 +534,19 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
return ERR_PTR(-EAGAIN);
}
+ return alg;
+}
+
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+ u32 mask)
+{
+ struct crypto_alg *alg;
+ struct crypto_tfm *tfm;
+
+ alg = crypto_spawn_alg(spawn);
+ if (IS_ERR(alg))
+ return ERR_CAST(alg);
+
tfm = ERR_PTR(-EINVAL);
if (unlikely((alg->cra_flags ^ type) & mask))
goto out_put_alg;
@@ -532,6 +563,27 @@ out_put_alg:
}
EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
+void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
+{
+ struct crypto_alg *alg;
+ struct crypto_tfm *tfm;
+
+ alg = crypto_spawn_alg(spawn);
+ if (IS_ERR(alg))
+ return ERR_CAST(alg);
+
+ tfm = crypto_create_tfm(alg, spawn->frontend);
+ if (IS_ERR(tfm))
+ goto out_put_alg;
+
+ return tfm;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);
+
int crypto_register_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&crypto_chain, nb);
@@ -595,7 +647,9 @@ const char *crypto_attr_alg_name(struct rtattr *rta)
}
EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
-struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+struct crypto_alg *crypto_attr_alg2(struct rtattr *rta,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask)
{
const char *name;
int err;
@@ -605,9 +659,9 @@ struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
if (IS_ERR(name))
return ERR_PTR(err);
- return crypto_alg_mod_lookup(name, type, mask);
+ return crypto_find_alg(name, frontend, type, mask);
}
-EXPORT_SYMBOL_GPL(crypto_attr_alg);
+EXPORT_SYMBOL_GPL(crypto_attr_alg2);
int crypto_attr_u32(struct rtattr *rta, u32 *num)
{
@@ -627,17 +681,20 @@ int crypto_attr_u32(struct rtattr *rta, u32 *num)
}
EXPORT_SYMBOL_GPL(crypto_attr_u32);
-struct crypto_instance *crypto_alloc_instance(const char *name,
- struct crypto_alg *alg)
+void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg,
+ unsigned int head)
{
struct crypto_instance *inst;
- struct crypto_spawn *spawn;
+ char *p;
int err;
- inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
- if (!inst)
+ p = kzalloc(head + sizeof(*inst) + sizeof(struct crypto_spawn),
+ GFP_KERNEL);
+ if (!p)
return ERR_PTR(-ENOMEM);
+ inst = (void *)(p + head);
+
err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
@@ -647,6 +704,25 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
+ return p;
+
+err_free_inst:
+ kfree(p);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_instance2);
+
+struct crypto_instance *crypto_alloc_instance(const char *name,
+ struct crypto_alg *alg)
+{
+ struct crypto_instance *inst;
+ struct crypto_spawn *spawn;
+ int err;
+
+ inst = crypto_alloc_instance2(name, alg, 0);
+ if (IS_ERR(inst))
+ goto out;
+
spawn = crypto_instance_ctx(inst);
err = crypto_init_spawn(spawn, alg, inst,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
@@ -658,7 +734,10 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
err_free_inst:
kfree(inst);
- return ERR_PTR(err);
+ inst = ERR_PTR(err);
+
+out:
+ return inst;
}
EXPORT_SYMBOL_GPL(crypto_alloc_instance);
diff --git a/crypto/algboss.c b/crypto/algboss.c
index 9908dd830c26..412241ce4cfa 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -68,6 +68,11 @@ static int cryptomgr_probe(void *data)
goto err;
do {
+ if (tmpl->create) {
+ err = tmpl->create(tmpl, param->tb);
+ continue;
+ }
+
inst = tmpl->alloc(param->tb);
if (IS_ERR(inst))
err = PTR_ERR(inst);
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index d80ed4c1e009..5357ba7d821a 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -187,7 +187,6 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
/* Our exported functions */
static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
{
- unsigned long flags;
unsigned char *ptr = buf;
unsigned int byte_count = (unsigned int)nbytes;
int err;
@@ -196,7 +195,7 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
if (nbytes < 0)
return -EINVAL;
- spin_lock_irqsave(&ctx->prng_lock, flags);
+ spin_lock_bh(&ctx->prng_lock);
err = -EINVAL;
if (ctx->flags & PRNG_NEED_RESET)
@@ -268,7 +267,7 @@ empty_rbuf:
goto remainder;
done:
- spin_unlock_irqrestore(&ctx->prng_lock, flags);
+ spin_unlock_bh(&ctx->prng_lock);
dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",
err, ctx);
return err;
@@ -284,10 +283,9 @@ static int reset_prng_context(struct prng_context *ctx,
unsigned char *V, unsigned char *DT)
{
int ret;
- int rc = -EINVAL;
unsigned char *prng_key;
- spin_lock(&ctx->prng_lock);
+ spin_lock_bh(&ctx->prng_lock);
ctx->flags |= PRNG_NEED_RESET;
prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY;
@@ -308,34 +306,20 @@ static int reset_prng_context(struct prng_context *ctx,
memset(ctx->rand_data, 0, DEFAULT_BLK_SZ);
memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ);
- if (ctx->tfm)
- crypto_free_cipher(ctx->tfm);
-
- ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
- if (IS_ERR(ctx->tfm)) {
- dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
- ctx);
- ctx->tfm = NULL;
- goto out;
- }
-
ctx->rand_data_valid = DEFAULT_BLK_SZ;
ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen);
if (ret) {
dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
crypto_cipher_get_flags(ctx->tfm));
- crypto_free_cipher(ctx->tfm);
goto out;
}
- rc = 0;
+ ret = 0;
ctx->flags &= ~PRNG_NEED_RESET;
out:
- spin_unlock(&ctx->prng_lock);
-
- return rc;
-
+ spin_unlock_bh(&ctx->prng_lock);
+ return ret;
}
static int cprng_init(struct crypto_tfm *tfm)
@@ -343,6 +327,12 @@ static int cprng_init(struct crypto_tfm *tfm)
struct prng_context *ctx = crypto_tfm_ctx(tfm);
spin_lock_init(&ctx->prng_lock);
+ ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
+ if (IS_ERR(ctx->tfm)) {
+ dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
+ ctx);
+ return PTR_ERR(ctx->tfm);
+ }
if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0)
return -EINVAL;
diff --git a/crypto/api.c b/crypto/api.c
index d5944f92b416..798526d90538 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -285,13 +285,6 @@ static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
return crypto_init_cipher_ops(tfm);
-
- case CRYPTO_ALG_TYPE_DIGEST:
- if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) !=
- CRYPTO_ALG_TYPE_HASH_MASK)
- return crypto_init_digest_ops_async(tfm);
- else
- return crypto_init_digest_ops(tfm);
case CRYPTO_ALG_TYPE_COMPRESS:
return crypto_init_compress_ops(tfm);
@@ -318,11 +311,7 @@ static void crypto_exit_ops(struct crypto_tfm *tfm)
case CRYPTO_ALG_TYPE_CIPHER:
crypto_exit_cipher_ops(tfm);
break;
-
- case CRYPTO_ALG_TYPE_DIGEST:
- crypto_exit_digest_ops(tfm);
- break;
-
+
case CRYPTO_ALG_TYPE_COMPRESS:
crypto_exit_compress_ops(tfm);
break;
@@ -349,11 +338,7 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
case CRYPTO_ALG_TYPE_CIPHER:
len += crypto_cipher_ctxsize(alg);
break;
-
- case CRYPTO_ALG_TYPE_DIGEST:
- len += crypto_digest_ctxsize(alg);
- break;
-
+
case CRYPTO_ALG_TYPE_COMPRESS:
len += crypto_compress_ctxsize(alg);
break;
@@ -472,7 +457,7 @@ void *crypto_create_tfm(struct crypto_alg *alg,
int err = -ENOMEM;
tfmsize = frontend->tfmsize;
- total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend);
+ total = tfmsize + sizeof(*tfm) + frontend->extsize(alg);
mem = kzalloc(total, GFP_KERNEL);
if (mem == NULL)
@@ -481,7 +466,7 @@ void *crypto_create_tfm(struct crypto_alg *alg,
tfm = (struct crypto_tfm *)(mem + tfmsize);
tfm->__crt_alg = alg;
- err = frontend->init_tfm(tfm, frontend);
+ err = frontend->init_tfm(tfm);
if (err)
goto out_free_tfm;
@@ -503,6 +488,27 @@ out:
}
EXPORT_SYMBOL_GPL(crypto_create_tfm);
+struct crypto_alg *crypto_find_alg(const char *alg_name,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask)
+{
+ struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) =
+ crypto_alg_mod_lookup;
+
+ if (frontend) {
+ type &= frontend->maskclear;
+ mask &= frontend->maskclear;
+ type |= frontend->type;
+ mask |= frontend->maskset;
+
+ if (frontend->lookup)
+ lookup = frontend->lookup;
+ }
+
+ return lookup(alg_name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_find_alg);
+
/*
* crypto_alloc_tfm - Locate algorithm and allocate transform
* @alg_name: Name of algorithm
@@ -526,21 +532,13 @@ EXPORT_SYMBOL_GPL(crypto_create_tfm);
void *crypto_alloc_tfm(const char *alg_name,
const struct crypto_type *frontend, u32 type, u32 mask)
{
- struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
void *tfm;
int err;
- type &= frontend->maskclear;
- mask &= frontend->maskclear;
- type |= frontend->type;
- mask |= frontend->maskset;
-
- lookup = frontend->lookup ?: crypto_alg_mod_lookup;
-
for (;;) {
struct crypto_alg *alg;
- alg = lookup(alg_name, type, mask);
+ alg = crypto_find_alg(alg_name, frontend, type, mask);
if (IS_ERR(alg)) {
err = PTR_ERR(alg);
goto err;
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index 95fe2c8d6c51..90dd3f8bd283 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -300,7 +300,7 @@ EXPORT_SYMBOL_GPL(async_xor_zero_sum);
static int __init async_xor_init(void)
{
- #ifdef CONFIG_DMA_ENGINE
+ #ifdef CONFIG_ASYNC_TX_DMA
/* To conserve stack space the input src_list (array of page pointers)
* is reused to hold the array of dma addresses passed to the driver.
* This conversion is only possible when dma_addr_t is less than the
diff --git a/crypto/authenc.c b/crypto/authenc.c
index 5793b64c81a8..2e16ce0089cb 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -436,11 +436,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
inst->alg.cra_type = &crypto_aead_type;
inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
- inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ?
- auth->cra_hash.digestsize :
- auth->cra_type ?
- __crypto_shash_alg(auth)->digestsize :
- auth->cra_digest.dia_digestsize;
+ inst->alg.cra_aead.maxauthsize = __crypto_shash_alg(auth)->digestsize;
inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index ae5fa99d5d36..2eb705822f2b 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -39,6 +39,11 @@ struct cryptd_instance_ctx {
struct cryptd_queue *queue;
};
+struct hashd_instance_ctx {
+ struct crypto_shash_spawn spawn;
+ struct cryptd_queue *queue;
+};
+
struct cryptd_blkcipher_ctx {
struct crypto_blkcipher *child;
};
@@ -48,11 +53,12 @@ struct cryptd_blkcipher_request_ctx {
};
struct cryptd_hash_ctx {
- struct crypto_hash *child;
+ struct crypto_shash *child;
};
struct cryptd_hash_request_ctx {
crypto_completion_t complete;
+ struct shash_desc desc;
};
static void cryptd_queue_worker(struct work_struct *work);
@@ -249,32 +255,24 @@ static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm)
crypto_free_blkcipher(ctx->child);
}
-static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
- struct cryptd_queue *queue)
+static void *cryptd_alloc_instance(struct crypto_alg *alg, unsigned int head,
+ unsigned int tail)
{
+ char *p;
struct crypto_instance *inst;
- struct cryptd_instance_ctx *ctx;
int err;
- inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
- if (!inst) {
- inst = ERR_PTR(-ENOMEM);
- goto out;
- }
+ p = kzalloc(head + sizeof(*inst) + tail, GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+
+ inst = (void *)(p + head);
err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
"cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
goto out_free_inst;
- ctx = crypto_instance_ctx(inst);
- err = crypto_init_spawn(&ctx->spawn, alg, inst,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
- if (err)
- goto out_free_inst;
-
- ctx->queue = queue;
-
memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
inst->alg.cra_priority = alg->cra_priority + 50;
@@ -282,29 +280,41 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
inst->alg.cra_alignmask = alg->cra_alignmask;
out:
- return inst;
+ return p;
out_free_inst:
- kfree(inst);
- inst = ERR_PTR(err);
+ kfree(p);
+ p = ERR_PTR(err);
goto out;
}
-static struct crypto_instance *cryptd_alloc_blkcipher(
- struct rtattr **tb, struct cryptd_queue *queue)
+static int cryptd_create_blkcipher(struct crypto_template *tmpl,
+ struct rtattr **tb,
+ struct cryptd_queue *queue)
{
+ struct cryptd_instance_ctx *ctx;
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return PTR_ERR(alg);
- inst = cryptd_alloc_instance(alg, queue);
+ inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx));
+ err = PTR_ERR(inst);
if (IS_ERR(inst))
goto out_put_alg;
+ ctx = crypto_instance_ctx(inst);
+ ctx->queue = queue;
+
+ err = crypto_init_spawn(&ctx->spawn, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ if (err)
+ goto out_free_inst;
+
inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
inst->alg.cra_type = &crypto_ablkcipher_type;
@@ -323,26 +333,34 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue;
inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue;
+ err = crypto_register_instance(tmpl, inst);
+ if (err) {
+ crypto_drop_spawn(&ctx->spawn);
+out_free_inst:
+ kfree(inst);
+ }
+
out_put_alg:
crypto_mod_put(alg);
- return inst;
+ return err;
}
static int cryptd_hash_init_tfm(struct crypto_tfm *tfm)
{
struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
- struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
- struct crypto_spawn *spawn = &ictx->spawn;
+ struct hashd_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct crypto_shash_spawn *spawn = &ictx->spawn;
struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
- struct crypto_hash *cipher;
+ struct crypto_shash *hash;
- cipher = crypto_spawn_hash(spawn);
- if (IS_ERR(cipher))
- return PTR_ERR(cipher);
+ hash = crypto_spawn_shash(spawn);
+ if (IS_ERR(hash))
+ return PTR_ERR(hash);
- ctx->child = cipher;
- tfm->crt_ahash.reqsize =
- sizeof(struct cryptd_hash_request_ctx);
+ ctx->child = hash;
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct cryptd_hash_request_ctx) +
+ crypto_shash_descsize(hash));
return 0;
}
@@ -350,22 +368,22 @@ static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm)
{
struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_hash(ctx->child);
+ crypto_free_shash(ctx->child);
}
static int cryptd_hash_setkey(struct crypto_ahash *parent,
const u8 *key, unsigned int keylen)
{
struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(parent);
- struct crypto_hash *child = ctx->child;
+ struct crypto_shash *child = ctx->child;
int err;
- crypto_hash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
- crypto_hash_set_flags(child, crypto_ahash_get_flags(parent) &
- CRYPTO_TFM_REQ_MASK);
- err = crypto_hash_setkey(child, key, keylen);
- crypto_ahash_set_flags(parent, crypto_hash_get_flags(child) &
- CRYPTO_TFM_RES_MASK);
+ crypto_shash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_shash_set_flags(child, crypto_ahash_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_shash_setkey(child, key, keylen);
+ crypto_ahash_set_flags(parent, crypto_shash_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
return err;
}
@@ -385,21 +403,19 @@ static int cryptd_hash_enqueue(struct ahash_request *req,
static void cryptd_hash_init(struct crypto_async_request *req_async, int err)
{
- struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
- struct crypto_hash *child = ctx->child;
- struct ahash_request *req = ahash_request_cast(req_async);
- struct cryptd_hash_request_ctx *rctx;
- struct hash_desc desc;
-
- rctx = ahash_request_ctx(req);
+ struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
+ struct crypto_shash *child = ctx->child;
+ struct ahash_request *req = ahash_request_cast(req_async);
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+ struct shash_desc *desc = &rctx->desc;
if (unlikely(err == -EINPROGRESS))
goto out;
- desc.tfm = child;
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ desc->tfm = child;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- err = crypto_hash_crt(child)->init(&desc);
+ err = crypto_shash_init(desc);
req->base.complete = rctx->complete;
@@ -416,23 +432,15 @@ static int cryptd_hash_init_enqueue(struct ahash_request *req)
static void cryptd_hash_update(struct crypto_async_request *req_async, int err)
{
- struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
- struct crypto_hash *child = ctx->child;
- struct ahash_request *req = ahash_request_cast(req_async);
+ struct ahash_request *req = ahash_request_cast(req_async);
struct cryptd_hash_request_ctx *rctx;
- struct hash_desc desc;
rctx = ahash_request_ctx(req);
if (unlikely(err == -EINPROGRESS))
goto out;
- desc.tfm = child;
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-
- err = crypto_hash_crt(child)->update(&desc,
- req->src,
- req->nbytes);
+ err = shash_ahash_update(req, &rctx->desc);
req->base.complete = rctx->complete;
@@ -449,21 +457,13 @@ static int cryptd_hash_update_enqueue(struct ahash_request *req)
static void cryptd_hash_final(struct crypto_async_request *req_async, int err)
{
- struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
- struct crypto_hash *child = ctx->child;
- struct ahash_request *req = ahash_request_cast(req_async);
- struct cryptd_hash_request_ctx *rctx;
- struct hash_desc desc;
-
- rctx = ahash_request_ctx(req);
+ struct ahash_request *req = ahash_request_cast(req_async);
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
if (unlikely(err == -EINPROGRESS))
goto out;
- desc.tfm = child;
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-
- err = crypto_hash_crt(child)->final(&desc, req->result);
+ err = crypto_shash_final(&rctx->desc, req->result);
req->base.complete = rctx->complete;
@@ -478,26 +478,44 @@ static int cryptd_hash_final_enqueue(struct ahash_request *req)
return cryptd_hash_enqueue(req, cryptd_hash_final);
}
-static void cryptd_hash_digest(struct crypto_async_request *req_async, int err)
+static void cryptd_hash_finup(struct crypto_async_request *req_async, int err)
{
- struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
- struct crypto_hash *child = ctx->child;
- struct ahash_request *req = ahash_request_cast(req_async);
- struct cryptd_hash_request_ctx *rctx;
- struct hash_desc desc;
+ struct ahash_request *req = ahash_request_cast(req_async);
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
- rctx = ahash_request_ctx(req);
+ if (unlikely(err == -EINPROGRESS))
+ goto out;
+
+ err = shash_ahash_finup(req, &rctx->desc);
+
+ req->base.complete = rctx->complete;
+
+out:
+ local_bh_disable();
+ rctx->complete(&req->base, err);
+ local_bh_enable();
+}
+
+static int cryptd_hash_finup_enqueue(struct ahash_request *req)
+{
+ return cryptd_hash_enqueue(req, cryptd_hash_finup);
+}
+
+static void cryptd_hash_digest(struct crypto_async_request *req_async, int err)
+{
+ struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm);
+ struct crypto_shash *child = ctx->child;
+ struct ahash_request *req = ahash_request_cast(req_async);
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+ struct shash_desc *desc = &rctx->desc;
if (unlikely(err == -EINPROGRESS))
goto out;
- desc.tfm = child;
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ desc->tfm = child;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- err = crypto_hash_crt(child)->digest(&desc,
- req->src,
- req->nbytes,
- req->result);
+ err = shash_ahash_digest(req, desc);
req->base.complete = rctx->complete;
@@ -512,64 +530,108 @@ static int cryptd_hash_digest_enqueue(struct ahash_request *req)
return cryptd_hash_enqueue(req, cryptd_hash_digest);
}
-static struct crypto_instance *cryptd_alloc_hash(
- struct rtattr **tb, struct cryptd_queue *queue)
+static int cryptd_hash_export(struct ahash_request *req, void *out)
{
- struct crypto_instance *inst;
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+
+ return crypto_shash_export(&rctx->desc, out);
+}
+
+static int cryptd_hash_import(struct ahash_request *req, const void *in)
+{
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+
+ return crypto_shash_import(&rctx->desc, in);
+}
+
+static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
+ struct cryptd_queue *queue)
+{
+ struct hashd_instance_ctx *ctx;
+ struct ahash_instance *inst;
+ struct shash_alg *salg;
struct crypto_alg *alg;
+ int err;
- alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
- CRYPTO_ALG_TYPE_HASH_MASK);
- if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ salg = shash_attr_alg(tb[1], 0, 0);
+ if (IS_ERR(salg))
+ return PTR_ERR(salg);
- inst = cryptd_alloc_instance(alg, queue);
+ alg = &salg->base;
+ inst = cryptd_alloc_instance(alg, ahash_instance_headroom(),
+ sizeof(*ctx));
+ err = PTR_ERR(inst);
if (IS_ERR(inst))
goto out_put_alg;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC;
- inst->alg.cra_type = &crypto_ahash_type;
+ ctx = ahash_instance_ctx(inst);
+ ctx->queue = queue;
+
+ err = crypto_init_shash_spawn(&ctx->spawn, salg,
+ ahash_crypto_instance(inst));
+ if (err)
+ goto out_free_inst;
+
+ inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC;
+
+ inst->alg.halg.digestsize = salg->digestsize;
+ inst->alg.halg.base.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
- inst->alg.cra_ahash.digestsize = alg->cra_hash.digestsize;
- inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
+ inst->alg.halg.base.cra_init = cryptd_hash_init_tfm;
+ inst->alg.halg.base.cra_exit = cryptd_hash_exit_tfm;
- inst->alg.cra_init = cryptd_hash_init_tfm;
- inst->alg.cra_exit = cryptd_hash_exit_tfm;
+ inst->alg.init = cryptd_hash_init_enqueue;
+ inst->alg.update = cryptd_hash_update_enqueue;
+ inst->alg.final = cryptd_hash_final_enqueue;
+ inst->alg.finup = cryptd_hash_finup_enqueue;
+ inst->alg.export = cryptd_hash_export;
+ inst->alg.import = cryptd_hash_import;
+ inst->alg.setkey = cryptd_hash_setkey;
+ inst->alg.digest = cryptd_hash_digest_enqueue;
- inst->alg.cra_ahash.init = cryptd_hash_init_enqueue;
- inst->alg.cra_ahash.update = cryptd_hash_update_enqueue;
- inst->alg.cra_ahash.final = cryptd_hash_final_enqueue;
- inst->alg.cra_ahash.setkey = cryptd_hash_setkey;
- inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue;
+ err = ahash_register_instance(tmpl, inst);
+ if (err) {
+ crypto_drop_shash(&ctx->spawn);
+out_free_inst:
+ kfree(inst);
+ }
out_put_alg:
crypto_mod_put(alg);
- return inst;
+ return err;
}
static struct cryptd_queue queue;
-static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
+static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb)
{
struct crypto_attr_type *algt;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return PTR_ERR(algt);
switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_BLKCIPHER:
- return cryptd_alloc_blkcipher(tb, &queue);
+ return cryptd_create_blkcipher(tmpl, tb, &queue);
case CRYPTO_ALG_TYPE_DIGEST:
- return cryptd_alloc_hash(tb, &queue);
+ return cryptd_create_hash(tmpl, tb, &queue);
}
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
static void cryptd_free(struct crypto_instance *inst)
{
struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst);
+ struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst);
+
+ switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_drop_shash(&hctx->spawn);
+ kfree(ahash_instance(inst));
+ return;
+ }
crypto_drop_spawn(&ctx->spawn);
kfree(inst);
@@ -577,7 +639,7 @@ static void cryptd_free(struct crypto_instance *inst)
static struct crypto_template cryptd_tmpl = {
.name = "cryptd",
- .alloc = cryptd_alloc,
+ .create = cryptd_create,
.free = cryptd_free,
.module = THIS_MODULE,
};
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 0ad39c374963..15c2eb534541 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -27,7 +27,7 @@
#include <linux/string.h>
struct hmac_ctx {
- struct crypto_hash *child;
+ struct crypto_shash *hash;
};
static inline void *align_ptr(void *p, unsigned int align)
@@ -35,65 +35,45 @@ static inline void *align_ptr(void *p, unsigned int align)
return (void *)ALIGN((unsigned long)p, align);
}
-static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
+static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm)
{
- return align_ptr(crypto_hash_ctx_aligned(tfm) +
- crypto_hash_blocksize(tfm) * 2 +
- crypto_hash_digestsize(tfm), sizeof(void *));
+ return align_ptr(crypto_shash_ctx_aligned(tfm) +
+ crypto_shash_statesize(tfm) * 2,
+ crypto_tfm_ctx_alignment());
}
-static int hmac_setkey(struct crypto_hash *parent,
+static int hmac_setkey(struct crypto_shash *parent,
const u8 *inkey, unsigned int keylen)
{
- int bs = crypto_hash_blocksize(parent);
- int ds = crypto_hash_digestsize(parent);
- char *ipad = crypto_hash_ctx_aligned(parent);
- char *opad = ipad + bs;
- char *digest = opad + bs;
- struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
- struct crypto_hash *tfm = ctx->child;
+ int bs = crypto_shash_blocksize(parent);
+ int ds = crypto_shash_digestsize(parent);
+ int ss = crypto_shash_statesize(parent);
+ char *ipad = crypto_shash_ctx_aligned(parent);
+ char *opad = ipad + ss;
+ struct hmac_ctx *ctx = align_ptr(opad + ss,
+ crypto_tfm_ctx_alignment());
+ struct crypto_shash *hash = ctx->hash;
+ struct {
+ struct shash_desc shash;
+ char ctx[crypto_shash_descsize(hash)];
+ } desc;
unsigned int i;
+ desc.shash.tfm = hash;
+ desc.shash.flags = crypto_shash_get_flags(parent) &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
if (keylen > bs) {
- struct hash_desc desc;
- struct scatterlist tmp;
- int tmplen;
int err;
- desc.tfm = tfm;
- desc.flags = crypto_hash_get_flags(parent);
- desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
-
- err = crypto_hash_init(&desc);
+ err = crypto_shash_digest(&desc.shash, inkey, keylen, ipad);
if (err)
return err;
- tmplen = bs * 2 + ds;
- sg_init_one(&tmp, ipad, tmplen);
-
- for (; keylen > tmplen; inkey += tmplen, keylen -= tmplen) {
- memcpy(ipad, inkey, tmplen);
- err = crypto_hash_update(&desc, &tmp, tmplen);
- if (err)
- return err;
- }
-
- if (keylen) {
- memcpy(ipad, inkey, keylen);
- err = crypto_hash_update(&desc, &tmp, keylen);
- if (err)
- return err;
- }
-
- err = crypto_hash_final(&desc, digest);
- if (err)
- return err;
-
- inkey = digest;
keylen = ds;
- }
+ } else
+ memcpy(ipad, inkey, keylen);
- memcpy(ipad, inkey, keylen);
memset(ipad + keylen, 0, bs - keylen);
memcpy(opad, ipad, bs);
@@ -102,184 +82,178 @@ static int hmac_setkey(struct crypto_hash *parent,
opad[i] ^= 0x5c;
}
- return 0;
+ return crypto_shash_init(&desc.shash) ?:
+ crypto_shash_update(&desc.shash, ipad, bs) ?:
+ crypto_shash_export(&desc.shash, ipad) ?:
+ crypto_shash_init(&desc.shash) ?:
+ crypto_shash_update(&desc.shash, opad, bs) ?:
+ crypto_shash_export(&desc.shash, opad);
}
-static int hmac_init(struct hash_desc *pdesc)
+static int hmac_export(struct shash_desc *pdesc, void *out)
{
- struct crypto_hash *parent = pdesc->tfm;
- int bs = crypto_hash_blocksize(parent);
- int ds = crypto_hash_digestsize(parent);
- char *ipad = crypto_hash_ctx_aligned(parent);
- struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
- struct hash_desc desc;
- struct scatterlist tmp;
- int err;
+ struct shash_desc *desc = shash_desc_ctx(pdesc);
- desc.tfm = ctx->child;
- desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- sg_init_one(&tmp, ipad, bs);
+ desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- err = crypto_hash_init(&desc);
- if (unlikely(err))
- return err;
-
- return crypto_hash_update(&desc, &tmp, bs);
+ return crypto_shash_export(desc, out);
}
-static int hmac_update(struct hash_desc *pdesc,
- struct scatterlist *sg, unsigned int nbytes)
+static int hmac_import(struct shash_desc *pdesc, const void *in)
{
+ struct shash_desc *desc = shash_desc_ctx(pdesc);
struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
- struct hash_desc desc;
- desc.tfm = ctx->child;
- desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ desc->tfm = ctx->hash;
+ desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- return crypto_hash_update(&desc, sg, nbytes);
+ return crypto_shash_import(desc, in);
}
-static int hmac_final(struct hash_desc *pdesc, u8 *out)
+static int hmac_init(struct shash_desc *pdesc)
{
- struct crypto_hash *parent = pdesc->tfm;
- int bs = crypto_hash_blocksize(parent);
- int ds = crypto_hash_digestsize(parent);
- char *opad = crypto_hash_ctx_aligned(parent) + bs;
- char *digest = opad + bs;
- struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
- struct hash_desc desc;
- struct scatterlist tmp;
- int err;
+ return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm));
+}
- desc.tfm = ctx->child;
- desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- sg_init_one(&tmp, opad, bs + ds);
+static int hmac_update(struct shash_desc *pdesc,
+ const u8 *data, unsigned int nbytes)
+{
+ struct shash_desc *desc = shash_desc_ctx(pdesc);
- err = crypto_hash_final(&desc, digest);
- if (unlikely(err))
- return err;
+ desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- return crypto_hash_digest(&desc, &tmp, bs + ds, out);
+ return crypto_shash_update(desc, data, nbytes);
}
-static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
- unsigned int nbytes, u8 *out)
+static int hmac_final(struct shash_desc *pdesc, u8 *out)
{
- struct crypto_hash *parent = pdesc->tfm;
- int bs = crypto_hash_blocksize(parent);
- int ds = crypto_hash_digestsize(parent);
- char *ipad = crypto_hash_ctx_aligned(parent);
- char *opad = ipad + bs;
- char *digest = opad + bs;
- struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
- struct hash_desc desc;
- struct scatterlist sg1[2];
- struct scatterlist sg2[1];
- int err;
+ struct crypto_shash *parent = pdesc->tfm;
+ int ds = crypto_shash_digestsize(parent);
+ int ss = crypto_shash_statesize(parent);
+ char *opad = crypto_shash_ctx_aligned(parent) + ss;
+ struct shash_desc *desc = shash_desc_ctx(pdesc);
- desc.tfm = ctx->child;
- desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- sg_init_table(sg1, 2);
- sg_set_buf(sg1, ipad, bs);
- scatterwalk_sg_chain(sg1, 2, sg);
+ return crypto_shash_final(desc, out) ?:
+ crypto_shash_import(desc, opad) ?:
+ crypto_shash_finup(desc, out, ds, out);
+}
- sg_init_table(sg2, 1);
- sg_set_buf(sg2, opad, bs + ds);
+static int hmac_finup(struct shash_desc *pdesc, const u8 *data,
+ unsigned int nbytes, u8 *out)
+{
- err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
- if (unlikely(err))
- return err;
+ struct crypto_shash *parent = pdesc->tfm;
+ int ds = crypto_shash_digestsize(parent);
+ int ss = crypto_shash_statesize(parent);
+ char *opad = crypto_shash_ctx_aligned(parent) + ss;
+ struct shash_desc *desc = shash_desc_ctx(pdesc);
- return crypto_hash_digest(&desc, sg2, bs + ds, out);
+ desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ return crypto_shash_finup(desc, data, nbytes, out) ?:
+ crypto_shash_import(desc, opad) ?:
+ crypto_shash_finup(desc, out, ds, out);
}
static int hmac_init_tfm(struct crypto_tfm *tfm)
{
- struct crypto_hash *hash;
+ struct crypto_shash *parent = __crypto_shash_cast(tfm);
+ struct crypto_shash *hash;
struct crypto_instance *inst = (void *)tfm->__crt_alg;
- struct crypto_spawn *spawn = crypto_instance_ctx(inst);
- struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
+ struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
+ struct hmac_ctx *ctx = hmac_ctx(parent);
- hash = crypto_spawn_hash(spawn);
+ hash = crypto_spawn_shash(spawn);
if (IS_ERR(hash))
return PTR_ERR(hash);
- ctx->child = hash;
+ parent->descsize = sizeof(struct shash_desc) +
+ crypto_shash_descsize(hash);
+
+ ctx->hash = hash;
return 0;
}
static void hmac_exit_tfm(struct crypto_tfm *tfm)
{
- struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
- crypto_free_hash(ctx->child);
+ struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm));
+ crypto_free_shash(ctx->hash);
}
-static void hmac_free(struct crypto_instance *inst)
+static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
{
- crypto_drop_spawn(crypto_instance_ctx(inst));
- kfree(inst);
-}
-
-static struct crypto_instance *hmac_alloc(struct rtattr **tb)
-{
- struct crypto_instance *inst;
+ struct shash_instance *inst;
struct crypto_alg *alg;
+ struct shash_alg *salg;
int err;
int ds;
+ int ss;
- err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
if (err)
- return ERR_PTR(err);
-
- alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
- CRYPTO_ALG_TYPE_HASH_MASK);
- if (IS_ERR(alg))
- return ERR_CAST(alg);
-
- inst = ERR_PTR(-EINVAL);
- ds = alg->cra_type == &crypto_hash_type ?
- alg->cra_hash.digestsize :
- alg->cra_type ?
- __crypto_shash_alg(alg)->digestsize :
- alg->cra_digest.dia_digestsize;
- if (ds > alg->cra_blocksize)
+ return err;
+
+ salg = shash_attr_alg(tb[1], 0, 0);
+ if (IS_ERR(salg))
+ return PTR_ERR(salg);
+
+ err = -EINVAL;
+ ds = salg->digestsize;
+ ss = salg->statesize;
+ alg = &salg->base;
+ if (ds > alg->cra_blocksize ||
+ ss < alg->cra_blocksize)
goto out_put_alg;
- inst = crypto_alloc_instance("hmac", alg);
+ inst = shash_alloc_instance("hmac", alg);
+ err = PTR_ERR(inst);
if (IS_ERR(inst))
goto out_put_alg;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
- inst->alg.cra_priority = alg->cra_priority;
- inst->alg.cra_blocksize = alg->cra_blocksize;
- inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_hash_type;
-
- inst->alg.cra_hash.digestsize = ds;
-
- inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
- ALIGN(inst->alg.cra_blocksize * 2 + ds,
- sizeof(void *));
-
- inst->alg.cra_init = hmac_init_tfm;
- inst->alg.cra_exit = hmac_exit_tfm;
-
- inst->alg.cra_hash.init = hmac_init;
- inst->alg.cra_hash.update = hmac_update;
- inst->alg.cra_hash.final = hmac_final;
- inst->alg.cra_hash.digest = hmac_digest;
- inst->alg.cra_hash.setkey = hmac_setkey;
+ err = crypto_init_shash_spawn(shash_instance_ctx(inst), salg,
+ shash_crypto_instance(inst));
+ if (err)
+ goto out_free_inst;
+
+ inst->alg.base.cra_priority = alg->cra_priority;
+ inst->alg.base.cra_blocksize = alg->cra_blocksize;
+ inst->alg.base.cra_alignmask = alg->cra_alignmask;
+
+ ss = ALIGN(ss, alg->cra_alignmask + 1);
+ inst->alg.digestsize = ds;
+ inst->alg.statesize = ss;
+
+ inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) +
+ ALIGN(ss * 2, crypto_tfm_ctx_alignment());
+
+ inst->alg.base.cra_init = hmac_init_tfm;
+ inst->alg.base.cra_exit = hmac_exit_tfm;
+
+ inst->alg.init = hmac_init;
+ inst->alg.update = hmac_update;
+ inst->alg.final = hmac_final;
+ inst->alg.finup = hmac_finup;
+ inst->alg.export = hmac_export;
+ inst->alg.import = hmac_import;
+ inst->alg.setkey = hmac_setkey;
+
+ err = shash_register_instance(tmpl, inst);
+ if (err) {
+out_free_inst:
+ shash_free_instance(shash_crypto_instance(inst));
+ }
out_put_alg:
crypto_mod_put(alg);
- return inst;
+ return err;
}
static struct crypto_template hmac_tmpl = {
.name = "hmac",
- .alloc = hmac_alloc,
- .free = hmac_free,
+ .create = hmac_create,
+ .free = shash_free_instance,
.module = THIS_MODULE,
};
diff --git a/crypto/internal.h b/crypto/internal.h
index 113579a82dff..2d226362e594 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -25,12 +25,7 @@
#include <linux/notifier.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
-
-#ifdef CONFIG_CRYPTO_FIPS
-extern int fips_enabled;
-#else
-#define fips_enabled 0
-#endif
+#include <linux/fips.h>
/* Crypto notification events. */
enum {
@@ -65,18 +60,6 @@ static inline void crypto_exit_proc(void)
{ }
#endif
-static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg)
-{
- unsigned int len = alg->cra_ctxsize;
-
- if (alg->cra_alignmask) {
- len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
- len += alg->cra_digest.dia_digestsize;
- }
-
- return len;
-}
-
static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
@@ -91,12 +74,9 @@ struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask);
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
-int crypto_init_digest_ops(struct crypto_tfm *tfm);
-int crypto_init_digest_ops_async(struct crypto_tfm *tfm);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
int crypto_init_compress_ops(struct crypto_tfm *tfm);
-void crypto_exit_digest_ops(struct crypto_tfm *tfm);
void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
void crypto_exit_compress_ops(struct crypto_tfm *tfm);
@@ -111,12 +91,12 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
u32 mask);
void *crypto_create_tfm(struct crypto_alg *alg,
const struct crypto_type *frontend);
+struct crypto_alg *crypto_find_alg(const char *alg_name,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask);
void *crypto_alloc_tfm(const char *alg_name,
const struct crypto_type *frontend, u32 type, u32 mask);
-int crypto_register_instance(struct crypto_template *tmpl,
- struct crypto_instance *inst);
-
int crypto_register_notifier(struct notifier_block *nb);
int crypto_unregister_notifier(struct notifier_block *nb);
int crypto_probing_notify(unsigned long val, void *v);
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
index bcadc03726b7..f7c4a7d7412e 100644
--- a/crypto/pcompress.c
+++ b/crypto/pcompress.c
@@ -36,14 +36,12 @@ static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
return 0;
}
-static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg,
- const struct crypto_type *frontend)
+static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}
-static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm,
- const struct crypto_type *frontend)
+static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm)
{
return 0;
}
diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c
index 9efef20454cb..0416091bf45a 100644
--- a/crypto/sha1_generic.c
+++ b/crypto/sha1_generic.c
@@ -25,31 +25,21 @@
#include <crypto/sha.h>
#include <asm/byteorder.h>
-struct sha1_ctx {
- u64 count;
- u32 state[5];
- u8 buffer[64];
-};
-
static int sha1_init(struct shash_desc *desc)
{
- struct sha1_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *sctx = shash_desc_ctx(desc);
- static const struct sha1_ctx initstate = {
- 0,
- { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
- { 0, }
+ *sctx = (struct sha1_state){
+ .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
};
- *sctx = initstate;
-
return 0;
}
static int sha1_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
- struct sha1_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *sctx = shash_desc_ctx(desc);
unsigned int partial, done;
const u8 *src;
@@ -85,7 +75,7 @@ static int sha1_update(struct shash_desc *desc, const u8 *data,
/* Add padding and return the message digest. */
static int sha1_final(struct shash_desc *desc, u8 *out)
{
- struct sha1_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *sctx = shash_desc_ctx(desc);
__be32 *dst = (__be32 *)out;
u32 i, index, padlen;
__be64 bits;
@@ -111,12 +101,31 @@ static int sha1_final(struct shash_desc *desc, u8 *out)
return 0;
}
+static int sha1_export(struct shash_desc *desc, void *out)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(out, sctx, sizeof(*sctx));
+ return 0;
+}
+
+static int sha1_import(struct shash_desc *desc, const void *in)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(sctx, in, sizeof(*sctx));
+ return 0;
+}
+
static struct shash_alg alg = {
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_init,
.update = sha1_update,
.final = sha1_final,
- .descsize = sizeof(struct sha1_ctx),
+ .export = sha1_export,
+ .import = sha1_import,
+ .descsize = sizeof(struct sha1_state),
+ .statesize = sizeof(struct sha1_state),
.base = {
.cra_name = "sha1",
.cra_driver_name= "sha1-generic",
diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c
index 6349d8339d37..c48459ebf05b 100644
--- a/crypto/sha256_generic.c
+++ b/crypto/sha256_generic.c
@@ -25,12 +25,6 @@
#include <crypto/sha.h>
#include <asm/byteorder.h>
-struct sha256_ctx {
- u32 count[2];
- u32 state[8];
- u8 buf[128];
-};
-
static inline u32 Ch(u32 x, u32 y, u32 z)
{
return z ^ (x & (y ^ z));
@@ -222,7 +216,7 @@ static void sha256_transform(u32 *state, const u8 *input)
static int sha224_init(struct shash_desc *desc)
{
- struct sha256_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sctx = shash_desc_ctx(desc);
sctx->state[0] = SHA224_H0;
sctx->state[1] = SHA224_H1;
sctx->state[2] = SHA224_H2;
@@ -231,15 +225,14 @@ static int sha224_init(struct shash_desc *desc)
sctx->state[5] = SHA224_H5;
sctx->state[6] = SHA224_H6;
sctx->state[7] = SHA224_H7;
- sctx->count[0] = 0;
- sctx->count[1] = 0;
+ sctx->count = 0;
return 0;
}
static int sha256_init(struct shash_desc *desc)
{
- struct sha256_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sctx = shash_desc_ctx(desc);
sctx->state[0] = SHA256_H0;
sctx->state[1] = SHA256_H1;
sctx->state[2] = SHA256_H2;
@@ -248,7 +241,7 @@ static int sha256_init(struct shash_desc *desc)
sctx->state[5] = SHA256_H5;
sctx->state[6] = SHA256_H6;
sctx->state[7] = SHA256_H7;
- sctx->count[0] = sctx->count[1] = 0;
+ sctx->count = 0;
return 0;
}
@@ -256,58 +249,54 @@ static int sha256_init(struct shash_desc *desc)
static int sha256_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
- struct sha256_ctx *sctx = shash_desc_ctx(desc);
- unsigned int i, index, part_len;
-
- /* Compute number of bytes mod 128 */
- index = (unsigned int)((sctx->count[0] >> 3) & 0x3f);
-
- /* Update number of bits */
- if ((sctx->count[0] += (len << 3)) < (len << 3)) {
- sctx->count[1]++;
- sctx->count[1] += (len >> 29);
- }
-
- part_len = 64 - index;
-
- /* Transform as many times as possible. */
- if (len >= part_len) {
- memcpy(&sctx->buf[index], data, part_len);
- sha256_transform(sctx->state, sctx->buf);
-
- for (i = part_len; i + 63 < len; i += 64)
- sha256_transform(sctx->state, &data[i]);
- index = 0;
- } else {
- i = 0;
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ unsigned int partial, done;
+ const u8 *src;
+
+ partial = sctx->count & 0x3f;
+ sctx->count += len;
+ done = 0;
+ src = data;
+
+ if ((partial + len) > 63) {
+ if (partial) {
+ done = -partial;
+ memcpy(sctx->buf + partial, data, done + 64);
+ src = sctx->buf;
+ }
+
+ do {
+ sha256_transform(sctx->state, src);
+ done += 64;
+ src = data + done;
+ } while (done + 63 < len);
+
+ partial = 0;
}
-
- /* Buffer remaining input */
- memcpy(&sctx->buf[index], &data[i], len-i);
+ memcpy(sctx->buf + partial, src, len - done);
return 0;
}
static int sha256_final(struct shash_desc *desc, u8 *out)
{
- struct sha256_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sctx = shash_desc_ctx(desc);
__be32 *dst = (__be32 *)out;
- __be32 bits[2];
+ __be64 bits;
unsigned int index, pad_len;
int i;
static const u8 padding[64] = { 0x80, };
/* Save number of bits */
- bits[1] = cpu_to_be32(sctx->count[0]);
- bits[0] = cpu_to_be32(sctx->count[1]);
+ bits = cpu_to_be64(sctx->count << 3);
/* Pad out to 56 mod 64. */
- index = (sctx->count[0] >> 3) & 0x3f;
+ index = sctx->count & 0x3f;
pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
sha256_update(desc, padding, pad_len);
/* Append length (before padding) */
- sha256_update(desc, (const u8 *)bits, sizeof(bits));
+ sha256_update(desc, (const u8 *)&bits, sizeof(bits));
/* Store state in digest */
for (i = 0; i < 8; i++)
@@ -331,12 +320,31 @@ static int sha224_final(struct shash_desc *desc, u8 *hash)
return 0;
}
+static int sha256_export(struct shash_desc *desc, void *out)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(out, sctx, sizeof(*sctx));
+ return 0;
+}
+
+static int sha256_import(struct shash_desc *desc, const void *in)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(sctx, in, sizeof(*sctx));
+ return 0;
+}
+
static struct shash_alg sha256 = {
.digestsize = SHA256_DIGEST_SIZE,
.init = sha256_init,
.update = sha256_update,
.final = sha256_final,
- .descsize = sizeof(struct sha256_ctx),
+ .export = sha256_export,
+ .import = sha256_import,
+ .descsize = sizeof(struct sha256_state),
+ .statesize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha256",
.cra_driver_name= "sha256-generic",
@@ -351,7 +359,7 @@ static struct shash_alg sha224 = {
.init = sha224_init,
.update = sha256_update,
.final = sha224_final,
- .descsize = sizeof(struct sha256_ctx),
+ .descsize = sizeof(struct sha256_state),
.base = {
.cra_name = "sha224",
.cra_driver_name= "sha224-generic",
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index 3bea38d12242..9ed9f60316e5 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -21,12 +21,6 @@
#include <linux/percpu.h>
#include <asm/byteorder.h>
-struct sha512_ctx {
- u64 state[8];
- u32 count[4];
- u8 buf[128];
-};
-
static DEFINE_PER_CPU(u64[80], msg_schedule);
static inline u64 Ch(u64 x, u64 y, u64 z)
@@ -141,7 +135,7 @@ sha512_transform(u64 *state, const u8 *input)
static int
sha512_init(struct shash_desc *desc)
{
- struct sha512_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *sctx = shash_desc_ctx(desc);
sctx->state[0] = SHA512_H0;
sctx->state[1] = SHA512_H1;
sctx->state[2] = SHA512_H2;
@@ -150,7 +144,7 @@ sha512_init(struct shash_desc *desc)
sctx->state[5] = SHA512_H5;
sctx->state[6] = SHA512_H6;
sctx->state[7] = SHA512_H7;
- sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
+ sctx->count[0] = sctx->count[1] = 0;
return 0;
}
@@ -158,7 +152,7 @@ sha512_init(struct shash_desc *desc)
static int
sha384_init(struct shash_desc *desc)
{
- struct sha512_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *sctx = shash_desc_ctx(desc);
sctx->state[0] = SHA384_H0;
sctx->state[1] = SHA384_H1;
sctx->state[2] = SHA384_H2;
@@ -167,7 +161,7 @@ sha384_init(struct shash_desc *desc)
sctx->state[5] = SHA384_H5;
sctx->state[6] = SHA384_H6;
sctx->state[7] = SHA384_H7;
- sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
+ sctx->count[0] = sctx->count[1] = 0;
return 0;
}
@@ -175,20 +169,16 @@ sha384_init(struct shash_desc *desc)
static int
sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len)
{
- struct sha512_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *sctx = shash_desc_ctx(desc);
unsigned int i, index, part_len;
/* Compute number of bytes mod 128 */
- index = (unsigned int)((sctx->count[0] >> 3) & 0x7F);
-
- /* Update number of bits */
- if ((sctx->count[0] += (len << 3)) < (len << 3)) {
- if ((sctx->count[1] += 1) < 1)
- if ((sctx->count[2] += 1) < 1)
- sctx->count[3]++;
- sctx->count[1] += (len >> 29);
- }
+ index = sctx->count[0] & 0x7f;
+
+ /* Update number of bytes */
+ if (!(sctx->count[0] += len))
+ sctx->count[1]++;
part_len = 128 - index;
@@ -214,21 +204,19 @@ sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len)
static int
sha512_final(struct shash_desc *desc, u8 *hash)
{
- struct sha512_ctx *sctx = shash_desc_ctx(desc);
+ struct sha512_state *sctx = shash_desc_ctx(desc);
static u8 padding[128] = { 0x80, };
__be64 *dst = (__be64 *)hash;
- __be32 bits[4];
+ __be64 bits[2];
unsigned int index, pad_len;
int i;
/* Save number of bits */
- bits[3] = cpu_to_be32(sctx->count[0]);
- bits[2] = cpu_to_be32(sctx->count[1]);
- bits[1] = cpu_to_be32(sctx->count[2]);
- bits[0] = cpu_to_be32(sctx->count[3]);
+ bits[1] = cpu_to_be64(sctx->count[0] << 3);
+ bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
/* Pad out to 112 mod 128. */
- index = (sctx->count[0] >> 3) & 0x7f;
+ index = sctx->count[0] & 0x7f;
pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
sha512_update(desc, padding, pad_len);
@@ -240,7 +228,7 @@ sha512_final(struct shash_desc *desc, u8 *hash)
dst[i] = cpu_to_be64(sctx->state[i]);
/* Zeroize sensitive information. */
- memset(sctx, 0, sizeof(struct sha512_ctx));
+ memset(sctx, 0, sizeof(struct sha512_state));
return 0;
}
@@ -262,7 +250,7 @@ static struct shash_alg sha512 = {
.init = sha512_init,
.update = sha512_update,
.final = sha512_final,
- .descsize = sizeof(struct sha512_ctx),
+ .descsize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha512",
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
@@ -276,7 +264,7 @@ static struct shash_alg sha384 = {
.init = sha384_init,
.update = sha512_update,
.final = sha384_final,
- .descsize = sizeof(struct sha512_ctx),
+ .descsize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha384",
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
diff --git a/crypto/shash.c b/crypto/shash.c
index 2ccc8b0076ce..91f7b9d83881 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -22,6 +22,12 @@
static const struct crypto_type crypto_shash_type;
+static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return -ENOSYS;
+}
+
static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
unsigned int keylen)
{
@@ -39,8 +45,7 @@ static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
memcpy(alignbuffer, key, keylen);
err = shash->setkey(tfm, alignbuffer, keylen);
- memset(alignbuffer, 0, keylen);
- kfree(buffer);
+ kzfree(buffer);
return err;
}
@@ -50,9 +55,6 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned long alignmask = crypto_shash_alignmask(tfm);
- if (!shash->setkey)
- return -ENOSYS;
-
if ((unsigned long)key & alignmask)
return shash_setkey_unaligned(tfm, key, keylen);
@@ -74,15 +76,19 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
unsigned long alignmask = crypto_shash_alignmask(tfm);
unsigned int unaligned_len = alignmask + 1 -
((unsigned long)data & alignmask);
- u8 buf[shash_align_buffer_size(unaligned_len, alignmask)]
+ u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)]
__attribute__ ((aligned));
+ u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
+ int err;
if (unaligned_len > len)
unaligned_len = len;
memcpy(buf, data, unaligned_len);
+ err = shash->update(desc, buf, unaligned_len);
+ memset(buf, 0, unaligned_len);
- return shash->update(desc, buf, unaligned_len) ?:
+ return err ?:
shash->update(desc, data + unaligned_len, len - unaligned_len);
}
@@ -106,12 +112,19 @@ static int shash_final_unaligned(struct shash_desc *desc, u8 *out)
unsigned long alignmask = crypto_shash_alignmask(tfm);
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned int ds = crypto_shash_digestsize(tfm);
- u8 buf[shash_align_buffer_size(ds, alignmask)]
+ u8 ubuf[shash_align_buffer_size(ds, alignmask)]
__attribute__ ((aligned));
+ u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
int err;
err = shash->final(desc, buf);
+ if (err)
+ goto out;
+
memcpy(out, buf, ds);
+
+out:
+ memset(buf, 0, ds);
return err;
}
@@ -142,8 +155,7 @@ int crypto_shash_finup(struct shash_desc *desc, const u8 *data,
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned long alignmask = crypto_shash_alignmask(tfm);
- if (((unsigned long)data | (unsigned long)out) & alignmask ||
- !shash->finup)
+ if (((unsigned long)data | (unsigned long)out) & alignmask)
return shash_finup_unaligned(desc, data, len, out);
return shash->finup(desc, data, len, out);
@@ -154,8 +166,7 @@ static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out)
{
return crypto_shash_init(desc) ?:
- crypto_shash_update(desc, data, len) ?:
- crypto_shash_final(desc, out);
+ crypto_shash_finup(desc, data, len, out);
}
int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
@@ -165,27 +176,24 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
struct shash_alg *shash = crypto_shash_alg(tfm);
unsigned long alignmask = crypto_shash_alignmask(tfm);
- if (((unsigned long)data | (unsigned long)out) & alignmask ||
- !shash->digest)
+ if (((unsigned long)data | (unsigned long)out) & alignmask)
return shash_digest_unaligned(desc, data, len, out);
return shash->digest(desc, data, len, out);
}
EXPORT_SYMBOL_GPL(crypto_shash_digest);
-int crypto_shash_import(struct shash_desc *desc, const u8 *in)
+static int shash_default_export(struct shash_desc *desc, void *out)
{
- struct crypto_shash *tfm = desc->tfm;
- struct shash_alg *alg = crypto_shash_alg(tfm);
-
- memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(tfm));
-
- if (alg->reinit)
- alg->reinit(desc);
+ memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm));
+ return 0;
+}
+static int shash_default_import(struct shash_desc *desc, const void *in)
+{
+ memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(desc->tfm));
return 0;
}
-EXPORT_SYMBOL_GPL(crypto_shash_import);
static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
@@ -206,9 +214,8 @@ static int shash_async_init(struct ahash_request *req)
return crypto_shash_init(desc);
}
-static int shash_async_update(struct ahash_request *req)
+int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc)
{
- struct shash_desc *desc = ahash_request_ctx(req);
struct crypto_hash_walk walk;
int nbytes;
@@ -218,13 +225,51 @@ static int shash_async_update(struct ahash_request *req)
return nbytes;
}
+EXPORT_SYMBOL_GPL(shash_ahash_update);
+
+static int shash_async_update(struct ahash_request *req)
+{
+ return shash_ahash_update(req, ahash_request_ctx(req));
+}
static int shash_async_final(struct ahash_request *req)
{
return crypto_shash_final(ahash_request_ctx(req), req->result);
}
-static int shash_async_digest(struct ahash_request *req)
+int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc)
+{
+ struct crypto_hash_walk walk;
+ int nbytes;
+
+ nbytes = crypto_hash_walk_first(req, &walk);
+ if (!nbytes)
+ return crypto_shash_final(desc, req->result);
+
+ do {
+ nbytes = crypto_hash_walk_last(&walk) ?
+ crypto_shash_finup(desc, walk.data, nbytes,
+ req->result) :
+ crypto_shash_update(desc, walk.data, nbytes);
+ nbytes = crypto_hash_walk_done(&walk, nbytes);
+ } while (nbytes > 0);
+
+ return nbytes;
+}
+EXPORT_SYMBOL_GPL(shash_ahash_finup);
+
+static int shash_async_finup(struct ahash_request *req)
+{
+ struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+ struct shash_desc *desc = ahash_request_ctx(req);
+
+ desc->tfm = *ctx;
+ desc->flags = req->base.flags;
+
+ return shash_ahash_finup(req, desc);
+}
+
+int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
{
struct scatterlist *sg = req->src;
unsigned int offset = sg->offset;
@@ -232,34 +277,40 @@ static int shash_async_digest(struct ahash_request *req)
int err;
if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
- struct crypto_shash **ctx =
- crypto_ahash_ctx(crypto_ahash_reqtfm(req));
- struct shash_desc *desc = ahash_request_ctx(req);
void *data;
- desc->tfm = *ctx;
- desc->flags = req->base.flags;
-
data = crypto_kmap(sg_page(sg), 0);
err = crypto_shash_digest(desc, data + offset, nbytes,
req->result);
crypto_kunmap(data, 0);
crypto_yield(desc->flags);
- goto out;
- }
+ } else
+ err = crypto_shash_init(desc) ?:
+ shash_ahash_finup(req, desc);
- err = shash_async_init(req);
- if (err)
- goto out;
+ return err;
+}
+EXPORT_SYMBOL_GPL(shash_ahash_digest);
- err = shash_async_update(req);
- if (err)
- goto out;
+static int shash_async_digest(struct ahash_request *req)
+{
+ struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+ struct shash_desc *desc = ahash_request_ctx(req);
- err = shash_async_final(req);
+ desc->tfm = *ctx;
+ desc->flags = req->base.flags;
-out:
- return err;
+ return shash_ahash_digest(req, desc);
+}
+
+static int shash_async_export(struct ahash_request *req, void *out)
+{
+ return crypto_shash_export(ahash_request_ctx(req), out);
+}
+
+static int shash_async_import(struct ahash_request *req, const void *in)
+{
+ return crypto_shash_import(ahash_request_ctx(req), in);
}
static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
@@ -269,11 +320,11 @@ static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
crypto_free_shash(*ctx);
}
-static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
+int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
{
struct crypto_alg *calg = tfm->__crt_alg;
struct shash_alg *alg = __crypto_shash_alg(calg);
- struct ahash_tfm *crt = &tfm->crt_ahash;
+ struct crypto_ahash *crt = __crypto_ahash_cast(tfm);
struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
struct crypto_shash *shash;
@@ -291,11 +342,17 @@ static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
crt->init = shash_async_init;
crt->update = shash_async_update;
- crt->final = shash_async_final;
+ crt->final = shash_async_final;
+ crt->finup = shash_async_finup;
crt->digest = shash_async_digest;
- crt->setkey = shash_async_setkey;
- crt->digestsize = alg->digestsize;
+ if (alg->setkey)
+ crt->setkey = shash_async_setkey;
+ if (alg->export)
+ crt->export = shash_async_export;
+ if (alg->import)
+ crt->import = shash_async_import;
+
crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash);
return 0;
@@ -304,14 +361,16 @@ static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
static int shash_compat_setkey(struct crypto_hash *tfm, const u8 *key,
unsigned int keylen)
{
- struct shash_desc *desc = crypto_hash_ctx(tfm);
+ struct shash_desc **descp = crypto_hash_ctx(tfm);
+ struct shash_desc *desc = *descp;
return crypto_shash_setkey(desc->tfm, key, keylen);
}
static int shash_compat_init(struct hash_desc *hdesc)
{
- struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc *desc = *descp;
desc->flags = hdesc->flags;
@@ -321,7 +380,8 @@ static int shash_compat_init(struct hash_desc *hdesc)
static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg,
unsigned int len)
{
- struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc *desc = *descp;
struct crypto_hash_walk walk;
int nbytes;
@@ -334,7 +394,9 @@ static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg,
static int shash_compat_final(struct hash_desc *hdesc, u8 *out)
{
- return crypto_shash_final(crypto_hash_ctx(hdesc->tfm), out);
+ struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
+
+ return crypto_shash_final(*descp, out);
}
static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg,
@@ -344,7 +406,8 @@ static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg,
int err;
if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
- struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
+ struct shash_desc *desc = *descp;
void *data;
desc->flags = hdesc->flags;
@@ -372,9 +435,11 @@ out:
static void crypto_exit_shash_ops_compat(struct crypto_tfm *tfm)
{
- struct shash_desc *desc= crypto_tfm_ctx(tfm);
+ struct shash_desc **descp = crypto_tfm_ctx(tfm);
+ struct shash_desc *desc = *descp;
crypto_free_shash(desc->tfm);
+ kzfree(desc);
}
static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
@@ -382,8 +447,9 @@ static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
struct hash_tfm *crt = &tfm->crt_hash;
struct crypto_alg *calg = tfm->__crt_alg;
struct shash_alg *alg = __crypto_shash_alg(calg);
- struct shash_desc *desc = crypto_tfm_ctx(tfm);
+ struct shash_desc **descp = crypto_tfm_ctx(tfm);
struct crypto_shash *shash;
+ struct shash_desc *desc;
if (!crypto_mod_get(calg))
return -EAGAIN;
@@ -394,6 +460,14 @@ static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
return PTR_ERR(shash);
}
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(shash),
+ GFP_KERNEL);
+ if (!desc) {
+ crypto_free_shash(shash);
+ return -ENOMEM;
+ }
+
+ *descp = desc;
desc->tfm = shash;
tfm->exit = crypto_exit_shash_ops_compat;
@@ -413,8 +487,6 @@ static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
switch (mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_HASH_MASK:
return crypto_init_shash_ops_compat(tfm);
- case CRYPTO_ALG_TYPE_AHASH_MASK:
- return crypto_init_shash_ops_async(tfm);
}
return -EINVAL;
@@ -423,26 +495,23 @@ static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
u32 mask)
{
- struct shash_alg *salg = __crypto_shash_alg(alg);
-
switch (mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_HASH_MASK:
- return sizeof(struct shash_desc) + salg->descsize;
- case CRYPTO_ALG_TYPE_AHASH_MASK:
- return sizeof(struct crypto_shash *);
+ return sizeof(struct shash_desc *);
}
return 0;
}
-static int crypto_shash_init_tfm(struct crypto_tfm *tfm,
- const struct crypto_type *frontend)
+static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
{
+ struct crypto_shash *hash = __crypto_shash_cast(tfm);
+
+ hash->descsize = crypto_shash_alg(hash)->descsize;
return 0;
}
-static unsigned int crypto_shash_extsize(struct crypto_alg *alg,
- const struct crypto_type *frontend)
+static unsigned int crypto_shash_extsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}
@@ -456,7 +525,6 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
seq_printf(m, "type : shash\n");
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
seq_printf(m, "digestsize : %u\n", salg->digestsize);
- seq_printf(m, "descsize : %u\n", salg->descsize);
}
static const struct crypto_type crypto_shash_type = {
@@ -480,18 +548,43 @@ struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
}
EXPORT_SYMBOL_GPL(crypto_alloc_shash);
-int crypto_register_shash(struct shash_alg *alg)
+static int shash_prepare_alg(struct shash_alg *alg)
{
struct crypto_alg *base = &alg->base;
if (alg->digestsize > PAGE_SIZE / 8 ||
- alg->descsize > PAGE_SIZE / 8)
+ alg->descsize > PAGE_SIZE / 8 ||
+ alg->statesize > PAGE_SIZE / 8)
return -EINVAL;
base->cra_type = &crypto_shash_type;
base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
base->cra_flags |= CRYPTO_ALG_TYPE_SHASH;
+ if (!alg->finup)
+ alg->finup = shash_finup_unaligned;
+ if (!alg->digest)
+ alg->digest = shash_digest_unaligned;
+ if (!alg->export) {
+ alg->export = shash_default_export;
+ alg->import = shash_default_import;
+ alg->statesize = alg->descsize;
+ }
+ if (!alg->setkey)
+ alg->setkey = shash_no_setkey;
+
+ return 0;
+}
+
+int crypto_register_shash(struct shash_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+ int err;
+
+ err = shash_prepare_alg(alg);
+ if (err)
+ return err;
+
return crypto_register_alg(base);
}
EXPORT_SYMBOL_GPL(crypto_register_shash);
@@ -502,5 +595,44 @@ int crypto_unregister_shash(struct shash_alg *alg)
}
EXPORT_SYMBOL_GPL(crypto_unregister_shash);
+int shash_register_instance(struct crypto_template *tmpl,
+ struct shash_instance *inst)
+{
+ int err;
+
+ err = shash_prepare_alg(&inst->alg);
+ if (err)
+ return err;
+
+ return crypto_register_instance(tmpl, shash_crypto_instance(inst));
+}
+EXPORT_SYMBOL_GPL(shash_register_instance);
+
+void shash_free_instance(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(shash_instance(inst));
+}
+EXPORT_SYMBOL_GPL(shash_free_instance);
+
+int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn,
+ struct shash_alg *alg,
+ struct crypto_instance *inst)
+{
+ return crypto_init_spawn2(&spawn->base, &alg->base, inst,
+ &crypto_shash_type);
+}
+EXPORT_SYMBOL_GPL(crypto_init_shash_spawn);
+
+struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+{
+ struct crypto_alg *alg;
+
+ alg = crypto_attr_alg2(rta, &crypto_shash_type, type, mask);
+ return IS_ERR(alg) ? ERR_CAST(alg) :
+ container_of(alg, struct shash_alg, base);
+}
+EXPORT_SYMBOL_GPL(shash_attr_alg);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synchronous cryptographic hash type");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index d59ba5079d14..5a375e819d5d 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -45,6 +45,9 @@
*/
static unsigned int sec;
+static char *alg = NULL;
+static u32 type;
+static u32 mask;
static int mode;
static char *tvmem[TVMEMSIZE];
@@ -885,6 +888,12 @@ static int do_test(int m)
return ret;
}
+static int do_alg_test(const char *alg, u32 type, u32 mask)
+{
+ return crypto_has_alg(alg, type, mask ?: CRYPTO_ALG_TYPE_MASK) ?
+ 0 : -ENOENT;
+}
+
static int __init tcrypt_mod_init(void)
{
int err = -ENOMEM;
@@ -896,7 +905,11 @@ static int __init tcrypt_mod_init(void)
goto err_free_tv;
}
- err = do_test(mode);
+ if (alg)
+ err = do_alg_test(alg, type, mask);
+ else
+ err = do_test(mode);
+
if (err) {
printk(KERN_ERR "tcrypt: one or more tests failed!\n");
goto err_free_tv;
@@ -928,6 +941,9 @@ static void __exit tcrypt_mod_fini(void) { }
module_init(tcrypt_mod_init);
module_exit(tcrypt_mod_fini);
+module_param(alg, charp, 0);
+module_param(type, uint, 0);
+module_param(mask, uint, 0);
module_param(mode, int, 0);
module_param(sec, uint, 0);
MODULE_PARM_DESC(sec, "Length in seconds of speed tests "
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index e9e9d84293b9..29b228d9b1a2 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -190,10 +190,6 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
hash_buff = xbuf[0];
- ret = -EINVAL;
- if (WARN_ON(template[i].psize > PAGE_SIZE))
- goto out;
-
memcpy(hash_buff, template[i].plaintext, template[i].psize);
sg_init_one(&sg[0], hash_buff, template[i].psize);
@@ -2348,6 +2344,7 @@ static int alg_find_test(const char *alg)
int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
{
int i;
+ int j;
int rc;
if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
@@ -2369,14 +2366,22 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
}
i = alg_find_test(alg);
- if (i < 0)
+ j = alg_find_test(driver);
+ if (i < 0 && j < 0)
goto notest;
- if (fips_enabled && !alg_test_descs[i].fips_allowed)
+ if (fips_enabled && ((i >= 0 && !alg_test_descs[i].fips_allowed) ||
+ (j >= 0 && !alg_test_descs[j].fips_allowed)))
goto non_fips_alg;
- rc = alg_test_descs[i].test(alg_test_descs + i, driver,
- type, mask);
+ rc = 0;
+ if (i >= 0)
+ rc |= alg_test_descs[i].test(alg_test_descs + i, driver,
+ type, mask);
+ if (j >= 0)
+ rc |= alg_test_descs[j].test(alg_test_descs + j, driver,
+ type, mask);
+
test_done:
if (fips_enabled && rc)
panic("%s: %s alg self test failed in fips mode!\n", driver, alg);
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index b63b633e549c..1e30b31f33c6 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -19,211 +19,142 @@
* Kazunori Miyazawa <miyazawa@linux-ipv6.org>
*/
-#include <crypto/scatterwalk.h>
-#include <linux/crypto.h>
+#include <crypto/internal/hash.h>
#include <linux/err.h>
-#include <linux/hardirq.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/rtnetlink.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
0x02020202, 0x02020202, 0x02020202, 0x02020202,
0x03030303, 0x03030303, 0x03030303, 0x03030303};
+
/*
* +------------------------
* | <parent tfm>
* +------------------------
- * | crypto_xcbc_ctx
+ * | xcbc_tfm_ctx
* +------------------------
- * | odds (block size)
+ * | consts (block size * 2)
* +------------------------
- * | prev (block size)
+ */
+struct xcbc_tfm_ctx {
+ struct crypto_cipher *child;
+ u8 ctx[];
+};
+
+/*
* +------------------------
- * | key (block size)
+ * | <shash desc>
* +------------------------
- * | consts (block size * 3)
+ * | xcbc_desc_ctx
+ * +------------------------
+ * | odds (block size)
+ * +------------------------
+ * | prev (block size)
* +------------------------
*/
-struct crypto_xcbc_ctx {
- struct crypto_cipher *child;
- u8 *odds;
- u8 *prev;
- u8 *key;
- u8 *consts;
- void (*xor)(u8 *a, const u8 *b, unsigned int bs);
- unsigned int keylen;
+struct xcbc_desc_ctx {
unsigned int len;
+ u8 ctx[];
};
-static void xor_128(u8 *a, const u8 *b, unsigned int bs)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
- ((u32 *)a)[2] ^= ((u32 *)b)[2];
- ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
-static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent,
- struct crypto_xcbc_ctx *ctx)
+static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
+ const u8 *inkey, unsigned int keylen)
{
- int bs = crypto_hash_blocksize(parent);
+ unsigned long alignmask = crypto_shash_alignmask(parent);
+ struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
+ int bs = crypto_shash_blocksize(parent);
+ u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
int err = 0;
u8 key1[bs];
- if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen)))
- return err;
+ if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
+ return err;
- crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts);
+ crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs);
+ crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2);
+ crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks);
return crypto_cipher_setkey(ctx->child, key1, bs);
-}
-
-static int crypto_xcbc_digest_setkey(struct crypto_hash *parent,
- const u8 *inkey, unsigned int keylen)
-{
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
-
- if (keylen != crypto_cipher_blocksize(ctx->child))
- return -EINVAL;
- ctx->keylen = keylen;
- memcpy(ctx->key, inkey, keylen);
- ctx->consts = (u8*)ks;
-
- return _crypto_xcbc_digest_setkey(parent, ctx);
}
-static int crypto_xcbc_digest_init(struct hash_desc *pdesc)
+static int crypto_xcbc_digest_init(struct shash_desc *pdesc)
{
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(pdesc->tfm);
- int bs = crypto_hash_blocksize(pdesc->tfm);
+ unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm);
+ struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
+ int bs = crypto_shash_blocksize(pdesc->tfm);
+ u8 *prev = PTR_ALIGN(&ctx->ctx[0], alignmask + 1) + bs;
ctx->len = 0;
- memset(ctx->odds, 0, bs);
- memset(ctx->prev, 0, bs);
+ memset(prev, 0, bs);
return 0;
}
-static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
- struct scatterlist *sg,
- unsigned int nbytes)
+static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
+ unsigned int len)
{
- struct crypto_hash *parent = pdesc->tfm;
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
- struct crypto_cipher *tfm = ctx->child;
- int bs = crypto_hash_blocksize(parent);
-
- for (;;) {
- struct page *pg = sg_page(sg);
- unsigned int offset = sg->offset;
- unsigned int slen = sg->length;
-
- if (unlikely(slen > nbytes))
- slen = nbytes;
-
- nbytes -= slen;
-
- while (slen > 0) {
- unsigned int len = min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
- char *p = crypto_kmap(pg, 0) + offset;
-
- /* checking the data can fill the block */
- if ((ctx->len + len) <= bs) {
- memcpy(ctx->odds + ctx->len, p, len);
- ctx->len += len;
- slen -= len;
-
- /* checking the rest of the page */
- if (len + offset >= PAGE_SIZE) {
- offset = 0;
- pg++;
- } else
- offset += len;
-
- crypto_kunmap(p, 0);
- crypto_yield(pdesc->flags);
- continue;
- }
-
- /* filling odds with new data and encrypting it */
- memcpy(ctx->odds + ctx->len, p, bs - ctx->len);
- len -= bs - ctx->len;
- p += bs - ctx->len;
-
- ctx->xor(ctx->prev, ctx->odds, bs);
- crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev);
-
- /* clearing the length */
- ctx->len = 0;
-
- /* encrypting the rest of data */
- while (len > bs) {
- ctx->xor(ctx->prev, p, bs);
- crypto_cipher_encrypt_one(tfm, ctx->prev,
- ctx->prev);
- p += bs;
- len -= bs;
- }
-
- /* keeping the surplus of blocksize */
- if (len) {
- memcpy(ctx->odds, p, len);
- ctx->len = len;
- }
- crypto_kunmap(p, 0);
- crypto_yield(pdesc->flags);
- slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
- offset = 0;
- pg++;
- }
-
- if (!nbytes)
- break;
- sg = scatterwalk_sg_next(sg);
+ struct crypto_shash *parent = pdesc->tfm;
+ unsigned long alignmask = crypto_shash_alignmask(parent);
+ struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
+ struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
+ struct crypto_cipher *tfm = tctx->child;
+ int bs = crypto_shash_blocksize(parent);
+ u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
+ u8 *prev = odds + bs;
+
+ /* checking the data can fill the block */
+ if ((ctx->len + len) <= bs) {
+ memcpy(odds + ctx->len, p, len);
+ ctx->len += len;
+ return 0;
}
- return 0;
-}
+ /* filling odds with new data and encrypting it */
+ memcpy(odds + ctx->len, p, bs - ctx->len);
+ len -= bs - ctx->len;
+ p += bs - ctx->len;
-static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
- struct scatterlist *sg,
- unsigned int nbytes)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
- return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
-}
+ crypto_xor(prev, odds, bs);
+ crypto_cipher_encrypt_one(tfm, prev, prev);
-static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
-{
- struct crypto_hash *parent = pdesc->tfm;
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
- struct crypto_cipher *tfm = ctx->child;
- int bs = crypto_hash_blocksize(parent);
- int err = 0;
-
- if (ctx->len == bs) {
- u8 key2[bs];
+ /* clearing the length */
+ ctx->len = 0;
- if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
- return err;
+ /* encrypting the rest of data */
+ while (len > bs) {
+ crypto_xor(prev, p, bs);
+ crypto_cipher_encrypt_one(tfm, prev, prev);
+ p += bs;
+ len -= bs;
+ }
- crypto_cipher_encrypt_one(tfm, key2,
- (u8 *)(ctx->consts + bs));
+ /* keeping the surplus of blocksize */
+ if (len) {
+ memcpy(odds, p, len);
+ ctx->len = len;
+ }
- ctx->xor(ctx->prev, ctx->odds, bs);
- ctx->xor(ctx->prev, key2, bs);
- _crypto_xcbc_digest_setkey(parent, ctx);
+ return 0;
+}
- crypto_cipher_encrypt_one(tfm, out, ctx->prev);
- } else {
- u8 key3[bs];
+static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out)
+{
+ struct crypto_shash *parent = pdesc->tfm;
+ unsigned long alignmask = crypto_shash_alignmask(parent);
+ struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
+ struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc);
+ struct crypto_cipher *tfm = tctx->child;
+ int bs = crypto_shash_blocksize(parent);
+ u8 *consts = PTR_ALIGN(&tctx->ctx[0], alignmask + 1);
+ u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1);
+ u8 *prev = odds + bs;
+ unsigned int offset = 0;
+
+ if (ctx->len != bs) {
unsigned int rlen;
- u8 *p = ctx->odds + ctx->len;
+ u8 *p = odds + ctx->len;
+
*p = 0x80;
p++;
@@ -231,32 +162,15 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
if (rlen)
memset(p, 0, rlen);
- if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
- return err;
-
- crypto_cipher_encrypt_one(tfm, key3,
- (u8 *)(ctx->consts + bs * 2));
-
- ctx->xor(ctx->prev, ctx->odds, bs);
- ctx->xor(ctx->prev, key3, bs);
-
- _crypto_xcbc_digest_setkey(parent, ctx);
-
- crypto_cipher_encrypt_one(tfm, out, ctx->prev);
+ offset += bs;
}
- return 0;
-}
+ crypto_xor(prev, odds, bs);
+ crypto_xor(prev, consts + offset, bs);
-static int crypto_xcbc_digest(struct hash_desc *pdesc,
- struct scatterlist *sg, unsigned int nbytes, u8 *out)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
+ crypto_cipher_encrypt_one(tfm, out, prev);
- crypto_xcbc_digest_init(pdesc);
- crypto_xcbc_digest_update2(pdesc, sg, nbytes);
- return crypto_xcbc_digest_final(pdesc, out);
+ return 0;
}
static int xcbc_init_tfm(struct crypto_tfm *tfm)
@@ -264,95 +178,93 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm)
struct crypto_cipher *cipher;
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
- int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm));
+ struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
cipher = crypto_spawn_cipher(spawn);
if (IS_ERR(cipher))
return PTR_ERR(cipher);
- switch(bs) {
- case 16:
- ctx->xor = xor_128;
- break;
- default:
- return -EINVAL;
- }
-
ctx->child = cipher;
- ctx->odds = (u8*)(ctx+1);
- ctx->prev = ctx->odds + bs;
- ctx->key = ctx->prev + bs;
return 0;
};
static void xcbc_exit_tfm(struct crypto_tfm *tfm)
{
- struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
+ struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
+static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
{
- struct crypto_instance *inst;
+ struct shash_instance *inst;
struct crypto_alg *alg;
int err;
- err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
if (err)
- return ERR_PTR(err);
+ return err;
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_CAST(alg);
+ return PTR_ERR(alg);
switch(alg->cra_blocksize) {
case 16:
break;
default:
- inst = ERR_PTR(-EINVAL);
goto out_put_alg;
}
- inst = crypto_alloc_instance("xcbc", alg);
+ inst = shash_alloc_instance("xcbc", alg);
+ err = PTR_ERR(inst);
if (IS_ERR(inst))
goto out_put_alg;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
- inst->alg.cra_priority = alg->cra_priority;
- inst->alg.cra_blocksize = alg->cra_blocksize;
- inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_hash_type;
-
- inst->alg.cra_hash.digestsize = alg->cra_blocksize;
- inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) +
- ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *));
- inst->alg.cra_init = xcbc_init_tfm;
- inst->alg.cra_exit = xcbc_exit_tfm;
-
- inst->alg.cra_hash.init = crypto_xcbc_digest_init;
- inst->alg.cra_hash.update = crypto_xcbc_digest_update;
- inst->alg.cra_hash.final = crypto_xcbc_digest_final;
- inst->alg.cra_hash.digest = crypto_xcbc_digest;
- inst->alg.cra_hash.setkey = crypto_xcbc_digest_setkey;
+ err = crypto_init_spawn(shash_instance_ctx(inst), alg,
+ shash_crypto_instance(inst),
+ CRYPTO_ALG_TYPE_MASK);
+ if (err)
+ goto out_free_inst;
+
+ inst->alg.base.cra_priority = alg->cra_priority;
+ inst->alg.base.cra_blocksize = alg->cra_blocksize;
+ inst->alg.base.cra_alignmask = alg->cra_alignmask | 3;
+
+ inst->alg.digestsize = alg->cra_blocksize;
+ inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx),
+ crypto_tfm_ctx_alignment()) +
+ (alg->cra_alignmask &
+ ~(crypto_tfm_ctx_alignment() - 1)) +
+ alg->cra_blocksize * 2;
+
+ inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx),
+ alg->cra_alignmask) +
+ alg->cra_blocksize * 2;
+ inst->alg.base.cra_init = xcbc_init_tfm;
+ inst->alg.base.cra_exit = xcbc_exit_tfm;
+
+ inst->alg.init = crypto_xcbc_digest_init;
+ inst->alg.update = crypto_xcbc_digest_update;
+ inst->alg.final = crypto_xcbc_digest_final;
+ inst->alg.setkey = crypto_xcbc_digest_setkey;
+
+ err = shash_register_instance(tmpl, inst);
+ if (err) {
+out_free_inst:
+ shash_free_instance(shash_crypto_instance(inst));
+ }
out_put_alg:
crypto_mod_put(alg);
- return inst;
-}
-
-static void xcbc_free(struct crypto_instance *inst)
-{
- crypto_drop_spawn(crypto_instance_ctx(inst));
- kfree(inst);
+ return err;
}
static struct crypto_template crypto_xcbc_tmpl = {
.name = "xcbc",
- .alloc = xcbc_alloc,
- .free = xcbc_free,
+ .create = xcbc_create,
+ .free = shash_free_instance,
.module = THIS_MODULE,
};
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7ec7d88c5999..c283f3405f78 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,7 +60,11 @@ config ACPI_PROCFS
/proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
/proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
/proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
-
+ /proc/acpi/processor/*/power (/sys/devices/system/cpu/*/cpuidle/*)
+ /proc/acpi/processor/*/performance (/sys/devices/system/cpu/*/
+ cpufreq/*)
+ /proc/acpi/processor/*/throttling (/sys/class/thermal/
+ cooling_device*/*)
This option has no effect on /proc/acpi/ files
and functions which do not yet exist in /sys.
@@ -196,6 +200,17 @@ config ACPI_HOTPLUG_CPU
select ACPI_CONTAINER
default y
+config ACPI_PROCESSOR_AGGREGATOR
+ tristate "Processor Aggregator"
+ depends on ACPI_PROCESSOR
+ depends on EXPERIMENTAL
+ help
+ ACPI 4.0 defines processor Aggregator, which enables OS to perform
+ specfic 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.
+
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 03a985be3fe3..8dae61c8a176 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -61,3 +61,5 @@ obj-$(CONFIG_ACPI_SBS) += sbs.o
processor-y := processor_core.o processor_throttling.o
processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
+
+obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 7a0f4aa4fa1e..28ccdbc05ac8 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -38,6 +38,9 @@
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
+#undef PREFIX
+#define PREFIX "ACPI:memory_hp:"
+
ACPI_MODULE_NAME("acpi_memhotplug");
MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
MODULE_DESCRIPTION("Hotplug Mem Driver");
@@ -50,7 +53,6 @@ MODULE_LICENSE("GPL");
static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device, int type);
-static int acpi_memory_device_start(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
@@ -65,7 +67,6 @@ static struct acpi_driver acpi_memory_device_driver = {
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
- .start = acpi_memory_device_start,
},
};
@@ -153,6 +154,7 @@ acpi_memory_get_device(acpi_handle handle,
acpi_handle phandle;
struct acpi_device *device = NULL;
struct acpi_device *pdevice = NULL;
+ int result;
if (!acpi_bus_get_device(handle, &device) && device)
@@ -165,9 +167,9 @@ acpi_memory_get_device(acpi_handle handle,
}
/* Get the parent device */
- status = acpi_bus_get_device(phandle, &pdevice);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
+ result = acpi_bus_get_device(phandle, &pdevice);
+ if (result) {
+ printk(KERN_WARNING PREFIX "Cannot get acpi bus device");
return -EINVAL;
}
@@ -175,9 +177,9 @@ acpi_memory_get_device(acpi_handle handle,
* Now add the notified device. This creates the acpi_device
* and invokes .add function
*/
- status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
+ result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+ if (result) {
+ printk(KERN_WARNING PREFIX "Cannot add acpi bus");
return -EINVAL;
}
@@ -238,7 +240,12 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
num_enabled++;
continue;
}
-
+ /*
+ * If the memory block size is zero, please ignore it.
+ * Don't try to do the following memory hotplug flowchart.
+ */
+ if (!info->length)
+ continue;
if (node < 0)
node = memory_add_physaddr_to_nid(info->start_addr);
@@ -253,8 +260,15 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
mem_device->state = MEMORY_INVALID_STATE;
return -EINVAL;
}
-
- return result;
+ /*
+ * Sometimes the memory device will contain several memory blocks.
+ * When one memory block is hot-added to the system memory, it will
+ * be regarded as a success.
+ * Otherwise if the last memory block can't be hot-added to the system
+ * memory, it will be failure and the memory device can't be bound with
+ * driver.
+ */
+ return 0;
}
static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
@@ -415,28 +429,6 @@ static int acpi_memory_device_add(struct acpi_device *device)
printk(KERN_DEBUG "%s \n", acpi_device_name(device));
- return result;
-}
-
-static int acpi_memory_device_remove(struct acpi_device *device, int type)
-{
- struct acpi_memory_device *mem_device = NULL;
-
-
- if (!device || !acpi_driver_data(device))
- return -EINVAL;
-
- mem_device = acpi_driver_data(device);
- kfree(mem_device);
-
- return 0;
-}
-
-static int acpi_memory_device_start (struct acpi_device *device)
-{
- struct acpi_memory_device *mem_device;
- int result = 0;
-
/*
* Early boot code has recognized memory area by EFI/E820.
* If DSDT shows these memory devices on boot, hotplug is not necessary
@@ -446,8 +438,6 @@ static int acpi_memory_device_start (struct acpi_device *device)
if (!acpi_hotmem_initialized)
return 0;
- mem_device = acpi_driver_data(device);
-
if (!acpi_memory_check_device(mem_device)) {
/* call add_memory func */
result = acpi_memory_enable_device(mem_device);
@@ -458,6 +448,20 @@ static int acpi_memory_device_start (struct acpi_device *device)
return result;
}
+static int acpi_memory_device_remove(struct acpi_device *device, int type)
+{
+ struct acpi_memory_device *mem_device = NULL;
+
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ mem_device = acpi_driver_data(device);
+ kfree(mem_device);
+
+ return 0;
+}
+
/*
* Helper function to check for memory device
*/
@@ -465,26 +469,23 @@ static acpi_status is_memory_device(acpi_handle handle)
{
char *hardware_id;
acpi_status status;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info;
-
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status))
return status;
- info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID)) {
- kfree(buffer.pointer);
+ kfree(info);
return AE_ERROR;
}
- hardware_id = info->hardware_id.value;
+ hardware_id = info->hardware_id.string;
if ((hardware_id == NULL) ||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
status = AE_ERROR;
- kfree(buffer.pointer);
+ kfree(info);
return status;
}
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
new file mode 100644
index 000000000000..0d2cdb86158b
--- /dev/null
+++ b/drivers/acpi/acpi_pad.c
@@ -0,0 +1,514 @@
+/*
+ * acpi_pad.c ACPI Processor Aggregator Driver
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_PROCESSOR_AGGREGATOR_CLASS "processor_aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
+static DEFINE_MUTEX(isolated_cpus_lock);
+
+#define MWAIT_SUBSTATE_MASK (0xf)
+#define MWAIT_CSTATE_MASK (0xf)
+#define MWAIT_SUBSTATE_SIZE (4)
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
+static unsigned long power_saving_mwait_eax;
+static void power_saving_mwait_init(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int highest_cstate = 0;
+ unsigned int highest_subcstate = 0;
+ int i;
+
+ if (!boot_cpu_has(X86_FEATURE_MWAIT))
+ return;
+ if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+ return;
+
+ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+ if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+ !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+ return;
+
+ edx >>= MWAIT_SUBSTATE_SIZE;
+ for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+ if (edx & MWAIT_SUBSTATE_MASK) {
+ highest_cstate = i;
+ highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+ }
+ }
+ power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+ (highest_subcstate - 1);
+
+ for_each_online_cpu(i)
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &i);
+
+#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ case X86_VENDOR_INTEL:
+ /*
+ * AMD Fam10h TSC will tick in all
+ * C/P/S0/S1 states when this bit is set.
+ */
+ if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ return;
+
+ /*FALL THROUGH*/
+ default:
+ /* TSC could halt in idle, so notify users */
+ mark_tsc_unstable("TSC halts in idle");
+ }
+#endif
+}
+
+static unsigned long cpu_weight[NR_CPUS];
+static int tsk_in_cpu[NR_CPUS] = {[0 ... NR_CPUS-1] = -1};
+static DECLARE_BITMAP(pad_busy_cpus_bits, NR_CPUS);
+static void round_robin_cpu(unsigned int tsk_index)
+{
+ struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+ cpumask_var_t tmp;
+ int cpu;
+ unsigned long min_weight = -1, preferred_cpu;
+
+ if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
+ return;
+
+ mutex_lock(&isolated_cpus_lock);
+ cpumask_clear(tmp);
+ for_each_cpu(cpu, pad_busy_cpus)
+ cpumask_or(tmp, tmp, topology_thread_cpumask(cpu));
+ cpumask_andnot(tmp, cpu_online_mask, tmp);
+ /* avoid HT sibilings if possible */
+ if (cpumask_empty(tmp))
+ cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus);
+ if (cpumask_empty(tmp)) {
+ mutex_unlock(&isolated_cpus_lock);
+ return;
+ }
+ for_each_cpu(cpu, tmp) {
+ if (cpu_weight[cpu] < min_weight) {
+ min_weight = cpu_weight[cpu];
+ preferred_cpu = cpu;
+ }
+ }
+
+ if (tsk_in_cpu[tsk_index] != -1)
+ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+ tsk_in_cpu[tsk_index] = preferred_cpu;
+ cpumask_set_cpu(preferred_cpu, pad_busy_cpus);
+ cpu_weight[preferred_cpu]++;
+ mutex_unlock(&isolated_cpus_lock);
+
+ set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu));
+}
+
+static void exit_round_robin(unsigned int tsk_index)
+{
+ struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+ tsk_in_cpu[tsk_index] = -1;
+}
+
+static unsigned int idle_pct = 5; /* percentage */
+static unsigned int round_robin_time = 10; /* second */
+static int power_saving_thread(void *data)
+{
+ struct sched_param param = {.sched_priority = 1};
+ int do_sleep;
+ unsigned int tsk_index = (unsigned long)data;
+ u64 last_jiffies = 0;
+
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ while (!kthread_should_stop()) {
+ int cpu;
+ u64 expire_time;
+
+ try_to_freeze();
+
+ /* round robin to cpus */
+ if (last_jiffies + round_robin_time * HZ < jiffies) {
+ last_jiffies = jiffies;
+ round_robin_cpu(tsk_index);
+ }
+
+ do_sleep = 0;
+
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we test
+ * NEED_RESCHED:
+ */
+ smp_mb();
+
+ expire_time = jiffies + HZ * (100 - idle_pct) / 100;
+
+ while (!need_resched()) {
+ local_irq_disable();
+ cpu = smp_processor_id();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ &cpu);
+ stop_critical_timings();
+
+ __monitor((void *)&current_thread_info()->flags, 0, 0);
+ smp_mb();
+ if (!need_resched())
+ __mwait(power_saving_mwait_eax, 1);
+
+ start_critical_timings();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ &cpu);
+ local_irq_enable();
+
+ if (jiffies > expire_time) {
+ do_sleep = 1;
+ break;
+ }
+ }
+
+ current_thread_info()->status |= TS_POLLING;
+
+ /*
+ * current sched_rt has threshold for rt task running time.
+ * When a rt task uses 95% CPU time, the rt thread will be
+ * scheduled out for 5% CPU time to not starve other tasks. But
+ * the mechanism only works when all CPUs have RT task running,
+ * as if one CPU hasn't RT task, RT task from other CPUs will
+ * borrow CPU time from this CPU and cause RT task use > 95%
+ * CPU time. To make 'avoid staration' work, takes a nap here.
+ */
+ if (do_sleep)
+ schedule_timeout_killable(HZ * idle_pct / 100);
+ }
+
+ exit_round_robin(tsk_index);
+ return 0;
+}
+
+static struct task_struct *ps_tsks[NR_CPUS];
+static unsigned int ps_tsk_num;
+static int create_power_saving_task(void)
+{
+ ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
+ (void *)(unsigned long)ps_tsk_num,
+ "power_saving/%d", ps_tsk_num);
+ if (ps_tsks[ps_tsk_num]) {
+ ps_tsk_num++;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void destroy_power_saving_task(void)
+{
+ if (ps_tsk_num > 0) {
+ ps_tsk_num--;
+ kthread_stop(ps_tsks[ps_tsk_num]);
+ }
+}
+
+static void set_power_saving_task_num(unsigned int num)
+{
+ if (num > ps_tsk_num) {
+ while (ps_tsk_num < num) {
+ if (create_power_saving_task())
+ return;
+ }
+ } else if (num < ps_tsk_num) {
+ while (ps_tsk_num > num)
+ destroy_power_saving_task();
+ }
+}
+
+static int acpi_pad_idle_cpus(unsigned int num_cpus)
+{
+ get_online_cpus();
+
+ num_cpus = min_t(unsigned int, num_cpus, num_online_cpus());
+ set_power_saving_task_num(num_cpus);
+
+ put_online_cpus();
+ return 0;
+}
+
+static uint32_t acpi_pad_idle_cpus_num(void)
+{
+ return ps_tsk_num;
+}
+
+static ssize_t acpi_pad_rrtime_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ if (num < 1 || num >= 100)
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ round_robin_time = num;
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_rrtime_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d", round_robin_time);
+}
+static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR,
+ acpi_pad_rrtime_show,
+ acpi_pad_rrtime_store);
+
+static ssize_t acpi_pad_idlepct_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ if (num < 1 || num >= 100)
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ idle_pct = num;
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_idlepct_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d", idle_pct);
+}
+static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR,
+ acpi_pad_idlepct_show,
+ acpi_pad_idlepct_store);
+
+static ssize_t acpi_pad_idlecpus_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long num;
+ if (strict_strtoul(buf, 0, &num))
+ return -EINVAL;
+ mutex_lock(&isolated_cpus_lock);
+ acpi_pad_idle_cpus(num);
+ mutex_unlock(&isolated_cpus_lock);
+ return count;
+}
+
+static ssize_t acpi_pad_idlecpus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return cpumask_scnprintf(buf, PAGE_SIZE,
+ to_cpumask(pad_busy_cpus_bits));
+}
+static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR,
+ acpi_pad_idlecpus_show,
+ acpi_pad_idlecpus_store);
+
+static int acpi_pad_add_sysfs(struct acpi_device *device)
+{
+ int result;
+
+ result = device_create_file(&device->dev, &dev_attr_idlecpus);
+ if (result)
+ return -ENODEV;
+ result = device_create_file(&device->dev, &dev_attr_idlepct);
+ if (result) {
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ return -ENODEV;
+ }
+ result = device_create_file(&device->dev, &dev_attr_rrtime);
+ if (result) {
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ device_remove_file(&device->dev, &dev_attr_idlepct);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void acpi_pad_remove_sysfs(struct acpi_device *device)
+{
+ device_remove_file(&device->dev, &dev_attr_idlecpus);
+ device_remove_file(&device->dev, &dev_attr_idlepct);
+ device_remove_file(&device->dev, &dev_attr_rrtime);
+}
+
+/* Query firmware how many CPUs should be idle */
+static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+ union acpi_object *package;
+ int rev, num, ret = -EINVAL;
+
+ status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ package = buffer.pointer;
+ if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
+ goto out;
+ rev = package->package.elements[0].integer.value;
+ num = package->package.elements[1].integer.value;
+ if (rev != 1)
+ goto out;
+ *num_cpus = num;
+ ret = 0;
+out:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+/* Notify firmware how many CPUs are idle */
+static void acpi_pad_ost(acpi_handle handle, int stat,
+ uint32_t idle_cpus)
+{
+ union acpi_object params[3] = {
+ {.type = ACPI_TYPE_INTEGER,},
+ {.type = ACPI_TYPE_INTEGER,},
+ {.type = ACPI_TYPE_BUFFER,},
+ };
+ struct acpi_object_list arg_list = {3, params};
+
+ params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
+ params[1].integer.value = stat;
+ params[2].buffer.length = 4;
+ params[2].buffer.pointer = (void *)&idle_cpus;
+ acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+}
+
+static void acpi_pad_handle_notify(acpi_handle handle)
+{
+ int num_cpus, ret;
+ uint32_t idle_cpus;
+
+ mutex_lock(&isolated_cpus_lock);
+ if (acpi_pad_pur(handle, &num_cpus)) {
+ mutex_unlock(&isolated_cpus_lock);
+ return;
+ }
+ ret = acpi_pad_idle_cpus(num_cpus);
+ idle_cpus = acpi_pad_idle_cpus_num();
+ if (!ret)
+ acpi_pad_ost(handle, 0, idle_cpus);
+ else
+ acpi_pad_ost(handle, 1, 0);
+ mutex_unlock(&isolated_cpus_lock);
+}
+
+static void acpi_pad_notify(acpi_handle handle, u32 event,
+ void *data)
+{
+ struct acpi_device *device = data;
+
+ switch (event) {
+ case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
+ acpi_pad_handle_notify(handle);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ dev_name(&device->dev), event, 0);
+ break;
+ default:
+ printk(KERN_WARNING"Unsupported event [0x%x]\n", event);
+ break;
+ }
+}
+
+static int acpi_pad_add(struct acpi_device *device)
+{
+ acpi_status status;
+
+ strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
+
+ if (acpi_pad_add_sysfs(device))
+ return -ENODEV;
+
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
+ if (ACPI_FAILURE(status)) {
+ acpi_pad_remove_sysfs(device);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_pad_remove(struct acpi_device *device,
+ int type)
+{
+ mutex_lock(&isolated_cpus_lock);
+ acpi_pad_idle_cpus(0);
+ mutex_unlock(&isolated_cpus_lock);
+
+ acpi_remove_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY, acpi_pad_notify);
+ acpi_pad_remove_sysfs(device);
+ return 0;
+}
+
+static const struct acpi_device_id pad_device_ids[] = {
+ {"ACPI000C", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, pad_device_ids);
+
+static struct acpi_driver acpi_pad_driver = {
+ .name = "processor_aggregator",
+ .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
+ .ids = pad_device_ids,
+ .ops = {
+ .add = acpi_pad_add,
+ .remove = acpi_pad_remove,
+ },
+};
+
+static int __init acpi_pad_init(void)
+{
+ power_saving_mwait_init();
+ if (power_saving_mwait_eax == 0)
+ return -EINVAL;
+
+ return acpi_bus_register_driver(&acpi_pad_driver);
+}
+
+static void __exit acpi_pad_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_pad_driver);
+}
+
+module_init(acpi_pad_init);
+module_exit(acpi_pad_exit);
+MODULE_AUTHOR("Shaohua Li<shaohua.li@intel.com>");
+MODULE_DESCRIPTION("ACPI Processor Aggregator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 72ac28da14e3..0e7d56185f6d 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -44,4 +44,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
- utstate.o utmutex.o utobject.o utresrc.o utlock.o
+ utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index e6777fb883d2..8e679ef5b231 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -183,7 +183,7 @@
/* Operation regions */
-#define ACPI_NUM_PREDEFINED_REGIONS 8
+#define ACPI_NUM_PREDEFINED_REGIONS 9
#define ACPI_USER_REGION_BEGIN 0x80
/* Maximum space_ids for Operation Regions */
@@ -199,9 +199,15 @@
#define ACPI_RSDP_CHECKSUM_LENGTH 20
#define ACPI_RSDP_XCHECKSUM_LENGTH 36
-/* SMBus bidirectional buffer size */
+/* SMBus and IPMI bidirectional buffer size */
#define ACPI_SMBUS_BUFFER_SIZE 34
+#define ACPI_IPMI_BUFFER_SIZE 66
+
+/* _sx_d and _sx_w control methods */
+
+#define ACPI_NUM_sx_d_METHODS 4
+#define ACPI_NUM_sx_w_METHODS 5
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 62c59df3b86c..a4fb001d96f1 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -154,10 +154,6 @@ void
acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
-void acpi_db_check_predefined_names(void);
-
-void acpi_db_batch_execute(void);
-
/*
* dbexec - debugger control method execution
*/
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 3d87362d17ed..6389f7c1de59 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -58,6 +58,10 @@
#define ACPI_INIT_GLOBAL(a,b) a
#endif
+#ifdef DEFINE_ACPI_GLOBALS
+
+/* Public globals, available from outside ACPICA subsystem */
+
/*****************************************************************************
*
* Runtime configuration (static defaults that can be overriden at runtime)
@@ -78,7 +82,7 @@
* 5) Allow unresolved references (invalid target name) in package objects
* 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
/*
* Automatically serialize ALL control methods? Default is FALSE, meaning
@@ -86,27 +90,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
* Only change this if the ASL code is poorly written and cannot handle
* reentrancy even though methods are marked "NotSerialized".
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
/*
* Create the predefined _OSI method in the namespace? Default is TRUE
* because ACPI CA is fully compatible with other ACPI implementations.
* Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
/*
* Disable wakeup GPEs during runtime? Default is TRUE because WAKE and
* RUNTIME GPEs should never be shared, and WAKE GPEs should typically only
* be enabled just before going to sleep.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+
+/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
+
+struct acpi_table_fadt acpi_gbl_FADT;
+u32 acpi_current_gpe_count;
+u32 acpi_gbl_trace_flags;
+acpi_name acpi_gbl_trace_method_name;
+
+#endif
/*****************************************************************************
*
@@ -114,11 +127,6 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
*
****************************************************************************/
-/* Runtime configuration of debug print levels */
-
-extern u32 acpi_dbg_level;
-extern u32 acpi_dbg_layer;
-
/* Procedure nesting level for debug output */
extern u32 acpi_gbl_nesting_level;
@@ -127,10 +135,8 @@ extern u32 acpi_gbl_nesting_level;
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_flags;
/*****************************************************************************
*
@@ -142,10 +148,8 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags;
* acpi_gbl_root_table_list is the master list of ACPI tables found in the
* RSDT/XSDT.
*
- * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
*/
ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
-ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
/* These addresses are calculated from the FADT Event Block addresses */
@@ -261,7 +265,8 @@ ACPI_EXTERN u8 acpi_gbl_osi_data;
extern u8 acpi_gbl_shutdown;
extern u32 acpi_gbl_startup_flags;
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
-extern const char *acpi_gbl_highest_dstate_names[4];
+extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS];
+extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS];
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
@@ -340,7 +345,6 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN u32 acpi_current_gpe_count;
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 4afa3d8e0efb..36192f142fbb 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -62,6 +62,14 @@ u32 acpi_hw_get_mode(void);
/*
* hwregs - ACPI Register I/O
*/
+acpi_status
+acpi_hw_validate_register(struct acpi_generic_address *reg,
+ u8 max_bit_width, u64 *address);
+
+acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg);
+
+acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg);
+
struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id);
acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control);
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index e8db7a3143a5..5db9f2916f7c 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -461,9 +461,9 @@ void acpi_ex_acquire_global_lock(u32 rule);
void acpi_ex_release_global_lock(u32 rule);
-void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string);
+void acpi_ex_eisa_id_to_string(char *dest, acpi_integer compressed_id);
-void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string);
+void acpi_ex_integer_to_string(char *dest, acpi_integer value);
/*
* exregion - default op_region handlers
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index ee986edfa0da..ff6689eba917 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -369,6 +369,19 @@ union acpi_predefined_info {
struct acpi_package_info3 ret_info3;
};
+/* Data block used during object validation */
+
+struct acpi_predefined_data {
+ char *pathname;
+ const union acpi_predefined_info *predefined;
+ u32 flags;
+ u8 node_flags;
+};
+
+/* Defines for Flags field above */
+
+#define ACPI_OBJECT_REPAIRED 1
+
/*
* Bitmapped return value types
* Note: the actual data types must be contiguous, a loop in nspredef.c
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 91ac7d7b4402..3acd9c6760ea 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -340,6 +340,7 @@
*/
#define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e);
#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist
#else
@@ -347,6 +348,7 @@
#define ACPI_ERROR_NAMESPACE(s, e)
#define ACPI_ERROR_METHOD(s, n, p, e)
+#define ACPI_WARN_PREDEFINED(plist)
#endif /* ACPI_NO_ERROR_MESSAGES */
/*
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 94cdc2b8cb93..a78e02f62d5e 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -144,6 +144,8 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name);
void acpi_ns_delete_node(struct acpi_namespace_node *node);
+void acpi_ns_remove_node(struct acpi_namespace_node *node);
+
void
acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle);
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 544dcf834922..eb6f038b03d9 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -97,6 +97,7 @@
#define AOPOBJ_OBJECT_INITIALIZED 0x08
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
+#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 897810ba0ccc..863a264b829e 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -324,26 +324,30 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer * address);
+ acpi_integer *value);
acpi_status
-acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *hid);
+acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 *status_flags);
acpi_status
-acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
- struct acpi_compatible_id_list **return_cid_list);
+acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
+ const char **method_names,
+ u8 method_count, u8 *out_values);
+/*
+ * utids - device ID support
+ */
acpi_status
-acpi_ut_execute_STA(struct acpi_namespace_node *device_node,
- u32 * status_flags);
+acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id);
acpi_status
acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *uid);
+ struct acpica_device_id **return_id);
acpi_status
-acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest);
+acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id_list **return_cid_list);
/*
* utlock - reader/writer locks
@@ -445,6 +449,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
*/
const char *acpi_ut_validate_exception(acpi_status status);
+u8 acpi_ut_is_pci_root_bridge(char *id);
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
@@ -469,6 +475,12 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position);
acpi_status
acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...);
+
/* Values for Base above (16=Hex, 10=Decimal) */
#define ACPI_ANY_BASE 0
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 067f967eb389..4940249f2524 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -404,6 +404,7 @@ typedef enum {
REGION_SMBUS,
REGION_CMOS,
REGION_PCI_BAR,
+ REGION_IPMI,
REGION_DATA_TABLE, /* Internal use only */
REGION_FIXED_HW = 0x7F
} AML_REGION_TYPES;
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 584d766e6f12..b79978f7bc71 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -397,6 +397,30 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Validate the region address/length via the host OS */
+
+ status = acpi_os_validate_address(obj_desc->region.space_id,
+ obj_desc->region.address,
+ (acpi_size) obj_desc->region.length,
+ acpi_ut_get_node_name(node));
+
+ if (ACPI_FAILURE(status)) {
+ /*
+ * Invalid address/length. We will emit an error message and mark
+ * the region as invalid, so that it will cause an additional error if
+ * it is ever used. Then return AE_OK.
+ */
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During address validation of OpRegion [%4.4s]",
+ node->name.ascii));
+ obj_desc->common.flags |= AOPOBJ_INVALID;
+ status = AE_OK;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index cd55c774e882..5df6af7897bf 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -203,10 +203,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
/* Disable the fixed event */
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
- status =
- acpi_write_bit_register(acpi_gbl_fixed_event_info
- [i].enable_register_id,
- ACPI_DISABLE_EVENT);
+ status = acpi_disable_event(i, 0);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -288,18 +285,14 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
ACPI_FUNCTION_ENTRY();
/* Clear the status bit */
-
- (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
- status_register_id, ACPI_CLEAR_STATUS);
+ acpi_clear_event(event);
/*
* Make sure we've got a handler. If not, report an error. The event is
* disabled to prevent further interrupts.
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
- (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
- enable_register_id,
- ACPI_DISABLE_EVENT);
+ acpi_disable_event(event, 0);
ACPI_ERROR((AE_INFO,
"No installed handler for fixed event [%08X]",
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index b9d8ee69ca6c..afacf4416c73 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -424,8 +424,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Status Register */
status =
- acpi_read(&status_reg,
- &gpe_register_info->status_address);
+ acpi_hw_read(&status_reg,
+ &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -433,8 +433,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Enable Register */
status =
- acpi_read(&enable_reg,
- &gpe_register_info->enable_address);
+ acpi_hw_read(&enable_reg,
+ &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 7b3463639422..a60aaa7635f3 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -843,14 +843,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Disable all GPEs within this register */
- status = acpi_write(0x00, &this_register->enable_address);
+ status = acpi_hw_write(0x00, &this_register->enable_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
/* Clear any pending GPE events within this register */
- status = acpi_write(0xFF, &this_register->status_address);
+ status = acpi_hw_write(0xFF, &this_register->status_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 284a7becbe96..cf29c4953028 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -50,8 +50,6 @@
ACPI_MODULE_NAME("evrgnini")
/* Local prototypes */
-static u8 acpi_ev_match_pci_root_bridge(char *id);
-
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
/*******************************************************************************
@@ -332,37 +330,6 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*******************************************************************************
*
- * FUNCTION: acpi_ev_match_pci_root_bridge
- *
- * PARAMETERS: Id - The HID/CID in string format
- *
- * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
- *
- * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
- *
- ******************************************************************************/
-
-static u8 acpi_ev_match_pci_root_bridge(char *id)
-{
-
- /*
- * Check if this is a PCI root.
- * ACPI 3.0+: check for a PCI Express root also.
- */
- if (!(ACPI_STRNCMP(id,
- PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING))) ||
- !(ACPI_STRNCMP(id,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
- return (TRUE);
- }
-
- return (FALSE);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_is_pci_root_bridge
*
* PARAMETERS: Node - Device node being examined
@@ -377,9 +344,10 @@ static u8 acpi_ev_match_pci_root_bridge(char *id)
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
{
acpi_status status;
- struct acpica_device_id hid;
- struct acpi_compatible_id_list *cid;
+ struct acpica_device_id *hid;
+ struct acpica_device_id_list *cid;
u32 i;
+ u8 match;
/* Get the _HID and check for a PCI Root Bridge */
@@ -388,7 +356,10 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
return (FALSE);
}
- if (acpi_ev_match_pci_root_bridge(hid.value)) {
+ match = acpi_ut_is_pci_root_bridge(hid->string);
+ ACPI_FREE(hid);
+
+ if (match) {
return (TRUE);
}
@@ -402,7 +373,7 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
/* Check all _CIDs in the returned list */
for (i = 0; i < cid->count; i++) {
- if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+ if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) {
ACPI_FREE(cid);
return (TRUE);
}
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index ec524614e708..de3446372ddc 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -418,9 +418,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_REFERENCE:
acpi_ex_out_string("Class Name",
- (char *)
- acpi_ut_get_reference_name
- (obj_desc));
+ ACPI_CAST_PTR(char,
+ acpi_ut_get_reference_name
+ (obj_desc)));
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 546dcdd86785..0b33d6c887b9 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -72,6 +72,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
union acpi_operand_object *buffer_desc;
acpi_size length;
void *buffer;
+ u32 function;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -97,13 +98,27 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
}
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS)) {
+ ACPI_ADR_SPACE_SMBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_IPMI)) {
/*
- * This is an SMBus read. We must create a buffer to hold the data
- * and directly access the region handler.
+ * This is an SMBus or IPMI read. We must create a buffer to hold
+ * the data and then directly access the region handler.
+ *
+ * Note: Smbus protocol value is passed in upper 16-bits of Function
*/
- buffer_desc =
- acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
+ if (obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_SMBUS) {
+ length = ACPI_SMBUS_BUFFER_SIZE;
+ function =
+ ACPI_READ | (obj_desc->field.attribute << 16);
+ } else { /* IPMI */
+
+ length = ACPI_IPMI_BUFFER_SIZE;
+ function = ACPI_READ;
+ }
+
+ buffer_desc = acpi_ut_create_buffer_object(length);
if (!buffer_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -112,16 +127,13 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
- /*
- * Perform the read.
- * Note: Smbus protocol value is passed in upper 16-bits of Function
- */
+ /* Call the region handler for the read */
+
status = acpi_ex_access_region(obj_desc, 0,
ACPI_CAST_PTR(acpi_integer,
buffer_desc->
buffer.pointer),
- ACPI_READ | (obj_desc->field.
- attribute << 16));
+ function);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
goto exit;
}
@@ -212,6 +224,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
u32 length;
void *buffer;
union acpi_operand_object *buffer_desc;
+ u32 function;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -234,39 +247,56 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
}
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS)) {
+ ACPI_ADR_SPACE_SMBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_IPMI)) {
/*
- * This is an SMBus write. We will bypass the entire field mechanism
- * and handoff the buffer directly to the handler.
+ * This is an SMBus or IPMI write. We will bypass the entire field
+ * mechanism and handoff the buffer directly to the handler. For
+ * these address spaces, the buffer is bi-directional; on a write,
+ * return data is returned in the same buffer.
+ *
+ * Source must be a buffer of sufficient size:
+ * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
*
- * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
+ * Note: SMBus protocol type is passed in upper 16-bits of Function
*/
if (source_desc->common.type != ACPI_TYPE_BUFFER) {
ACPI_ERROR((AE_INFO,
- "SMBus write requires Buffer, found type %s",
+ "SMBus or IPMI write requires Buffer, found type %s",
acpi_ut_get_object_type_name(source_desc)));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
+ if (obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_SMBUS) {
+ length = ACPI_SMBUS_BUFFER_SIZE;
+ function =
+ ACPI_WRITE | (obj_desc->field.attribute << 16);
+ } else { /* IPMI */
+
+ length = ACPI_IPMI_BUFFER_SIZE;
+ function = ACPI_WRITE;
+ }
+
+ if (source_desc->buffer.length < length) {
ACPI_ERROR((AE_INFO,
- "SMBus write requires Buffer of length %X, found length %X",
- ACPI_SMBUS_BUFFER_SIZE,
- source_desc->buffer.length));
+ "SMBus or IPMI write requires Buffer of length %X, found length %X",
+ length, source_desc->buffer.length));
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
}
- buffer_desc =
- acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
+ /* Create the bi-directional buffer */
+
+ buffer_desc = acpi_ut_create_buffer_object(length);
if (!buffer_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
buffer = buffer_desc->buffer.pointer;
- ACPI_MEMCPY(buffer, source_desc->buffer.pointer,
- ACPI_SMBUS_BUFFER_SIZE);
+ ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length);
/* Lock entire transaction if requested */
@@ -275,12 +305,10 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/*
* Perform the write (returns status and perhaps data in the
* same buffer)
- * Note: SMBus protocol type is passed in upper 16-bits of Function.
*/
status = acpi_ex_access_region(obj_desc, 0,
(acpi_integer *) buffer,
- ACPI_WRITE | (obj_desc->field.
- attribute << 16));
+ function);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index d4075b821021..d7b3b418fb45 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -113,13 +113,20 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
}
}
+ /* Exit if Address/Length have been disallowed by the host OS */
+
+ if (rgn_desc->common.flags & AOPOBJ_INVALID) {
+ return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
+ }
+
/*
- * Exit now for SMBus address space, it has a non-linear address space
+ * Exit now for SMBus or IPMI address space, it has a non-linear address space
* and the request cannot be directly validated
*/
- if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
+ if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
+ rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
- /* SMBus has a non-linear address space */
+ /* SMBus or IPMI has a non-linear address space */
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 87730e944132..7d41f99f7052 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -358,50 +358,67 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base)
*
* FUNCTION: acpi_ex_eisa_id_to_string
*
- * PARAMETERS: numeric_id - EISA ID to be converted
+ * PARAMETERS: compressed_id - EISAID to be converted
* out_string - Where to put the converted string (8 bytes)
*
* RETURN: None
*
- * DESCRIPTION: Convert a numeric EISA ID to string representation
+ * DESCRIPTION: Convert a numeric EISAID to string representation. Return
+ * buffer must be large enough to hold the string. The string
+ * returned is always exactly of length ACPI_EISAID_STRING_SIZE
+ * (includes null terminator). The EISAID is always 32 bits.
*
******************************************************************************/
-void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string)
+void acpi_ex_eisa_id_to_string(char *out_string, acpi_integer compressed_id)
{
- u32 eisa_id;
+ u32 swapped_id;
ACPI_FUNCTION_ENTRY();
+ /* The EISAID should be a 32-bit integer */
+
+ if (compressed_id > ACPI_UINT32_MAX) {
+ ACPI_WARNING((AE_INFO,
+ "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
+ ACPI_FORMAT_UINT64(compressed_id)));
+ }
+
/* Swap ID to big-endian to get contiguous bits */
- eisa_id = acpi_ut_dword_byte_swap(numeric_id);
+ swapped_id = acpi_ut_dword_byte_swap((u32)compressed_id);
- out_string[0] = (char)('@' + (((unsigned long)eisa_id >> 26) & 0x1f));
- out_string[1] = (char)('@' + ((eisa_id >> 21) & 0x1f));
- out_string[2] = (char)('@' + ((eisa_id >> 16) & 0x1f));
- out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 12);
- out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 8);
- out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 4);
- out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer) eisa_id, 0);
+ /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
+
+ out_string[0] =
+ (char)(0x40 + (((unsigned long)swapped_id >> 26) & 0x1F));
+ out_string[1] = (char)(0x40 + ((swapped_id >> 21) & 0x1F));
+ out_string[2] = (char)(0x40 + ((swapped_id >> 16) & 0x1F));
+ out_string[3] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 12);
+ out_string[4] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 8);
+ out_string[5] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 4);
+ out_string[6] = acpi_ut_hex_to_ascii_char((acpi_integer)swapped_id, 0);
out_string[7] = 0;
}
/*******************************************************************************
*
- * FUNCTION: acpi_ex_unsigned_integer_to_string
+ * FUNCTION: acpi_ex_integer_to_string
*
- * PARAMETERS: Value - Value to be converted
- * out_string - Where to put the converted string (8 bytes)
+ * PARAMETERS: out_string - Where to put the converted string. At least
+ * 21 bytes are needed to hold the largest
+ * possible 64-bit integer.
+ * Value - Value to be converted
*
* RETURN: None, string
*
- * DESCRIPTION: Convert a number to string representation. Assumes string
- * buffer is large enough to hold the string.
+ * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
+ * Assumes string buffer is large enough to hold the string. The
+ * largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
*
******************************************************************************/
-void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string)
+void acpi_ex_integer_to_string(char *out_string, acpi_integer value)
{
u32 count;
u32 digits_needed;
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index d3b7e37c9eed..c28c41b3180b 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -82,7 +82,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Get current value of the enable register that contains this GPE */
- status = acpi_read(&enable_mask, &gpe_register_info->enable_address);
+ status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -95,7 +95,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Write the updated enable mask */
- status = acpi_write(enable_mask, &gpe_register_info->enable_address);
+ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
return (status);
}
@@ -130,8 +130,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
/* Write the entire GPE (runtime) enable register */
- status = acpi_write(gpe_register_info->enable_for_run,
- &gpe_register_info->enable_address);
+ status = acpi_hw_write(gpe_register_info->enable_for_run,
+ &gpe_register_info->enable_address);
return (status);
}
@@ -163,8 +163,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_write(register_bit,
- &gpe_event_info->register_info->status_address);
+ status = acpi_hw_write(register_bit,
+ &gpe_event_info->register_info->status_address);
return (status);
}
@@ -222,7 +222,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* GPE currently active (status bit == 1)? */
- status = acpi_read(&in_byte, &gpe_register_info->status_address);
+ status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -266,8 +266,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Disable all GPEs in this register */
status =
- acpi_write(0x00,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_write(0x00,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -303,8 +303,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Clear status on all GPEs in this register */
status =
- acpi_write(0xFF,
- &gpe_block->register_info[i].status_address);
+ acpi_hw_write(0xFF,
+ &gpe_block->register_info[i].status_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -345,9 +345,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Enable all "runtime" GPEs in this register */
- status = acpi_write(gpe_block->register_info[i].enable_for_run,
- &gpe_block->register_info[i].
- enable_address);
+ status =
+ acpi_hw_write(gpe_block->register_info[i].enable_for_run,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -387,9 +387,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Enable all "wake" GPEs in this register */
- status = acpi_write(gpe_block->register_info[i].enable_for_wake,
- &gpe_block->register_info[i].
- enable_address);
+ status =
+ acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 23d5505cb1f7..15c9ed2be853 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -62,6 +62,184 @@ acpi_hw_write_multiple(u32 value,
struct acpi_generic_address *register_a,
struct acpi_generic_address *register_b);
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_validate_register
+ *
+ * PARAMETERS: Reg - GAS register structure
+ * max_bit_width - Max bit_width supported (32 or 64)
+ * Address - Pointer to where the gas->address
+ * is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
+ * pointer, Address, space_id, bit_width, and bit_offset.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_validate_register(struct acpi_generic_address *reg,
+ u8 max_bit_width, u64 *address)
+{
+
+ /* Must have a valid pointer to a GAS structure */
+
+ if (!reg) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Copy the target address. This handles possible alignment issues.
+ * Address must not be null. A null address also indicates an optional
+ * ACPI register that is not supported, so no error message.
+ */
+ ACPI_MOVE_64_TO_64(address, &reg->address);
+ if (!(*address)) {
+ return (AE_BAD_ADDRESS);
+ }
+
+ /* Validate the space_iD */
+
+ if ((reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
+ (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+ ACPI_ERROR((AE_INFO,
+ "Unsupported address space: 0x%X", reg->space_id));
+ return (AE_SUPPORT);
+ }
+
+ /* Validate the bit_width */
+
+ if ((reg->bit_width != 8) &&
+ (reg->bit_width != 16) &&
+ (reg->bit_width != 32) && (reg->bit_width != max_bit_width)) {
+ ACPI_ERROR((AE_INFO,
+ "Unsupported register bit width: 0x%X",
+ reg->bit_width));
+ return (AE_SUPPORT);
+ }
+
+ /* Validate the bit_offset. Just a warning for now. */
+
+ if (reg->bit_offset != 0) {
+ ACPI_WARNING((AE_INFO,
+ "Unsupported register bit offset: 0x%X",
+ reg->bit_offset));
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_read
+ *
+ * PARAMETERS: Value - Where the value is returned
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
+ * version of acpi_read, used internally since the overhead of
+ * 64-bit values is not needed.
+ *
+ * LIMITATIONS: <These limitations also apply to acpi_hw_write>
+ * bit_width must be exactly 8, 16, or 32.
+ * space_iD must be system_memory or system_iO.
+ * bit_offset and access_width are currently ignored, as there has
+ * not been a need to implement these.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(hw_read);
+
+ /* Validate contents of the GAS register */
+
+ status = acpi_hw_validate_register(reg, 32, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Initialize entire 32-bit return value to zero */
+
+ *value = 0;
+
+ /*
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
+ */
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_read_memory((acpi_physical_address)
+ address, value, reg->bit_width);
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+ status = acpi_hw_read_port((acpi_io_address)
+ address, value, reg->bit_width);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
+ *value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
+
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_write
+ *
+ * PARAMETERS: Value - Value to be written
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
+ * version of acpi_write, used internally since the overhead of
+ * 64-bit values is not needed.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(hw_write);
+
+ /* Validate contents of the GAS register */
+
+ status = acpi_hw_validate_register(reg, 32, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
+ */
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ address, value, reg->bit_width);
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+ status = acpi_hw_write_port((acpi_io_address)
+ address, value, reg->bit_width);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
+ value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
+
+ return (status);
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_hw_clear_acpi_status
@@ -152,15 +330,16 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
ACPI_FUNCTION_TRACE(hw_write_pm1_control);
- status = acpi_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
+ status =
+ acpi_hw_write(pm1a_control, &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (acpi_gbl_FADT.xpm1b_control_block.address) {
status =
- acpi_write(pm1b_control,
- &acpi_gbl_FADT.xpm1b_control_block);
+ acpi_hw_write(pm1b_control,
+ &acpi_gbl_FADT.xpm1b_control_block);
}
return_ACPI_STATUS(status);
}
@@ -218,12 +397,13 @@ acpi_hw_register_read(u32 register_id, u32 * return_value)
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
- status = acpi_read(&value, &acpi_gbl_FADT.xpm2_control_block);
+ status =
+ acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
- status = acpi_read(&value, &acpi_gbl_FADT.xpm_timer_block);
+ status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
@@ -340,7 +520,8 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
* as per the ACPI spec.
*/
status =
- acpi_read(&read_value, &acpi_gbl_FADT.xpm2_control_block);
+ acpi_hw_read(&read_value,
+ &acpi_gbl_FADT.xpm2_control_block);
if (ACPI_FAILURE(status)) {
goto exit;
}
@@ -350,12 +531,13 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
ACPI_INSERT_BITS(value, ACPI_PM2_CONTROL_PRESERVED_BITS,
read_value);
- status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block);
+ status =
+ acpi_hw_write(value, &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
- status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block);
+ status = acpi_hw_write(value, &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
@@ -401,7 +583,7 @@ acpi_hw_read_multiple(u32 *value,
/* The first register is always required */
- status = acpi_read(&value_a, register_a);
+ status = acpi_hw_read(&value_a, register_a);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -409,7 +591,7 @@ acpi_hw_read_multiple(u32 *value,
/* Second register is optional */
if (register_b->address) {
- status = acpi_read(&value_b, register_b);
+ status = acpi_hw_read(&value_b, register_b);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -452,7 +634,7 @@ acpi_hw_write_multiple(u32 value,
/* The first register is always required */
- status = acpi_write(value, register_a);
+ status = acpi_hw_write(value, register_a);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -470,7 +652,7 @@ acpi_hw_write_multiple(u32 value,
* and writes have no side effects"
*/
if (register_b->address) {
- status = acpi_write(value, register_b);
+ status = acpi_hw_write(value, register_b);
}
return (status);
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index db307a356f08..283e872f87a3 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -534,6 +534,12 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
}
}
+
+ /* Clear any pending events before enabling interrupts */
+
+ acpi_hw_disable_all_gpes();
+ acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
+
return_ACPI_STATUS(status);
}
@@ -578,15 +584,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
/*
* GPEs must be enabled before _WAK is called as GPEs
* might get fired there
- *
- * Restore the GPEs:
- * 1) Disable/Clear all GPEs
- * 2) Enable all runtime GPEs
*/
- status = acpi_hw_disable_all_gpes();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
status = acpi_hw_enable_all_runtime_gpes();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -610,15 +608,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
/* Enable power button */
- (void)
- acpi_write_bit_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].
- enable_register_id, ACPI_ENABLE_EVENT);
-
- (void)
- acpi_write_bit_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].
- status_register_id, ACPI_CLEAR_STATUS);
+ acpi_enable_event(ACPI_EVENT_POWER_BUTTON, 0);
arg.integer.value = ACPI_SST_WORKING;
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index b7f522c8f023..6b282e85d039 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -100,7 +100,7 @@ acpi_status acpi_get_timer(u32 * ticks)
}
status =
- acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
+ acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 9829979f2bdd..4ead85f29215 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -80,7 +80,7 @@ acpi_status acpi_reset(void)
/* Write the reset value to the reset register */
- status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg);
+ status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg);
return_ACPI_STATUS(status);
}
@@ -97,67 +97,92 @@ ACPI_EXPORT_SYMBOL(acpi_reset)
*
* DESCRIPTION: Read from either memory or IO space.
*
+ * LIMITATIONS: <These limitations also apply to acpi_write>
+ * bit_width must be exactly 8, 16, 32, or 64.
+ * space_iD must be system_memory or system_iO.
+ * bit_offset and access_width are currently ignored, as there has
+ * not been a need to implement these.
+ *
******************************************************************************/
-acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg)
+acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
{
+ u32 value;
u32 width;
u64 address;
acpi_status status;
ACPI_FUNCTION_NAME(acpi_read);
- /*
- * Must have a valid pointer to a GAS structure, and a non-zero address
- * within.
- */
- if (!reg) {
+ if (!return_value) {
return (AE_BAD_PARAMETER);
}
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* Validate contents of the GAS register. Allow 64-bit transfers */
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_BAD_ADDRESS);
+ status = acpi_hw_validate_register(reg, 64, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
}
- /* Supported widths are 8/16/32 */
-
width = reg->bit_width;
- if ((width != 8) && (width != 16) && (width != 32)) {
- return (AE_SUPPORT);
+ if (width == 64) {
+ width = 32; /* Break into two 32-bit transfers */
}
- /* Initialize entire 32-bit return value to zero */
+ /* Initialize entire 64-bit return value to zero */
- *value = 0;
+ *return_value = 0;
+ value = 0;
/*
* Two address spaces supported: Memory or IO. PCI_Config is
* not supported here because the GAS structure is insufficient
*/
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_read_memory((acpi_physical_address)
+ address, &value, width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value = value;
+
+ if (reg->bit_width == 64) {
- status = acpi_os_read_memory((acpi_physical_address) address,
- value, width);
- break;
+ /* Read the top 32 bits */
- case ACPI_ADR_SPACE_SYSTEM_IO:
+ status = acpi_os_read_memory((acpi_physical_address)
+ (address + 4), &value, 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value |= ((u64)value << 32);
+ }
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
- status =
- acpi_hw_read_port((acpi_io_address) address, value, width);
- break;
+ status = acpi_hw_read_port((acpi_io_address)
+ address, &value, width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value = value;
- default:
- ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ if (reg->bit_width == 64) {
+
+ /* Read the top 32 bits */
+
+ status = acpi_hw_read_port((acpi_io_address)
+ (address + 4), &value, 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ *return_value |= ((u64)value << 32);
+ }
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width, ACPI_FORMAT_UINT64(address),
+ "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
+ ACPI_FORMAT_UINT64(*return_value), reg->bit_width,
+ ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(reg->space_id)));
return (status);
@@ -169,7 +194,7 @@ ACPI_EXPORT_SYMBOL(acpi_read)
*
* FUNCTION: acpi_write
*
- * PARAMETERS: Value - To be written
+ * PARAMETERS: Value - Value to be written
* Reg - GAS register structure
*
* RETURN: Status
@@ -177,7 +202,7 @@ ACPI_EXPORT_SYMBOL(acpi_read)
* DESCRIPTION: Write to either memory or IO space.
*
******************************************************************************/
-acpi_status acpi_write(u32 value, struct acpi_generic_address *reg)
+acpi_status acpi_write(u64 value, struct acpi_generic_address *reg)
{
u32 width;
u64 address;
@@ -185,54 +210,61 @@ acpi_status acpi_write(u32 value, struct acpi_generic_address *reg)
ACPI_FUNCTION_NAME(acpi_write);
- /*
- * Must have a valid pointer to a GAS structure, and a non-zero address
- * within.
- */
- if (!reg) {
- return (AE_BAD_PARAMETER);
- }
+ /* Validate contents of the GAS register. Allow 64-bit transfers */
- /* Get a local copy of the address. Handles possible alignment issues */
-
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_BAD_ADDRESS);
+ status = acpi_hw_validate_register(reg, 64, &address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
}
- /* Supported widths are 8/16/32 */
-
width = reg->bit_width;
- if ((width != 8) && (width != 16) && (width != 32)) {
- return (AE_SUPPORT);
+ if (width == 64) {
+ width = 32; /* Break into two 32-bit transfers */
}
/*
- * Two address spaces supported: Memory or IO.
- * PCI_Config is not supported here because the GAS struct is insufficient
+ * Two address spaces supported: Memory or IO. PCI_Config is
+ * not supported here because the GAS structure is insufficient
*/
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-
- status = acpi_os_write_memory((acpi_physical_address) address,
- value, width);
- break;
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ address, ACPI_LODWORD(value),
+ width);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- case ACPI_ADR_SPACE_SYSTEM_IO:
+ if (reg->bit_width == 64) {
+ status = acpi_os_write_memory((acpi_physical_address)
+ (address + 4),
+ ACPI_HIDWORD(value), 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
- status = acpi_hw_write_port((acpi_io_address) address, value,
+ status = acpi_hw_write_port((acpi_io_address)
+ address, ACPI_LODWORD(value),
width);
- break;
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
- default:
- ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ if (reg->bit_width == 64) {
+ status = acpi_hw_write_port((acpi_io_address)
+ (address + 4),
+ ACPI_HIDWORD(value), 32);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width, ACPI_FORMAT_UINT64(address),
+ "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n",
+ ACPI_FORMAT_UINT64(value), reg->bit_width,
+ ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(reg->space_id)));
return (status);
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index efc971ab7d65..8a58a1b85aa0 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -96,17 +96,68 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
*
* RETURN: None
*
- * DESCRIPTION: Delete a namespace node
+ * DESCRIPTION: Delete a namespace node. All node deletions must come through
+ * here. Detaches any attached objects, including any attached
+ * data. If a handler is associated with attached data, it is
+ * invoked before the node is deleted.
*
******************************************************************************/
void acpi_ns_delete_node(struct acpi_namespace_node *node)
{
+ union acpi_operand_object *obj_desc;
+
+ ACPI_FUNCTION_NAME(ns_delete_node);
+
+ /* Detach an object if there is one */
+
+ acpi_ns_detach_object(node);
+
+ /*
+ * Delete an attached data object if present (an object that was created
+ * and attached via acpi_attach_data). Note: After any normal object is
+ * detached above, the only possible remaining object is a data object.
+ */
+ obj_desc = node->object;
+ if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
+
+ /* Invoke the attached data deletion handler if present */
+
+ if (obj_desc->data.handler) {
+ obj_desc->data.handler(node, obj_desc->data.pointer);
+ }
+
+ acpi_ut_remove_reference(obj_desc);
+ }
+
+ /* Now we can delete the node */
+
+ (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+
+ ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n",
+ node, acpi_gbl_current_node_count));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_node
+ *
+ * PARAMETERS: Node - Node to be removed/deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Remove (unlink) and delete a namespace node
+ *
+ ******************************************************************************/
+
+void acpi_ns_remove_node(struct acpi_namespace_node *node)
+{
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *prev_node;
struct acpi_namespace_node *next_node;
- ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
+ ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
parent_node = acpi_ns_get_parent_node(node);
@@ -142,12 +193,9 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
}
}
- ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
-
- /* Detach an object if there is one, then delete the node */
+ /* Delete the node and any attached objects */
- acpi_ns_detach_object(node);
- (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+ acpi_ns_delete_node(node);
return_VOID;
}
@@ -273,25 +321,11 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
parent_node, child_node));
}
- /* Now we can free this child object */
-
- ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
-
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Object %p, Remaining %X\n", child_node,
- acpi_gbl_current_node_count));
-
- /* Detach an object if there is one, then free the child node */
-
- acpi_ns_detach_object(child_node);
-
- /* Now we can delete the node */
-
- (void)acpi_os_release_object(acpi_gbl_namespace_cache,
- child_node);
-
- /* And move on to the next child in the list */
-
+ /*
+ * Delete this child node and move on to the next child in the list.
+ * No need to unlink the node since we are deleting the entire branch.
+ */
+ acpi_ns_delete_node(child_node);
child_node = next_node;
} while (!(flags & ANOBJ_END_OF_PEER_LIST));
@@ -433,7 +467,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
if (deletion_node) {
acpi_ns_delete_children(deletion_node);
- acpi_ns_delete_node(deletion_node);
+ acpi_ns_remove_node(deletion_node);
deletion_node = NULL;
}
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 41994fe7fbb8..0fe87f1aef16 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -70,7 +70,6 @@ static acpi_status
acpi_ns_dump_one_device(acpi_handle obj_handle,
u32 level, void *context, void **return_value)
{
- struct acpi_buffer buffer;
struct acpi_device_info *info;
acpi_status status;
u32 i;
@@ -80,17 +79,15 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
status =
acpi_ns_dump_one_object(obj_handle, level, context, return_value);
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_get_object_info(obj_handle, &buffer);
+ status = acpi_get_object_info(obj_handle, &info);
if (ACPI_SUCCESS(status)) {
- info = buffer.pointer;
for (i = 0; i < level; i++) {
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES, " "));
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_TABLES,
" HID: %s, ADR: %8.8X%8.8X, Status: %X\n",
- info->hardware_id.value,
+ info->hardware_id.string,
ACPI_FORMAT_UINT64(info->address),
info->current_status));
ACPI_FREE(info);
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index dcd7a6adbbbc..a7234e60e985 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -270,8 +270,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
/* Now delete the starting object, and we are done */
- acpi_ns_delete_node(child_handle);
-
+ acpi_ns_remove_node(child_handle);
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 7f8e066b12a3..1dc1a4737aa9 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -72,31 +72,33 @@ ACPI_MODULE_NAME("nspredef")
******************************************************************************/
/* Local prototypes */
static acpi_status
-acpi_ns_check_package(char *pathname,
- union acpi_operand_object **return_object_ptr,
- const union acpi_predefined_info *predefined);
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_check_package_elements(char *pathname,
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
u8 type2, u32 count2, u32 start_index);
static acpi_status
-acpi_ns_check_object_type(char *pathname,
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index);
static acpi_status
-acpi_ns_check_reference(char *pathname,
+acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object);
static acpi_status
-acpi_ns_repair_object(u32 expected_btypes,
+acpi_ns_repair_object(struct acpi_predefined_data *data,
+ u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr);
+static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes);
+
/*
* Names for the types that can be returned by the predefined objects.
* Used for warning messages. Must be in the same order as the ACPI_RTYPEs
@@ -109,13 +111,21 @@ static const char *acpi_rtype_names[] = {
"/Reference",
};
-#define ACPI_NOT_PACKAGE ACPI_UINT32_MAX
+/* Object is not a package element */
+
+#define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX
+
+/* Always emit warning message, not dependent on node flags */
+
+#define ACPI_WARN_ALWAYS 0
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_predefined_names
*
* PARAMETERS: Node - Namespace node for the method/object
+ * user_param_count - Number of parameters actually passed
+ * return_status - Status from the object evaluation
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -135,12 +145,13 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status status = AE_OK;
const union acpi_predefined_info *predefined;
char *pathname;
+ struct acpi_predefined_data *data;
/* Match the name for this method/object against the predefined list */
predefined = acpi_ns_check_for_predefined_name(node);
- /* Get the full pathname to the object, for use in error messages */
+ /* Get the full pathname to the object, for use in warning messages */
pathname = acpi_ns_get_external_pathname(node);
if (!pathname) {
@@ -158,28 +169,17 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* If not a predefined name, we cannot validate the return object */
if (!predefined) {
- goto exit;
- }
-
- /* If the method failed, we cannot validate the return object */
-
- if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
- goto exit;
+ goto cleanup;
}
/*
- * Only validate the return value on the first successful evaluation of
- * the method. This ensures that any warnings will only be emitted during
- * the very first evaluation of the method/object.
+ * If the method failed or did not actually return an object, we cannot
+ * validate the return object
*/
- if (node->flags & ANOBJ_EVALUATED) {
- goto exit;
+ if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
+ goto cleanup;
}
- /* Mark the node as having been successfully evaluated */
-
- node->flags |= ANOBJ_EVALUATED;
-
/*
* If there is no return value, check if we require a return value for
* this predefined name. Either one return value is expected, or none,
@@ -190,46 +190,63 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
if (!return_object) {
if ((predefined->info.expected_btypes) &&
(!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_ERROR((AE_INFO,
- "%s: Missing expected return value",
- pathname));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
status = AE_AML_NO_RETURN_VALUE;
}
- goto exit;
+ goto cleanup;
}
/*
* We have a return value, but if one wasn't expected, just exit, this is
- * not a problem
- *
- * For example, if the "Implicit Return" feature is enabled, methods will
- * always return a value
+ * not a problem. For example, if the "Implicit Return" feature is
+ * enabled, methods will always return a value.
*/
if (!predefined->info.expected_btypes) {
- goto exit;
+ goto cleanup;
}
+ /* Create the parameter data block for object validation */
+
+ data = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_predefined_data));
+ if (!data) {
+ goto cleanup;
+ }
+ data->predefined = predefined;
+ data->node_flags = node->flags;
+ data->pathname = pathname;
+
/*
* Check that the type of the return object is what is expected for
* this predefined name
*/
- status = acpi_ns_check_object_type(pathname, return_object_ptr,
+ status = acpi_ns_check_object_type(data, return_object_ptr,
predefined->info.expected_btypes,
- ACPI_NOT_PACKAGE);
+ ACPI_NOT_PACKAGE_ELEMENT);
if (ACPI_FAILURE(status)) {
- goto exit;
+ goto check_validation_status;
}
/* For returned Package objects, check the type of all sub-objects */
if (return_object->common.type == ACPI_TYPE_PACKAGE) {
- status =
- acpi_ns_check_package(pathname, return_object_ptr,
- predefined);
+ status = acpi_ns_check_package(data, return_object_ptr);
+ }
+
+check_validation_status:
+ /*
+ * If the object validation failed or if we successfully repaired one
+ * or more objects, mark the parent node to suppress further warning
+ * messages during the next evaluation of the same method/object.
+ */
+ if (ACPI_FAILURE(status) || (data->flags & ACPI_OBJECT_REPAIRED)) {
+ node->flags |= ANOBJ_EVALUATED;
}
+ ACPI_FREE(data);
- exit:
+cleanup:
ACPI_FREE(pathname);
return (status);
}
@@ -268,64 +285,58 @@ acpi_ns_check_parameter_count(char *pathname,
param_count = node->object->method.param_count;
}
- /* Argument count check for non-predefined methods/objects */
-
if (!predefined) {
/*
+ * Check the parameter count for non-predefined methods/objects.
+ *
* Warning if too few or too many arguments have been passed by the
* caller. An incorrect number of arguments may not cause the method
* to fail. However, the method will fail if there are too few
* arguments and the method attempts to use one of the missing ones.
*/
if (user_param_count < param_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Insufficient arguments - needs %d, found %d",
- pathname, param_count, user_param_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Insufficient arguments - needs %u, found %u",
+ param_count, user_param_count));
} else if (user_param_count > param_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Excess arguments - needs %d, found %d",
- pathname, param_count, user_param_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Excess arguments - needs %u, found %u",
+ param_count, user_param_count));
}
return;
}
- /* Allow two different legal argument counts (_SCP, etc.) */
-
+ /*
+ * Validate the user-supplied parameter count.
+ * Allow two different legal argument counts (_SCP, etc.)
+ */
required_params_current = predefined->info.param_count & 0x0F;
required_params_old = predefined->info.param_count >> 4;
if (user_param_count != ACPI_UINT32_MAX) {
-
- /* Validate the user-supplied parameter count */
-
if ((user_param_count != required_params_current) &&
(user_param_count != required_params_old)) {
- ACPI_WARNING((AE_INFO,
- "%s: Parameter count mismatch - "
- "caller passed %d, ACPI requires %d",
- pathname, user_param_count,
- required_params_current));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Parameter count mismatch - "
+ "caller passed %u, ACPI requires %u",
+ user_param_count,
+ required_params_current));
}
}
/*
- * Only validate the argument count on the first successful evaluation of
- * the method. This ensures that any warnings will only be emitted during
- * the very first evaluation of the method/object.
- */
- if (node->flags & ANOBJ_EVALUATED) {
- return;
- }
-
- /*
* Check that the ASL-defined parameter count is what is expected for
- * this predefined name.
+ * this predefined name (parameter count as defined by the ACPI
+ * specification)
*/
if ((param_count != required_params_current) &&
(param_count != required_params_old)) {
- ACPI_WARNING((AE_INFO,
- "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d",
- pathname, param_count, required_params_current));
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname, node->flags,
+ "Parameter count mismatch - ASL declared %u, ACPI requires %u",
+ param_count, required_params_current));
}
}
@@ -358,9 +369,6 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
this_name = predefined_names;
while (this_name->info.name[0]) {
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) {
-
- /* Return pointer to this table entry */
-
return (this_name);
}
@@ -375,17 +383,16 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
this_name++;
}
- return (NULL);
+ return (NULL); /* Not found */
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_package
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
- * Predefined - Pointer to entry in predefined name table
*
* RETURN: Status
*
@@ -395,9 +402,8 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
******************************************************************************/
static acpi_status
-acpi_ns_check_package(char *pathname,
- union acpi_operand_object **return_object_ptr,
- const union acpi_predefined_info *predefined)
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
const union acpi_predefined_info *package;
@@ -414,11 +420,11 @@ acpi_ns_check_package(char *pathname,
/* The package info for this name is in the next table entry */
- package = predefined + 1;
+ package = data->predefined + 1;
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"%s Validating return Package of Type %X, Count %X\n",
- pathname, package->ret_info.type,
+ data->pathname, package->ret_info.type,
return_object->package.count));
/* Extract package count and elements array */
@@ -429,9 +435,8 @@ acpi_ns_check_package(char *pathname,
/* The package must have at least one element, else invalid */
if (!count) {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package has no elements (empty)",
- pathname));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package has no elements (empty)"));
return (AE_AML_OPERAND_VALUE);
}
@@ -456,15 +461,16 @@ acpi_ns_check_package(char *pathname,
if (count < expected_count) {
goto package_too_small;
} else if (count > expected_count) {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package is larger than needed - "
- "found %u, expected %u", pathname, count,
- expected_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ data->node_flags,
+ "Return Package is larger than needed - "
+ "found %u, expected %u", count,
+ expected_count));
}
/* Validate all elements of the returned package */
- status = acpi_ns_check_package_elements(pathname, elements,
+ status = acpi_ns_check_package_elements(data, elements,
package->ret_info.
object_type1,
package->ret_info.
@@ -485,7 +491,7 @@ acpi_ns_check_package(char *pathname,
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
- status = acpi_ns_check_object_type(pathname, elements,
+ status = acpi_ns_check_object_type(data, elements,
package->ret_info.
object_type1, i);
if (ACPI_FAILURE(status)) {
@@ -517,8 +523,7 @@ acpi_ns_check_package(char *pathname,
/* These are the required package elements (0, 1, or 2) */
status =
- acpi_ns_check_object_type(pathname,
- elements,
+ acpi_ns_check_object_type(data, elements,
package->
ret_info3.
object_type[i],
@@ -530,8 +535,7 @@ acpi_ns_check_package(char *pathname,
/* These are the optional package elements */
status =
- acpi_ns_check_object_type(pathname,
- elements,
+ acpi_ns_check_object_type(data, elements,
package->
ret_info3.
tail_object_type,
@@ -548,7 +552,7 @@ acpi_ns_check_package(char *pathname,
/* First element is the (Integer) count of sub-packages to follow */
- status = acpi_ns_check_object_type(pathname, elements,
+ status = acpi_ns_check_object_type(data, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
@@ -585,9 +589,9 @@ acpi_ns_check_package(char *pathname,
/* Each sub-object must be of type Package */
- status =
- acpi_ns_check_object_type(pathname, &sub_package,
- ACPI_RTYPE_PACKAGE, i);
+ status = acpi_ns_check_object_type(data, &sub_package,
+ ACPI_RTYPE_PACKAGE,
+ i);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -610,7 +614,7 @@ acpi_ns_check_package(char *pathname,
}
status =
- acpi_ns_check_package_elements(pathname,
+ acpi_ns_check_package_elements(data,
sub_elements,
package->
ret_info.
@@ -643,7 +647,7 @@ acpi_ns_check_package(char *pathname,
for (j = 0; j < expected_count; j++) {
status =
- acpi_ns_check_object_type(pathname,
+ acpi_ns_check_object_type(data,
&sub_elements[j],
package->ret_info2.object_type[j], j);
if (ACPI_FAILURE(status)) {
@@ -665,7 +669,7 @@ acpi_ns_check_package(char *pathname,
/* Check the type of each sub-package element */
status =
- acpi_ns_check_package_elements(pathname,
+ acpi_ns_check_package_elements(data,
sub_elements,
package->
ret_info.
@@ -684,7 +688,7 @@ acpi_ns_check_package(char *pathname,
/* First element is the (Integer) count of elements to follow */
status =
- acpi_ns_check_object_type(pathname,
+ acpi_ns_check_object_type(data,
sub_elements,
ACPI_RTYPE_INTEGER,
0);
@@ -704,7 +708,7 @@ acpi_ns_check_package(char *pathname,
/* Check the type of each sub-package element */
status =
- acpi_ns_check_package_elements(pathname,
+ acpi_ns_check_package_elements(data,
(sub_elements
+ 1),
package->
@@ -730,9 +734,9 @@ acpi_ns_check_package(char *pathname,
/* Should not get here if predefined info table is correct */
- ACPI_WARNING((AE_INFO,
- "%s: Invalid internal return type in table entry: %X",
- pathname, package->ret_info.type));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid internal return type in table entry: %X",
+ package->ret_info.type));
return (AE_AML_INTERNAL);
}
@@ -743,9 +747,9 @@ acpi_ns_check_package(char *pathname,
/* Error exit for the case with an incorrect package count */
- ACPI_WARNING((AE_INFO, "%s: Return Package is too small - "
- "found %u, expected %u", pathname, count,
- expected_count));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package is too small - found %u, expected %u",
+ count, expected_count));
return (AE_AML_OPERAND_VALUE);
}
@@ -754,7 +758,7 @@ acpi_ns_check_package(char *pathname,
*
* FUNCTION: acpi_ns_check_package_elements
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* Elements - Pointer to the package elements array
* Type1 - Object type for first group
* Count1 - Count for first group
@@ -770,7 +774,7 @@ acpi_ns_check_package(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_package_elements(char *pathname,
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
@@ -786,7 +790,7 @@ acpi_ns_check_package_elements(char *pathname,
* The second group can have a count of zero.
*/
for (i = 0; i < count1; i++) {
- status = acpi_ns_check_object_type(pathname, this_element,
+ status = acpi_ns_check_object_type(data, this_element,
type1, i + start_index);
if (ACPI_FAILURE(status)) {
return (status);
@@ -795,7 +799,7 @@ acpi_ns_check_package_elements(char *pathname,
}
for (i = 0; i < count2; i++) {
- status = acpi_ns_check_object_type(pathname, this_element,
+ status = acpi_ns_check_object_type(data, this_element,
type2,
(i + count1 + start_index));
if (ACPI_FAILURE(status)) {
@@ -811,12 +815,13 @@ acpi_ns_check_package_elements(char *pathname,
*
* FUNCTION: acpi_ns_check_object_type
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
* expected_btypes - Bitmap of expected return type(s)
* package_index - Index of object within parent package (if
- * applicable - ACPI_NOT_PACKAGE otherwise)
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
*
* RETURN: Status
*
@@ -826,7 +831,7 @@ acpi_ns_check_package_elements(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_object_type(char *pathname,
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index)
{
@@ -834,9 +839,6 @@ acpi_ns_check_object_type(char *pathname,
acpi_status status = AE_OK;
u32 return_btype;
char type_buffer[48]; /* Room for 5 types */
- u32 this_rtype;
- u32 i;
- u32 j;
/*
* If we get a NULL return_object here, it is a NULL package element,
@@ -849,10 +851,11 @@ acpi_ns_check_object_type(char *pathname,
/* A Namespace node should not get here, but make sure */
if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
- ACPI_WARNING((AE_INFO,
- "%s: Invalid return type - Found a Namespace node [%4.4s] type %s",
- pathname, return_object->node.name.ascii,
- acpi_ut_get_type_name(return_object->node.type)));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid return type - Found a Namespace node [%4.4s] type %s",
+ return_object->node.name.ascii,
+ acpi_ut_get_type_name(return_object->node.
+ type)));
return (AE_AML_OPERAND_TYPE);
}
@@ -897,10 +900,11 @@ acpi_ns_check_object_type(char *pathname,
/* Type mismatch -- attempt repair of the returned object */
- status = acpi_ns_repair_object(expected_btypes, package_index,
+ status = acpi_ns_repair_object(data, expected_btypes,
+ package_index,
return_object_ptr);
if (ACPI_SUCCESS(status)) {
- return (status);
+ return (AE_OK); /* Repair was successful */
}
goto type_error_exit;
}
@@ -908,7 +912,7 @@ acpi_ns_check_object_type(char *pathname,
/* For reference objects, check that the reference type is correct */
if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
- status = acpi_ns_check_reference(pathname, return_object);
+ status = acpi_ns_check_reference(data, return_object);
}
return (status);
@@ -917,33 +921,19 @@ acpi_ns_check_object_type(char *pathname,
/* Create a string with all expected types for this predefined object */
- j = 1;
- type_buffer[0] = 0;
- this_rtype = ACPI_RTYPE_INTEGER;
-
- for (i = 0; i < ACPI_NUM_RTYPES; i++) {
-
- /* If one of the expected types, concatenate the name of this type */
-
- if (expected_btypes & this_rtype) {
- ACPI_STRCAT(type_buffer, &acpi_rtype_names[i][j]);
- j = 0; /* Use name separator from now on */
- }
- this_rtype <<= 1; /* Next Rtype */
- }
+ acpi_ns_get_expected_types(type_buffer, expected_btypes);
- if (package_index == ACPI_NOT_PACKAGE) {
- ACPI_WARNING((AE_INFO,
- "%s: Return type mismatch - found %s, expected %s",
- pathname,
- acpi_ut_get_object_type_name(return_object),
- type_buffer));
+ if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return type mismatch - found %s, expected %s",
+ acpi_ut_get_object_type_name
+ (return_object), type_buffer));
} else {
- ACPI_WARNING((AE_INFO,
- "%s: Return Package type mismatch at index %u - "
- "found %s, expected %s", pathname, package_index,
- acpi_ut_get_object_type_name(return_object),
- type_buffer));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package type mismatch at index %u - "
+ "found %s, expected %s", package_index,
+ acpi_ut_get_object_type_name
+ (return_object), type_buffer));
}
return (AE_AML_OPERAND_TYPE);
@@ -953,7 +943,7 @@ acpi_ns_check_object_type(char *pathname,
*
* FUNCTION: acpi_ns_check_reference
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * PARAMETERS: Data - Pointer to validation data structure
* return_object - Object returned from the evaluation of a
* method or object
*
@@ -966,7 +956,7 @@ acpi_ns_check_object_type(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_check_reference(char *pathname,
+acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object)
{
@@ -979,11 +969,10 @@ acpi_ns_check_reference(char *pathname,
return (AE_OK);
}
- ACPI_WARNING((AE_INFO,
- "%s: Return type mismatch - "
- "unexpected reference object type [%s] %2.2X",
- pathname, acpi_ut_get_reference_name(return_object),
- return_object->reference.class));
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return type mismatch - unexpected reference object type [%s] %2.2X",
+ acpi_ut_get_reference_name(return_object),
+ return_object->reference.class));
return (AE_AML_OPERAND_TYPE);
}
@@ -992,8 +981,11 @@ acpi_ns_check_reference(char *pathname,
*
* FUNCTION: acpi_ns_repair_object
*
- * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
- * package_index - Used to determine if target is in a package
+ * PARAMETERS: Data - Pointer to validation data structure
+ * expected_btypes - Object types expected
+ * package_index - Index of object within parent package (if
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -1005,7 +997,8 @@ acpi_ns_check_reference(char *pathname,
******************************************************************************/
static acpi_status
-acpi_ns_repair_object(u32 expected_btypes,
+acpi_ns_repair_object(struct acpi_predefined_data *data,
+ u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr)
{
@@ -1016,6 +1009,8 @@ acpi_ns_repair_object(u32 expected_btypes,
switch (return_object->common.type) {
case ACPI_TYPE_BUFFER:
+ /* Does the method/object legally return a string? */
+
if (!(expected_btypes & ACPI_RTYPE_STRING)) {
return (AE_AML_OPERAND_TYPE);
}
@@ -1046,22 +1041,35 @@ acpi_ns_repair_object(u32 expected_btypes,
ACPI_MEMCPY(new_object->string.pointer,
return_object->buffer.pointer, length);
- /* Install the new return object */
-
- acpi_ut_remove_reference(return_object);
- *return_object_ptr = new_object;
-
/*
- * If the object is a package element, we need to:
- * 1. Decrement the reference count of the orignal object, it was
- * incremented when building the package
- * 2. Increment the reference count of the new object, it will be
- * decremented when releasing the package
+ * 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) {
- acpi_ut_remove_reference(return_object);
- acpi_ut_add_reference(new_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 Buffer to expected String at index %u",
+ package_index));
+ } else {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ data->node_flags,
+ "Converted Buffer to expected String"));
}
+
+ /* 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);
default:
@@ -1070,3 +1078,39 @@ acpi_ns_repair_object(u32 expected_btypes,
return (AE_AML_OPERAND_TYPE);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_expected_types
+ *
+ * PARAMETERS: Buffer - Pointer to where the string is returned
+ * expected_btypes - Bitmap of expected return type(s)
+ *
+ * RETURN: Buffer is populated with type names.
+ *
+ * DESCRIPTION: Translate the expected types bitmap into a string of ascii
+ * names of expected types, for use in warning messages.
+ *
+ ******************************************************************************/
+
+static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes)
+{
+ u32 this_rtype;
+ u32 i;
+ u32 j;
+
+ j = 1;
+ buffer[0] = 0;
+ this_rtype = ACPI_RTYPE_INTEGER;
+
+ for (i = 0; i < ACPI_NUM_RTYPES; i++) {
+
+ /* If one of the expected types, concatenate the name of this type */
+
+ if (expected_btypes & this_rtype) {
+ ACPI_STRCAT(buffer, &acpi_rtype_names[i][j]);
+ j = 0; /* Use name separator from now on */
+ }
+ this_rtype <<= 1; /* Next Rtype */
+ }
+}
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 78277ed08339..ea55ab4f9849 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -88,7 +88,8 @@ acpi_ns_report_error(const char *module_name,
/* There is a non-ascii character in the name */
- ACPI_MOVE_32_TO_32(&bad_name, internal_name);
+ ACPI_MOVE_32_TO_32(&bad_name,
+ ACPI_CAST_PTR(u32, internal_name));
acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
} else {
/* Convert path to external format */
@@ -836,7 +837,7 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
acpi_status status;
char *internal_path;
- ACPI_FUNCTION_TRACE_PTR(ns_get_node, pathname);
+ ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));
if (!pathname) {
*return_node = prefix_node;
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index daf4ad37896d..4929dbdbc8f0 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -535,10 +535,11 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
acpi_status status;
struct acpi_namespace_node *node;
u32 flags;
- struct acpica_device_id hid;
- struct acpi_compatible_id_list *cid;
+ struct acpica_device_id *hid;
+ struct acpica_device_id_list *cid;
u32 i;
- int found;
+ u8 found;
+ int no_match;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -582,10 +583,14 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
return (AE_CTRL_DEPTH);
}
- if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) {
-
- /* Get the list of Compatible IDs */
+ no_match = ACPI_STRCMP(hid->string, info->hid);
+ ACPI_FREE(hid);
+ if (no_match) {
+ /*
+ * HID does not match, attempt match within the
+ * list of Compatible IDs (CIDs)
+ */
status = acpi_ut_execute_CID(node, &cid);
if (status == AE_NOT_FOUND) {
return (AE_OK);
@@ -597,10 +602,8 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
found = 0;
for (i = 0; i < cid->count; i++) {
- if (ACPI_STRNCMP(cid->id[i].value, info->hid,
- sizeof(struct
- acpi_compatible_id)) ==
- 0) {
+ if (ACPI_STRCMP(cid->ids[i].string, info->hid)
+ == 0) {
found = 1;
break;
}
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index f23593d6add4..ddc84af6336e 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -51,6 +51,11 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfname")
+/* Local prototypes */
+static char *acpi_ns_copy_device_id(struct acpica_device_id *dest,
+ struct acpica_device_id *source,
+ char *string_area);
+
/******************************************************************************
*
* FUNCTION: acpi_get_handle
@@ -68,6 +73,7 @@ ACPI_MODULE_NAME("nsxfname")
* namespace handle.
*
******************************************************************************/
+
acpi_status
acpi_get_handle(acpi_handle parent,
acpi_string pathname, acpi_handle * ret_handle)
@@ -210,10 +216,38 @@ ACPI_EXPORT_SYMBOL(acpi_get_name)
/******************************************************************************
*
+ * FUNCTION: acpi_ns_copy_device_id
+ *
+ * PARAMETERS: Dest - Pointer to the destination DEVICE_ID
+ * Source - Pointer to the source DEVICE_ID
+ * string_area - Pointer to where to copy the dest string
+ *
+ * RETURN: Pointer to the next string area
+ *
+ * DESCRIPTION: Copy a single DEVICE_ID, including the string data.
+ *
+ ******************************************************************************/
+static char *acpi_ns_copy_device_id(struct acpica_device_id *dest,
+ struct acpica_device_id *source,
+ char *string_area)
+{
+ /* Create the destination DEVICE_ID */
+
+ dest->string = string_area;
+ dest->length = source->length;
+
+ /* Copy actual string and return a pointer to the next string area */
+
+ ACPI_MEMCPY(string_area, source->string, source->length);
+ return (string_area + source->length);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_get_object_info
*
- * PARAMETERS: Handle - Object Handle
- * Buffer - Where the info is returned
+ * PARAMETERS: Handle - Object Handle
+ * return_buffer - Where the info is returned
*
* RETURN: Status
*
@@ -221,33 +255,37 @@ ACPI_EXPORT_SYMBOL(acpi_get_name)
* namespace node and possibly by running several standard
* control methods (Such as in the case of a device.)
*
+ * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA,
+ * _ADR, _sx_w, and _sx_d methods.
+ *
+ * Note: Allocates the return buffer, must be freed by the caller.
+ *
******************************************************************************/
+
acpi_status
-acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
+acpi_get_object_info(acpi_handle handle,
+ struct acpi_device_info **return_buffer)
{
- acpi_status status;
struct acpi_namespace_node *node;
struct acpi_device_info *info;
- struct acpi_device_info *return_info;
- struct acpi_compatible_id_list *cid_list = NULL;
- acpi_size size;
+ struct acpica_device_id_list *cid_list = NULL;
+ struct acpica_device_id *hid = NULL;
+ struct acpica_device_id *uid = NULL;
+ char *next_id_string;
+ acpi_object_type type;
+ acpi_name name;
+ u8 param_count = 0;
+ u8 valid = 0;
+ u32 info_size;
+ u32 i;
+ acpi_status status;
/* Parameter validation */
- if (!handle || !buffer) {
+ if (!handle || !return_buffer) {
return (AE_BAD_PARAMETER);
}
- status = acpi_ut_validate_buffer(buffer);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info));
- if (!info) {
- return (AE_NO_MEMORY);
- }
-
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto cleanup;
@@ -256,66 +294,91 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
node = acpi_ns_map_handle_to_node(handle);
if (!node) {
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- status = AE_BAD_PARAMETER;
- goto cleanup;
+ return (AE_BAD_PARAMETER);
}
- /* Init return structure */
-
- size = sizeof(struct acpi_device_info);
+ /* Get the namespace node data while the namespace is locked */
- info->type = node->type;
- info->name = node->name.integer;
- info->valid = 0;
+ info_size = sizeof(struct acpi_device_info);
+ type = node->type;
+ name = node->name.integer;
if (node->type == ACPI_TYPE_METHOD) {
- info->param_count = node->object->method.param_count;
+ param_count = node->object->method.param_count;
}
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return (status);
}
- /* If not a device, we are all done */
-
- if (info->type == ACPI_TYPE_DEVICE) {
+ if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
/*
- * Get extra info for ACPI Devices objects only:
- * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods.
+ * Get extra info for ACPI Device/Processor objects only:
+ * Run the Device _HID, _UID, and _CID methods.
*
* Note: none of these methods are required, so they may or may
- * not be present for this device. The Info->Valid bitfield is used
- * to indicate which methods were found and ran successfully.
+ * not be present for this device. The Info->Valid bitfield is used
+ * to indicate which methods were found and run successfully.
*/
/* Execute the Device._HID method */
- status = acpi_ut_execute_HID(node, &info->hardware_id);
+ status = acpi_ut_execute_HID(node, &hid);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_HID;
+ info_size += hid->length;
+ valid |= ACPI_VALID_HID;
}
/* Execute the Device._UID method */
- status = acpi_ut_execute_UID(node, &info->unique_id);
+ status = acpi_ut_execute_UID(node, &uid);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_UID;
+ info_size += uid->length;
+ valid |= ACPI_VALID_UID;
}
/* Execute the Device._CID method */
status = acpi_ut_execute_CID(node, &cid_list);
if (ACPI_SUCCESS(status)) {
- size += cid_list->size;
- info->valid |= ACPI_VALID_CID;
+
+ /* Add size of CID strings and CID pointer array */
+
+ info_size +=
+ (cid_list->list_size -
+ sizeof(struct acpica_device_id_list));
+ valid |= ACPI_VALID_CID;
}
+ }
+
+ /*
+ * Now that we have the variable-length data, we can allocate the
+ * return buffer
+ */
+ info = ACPI_ALLOCATE_ZEROED(info_size);
+ if (!info) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Get the fixed-length data */
+
+ if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
+ /*
+ * Get extra info for ACPI Device/Processor objects only:
+ * Run the _STA, _ADR and, sx_w, and _sx_d methods.
+ *
+ * Note: none of these methods are required, so they may or may
+ * not be present for this device. The Info->Valid bitfield is used
+ * to indicate which methods were found and run successfully.
+ */
/* Execute the Device._STA method */
status = acpi_ut_execute_STA(node, &info->current_status);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_STA;
+ valid |= ACPI_VALID_STA;
}
/* Execute the Device._ADR method */
@@ -323,36 +386,100 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
&info->address);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_ADR;
+ valid |= ACPI_VALID_ADR;
+ }
+
+ /* Execute the Device._sx_w methods */
+
+ status = acpi_ut_execute_power_methods(node,
+ acpi_gbl_lowest_dstate_names,
+ ACPI_NUM_sx_w_METHODS,
+ info->lowest_dstates);
+ if (ACPI_SUCCESS(status)) {
+ valid |= ACPI_VALID_SXWS;
}
/* Execute the Device._sx_d methods */
- status = acpi_ut_execute_sxds(node, info->highest_dstates);
+ status = acpi_ut_execute_power_methods(node,
+ acpi_gbl_highest_dstate_names,
+ ACPI_NUM_sx_d_METHODS,
+ info->highest_dstates);
if (ACPI_SUCCESS(status)) {
- info->valid |= ACPI_VALID_SXDS;
+ valid |= ACPI_VALID_SXDS;
}
}
- /* Validate/Allocate/Clear caller buffer */
+ /*
+ * Create a pointer to the string area of the return buffer.
+ * Point to the end of the base struct acpi_device_info structure.
+ */
+ next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
+ if (cid_list) {
- status = acpi_ut_initialize_buffer(buffer, size);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ /* Point past the CID DEVICE_ID array */
+
+ next_id_string +=
+ ((acpi_size) cid_list->count *
+ sizeof(struct acpica_device_id));
}
- /* Populate the return buffer */
+ /*
+ * Copy the HID, UID, and CIDs to the return buffer. The variable-length
+ * strings are copied to the reserved area at the end of the buffer.
+ *
+ * For HID and CID, check if the ID is a PCI Root Bridge.
+ */
+ if (hid) {
+ next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
+ hid, next_id_string);
+
+ if (acpi_ut_is_pci_root_bridge(hid->string)) {
+ info->flags |= ACPI_PCI_ROOT_BRIDGE;
+ }
+ }
- return_info = buffer->pointer;
- ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info));
+ if (uid) {
+ next_id_string = acpi_ns_copy_device_id(&info->unique_id,
+ uid, next_id_string);
+ }
if (cid_list) {
- ACPI_MEMCPY(&return_info->compatibility_id, cid_list,
- cid_list->size);
+ info->compatible_id_list.count = cid_list->count;
+ info->compatible_id_list.list_size = cid_list->list_size;
+
+ /* Copy each CID */
+
+ for (i = 0; i < cid_list->count; i++) {
+ next_id_string =
+ acpi_ns_copy_device_id(&info->compatible_id_list.
+ ids[i], &cid_list->ids[i],
+ next_id_string);
+
+ if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
+ info->flags |= ACPI_PCI_ROOT_BRIDGE;
+ }
+ }
}
+ /* Copy the fixed-length data */
+
+ info->info_size = info_size;
+ info->type = type;
+ info->name = name;
+ info->param_count = param_count;
+ info->valid = valid;
+
+ *return_buffer = info;
+ status = AE_OK;
+
cleanup:
- ACPI_FREE(info);
+ if (hid) {
+ ACPI_FREE(hid);
+ }
+ if (uid) {
+ ACPI_FREE(uid);
+ }
if (cid_list) {
ACPI_FREE(cid_list);
}
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index ef7d2c2d8f0b..1f15497f00d1 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -49,6 +49,12 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
+static void acpi_tb_fix_string(char *string, acpi_size length);
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header);
+
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
@@ -161,6 +167,59 @@ u8 acpi_tb_tables_loaded(void)
/*******************************************************************************
*
+ * FUNCTION: acpi_tb_fix_string
+ *
+ * PARAMETERS: String - String to be repaired
+ * Length - Maximum length
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
+ * with a question mark '?'.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_fix_string(char *string, acpi_size length)
+{
+
+ while (length && *string) {
+ if (!ACPI_IS_PRINT(*string)) {
+ *string = '?';
+ }
+ string++;
+ length--;
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_cleanup_table_header
+ *
+ * PARAMETERS: out_header - Where the cleaned header is returned
+ * Header - Input ACPI table header
+ *
+ * RETURN: Returns the cleaned header in out_header
+ *
+ * DESCRIPTION: Copy the table header and ensure that all "string" fields in
+ * the header consist of printable characters.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header)
+{
+
+ ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
+
+ acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
+ acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+ acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_tb_print_table_header
*
* PARAMETERS: Address - Table physical address
@@ -176,6 +235,7 @@ void
acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header *header)
{
+ struct acpi_table_header local_header;
/*
* The reason that the Address is cast to a void pointer is so that we
@@ -192,6 +252,11 @@ acpi_tb_print_table_header(acpi_physical_address address,
/* RSDP has no common fields */
+ ACPI_MEMCPY(local_header.oem_id,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
+
ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
ACPI_CAST_PTR (void, address),
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
@@ -200,18 +265,21 @@ acpi_tb_print_table_header(acpi_physical_address address,
header)->length : 20,
ACPI_CAST_PTR(struct acpi_table_rsdp,
header)->revision,
- ACPI_CAST_PTR(struct acpi_table_rsdp,
- header)->oem_id));
+ local_header.oem_id));
} else {
/* Standard ACPI table with full common header */
+ acpi_tb_cleanup_table_header(&local_header, header);
+
ACPI_INFO((AE_INFO,
"%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
- header->signature, ACPI_CAST_PTR (void, address),
- header->length, header->revision, header->oem_id,
- header->oem_table_id, header->oem_revision,
- header->asl_compiler_id,
- header->asl_compiler_revision));
+ local_header.signature, ACPI_CAST_PTR(void, address),
+ local_header.length, local_header.revision,
+ local_header.oem_id, local_header.oem_table_id,
+ local_header.oem_revision,
+ local_header.asl_compiler_id,
+ local_header.asl_compiler_revision));
+
}
}
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 006b16c26017..5503307b8bb7 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -44,19 +44,10 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
-#include "acinterp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("uteval")
-/* Local prototypes */
-static void
-acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length);
-
-static acpi_status
-acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
- struct acpi_compatible_id *one_cid);
-
/*
* Strings supported by the _OSI predefined (internal) method.
*
@@ -213,7 +204,7 @@ acpi_status acpi_osi_invalidate(char *interface)
* RETURN: Status
*
* DESCRIPTION: Evaluates a namespace object and verifies the type of the
- * return object. Common code that simplifies accessing objects
+ * return object. Common code that simplifies accessing objects
* that have required return objects of fixed types.
*
* NOTE: Internal function, no parameter validation
@@ -298,7 +289,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) {
/*
- * We received a return object, but one was not expected. This can
+ * We received a return object, but one was not expected. This can
* happen frequently if the "implicit return" feature is enabled.
* Just delete the return object and return AE_OK.
*/
@@ -340,12 +331,12 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
*
* PARAMETERS: object_name - Object name to be evaluated
* device_node - Node for the device
- * Address - Where the value is returned
+ * Value - Where the value is returned
*
* RETURN: Status
*
* DESCRIPTION: Evaluates a numeric namespace object for a selected device
- * and stores result in *Address.
+ * and stores result in *Value.
*
* NOTE: Internal function, no parameter validation
*
@@ -354,7 +345,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
acpi_status
acpi_ut_evaluate_numeric_object(char *object_name,
struct acpi_namespace_node *device_node,
- acpi_integer * address)
+ acpi_integer *value)
{
union acpi_operand_object *obj_desc;
acpi_status status;
@@ -369,295 +360,7 @@ acpi_ut_evaluate_numeric_object(char *object_name,
/* Get the returned Integer */
- *address = obj_desc->integer.value;
-
- /* On exit, we must delete the return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_copy_id_string
- *
- * PARAMETERS: Destination - Where to copy the string
- * Source - Source string
- * max_length - Length of the destination buffer
- *
- * RETURN: None
- *
- * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
- * Performs removal of a leading asterisk if present -- workaround
- * for a known issue on a bunch of machines.
- *
- ******************************************************************************/
-
-static void
-acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length)
-{
-
- /*
- * Workaround for ID strings that have a leading asterisk. This construct
- * is not allowed by the ACPI specification (ID strings must be
- * alphanumeric), but enough existing machines have this embedded in their
- * ID strings that the following code is useful.
- */
- if (*source == '*') {
- source++;
- }
-
- /* Do the actual copy */
-
- ACPI_STRNCPY(destination, source, max_length);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_HID
- *
- * PARAMETERS: device_node - Node for the device
- * Hid - Where the HID is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _HID control method that returns the hardware
- * ID of the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *hid)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ut_execute_HID);
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
- &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
-
- /* Convert the Numeric HID to string */
-
- acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
- hid->value);
- } else {
- /* Copy the String HID from the returned object */
-
- acpi_ut_copy_id_string(hid->value, obj_desc->string.pointer,
- sizeof(hid->value));
- }
-
- /* On exit, we must delete the return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_translate_one_cid
- *
- * PARAMETERS: obj_desc - _CID object, must be integer or string
- * one_cid - Where the CID string is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Return a numeric or string _CID value as a string.
- * (Compatible ID)
- *
- * NOTE: Assumes a maximum _CID string length of
- * ACPI_MAX_CID_LENGTH.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
- struct acpi_compatible_id *one_cid)
-{
-
- switch (obj_desc->common.type) {
- case ACPI_TYPE_INTEGER:
-
- /* Convert the Numeric CID to string */
-
- acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value,
- one_cid->value);
- return (AE_OK);
-
- case ACPI_TYPE_STRING:
-
- if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) {
- return (AE_AML_STRING_LIMIT);
- }
-
- /* Copy the String CID from the returned object */
-
- acpi_ut_copy_id_string(one_cid->value, obj_desc->string.pointer,
- ACPI_MAX_CID_LENGTH);
- return (AE_OK);
-
- default:
-
- return (AE_TYPE);
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_CID
- *
- * PARAMETERS: device_node - Node for the device
- * return_cid_list - Where the CID list is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _CID control method that returns one or more
- * compatible hardware IDs for the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
- struct acpi_compatible_id_list ** return_cid_list)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
- u32 count;
- u32 size;
- struct acpi_compatible_id_list *cid_list;
- u32 i;
-
- ACPI_FUNCTION_TRACE(ut_execute_CID);
-
- /* Evaluate the _CID method for this device */
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
- | ACPI_BTYPE_PACKAGE, &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the number of _CIDs returned */
-
- count = 1;
- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
- count = obj_desc->package.count;
- }
-
- /* Allocate a worst-case buffer for the _CIDs */
-
- size = (((count - 1) * sizeof(struct acpi_compatible_id)) +
- sizeof(struct acpi_compatible_id_list));
-
- cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
- if (!cid_list) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Init CID list */
-
- cid_list->count = count;
- cid_list->size = size;
-
- /*
- * A _CID can return either a single compatible ID or a package of
- * compatible IDs. Each compatible ID can be one of the following:
- * 1) Integer (32 bit compressed EISA ID) or
- * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
- */
-
- /* The _CID object can be either a single CID or a package (list) of CIDs */
-
- if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
-
- /* Translate each package element */
-
- for (i = 0; i < count; i++) {
- status =
- acpi_ut_translate_one_cid(obj_desc->package.
- elements[i],
- &cid_list->id[i]);
- if (ACPI_FAILURE(status)) {
- break;
- }
- }
- } else {
- /* Only one CID, translate to a string */
-
- status = acpi_ut_translate_one_cid(obj_desc, cid_list->id);
- }
-
- /* Cleanup on error */
-
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(cid_list);
- } else {
- *return_cid_list = cid_list;
- }
-
- /* On exit, we must delete the _CID return object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_execute_UID
- *
- * PARAMETERS: device_node - Node for the device
- * Uid - Where the UID is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Executes the _UID control method that returns the hardware
- * ID of the device.
- *
- * NOTE: Internal function, no parameter validation
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
- struct acpica_device_id *uid)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ut_execute_UID);
-
- status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
- ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
- &obj_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
-
- /* Convert the Numeric UID to string */
-
- acpi_ex_unsigned_integer_to_string(obj_desc->integer.value,
- uid->value);
- } else {
- /* Copy the String UID from the returned object */
-
- acpi_ut_copy_id_string(uid->value, obj_desc->string.pointer,
- sizeof(uid->value));
- }
+ *value = obj_desc->integer.value;
/* On exit, we must delete the return object */
@@ -716,60 +419,64 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_execute_Sxds
+ * FUNCTION: acpi_ut_execute_power_methods
*
* PARAMETERS: device_node - Node for the device
- * Flags - Where the status flags are returned
+ * method_names - Array of power method names
+ * method_count - Number of methods to execute
+ * out_values - Where the power method values are returned
*
- * RETURN: Status
+ * RETURN: Status, out_values
*
- * DESCRIPTION: Executes _STA for selected device and stores results in
- * *Flags.
+ * DESCRIPTION: Executes the specified power methods for the device and returns
+ * the result(s).
*
* NOTE: Internal function, no parameter validation
*
- ******************************************************************************/
+******************************************************************************/
acpi_status
-acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest)
+acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
+ const char **method_names,
+ u8 method_count, u8 *out_values)
{
union acpi_operand_object *obj_desc;
acpi_status status;
+ acpi_status final_status = AE_NOT_FOUND;
u32 i;
- ACPI_FUNCTION_TRACE(ut_execute_sxds);
+ ACPI_FUNCTION_TRACE(ut_execute_power_methods);
- for (i = 0; i < 4; i++) {
- highest[i] = 0xFF;
+ for (i = 0; i < method_count; i++) {
+ /*
+ * Execute the power method (_sx_d or _sx_w). The only allowable
+ * return type is an Integer.
+ */
status = acpi_ut_evaluate_object(device_node,
ACPI_CAST_PTR(char,
- acpi_gbl_highest_dstate_names
- [i]),
+ method_names[i]),
ACPI_BTYPE_INTEGER, &obj_desc);
- if (ACPI_FAILURE(status)) {
- if (status != AE_NOT_FOUND) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "%s on Device %4.4s, %s\n",
- ACPI_CAST_PTR(char,
- acpi_gbl_highest_dstate_names
- [i]),
- acpi_ut_get_node_name
- (device_node),
- acpi_format_exception
- (status)));
-
- return_ACPI_STATUS(status);
- }
- } else {
- /* Extract the Dstate value */
-
- highest[i] = (u8) obj_desc->integer.value;
+ if (ACPI_SUCCESS(status)) {
+ out_values[i] = (u8)obj_desc->integer.value;
/* Delete the return object */
acpi_ut_remove_reference(obj_desc);
+ final_status = AE_OK; /* At least one value is valid */
+ continue;
}
+
+ out_values[i] = ACPI_UINT8_MAX;
+ if (status == AE_NOT_FOUND) {
+ continue; /* Ignore if not found */
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Failed %s on Device %4.4s, %s\n",
+ ACPI_CAST_PTR(char, method_names[i]),
+ acpi_ut_get_node_name(device_node),
+ acpi_format_exception(status)));
}
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(final_status);
}
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 59e46f257c02..9e33b6261939 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -90,7 +90,15 @@ const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S5_"
};
-const char *acpi_gbl_highest_dstate_names[4] = {
+const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS] = {
+ "_S0W",
+ "_S1W",
+ "_S2W",
+ "_S3W",
+ "_S4W"
+};
+
+const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = {
"_S1D",
"_S2D",
"_S3D",
@@ -351,6 +359,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
"SMBus",
"SystemCMOS",
"PCIBARTarget",
+ "IPMI",
"DataTable"
};
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
new file mode 100644
index 000000000000..52eaae404554
--- /dev/null
+++ b/drivers/acpi/acpica/utids.c
@@ -0,0 +1,382 @@
+/******************************************************************************
+ *
+ * Module Name: utids - support for device IDs - HID, UID, CID
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acinterp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utids")
+
+/* Local prototypes */
+static void acpi_ut_copy_id_string(char *destination, char *source);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_id_string
+ *
+ * PARAMETERS: Destination - Where to copy the string
+ * Source - Source string
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
+ * Performs removal of a leading asterisk if present -- workaround
+ * for a known issue on a bunch of machines.
+ *
+ ******************************************************************************/
+
+static void acpi_ut_copy_id_string(char *destination, char *source)
+{
+
+ /*
+ * Workaround for ID strings that have a leading asterisk. This construct
+ * is not allowed by the ACPI specification (ID strings must be
+ * alphanumeric), but enough existing machines have this embedded in their
+ * ID strings that the following code is useful.
+ */
+ if (*source == '*') {
+ source++;
+ }
+
+ /* Do the actual copy */
+
+ ACPI_STRCPY(destination, source);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_HID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_id - Where the string HID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _HID control method that returns the hardware
+ * ID of the device. The HID is either an 32-bit encoded EISAID
+ * Integer or a String. A string is always returned. An EISAID
+ * is converted to a string.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id *hid;
+ u32 length;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ut_execute_HID);
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the size of the String to be returned, includes null terminator */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ length = ACPI_EISAID_STRING_SIZE;
+ } else {
+ length = obj_desc->string.length + 1;
+ }
+
+ /* Allocate a buffer for the HID */
+
+ hid =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) +
+ (acpi_size) length);
+ if (!hid) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for the string starts after DEVICE_ID struct */
+
+ hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id));
+
+ /* Convert EISAID to a string or simply copy existing string */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
+ } else {
+ acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer);
+ }
+
+ hid->length = length;
+ *return_id = hid;
+
+cleanup:
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_UID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_id - Where the string UID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _UID control method that returns the unique
+ * ID of the device. The UID is either a 64-bit Integer (NOT an
+ * EISAID) or a string. Always returns a string. A 64-bit integer
+ * is converted to a decimal string.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id **return_id)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id *uid;
+ u32 length;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ut_execute_UID);
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the size of the String to be returned, includes null terminator */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ length = ACPI_MAX64_DECIMAL_DIGITS + 1;
+ } else {
+ length = obj_desc->string.length + 1;
+ }
+
+ /* Allocate a buffer for the UID */
+
+ uid =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) +
+ (acpi_size) length);
+ if (!uid) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for the string starts after DEVICE_ID struct */
+
+ uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id));
+
+ /* Convert an Integer to string, or just copy an existing string */
+
+ if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
+ acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
+ } else {
+ acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer);
+ }
+
+ uid->length = length;
+ *return_id = uid;
+
+cleanup:
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_CID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * return_cid_list - Where the CID list is returned
+ *
+ * RETURN: Status, list of CID strings
+ *
+ * DESCRIPTION: Executes the _CID control method that returns one or more
+ * compatible hardware IDs for the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ * A _CID method can return either a single compatible ID or a package of
+ * compatible IDs. Each compatible ID can be one of the following:
+ * 1) Integer (32 bit compressed EISA ID) or
+ * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
+ *
+ * The Integer CIDs are converted to string format by this function.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id_list **return_cid_list)
+{
+ union acpi_operand_object **cid_objects;
+ union acpi_operand_object *obj_desc;
+ struct acpica_device_id_list *cid_list;
+ char *next_id_string;
+ u32 string_area_size;
+ u32 length;
+ u32 cid_list_size;
+ acpi_status status;
+ u32 count;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE(ut_execute_CID);
+
+ /* Evaluate the _CID method for this device */
+
+ status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
+ | ACPI_BTYPE_PACKAGE, &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Get the count and size of the returned _CIDs. _CID can return either
+ * a Package of Integers/Strings or a single Integer or String.
+ * Note: This section also validates that all CID elements are of the
+ * correct type (Integer or String).
+ */
+ if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
+ count = obj_desc->package.count;
+ cid_objects = obj_desc->package.elements;
+ } else { /* Single Integer or String CID */
+
+ count = 1;
+ cid_objects = &obj_desc;
+ }
+
+ string_area_size = 0;
+ for (i = 0; i < count; i++) {
+
+ /* String lengths include null terminator */
+
+ switch (cid_objects[i]->common.type) {
+ case ACPI_TYPE_INTEGER:
+ string_area_size += ACPI_EISAID_STRING_SIZE;
+ break;
+
+ case ACPI_TYPE_STRING:
+ string_area_size += cid_objects[i]->string.length + 1;
+ break;
+
+ default:
+ status = AE_TYPE;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Now that we know the length of the CIDs, allocate return buffer:
+ * 1) Size of the base structure +
+ * 2) Size of the CID DEVICE_ID array +
+ * 3) Size of the actual CID strings
+ */
+ cid_list_size = sizeof(struct acpica_device_id_list) +
+ ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size;
+
+ cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
+ if (!cid_list) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Area for CID strings starts after the CID DEVICE_ID array */
+
+ next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
+ ((acpi_size) count * sizeof(struct acpica_device_id));
+
+ /* Copy/convert the CIDs to the return buffer */
+
+ for (i = 0; i < count; i++) {
+ if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
+
+ /* Convert the Integer (EISAID) CID to a string */
+
+ acpi_ex_eisa_id_to_string(next_id_string,
+ cid_objects[i]->integer.
+ value);
+ length = ACPI_EISAID_STRING_SIZE;
+ } else { /* ACPI_TYPE_STRING */
+
+ /* Copy the String CID from the returned object */
+
+ acpi_ut_copy_id_string(next_id_string,
+ cid_objects[i]->string.pointer);
+ length = cid_objects[i]->string.length + 1;
+ }
+
+ cid_list->ids[i].string = next_id_string;
+ cid_list->ids[i].length = length;
+ next_id_string += length;
+ }
+
+ /* Finish the CID list */
+
+ cid_list->count = count;
+ cid_list->list_size = cid_list_size;
+ *return_cid_list = cid_list;
+
+cleanup:
+
+ /* On exit, we must delete the _CID return object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index fbe782348b0b..61f6315fce9f 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -50,6 +50,11 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmisc")
+/*
+ * Common suffix for messages
+ */
+#define ACPI_COMMON_MSG_SUFFIX \
+ acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
/*******************************************************************************
*
* FUNCTION: acpi_ut_validate_exception
@@ -120,6 +125,34 @@ const char *acpi_ut_validate_exception(acpi_status status)
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_is_pci_root_bridge
+ *
+ * PARAMETERS: Id - The HID/CID in string format
+ *
+ * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_is_pci_root_bridge(char *id)
+{
+
+ /*
+ * Check if this is a PCI root bridge.
+ * ACPI 3.0+: check for a PCI Express root also.
+ */
+ if (!(ACPI_STRCMP(id,
+ PCI_ROOT_HID_STRING)) ||
+ !(ACPI_STRCMP(id, PCI_EXPRESS_ROOT_HID_STRING))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_is_aml_table
*
* PARAMETERS: Table - An ACPI table
@@ -1037,8 +1070,7 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1052,8 +1084,7 @@ acpi_exception(const char *module_name,
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1066,8 +1097,7 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
- line_number);
+ ACPI_COMMON_MSG_SUFFIX;
va_end(args);
}
@@ -1088,3 +1118,46 @@ ACPI_EXPORT_SYMBOL(acpi_error)
ACPI_EXPORT_SYMBOL(acpi_exception)
ACPI_EXPORT_SYMBOL(acpi_warning)
ACPI_EXPORT_SYMBOL(acpi_info)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ * only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of error
+ * messages for methods that are repeatedly evaluated.
+ *
+******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...)
+{
+ va_list args;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf("ACPI Warning for %s: ", pathname);
+
+ va_start(args, format);
+ acpi_os_vprintf(format, args);
+ ACPI_COMMON_MSG_SUFFIX;
+ va_end(args);
+}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2876fc70c3a9..620183f13e5e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -141,7 +141,7 @@ int acpi_bus_get_status(struct acpi_device *device)
EXPORT_SYMBOL(acpi_bus_get_status);
void acpi_bus_private_data_handler(acpi_handle handle,
- u32 function, void *context)
+ void *context)
{
return;
}
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 5f2c3c00a315..642bb305cb65 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -202,20 +202,17 @@ container_walk_namespace_cb(acpi_handle handle,
u32 lvl, void *context, void **rv)
{
char *hid = NULL;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info;
acpi_status status;
int *action = context;
-
- status = acpi_get_object_info(handle, &buffer);
- if (ACPI_FAILURE(status) || !buffer.pointer) {
+ status = acpi_get_object_info(handle, &info);
+ if (ACPI_FAILURE(status)) {
return AE_OK;
}
- info = buffer.pointer;
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.value;
+ hid = info->hardware_id.string;
if (hid == NULL) {
goto end;
@@ -242,7 +239,7 @@ container_walk_namespace_cb(acpi_handle handle,
}
end:
- kfree(buffer.pointer);
+ kfree(info);
return AE_OK;
}
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 9a855669ff12..3a2cfefc71ab 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -233,18 +233,16 @@ static int is_ata(acpi_handle handle)
static int is_battery(acpi_handle handle)
{
struct acpi_device_info *info;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
int ret = 1;
- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
return 0;
- info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID))
ret = 0;
else
- ret = !strcmp("PNP0C0A", info->hardware_id.value);
+ ret = !strcmp("PNP0C0A", info->hardware_id.string);
- kfree(buffer.pointer);
+ kfree(info);
return ret;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5180f0f1dd02..f28619d658f7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -787,6 +787,42 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
return AE_CTRL_TERMINATE;
}
+static int ec_install_handlers(struct acpi_ec *ec)
+{
+ acpi_status status;
+ if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
+ return 0;
+ status = acpi_install_gpe_handler(NULL, ec->gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe);
+ status = acpi_install_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler,
+ NULL, ec);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_NOT_FOUND) {
+ /*
+ * Maybe OS fails in evaluating the _REG object.
+ * The AE_NOT_FOUND error will be ignored and OS
+ * continue to initialize EC.
+ */
+ printk(KERN_ERR "Fail in evaluating the _REG object"
+ " of EC device. Broken bios is suspected.\n");
+ } else {
+ acpi_remove_gpe_handler(NULL, ec->gpe,
+ &acpi_ec_gpe_handler);
+ return -ENODEV;
+ }
+ }
+
+ set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
+ return 0;
+}
+
static void ec_remove_handlers(struct acpi_ec *ec)
{
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
@@ -801,9 +837,8 @@ static void ec_remove_handlers(struct acpi_ec *ec)
static int acpi_ec_add(struct acpi_device *device)
{
struct acpi_ec *ec = NULL;
+ int ret;
- if (!device)
- return -EINVAL;
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
@@ -838,7 +873,12 @@ static int acpi_ec_add(struct acpi_device *device)
ec->gpe, ec->command_addr, ec->data_addr);
pr_info(PREFIX "driver started in %s mode\n",
(test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");
- return 0;
+
+ ret = ec_install_handlers(ec);
+
+ /* EC is fully operational, allow queries */
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ return ret;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
@@ -850,6 +890,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
return -EINVAL;
ec = acpi_driver_data(device);
+ ec_remove_handlers(ec);
mutex_lock(&ec->lock);
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
list_del(&handler->node);
@@ -887,75 +928,6 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
return AE_OK;
}
-static int ec_install_handlers(struct acpi_ec *ec)
-{
- acpi_status status;
- if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
- return 0;
- status = acpi_install_gpe_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->gpe);
- status = acpi_install_address_space_handler(ec->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- NULL, ec);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_FOUND) {
- /*
- * Maybe OS fails in evaluating the _REG object.
- * The AE_NOT_FOUND error will be ignored and OS
- * continue to initialize EC.
- */
- printk(KERN_ERR "Fail in evaluating the _REG object"
- " of EC device. Broken bios is suspected.\n");
- } else {
- acpi_remove_gpe_handler(NULL, ec->gpe,
- &acpi_ec_gpe_handler);
- return -ENODEV;
- }
- }
-
- set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
- return 0;
-}
-
-static int acpi_ec_start(struct acpi_device *device)
-{
- struct acpi_ec *ec;
- int ret = 0;
-
- if (!device)
- return -EINVAL;
-
- ec = acpi_driver_data(device);
-
- if (!ec)
- return -EINVAL;
-
- ret = ec_install_handlers(ec);
-
- /* EC is fully operational, allow queries */
- clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
- return ret;
-}
-
-static int acpi_ec_stop(struct acpi_device *device, int type)
-{
- struct acpi_ec *ec;
- if (!device)
- return -EINVAL;
- ec = acpi_driver_data(device);
- if (!ec)
- return -EINVAL;
- ec_remove_handlers(ec);
-
- return 0;
-}
-
int __init acpi_boot_ec_enable(void)
{
if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
@@ -1076,8 +1048,6 @@ static struct acpi_driver acpi_ec_driver = {
.ops = {
.add = acpi_ec_add,
.remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
.suspend = acpi_ec_suspend,
.resume = acpi_ec_resume,
},
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index dc36a448de43..c6645f26224b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -95,15 +95,13 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
struct acpi_device_info *info;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_find_child *find = context;
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_SUCCESS(status)) {
- info = buffer.pointer;
if (info->address == find->address)
find->handle = handle;
- kfree(buffer.pointer);
+ kfree(info);
}
return AE_OK;
}
@@ -123,7 +121,7 @@ EXPORT_SYMBOL(acpi_get_child);
/* Link ACPI devices with physical devices */
static void acpi_glue_data_handler(acpi_handle handle,
- u32 function, void *context)
+ void *context)
{
/* we provide an empty handler */
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 71670719d61a..5691f165a952 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -189,11 +189,36 @@ acpi_status __init acpi_os_initialize(void)
return AE_OK;
}
+static void bind_to_cpu0(struct work_struct *work)
+{
+ set_cpus_allowed(current, cpumask_of_cpu(0));
+ kfree(work);
+}
+
+static void bind_workqueue(struct workqueue_struct *wq)
+{
+ struct work_struct *work;
+
+ work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
+ INIT_WORK(work, bind_to_cpu0);
+ queue_work(wq, work);
+}
+
acpi_status acpi_os_initialize1(void)
{
+ /*
+ * On some machines, a software-initiated SMI causes corruption unless
+ * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
+ * typically it's done in GPE-related methods that are run via
+ * workqueues, so we can avoid the known corruption cases by binding
+ * the workqueues to CPU 0.
+ */
kacpid_wq = create_singlethread_workqueue("kacpid");
+ bind_workqueue(kacpid_wq);
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
+ bind_workqueue(kacpi_notify_wq);
kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
+ bind_workqueue(kacpi_hotplug_wq);
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index dee916707a7d..31122214e0ec 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -63,20 +63,6 @@ static struct acpi_driver acpi_pci_root_driver = {
},
};
-struct acpi_pci_root {
- struct list_head node;
- struct acpi_device *device;
- struct pci_bus *bus;
- u16 segment;
- u8 bus_nr;
-
- u32 osc_support_set; /* _OSC state of support bits */
- u32 osc_control_set; /* _OSC state of control bits */
- u32 osc_control_qry; /* the latest _OSC query result */
-
- u32 osc_queried:1; /* has _OSC control been queried? */
-};
-
static LIST_HEAD(acpi_pci_roots);
static struct acpi_pci_driver *sub_driver;
@@ -319,7 +305,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
return status;
}
-static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
+struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
{
struct acpi_pci_root *root;
@@ -329,6 +315,7 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
}
return NULL;
}
+EXPORT_SYMBOL_GPL(acpi_pci_find_root);
struct acpi_handle_node {
struct list_head node;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 524984067748..8f8952a8fc72 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -81,9 +81,10 @@ MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_start(struct acpi_device *device);
static int acpi_processor_remove(struct acpi_device *device, int type);
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
+#endif
static void acpi_processor_notify(struct acpi_device *device, u32 event);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
@@ -103,7 +104,6 @@ static struct acpi_driver acpi_processor_driver = {
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
- .start = acpi_processor_start,
.suspend = acpi_processor_suspend,
.resume = acpi_processor_resume,
.notify = acpi_processor_notify,
@@ -112,7 +112,7 @@ static struct acpi_driver acpi_processor_driver = {
#define INSTALL_NOTIFY_HANDLER 1
#define UNINSTALL_NOTIFY_HANDLER 2
-
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_processor_info_fops = {
.owner = THIS_MODULE,
.open = acpi_processor_info_open_fs,
@@ -120,6 +120,7 @@ static const struct file_operations acpi_processor_info_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
DEFINE_PER_CPU(struct acpi_processor *, processors);
struct acpi_processor_errata errata __read_mostly;
@@ -318,6 +319,7 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr)
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_processor_dir = NULL;
static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
@@ -390,7 +392,6 @@ static int acpi_processor_add_fs(struct acpi_device *device)
return -EIO;
return 0;
}
-
static int acpi_processor_remove_fs(struct acpi_device *device)
{
@@ -407,6 +408,16 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
return 0;
}
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif
/* Use the acpiid in MADT to map cpus in case of SMP */
@@ -700,92 +711,6 @@ static int acpi_processor_get_info(struct acpi_device *device)
static DEFINE_PER_CPU(void *, processor_device_array);
-static int __cpuinit acpi_processor_start(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_processor *pr;
- struct sys_device *sysdev;
-
- pr = acpi_driver_data(device);
-
- result = acpi_processor_get_info(device);
- if (result) {
- /* Processor is physically not present */
- return 0;
- }
-
- BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
-
- /*
- * Buggy BIOS check
- * ACPI id of processors can be reported wrongly by the BIOS.
- * Don't trust it blindly
- */
- if (per_cpu(processor_device_array, pr->id) != NULL &&
- per_cpu(processor_device_array, pr->id) != device) {
- printk(KERN_WARNING "BIOS reported wrong ACPI id "
- "for the processor\n");
- return -ENODEV;
- }
- per_cpu(processor_device_array, pr->id) = device;
-
- per_cpu(processors, pr->id) = pr;
-
- result = acpi_processor_add_fs(device);
- if (result)
- goto end;
-
- sysdev = get_cpu_sysdev(pr->id);
- if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev"))
- return -EFAULT;
-
- /* _PDC call should be done before doing anything else (if reqd.). */
- arch_acpi_processor_init_pdc(pr);
- acpi_processor_set_pdc(pr);
- arch_acpi_processor_cleanup_pdc(pr);
-
-#ifdef CONFIG_CPU_FREQ
- acpi_processor_ppc_has_changed(pr);
-#endif
- acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
-
-
- acpi_processor_power_init(pr, device);
-
- pr->cdev = thermal_cooling_device_register("Processor", device,
- &processor_cooling_ops);
- if (IS_ERR(pr->cdev)) {
- result = PTR_ERR(pr->cdev);
- goto end;
- }
-
- dev_info(&device->dev, "registered as cooling_device%d\n",
- pr->cdev->id);
-
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
-
- if (pr->flags.throttling) {
- printk(KERN_INFO PREFIX "%s [%s] (supports",
- acpi_device_name(device), acpi_device_bid(device));
- printk(" %d throttling states", pr->throttling.state_count);
- printk(")\n");
- }
-
- end:
-
- return result;
-}
-
static void acpi_processor_notify(struct acpi_device *device, u32 event)
{
struct acpi_processor *pr = acpi_driver_data(device);
@@ -848,10 +773,8 @@ static struct notifier_block acpi_cpu_notifier =
static int acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
-
-
- if (!device)
- return -EINVAL;
+ int result = 0;
+ struct sys_device *sysdev;
pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr)
@@ -867,7 +790,100 @@ static int acpi_processor_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
device->driver_data = pr;
+ result = acpi_processor_get_info(device);
+ if (result) {
+ /* Processor is physically not present */
+ return 0;
+ }
+
+ BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
+
+ /*
+ * Buggy BIOS check
+ * ACPI id of processors can be reported wrongly by the BIOS.
+ * Don't trust it blindly
+ */
+ if (per_cpu(processor_device_array, pr->id) != NULL &&
+ per_cpu(processor_device_array, pr->id) != device) {
+ printk(KERN_WARNING "BIOS reported wrong ACPI id "
+ "for the processor\n");
+ result = -ENODEV;
+ goto err_free_cpumask;
+ }
+ per_cpu(processor_device_array, pr->id) = device;
+
+ per_cpu(processors, pr->id) = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto err_free_cpumask;
+
+ sysdev = get_cpu_sysdev(pr->id);
+ if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
+ result = -EFAULT;
+ goto err_remove_fs;
+ }
+
+ /* _PDC call should be done before doing anything else (if reqd.). */
+ arch_acpi_processor_init_pdc(pr);
+ acpi_processor_set_pdc(pr);
+ arch_acpi_processor_cleanup_pdc(pr);
+
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
+
+ acpi_processor_power_init(pr, device);
+
+ pr->cdev = thermal_cooling_device_register("Processor", device,
+ &processor_cooling_ops);
+ if (IS_ERR(pr->cdev)) {
+ result = PTR_ERR(pr->cdev);
+ goto err_power_exit;
+ }
+
+ dev_info(&device->dev, "registered as cooling_device%d\n",
+ pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_thermal_unregister;
+ }
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result) {
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ goto err_remove_sysfs;
+ }
+
+ if (pr->flags.throttling) {
+ printk(KERN_INFO PREFIX "%s [%s] (supports",
+ acpi_device_name(device), acpi_device_bid(device));
+ printk(" %d throttling states", pr->throttling.state_count);
+ printk(")\n");
+ }
+
return 0;
+
+err_remove_sysfs:
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+err_thermal_unregister:
+ thermal_cooling_device_unregister(pr->cdev);
+err_power_exit:
+ acpi_processor_power_exit(pr, device);
+err_remove_fs:
+ acpi_processor_remove_fs(device);
+err_free_cpumask:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+
+ return result;
}
static int acpi_processor_remove(struct acpi_device *device, int type)
@@ -944,7 +960,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
{
acpi_handle phandle;
struct acpi_device *pdev;
- struct acpi_processor *pr;
if (acpi_get_parent(handle, &phandle)) {
@@ -959,15 +974,6 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return -ENODEV;
}
- acpi_bus_start(*device);
-
- pr = acpi_driver_data(*device);
- if (!pr)
- return -ENODEV;
-
- if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {
- kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
- }
return 0;
}
@@ -997,25 +1003,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
"Unable to add the device\n");
break;
}
-
- pr = acpi_driver_data(device);
- if (!pr) {
- printk(KERN_ERR PREFIX "Driver data is NULL\n");
- break;
- }
-
- if (pr->id >= 0 && (pr->id < nr_cpu_ids)) {
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- break;
- }
-
- result = acpi_processor_start(device);
- if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) {
- kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
- } else {
- printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
- acpi_device_bid(device));
- }
break;
case ACPI_NOTIFY_EJECT_REQUEST:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1032,9 +1019,6 @@ static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
"Driver data is NULL, dropping EJECT\n");
return;
}
-
- if ((pr->id < nr_cpu_ids) && (cpu_present(pr->id)))
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1160,11 +1144,11 @@ static int __init acpi_processor_init(void)
(struct acpi_table_header **)&madt)))
madt = NULL;
#endif
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
return -ENOMEM;
-
+#endif
/*
* Check whether the system is DMI table. If yes, OSPM
* should not use mwait for CPU-states.
@@ -1192,7 +1176,9 @@ out_cpuidle:
cpuidle_unregister_driver(&acpi_idle_driver);
out_proc:
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return result;
}
@@ -1209,7 +1195,9 @@ static void __exit acpi_processor_exit(void)
cpuidle_unregister_driver(&acpi_idle_driver);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e605a002b0a1..dbeb516a3fda 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -680,6 +680,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
return 0;
}
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = seq->private;
@@ -759,7 +760,7 @@ static const struct file_operations acpi_processor_power_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-
+#endif
/**
* acpi_idle_bm_check - checks if bus master activity was detected
@@ -1160,7 +1161,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
{
acpi_status status = 0;
static int first_run;
+#ifdef CONFIG_ACPI_PROCFS
struct proc_dir_entry *entry = NULL;
+#endif
unsigned int i;
if (boot_option_idle_override)
@@ -1217,7 +1220,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
pr->power.states[i].type);
printk(")\n");
}
-
+#ifdef CONFIG_ACPI_PROCFS
/* 'power' [R] */
entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER,
S_IRUGO, acpi_device_dir(device),
@@ -1225,6 +1228,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_driver_data(device));
if (!entry)
return -EIO;
+#endif
return 0;
}
@@ -1237,9 +1241,11 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
cpuidle_unregister_device(&pr->power.dev);
pr->flags.power_setup_done = 0;
+#ifdef CONFIG_ACPI_PROCFS
if (acpi_device_dir(device))
remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
acpi_device_dir(device));
+#endif
return 0;
}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 11088cf10319..8ba0ed0b9ddb 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -511,7 +511,7 @@ int acpi_processor_preregister_performance(
struct acpi_processor *match_pr;
struct acpi_psd_package *match_pdomain;
- if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
return -ENOMEM;
mutex_lock(&performance_mutex);
@@ -558,7 +558,6 @@ int acpi_processor_preregister_performance(
* Now that we have _PSD data from all CPUs, lets setup P-state
* domain info.
*/
- cpumask_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = per_cpu(processors, i);
if (!pr)
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 39ed8d17b476..d26f32131a7c 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -440,7 +440,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = {
};
/* /proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
@@ -519,3 +519,4 @@ const struct file_operations acpi_processor_limit_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index e175042177c2..57bc64ca763d 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -76,7 +76,7 @@ static int acpi_processor_update_tsd_coord(void)
struct acpi_tsd_package *pdomain, *match_pdomain;
struct acpi_processor_throttling *pthrottling, *match_pthrottling;
- if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
return -ENOMEM;
/*
@@ -104,7 +104,6 @@ static int acpi_processor_update_tsd_coord(void)
if (retval)
goto err_ret;
- cpumask_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = per_cpu(processors, i);
if (!pr)
@@ -619,6 +618,8 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
u32 duty_mask = 0;
u32 duty_value = 0;
+ WARN_ON_ONCE(!irqs_disabled());
+
if (!pr)
return -EINVAL;
@@ -631,8 +632,6 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
duty_mask <<= pr->throttling.duty_offset;
- local_irq_disable();
-
value = inl(pr->throttling.address);
/*
@@ -649,8 +648,6 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
pr->throttling.state = state;
- local_irq_enable();
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling state is T%d (%d%% throttling applied)\n",
state, pr->throttling.states[state].performance));
@@ -854,10 +851,21 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
return 0;
}
+struct get_throttling {
+ struct acpi_processor *pr;
+ int ret;
+};
+
+static void get_throttling(void *_gt)
+{
+ struct get_throttling *gt = _gt;
+
+ gt->ret = gt->pr->throttling.acpi_processor_get_throttling(gt->pr);
+}
+
static int acpi_processor_get_throttling(struct acpi_processor *pr)
{
- cpumask_var_t saved_mask;
- int ret;
+ struct get_throttling gt;
if (!pr)
return -EINVAL;
@@ -865,21 +873,9 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
if (!pr->flags.throttling)
return -ENODEV;
- if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
- return -ENOMEM;
-
- /*
- * Migrate task to the cpu pointed by pr.
- */
- cpumask_copy(saved_mask, &current->cpus_allowed);
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
- ret = pr->throttling.acpi_processor_get_throttling(pr);
- /* restore the previous state */
- set_cpus_allowed_ptr(current, saved_mask);
- free_cpumask_var(saved_mask);
-
- return ret;
+ gt.pr = pr;
+ smp_call_function_single(pr->id, get_throttling, &gt, 1);
+ return gt.ret;
}
static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
@@ -923,6 +919,8 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
u32 duty_mask = 0;
u32 duty_value = 0;
+ WARN_ON_ONCE(!irqs_disabled());
+
if (!pr)
return -EINVAL;
@@ -952,8 +950,6 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
duty_mask = ~duty_mask;
}
- local_irq_disable();
-
/*
* Disable throttling by writing a 0 to bit 4. Note that we must
* turn it off before you can change the duty_value.
@@ -979,8 +975,6 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
pr->throttling.state = state;
- local_irq_enable();
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling state set to T%d (%d%%)\n", state,
(pr->throttling.states[state].performance ? pr->
@@ -1020,9 +1014,23 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
return 0;
}
+struct set_throttling_info {
+ struct acpi_processor *pr;
+ struct acpi_processor_throttling *p_throttling;
+ int target_state;
+ int ret;
+};
+
+static void set_throttling(void *_sti)
+{
+ struct set_throttling_info *s = _sti;
+
+ s->ret = s->p_throttling->acpi_processor_set_throttling(s->pr,
+ s->target_state);
+}
+
int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
{
- cpumask_var_t saved_mask;
int ret = 0;
unsigned int i;
struct acpi_processor *match_pr;
@@ -1039,15 +1047,9 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
return -EINVAL;
- if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
+ if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL))
return -ENOMEM;
- if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
- free_cpumask_var(saved_mask);
- return -ENOMEM;
- }
-
- cpumask_copy(saved_mask, &current->cpus_allowed);
t_state.target_state = state;
p_throttling = &(pr->throttling);
cpumask_and(online_throttling_cpus, cpu_online_mask,
@@ -1069,10 +1071,10 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
* it can be called only for the cpu pointed by pr.
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
- ret = p_throttling->acpi_processor_set_throttling(pr,
- t_state.target_state);
+ struct set_throttling_info sti
+ = { pr, p_throttling, t_state.target_state };
+ smp_call_function_single(pr->id, set_throttling, &sti, 1);
+ ret = sti.ret;
} else {
/*
* When the T-state coordination is SW_ALL or HW_ALL,
@@ -1080,6 +1082,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
* cpus.
*/
for_each_cpu(i, online_throttling_cpus) {
+ struct set_throttling_info sti;
+
match_pr = per_cpu(processors, i);
/*
* If the pointer is invalid, we will report the
@@ -1101,11 +1105,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
continue;
}
t_state.cpu = i;
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(i));
- ret = match_pr->throttling.
- acpi_processor_set_throttling(
- match_pr, t_state.target_state);
+ sti.pr = match_pr;
+ sti.p_throttling = &match_pr->throttling;
+ sti.target_state = t_state.target_state;
+ smp_call_function_single(i, set_throttling, &sti, 1);
+ ret = sti.ret;
}
}
/*
@@ -1119,11 +1123,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
&t_state);
}
- /* restore the previous state */
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, saved_mask);
- free_cpumask_var(online_throttling_cpus);
- free_cpumask_var(saved_mask);
return ret;
}
@@ -1216,7 +1215,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
}
/* proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_throttling_seq_show(struct seq_file *seq,
void *offset)
{
@@ -1324,3 +1323,4 @@ const struct file_operations acpi_processor_throttling_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 781435d7e369..3ceebfe55ea5 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -60,13 +60,13 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
}
if (acpi_dev->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list;
+ struct acpica_device_id_list *cid_list;
int i;
cid_list = acpi_dev->pnp.cid_list;
for (i = 0; i < cid_list->count; i++) {
count = snprintf(&modalias[len], size, "%s:",
- cid_list->id[i].value);
+ cid_list->ids[i].string);
if (count < 0 || count >= size) {
printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
acpi_dev->pnp.device_name, i);
@@ -287,14 +287,14 @@ int acpi_match_device_ids(struct acpi_device *device,
}
if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+ struct acpica_device_id_list *cid_list = device->pnp.cid_list;
int i;
for (id = ids; id->id[0]; id++) {
/* compare multiple _CID entries against driver ids */
for (i = 0; i < cid_list->count; i++) {
if (!strcmp((char*)id->id,
- cid_list->id[i].value))
+ cid_list->ids[i].string))
return 0;
}
}
@@ -426,9 +426,6 @@ static int acpi_device_probe(struct device * dev)
if (acpi_drv->ops.notify) {
ret = acpi_device_install_notify_handler(acpi_dev);
if (ret) {
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev,
- acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev,
acpi_dev->removal_type);
@@ -452,8 +449,6 @@ static int acpi_device_remove(struct device * dev)
if (acpi_drv) {
if (acpi_drv->ops.notify)
acpi_device_remove_notify_handler(acpi_dev);
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
}
@@ -687,7 +682,7 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+void acpi_bus_data_handler(acpi_handle handle, void *context)
{
/* TBD */
@@ -999,33 +994,89 @@ static int acpi_dock_match(struct acpi_device *device)
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
+static struct acpica_device_id_list*
+acpi_add_cid(
+ struct acpi_device_info *info,
+ struct acpica_device_id *new_cid)
+{
+ struct acpica_device_id_list *cid;
+ char *next_id_string;
+ acpi_size cid_length;
+ acpi_size new_cid_length;
+ u32 i;
+
+
+ /* Allocate new CID list with room for the new CID */
+
+ if (!new_cid)
+ new_cid_length = info->compatible_id_list.list_size;
+ else if (info->compatible_id_list.list_size)
+ new_cid_length = info->compatible_id_list.list_size +
+ new_cid->length + sizeof(struct acpica_device_id);
+ else
+ new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length;
+
+ cid = ACPI_ALLOCATE_ZEROED(new_cid_length);
+ if (!cid) {
+ return NULL;
+ }
+
+ cid->list_size = new_cid_length;
+ cid->count = info->compatible_id_list.count;
+ if (new_cid)
+ cid->count++;
+ next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id));
+
+ /* Copy all existing CIDs */
+
+ for (i = 0; i < info->compatible_id_list.count; i++) {
+ cid_length = info->compatible_id_list.ids[i].length;
+ cid->ids[i].string = next_id_string;
+ cid->ids[i].length = cid_length;
+
+ ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string,
+ cid_length);
+
+ next_id_string += cid_length;
+ }
+
+ /* Append the new CID */
+
+ if (new_cid) {
+ cid->ids[i].string = next_id_string;
+ cid->ids[i].length = new_cid->length;
+
+ ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length);
+ }
+
+ return cid;
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
{
- struct acpi_device_info *info;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_device_info *info = NULL;
char *hid = NULL;
char *uid = NULL;
- struct acpi_compatible_id_list *cid_list = NULL;
- const char *cid_add = NULL;
+ struct acpica_device_id_list *cid_list = NULL;
+ char *cid_add = NULL;
acpi_status status;
switch (type) {
case ACPI_BUS_TYPE_DEVICE:
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return;
}
- info = buffer.pointer;
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.value;
+ hid = info->hardware_id.string;
if (info->valid & ACPI_VALID_UID)
- uid = info->unique_id.value;
+ uid = info->unique_id.string;
if (info->valid & ACPI_VALID_CID)
- cid_list = &info->compatibility_id;
+ cid_list = &info->compatible_id_list;
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
@@ -1076,55 +1127,44 @@ static void acpi_device_set_id(struct acpi_device *device,
}
if (hid) {
- strcpy(device->pnp.hardware_id, hid);
- device->flags.hardware_id = 1;
- }
+ device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1);
+ if (device->pnp.hardware_id) {
+ strcpy(device->pnp.hardware_id, hid);
+ device->flags.hardware_id = 1;
+ }
+ } else
+ device->pnp.hardware_id = NULL;
+
if (uid) {
- strcpy(device->pnp.unique_id, uid);
- device->flags.unique_id = 1;
- }
+ device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1);
+ if (device->pnp.unique_id) {
+ strcpy(device->pnp.unique_id, uid);
+ device->flags.unique_id = 1;
+ }
+ } else
+ device->pnp.unique_id = NULL;
+
if (cid_list || cid_add) {
- struct acpi_compatible_id_list *list;
- int size = 0;
- int count = 0;
-
- if (cid_list) {
- size = cid_list->size;
- } else if (cid_add) {
- size = sizeof(struct acpi_compatible_id_list);
- cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
- if (!cid_list) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(buffer.pointer);
- return;
- } else {
- cid_list->count = 0;
- cid_list->size = size;
- }
+ struct acpica_device_id_list *list;
+
+ if (cid_add) {
+ struct acpica_device_id cid;
+ cid.length = strlen (cid_add) + 1;
+ cid.string = cid_add;
+
+ list = acpi_add_cid(info, &cid);
+ } else {
+ list = acpi_add_cid(info, NULL);
}
- if (cid_add)
- size += sizeof(struct acpi_compatible_id);
- list = kmalloc(size, GFP_KERNEL);
if (list) {
- if (cid_list) {
- memcpy(list, cid_list, cid_list->size);
- count = cid_list->count;
- }
- if (cid_add) {
- strncpy(list->id[count].value, cid_add,
- ACPI_MAX_CID_LENGTH);
- count++;
- device->flags.compatible_ids = 1;
- }
- list->size = size;
- list->count = count;
device->pnp.cid_list = list;
- } else
- printk(KERN_ERR PREFIX "Memory allocation error\n");
+ if (cid_add)
+ device->flags.compatible_ids = 1;
+ }
}
- kfree(buffer.pointer);
+ kfree(info);
}
static int acpi_device_set_context(struct acpi_device *device, int type)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 01574a066534..09c35d65396b 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -257,20 +257,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
/* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(acpi_state);
- /* ACPI 3.0 specs (P62) says that it's the responsibility
- * of the OSPM to clear the status bit [ implying that the
- * POWER_BUTTON event should not reach userspace ]
- */
- if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
- acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
-
- /*
- * Disable and clear GPE status before interrupt is enabled. Some GPEs
- * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
- * acpi_leave_sleep_state will reenable specific GPEs later
- */
- acpi_disable_all_gpes();
-
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
@@ -397,6 +383,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
},
{
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Hewlett-Packard HP G7000 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP G7000 Notebook PC"),
+ },
+ },
+ {
.callback = init_old_suspend_ordering,
.ident = "Panasonic CF51-2L",
.matches = {
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 3daee601b179..d11282975f35 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -123,7 +123,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
table_attr->attr.size = 0;
table_attr->attr.read = acpi_table_show;
table_attr->attr.attr.name = table_attr->name;
- table_attr->attr.attr.mode = 0444;
+ table_attr->attr.attr.mode = 0400;
return;
}
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 246650673010..f60b2b6a0931 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -204,6 +204,7 @@ static void amba_device_release(struct device *dev)
int amba_device_register(struct amba_device *dev, struct resource *parent)
{
u32 pid, cid;
+ u32 size;
void __iomem *tmp;
int i, ret;
@@ -229,16 +230,25 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
if (ret)
goto err_out;
- tmp = ioremap(dev->res.start, SZ_4K);
+ /*
+ * Dynamically calculate the size of the resource
+ * and use this for iomap
+ */
+ size = resource_size(&dev->res);
+ tmp = ioremap(dev->res.start, size);
if (!tmp) {
ret = -ENOMEM;
goto err_release;
}
+ /*
+ * Read pid and cid based on size of resource
+ * they are located at end of region
+ */
for (pid = 0, i = 0; i < 4; i++)
- pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8);
+ pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
for (cid = 0, i = 0; i < 4; i++)
- cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8);
+ cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
iounmap(tmp);
@@ -353,11 +363,14 @@ amba_find_device(const char *busid, struct device *parent, unsigned int id,
int amba_request_regions(struct amba_device *dev, const char *name)
{
int ret = 0;
+ u32 size;
if (!name)
name = dev->dev.driver->name;
- if (!request_mem_region(dev->res.start, SZ_4K, name))
+ size = resource_size(&dev->res);
+
+ if (!request_mem_region(dev->res.start, size, name))
ret = -EBUSY;
return ret;
@@ -371,7 +384,10 @@ int amba_request_regions(struct amba_device *dev, const char *name)
*/
void amba_release_regions(struct amba_device *dev)
{
- release_mem_region(dev->res.start, SZ_4K);
+ u32 size;
+
+ size = resource_size(&dev->res);
+ release_mem_region(dev->res.start, size);
}
EXPORT_SYMBOL(amba_driver_register);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index b17c57f85032..ab2fa4eeb364 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -26,6 +26,17 @@ config ATA_NONSTANDARD
bool
default n
+config ATA_VERBOSE_ERROR
+ bool "Verbose ATA error reporting"
+ default y
+ help
+ This option adds parsing of ATA command descriptions and error bits
+ in libata kernel output, making it easier to interpret.
+ This option will enlarge the kernel by approx. 6KB. Disable it only
+ if kernel size is more important than ease of debugging.
+
+ If unsure, say Y.
+
config ATA_ACPI
bool "ATA ACPI Support"
depends on ACPI && PCI
@@ -586,6 +597,16 @@ config PATA_RB532
If unsure, say N.
+config PATA_RDC
+ tristate "RDC PATA support"
+ depends on PCI
+ help
+ This option enables basic support for the later RDC PATA controllers
+ controllers via the new ATA layer. For the RDC 1010, you need to
+ enable the IT821X driver instead.
+
+ If unsure, say N.
+
config PATA_RZ1000
tristate "PC Tech RZ1000 PATA support"
depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 38906f9bbb4e..463eb52236aa 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
obj-$(CONFIG_PATA_QDI) += pata_qdi.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
+obj-$(CONFIG_PATA_RDC) += pata_rdc.o
obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 336eb1ed73cc..1c63af60dd6e 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -515,10 +515,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -2802,7 +2806,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* prepare host */
if (hpriv->cap & HOST_CAP_NCQ)
- pi.flags |= ATA_FLAG_NCQ;
+ pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index d0a14cf2bd74..56b8a3ff1286 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -596,9 +596,12 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
+ { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on unknown Dell */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
+ { 0x27DF, 0x103C, 0x361a }, /* ICH7 on unkown HP */
{ 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
+ { 0x27DF, 0x152D, 0x0778 }, /* ICH7 on unknown Intel */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
{ 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
{ 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index ac176da1f94e..01964b6e6f6b 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -689,6 +689,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
struct ata_taskfile tf, ptf, rtf;
unsigned int err_mask;
const char *level;
+ const char *descr;
char msg[60];
int rc;
@@ -736,11 +737,13 @@ static int ata_acpi_run_tf(struct ata_device *dev,
snprintf(msg, sizeof(msg), "filtered out");
rc = 0;
}
+ descr = ata_get_cmd_descript(tf.command);
ata_dev_printk(dev, level,
- "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n",
+ "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x (%s) %s\n",
tf.command, tf.feature, tf.nsect, tf.lbal,
- tf.lbam, tf.lbah, tf.device, msg);
+ tf.lbam, tf.lbah, tf.device,
+ (descr ? descr : "unknown"), msg);
return rc;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2c6aedaef718..b9d72d5be75f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1515,6 +1515,7 @@ static int ata_hpa_resize(struct ata_device *dev)
return rc;
}
+ dev->n_native_sectors = native_sectors;
/* nothing to do? */
if (native_sectors <= sectors || !ata_ignore_hpa) {
@@ -2298,29 +2299,49 @@ static inline u8 ata_dev_knobble(struct ata_device *dev)
return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
-static void ata_dev_config_ncq(struct ata_device *dev,
+static int ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+ unsigned int err_mask;
+ char *aa_desc = "";
if (!ata_id_has_ncq(dev->id)) {
desc[0] = '\0';
- return;
+ return 0;
}
if (dev->horkage & ATA_HORKAGE_NONCQ) {
snprintf(desc, desc_sz, "NCQ (not used)");
- return;
+ return 0;
}
if (ap->flags & ATA_FLAG_NCQ) {
hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
dev->flags |= ATA_DFLAG_NCQ;
}
+ if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) &&
+ (ap->flags & ATA_FLAG_FPDMA_AA) &&
+ ata_id_has_fpdma_aa(dev->id)) {
+ err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE,
+ SATA_FPDMA_AA);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to enable AA"
+ "(error_mask=0x%x)\n", err_mask);
+ if (err_mask != AC_ERR_DEV) {
+ dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA;
+ return -EIO;
+ }
+ } else
+ aa_desc = ", AA";
+ }
+
if (hdepth >= ddepth)
- snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc);
else
- snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
+ ddepth, aa_desc);
+ return 0;
}
/**
@@ -2460,7 +2481,7 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_id_has_lba(id)) {
const char *lba_desc;
- char ncq_desc[20];
+ char ncq_desc[24];
lba_desc = "LBA";
dev->flags |= ATA_DFLAG_LBA;
@@ -2474,7 +2495,9 @@ int ata_dev_configure(struct ata_device *dev)
}
/* config NCQ */
- ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ if (rc)
+ return rc;
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info) {
@@ -4099,6 +4122,7 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
+ u64 n_native_sectors = dev->n_native_sectors;
int rc;
if (!ata_dev_enabled(dev))
@@ -4128,16 +4152,30 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
/* verify n_sectors hasn't changed */
if (dev->class == ATA_DEV_ATA && n_sectors &&
dev->n_sectors != n_sectors) {
- ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+ ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch "
"%llu != %llu\n",
(unsigned long long)n_sectors,
(unsigned long long)dev->n_sectors);
-
- /* restore original n_sectors */
- dev->n_sectors = n_sectors;
-
- rc = -ENODEV;
- goto fail;
+ /*
+ * Something could have caused HPA to be unlocked
+ * involuntarily. If n_native_sectors hasn't changed
+ * and the new size matches it, keep the device.
+ */
+ if (dev->n_native_sectors == n_native_sectors &&
+ dev->n_sectors > n_sectors &&
+ dev->n_sectors == n_native_sectors) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "new n_sectors matches native, probably "
+ "late HPA unlock, continuing\n");
+ /* keep using the old n_sectors */
+ dev->n_sectors = n_sectors;
+ } else {
+ /* restore original n_[native]_sectors and fail */
+ dev->n_native_sectors = n_native_sectors;
+ dev->n_sectors = n_sectors;
+ rc = -ENODEV;
+ goto fail;
+ }
}
return 0;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 1a07c061f644..a04488f0de88 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -40,6 +40,7 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
#include "../scsi/scsi_transport_api.h"
#include <linux/libata.h>
@@ -999,7 +1000,9 @@ static void __ata_port_freeze(struct ata_port *ap)
* ata_port_freeze - abort & freeze port
* @ap: ATA port to freeze
*
- * Abort and freeze @ap.
+ * Abort and freeze @ap. The freeze operation must be called
+ * first, because some hardware requires special operations
+ * before the taskfile registers are accessible.
*
* LOCKING:
* spin_lock_irqsave(host lock)
@@ -1013,8 +1016,8 @@ int ata_port_freeze(struct ata_port *ap)
WARN_ON(!ap->ops->error_handler);
- nr_aborted = ata_port_abort(ap);
__ata_port_freeze(ap);
+ nr_aborted = ata_port_abort(ap);
return nr_aborted;
}
@@ -2110,6 +2113,116 @@ void ata_eh_autopsy(struct ata_port *ap)
}
/**
+ * ata_get_cmd_descript - get description for ATA command
+ * @command: ATA command code to get description for
+ *
+ * Return a textual description of the given command, or NULL if the
+ * command is not known.
+ *
+ * LOCKING:
+ * None
+ */
+const char *ata_get_cmd_descript(u8 command)
+{
+#ifdef CONFIG_ATA_VERBOSE_ERROR
+ static const struct
+ {
+ u8 command;
+ const char *text;
+ } cmd_descr[] = {
+ { ATA_CMD_DEV_RESET, "DEVICE RESET" },
+ { ATA_CMD_CHK_POWER, "CHECK POWER MODE" },
+ { ATA_CMD_STANDBY, "STANDBY" },
+ { ATA_CMD_IDLE, "IDLE" },
+ { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" },
+ { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" },
+ { ATA_CMD_NOP, "NOP" },
+ { ATA_CMD_FLUSH, "FLUSH CACHE" },
+ { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" },
+ { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" },
+ { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" },
+ { ATA_CMD_SERVICE, "SERVICE" },
+ { ATA_CMD_READ, "READ DMA" },
+ { ATA_CMD_READ_EXT, "READ DMA EXT" },
+ { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" },
+ { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" },
+ { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" },
+ { ATA_CMD_WRITE, "WRITE DMA" },
+ { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" },
+ { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" },
+ { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" },
+ { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" },
+ { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" },
+ { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
+ { ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" },
+ { ATA_CMD_PIO_READ, "READ SECTOR(S)" },
+ { ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" },
+ { ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" },
+ { ATA_CMD_PIO_WRITE_EXT, "WRITE SECTOR(S) EXT" },
+ { ATA_CMD_READ_MULTI, "READ MULTIPLE" },
+ { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" },
+ { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" },
+ { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" },
+ { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" },
+ { ATA_CMD_SET_FEATURES, "SET FEATURES" },
+ { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" },
+ { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" },
+ { ATA_CMD_VERIFY_EXT, "READ VERIFY SECTOR(S) EXT" },
+ { ATA_CMD_WRITE_UNCORR_EXT, "WRITE UNCORRECTABLE EXT" },
+ { ATA_CMD_STANDBYNOW1, "STANDBY IMMEDIATE" },
+ { ATA_CMD_IDLEIMMEDIATE, "IDLE IMMEDIATE" },
+ { ATA_CMD_SLEEP, "SLEEP" },
+ { ATA_CMD_INIT_DEV_PARAMS, "INITIALIZE DEVICE PARAMETERS" },
+ { ATA_CMD_READ_NATIVE_MAX, "READ NATIVE MAX ADDRESS" },
+ { ATA_CMD_READ_NATIVE_MAX_EXT, "READ NATIVE MAX ADDRESS EXT" },
+ { ATA_CMD_SET_MAX, "SET MAX ADDRESS" },
+ { ATA_CMD_SET_MAX_EXT, "SET MAX ADDRESS EXT" },
+ { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" },
+ { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" },
+ { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" },
+ { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" },
+ { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" },
+ { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" },
+ { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" },
+ { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" },
+ { ATA_CMD_PMP_READ, "READ BUFFER" },
+ { ATA_CMD_PMP_WRITE, "WRITE BUFFER" },
+ { ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" },
+ { ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" },
+ { ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" },
+ { ATA_CMD_SEC_ERASE_PREP, "SECURITY ERASE PREPARE" },
+ { ATA_CMD_SEC_ERASE_UNIT, "SECURITY ERASE UNIT" },
+ { ATA_CMD_SEC_FREEZE_LOCK, "SECURITY FREEZE LOCK" },
+ { ATA_CMD_SEC_DISABLE_PASS, "SECURITY DISABLE PASSWORD" },
+ { ATA_CMD_CONFIG_STREAM, "CONFIGURE STREAM" },
+ { ATA_CMD_SMART, "SMART" },
+ { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" },
+ { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" },
+ { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" },
+ { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" },
+ { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" },
+ { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" },
+ { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" },
+ { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
+ { ATA_CMD_READ_LONG, "READ LONG (with retries)" },
+ { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" },
+ { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" },
+ { ATA_CMD_WRITE_LONG_ONCE, "WRITE LONG (without retries)" },
+ { ATA_CMD_RESTORE, "RECALIBRATE" },
+ { 0, NULL } /* terminate list */
+ };
+
+ unsigned int i;
+ for (i = 0; cmd_descr[i].text; i++)
+ if (cmd_descr[i].command == command)
+ return cmd_descr[i].text;
+#endif
+
+ return NULL;
+}
+
+/**
* ata_eh_link_report - report error handling to user
* @link: ATA link EH is going on
*
@@ -2175,6 +2288,7 @@ static void ata_eh_link_report(struct ata_link *link)
ata_link_printk(link, KERN_ERR, "%s\n", desc);
}
+#ifdef CONFIG_ATA_VERBOSE_ERROR
if (ehc->i.serror)
ata_link_printk(link, KERN_ERR,
"SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
@@ -2195,6 +2309,7 @@ static void ata_eh_link_report(struct ata_link *link)
ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "");
+#endif
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
@@ -2226,14 +2341,23 @@ static void ata_eh_link_report(struct ata_link *link)
dma_str[qc->dma_dir]);
}
- if (ata_is_atapi(qc->tf.protocol))
- snprintf(cdb_buf, sizeof(cdb_buf),
+ if (ata_is_atapi(qc->tf.protocol)) {
+ if (qc->scsicmd)
+ scsi_print_command(qc->scsicmd);
+ else
+ snprintf(cdb_buf, sizeof(cdb_buf),
"cdb %02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n ",
cdb[0], cdb[1], cdb[2], cdb[3],
cdb[4], cdb[5], cdb[6], cdb[7],
cdb[8], cdb[9], cdb[10], cdb[11],
cdb[12], cdb[13], cdb[14], cdb[15]);
+ } else {
+ const char *descr = ata_get_cmd_descript(cmd->command);
+ if (descr)
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "failed command: %s\n", descr);
+ }
ata_dev_printk(qc->dev, KERN_ERR,
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
@@ -2252,6 +2376,7 @@ static void ata_eh_link_report(struct ata_link *link)
res->device, qc->err_mask, ata_err_string(qc->err_mask),
qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+#ifdef CONFIG_ATA_VERBOSE_ERROR
if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
ATA_ERR)) {
if (res->command & ATA_BUSY)
@@ -2275,6 +2400,7 @@ static void ata_eh_link_report(struct ata_link *link)
res->feature & ATA_UNC ? "UNC " : "",
res->feature & ATA_IDNF ? "IDNF " : "",
res->feature & ATA_ABORTED ? "ABRT " : "");
+#endif
}
}
@@ -2327,7 +2453,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
struct ata_port *ap = link->ap;
struct ata_link *slave = ap->slave_link;
struct ata_eh_context *ehc = &link->eh_context;
- struct ata_eh_context *sehc = &slave->eh_context;
+ struct ata_eh_context *sehc = slave ? &slave->eh_context : NULL;
unsigned int *classes = ehc->classes;
unsigned int lflags = link->flags;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
@@ -2574,11 +2700,17 @@ int ata_eh_reset(struct ata_link *link, int classify,
postreset(slave, classes);
}
- /* clear cached SError */
+ /*
+ * Some controllers can't be frozen very well and may set
+ * spuruious error conditions during reset. Clear accumulated
+ * error information. As reset is the final recovery action,
+ * nothing is lost by doing this.
+ */
spin_lock_irqsave(link->ap->lock, flags);
- link->eh_info.serror = 0;
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
if (slave)
- slave->eh_info.serror = 0;
+ memset(&slave->eh_info, 0, sizeof(link->eh_info));
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
spin_unlock_irqrestore(link->ap->lock, flags);
/* Make sure onlineness and classification result correspond.
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index d0dfeef55db5..5d7a1bd37e9a 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1119,10 +1119,6 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
} else {
- if (ata_id_is_ssd(dev->id))
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT,
- sdev->request_queue);
-
/* ATA devices must be sector aligned */
blk_queue_update_dma_alignment(sdev->request_queue,
ATA_SECT_SIZE - 1);
@@ -1257,23 +1253,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
return queue_depth;
}
-/* XXX: for spindown warning */
-static void ata_delayed_done_timerfn(unsigned long arg)
-{
- struct scsi_cmnd *scmd = (void *)arg;
-
- scmd->scsi_done(scmd);
-}
-
-/* XXX: for spindown warning */
-static void ata_delayed_done(struct scsi_cmnd *scmd)
-{
- static struct timer_list timer;
-
- setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd);
- mod_timer(&timer, jiffies + 5 * HZ);
-}
-
/**
* ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
* @qc: Storage for translated ATA taskfile
@@ -1338,32 +1317,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
system_entering_hibernation())
goto skip;
- /* XXX: This is for backward compatibility, will be
- * removed. Read Documentation/feature-removal-schedule.txt
- * for more info.
- */
- if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) &&
- (system_state == SYSTEM_HALT ||
- system_state == SYSTEM_POWER_OFF)) {
- static unsigned long warned;
-
- if (!test_and_set_bit(0, &warned)) {
- ata_dev_printk(qc->dev, KERN_WARNING,
- "DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
- "UPDATE SHUTDOWN UTILITY\n");
- ata_dev_printk(qc->dev, KERN_WARNING,
- "For more info, visit "
- "http://linux-ata.org/shutdown.html\n");
-
- /* ->scsi_done is not used, use it for
- * delayed completion.
- */
- scmd->scsi_done = qc->scsidone;
- qc->scsidone = ata_delayed_done;
- }
- goto skip;
- }
-
/* Issue ATA STANDBY IMMEDIATE command */
tf->command = ATA_CMD_STANDBYNOW1;
}
@@ -1764,14 +1717,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
}
- /* XXX: track spindown state for spindown skipping and warning */
- if (unlikely(qc->tf.command == ATA_CMD_STANDBY ||
- qc->tf.command == ATA_CMD_STANDBYNOW1))
- qc->dev->flags |= ATA_DFLAG_SPUNDOWN;
- else if (likely(system_state != SYSTEM_HALT &&
- system_state != SYSTEM_POWER_OFF))
- qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN;
-
if (need_sense && !ap->ops->error_handler)
ata_dump_status(ap->print_id, &qc->result_tf);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 89a1e0018e71..be8e2628f82c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -164,6 +164,7 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
unsigned int action);
extern void ata_eh_autopsy(struct ata_port *ap);
+const char *ata_get_cmd_descript(u8 command);
extern void ata_eh_report(struct ata_port *ap);
extern int ata_eh_reset(struct ata_link *link, int classify,
ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index 8561a9f195c1..5702affcb325 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -26,9 +26,7 @@
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
-#include <mach/at91sam9260_matrix.h>
#include <mach/at91sam9_smc.h>
-#include <mach/at91sam9260.h>
#include <mach/board.h>
#include <mach/gpio.h>
@@ -44,65 +42,62 @@ struct at91_ide_info {
unsigned long mode;
unsigned int cs;
+ struct clk *mck;
+
void __iomem *ide_addr;
void __iomem *alt_addr;
};
-const struct ata_timing initial_timing =
+static const struct ata_timing initial_timing =
{XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
-static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
+static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
{
unsigned long mul;
- /*
- * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
- * x * (f / 1_000_000_000) =
- * x * ((f * 65536) / 1_000_000_000) / 65536 =
- * x * (((f / 10_000) * 65536) / 100_000) / 65536 =
- */
+ /*
+ * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
+ * x * (f / 1_000_000_000) =
+ * x * ((f * 65536) / 1_000_000_000) / 65536 =
+ * x * (((f / 10_000) * 65536) / 100_000) / 65536 =
+ */
- mul = (mck_hz / 10000) << 16;
- mul /= 100000;
+ mul = (mck_hz / 10000) << 16;
+ mul /= 100000;
- return (ns * mul + 65536) >> 16; /* rounding */
+ return (ns * mul + 65536) >> 16; /* rounding */
}
static void set_smc_mode(struct at91_ide_info *info)
{
- at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
- return;
+ at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
+ return;
}
static void set_smc_timing(struct device *dev,
struct at91_ide_info *info, const struct ata_timing *ata)
{
- int read_cycle, write_cycle, active, recover;
- int nrd_setup, nrd_pulse, nrd_recover;
- int nwe_setup, nwe_pulse;
+ unsigned long read_cycle, write_cycle, active, recover;
+ unsigned long nrd_setup, nrd_pulse, nrd_recover;
+ unsigned long nwe_setup, nwe_pulse;
- int ncs_write_setup, ncs_write_pulse;
- int ncs_read_setup, ncs_read_pulse;
+ unsigned long ncs_write_setup, ncs_write_pulse;
+ unsigned long ncs_read_setup, ncs_read_pulse;
- unsigned int mck_hz;
- struct clk *mck;
+ unsigned long mck_hz;
read_cycle = ata->cyc8b;
nrd_setup = ata->setup;
nrd_pulse = ata->act8b;
nrd_recover = ata->rec8b;
- mck = clk_get(NULL, "mck");
- BUG_ON(IS_ERR(mck));
- mck_hz = clk_get_rate(mck);
+ mck_hz = clk_get_rate(info->mck);
read_cycle = calc_mck_cycles(read_cycle, mck_hz);
nrd_setup = calc_mck_cycles(nrd_setup, mck_hz);
nrd_pulse = calc_mck_cycles(nrd_pulse, mck_hz);
nrd_recover = calc_mck_cycles(nrd_recover, mck_hz);
- clk_put(mck);
-
active = nrd_setup + nrd_pulse;
recover = read_cycle - active;
@@ -121,13 +116,13 @@ static void set_smc_timing(struct device *dev,
ncs_write_setup = ncs_read_setup;
ncs_write_pulse = ncs_read_pulse;
- dev_dbg(dev, "ATA timings: nrd_setup = %d nrd_pulse = %d nrd_cycle = %d\n",
+ dev_dbg(dev, "ATA timings: nrd_setup = %lu nrd_pulse = %lu nrd_cycle = %lu\n",
nrd_setup, nrd_pulse, read_cycle);
- dev_dbg(dev, "ATA timings: nwe_setup = %d nwe_pulse = %d nwe_cycle = %d\n",
+ dev_dbg(dev, "ATA timings: nwe_setup = %lu nwe_pulse = %lu nwe_cycle = %lu\n",
nwe_setup, nwe_pulse, write_cycle);
- dev_dbg(dev, "ATA timings: ncs_read_setup = %d ncs_read_pulse = %d\n",
+ dev_dbg(dev, "ATA timings: ncs_read_setup = %lu ncs_read_pulse = %lu\n",
ncs_read_setup, ncs_read_pulse);
- dev_dbg(dev, "ATA timings: ncs_write_setup = %d ncs_write_pulse = %d\n",
+ dev_dbg(dev, "ATA timings: ncs_write_setup = %lu ncs_write_pulse = %lu\n",
ncs_write_setup, ncs_write_pulse);
at91_sys_write(AT91_SMC_SETUP(info->cs),
@@ -217,6 +212,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev)
struct resource *mem_res;
struct ata_host *host;
struct ata_port *ap;
+
int irq_flags = 0;
int irq = 0;
int ret;
@@ -261,6 +257,13 @@ static int __devinit pata_at91_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ info->mck = clk_get(NULL, "mck");
+
+ if (IS_ERR(info->mck)) {
+ dev_err(dev, "failed to get access to mck clock\n");
+ return -ENODEV;
+ }
+
info->cs = board->chipselect;
info->mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT |
@@ -304,6 +307,7 @@ err_alt_ioremap:
devm_iounmap(dev, info->ide_addr);
err_ide_ioremap:
+ clk_put(info->mck);
kfree(info);
return ret;
@@ -326,6 +330,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev)
devm_iounmap(dev, info->ide_addr);
devm_iounmap(dev, info->alt_addr);
+ clk_put(info->mck);
kfree(info);
return 0;
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index 8d9343accf3c..e807cc3b6ab4 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -213,7 +213,7 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev)
* This is tI, C.F. spec. says 0, but Sony CF card requires
* more, we use 20 nS.
*/
- dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);;
+ dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);
dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh);
dma_tim.s.dmarq = dma_arq;
@@ -653,7 +653,8 @@ static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
ap = host->ports[i];
ocd = ap->dev->platform_data;
- if (!ap || (ap->flags & ATA_FLAG_DISABLED))
+
+ if (ap->flags & ATA_FLAG_DISABLED)
continue;
ocd = ap->dev->platform_data;
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index f4d009ed50ac..dc99e26f8e5b 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -411,6 +411,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
new file mode 100644
index 000000000000..c843a1e07c4f
--- /dev/null
+++ b/drivers/ata/pata_rdc.c
@@ -0,0 +1,400 @@
+/*
+ * pata_rdc - Driver for later RDC PATA controllers
+ *
+ * This is actually a driver for hardware meeting
+ * INCITS 370-2004 (1510D): ATA Host Adapter Standards
+ *
+ * Based on ata_piix.
+ *
+ * This program is free software; you can redistribute 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_rdc"
+#define DRV_VERSION "0.01"
+
+struct rdc_host_priv {
+ u32 saved_iocfg;
+};
+
+/**
+ * rdc_pata_cable_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from ATA PCI device's PCI config
+ * register. This register is normally set by firmware (BIOS).
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static int rdc_pata_cable_detect(struct ata_port *ap)
+{
+ struct rdc_host_priv *hpriv = ap->host->private_data;
+ u8 mask;
+
+ /* check BIOS cable detect results */
+ mask = 0x30 << (2 * ap->port_no);
+ if ((hpriv->saved_iocfg & mask) == 0)
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * rdc_pata_prereset - prereset for PATA host controller
+ * @link: Target link
+ * @deadline: deadline jiffies for the operation
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int rdc_pata_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ static const struct pci_bits rdc_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &rdc_enable_bits[ap->port_no]))
+ return -ENOENT;
+ return ata_sff_prereset(link, deadline);
+}
+
+/**
+ * rdc_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void rdc_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int is_slave = (adev->devno != 0);
+ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
+ unsigned int slave_port = 0x44;
+ u16 master_data;
+ u8 slave_data;
+ u8 udma_enable;
+ int control = 0;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio >= 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE enable */
+
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ /* PIO configuration clears DTE unconditionally. It will be
+ * programmed in set_dmamode which is guaranteed to be called
+ * after set_piomode if any DMA mode is available.
+ */
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ /* clear TIME1|IE1|PPE1|DTE1 */
+ master_data &= 0xff0f;
+ /* Enable SITRE (separate slave timing register) */
+ master_data |= 0x4000;
+ /* enable PPE1, IE1 and TIME1 as needed */
+ master_data |= (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the timing nibble for this slave */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1])
+ << (ap->port_no ? 4 : 0);
+ } else {
+ /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */
+ master_data &= 0xccf0;
+ /* Enable PPE, IE and TIME as appropriate */
+ master_data |= control;
+ /* load ISP and RCT */
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+
+ /* Ensure the UDMA bit is off - it will be turned back on if
+ UDMA is selected */
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+/**
+ * rdc_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Drive in question
+ *
+ * Set UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable = 0;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /*
+ * UDMA is handled by a combination of clock switching and
+ * selection of dividers
+ *
+ * Handy rule: Odd modes are UDMATIMx 01, even are 02
+ * except UDMA0 which is 00
+ */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the CT/RP selection */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= u_speed << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ /* Select a 33/66/100Mhz clock */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ pci_write_config_word(dev, 0x54, ideconf);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+static struct ata_port_operations rdc_pata_ops = {
+ .inherits = &ata_bmdma32_port_ops,
+ .cable_detect = rdc_pata_cable_detect,
+ .set_piomode = rdc_set_piomode,
+ .set_dmamode = rdc_set_dmamode,
+ .prereset = rdc_pata_prereset,
+};
+
+static struct ata_port_info rdc_port_info = {
+
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &rdc_pata_ops,
+};
+
+static struct scsi_host_template rdc_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+/**
+ * rdc_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in rdc_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int __devinit rdc_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct device *dev = &pdev->dev;
+ struct ata_port_info port_info[2];
+ const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
+ unsigned long port_flags;
+ struct ata_host *host;
+ struct rdc_host_priv *hpriv;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ port_info[0] = rdc_port_info;
+ port_info[1] = rdc_port_info;
+
+ port_flags = port_info[0].flags;
+
+ /* enable device and prepare host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
+ /* Save IOCFG, this will be used for cable detection, quirk
+ * detection and restoration on detach.
+ */
+ pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg);
+
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ host->private_data = hpriv;
+
+ pci_intx(pdev, 1);
+
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
+ pci_set_master(pdev);
+ return ata_pci_sff_activate_host(host, ata_sff_interrupt, &rdc_sht);
+}
+
+static void rdc_remove_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct rdc_host_priv *hpriv = host->private_data;
+
+ pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg);
+
+ ata_pci_remove_one(pdev);
+}
+
+static const struct pci_device_id rdc_pci_tbl[] = {
+ { PCI_DEVICE(0x17F3, 0x1011), },
+ { PCI_DEVICE(0x17F3, 0x1012), },
+ { } /* terminate list */
+};
+
+static struct pci_driver rdc_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rdc_pci_tbl,
+ .probe = rdc_init_one,
+ .remove = rdc_remove_one,
+};
+
+
+static int __init rdc_init(void)
+{
+ return pci_register_driver(&rdc_pci_driver);
+}
+
+static void __exit rdc_exit(void)
+{
+ pci_unregister_driver(&rdc_pci_driver);
+}
+
+module_init(rdc_init);
+module_exit(rdc_exit);
+
+MODULE_AUTHOR("Alan Cox (based on ata_piix)");
+MODULE_DESCRIPTION("SCSI low-level driver for RDC PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, rdc_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 8d890cc5a7ee..4406902b4293 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -405,7 +405,7 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
- int i, handled = 0;;
+ int i, handled = 0;
host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 23714aefb825..c19417e02208 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -2514,7 +2514,7 @@ static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
char *when = "idle";
ata_ehi_clear_desc(ehi);
- if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ if (ap->flags & ATA_FLAG_DISABLED) {
when = "disabled";
} else if (edma_was_enabled) {
when = "EDMA enabled";
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 030ec079b184..3cb69d5fb817 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -532,7 +532,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
struct ata_port *ap = host->ports[i];
u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
- if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+ if (unlikely(ap->flags & ATA_FLAG_DISABLED))
continue;
/* turn off SATA_IRQ if not supported */
@@ -565,6 +565,19 @@ static void sil_freeze(struct ata_port *ap)
tmp |= SIL_MASK_IDE0_INT << ap->port_no;
writel(tmp, mmio_base + SIL_SYSCFG);
readl(mmio_base + SIL_SYSCFG); /* flush */
+
+ /* Ensure DMA_ENABLE is off.
+ *
+ * This is because the controller will not give us access to the
+ * taskfile registers while a DMA is in progress
+ */
+ iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE,
+ ap->ioaddr.bmdma_addr);
+
+ /* According to ata_bmdma_stop, an HDMA transition requires
+ * on PIO cycle. But we can't read a taskfile register.
+ */
+ ioread8(ap->ioaddr.bmdma_addr);
}
static void sil_thaw(struct ata_port *ap)
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 9359613addc5..307321b32cb3 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -372,7 +372,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
}
snr = next_string(skb);
- if (!str)
+ if (!snr)
return -EIO;
attn = next_string(skb);
if (!attn)
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index f285f441fab9..7376367bcb80 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -180,7 +180,6 @@ static ssize_t firmware_loading_store(struct device *dev,
goto err;
}
/* Pages will be freed by vfree() */
- fw_priv->pages = NULL;
fw_priv->page_array_size = 0;
fw_priv->nr_pages = 0;
complete(&fw_priv->completion);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 81cb01bfc356..ae5c4aa6d269 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -628,30 +628,6 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
return ret;
}
-static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
-{
- struct platform_driver *pdrv = to_platform_driver(dev->driver);
- struct platform_device *pdev = to_platform_device(dev);
- int ret = 0;
-
- if (dev->driver && pdrv->suspend_late)
- ret = pdrv->suspend_late(pdev, mesg);
-
- return ret;
-}
-
-static int platform_legacy_resume_early(struct device *dev)
-{
- struct platform_driver *pdrv = to_platform_driver(dev->driver);
- struct platform_device *pdev = to_platform_device(dev);
- int ret = 0;
-
- if (dev->driver && pdrv->resume_early)
- ret = pdrv->resume_early(pdev);
-
- return ret;
-}
-
static int platform_legacy_resume(struct device *dev)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
@@ -714,8 +690,6 @@ static int platform_pm_suspend_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->suspend_noirq)
ret = drv->pm->suspend_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
}
return ret;
@@ -750,8 +724,6 @@ static int platform_pm_resume_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->resume_noirq)
ret = drv->pm->resume_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -797,8 +769,6 @@ static int platform_pm_freeze_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->freeze_noirq)
ret = drv->pm->freeze_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
}
return ret;
@@ -833,8 +803,6 @@ static int platform_pm_thaw_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->thaw_noirq)
ret = drv->pm->thaw_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -869,8 +837,6 @@ static int platform_pm_poweroff_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->poweroff_noirq)
ret = drv->pm->poweroff_noirq(dev);
- } else {
- ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
}
return ret;
@@ -905,8 +871,6 @@ static int platform_pm_restore_noirq(struct device *dev)
if (drv->pm) {
if (drv->pm->restore_noirq)
ret = drv->pm->restore_noirq(dev);
- } else {
- ret = platform_legacy_resume_early(dev);
}
return ret;
@@ -925,7 +889,7 @@ static int platform_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
-static struct dev_pm_ops platform_dev_pm_ops = {
+static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare,
.complete = platform_pm_complete,
.suspend = platform_pm_suspend,
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 58a3e572f2c9..1b1a786b7dec 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -157,8 +157,9 @@ void device_pm_move_last(struct device *dev)
* @ops: PM operations to choose from.
* @state: PM transition of the system being carried out.
*/
-static int pm_op(struct device *dev, struct dev_pm_ops *ops,
- pm_message_t state)
+static int pm_op(struct device *dev,
+ const struct dev_pm_ops *ops,
+ pm_message_t state)
{
int error = 0;
@@ -220,7 +221,8 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops,
* The operation is executed with interrupts disabled by the only remaining
* functional CPU in the system.
*/
-static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
+static int pm_noirq_op(struct device *dev,
+ const struct dev_pm_ops *ops,
pm_message_t state)
{
int error = 0;
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 79a9ae5238ac..0d903909af7e 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -275,9 +275,9 @@ int sysdev_register(struct sys_device *sysdev)
drv->add(sysdev);
}
mutex_unlock(&sysdev_drivers_lock);
+ kobject_uevent(&sysdev->kobj, KOBJ_ADD);
}
- kobject_uevent(&sysdev->kobj, KOBJ_ADD);
return error;
}
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index bf6b13206d00..1e35a4376d89 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -103,6 +103,9 @@ static ssize_t show_##name##_list(struct sys_device *dev, \
define_id_show_func(physical_package_id);
define_one_ro(physical_package_id);
+define_id_show_func(cpu_node_id);
+define_one_ro(cpu_node_id);
+
define_id_show_func(core_id);
define_one_ro(core_id);
@@ -110,6 +113,10 @@ define_siblings_show_func(thread_cpumask);
define_one_ro_named(thread_siblings, show_thread_cpumask);
define_one_ro_named(thread_siblings_list, show_thread_cpumask_list);
+define_siblings_show_func(cpu_node_cpumask);
+define_one_ro_named(cpu_node_siblings, show_cpu_node_cpumask);
+define_one_ro_named(cpu_node_siblings_list, show_cpu_node_cpumask_list);
+
define_siblings_show_func(core_cpumask);
define_one_ro_named(core_siblings, show_core_cpumask);
define_one_ro_named(core_siblings_list, show_core_cpumask_list);
@@ -119,6 +126,9 @@ static struct attribute *default_attrs[] = {
&attr_core_id.attr,
&attr_thread_siblings.attr,
&attr_thread_siblings_list.attr,
+ &attr_cpu_node_id.attr,
+ &attr_cpu_node_siblings.attr,
+ &attr_cpu_node_siblings_list.attr,
&attr_core_siblings.attr,
&attr_core_siblings_list.attr,
NULL
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 1e6b7c14f697..b839af1702e2 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -7210,7 +7210,7 @@ static struct pci_driver DAC960_pci_driver = {
.remove = DAC960_Remove,
};
-static int DAC960_init_module(void)
+static int __init DAC960_init_module(void)
{
int ret;
@@ -7222,7 +7222,7 @@ static int DAC960_init_module(void)
return ret;
}
-static void DAC960_cleanup_module(void)
+static void __exit DAC960_cleanup_module(void)
{
int i;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 1d886e079c58..77bfce52e9ca 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -271,6 +271,8 @@ config BLK_DEV_CRYPTOLOOP
instead, which can be configured to be on-disk compatible with the
cryptoloop device.
+source "drivers/block/drbd/Kconfig"
+
config BLK_DEV_NBD
tristate "Network block device support"
depends on NET
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index cdaa3f8fddf0..aff5ac925c34 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -36,5 +36,6 @@ obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_BLK_DEV_HD) += hd.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
+obj-$(CONFIG_BLK_DEV_DRBD) += drbd/
swim_mod-objs := swim.o swim_asm.o
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 2307a271bdc9..0efb8fccb619 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -265,6 +265,7 @@ aoeblk_gdalloc(void *vp)
}
blk_queue_make_request(&d->blkq, aoeblk_make_request);
+ d->blkq.backing_dev_info.name = "aoe";
if (bdi_init(&d->blkq.backing_dev_info))
goto err_mempool;
spin_lock_irqsave(&d->lock, flags);
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
new file mode 100644
index 000000000000..8b14ea2c43f8
--- /dev/null
+++ b/drivers/block/drbd/Kconfig
@@ -0,0 +1,82 @@
+#
+# 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 m
+ 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 M.
+
+config DRBD_TRACE
+ tristate "DRBD tracing"
+ depends on BLK_DEV_DRBD
+ select TRACEPOINTS
+ default m
+ help
+
+ Say Y here if you want to be able to trace various events in DRBD.
+
+ If unsure, say M.
+
+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..7d86ef8a8b40
--- /dev/null
+++ b/drivers/block/drbd/Makefile
@@ -0,0 +1,8 @@
+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
+
+drbd_trace-y := drbd_tracing.o
+
+obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o
+obj-$(CONFIG_DRBD_TRACE) += drbd_trace.o
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
new file mode 100644
index 000000000000..38518691f356
--- /dev/null
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -0,0 +1,1485 @@
+/*
+ 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_tracing.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);
+
+/* The actual tracepoint needs to have constant number of known arguments...
+ */
+void trace_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ trace__drbd_resync(mdev, level, fmt, ap);
+ va_end(ap);
+}
+
+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;
+
+ trace_drbd_bio(mdev, "Md", bio, 0, NULL);
+
+ 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, preallocated
+ * 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);
+
+ trace_drbd_actlog(mdev, sector, "al_begin_io");
+
+ 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
+ * disalows 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;
+
+ trace_drbd_actlog(mdev, sector, "al_complete_io");
+
+ 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 = (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);
+ drbd_io_error(mdev, 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 atached! */
+ 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 behaviour of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?! */
+ if (!error && !uptodate)
+ error = -EIO;
+
+ /* corresponding drbd_io_error is in drbd_al_to_on_disk_bm */
+ 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 */
+
+ 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;
+
+ 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;
+ }
+
+ /* unneccessary 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);
+
+ if (wc.error)
+ drbd_io_error(mdev, TRUE);
+ 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 etry 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 = (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");
+ 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, alligned, 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);
+
+ trace_drbd_resync(mdev, TRACE_LVL_METRICS,
+ "drbd_set_in_sync: sector=%llus size=%u sbnr=%lu ebnr=%lu\n",
+ (unsigned long long)sector, size, sbnr, ebnr);
+
+ 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 roling 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);
+
+ trace_drbd_resync(mdev, TRACE_LVL_METRICS,
+ "drbd_set_out_of_sync: sector=%llus size=%u sbnr=%lu ebnr=%lu\n",
+ (unsigned long long)sector, size, sbnr, ebnr);
+
+ /* 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;
+
+ trace_drbd_resync(mdev, TRACE_LVL_ALL,
+ "drbd_rs_begin_io: sector=%llus (rs_end=%d)\n",
+ (unsigned long long)sector, enr);
+
+ 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;
+
+ trace_drbd_resync(mdev, TRACE_LVL_ALL, "drbd_try_rs_begin_io: sector=%llus\n",
+ (unsigned long long)sector);
+
+ 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 giveup 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 keept the refcount on.
+ * so we remembered which extent we had to try agin, and
+ * if the next requested one is something else, we do
+ * the lc_put here...
+ * we also have to wake_up
+ */
+
+ trace_drbd_resync(mdev, TRACE_LVL_ALL,
+ "dropping %u, aparently got 'synced' by application io\n",
+ mdev->resync_wenr);
+
+ 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. */
+ trace_drbd_resync(mdev, TRACE_LVL_ALL,
+ "dropping extra reference on %u\n", enr);
+
+ 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) {
+ trace_drbd_resync(mdev, TRACE_LVL_ALL,
+ "resync_locked = %u!\n", mdev->resync_locked);
+
+ goto try_again;
+ }
+ /* Do or do not. There is no try. -- Joda */
+ 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:
+ trace_drbd_resync(mdev, TRACE_LVL_ALL, "checking al for %u\n", enr);
+
+ 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:
+ trace_drbd_resync(mdev, TRACE_LVL_ALL, "need to try again for %u\n", enr);
+ 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;
+
+ trace_drbd_resync(mdev, TRACE_LVL_ALL,
+ "drbd_rs_complete_io: sector=%llus (rs_enr=%d)\n",
+ (long long)sector, enr);
+
+ 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);
+ 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)
+{
+ trace_drbd_resync(mdev, TRACE_LVL_METRICS, "drbd_rs_cancel_all\n");
+
+ 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;
+
+ trace_drbd_resync(mdev, TRACE_LVL_METRICS, "drbd_rs_del_all\n");
+
+ 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;
+
+ trace_drbd_resync(mdev, TRACE_LVL_SUMMARY,
+ "drbd_rs_failed_io: sector=%llus, size=%u\n",
+ (unsigned long long)sector, size);
+
+ 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, alligned, 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..5b7c763e59d7
--- /dev/null
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -0,0 +1,1321 @@
+/*
+ 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
+
+ * convetion:
+ * 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.
+ * Rerturns 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, const enum km_type km)
+{
+ 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);
+ 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);
+ offset += do_now;
+ }
+
+ return bits;
+}
+
+static unsigned long bm_count_bits(struct drbd_bitmap *b)
+{
+ return __bm_count_bits(b, 0, KM_IRQ1);
+}
+
+static unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b)
+{
+ return __bm_count_bits(b, 1, KM_USER0);
+}
+
+/* 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 neccessary, 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 initiallized 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);
+ if (!growing)
+ b->bm_set = bm_count_bits(b);
+
+ spin_unlock_irq(&b->bm_lock);
+ if (opages != npages)
+ bm_vk_free(opages, opages_vmalloced);
+ 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 ?
+ */
+unsigned long drbd_bm_total_weight(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long s;
+ unsigned long flags;
+
+ /* 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;
+
+ 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);
+
+ 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 behaviour 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);
+ drbd_io_error(mdev, 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 neccessary 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 exactle 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);
+ drbd_io_error(mdev, 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 positiv
+ * 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 positiv
+ * 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);
+ 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..10fa153d0f1f
--- /dev/null
+++ b/drivers/block/drbd/drbd_int.h
@@ -0,0 +1,2243 @@
+/*
+ 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/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 DRBD_ENABLE_FAULTS
+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,
+};
+
+extern void trace_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt, ...);
+
+#ifdef DRBD_ENABLE_FAULTS
+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;
+ 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_TRACE_FLUSH, /* TRACE_ are not real events, only used for tracing */
+ EV_TRACE_ADD_BARRIER, /* Doing the first write as a barrier write */
+ EV_TRACE_SETTING_BI, /* Barrier is expressed with the first write of the next epoch */
+ EV_TRACE_ALLOC,
+ EV_TRACE_FREE,
+ 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 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 */
+ WORK_PENDING, /* completion flag for drbd_disconnect */
+ 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 int drbd_io_error(struct drbd_conf *mdev, int forcedetach);
+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);
+
+/* 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);
+}
+
+static inline void __drbd_chk_io_error(struct drbd_conf *mdev, int forcedetach)
+{
+ switch (mdev->ldev->dc.on_io_error) {
+ case EP_PASS_ON:
+ if (!forcedetach) {
+ if (printk_ratelimit())
+ dev_err(DEV, "Local IO failed. Passing error on...\n");
+ 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. Detaching...\n");
+ }
+ 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_io_error().
+ */
+static inline void drbd_chk_io_error(struct drbd_conf *mdev,
+ int error, int forcedetach)
+{
+ if (error) {
+ unsigned long flags;
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ __drbd_chk_io_error(mdev, forcedetach);
+ 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..030f546967dc
--- /dev/null
+++ b/drivers/block/drbd/drbd_main.c
@@ -0,0 +1,3754 @@
+/*
+ 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>.
+
+ 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/autoconf.h>
+#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_tracing.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);
+
+DEFINE_TRACE(drbd_unplug);
+DEFINE_TRACE(drbd_uuid);
+DEFINE_TRACE(drbd_ee);
+DEFINE_TRACE(drbd_packet);
+DEFINE_TRACE(drbd_md_io);
+DEFINE_TRACE(drbd_epoch);
+DEFINE_TRACE(drbd_netlink);
+DEFINE_TRACE(drbd_actlog);
+DEFINE_TRACE(drbd_bio);
+DEFINE_TRACE(_drbd_resync);
+DEFINE_TRACE(drbd_req);
+
+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 preallocated 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, 0);
+ }
+ /* 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 but 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
+ barrer. Threfore 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);
+ _req_mod(r, connection_lost_while_pending, 0);
+ }
+ 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);
+ _req_mod(r, connection_lost_while_pending, 0);
+ }
+
+ /* ensure bit indicating barrier is required is clear */
+ clear_bit(CREATE_BARRIER, &mdev->flags);
+
+ spin_unlock_irq(&mdev->req_lock);
+}
+
+/**
+ * drbd_io_error() - Detach from the local disk of so configured with the on_io_error setting
+ * @mdev: DRBD device.
+ * @force_detach: Detach no matter how on_io_error is set (meta data IO error)
+ *
+ * Should be called in the unlikely(!drbd_bio_uptodate(e->bio)) case from
+ * kernel thread context. See also drbd_chk_io_error().
+ */
+int drbd_io_error(struct drbd_conf *mdev, int force_detach)
+{
+ enum drbd_io_error_p eh;
+ unsigned long flags;
+ int send;
+ int ok = 1;
+
+ eh = EP_PASS_ON;
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ eh = mdev->ldev->dc.on_io_error;
+ put_ldev(mdev);
+ }
+
+ if (!force_detach && eh == EP_PASS_ON)
+ return 1;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ send = (mdev->state.disk == D_FAILED);
+ if (send)
+ _drbd_set_state(_NS(mdev, disk, D_DISKLESS), CS_HARD, NULL);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (!send)
+ return ok;
+
+ if (mdev->state.conn >= C_CONNECTED) {
+ ok = drbd_send_state(mdev);
+ if (ok)
+ dev_warn(DEV, "Notified peer that my disk is broken.\n");
+ else
+ dev_err(DEV, "Sending state in drbd_io_error() failed\n");
+ }
+
+ /* Make sure we try to flush meta-data to disk - we come
+ * in here because of a local disk error so it might fail
+ * but we still need to try -- both because the error might
+ * be in the data portion of the disk and because we need
+ * to ensure the md-sync-timer is stopped if running. */
+ drbd_md_sync(mdev);
+
+ /* Releasing the backing device is done in after_state_ch() */
+
+ if (eh == EP_CALL_HELPER)
+ drbd_khelper(mdev, "local-io-error");
+
+ return ok;
+}
+
+/**
+ * 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() - Reqest 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(), use full 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);
+ }
+
+ /* Dissalow 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 existion 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;
+
+ ascw = (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 successfull:
+ * 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_DISKLESS && ns.disk == D_DISKLESS) {
+ /* 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));
+
+ drbd_rs_cancel_all(mdev);
+ mdev->rs_total = 0;
+ mdev->rs_failed = 0;
+ atomic_set(&mdev->rs_pending_cnt, 0);
+
+ 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 assignement 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;
+ }
+
+ 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(&thi->t_lock);
+ thi->task = nt;
+ thi->t_state = Running;
+ spin_unlock(&thi->t_lock);
+ 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 benificial 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));
+
+ trace_drbd_packet(mdev, sock, 0, (void *)h, __FILE__, __LINE__);
+ 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;
+
+ trace_drbd_packet(mdev, mdev->data.socket, 0, (void *)&h, __FILE__, __LINE__);
+
+ 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))
+ dp_flags |= DP_HARDBARRIER;
+ if (bio_rw_flagged(req->master_bio, BIO_RW_SYNCIO))
+ 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);
+ trace_drbd_packet(mdev, mdev->data.socket, 0, (void *)&p, __FILE__, __LINE__);
+ 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 interupted by DRBD_SIG and/or DRBD_SIGKILL
+ * in response to admin command or module unload.
+ */
+ if (!drbd_get_data_sock(mdev))
+ return 0;
+
+ trace_drbd_packet(mdev, mdev->data.socket, 0, (void *)&p, __FILE__, __LINE__);
+ 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;
+
+ trace_drbd_unplug(mdev, "got unplugged");
+
+ /* 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 interessting 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;
+
+ 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: initialised. "
+ "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;
+
+ trace_drbd_md_io(mdev, WRITE, mdev->ldev);
+
+ 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);
+ drbd_io_error(mdev, 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;
+
+ trace_drbd_md_io(mdev, READ, bdev);
+
+ 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 enything 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];
+
+ trace_drbd_uuid(mdev, i+1);
+ }
+}
+
+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;
+ trace_drbd_uuid(mdev, idx);
+ 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];
+ trace_drbd_uuid(mdev, UI_HISTORY_START);
+ }
+ _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];
+ trace_drbd_uuid(mdev, UI_BITMAP);
+
+ 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;
+ trace_drbd_uuid(mdev, UI_HISTORY_START);
+ trace_drbd_uuid(mdev, UI_BITMAP);
+ } 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);
+
+ trace_drbd_uuid(mdev, UI_BITMAP);
+ }
+ 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 = (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 appliation 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)
+
+/* For drbd_tracing: */
+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..2552047c21c4
--- /dev/null
+++ b/drivers/block/drbd/drbd_nl.c
@@ -0,0 +1,2355 @@
+/*
+ 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/autoconf.h>
+#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_tracing.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:
+ ex_to_string = "peer is outdated";
+ nps = D_OUTDATED;
+ break;
+ case 5: /* peer was down, we will(have) create(d) a new UUID anyways... */
+ /* If we would be more strict, we would return D_UNKNOWN here. */
+ ex_to_string = "peer is unreachable, assumed to be dead";
+ nps = D_OUTDATED;
+ break;
+ case 6: /* Peer is primary, voluntarily outdate myself.
+ * This is useful when an unconnected R_SECONDARY is asked to
+ * become R_PRIMARY, but findes 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) {
+ D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+ nps = drbd_try_outdate_peer(mdev);
+
+ if (nps == D_OUTDATED) {
+ 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) {
+ 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 (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_determin_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));
+
+ 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 performace 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 investige 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 desicion 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 probabely 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 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;
+ }
+
+ mdev = ensure_mdev(nlp);
+ if (!mdev) {
+ retcode = ERR_MINOR_INVALID;
+ goto fail;
+ }
+
+ trace_drbd_netlink(req, 1);
+
+ 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->fucntion. */
+
+ 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;
+
+ trace_drbd_netlink(cn_reply, 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;
+
+ trace_drbd_netlink(cn_reply, 0);
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+}
+
+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;
+
+ trace_drbd_netlink(cn_reply, 0);
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+}
+
+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;
+
+ /* aparently 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;
+
+ trace_drbd_netlink(cn_reply, 0);
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+ 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;
+
+ trace_drbd_netlink(cn_reply, 0);
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+}
+
+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;
+
+ trace_drbd_netlink(cn_reply, 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);
+}
+
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
new file mode 100644
index 000000000000..98fcb7450c76
--- /dev/null
+++ b/drivers/block/drbd/drbd_proc.c
@@ -0,0 +1,266 @@
+/*
+ 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/autoconf.h>
+#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..f884baf961fd
--- /dev/null
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -0,0 +1,4366 @@
+/*
+ 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/autoconf.h>
+#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_tracing.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)
+
+/**
+ * drbd_bp_alloc() - Returns a page, fails only if a signal comes in
+ * @mdev: DRBD device.
+ * @gfp_mask: Get free page allocation mask
+ *
+ * Allocates a page from the kernel or our own page pool. In case that
+ * allocation would go beyond the max_buffers setting, this function sleeps
+ * until DRBD frees a page somewhere else.
+ */
+static struct page *drbd_pp_alloc(struct drbd_conf *mdev, gfp_t gfp_mask)
+{
+ unsigned long flags = 0;
+ struct page *page;
+ DEFINE_WAIT(wait);
+
+ spin_lock_irqsave(&drbd_pp_lock, flags);
+ 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_irqrestore(&drbd_pp_lock, flags);
+ if (page)
+ goto got_page;
+
+ drbd_kick_lo(mdev);
+
+ for (;;) {
+ prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
+
+ /* try the pool again, maybe the drbd_kick_lo set some free */
+ spin_lock_irqsave(&drbd_pp_lock, flags);
+ page = drbd_pp_pool;
+ if (page) {
+ drbd_pp_pool = (struct page *)page_private(page);
+ drbd_pp_vacant--;
+ }
+ spin_unlock_irqrestore(&drbd_pp_lock, flags);
+
+ if (page)
+ break;
+
+ /* hm. pool was empty. try to allocate from kernel.
+ * don't wait, if none is available, though.
+ */
+ if (atomic_read(&mdev->pp_in_use)
+ < mdev->net_conf->max_buffers) {
+ page = alloc_page(GFP_TRY);
+ if (page)
+ break;
+ }
+
+ /* doh. still no page.
+ * either used up the configured maximum number,
+ * or we are low on memory.
+ * wait for someone to return a page into the pool.
+ * unless, of course, someone signalled us.
+ */
+ if (signal_pending(current)) {
+ dev_warn(DEV, "drbd_pp_alloc interrupted!\n");
+ finish_wait(&drbd_pp_wait, &wait);
+ return NULL;
+ }
+ drbd_kick_lo(mdev);
+ if (!(gfp_mask & __GFP_WAIT)) {
+ finish_wait(&drbd_pp_wait, &wait);
+ return NULL;
+ }
+ schedule();
+ }
+ finish_wait(&drbd_pp_wait, &wait);
+
+ got_page:
+ atomic_inc(&mdev->pp_in_use);
+ return page;
+}
+
+static void drbd_pp_free(struct drbd_conf *mdev, struct page *page)
+{
+ unsigned long flags = 0;
+ int free_it;
+
+ spin_lock_irqsave(&drbd_pp_lock, flags);
+ 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_irqrestore(&drbd_pp_lock, flags);
+
+ atomic_dec(&mdev->pp_in_use);
+
+ if (free_it)
+ __free_page(page);
+
+ wake_up(&drbd_pp_wait);
+}
+
+/*
+You need to hold the req_lock:
+ drbd_free_ee()
+ _drbd_wait_ee_list_empty()
+
+You must not have the req_lock:
+ 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 bio_vec *bvec;
+ struct page *page;
+ struct bio *bio;
+ unsigned int ds;
+ int i;
+
+ 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);
+ 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;
+
+ trace_drbd_ee(mdev, e, "allocated");
+
+ return e;
+
+ fail2:
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ drbd_pp_free(mdev, bvec->bv_page);
+ }
+ 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;
+ struct bio_vec *bvec;
+ int i;
+
+ trace_drbd_ee(mdev, e, "freed");
+
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ drbd_pp_free(mdev, bvec->bv_page);
+ }
+
+ bio_put(bio);
+
+ D_ASSERT(hlist_unhashed(&e->colision));
+
+ mempool_free(e, drbd_ee_mempool);
+}
+
+/* currently on module unload only */
+int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list)
+{
+ int count = 0;
+ struct drbd_epoch_entry *e;
+ struct list_head *le;
+
+ spin_lock_irq(&mdev->req_lock);
+ while (!list_empty(list)) {
+ le = list->next;
+ list_del(le);
+ e = list_entry(le, struct drbd_epoch_entry, w.list);
+ drbd_free_ee(mdev, e);
+ count++;
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ return count;
+}
+
+
+static void reclaim_net_ee(struct drbd_conf *mdev)
+{
+ 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_del(le);
+ drbd_free_ee(mdev, e);
+ }
+}
+
+
+/*
+ * 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);
+ struct drbd_epoch_entry *e, *t;
+ int ok = 1;
+
+ spin_lock_irq(&mdev->req_lock);
+ reclaim_net_ee(mdev);
+ list_splice_init(&mdev->done_ee, &work_list);
+ spin_unlock_irq(&mdev->req_lock);
+
+ /* 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) {
+ trace_drbd_ee(mdev, e, "process_done_ee");
+ /* list_del not necessary, next/prev members not touched */
+ if (e->w.cb(mdev, &e->w, 0) == 0)
+ ok = 0;
+ drbd_free_ee(mdev, e);
+ }
+ wake_up(&mdev->ee_wait);
+
+ return ok;
+}
+
+
+
+/* clean-up helper for drbd_disconnect */
+void _drbd_clear_done_ee(struct drbd_conf *mdev)
+{
+ struct list_head *le;
+ struct drbd_epoch_entry *e;
+ struct drbd_epoch *epoch;
+ int n = 0;
+
+
+ reclaim_net_ee(mdev);
+
+ while (!list_empty(&mdev->done_ee)) {
+ le = mdev->done_ee.next;
+ list_del(le);
+ e = list_entry(le, struct drbd_epoch_entry, w.list);
+ if (mdev->net_conf->wire_protocol == DRBD_PROT_C
+ || is_syncer_block_id(e->block_id))
+ ++n;
+
+ if (!hlist_unhashed(&e->colision))
+ hlist_del_init(&e->colision);
+
+ if (e->epoch) {
+ if (e->flags & EE_IS_BARRIER) {
+ epoch = previous_epoch(mdev, e->epoch);
+ if (epoch)
+ drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + EV_CLEANUP);
+ }
+ drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + EV_CLEANUP);
+ }
+ drbd_free_ee(mdev, e);
+ }
+
+ sub_unacked(mdev, n);
+}
+
+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 portnumber, 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 yess, 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");
+ return -1;
+ }
+ }
+
+ 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)
+ return -1;
+ if (signal_pending(current)) {
+ flush_signals(current);
+ smp_rmb();
+ if (get_t_state(&mdev->receiver) == Exiting) {
+ if (sock)
+ sock_release(sock);
+ if (msock)
+ sock_release(msock);
+ return -1;
+ }
+ }
+
+ 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, wich is hardcoded for now: */
+ sock->sk->sk_sndtimeo =
+ sock->sk->sk_rcvtimeo = 2*HZ;
+
+ 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;
+}
+
+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;
+ }
+
+ trace_drbd_epoch(mdev, epoch, ev);
+
+ 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--;
+ trace_drbd_epoch(mdev, epoch, EV_TRACE_FREE);
+ 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) {
+ trace_drbd_epoch(mdev, epoch, EV_TRACE_FLUSH);
+ 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. It it is reported late, we will just
+ print that warning an continue corretly 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++;
+ trace_drbd_epoch(mdev, epoch, EV_TRACE_ALLOC);
+ } 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;
+
+ e = drbd_alloc_ee(mdev, id, sector, data_size, GFP_KERNEL);
+ 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, GFP_KERNEL);
+
+ 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;
+}
+
+/* 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 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);
+ ok &= drbd_io_error(mdev, FALSE);
+ }
+ 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);
+
+ trace_drbd_ee(mdev, e, "submitting for (rs)write");
+ trace_drbd_bio(mdev, "Sec", e->private_bio, 0, NULL);
+ 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, 0);
+ /* 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 unused)
+{
+ 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);
+ }
+
+ 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);
+ ok &= drbd_io_error(mdev, FALSE);
+ /* we expect it to be marked out of sync anyways...
+ * maybe assert this? */
+ }
+ dec_unacked(mdev);
+ } else if (unlikely(!drbd_bio_uptodate(e->private_bio))) {
+ ok = drbd_io_error(mdev, FALSE);
+ }
+
+ /* 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);
+
+ 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)) {
+ /* data is submitted to disk at the end of this function.
+ * corresponding put_ldev done either below (on error),
+ * or in drbd_endio_write_sec. */
+ 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);
+ }
+
+ 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);
+ trace_drbd_epoch(mdev, e->epoch, EV_TRACE_ADD_BARRIER);
+ 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);
+ trace_drbd_epoch(mdev, epoch, EV_TRACE_SETTING_BI);
+ set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
+ trace_drbd_epoch(mdev, e->epoch, EV_TRACE_ADD_BARRIER);
+ 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)
+ 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;
+ trace_drbd_ee(mdev, e, "submitting for (data)write");
+ trace_drbd_bio(mdev, "Sec", e->private_bio, 0, NULL);
+ 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;
+ 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;
+ }
+
+ e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_KERNEL);
+ 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 asynchrously. 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));
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ return 0;
+ }
+ 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) {
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ return 0;
+ }
+
+ di->digest_size = digest_size;
+ di->digest = (((char *)di)+sizeof(struct digest_info));
+
+ if (drbd_recv(mdev, di->digest, digest_size) != digest_size) {
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ kfree(di);
+ return FALSE;
+ }
+
+ 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));
+ drbd_free_ee(mdev, e);
+ kfree(di);
+ put_ldev(mdev);
+ return FALSE;
+ }
+ 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 asynchrously. 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));
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ return 0;
+ }
+ 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);
+
+ trace_drbd_ee(mdev, e, "submitting for read");
+ trace_drbd_bio(mdev, "Sec", e->private_bio, 0, NULL);
+ drbd_generic_make_request(mdev, fault_type, e->private_bio);
+ maybe_kick_lo(mdev);
+
+ return TRUE;
+}
+
+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, "Sucessfully 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, "Sucessfully 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 = 1;
+ if (self == UUID_JUST_CREATED && peer == UUID_JUST_CREATED)
+ return 0;
+
+ *rule_nr = 2;
+ if ((self == UUID_JUST_CREATED || self == (u64)0) &&
+ peer != UUID_JUST_CREATED)
+ return -2;
+
+ *rule_nr = 3;
+ if (self != UUID_JUST_CREATED &&
+ (peer == UUID_JUST_CREATED || peer == (u64)0))
+ return 2;
+
+ *rule_nr = 4;
+ if (self == peer) { /* Common power [off|failure] */
+ int rct, dc; /* roles at crash time */
+
+ 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 */
+
+ 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 = 5;
+ peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ if (self == peer)
+ return -1;
+
+ *rule_nr = 6;
+ for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+ peer = mdev->p_uuid[i] & ~((u64)1);
+ if (self == peer)
+ return -2;
+ }
+
+ *rule_nr = 7;
+ self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ if (self == peer)
+ return 1;
+
+ *rule_nr = 8;
+ 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 = 9;
+ 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 = 10;
+ 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;
+
+ hg = drbd_uuid_compare(mdev, &rule_nr);
+
+ dev_info(DEV, "drbd_sync_handshake:\n");
+ drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
+ mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ drbd_uuid_dump(mdev, "peer", mdev->p_uuid,
+ mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ 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 ((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 wether 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, probabely 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 UpTpDate 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_CONNECTED ||
+ mdev->state.conn == C_WF_SYNC_UUID);
+
+ /* 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 suceessfully 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;
+ }
+
+ trace_drbd_packet(mdev, mdev->data.socket, 2, &mdev->data.rbuf,
+ __FILE__, __LINE__);
+ }
+}
+
+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));
+ _req_mod(req, connection_lost_while_pending, 0);
+ }
+ }
+ 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);
+}
+
+static void drbd_disconnect(struct drbd_conf *mdev)
+{
+ struct drbd_work prev_work_done;
+ 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_clear_done_ee(mdev);
+ _drbd_wait_ee_list_empty(mdev, &mdev->read_ee);
+ reclaim_net_ee(mdev);
+ 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);
+
+ /* 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" */
+ set_bit(WORK_PENDING, &mdev->flags);
+ prev_work_done.cb = w_prev_work_done;
+ drbd_queue_work(&mdev->data.work, &prev_work_done);
+ wait_event(mdev->misc_wait, !test_bit(WORK_PENDING, &mdev->flags));
+
+ 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));
+ }
+
+ /* they do trigger all the time.
+ * hm. why won't tcp release the page references,
+ * we already released the socket!? */
+ i = atomic_read(&mdev->pp_in_use);
+ if (i)
+ dev_info(DEV, "pp_in_use = %u, expected 0\n", i);
+ if (!list_empty(&mdev->net_ee))
+ dev_info(DEV, "net_ee not empty!\n");
+
+ 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 yess, 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.
+ */
+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;
+ }
+
+ trace_drbd_packet(mdev, mdev->data.socket, 2, &mdev->data.rbuf,
+ __FILE__, __LINE__);
+
+ 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)
+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
+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;
+}
+
+static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct drbd_request *req;
+ 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);
+
+ 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);
+ } else {
+ spin_lock_irq(&mdev->req_lock);
+ req = _ack_id_to_req(mdev, p->block_id, sector);
+
+ if (unlikely(!req)) {
+ spin_unlock_irq(&mdev->req_lock);
+ dev_err(DEV, "Got a corrupt block_id/sector pair(2).\n");
+ return FALSE;
+ }
+
+ switch (be16_to_cpu(h->command)) {
+ case P_RS_WRITE_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ _req_mod(req, write_acked_by_peer_and_sis, 0);
+ break;
+ case P_WRITE_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ _req_mod(req, write_acked_by_peer, 0);
+ break;
+ case P_RECV_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B);
+ _req_mod(req, recv_acked_by_peer, 0);
+ break;
+ case P_DISCARD_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ dev_alert(DEV, "Got DiscardAck packet %llus +%u!"
+ " DRBD is not a random data generator!\n",
+ (unsigned long long)req->sector, req->size);
+ _req_mod(req, conflict_discarded_by_peer, 0);
+ break;
+ default:
+ D_ASSERT(0);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+ }
+ /* dec_ap_pending is handled within _req_mod */
+
+ return TRUE;
+}
+
+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);
+ struct drbd_request *req;
+
+ 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);
+ } else {
+ spin_lock_irq(&mdev->req_lock);
+ req = _ack_id_to_req(mdev, p->block_id, sector);
+
+ if (unlikely(!req)) {
+ spin_unlock_irq(&mdev->req_lock);
+ dev_err(DEV, "Got a corrupt block_id/sector pair(2).\n");
+ return FALSE;
+ }
+
+ _req_mod(req, neg_acked, 0);
+ spin_unlock_irq(&mdev->req_lock);
+ }
+
+ return TRUE;
+}
+
+static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct drbd_request *req;
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ sector_t sector = be64_to_cpu(p->sector);
+
+ spin_lock_irq(&mdev->req_lock);
+ req = _ar_id_to_req(mdev, p->block_id, sector);
+ if (unlikely(!req)) {
+ spin_unlock_irq(&mdev->req_lock);
+ dev_err(DEV, "Got a corrupt block_id/sector pair(3).\n");
+ return FALSE;
+ }
+
+ _req_mod(req, neg_acked, 0);
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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 TRUE;
+}
+
+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)) {
+ trace_drbd_packet(mdev, mdev->meta.socket, 1, (void *)h, __FILE__, __LINE__);
+ goto reconnect;
+ }
+ }
+ if (received == expect) {
+ D_ASSERT(cmd != NULL);
+ trace_drbd_packet(mdev, mdev->meta.socket, 1, (void *)h, __FILE__, __LINE__);
+ 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..67609ec26a6d
--- /dev/null
+++ b/drivers/block/drbd/drbd_req.c
@@ -0,0 +1,1130 @@
+/*
+ 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/autoconf.h>
+#include <linux/module.h>
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_tracing.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++;
+}
+
+/* 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--;
+}
+
+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
+ * initialised 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
+}
+
+static void _complete_master_bio(struct drbd_conf *mdev,
+ struct drbd_request *req, int error)
+{
+ trace_drbd_bio(mdev, "Rq", req->master_bio, 1, req);
+ bio_endio(req->master_bio, error);
+ req->master_bio = NULL;
+ dec_ap_bio(mdev);
+}
+
+void _req_may_be_done(struct drbd_request *req, int error)
+{
+ const unsigned long s = req->rq_state;
+ struct drbd_conf *mdev = req->mdev;
+ int rw;
+
+ trace_drbd_req(req, nothing, "_req_may_be_done");
+
+ /* 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 suceeded.
+ * 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.
+ */
+ int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK);
+ rw = bio_data_dir(req->master_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);
+
+ _complete_master_bio(mdev, req,
+ ok ? 0 : (error ? error : -EIO));
+ } else {
+ /* only WRITE requests can end up here without a master_bio */
+ rw = WRITE;
+ }
+
+ 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, int error)
+{
+ struct drbd_conf *mdev = req->mdev;
+
+ if (error && (bio_rw(req->master_bio) != READA))
+ dev_err(DEV, "got an _req_mod() errno of %d\n", error);
+
+ trace_drbd_req(req, what, NULL);
+
+ switch (what) {
+ default:
+ dev_err(DEV, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
+ return;
+
+ /* 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->private_bio) == WRITE)
+ mdev->writ_cnt += req->size>>9;
+ else
+ mdev->read_cnt += req->size>>9;
+
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+
+ req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ _req_may_be_done(req, error);
+ put_ldev(mdev);
+ break;
+
+ case write_completed_with_error:
+ req->rq_state |= RQ_LOCAL_COMPLETED;
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+ 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, error);
+ put_ldev(mdev);
+ break;
+
+ case read_completed_with_error:
+ if (bio_rw(req->master_bio) != READA)
+ drbd_set_out_of_sync(mdev, req->sector, req->size);
+
+ req->rq_state |= RQ_LOCAL_COMPLETED;
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+ if (bio_rw(req->master_bio) == READA) {
+ /* it is legal to fail READA */
+ _req_may_be_done(req, error);
+ put_ldev(mdev);
+ break;
+ }
+ /* else */
+ 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, error);
+ 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 sucessfully 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, error);
+ 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, error);
+ 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 primarys,
+ * there is no need to keep anything in the tl, potential
+ * node crashes are covered by the activity log. */
+ 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 unecessary optimisation. */
+
+ /* this makes it effectively the same as for: */
+ case recv_acked_by_peer:
+ /* protocol B; pretends to be sucessfully 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, error);
+ 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, error);
+ /* 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");
+ trace_drbd_req(req, nothing, "FIXME (barrier_acked but pending)");
+ 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, error);
+ 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, error);
+ 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, thats not our business. */
+ dev_err(DEV, "could not kmalloc() req\n");
+ bio_endio(bio, -ENOMEM);
+ return 0;
+ }
+
+ trace_drbd_bio(mdev, "Rq", bio, 0, req);
+
+ 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 deferres 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, 0);
+ if (local)
+ _req_mod(req, to_be_submitted, 0);
+
+ /* check this request on the colison 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.
+ */
+ if (rw == WRITE)
+ _req_mod(req, queue_for_net_write, 0);
+ else
+ _req_mod(req, queue_for_net_read, 0);
+ }
+ 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;
+
+ trace_drbd_bio(mdev, "Pri", req->private_bio, 0, NULL);
+
+ 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?) somehwere
+ * 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 allignment 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 emtpy 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..81393ffa8c25
--- /dev/null
+++ b/drivers/block/drbd/drbd_req.h
@@ -0,0 +1,299 @@
+/*
+ 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/autoconf.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,
+ 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)));
+}
+
+/* aparently too large to be inlined...
+ * moved to drbd_req.c */
+extern void _req_may_be_done(struct drbd_request *req, int error);
+extern void _req_mod(struct drbd_request *req,
+ enum drbd_req_event what, int error);
+
+/* If you need it irqsave, do it your self! */
+static inline void req_mod(struct drbd_request *req,
+ enum drbd_req_event what, int error)
+{
+ struct drbd_conf *mdev = req->mdev;
+ spin_lock_irq(&mdev->req_lock);
+ _req_mod(req, what, error);
+ spin_unlock_irq(&mdev->req_lock);
+}
+#endif
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
new file mode 100644
index 000000000000..b39f1b3a0cbd
--- /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 requesed operation requires a disk",
+ [-SS_DEVICE_IN_USE] = "Device is held open by someone",
+ [-SS_NO_NET_CONFIG] = "Have no net/connection configuration",
+ [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify",
+ [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync",
+ [-SS_NOT_SUPPORTED] = "Peer does not support protocol",
+ [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated",
+ [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change",
+ [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted",
+};
+
+const char *drbd_conn_str(enum drbd_conns s)
+{
+ /* enums are unsigned... */
+ return s > C_PAUSED_SYNC_T ? "TOO_LARGE" : drbd_conn_s_names[s];
+}
+
+const char *drbd_role_str(enum drbd_role s)
+{
+ return s > R_SECONDARY ? "TOO_LARGE" : drbd_role_s_names[s];
+}
+
+const char *drbd_disk_str(enum drbd_disk_state s)
+{
+ return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s];
+}
+
+const char *drbd_set_st_err_str(enum drbd_state_ret_codes err)
+{
+ return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" :
+ err > SS_TWO_PRIMARIES ? "TOO_LARGE"
+ : drbd_state_sw_errors[-err];
+}
diff --git a/drivers/block/drbd/drbd_tracing.c b/drivers/block/drbd/drbd_tracing.c
new file mode 100644
index 000000000000..86509cc77634
--- /dev/null
+++ b/drivers/block/drbd/drbd_tracing.c
@@ -0,0 +1,752 @@
+/*
+ drbd_tracing.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/drbd.h>
+#include <linux/ctype.h>
+#include <linux/marker.h>
+#include "drbd_int.h"
+#include "drbd_tracing.h"
+#include <linux/drbd_tag_magic.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philipp Reisner, Lars Ellenberg");
+MODULE_DESCRIPTION("DRBD tracepoint probes");
+MODULE_PARM_DESC(trace_mask, "Bitmap of events to trace see drbd_tracing.c");
+MODULE_PARM_DESC(trace_level, "Current tracing level (changeable in /sys)");
+MODULE_PARM_DESC(trace_devs, "Bitmap of devices to trace (changeable in /sys)");
+
+unsigned int trace_mask = 0; /* Bitmap of events to trace */
+int trace_level; /* Current trace level */
+int trace_devs; /* Bitmap of devices to trace */
+
+module_param(trace_mask, uint, 0444);
+module_param(trace_level, int, 0644);
+module_param(trace_devs, int, 0644);
+
+enum {
+ TRACE_PACKET = 0x0001,
+ TRACE_RQ = 0x0002,
+ TRACE_UUID = 0x0004,
+ TRACE_RESYNC = 0x0008,
+ TRACE_EE = 0x0010,
+ TRACE_UNPLUG = 0x0020,
+ TRACE_NL = 0x0040,
+ TRACE_AL_EXT = 0x0080,
+ TRACE_INT_RQ = 0x0100,
+ TRACE_MD_IO = 0x0200,
+ TRACE_EPOCH = 0x0400,
+};
+
+/* Buffer printing support
+ * dbg_print_flags: used for Flags arg to drbd_print_buffer
+ * - DBGPRINT_BUFFADDR; if set, each line starts with the
+ * virtual address of the line being output. If clear,
+ * each line starts with the offset from the beginning
+ * of the buffer. */
+enum dbg_print_flags {
+ DBGPRINT_BUFFADDR = 0x0001,
+};
+
+/* Macro stuff */
+static char *nl_packet_name(int packet_type)
+{
+/* Generate packet type strings */
+#define NL_PACKET(name, number, fields) \
+ [P_ ## name] = # name,
+#define NL_INTEGER Argh!
+#define NL_BIT Argh!
+#define NL_INT64 Argh!
+#define NL_STRING Argh!
+
+ static char *nl_tag_name[P_nl_after_last_packet] = {
+#include "linux/drbd_nl.h"
+ };
+
+ return (packet_type < sizeof(nl_tag_name)/sizeof(nl_tag_name[0])) ?
+ nl_tag_name[packet_type] : "*Unknown*";
+}
+/* /Macro stuff */
+
+static inline int is_mdev_trace(struct drbd_conf *mdev, unsigned int level)
+{
+ return trace_level >= level && ((1 << mdev_to_minor(mdev)) & trace_devs);
+}
+
+static void probe_drbd_unplug(struct drbd_conf *mdev, char *msg)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "%s, ap_bio_count=%d\n", msg, atomic_read(&mdev->ap_bio_cnt));
+}
+
+static void probe_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index)
+{
+ static char *uuid_str[UI_EXTENDED_SIZE] = {
+ [UI_CURRENT] = "CURRENT",
+ [UI_BITMAP] = "BITMAP",
+ [UI_HISTORY_START] = "HISTORY_START",
+ [UI_HISTORY_END] = "HISTORY_END",
+ [UI_SIZE] = "SIZE",
+ [UI_FLAGS] = "FLAGS",
+ };
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ if (index >= UI_EXTENDED_SIZE) {
+ dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n");
+ return;
+ }
+
+ dev_info(DEV, " uuid[%s] now %016llX\n",
+ uuid_str[index],
+ (unsigned long long)mdev->ldev->md.uuid[index]);
+}
+
+static void probe_drbd_md_io(struct drbd_conf *mdev, int rw,
+ struct drbd_backing_dev *bdev)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, " %s metadata superblock now\n",
+ rw == READ ? "Reading" : "Writing");
+}
+
+static void probe_drbd_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, char* msg)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "EE %s sec=%llus size=%u e=%p\n",
+ msg, (unsigned long long)e->sector, e->size, e);
+}
+
+static void probe_drbd_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch,
+ enum epoch_event ev)
+{
+ static char *epoch_event_str[] = {
+ [EV_PUT] = "put",
+ [EV_GOT_BARRIER_NR] = "got_barrier_nr",
+ [EV_BARRIER_DONE] = "barrier_done",
+ [EV_BECAME_LAST] = "became_last",
+ [EV_TRACE_FLUSH] = "issuing_flush",
+ [EV_TRACE_ADD_BARRIER] = "added_barrier",
+ [EV_TRACE_SETTING_BI] = "just set barrier_in_next_epoch",
+ };
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ ev &= ~EV_CLEANUP;
+
+ switch (ev) {
+ case EV_TRACE_ALLOC:
+ dev_info(DEV, "Allocat epoch %p/xxxx { } nr_epochs=%d\n", epoch, mdev->epochs);
+ break;
+ case EV_TRACE_FREE:
+ dev_info(DEV, "Freeing epoch %p/%d { size=%d } nr_epochs=%d\n",
+ epoch, epoch->barrier_nr, atomic_read(&epoch->epoch_size),
+ mdev->epochs);
+ break;
+ default:
+ dev_info(DEV, "Update epoch %p/%d { size=%d active=%d %c%c n%c%c } ev=%s\n",
+ epoch, epoch->barrier_nr, atomic_read(&epoch->epoch_size),
+ atomic_read(&epoch->active),
+ test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) ? 'n' : '-',
+ test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) ? 'b' : '-',
+ test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) ? 'i' : '-',
+ test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ? 'd' : '-',
+ epoch_event_str[ev]);
+ }
+}
+
+static void probe_drbd_netlink(void *data, int is_req)
+{
+ struct cn_msg *msg = data;
+
+ if (is_req) {
+ struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)msg->data;
+
+ printk(KERN_INFO "drbd%d: "
+ "Netlink: << %s (%d) - seq: %x, ack: %x, len: %x\n",
+ nlp->drbd_minor,
+ nl_packet_name(nlp->packet_type),
+ nlp->packet_type,
+ msg->seq, msg->ack, msg->len);
+ } else {
+ struct drbd_nl_cfg_reply *nlp = (struct drbd_nl_cfg_reply *)msg->data;
+
+ printk(KERN_INFO "drbd%d: "
+ "Netlink: >> %s (%d) - seq: %x, ack: %x, len: %x\n",
+ nlp->minor,
+ nlp->packet_type == P_nl_after_last_packet ?
+ "Empty-Reply" : nl_packet_name(nlp->packet_type),
+ nlp->packet_type,
+ msg->seq, msg->ack, msg->len);
+ }
+}
+
+static void probe_drbd_actlog(struct drbd_conf *mdev, sector_t sector, char* msg)
+{
+ unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "%s (sec=%llus, al_enr=%u, rs_enr=%d)\n",
+ msg, (unsigned long long) sector, enr,
+ (int)BM_SECT_TO_EXT(sector));
+}
+
+/**
+ * drbd_print_buffer() - Hexdump arbitraty binary data into a buffer
+ * @prefix: String is output at the beginning of each line output.
+ * @flags: Currently only defined flag: DBGPRINT_BUFFADDR; if set, each
+ * line starts with the virtual address of the line being
+ * outupt. If clear, each line starts with the offset from the
+ * beginning of the buffer.
+ * @size: Indicates the size of each entry in the buffer. Supported
+ * values are sizeof(char), sizeof(short) and sizeof(int)
+ * @buffer: Start address of buffer
+ * @buffer_va: Virtual address of start of buffer (normally the same
+ * as Buffer, but having it separate allows it to hold
+ * file address for example)
+ * @length: length of buffer
+ */
+static void drbd_print_buffer(const char *prefix, unsigned int flags, int size,
+ const void *buffer, const void *buffer_va,
+ unsigned int length)
+
+#define LINE_SIZE 16
+#define LINE_ENTRIES (int)(LINE_SIZE/size)
+{
+ const unsigned char *pstart;
+ const unsigned char *pstart_va;
+ const unsigned char *pend;
+ char bytes_str[LINE_SIZE*3+8], ascii_str[LINE_SIZE+8];
+ char *pbytes = bytes_str, *pascii = ascii_str;
+ int offset = 0;
+ long sizemask;
+ int field_width;
+ int index;
+ const unsigned char *pend_str;
+ const unsigned char *p;
+ int count;
+
+ /* verify size parameter */
+ if (size != sizeof(char) &&
+ size != sizeof(short) &&
+ size != sizeof(int)) {
+ printk(KERN_DEBUG "drbd_print_buffer: "
+ "ERROR invalid size %d\n", size);
+ return;
+ }
+
+ sizemask = size-1;
+ field_width = size*2;
+
+ /* Adjust start/end to be on appropriate boundary for size */
+ buffer = (const char *)((long)buffer & ~sizemask);
+ pend = (const unsigned char *)
+ (((long)buffer + length + sizemask) & ~sizemask);
+
+ if (flags & DBGPRINT_BUFFADDR) {
+ /* Move start back to nearest multiple of line size,
+ * if printing address. This results in nicely formatted output
+ * with addresses being on line size (16) byte boundaries */
+ pstart = (const unsigned char *)((long)buffer & ~(LINE_SIZE-1));
+ } else {
+ pstart = (const unsigned char *)buffer;
+ }
+
+ /* Set value of start VA to print if addresses asked for */
+ pstart_va = (const unsigned char *)buffer_va
+ - ((const unsigned char *)buffer-pstart);
+
+ /* Calculate end position to nicely align right hand side */
+ pend_str = pstart + (((pend-pstart) + LINE_SIZE-1) & ~(LINE_SIZE-1));
+
+ /* Init strings */
+ *pbytes = *pascii = '\0';
+
+ /* Start at beginning of first line */
+ p = pstart;
+ count = 0;
+
+ while (p < pend_str) {
+ if (p < (const unsigned char *)buffer || p >= pend) {
+ /* Before start of buffer or after end- print spaces */
+ pbytes += sprintf(pbytes, "%*c ", field_width, ' ');
+ pascii += sprintf(pascii, "%*c", size, ' ');
+ p += size;
+ } else {
+ /* Add hex and ascii to strings */
+ int val;
+ switch (size) {
+ default:
+ case 1:
+ val = *(unsigned char *)p;
+ break;
+ case 2:
+ val = *(unsigned short *)p;
+ break;
+ case 4:
+ val = *(unsigned int *)p;
+ break;
+ }
+
+ pbytes += sprintf(pbytes, "%0*x ", field_width, val);
+
+ for (index = size; index; index--) {
+ *pascii++ = isprint(*p) ? *p : '.';
+ p++;
+ }
+ }
+
+ count++;
+
+ if (count == LINE_ENTRIES || p >= pend_str) {
+ /* Null terminate and print record */
+ *pascii = '\0';
+ printk(KERN_DEBUG "%s%8.8lx: %*s|%*s|\n",
+ prefix,
+ (flags & DBGPRINT_BUFFADDR)
+ ? (long)pstart_va:(long)offset,
+ LINE_ENTRIES*(field_width+1), bytes_str,
+ LINE_SIZE, ascii_str);
+
+ /* Move onto next line */
+ pstart_va += (p-pstart);
+ pstart = p;
+ count = 0;
+ offset += LINE_SIZE;
+
+ /* Re-init strings */
+ pbytes = bytes_str;
+ pascii = ascii_str;
+ *pbytes = *pascii = '\0';
+ }
+ }
+}
+
+static void probe_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt, va_list args)
+{
+ char str[256];
+
+ if (!is_mdev_trace(mdev, level))
+ return;
+
+ if (vsnprintf(str, 256, fmt, args) >= 256)
+ str[255] = 0;
+
+ printk(KERN_INFO "%s %s: %s", dev_driver_string(disk_to_dev(mdev->vdisk)),
+ dev_name(disk_to_dev(mdev->vdisk)), str);
+}
+
+static void probe_drbd_bio(struct drbd_conf *mdev, const char *pfx, struct bio *bio, int complete,
+ struct drbd_request *r)
+{
+#if defined(CONFIG_LBDAF) || defined(CONFIG_LBD)
+#define SECTOR_FORMAT "%Lx"
+#else
+#define SECTOR_FORMAT "%lx"
+#endif
+#define SECTOR_SHIFT 9
+
+ unsigned long lowaddr = (unsigned long)(bio->bi_sector << SECTOR_SHIFT);
+ char *faddr = (char *)(lowaddr);
+ char rb[sizeof(void *)*2+6] = { 0, };
+ struct bio_vec *bvec;
+ int segno;
+
+ const int rw = bio->bi_rw;
+ const int biorw = (rw & (RW_MASK|RWA_MASK));
+ const int biobarrier = (rw & (1<<BIO_RW_BARRIER));
+ const int biosync = (rw & ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO)));
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ if (r)
+ sprintf(rb, "Req:%p ", r);
+
+ dev_info(DEV, "%s %s:%s%s%s Bio:%p %s- %soffset " SECTOR_FORMAT ", size %x\n",
+ complete ? "<<<" : ">>>",
+ pfx,
+ biorw == WRITE ? "Write" : "Read",
+ biobarrier ? " : B" : "",
+ biosync ? " : S" : "",
+ bio,
+ rb,
+ complete ? (bio_flagged(bio, BIO_UPTODATE) ? "Success, " : "Failed, ") : "",
+ bio->bi_sector << SECTOR_SHIFT,
+ bio->bi_size);
+
+ if (trace_level >= TRACE_LVL_METRICS &&
+ ((biorw == WRITE) ^ complete)) {
+ printk(KERN_DEBUG " ind page offset length\n");
+ __bio_for_each_segment(bvec, bio, segno, 0) {
+ printk(KERN_DEBUG " [%d] %p %8.8x %8.8x\n", segno,
+ bvec->bv_page, bvec->bv_offset, bvec->bv_len);
+
+ if (trace_level >= TRACE_LVL_ALL) {
+ char *bvec_buf;
+ unsigned long flags;
+
+ bvec_buf = bvec_kmap_irq(bvec, &flags);
+
+ drbd_print_buffer(" ", DBGPRINT_BUFFADDR, 1,
+ bvec_buf,
+ faddr,
+ (bvec->bv_len <= 0x80)
+ ? bvec->bv_len : 0x80);
+
+ bvec_kunmap_irq(bvec_buf, &flags);
+
+ if (bvec->bv_len > 0x40)
+ printk(KERN_DEBUG " ....\n");
+
+ faddr += bvec->bv_len;
+ }
+ }
+ }
+}
+
+static void probe_drbd_req(struct drbd_request *req, enum drbd_req_event what, char *msg)
+{
+ static const char *rq_event_names[] = {
+ [created] = "created",
+ [to_be_send] = "to_be_send",
+ [to_be_submitted] = "to_be_submitted",
+ [queue_for_net_write] = "queue_for_net_write",
+ [queue_for_net_read] = "queue_for_net_read",
+ [send_canceled] = "send_canceled",
+ [send_failed] = "send_failed",
+ [handed_over_to_network] = "handed_over_to_network",
+ [connection_lost_while_pending] =
+ "connection_lost_while_pending",
+ [recv_acked_by_peer] = "recv_acked_by_peer",
+ [write_acked_by_peer] = "write_acked_by_peer",
+ [neg_acked] = "neg_acked",
+ [conflict_discarded_by_peer] = "conflict_discarded_by_peer",
+ [barrier_acked] = "barrier_acked",
+ [data_received] = "data_received",
+ [read_completed_with_error] = "read_completed_with_error",
+ [write_completed_with_error] = "write_completed_with_error",
+ [completed_ok] = "completed_ok",
+ };
+
+ struct drbd_conf *mdev = req->mdev;
+
+ const int rw = (req->master_bio == NULL ||
+ bio_data_dir(req->master_bio) == WRITE) ?
+ 'W' : 'R';
+ const unsigned long s = req->rq_state;
+
+ if (what != nothing) {
+ dev_info(DEV, "_req_mod(%p %c ,%s)\n", req, rw, rq_event_names[what]);
+ } else {
+ dev_info(DEV, "%s %p %c L%c%c%cN%c%c%c%c%c %u (%llus +%u) %s\n",
+ msg, req, rw,
+ s & RQ_LOCAL_PENDING ? 'p' : '-',
+ s & RQ_LOCAL_COMPLETED ? 'c' : '-',
+ s & RQ_LOCAL_OK ? 'o' : '-',
+ s & RQ_NET_PENDING ? 'p' : '-',
+ s & RQ_NET_QUEUED ? 'q' : '-',
+ s & RQ_NET_SENT ? 's' : '-',
+ s & RQ_NET_DONE ? 'd' : '-',
+ s & RQ_NET_OK ? 'o' : '-',
+ req->epoch,
+ (unsigned long long)req->sector,
+ req->size,
+ drbd_conn_str(mdev->state.conn));
+ }
+}
+
+
+#define drbd_peer_str drbd_role_str
+#define drbd_pdsk_str drbd_disk_str
+
+#define PSM(A) \
+do { \
+ if (mask.A) { \
+ int i = snprintf(p, len, " " #A "( %s )", \
+ drbd_##A##_str(val.A)); \
+ if (i >= len) \
+ return op; \
+ p += i; \
+ len -= i; \
+ } \
+} while (0)
+
+static char *dump_st(char *p, int len, union drbd_state mask, union drbd_state val)
+{
+ char *op = p;
+ *p = '\0';
+ PSM(role);
+ PSM(peer);
+ PSM(conn);
+ PSM(disk);
+ PSM(pdsk);
+
+ return op;
+}
+
+#define INFOP(fmt, args...) \
+do { \
+ if (trace_level >= TRACE_LVL_ALL) { \
+ dev_info(DEV, "%s:%d: %s [%d] %s %s " fmt , \
+ file, line, current->comm, current->pid, \
+ sockname, recv ? "<<<" : ">>>" , \
+ ## args); \
+ } else { \
+ dev_info(DEV, "%s %s " fmt, sockname, \
+ recv ? "<<<" : ">>>" , \
+ ## args); \
+ } \
+} while (0)
+
+static char *_dump_block_id(u64 block_id, char *buff)
+{
+ if (is_syncer_block_id(block_id))
+ strcpy(buff, "SyncerId");
+ else
+ sprintf(buff, "%llx", (unsigned long long)block_id);
+
+ return buff;
+}
+
+static void probe_drbd_packet(struct drbd_conf *mdev, struct socket *sock,
+ int recv, union p_polymorph *p, char *file, int line)
+{
+ char *sockname = sock == mdev->meta.socket ? "meta" : "data";
+ int cmd = (recv == 2) ? p->header.command : be16_to_cpu(p->header.command);
+ char tmp[300];
+ union drbd_state m, v;
+
+ switch (cmd) {
+ case P_HAND_SHAKE:
+ INFOP("%s (protocol %u-%u)\n", cmdname(cmd),
+ be32_to_cpu(p->handshake.protocol_min),
+ be32_to_cpu(p->handshake.protocol_max));
+ break;
+
+ case P_BITMAP: /* don't report this */
+ case P_COMPRESSED_BITMAP: /* don't report this */
+ break;
+
+ case P_DATA:
+ INFOP("%s (sector %llus, id %s, seq %u, f %x)\n", cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->data.sector),
+ _dump_block_id(p->data.block_id, tmp),
+ be32_to_cpu(p->data.seq_num),
+ be32_to_cpu(p->data.dp_flags)
+ );
+ break;
+
+ case P_DATA_REPLY:
+ case P_RS_DATA_REPLY:
+ INFOP("%s (sector %llus, id %s)\n", cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->data.sector),
+ _dump_block_id(p->data.block_id, tmp)
+ );
+ break;
+
+ case P_RECV_ACK:
+ case P_WRITE_ACK:
+ case P_RS_WRITE_ACK:
+ case P_DISCARD_ACK:
+ case P_NEG_ACK:
+ case P_NEG_RS_DREPLY:
+ INFOP("%s (sector %llus, size %u, id %s, seq %u)\n",
+ cmdname(cmd),
+ (long long)be64_to_cpu(p->block_ack.sector),
+ be32_to_cpu(p->block_ack.blksize),
+ _dump_block_id(p->block_ack.block_id, tmp),
+ be32_to_cpu(p->block_ack.seq_num)
+ );
+ break;
+
+ case P_DATA_REQUEST:
+ case P_RS_DATA_REQUEST:
+ INFOP("%s (sector %llus, size %u, id %s)\n", cmdname(cmd),
+ (long long)be64_to_cpu(p->block_req.sector),
+ be32_to_cpu(p->block_req.blksize),
+ _dump_block_id(p->block_req.block_id, tmp)
+ );
+ break;
+
+ case P_BARRIER:
+ case P_BARRIER_ACK:
+ INFOP("%s (barrier %u)\n", cmdname(cmd), p->barrier.barrier);
+ break;
+
+ case P_SYNC_PARAM:
+ case P_SYNC_PARAM89:
+ INFOP("%s (rate %u, verify-alg \"%.64s\", csums-alg \"%.64s\")\n",
+ cmdname(cmd), be32_to_cpu(p->rs_param_89.rate),
+ p->rs_param_89.verify_alg, p->rs_param_89.csums_alg);
+ break;
+
+ case P_UUIDS:
+ INFOP("%s Curr:%016llX, Bitmap:%016llX, "
+ "HisSt:%016llX, HisEnd:%016llX\n",
+ cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_CURRENT]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_BITMAP]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_HISTORY_START]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_HISTORY_END]));
+ break;
+
+ case P_SIZES:
+ INFOP("%s (d %lluMiB, u %lluMiB, c %lldMiB, "
+ "max bio %x, q order %x)\n",
+ cmdname(cmd),
+ (long long)(be64_to_cpu(p->sizes.d_size)>>(20-9)),
+ (long long)(be64_to_cpu(p->sizes.u_size)>>(20-9)),
+ (long long)(be64_to_cpu(p->sizes.c_size)>>(20-9)),
+ be32_to_cpu(p->sizes.max_segment_size),
+ be32_to_cpu(p->sizes.queue_order_type));
+ break;
+
+ case P_STATE:
+ v.i = be32_to_cpu(p->state.state);
+ m.i = 0xffffffff;
+ dump_st(tmp, sizeof(tmp), m, v);
+ INFOP("%s (s %x {%s})\n", cmdname(cmd), v.i, tmp);
+ break;
+
+ case P_STATE_CHG_REQ:
+ m.i = be32_to_cpu(p->req_state.mask);
+ v.i = be32_to_cpu(p->req_state.val);
+ dump_st(tmp, sizeof(tmp), m, v);
+ INFOP("%s (m %x v %x {%s})\n", cmdname(cmd), m.i, v.i, tmp);
+ break;
+
+ case P_STATE_CHG_REPLY:
+ INFOP("%s (ret %x)\n", cmdname(cmd),
+ be32_to_cpu(p->req_state_reply.retcode));
+ break;
+
+ case P_PING:
+ case P_PING_ACK:
+ /*
+ * Dont trace pings at summary level
+ */
+ if (trace_level < TRACE_LVL_ALL)
+ break;
+ /* fall through... */
+ default:
+ INFOP("%s (%u)\n", cmdname(cmd), cmd);
+ break;
+ }
+}
+
+
+static int __init drbd_trace_init(void)
+{
+ int ret;
+
+ if (trace_mask & TRACE_UNPLUG) {
+ ret = register_trace_drbd_unplug(probe_drbd_unplug);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_UUID) {
+ ret = register_trace_drbd_uuid(probe_drbd_uuid);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_EE) {
+ ret = register_trace_drbd_ee(probe_drbd_ee);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_PACKET) {
+ ret = register_trace_drbd_packet(probe_drbd_packet);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_MD_IO) {
+ ret = register_trace_drbd_md_io(probe_drbd_md_io);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_EPOCH) {
+ ret = register_trace_drbd_epoch(probe_drbd_epoch);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_NL) {
+ ret = register_trace_drbd_netlink(probe_drbd_netlink);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_AL_EXT) {
+ ret = register_trace_drbd_actlog(probe_drbd_actlog);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_RQ) {
+ ret = register_trace_drbd_bio(probe_drbd_bio);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_INT_RQ) {
+ ret = register_trace_drbd_req(probe_drbd_req);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_RESYNC) {
+ ret = register_trace__drbd_resync(probe_drbd_resync);
+ WARN_ON(ret);
+ }
+ return 0;
+}
+
+module_init(drbd_trace_init);
+
+static void __exit drbd_trace_exit(void)
+{
+ if (trace_mask & TRACE_UNPLUG)
+ unregister_trace_drbd_unplug(probe_drbd_unplug);
+ if (trace_mask & TRACE_UUID)
+ unregister_trace_drbd_uuid(probe_drbd_uuid);
+ if (trace_mask & TRACE_EE)
+ unregister_trace_drbd_ee(probe_drbd_ee);
+ if (trace_mask & TRACE_PACKET)
+ unregister_trace_drbd_packet(probe_drbd_packet);
+ if (trace_mask & TRACE_MD_IO)
+ unregister_trace_drbd_md_io(probe_drbd_md_io);
+ if (trace_mask & TRACE_EPOCH)
+ unregister_trace_drbd_epoch(probe_drbd_epoch);
+ if (trace_mask & TRACE_NL)
+ unregister_trace_drbd_netlink(probe_drbd_netlink);
+ if (trace_mask & TRACE_AL_EXT)
+ unregister_trace_drbd_actlog(probe_drbd_actlog);
+ if (trace_mask & TRACE_RQ)
+ unregister_trace_drbd_bio(probe_drbd_bio);
+ if (trace_mask & TRACE_INT_RQ)
+ unregister_trace_drbd_req(probe_drbd_req);
+ if (trace_mask & TRACE_RESYNC)
+ unregister_trace__drbd_resync(probe_drbd_resync);
+
+ tracepoint_synchronize_unregister();
+}
+
+module_exit(drbd_trace_exit);
diff --git a/drivers/block/drbd/drbd_tracing.h b/drivers/block/drbd/drbd_tracing.h
new file mode 100644
index 000000000000..c4531a137f65
--- /dev/null
+++ b/drivers/block/drbd/drbd_tracing.h
@@ -0,0 +1,87 @@
+/*
+ drbd_tracing.h
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef DRBD_TRACING_H
+#define DRBD_TRACING_H
+
+#include <linux/tracepoint.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+enum {
+ TRACE_LVL_ALWAYS = 0,
+ TRACE_LVL_SUMMARY,
+ TRACE_LVL_METRICS,
+ TRACE_LVL_ALL,
+ TRACE_LVL_MAX
+};
+
+DECLARE_TRACE(drbd_unplug,
+ TP_PROTO(struct drbd_conf *mdev, char* msg),
+ TP_ARGS(mdev, msg));
+
+DECLARE_TRACE(drbd_uuid,
+ TP_PROTO(struct drbd_conf *mdev, enum drbd_uuid_index index),
+ TP_ARGS(mdev, index));
+
+DECLARE_TRACE(drbd_ee,
+ TP_PROTO(struct drbd_conf *mdev, struct drbd_epoch_entry *e, char* msg),
+ TP_ARGS(mdev, e, msg));
+
+DECLARE_TRACE(drbd_md_io,
+ TP_PROTO(struct drbd_conf *mdev, int rw, struct drbd_backing_dev *bdev),
+ TP_ARGS(mdev, rw, bdev));
+
+DECLARE_TRACE(drbd_epoch,
+ TP_PROTO(struct drbd_conf *mdev, struct drbd_epoch *epoch, enum epoch_event ev),
+ TP_ARGS(mdev, epoch, ev));
+
+DECLARE_TRACE(drbd_netlink,
+ TP_PROTO(void *data, int is_req),
+ TP_ARGS(data, is_req));
+
+DECLARE_TRACE(drbd_actlog,
+ TP_PROTO(struct drbd_conf *mdev, sector_t sector, char* msg),
+ TP_ARGS(mdev, sector, msg));
+
+DECLARE_TRACE(drbd_bio,
+ TP_PROTO(struct drbd_conf *mdev, const char *pfx, struct bio *bio, int complete,
+ struct drbd_request *r),
+ TP_ARGS(mdev, pfx, bio, complete, r));
+
+DECLARE_TRACE(drbd_req,
+ TP_PROTO(struct drbd_request *req, enum drbd_req_event what, char *msg),
+ TP_ARGS(req, what, msg));
+
+DECLARE_TRACE(drbd_packet,
+ TP_PROTO(struct drbd_conf *mdev, struct socket *sock,
+ int recv, union p_polymorph *p, char *file, int line),
+ TP_ARGS(mdev, sock, recv, p, file, line));
+
+DECLARE_TRACE(_drbd_resync,
+ TP_PROTO(struct drbd_conf *mdev, int level, const char *fmt, va_list args),
+ TP_ARGS(mdev, level, fmt, args));
+
+#endif
diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h
new file mode 100644
index 000000000000..fc824006e721
--- /dev/null
+++ b/drivers/block/drbd/drbd_vli.h
@@ -0,0 +1,351 @@
+/*
+-*- linux-c -*-
+ drbd_receiver.c
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DRBD_VLI_H
+#define _DRBD_VLI_H
+
+/*
+ * At a granularity of 4KiB storage represented per bit,
+ * and stroage sizes of several TiB,
+ * and possibly small-bandwidth replication,
+ * the bitmap transfer time can take much too long,
+ * if transmitted in plain text.
+ *
+ * We try to reduce the transfered bitmap information
+ * by encoding runlengths of bit polarity.
+ *
+ * We never actually need to encode a "zero" (runlengths are positive).
+ * But then we have to store the value of the first bit.
+ * The first bit of information thus shall encode if the first runlength
+ * gives the number of set or unset bits.
+ *
+ * We assume that large areas are either completely set or unset,
+ * which gives good compression with any runlength method,
+ * even when encoding the runlength as fixed size 32bit/64bit integers.
+ *
+ * Still, there may be areas where the polarity flips every few bits,
+ * and encoding the runlength sequence of those areas with fix size
+ * integers would be much worse than plaintext.
+ *
+ * We want to encode small runlength values with minimum code length,
+ * while still being able to encode a Huge run of all zeros.
+ *
+ * Thus we need a Variable Length Integer encoding, VLI.
+ *
+ * For some cases, we produce more code bits than plaintext input.
+ * We need to send incompressible chunks as plaintext, skip over them
+ * and then see if the next chunk compresses better.
+ *
+ * We don't care too much about "excellent" compression ratio for large
+ * runlengths (all set/all clear): whether we achieve a factor of 100
+ * or 1000 is not that much of an issue.
+ * We do not want to waste too much on short runlengths in the "noisy"
+ * parts of the bitmap, though.
+ *
+ * There are endless variants of VLI, we experimented with:
+ * * simple byte-based
+ * * various bit based with different code word length.
+ *
+ * To avoid yet an other configuration parameter (choice of bitmap compression
+ * algorithm) which was difficult to explain and tune, we just chose the one
+ * variant that turned out best in all test cases.
+ * Based on real world usage patterns, with device sizes ranging from a few GiB
+ * to several TiB, file server/mailserver/webserver/mysql/postgress,
+ * mostly idle to really busy, the all time winner (though sometimes only
+ * marginally better) is:
+ */
+
+/*
+ * encoding is "visualised" as
+ * __little endian__ bitstream, least significant bit first (left most)
+ *
+ * this particular encoding is chosen so that the prefix code
+ * starts as unary encoding the level, then modified so that
+ * 10 levels can be described in 8bit, with minimal overhead
+ * for the smaller levels.
+ *
+ * Number of data bits follow fibonacci sequence, with the exception of the
+ * last level (+1 data bit, so it makes 64bit total). The only worse code when
+ * encoding bit polarity runlength is 1 plain bits => 2 code bits.
+prefix data bits max val Nº data bits
+0 x 0x2 1
+10 x 0x4 1
+110 xx 0x8 2
+1110 xxx 0x10 3
+11110 xxx xx 0x30 5
+111110 xx xxxxxx 0x130 8
+11111100 xxxxxxxx xxxxx 0x2130 13
+11111110 xxxxxxxx xxxxxxxx xxxxx 0x202130 21
+11111101 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xx 0x400202130 34
+11111111 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 56
+ * maximum encodable value: 0x100000400202130 == 2**56 + some */
+
+/* compression "table":
+ transmitted x 0.29
+ as plaintext x ........................
+ x ........................
+ x ........................
+ x 0.59 0.21........................
+ x ........................................................
+ x .. c ...................................................
+ x 0.44.. o ...................................................
+ x .......... d ...................................................
+ x .......... e ...................................................
+ X............. ...................................................
+ x.............. b ...................................................
+2.0x............... i ...................................................
+ #X................ t ...................................................
+ #................. s ........................... plain bits ..........
+-+-----------------------------------------------------------------------
+ 1 16 32 64
+*/
+
+/* LEVEL: (total bits, prefix bits, prefix value),
+ * sorted ascending by number of total bits.
+ * The rest of the code table is calculated at compiletime from this. */
+
+/* fibonacci data 1, 1, ... */
+#define VLI_L_1_1() do { \
+ LEVEL( 2, 1, 0x00); \
+ LEVEL( 3, 2, 0x01); \
+ LEVEL( 5, 3, 0x03); \
+ LEVEL( 7, 4, 0x07); \
+ LEVEL(10, 5, 0x0f); \
+ LEVEL(14, 6, 0x1f); \
+ LEVEL(21, 8, 0x3f); \
+ LEVEL(29, 8, 0x7f); \
+ LEVEL(42, 8, 0xbf); \
+ LEVEL(64, 8, 0xff); \
+ } while (0)
+
+/* finds a suitable level to decode the least significant part of in.
+ * returns number of bits consumed.
+ *
+ * BUG() for bad input, as that would mean a buggy code table. */
+static inline int vli_decode_bits(u64 *out, const u64 in)
+{
+ u64 adj = 1;
+
+#define LEVEL(t,b,v) \
+ do { \
+ if ((in & ((1 << b) -1)) == v) { \
+ *out = ((in & ((~0ULL) >> (64-t))) >> b) + adj; \
+ return t; \
+ } \
+ adj += 1ULL << (t - b); \
+ } while (0)
+
+ VLI_L_1_1();
+
+ /* NOT REACHED, if VLI_LEVELS code table is defined properly */
+ BUG();
+#undef LEVEL
+}
+
+/* return number of code bits needed,
+ * or negative error number */
+static inline int __vli_encode_bits(u64 *out, const u64 in)
+{
+ u64 max = 0;
+ u64 adj = 1;
+
+ if (in == 0)
+ return -EINVAL;
+
+#define LEVEL(t,b,v) do { \
+ max += 1ULL << (t - b); \
+ if (in <= max) { \
+ if (out) \
+ *out = ((in - adj) << b) | v; \
+ return t; \
+ } \
+ adj = max + 1; \
+ } while (0)
+
+ VLI_L_1_1();
+
+ return -EOVERFLOW;
+#undef LEVEL
+}
+
+#undef VLI_L_1_1
+
+/* code from here down is independend of actually used bit code */
+
+/*
+ * Code length is determined by some unique (e.g. unary) prefix.
+ * This encodes arbitrary bit length, not whole bytes: we have a bit-stream,
+ * not a byte stream.
+ */
+
+/* for the bitstream, we need a cursor */
+struct bitstream_cursor {
+ /* the current byte */
+ u8 *b;
+ /* the current bit within *b, nomalized: 0..7 */
+ unsigned int bit;
+};
+
+/* initialize cursor to point to first bit of stream */
+static inline void bitstream_cursor_reset(struct bitstream_cursor *cur, void *s)
+{
+ cur->b = s;
+ cur->bit = 0;
+}
+
+/* advance cursor by that many bits; maximum expected input value: 64,
+ * but depending on VLI implementation, it may be more. */
+static inline void bitstream_cursor_advance(struct bitstream_cursor *cur, unsigned int bits)
+{
+ bits += cur->bit;
+ cur->b = cur->b + (bits >> 3);
+ cur->bit = bits & 7;
+}
+
+/* the bitstream itself knows its length */
+struct bitstream {
+ struct bitstream_cursor cur;
+ unsigned char *buf;
+ size_t buf_len; /* in bytes */
+
+ /* for input stream:
+ * number of trailing 0 bits for padding
+ * total number of valid bits in stream: buf_len * 8 - pad_bits */
+ unsigned int pad_bits;
+};
+
+static inline void bitstream_init(struct bitstream *bs, void *s, size_t len, unsigned int pad_bits)
+{
+ bs->buf = s;
+ bs->buf_len = len;
+ bs->pad_bits = pad_bits;
+ bitstream_cursor_reset(&bs->cur, bs->buf);
+}
+
+static inline void bitstream_rewind(struct bitstream *bs)
+{
+ bitstream_cursor_reset(&bs->cur, bs->buf);
+ memset(bs->buf, 0, bs->buf_len);
+}
+
+/* Put (at most 64) least significant bits of val into bitstream, and advance cursor.
+ * Ignores "pad_bits".
+ * Returns zero if bits == 0 (nothing to do).
+ * Returns number of bits used if successful.
+ *
+ * If there is not enough room left in bitstream,
+ * leaves bitstream unchanged and returns -ENOBUFS.
+ */
+static inline int bitstream_put_bits(struct bitstream *bs, u64 val, const unsigned int bits)
+{
+ unsigned char *b = bs->cur.b;
+ unsigned int tmp;
+
+ if (bits == 0)
+ return 0;
+
+ if ((bs->cur.b + ((bs->cur.bit + bits -1) >> 3)) - bs->buf >= bs->buf_len)
+ return -ENOBUFS;
+
+ /* paranoia: strip off hi bits; they should not be set anyways. */
+ if (bits < 64)
+ val &= ~0ULL >> (64 - bits);
+
+ *b++ |= (val & 0xff) << bs->cur.bit;
+
+ for (tmp = 8 - bs->cur.bit; tmp < bits; tmp += 8)
+ *b++ |= (val >> tmp) & 0xff;
+
+ bitstream_cursor_advance(&bs->cur, bits);
+ return bits;
+}
+
+/* Fetch (at most 64) bits from bitstream into *out, and advance cursor.
+ *
+ * If more than 64 bits are requested, returns -EINVAL and leave *out unchanged.
+ *
+ * If there are less than the requested number of valid bits left in the
+ * bitstream, still fetches all available bits.
+ *
+ * Returns number of actually fetched bits.
+ */
+static inline int bitstream_get_bits(struct bitstream *bs, u64 *out, int bits)
+{
+ u64 val;
+ unsigned int n;
+
+ if (bits > 64)
+ return -EINVAL;
+
+ if (bs->cur.b + ((bs->cur.bit + bs->pad_bits + bits -1) >> 3) - bs->buf >= bs->buf_len)
+ bits = ((bs->buf_len - (bs->cur.b - bs->buf)) << 3)
+ - bs->cur.bit - bs->pad_bits;
+
+ if (bits == 0) {
+ *out = 0;
+ return 0;
+ }
+
+ /* get the high bits */
+ val = 0;
+ n = (bs->cur.bit + bits + 7) >> 3;
+ /* n may be at most 9, if cur.bit + bits > 64 */
+ /* which means this copies at most 8 byte */
+ if (n) {
+ memcpy(&val, bs->cur.b+1, n - 1);
+ val = le64_to_cpu(val) << (8 - bs->cur.bit);
+ }
+
+ /* we still need the low bits */
+ val |= bs->cur.b[0] >> bs->cur.bit;
+
+ /* and mask out bits we don't want */
+ val &= ~0ULL >> (64 - bits);
+
+ bitstream_cursor_advance(&bs->cur, bits);
+ *out = val;
+
+ return bits;
+}
+
+/* encodes @in as vli into @bs;
+
+ * return values
+ * > 0: number of bits successfully stored in bitstream
+ * -ENOBUFS @bs is full
+ * -EINVAL input zero (invalid)
+ * -EOVERFLOW input too large for this vli code (invalid)
+ */
+static inline int vli_encode_bits(struct bitstream *bs, u64 in)
+{
+ u64 code = code;
+ int bits = __vli_encode_bits(&code, in);
+
+ if (bits <= 0)
+ return bits;
+
+ return bitstream_put_bits(bs, code, bits);
+}
+
+#endif
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
new file mode 100644
index 000000000000..a6d86e37de30
--- /dev/null
+++ b/drivers/block/drbd/drbd_worker.c
@@ -0,0 +1,1527 @@
+/*
+ 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/autoconf.h>
+#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"
+#include "drbd_tracing.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 follwing:
+ * 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;
+
+ trace_drbd_bio(md_io->mdev, "Md", bio, 1, NULL);
+
+ 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 && !uptodate) {
+ /* strange behaviour of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?!
+ * do we want to dev_warn(DEV, ) on this? */
+ error = -EIO;
+ }
+
+ D_ASSERT(e->block_id != ID_VACANT);
+
+ trace_drbd_bio(mdev, "Sec", bio, 1, NULL);
+
+ 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);
+
+ trace_drbd_ee(mdev, e, "read completed");
+}
+
+/* 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);
+
+ e = bio->bi_private;
+ mdev = e->mdev;
+
+ if (!error && !uptodate) {
+ /* strange behaviour of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?!
+ * do we want to dev_warn(DEV, ) on this? */
+ error = -EIO;
+ }
+
+ /* error == -ENOTSUPP would be a better test,
+ * alas it is not reliable */
+ if (error && 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;
+ __release(local); /* Actually happens in w_e_reissue. */
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+ drbd_queue_work(&mdev->data.work, &e->w);
+ return;
+ }
+
+ D_ASSERT(e->block_id != ID_VACANT);
+
+ trace_drbd_bio(mdev, "Sec", bio, 1, NULL);
+
+ 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);
+
+ trace_drbd_ee(mdev, e, "write completed");
+
+ /* 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 comming 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;
+ enum drbd_req_event what;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+ if (!error && !uptodate) {
+ /* strange behaviour of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?!
+ * do we want to dev_warn(DEV, ) on this? */
+ error = -EIO;
+ }
+
+ trace_drbd_bio(mdev, "Pri", bio, 1, NULL);
+
+ /* to avoid recursion in _req_mod */
+ what = error
+ ? (bio_data_dir(bio) == WRITE)
+ ? write_completed_with_error
+ : read_completed_with_error
+ : completed_ok;
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ _req_mod(req, what, error);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+}
+
+int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = (struct drbd_request *)w;
+ int ok;
+
+ /* 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);
+
+ ok = drbd_io_error(mdev, FALSE);
+ if (unlikely(!ok))
+ dev_err(DEV, "Sending in w_io_error() failed\n");
+ return ok;
+}
+
+int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = (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 */
+ drbd_io_error(mdev, FALSE); /* tries to schedule a detach and notifies peer */
+
+ spin_lock_irq(&mdev->req_lock);
+ if (cancel ||
+ mdev->state.conn < C_CONNECTED ||
+ mdev->state.pdsk <= D_INCONSISTENT) {
+ _req_mod(req, send_canceled, 0);
+ 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 = (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 {
+ drbd_io_error(mdev, FALSE);
+ 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;
+
+ if (FAULT_ACTIVE(mdev, DRBD_FAULT_AL_EE))
+ return 2;
+
+ 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 nunber 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 sendbuffer 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.
+ *
+ * Aditionally always align bigger requests, in order to
+ * be prepared for all stripe sizes of software RAIDs.
+ *
+ * we _do_ care about the agreed-uppon 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;
+}
+
+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 probabely 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;
+}
+
+/**
+ * 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 = (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);
+
+ drbd_io_error(mdev, FALSE);
+ }
+
+ dec_unacked(mdev);
+
+ spin_lock_irq(&mdev->req_lock);
+ if (drbd_bio_has_active_page(e->private_bio)) {
+ /* This might happen if sendpage() has not finished */
+ list_add_tail(&e->w.list, &mdev->net_ee);
+ } else {
+ drbd_free_ee(mdev, e);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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 = (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);
+
+ drbd_io_error(mdev, FALSE);
+
+ /* update resync data with failure */
+ drbd_rs_failed_io(mdev, e->sector, e->size);
+ }
+
+ dec_unacked(mdev);
+
+ spin_lock_irq(&mdev->req_lock);
+ if (drbd_bio_has_active_page(e->private_bio)) {
+ /* This might happen if sendpage() has not finished */
+ list_add_tail(&e->w.list, &mdev->net_ee);
+ } else {
+ drbd_free_ee(mdev, e);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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 = (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");
+ drbd_io_error(mdev, FALSE);
+ }
+
+ dec_unacked(mdev);
+
+ kfree(di);
+
+ spin_lock_irq(&mdev->req_lock);
+ if (drbd_bio_has_active_page(e->private_bio)) {
+ /* This might happen if sendpage() has not finished */
+ list_add_tail(&e->w.list, &mdev->net_ee);
+ } else {
+ drbd_free_ee(mdev, e);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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 = (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:
+ spin_lock_irq(&mdev->req_lock);
+ drbd_free_ee(mdev, e);
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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 = (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");
+ drbd_io_error(mdev, FALSE);
+ }
+
+ 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);
+
+ spin_lock_irq(&mdev->req_lock);
+ drbd_free_ee(mdev, e);
+ spin_unlock_irq(&mdev->req_lock);
+
+ 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)
+{
+ clear_bit(WORK_PENDING, &mdev->flags);
+ wake_up(&mdev->misc_wait);
+ return 1;
+}
+
+int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_tl_epoch *b = (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 requeued, 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 = (struct drbd_request *)w;
+ int ok;
+
+ if (unlikely(cancel)) {
+ req_mod(req, send_canceled, 0);
+ return 1;
+ }
+
+ ok = drbd_send_dblock(mdev, req);
+ req_mod(req, ok ? handed_over_to_network : send_failed, 0);
+
+ 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 = (struct drbd_request *)w;
+ int ok;
+
+ if (unlikely(cancel)) {
+ req_mod(req, send_canceled, 0);
+ 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, 0);
+
+ 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;
+ }
+
+ trace_drbd_resync(mdev, TRACE_LVL_SUMMARY, "Resync starting: side=%s\n",
+ side == C_SYNC_TARGET ? "SyncTarget" : "SyncSource");
+
+ /* 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) {
+ 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/floppy.c b/drivers/block/floppy.c
index 91b753013780..2b387c2260d8 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4151,7 +4151,7 @@ static void floppy_device_release(struct device *dev)
{
}
-static int floppy_resume(struct platform_device *dev)
+static int floppy_resume(struct device *dev)
{
int fdc;
@@ -4162,10 +4162,15 @@ static int floppy_resume(struct platform_device *dev)
return 0;
}
-static struct platform_driver floppy_driver = {
+static struct dev_pm_ops floppy_pm_ops = {
.resume = floppy_resume,
+ .restore = floppy_resume,
+};
+
+static struct platform_driver floppy_driver = {
.driver = {
.name = "floppy",
+ .pm = &floppy_pm_ops,
},
};
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5757188cd1fb..bbb79441d895 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -475,7 +475,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
if (bio_rw(bio) == WRITE) {
- int barrier = bio_barrier(bio);
+ bool barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
struct file *file = lo->lo_backing_file;
if (barrier) {
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c
index f703f5478246..6d7fbaa92248 100644
--- a/drivers/block/mg_disk.c
+++ b/drivers/block/mg_disk.c
@@ -36,7 +36,6 @@
/* Register offsets */
#define MG_BUFF_OFFSET 0x8000
-#define MG_STORAGE_BUFFER_SIZE 0x200
#define MG_REG_OFFSET 0xC000
#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */
#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */
@@ -219,6 +218,16 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
host->error = MG_ERR_NONE;
expire = jiffies + msecs_to_jiffies(msec);
+ /* These 2 times dummy status read prevents reading invalid
+ * status. A very little time (3 times of mflash operating clk)
+ * is required for busy bit is set. Use dummy read instead of
+ * busy wait, because mflash's PLL is machine dependent.
+ */
+ if (prv_data->use_polling) {
+ status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
+ status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
+ }
+
status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
do {
@@ -245,8 +254,6 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
mg_dump_status("not ready", status, host);
return MG_ERR_INV_STAT;
}
- if (prv_data->use_polling)
- msleep(1);
status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
} while (time_before(cur_jiffies, expire));
@@ -469,9 +476,18 @@ static unsigned int mg_out(struct mg_host *host,
return MG_ERR_NONE;
}
+static void mg_read_one(struct mg_host *host, struct request *req)
+{
+ u16 *buff = (u16 *)req->buffer;
+ u32 i;
+
+ for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
+ *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
+ (i << 1));
+}
+
static void mg_read(struct request *req)
{
- u32 j;
struct mg_host *host = req->rq_disk->private_data;
if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
@@ -482,49 +498,65 @@ static void mg_read(struct request *req)
blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
do {
- u16 *buff = (u16 *)req->buffer;
-
if (mg_wait(host, ATA_DRQ,
MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) {
mg_bad_rw_intr(host);
return;
}
- for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
- *buff++ = inw((unsigned long)host->dev_base +
- MG_BUFF_OFFSET + (j << 1));
+
+ mg_read_one(host, req);
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
MG_REG_COMMAND);
} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
}
+static void mg_write_one(struct mg_host *host, struct request *req)
+{
+ u16 *buff = (u16 *)req->buffer;
+ u32 i;
+
+ for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
+ outw(*buff++, (unsigned long)host->dev_base + MG_BUFF_OFFSET +
+ (i << 1));
+}
+
static void mg_write(struct request *req)
{
- u32 j;
struct mg_host *host = req->rq_disk->private_data;
+ unsigned int rem = blk_rq_sectors(req);
- if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
+ if (mg_out(host, blk_rq_pos(req), rem,
MG_CMD_WR, NULL) != MG_ERR_NONE) {
mg_bad_rw_intr(host);
return;
}
MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
- blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
+ rem, blk_rq_pos(req), req->buffer);
+
+ if (mg_wait(host, ATA_DRQ,
+ MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
+ mg_bad_rw_intr(host);
+ return;
+ }
do {
- u16 *buff = (u16 *)req->buffer;
+ mg_write_one(host, req);
- if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
+ outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
+ MG_REG_COMMAND);
+
+ rem--;
+ if (rem > 1 && mg_wait(host, ATA_DRQ,
+ MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
+ mg_bad_rw_intr(host);
+ return;
+ } else if (mg_wait(host, MG_STAT_READY,
+ MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
mg_bad_rw_intr(host);
return;
}
- for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
- outw(*buff++, (unsigned long)host->dev_base +
- MG_BUFF_OFFSET + (j << 1));
-
- outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
- MG_REG_COMMAND);
} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
}
@@ -532,7 +564,6 @@ static void mg_read_intr(struct mg_host *host)
{
struct request *req = host->req;
u32 i;
- u16 *buff;
/* check status */
do {
@@ -550,13 +581,7 @@ static void mg_read_intr(struct mg_host *host)
return;
ok_to_read:
- /* get current segment of request */
- buff = (u16 *)req->buffer;
-
- /* read 1 sector */
- for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
- *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
- (i << 1));
+ mg_read_one(host, req);
MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer);
@@ -575,8 +600,7 @@ ok_to_read:
static void mg_write_intr(struct mg_host *host)
{
struct request *req = host->req;
- u32 i, j;
- u16 *buff;
+ u32 i;
bool rem;
/* check status */
@@ -597,12 +621,7 @@ static void mg_write_intr(struct mg_host *host)
ok_to_write:
if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) {
/* write 1 sector and set handler if remains */
- buff = (u16 *)req->buffer;
- for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
- outw(*buff, (unsigned long)host->dev_base +
- MG_BUFF_OFFSET + (j << 1));
- buff++;
- }
+ mg_write_one(host, req);
MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
host->mg_do_intr = mg_write_intr;
@@ -667,9 +686,6 @@ static unsigned int mg_issue_req(struct request *req,
unsigned int sect_num,
unsigned int sect_cnt)
{
- u16 *buff;
- u32 i;
-
switch (rq_data_dir(req)) {
case READ:
if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr)
@@ -693,12 +709,7 @@ static unsigned int mg_issue_req(struct request *req,
mg_bad_rw_intr(host);
return host->error;
}
- buff = (u16 *)req->buffer;
- for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) {
- outw(*buff, (unsigned long)host->dev_base +
- MG_BUFF_OFFSET + (i << 1));
- buff++;
- }
+ mg_write_one(host, req);
mod_timer(&host->timer, jiffies + 3 * HZ);
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
MG_REG_COMMAND);
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
index 13c1aee6aa3f..28f1f25f0f63 100644
--- a/drivers/block/osdblk.c
+++ b/drivers/block/osdblk.c
@@ -442,7 +442,7 @@ static int osdblk_init_disk(struct osdblk_device *osdev)
* sleep when allocating a lower-request and therefore cannot be
* bouncing.
*/
- blk_queue_stack_limits(q, osd_request_queue(osdev->osd));
+ blk_stack_limits(&q->limits, &osd_request_queue(osdev->osd)->limits, 0);
blk_queue_prep_rq(q, blk_queue_start_tag);
blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, osdblk_prepare_flush);
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 1164837bb781..652367aa6546 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -170,5 +170,30 @@ config BT_HCIVHCI
Say Y here to compile support for virtual HCI devices into the
kernel or say M to compile it as module (hci_vhci).
+config BT_MRVL
+ tristate "Marvell Bluetooth driver support"
+ help
+ The core driver to support Marvell Bluetooth devices.
+
+ This driver is required if you want to support
+ Marvell Bluetooth devices, such as 8688.
+
+ Say Y here to compile Marvell Bluetooth driver
+ into the kernel or say M to compile it as module.
+
+config BT_MRVL_SDIO
+ tristate "Marvell BT-over-SDIO driver"
+ depends on BT_MRVL && MMC
+ select FW_LOADER
+ help
+ The driver for Marvell Bluetooth chipsets with SDIO interface.
+
+ This driver is required if you want to use Marvell Bluetooth
+ devices with SDIO interface. Currently only SD8688 chipset is
+ supported.
+
+ Say Y here to compile support for Marvell BT-over-SDIO driver
+ into the kernel or say M to compile it as module.
+
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 16930f93d1ca..b3f57d2d4eb0 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -15,6 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+obj-$(CONFIG_BT_MRVL) += btmrvl.o
+obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
+
+btmrvl-y := btmrvl_main.o
+btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
+
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
new file mode 100644
index 000000000000..4617bd12f63b
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -0,0 +1,432 @@
+/**
+ * Marvell Bluetooth driver: debugfs related functions
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/debugfs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+
+struct btmrvl_debugfs_data {
+ struct dentry *root_dir, *config_dir, *status_dir;
+
+ /* config */
+ struct dentry *drvdbg;
+ struct dentry *psmode;
+ struct dentry *pscmd;
+ struct dentry *hsmode;
+ struct dentry *hscmd;
+ struct dentry *gpiogap;
+ struct dentry *hscfgcmd;
+
+ /* status */
+ struct dentry *curpsmode;
+ struct dentry *hsstate;
+ struct dentry *psstate;
+ struct dentry *txdnldready;
+};
+
+static int btmrvl_open_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t btmrvl_hscfgcmd_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hscfgcmd = result;
+
+ if (priv->btmrvl_dev.hscfgcmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+}
+
+static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.hscfgcmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hscfgcmd_fops = {
+ .read = btmrvl_hscfgcmd_read,
+ .write = btmrvl_hscfgcmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.psmode = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.psmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_psmode_fops = {
+ .read = btmrvl_psmode_read,
+ .write = btmrvl_psmode_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.pscmd = result;
+
+ if (priv->btmrvl_dev.pscmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+
+}
+
+static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_pscmd_fops = {
+ .read = btmrvl_pscmd_read,
+ .write = btmrvl_pscmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 16, &result);
+
+ priv->btmrvl_dev.gpio_gap = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
+ priv->btmrvl_dev.gpio_gap);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_gpiogap_fops = {
+ .read = btmrvl_gpiogap_read,
+ .write = btmrvl_gpiogap_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hscmd = result;
+ if (priv->btmrvl_dev.hscmd) {
+ btmrvl_prepare_command(priv);
+ wake_up_interruptible(&priv->main_thread.wait_q);
+ }
+
+ return count;
+}
+
+static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hscmd_fops = {
+ .read = btmrvl_hscmd_read,
+ .write = btmrvl_hscmd_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ long result, ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ ret = strict_strtol(buf, 10, &result);
+
+ priv->btmrvl_dev.hsmode = result;
+
+ return count;
+}
+
+static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hsmode_fops = {
+ .read = btmrvl_hsmode_read,
+ .write = btmrvl_hsmode_write,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_curpsmode_fops = {
+ .read = btmrvl_curpsmode_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_psstate_fops = {
+ .read = btmrvl_psstate_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_hsstate_fops = {
+ .read = btmrvl_hsstate_read,
+ .open = btmrvl_open_generic,
+};
+
+static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct btmrvl_private *priv = file->private_data;
+ char buf[16];
+ int ret;
+
+ ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
+ priv->btmrvl_dev.tx_dnld_rdy);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+}
+
+static const struct file_operations btmrvl_txdnldready_fops = {
+ .read = btmrvl_txdnldready_read,
+ .open = btmrvl_open_generic,
+};
+
+void btmrvl_debugfs_init(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+ struct btmrvl_debugfs_data *dbg;
+
+ dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
+ priv->debugfs_data = dbg;
+
+ if (!dbg) {
+ BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
+ return;
+ }
+
+ dbg->root_dir = debugfs_create_dir("btmrvl", NULL);
+
+ dbg->config_dir = debugfs_create_dir("config", dbg->root_dir);
+
+ dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_psmode_fops);
+ dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_pscmd_fops);
+ dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_gpiogap_fops);
+ dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hsmode_fops);
+ dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hscmd_fops);
+ dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
+ hdev->driver_data, &btmrvl_hscfgcmd_fops);
+
+ dbg->status_dir = debugfs_create_dir("status", dbg->root_dir);
+ dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
+ dbg->status_dir,
+ hdev->driver_data,
+ &btmrvl_curpsmode_fops);
+ dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
+ hdev->driver_data, &btmrvl_psstate_fops);
+ dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
+ hdev->driver_data, &btmrvl_hsstate_fops);
+ dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
+ dbg->status_dir,
+ hdev->driver_data,
+ &btmrvl_txdnldready_fops);
+}
+
+void btmrvl_debugfs_remove(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+ struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
+
+ if (!dbg)
+ return;
+
+ debugfs_remove(dbg->psmode);
+ debugfs_remove(dbg->pscmd);
+ debugfs_remove(dbg->gpiogap);
+ debugfs_remove(dbg->hsmode);
+ debugfs_remove(dbg->hscmd);
+ debugfs_remove(dbg->hscfgcmd);
+ debugfs_remove(dbg->config_dir);
+
+ debugfs_remove(dbg->curpsmode);
+ debugfs_remove(dbg->psstate);
+ debugfs_remove(dbg->hsstate);
+ debugfs_remove(dbg->txdnldready);
+ debugfs_remove(dbg->status_dir);
+
+ debugfs_remove(dbg->root_dir);
+
+ kfree(dbg);
+}
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
new file mode 100644
index 000000000000..411c7a77082d
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -0,0 +1,139 @@
+/*
+ * Marvell Bluetooth driver: global definitions & declarations
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <net/bluetooth/bluetooth.h>
+
+#define BTM_HEADER_LEN 4
+#define BTM_UPLD_SIZE 2312
+
+/* Time to wait until Host Sleep state change in millisecond */
+#define WAIT_UNTIL_HS_STATE_CHANGED 5000
+/* Time to wait for command response in millisecond */
+#define WAIT_UNTIL_CMD_RESP 5000
+
+struct btmrvl_thread {
+ struct task_struct *task;
+ wait_queue_head_t wait_q;
+ void *priv;
+};
+
+struct btmrvl_device {
+ void *card;
+ struct hci_dev *hcidev;
+
+ u8 tx_dnld_rdy;
+
+ u8 psmode;
+ u8 pscmd;
+ u8 hsmode;
+ u8 hscmd;
+
+ /* Low byte is gap, high byte is GPIO */
+ u16 gpio_gap;
+
+ u8 hscfgcmd;
+ u8 sendcmdflag;
+};
+
+struct btmrvl_adapter {
+ u32 int_count;
+ struct sk_buff_head tx_queue;
+ u8 psmode;
+ u8 ps_state;
+ u8 hs_state;
+ u8 wakeup_tries;
+ wait_queue_head_t cmd_wait_q;
+ u8 cmd_complete;
+};
+
+struct btmrvl_private {
+ struct btmrvl_device btmrvl_dev;
+ struct btmrvl_adapter *adapter;
+ struct btmrvl_thread main_thread;
+ int (*hw_host_to_card) (struct btmrvl_private *priv,
+ u8 *payload, u16 nb);
+ int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
+ spinlock_t driver_lock; /* spinlock used by driver */
+#ifdef CONFIG_DEBUG_FS
+ void *debugfs_data;
+#endif
+};
+
+#define MRVL_VENDOR_PKT 0xFE
+
+/* Bluetooth commands */
+#define BT_CMD_AUTO_SLEEP_MODE 0x23
+#define BT_CMD_HOST_SLEEP_CONFIG 0x59
+#define BT_CMD_HOST_SLEEP_ENABLE 0x5A
+#define BT_CMD_MODULE_CFG_REQ 0x5B
+
+/* Sub-commands: Module Bringup/Shutdown Request */
+#define MODULE_BRINGUP_REQ 0xF1
+#define MODULE_SHUTDOWN_REQ 0xF2
+
+#define BT_EVENT_POWER_STATE 0x20
+
+/* Bluetooth Power States */
+#define BT_PS_ENABLE 0x02
+#define BT_PS_DISABLE 0x03
+#define BT_PS_SLEEP 0x01
+
+#define OGF 0x3F
+
+/* Host Sleep states */
+#define HS_ACTIVATED 0x01
+#define HS_DEACTIVATED 0x00
+
+/* Power Save modes */
+#define PS_SLEEP 0x01
+#define PS_AWAKE 0x00
+
+struct btmrvl_cmd {
+ __le16 ocf_ogf;
+ u8 length;
+ u8 data[4];
+} __attribute__ ((packed));
+
+struct btmrvl_event {
+ u8 ec; /* event counter */
+ u8 length;
+ u8 data[4];
+} __attribute__ ((packed));
+
+/* Prototype of global function */
+
+struct btmrvl_private *btmrvl_add_card(void *card);
+int btmrvl_remove_card(struct btmrvl_private *priv);
+
+void btmrvl_interrupt(struct btmrvl_private *priv);
+
+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
+
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
+int btmrvl_prepare_command(struct btmrvl_private *priv);
+
+#ifdef CONFIG_DEBUG_FS
+void btmrvl_debugfs_init(struct hci_dev *hdev);
+void btmrvl_debugfs_remove(struct hci_dev *hdev);
+#endif
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
new file mode 100644
index 000000000000..e605563b4eaa
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -0,0 +1,624 @@
+/**
+ * Marvell Bluetooth driver
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+
+#define VERSION "1.0"
+
+/*
+ * This function is called by interface specific interrupt handler.
+ * It updates Power Save & Host Sleep states, and wakes up the main
+ * thread.
+ */
+void btmrvl_interrupt(struct btmrvl_private *priv)
+{
+ priv->adapter->ps_state = PS_AWAKE;
+
+ priv->adapter->wakeup_tries = 0;
+
+ priv->adapter->int_count++;
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+}
+EXPORT_SYMBOL_GPL(btmrvl_interrupt);
+
+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ struct hci_event_hdr *hdr = (void *) skb->data;
+ struct hci_ev_cmd_complete *ec;
+ u16 opcode, ocf;
+
+ if (hdr->evt == HCI_EV_CMD_COMPLETE) {
+ ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);
+ opcode = __le16_to_cpu(ec->opcode);
+ ocf = hci_opcode_ocf(opcode);
+ if (ocf == BT_CMD_MODULE_CFG_REQ &&
+ priv->btmrvl_dev.sendcmdflag) {
+ priv->btmrvl_dev.sendcmdflag = false;
+ priv->adapter->cmd_complete = true;
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt);
+
+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ struct btmrvl_adapter *adapter = priv->adapter;
+ struct btmrvl_event *event;
+ u8 ret = 0;
+
+ event = (struct btmrvl_event *) skb->data;
+ if (event->ec != 0xff) {
+ BT_DBG("Not Marvell Event=%x", event->ec);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (event->data[0]) {
+ case BT_CMD_AUTO_SLEEP_MODE:
+ if (!event->data[2]) {
+ if (event->data[1] == BT_PS_ENABLE)
+ adapter->psmode = 1;
+ else
+ adapter->psmode = 0;
+ BT_DBG("PS Mode:%s",
+ (adapter->psmode) ? "Enable" : "Disable");
+ } else {
+ BT_DBG("PS Mode command failed");
+ }
+ break;
+
+ case BT_CMD_HOST_SLEEP_CONFIG:
+ if (!event->data[3])
+ BT_DBG("gpio=%x, gap=%x", event->data[1],
+ event->data[2]);
+ else
+ BT_DBG("HSCFG command failed");
+ break;
+
+ case BT_CMD_HOST_SLEEP_ENABLE:
+ if (!event->data[1]) {
+ adapter->hs_state = HS_ACTIVATED;
+ if (adapter->psmode)
+ adapter->ps_state = PS_SLEEP;
+ wake_up_interruptible(&adapter->cmd_wait_q);
+ BT_DBG("HS ACTIVATED!");
+ } else {
+ BT_DBG("HS Enable failed");
+ }
+ break;
+
+ case BT_CMD_MODULE_CFG_REQ:
+ if (priv->btmrvl_dev.sendcmdflag &&
+ event->data[1] == MODULE_BRINGUP_REQ) {
+ BT_DBG("EVENT:%s", (event->data[2]) ?
+ "Bring-up failed" : "Bring-up succeed");
+ } else if (priv->btmrvl_dev.sendcmdflag &&
+ event->data[1] == MODULE_SHUTDOWN_REQ) {
+ BT_DBG("EVENT:%s", (event->data[2]) ?
+ "Shutdown failed" : "Shutdown succeed");
+ } else {
+ BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP");
+ ret = -EINVAL;
+ }
+ break;
+
+ case BT_EVENT_POWER_STATE:
+ if (event->data[1] == BT_PS_SLEEP)
+ adapter->ps_state = PS_SLEEP;
+ BT_DBG("EVENT:%s",
+ (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");
+ break;
+
+ default:
+ BT_DBG("Unknown Event=%d", event->data[0]);
+ ret = -EINVAL;
+ break;
+ }
+
+exit:
+ if (!ret)
+ kfree_skb(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(btmrvl_process_event);
+
+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
+{
+ struct sk_buff *skb;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ));
+ cmd->length = 1;
+ cmd->data[0] = subcmd;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ priv->btmrvl_dev.sendcmdflag = true;
+
+ priv->adapter->cmd_complete = false;
+
+ BT_DBG("Queue module cfg Command");
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+ priv->adapter->cmd_complete,
+ msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {
+ ret = -ETIMEDOUT;
+ BT_ERR("module_cfg_cmd(%x): timeout: %d",
+ subcmd, priv->btmrvl_dev.sendcmdflag);
+ }
+
+ BT_DBG("module cfg Command done");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
+
+static int btmrvl_enable_hs(struct btmrvl_private *priv)
+{
+ struct sk_buff *skb;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE));
+ cmd->length = 0;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue hs enable Command");
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+ priv->adapter->hs_state,
+ msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) {
+ ret = -ETIMEDOUT;
+ BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state,
+ priv->adapter->ps_state,
+ priv->adapter->wakeup_tries);
+ }
+
+ return ret;
+}
+
+int btmrvl_prepare_command(struct btmrvl_private *priv)
+{
+ struct sk_buff *skb = NULL;
+ struct btmrvl_cmd *cmd;
+ int ret = 0;
+
+ if (priv->btmrvl_dev.hscfgcmd) {
+ priv->btmrvl_dev.hscfgcmd = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));
+ cmd->length = 2;
+ cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
+ cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
+ cmd->data[0], cmd->data[1]);
+ }
+
+ if (priv->btmrvl_dev.pscmd) {
+ priv->btmrvl_dev.pscmd = 0;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE));
+ cmd->length = 1;
+
+ if (priv->btmrvl_dev.psmode)
+ cmd->data[0] = BT_PS_ENABLE;
+ else
+ cmd->data[0] = BT_PS_DISABLE;
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
+ }
+
+ if (priv->btmrvl_dev.hscmd) {
+ priv->btmrvl_dev.hscmd = 0;
+
+ if (priv->btmrvl_dev.hsmode) {
+ ret = btmrvl_enable_hs(priv);
+ } else {
+ ret = priv->hw_wakeup_firmware(priv);
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ }
+ }
+
+ return ret;
+}
+
+static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
+{
+ int ret = 0;
+
+ if (!skb || !skb->data)
+ return -EINVAL;
+
+ if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) {
+ BT_ERR("Tx Error: Bad skb length %d : %d",
+ skb->len, BTM_UPLD_SIZE);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(skb) < BTM_HEADER_LEN) {
+ struct sk_buff *tmp = skb;
+
+ skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);
+ if (!skb) {
+ BT_ERR("Tx Error: realloc_headroom failed %d",
+ BTM_HEADER_LEN);
+ skb = tmp;
+ return -EINVAL;
+ }
+
+ kfree_skb(tmp);
+ }
+
+ skb_push(skb, BTM_HEADER_LEN);
+
+ /* header type: byte[3]
+ * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor
+ * header length: byte[2][1][0]
+ */
+
+ skb->data[0] = (skb->len & 0x0000ff);
+ skb->data[1] = (skb->len & 0x00ff00) >> 8;
+ skb->data[2] = (skb->len & 0xff0000) >> 16;
+ skb->data[3] = bt_cb(skb)->pkt_type;
+
+ if (priv->hw_host_to_card)
+ ret = priv->hw_host_to_card(priv, skb->data, skb->len);
+
+ return ret;
+}
+
+static void btmrvl_init_adapter(struct btmrvl_private *priv)
+{
+ skb_queue_head_init(&priv->adapter->tx_queue);
+
+ priv->adapter->ps_state = PS_AWAKE;
+
+ init_waitqueue_head(&priv->adapter->cmd_wait_q);
+}
+
+static void btmrvl_free_adapter(struct btmrvl_private *priv)
+{
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ kfree(priv->adapter);
+
+ priv->adapter = NULL;
+}
+
+static int btmrvl_ioctl(struct hci_dev *hdev,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static void btmrvl_destruct(struct hci_dev *hdev)
+{
+}
+
+static int btmrvl_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct btmrvl_private *priv = NULL;
+
+ BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
+
+ if (!hdev || !hdev->driver_data) {
+ BT_ERR("Frame for unknown HCI device");
+ return -ENODEV;
+ }
+
+ priv = (struct btmrvl_private *) hdev->driver_data;
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
+ print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
+ skb->data, skb->len);
+ return -EBUSY;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ skb_queue_tail(&priv->adapter->tx_queue, skb);
+
+ wake_up_interruptible(&priv->main_thread.wait_q);
+
+ return 0;
+}
+
+static int btmrvl_flush(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ return 0;
+}
+
+static int btmrvl_close(struct hci_dev *hdev)
+{
+ struct btmrvl_private *priv = hdev->driver_data;
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ return 0;
+}
+
+static int btmrvl_open(struct hci_dev *hdev)
+{
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ return 0;
+}
+
+/*
+ * This function handles the event generated by firmware, rx data
+ * received from firmware, and tx data sent from kernel.
+ */
+static int btmrvl_service_main_thread(void *data)
+{
+ struct btmrvl_thread *thread = data;
+ struct btmrvl_private *priv = thread->priv;
+ struct btmrvl_adapter *adapter = priv->adapter;
+ wait_queue_t wait;
+ struct sk_buff *skb;
+ ulong flags;
+
+ init_waitqueue_entry(&wait, current);
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ add_wait_queue(&thread->wait_q, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (adapter->wakeup_tries ||
+ ((!adapter->int_count) &&
+ (!priv->btmrvl_dev.tx_dnld_rdy ||
+ skb_queue_empty(&adapter->tx_queue)))) {
+ BT_DBG("main_thread is sleeping...");
+ schedule();
+ }
+
+ set_current_state(TASK_RUNNING);
+
+ remove_wait_queue(&thread->wait_q, &wait);
+
+ BT_DBG("main_thread woke up");
+
+ if (kthread_should_stop()) {
+ BT_DBG("main_thread: break from main thread");
+ break;
+ }
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ if (adapter->int_count) {
+ adapter->int_count = 0;
+ } else if (adapter->ps_state == PS_SLEEP &&
+ !skb_queue_empty(&adapter->tx_queue)) {
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ adapter->wakeup_tries++;
+ priv->hw_wakeup_firmware(priv);
+ continue;
+ }
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ if (adapter->ps_state == PS_SLEEP)
+ continue;
+
+ if (!priv->btmrvl_dev.tx_dnld_rdy)
+ continue;
+
+ skb = skb_dequeue(&adapter->tx_queue);
+ if (skb) {
+ if (btmrvl_tx_pkt(priv, skb))
+ priv->btmrvl_dev.hcidev->stat.err_tx++;
+ else
+ priv->btmrvl_dev.hcidev->stat.byte_tx += skb->len;
+
+ kfree_skb(skb);
+ }
+ }
+
+ return 0;
+}
+
+struct btmrvl_private *btmrvl_add_card(void *card)
+{
+ struct hci_dev *hdev = NULL;
+ struct btmrvl_private *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ BT_ERR("Can not allocate priv");
+ goto err_priv;
+ }
+
+ priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);
+ if (!priv->adapter) {
+ BT_ERR("Allocate buffer for btmrvl_adapter failed!");
+ goto err_adapter;
+ }
+
+ btmrvl_init_adapter(priv);
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ BT_ERR("Can not allocate HCI device");
+ goto err_hdev;
+ }
+
+ BT_DBG("Starting kthread...");
+ priv->main_thread.priv = priv;
+ spin_lock_init(&priv->driver_lock);
+
+ init_waitqueue_head(&priv->main_thread.wait_q);
+ priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
+ &priv->main_thread, "btmrvl_main_service");
+
+ priv->btmrvl_dev.hcidev = hdev;
+ priv->btmrvl_dev.card = card;
+
+ hdev->driver_data = priv;
+
+ priv->btmrvl_dev.tx_dnld_rdy = true;
+
+ hdev->type = HCI_SDIO;
+ hdev->open = btmrvl_open;
+ hdev->close = btmrvl_close;
+ hdev->flush = btmrvl_flush;
+ hdev->send = btmrvl_send_frame;
+ hdev->destruct = btmrvl_destruct;
+ hdev->ioctl = btmrvl_ioctl;
+ hdev->owner = THIS_MODULE;
+
+ ret = hci_register_dev(hdev);
+ if (ret < 0) {
+ BT_ERR("Can not register HCI device");
+ goto err_hci_register_dev;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ btmrvl_debugfs_init(hdev);
+#endif
+
+ return priv;
+
+err_hci_register_dev:
+ /* Stop the thread servicing the interrupts */
+ kthread_stop(priv->main_thread.task);
+
+ hci_free_dev(hdev);
+
+err_hdev:
+ btmrvl_free_adapter(priv);
+
+err_adapter:
+ kfree(priv);
+
+err_priv:
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(btmrvl_add_card);
+
+int btmrvl_remove_card(struct btmrvl_private *priv)
+{
+ struct hci_dev *hdev;
+
+ hdev = priv->btmrvl_dev.hcidev;
+
+ wake_up_interruptible(&priv->adapter->cmd_wait_q);
+
+ kthread_stop(priv->main_thread.task);
+
+#ifdef CONFIG_DEBUG_FS
+ btmrvl_debugfs_remove(hdev);
+#endif
+
+ hci_unregister_dev(hdev);
+
+ hci_free_dev(hdev);
+
+ priv->btmrvl_dev.hcidev = NULL;
+
+ btmrvl_free_adapter(priv);
+
+ kfree(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btmrvl_remove_card);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell Bluetooth driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
new file mode 100644
index 000000000000..1cfa8b4ace50
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -0,0 +1,1002 @@
+/**
+ * Marvell BT-over-SDIO driver: SDIO interface related functions.
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/firmware.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmrvl_drv.h"
+#include "btmrvl_sdio.h"
+
+#define VERSION "1.0"
+
+/* The btmrvl_sdio_remove() callback function is called
+ * when user removes this module from kernel space or ejects
+ * the card from the slot. The driver handles these 2 cases
+ * differently.
+ * If the user is removing the module, a MODULE_SHUTDOWN_REQ
+ * command is sent to firmware and interrupt will be disabled.
+ * If the card is removed, there is no need to send command
+ * or disable interrupt.
+ *
+ * The variable 'user_rmmod' is used to distinguish these two
+ * scenarios. This flag is initialized as FALSE in case the card
+ * is removed, and will be set to TRUE for module removal when
+ * module_exit function is called.
+ */
+static u8 user_rmmod;
+
+static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
+ .helper = "sd8688_helper.bin",
+ .firmware = "sd8688.bin",
+};
+
+static const struct sdio_device_id btmrvl_sdio_ids[] = {
+ /* Marvell SD8688 Bluetooth device */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
+ .driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids);
+
+static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
+{
+ u8 reg;
+ int ret;
+
+ reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+ if (!ret)
+ card->rx_unit = reg;
+
+ return ret;
+}
+
+static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
+{
+ u8 fws0, fws1;
+ int ret;
+
+ *dat = 0;
+
+ fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+
+ if (!ret)
+ fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+
+ if (ret)
+ return -EIO;
+
+ *dat = (((u16) fws1) << 8) | fws0;
+
+ return 0;
+}
+
+static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
+{
+ u8 reg;
+ int ret;
+
+ reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+ if (!ret)
+ *dat = (u16) reg << card->rx_unit;
+
+ return ret;
+}
+
+static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
+ u8 mask)
+{
+ int ret;
+
+ sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+ if (ret) {
+ BT_ERR("Unable to enable the host interrupt!");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
+ u8 mask)
+{
+ u8 host_int_mask;
+ int ret;
+
+ host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+ if (ret)
+ return -EIO;
+
+ host_int_mask &= ~mask;
+
+ sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+ if (ret < 0) {
+ BT_ERR("Unable to disable the host interrupt!");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
+{
+ unsigned int tries;
+ u8 status;
+ int ret;
+
+ for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
+ status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
+ if (ret)
+ goto failed;
+ if ((status & bits) == bits)
+ return ret;
+
+ udelay(1);
+ }
+
+ ret = -ETIMEDOUT;
+
+failed:
+ BT_ERR("FAILED! ret=%d", ret);
+
+ return ret;
+}
+
+static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,
+ int pollnum)
+{
+ int ret = -ETIMEDOUT;
+ u16 firmwarestat;
+ unsigned int tries;
+
+ /* Wait for firmware to become ready */
+ for (tries = 0; tries < pollnum; tries++) {
+ if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0)
+ continue;
+
+ if (firmwarestat == FIRMWARE_READY) {
+ ret = 0;
+ break;
+ } else {
+ msleep(10);
+ }
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
+{
+ const struct firmware *fw_helper = NULL;
+ const u8 *helper = NULL;
+ int ret;
+ void *tmphlprbuf = NULL;
+ int tmphlprbufsz, hlprblknow, helperlen;
+ u8 *helperbuf;
+ u32 tx_len;
+
+ ret = request_firmware(&fw_helper, card->helper,
+ &card->func->dev);
+ if ((ret < 0) || !fw_helper) {
+ BT_ERR("request_firmware(helper) failed, error code = %d",
+ ret);
+ ret = -ENOENT;
+ goto done;
+ }
+
+ helper = fw_helper->data;
+ helperlen = fw_helper->size;
+
+ BT_DBG("Downloading helper image (%d bytes), block size %d bytes",
+ helperlen, SDIO_BLOCK_SIZE);
+
+ tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
+
+ tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+ if (!tmphlprbuf) {
+ BT_ERR("Unable to allocate buffer for helper."
+ " Terminating download");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(tmphlprbuf, 0, tmphlprbufsz);
+
+ helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
+
+ /* Perform helper data transfer */
+ tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE)
+ - SDIO_HEADER_LEN;
+ hlprblknow = 0;
+
+ do {
+ ret = btmrvl_sdio_poll_card_status(card,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret < 0) {
+ BT_ERR("Helper download poll status timeout @ %d",
+ hlprblknow);
+ goto done;
+ }
+
+ /* Check if there is more data? */
+ if (hlprblknow >= helperlen)
+ break;
+
+ if (helperlen - hlprblknow < tx_len)
+ tx_len = helperlen - hlprblknow;
+
+ /* Little-endian */
+ helperbuf[0] = ((tx_len & 0x000000ff) >> 0);
+ helperbuf[1] = ((tx_len & 0x0000ff00) >> 8);
+ helperbuf[2] = ((tx_len & 0x00ff0000) >> 16);
+ helperbuf[3] = ((tx_len & 0xff000000) >> 24);
+
+ memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow],
+ tx_len);
+
+ /* Now send the data */
+ ret = sdio_writesb(card->func, card->ioport, helperbuf,
+ FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE);
+ if (ret < 0) {
+ BT_ERR("IO error during helper download @ %d",
+ hlprblknow);
+ goto done;
+ }
+
+ hlprblknow += tx_len;
+ } while (true);
+
+ BT_DBG("Transferring helper image EOF block");
+
+ memset(helperbuf, 0x0, SDIO_BLOCK_SIZE);
+
+ ret = sdio_writesb(card->func, card->ioport, helperbuf,
+ SDIO_BLOCK_SIZE);
+ if (ret < 0) {
+ BT_ERR("IO error in writing helper image EOF block");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ kfree(tmphlprbuf);
+ if (fw_helper)
+ release_firmware(fw_helper);
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
+{
+ const struct firmware *fw_firmware = NULL;
+ const u8 *firmware = NULL;
+ int firmwarelen, tmpfwbufsz, ret;
+ unsigned int tries, offset;
+ u8 base0, base1;
+ void *tmpfwbuf = NULL;
+ u8 *fwbuf;
+ u16 len;
+ int txlen = 0, tx_blocks = 0, count = 0;
+
+ ret = request_firmware(&fw_firmware, card->firmware,
+ &card->func->dev);
+ if ((ret < 0) || !fw_firmware) {
+ BT_ERR("request_firmware(firmware) failed, error code = %d",
+ ret);
+ ret = -ENOENT;
+ goto done;
+ }
+
+ firmware = fw_firmware->data;
+ firmwarelen = fw_firmware->size;
+
+ BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
+
+ tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+ if (!tmpfwbuf) {
+ BT_ERR("Unable to allocate buffer for firmware."
+ " Terminating download");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ memset(tmpfwbuf, 0, tmpfwbufsz);
+
+ /* Ensure aligned firmware buffer */
+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
+
+ /* Perform firmware data transfer */
+ offset = 0;
+ do {
+ ret = btmrvl_sdio_poll_card_status(card,
+ CARD_IO_READY | DN_LD_CARD_RDY);
+ if (ret < 0) {
+ BT_ERR("FW download with helper poll status"
+ " timeout @ %d", offset);
+ goto done;
+ }
+
+ /* Check if there is more data ? */
+ if (offset >= firmwarelen)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ base0 = sdio_readb(card->func,
+ SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+ if (ret) {
+ BT_ERR("BASE0 register read failed:"
+ " base0 = 0x%04X(%d)."
+ " Terminating download",
+ base0, base0);
+ ret = -EIO;
+ goto done;
+ }
+ base1 = sdio_readb(card->func,
+ SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+ if (ret) {
+ BT_ERR("BASE1 register read failed:"
+ " base1 = 0x%04X(%d)."
+ " Terminating download",
+ base1, base1);
+ ret = -EIO;
+ goto done;
+ }
+
+ len = (((u16) base1) << 8) | base0;
+ if (len)
+ break;
+
+ udelay(10);
+ }
+
+ if (!len)
+ break;
+ else if (len > BTM_UPLD_SIZE) {
+ BT_ERR("FW download failure @%d, invalid length %d",
+ offset, len);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ count++;
+ if (count > MAX_WRITE_IOMEM_RETRY) {
+ BT_ERR("FW download failure @%d, "
+ "over max retry count", offset);
+ ret = -EIO;
+ goto done;
+ }
+ BT_ERR("FW CRC error indicated by the helper: "
+ "len = 0x%04X, txlen = %d", len, txlen);
+ len &= ~BIT(0);
+ /* Set txlen to 0 so as to resend from same offset */
+ txlen = 0;
+ } else {
+ count = 0;
+
+ /* Last block ? */
+ if (firmwarelen - offset < txlen)
+ txlen = firmwarelen - offset;
+
+ tx_blocks =
+ (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
+
+ memcpy(fwbuf, &firmware[offset], txlen);
+ }
+
+ ret = sdio_writesb(card->func, card->ioport, fwbuf,
+ tx_blocks * SDIO_BLOCK_SIZE);
+
+ if (ret < 0) {
+ BT_ERR("FW download, writesb(%d) failed @%d",
+ count, offset);
+ sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
+ &ret);
+ if (ret)
+ BT_ERR("writeb failed (CFG)");
+ }
+
+ offset += txlen;
+ } while (true);
+
+ BT_DBG("FW download over, size %d bytes", offset);
+
+ ret = 0;
+
+done:
+ kfree(tmpfwbuf);
+
+ if (fw_firmware)
+ release_firmware(fw_firmware);
+
+ return ret;
+}
+
+static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
+{
+ u16 buf_len = 0;
+ int ret, buf_block_len, blksz;
+ struct sk_buff *skb = NULL;
+ u32 type;
+ u8 *payload = NULL;
+ struct hci_dev *hdev = priv->btmrvl_dev.hcidev;
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Read the length of data to be transferred */
+ ret = btmrvl_sdio_read_rx_len(card, &buf_len);
+ if (ret < 0) {
+ BT_ERR("read rx_len failed");
+ ret = -EIO;
+ goto exit;
+ }
+
+ blksz = SDIO_BLOCK_SIZE;
+ buf_block_len = (buf_len + blksz - 1) / blksz;
+
+ if (buf_len <= SDIO_HEADER_LEN
+ || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+ BT_ERR("invalid packet length: %d", buf_len);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Allocate buffer */
+ skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN,
+ GFP_ATOMIC);
+ if (skb == NULL) {
+ BT_ERR("No free skb");
+ goto exit;
+ }
+
+ if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) {
+ skb_put(skb, (unsigned long) skb->data &
+ (BTSDIO_DMA_ALIGN - 1));
+ skb_pull(skb, (unsigned long) skb->data &
+ (BTSDIO_DMA_ALIGN - 1));
+ }
+
+ payload = skb->data;
+
+ ret = sdio_readsb(card->func, payload, card->ioport,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ BT_ERR("readsb failed: %d", ret);
+ ret = -EIO;
+ goto exit;
+ }
+
+ /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
+ * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor)
+ */
+
+ buf_len = payload[0];
+ buf_len |= (u16) payload[1] << 8;
+ type = payload[3];
+
+ switch (type) {
+ case HCI_ACLDATA_PKT:
+ case HCI_SCODATA_PKT:
+ case HCI_EVENT_PKT:
+ bt_cb(skb)->pkt_type = type;
+ skb->dev = (void *)hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, SDIO_HEADER_LEN);
+
+ if (type == HCI_EVENT_PKT)
+ btmrvl_check_evtpkt(priv, skb);
+
+ hci_recv_frame(skb);
+ hdev->stat.byte_rx += buf_len;
+ break;
+
+ case MRVL_VENDOR_PKT:
+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
+ skb->dev = (void *)hdev;
+ skb_put(skb, buf_len);
+ skb_pull(skb, SDIO_HEADER_LEN);
+
+ if (btmrvl_process_event(priv, skb))
+ hci_recv_frame(skb);
+
+ hdev->stat.byte_rx += buf_len;
+ break;
+
+ default:
+ BT_ERR("Unknow packet type:%d", type);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,
+ blksz * buf_block_len);
+
+ kfree_skb(skb);
+ skb = NULL;
+ break;
+ }
+
+exit:
+ if (ret) {
+ hdev->stat.err_rx++;
+ if (skb)
+ kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)
+{
+ int ret;
+ u8 sdio_ireg = 0;
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+
+ *ireg = 0;
+
+ sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_readb: read int status register failed");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (sdio_ireg != 0) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register and re-enable the
+ * interrupt.
+ */
+ BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
+
+ sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
+ UP_LD_HOST_INT_STATUS),
+ HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_writeb: clear int status register "
+ "failed");
+ ret = -EIO;
+ goto done;
+ }
+ }
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ if (priv->btmrvl_dev.tx_dnld_rdy)
+ BT_DBG("tx_done already received: "
+ " int_status=0x%x", sdio_ireg);
+ else
+ priv->btmrvl_dev.tx_dnld_rdy = true;
+ }
+
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+ btmrvl_sdio_card_to_host(priv);
+
+ *ireg = sdio_ireg;
+
+ ret = 0;
+
+done:
+ return ret;
+}
+
+static void btmrvl_sdio_interrupt(struct sdio_func *func)
+{
+ struct btmrvl_private *priv;
+ struct hci_dev *hcidev;
+ struct btmrvl_sdio_card *card;
+ u8 ireg = 0;
+
+ card = sdio_get_drvdata(func);
+ if (card && card->priv) {
+ priv = card->priv;
+ hcidev = priv->btmrvl_dev.hcidev;
+
+ if (btmrvl_sdio_get_int_status(priv, &ireg))
+ BT_ERR("reading HOST_INT_STATUS_REG failed");
+ else
+ BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
+
+ btmrvl_interrupt(priv);
+ }
+}
+
+static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
+{
+ struct sdio_func *func;
+ u8 reg;
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("Error: card or function is NULL!");
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ func = card->func;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret) {
+ BT_ERR("sdio_enable_func() failed: ret=%d", ret);
+ ret = -EIO;
+ goto release_host;
+ }
+
+ ret = sdio_claim_irq(func, btmrvl_sdio_interrupt);
+ if (ret) {
+ BT_ERR("sdio_claim_irq failed: ret=%d", ret);
+ ret = -EIO;
+ goto disable_func;
+ }
+
+ ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE);
+ if (ret) {
+ BT_ERR("cannot set SDIO block size");
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport = reg;
+
+ reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport |= (reg << 8);
+
+ reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+ if (ret < 0) {
+ ret = -EIO;
+ goto release_irq;
+ }
+
+ card->ioport |= (reg << 16);
+
+ BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
+
+ sdio_set_drvdata(func, card);
+
+ sdio_release_host(func);
+
+ return 0;
+
+release_irq:
+ sdio_release_irq(func);
+
+disable_func:
+ sdio_disable_func(func);
+
+release_host:
+ sdio_release_host(func);
+
+failed:
+ return ret;
+}
+
+static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card)
+{
+ if (card && card->func) {
+ sdio_claim_host(card->func);
+ sdio_release_irq(card->func);
+ sdio_disable_func(card->func);
+ sdio_release_host(card->func);
+ sdio_set_drvdata(card->func, NULL);
+ }
+
+ return 0;
+}
+
+static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card)
+{
+ int ret;
+
+ if (!card || !card->func)
+ return -EINVAL;
+
+ sdio_claim_host(card->func);
+
+ ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE);
+
+ btmrvl_sdio_get_rx_unit(card);
+
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card)
+{
+ int ret;
+
+ if (!card || !card->func)
+ return -EINVAL;
+
+ sdio_claim_host(card->func);
+
+ ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE);
+
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
+ u8 *payload, u16 nb)
+{
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+ int ret = 0;
+ int buf_block_len;
+ int blksz;
+ int i = 0;
+ u8 *buf = NULL;
+ void *tmpbuf = NULL;
+ int tmpbufsz;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+
+ buf = payload;
+ if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) {
+ tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN);
+ tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
+ memset(tmpbuf, 0, tmpbufsz);
+ buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN);
+ memcpy(buf, payload, nb);
+ }
+
+ blksz = SDIO_BLOCK_SIZE;
+ buf_block_len = (nb + blksz - 1) / blksz;
+
+ sdio_claim_host(card->func);
+
+ do {
+ /* Transfer data to card */
+ ret = sdio_writesb(card->func, card->ioport, buf,
+ buf_block_len * blksz);
+ if (ret < 0) {
+ i++;
+ BT_ERR("i=%d writesb failed: %d", i, ret);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ payload, nb);
+ ret = -EIO;
+ if (i > MAX_WRITE_IOMEM_RETRY)
+ goto exit;
+ }
+ } while (ret);
+
+ priv->btmrvl_dev.tx_dnld_rdy = false;
+
+exit:
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
+{
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+ sdio_claim_host(card->func);
+
+ if (!btmrvl_sdio_verify_fw_download(card, 1)) {
+ BT_DBG("Firmware already downloaded!");
+ goto done;
+ }
+
+ ret = btmrvl_sdio_download_helper(card);
+ if (ret) {
+ BT_ERR("Failed to download helper!");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (btmrvl_sdio_download_fw_w_helper(card)) {
+ BT_ERR("Failed to download firmware!");
+ ret = -EIO;
+ goto done;
+ }
+
+ if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
+ BT_ERR("FW failed to be active in time!");
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+done:
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
+{
+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
+ int ret = 0;
+
+ if (!card || !card->func) {
+ BT_ERR("card or function is NULL!");
+ return -EINVAL;
+ }
+
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
+
+ sdio_release_host(card->func);
+
+ BT_DBG("wake up firmware");
+
+ return ret;
+}
+
+static int btmrvl_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret = 0;
+ struct btmrvl_private *priv = NULL;
+ struct btmrvl_sdio_card *card = NULL;
+
+ BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
+ id->vendor, id->device, id->class, func->num);
+
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
+ if (!card) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ card->func = func;
+
+ if (id->driver_data) {
+ struct btmrvl_sdio_device *data = (void *) id->driver_data;
+ card->helper = data->helper;
+ card->firmware = data->firmware;
+ }
+
+ if (btmrvl_sdio_register_dev(card) < 0) {
+ BT_ERR("Failed to register BT device!");
+ ret = -ENODEV;
+ goto free_card;
+ }
+
+ /* Disable the interrupts on the card */
+ btmrvl_sdio_disable_host_int(card);
+
+ if (btmrvl_sdio_download_fw(card)) {
+ BT_ERR("Downloading firmware failed!");
+ ret = -ENODEV;
+ goto unreg_dev;
+ }
+
+ msleep(100);
+
+ btmrvl_sdio_enable_host_int(card);
+
+ priv = btmrvl_add_card(card);
+ if (!priv) {
+ BT_ERR("Initializing card failed!");
+ ret = -ENODEV;
+ goto disable_host_int;
+ }
+
+ card->priv = priv;
+
+ /* Initialize the interface specific function pointers */
+ priv->hw_host_to_card = btmrvl_sdio_host_to_card;
+ priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
+
+ btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+
+ return 0;
+
+disable_host_int:
+ btmrvl_sdio_disable_host_int(card);
+unreg_dev:
+ btmrvl_sdio_unregister_dev(card);
+free_card:
+ kfree(card);
+done:
+ return ret;
+}
+
+static void btmrvl_sdio_remove(struct sdio_func *func)
+{
+ struct btmrvl_sdio_card *card;
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ /* Send SHUTDOWN command & disable interrupt
+ * if user removes the module.
+ */
+ if (user_rmmod) {
+ btmrvl_send_module_cfg_cmd(card->priv,
+ MODULE_SHUTDOWN_REQ);
+ btmrvl_sdio_disable_host_int(card);
+ }
+ BT_DBG("unregester dev");
+ btmrvl_sdio_unregister_dev(card);
+ btmrvl_remove_card(card->priv);
+ kfree(card);
+ }
+ }
+}
+
+static struct sdio_driver bt_mrvl_sdio = {
+ .name = "btmrvl_sdio",
+ .id_table = btmrvl_sdio_ids,
+ .probe = btmrvl_sdio_probe,
+ .remove = btmrvl_sdio_remove,
+};
+
+static int btmrvl_sdio_init_module(void)
+{
+ if (sdio_register_driver(&bt_mrvl_sdio) != 0) {
+ BT_ERR("SDIO Driver Registration Failed");
+ return -ENODEV;
+ }
+
+ /* Clear the flag in case user removes the card. */
+ user_rmmod = 0;
+
+ return 0;
+}
+
+static void btmrvl_sdio_exit_module(void)
+{
+ /* Set the flag as user is removing this module. */
+ user_rmmod = 1;
+
+ sdio_unregister_driver(&bt_mrvl_sdio);
+}
+
+module_init(btmrvl_sdio_init_module);
+module_exit(btmrvl_sdio_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
new file mode 100644
index 000000000000..27329f107e5a
--- /dev/null
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -0,0 +1,108 @@
+/**
+ * Marvell BT-over-SDIO driver: SDIO interface related definitions
+ *
+ * Copyright (C) 2009, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ **/
+
+#define SDIO_HEADER_LEN 4
+
+/* SD block size can not bigger than 64 due to buf size limit in firmware */
+/* define SD block size for data Tx/Rx */
+#define SDIO_BLOCK_SIZE 64
+
+/* Number of blocks for firmware transfer */
+#define FIRMWARE_TRANSFER_NBLOCK 2
+
+/* This is for firmware specific length */
+#define FW_EXTRA_LEN 36
+
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+
+#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \
+ (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN)
+
+#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \
+ MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+ + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \
+ * SDIO_BLOCK_SIZE)
+
+/* The number of times to try when polling for status */
+#define MAX_POLL_TRIES 100
+
+/* Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/* Host Control Registers */
+#define IO_PORT_0_REG 0x00
+#define IO_PORT_1_REG 0x01
+#define IO_PORT_2_REG 0x02
+
+#define CONFIG_REG 0x03
+#define HOST_POWER_UP BIT(1)
+#define HOST_CMD53_FIN BIT(2)
+
+#define HOST_INT_MASK_REG 0x04
+#define HIM_DISABLE 0xff
+#define HIM_ENABLE (BIT(0) | BIT(1))
+
+#define HOST_INTSTATUS_REG 0x05
+#define UP_LD_HOST_INT_STATUS BIT(0)
+#define DN_LD_HOST_INT_STATUS BIT(1)
+
+/* Card Control Registers */
+#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
+#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
+
+#define CARD_STATUS_REG 0x20
+#define DN_LD_CARD_RDY BIT(0)
+#define CARD_IO_READY BIT(3)
+
+#define CARD_FW_STATUS0_REG 0x40
+#define CARD_FW_STATUS1_REG 0x41
+#define FIRMWARE_READY 0xfedc
+
+#define CARD_RX_LEN_REG 0x42
+#define CARD_RX_UNIT_REG 0x43
+
+
+struct btmrvl_sdio_card {
+ struct sdio_func *func;
+ u32 ioport;
+ const char *helper;
+ const char *firmware;
+ u8 rx_unit;
+ struct btmrvl_private *priv;
+};
+
+struct btmrvl_sdio_device {
+ const char *helper;
+ const char *firmware;
+};
+
+
+/* Platform specific DMA alignment */
+#define BTSDIO_DMA_ALIGN 8
+
+/* Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a) \
+ (((p) + ((a) - 1)) & ~((a) - 1))
+
+/* Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a) \
+ ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \
+ ~(((unsigned long)(a)) - 1))
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e70c57ee4221..124db8cd144c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -301,7 +301,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
struct urb *urb;
unsigned char *buf;
unsigned int pipe;
- int err, size;
+ int err, size = HCI_MAX_FRAME_SIZE;
BT_DBG("%s", hdev->name);
@@ -312,8 +312,6 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (!urb)
return -ENOMEM;
- size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
-
buf = kmalloc(size, mem_flags);
if (!buf) {
usb_free_urb(urb);
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 8f3d4c184914..7bead4c816ca 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -478,7 +478,6 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
{
acpi_handle handle, parent;
acpi_status status;
- struct acpi_buffer buffer;
struct acpi_device_info *info;
u64 lba_hpa, sba_hpa, length;
int match;
@@ -490,13 +489,11 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
/* Look for an enclosing IOC scope and find its CSR space */
handle = obj;
do {
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_SUCCESS(status)) {
/* TBD check _CID also */
- info = buffer.pointer;
- info->hardware_id.value[sizeof(info->hardware_id)-1] = '\0';
- match = (strcmp(info->hardware_id.value, "HWP0001") == 0);
+ info->hardware_id.string[sizeof(info->hardware_id.length)-1] = '\0';
+ match = (strcmp(info->hardware_id.string, "HWP0001") == 0);
kfree(info);
if (match) {
status = hp_acpi_csr_space(handle, &sba_hpa, &length);
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index f192c3b9ad41..b6a01bad2c5a 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -271,7 +271,7 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) {
/*
- * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
+ * We need to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1,
* 2.2 and 2.3, Darwin do so.
*/
if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7)
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 86105efb4eb6..0ecac7e532f6 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -1006,7 +1006,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
priv->dev->release = (void (*)(struct device *)) kfree;
rc = device_register(priv->dev);
if (rc) {
- kfree(priv->dev);
+ put_device(priv->dev);
goto out_error_dev;
}
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index cd0ba51f7c80..0d8c5788b8e4 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -44,8 +44,8 @@
* want to register another driver on the same PCI id.
*/
static const struct pci_device_id pci_tbl[] = {
- { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { PCI_VDEVICE(AMD, 0x7443), 0, },
+ { PCI_VDEVICE(AMD, 0x746b), 0, },
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index 64d513f68368..4c4d4e140f98 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -46,8 +46,7 @@
* want to register another driver on the same PCI id.
*/
static const struct pci_device_id pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, },
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index afa8813e737a..645237bda682 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -822,6 +822,7 @@ static const struct file_operations zero_fops = {
* - permits private mappings, "copies" are taken of the source of zeros
*/
static struct backing_dev_info zero_bdi = {
+ .name = "char/mem",
.capabilities = BDI_CAP_MAP_COPY,
};
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index ff47907ff1bf..973be2f44195 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1583,6 +1583,7 @@ static int n_tty_open(struct tty_struct *tty)
static inline int input_available_p(struct tty_struct *tty, int amt)
{
+ tty_flush_to_ldisc(tty);
if (tty->icanon) {
if (tty->canon_data)
return 1;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 8c7444857a4b..d8a9255e1a3f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -240,6 +240,7 @@
#include <linux/spinlock.h>
#include <linux/percpu.h>
#include <linux/cryptohash.h>
+#include <linux/fips.h>
#ifdef CONFIG_GENERIC_HARDIRQS
# include <linux/irq.h>
@@ -413,6 +414,7 @@ struct entropy_store {
unsigned add_ptr;
int entropy_count;
int input_rotate;
+ __u8 *last_data;
};
static __u32 input_pool_data[INPUT_POOL_WORDS];
@@ -852,12 +854,21 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
{
ssize_t ret = 0, i;
__u8 tmp[EXTRACT_SIZE];
+ unsigned long flags;
xfer_secondary_pool(r, nbytes);
nbytes = account(r, nbytes, min, reserved);
while (nbytes) {
extract_buf(r, tmp);
+
+ if (r->last_data) {
+ spin_lock_irqsave(&r->lock, flags);
+ if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
+ panic("Hardware RNG duplicated output!\n");
+ memcpy(r->last_data, tmp, EXTRACT_SIZE);
+ spin_unlock_irqrestore(&r->lock, flags);
+ }
i = min_t(int, nbytes, EXTRACT_SIZE);
memcpy(buf, tmp, i);
nbytes -= i;
@@ -940,6 +951,9 @@ static void init_std_data(struct entropy_store *r)
now = ktime_get_real();
mix_pool_bytes(r, &now, sizeof(now));
mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
+ /* Enable continuous test in fips mode */
+ if (fips_enabled)
+ r->last_data = kmalloc(EXTRACT_SIZE, GFP_KERNEL);
}
static int rand_initialize(void)
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 0db35857e4d8..5d7a02f63e1c 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,7 +35,6 @@
#include <linux/spinlock.h>
#include <linux/vt_kern.h>
#include <linux/workqueue.h>
-#include <linux/kexec.h>
#include <linux/hrtimer.h>
#include <linux/oom.h>
@@ -124,9 +123,12 @@ static struct sysrq_key_op sysrq_unraw_op = {
static void sysrq_handle_crash(int key, struct tty_struct *tty)
{
char *killer = NULL;
+
+ panic_on_oops = 1; /* force panic */
+ wmb();
*killer = 1;
}
-static struct sysrq_key_op sysrq_crashdump_op = {
+static struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash,
.help_msg = "Crash",
.action_msg = "Trigger a crash",
@@ -401,7 +403,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
*/
NULL, /* a */
&sysrq_reboot_op, /* b */
- &sysrq_crashdump_op, /* c & ibm_emac driver debug */
+ &sysrq_crash_op, /* c & ibm_emac driver debug */
&sysrq_showlocks_op, /* d */
&sysrq_term_op, /* e */
&sysrq_moom_op, /* f */
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
index 810ee25d66a4..3108991c5c8b 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/char/tty_buffer.c
@@ -462,6 +462,19 @@ static void flush_to_ldisc(struct work_struct *work)
}
/**
+ * tty_flush_to_ldisc
+ * @tty: tty to push
+ *
+ * Push the terminal flip buffers to the line discipline.
+ *
+ * Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+ flush_to_ldisc(&tty->buf.work.work);
+}
+
+/**
* tty_flip_buffer_push - terminal
* @tty: tty to push
*
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/char/vr41xx_giu.c
+++ /dev/null
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index c5afc98e2675..85e5dc0431fe 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -202,9 +202,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(void *data)
+static void cn_proc_mcast_ctl(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
enum proc_cn_mcast_op *mc_op = NULL;
int err = 0;
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 408c2af25d50..4a1dfe1f4ba9 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -87,7 +87,9 @@ void cn_queue_wrapper(struct work_struct *work)
kfree(d->free);
}
-static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *))
+static struct cn_callback_entry *
+cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *))
{
struct cn_callback_entry *cbq;
@@ -120,7 +122,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
return ((i1->idx == i2->idx) && (i1->val == i2->val));
}
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *))
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *))
{
struct cn_callback_entry *cbq, *__cbq;
int found = 0;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 08b2500f21ec..74f52af79563 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -269,7 +269,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event)
*
* May sleep.
*/
-int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+int cn_add_callback(struct cb_id *id, char *name,
+ void (*callback)(struct cn_msg *))
{
int err;
struct cn_dev *dev = &cdev;
@@ -351,9 +352,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
*
* Used for notification of a request's processing.
*/
-static void cn_callback(void *data)
+static void cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct cn_ctl_msg *ctl;
struct cn_ctl_entry *ent;
u32 size;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b90eda8b3440..8a0aa072e380 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -757,91 +757,14 @@ static struct kobj_type ktype_cpufreq = {
};
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct sys_device *sys_dev)
+int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
{
- unsigned int cpu = sys_dev->id;
int ret = 0;
- struct cpufreq_policy new_policy;
- struct cpufreq_policy *policy;
- struct freq_attr **drv_attr;
- struct sys_device *cpu_sys_dev;
+#ifdef CONFIG_SMP
unsigned long flags;
unsigned int j;
- if (cpu_is_offline(cpu))
- return 0;
-
- cpufreq_debug_disable_ratelimit();
- dprintk("adding CPU %u\n", cpu);
-
-#ifdef CONFIG_SMP
- /* check whether a different CPU already registered this
- * CPU because it is in the same boat. */
- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
- cpufreq_debug_enable_ratelimit();
- return 0;
- }
-#endif
-
- if (!try_module_get(cpufreq_driver->owner)) {
- ret = -EINVAL;
- goto module_out;
- }
-
- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
- if (!policy) {
- ret = -ENOMEM;
- goto nomem_out;
- }
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_policy;
- }
- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_cpumask;
- }
-
- policy->cpu = cpu;
- cpumask_copy(policy->cpus, cpumask_of(cpu));
-
- /* Initially set CPU itself as the policy_cpu */
- per_cpu(policy_cpu, cpu) = cpu;
- ret = (lock_policy_rwsem_write(cpu) < 0);
- WARN_ON(ret);
-
- init_completion(&policy->kobj_unregister);
- INIT_WORK(&policy->update, handle_update);
-
- /* Set governor before ->init, so that driver could check it */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- /* call driver. From then on the cpufreq must be able
- * to accept all calls to ->verify and ->setpolicy for this CPU
- */
- ret = cpufreq_driver->init(policy);
- if (ret) {
- dprintk("initialization failed\n");
- goto err_unlock_policy;
- }
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
-
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_START, policy);
-
-#ifdef CONFIG_SMP
-
#ifdef CONFIG_HOTPLUG_CPU
if (per_cpu(cpufreq_cpu_governor, cpu)) {
policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
@@ -870,9 +793,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
/* Should not go through policy unlock path */
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
- ret = -EBUSY;
cpufreq_cpu_put(managed_policy);
- goto err_free_cpumask;
+ return -EBUSY;
}
spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -891,17 +813,58 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
* Call driver->exit() because only the cpu parent of
* the kobj needed to call init().
*/
- goto out_driver_exit; /* call driver->exit() */
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+ return ret;
}
}
#endif
- memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ return ret;
+}
+
+
+/* symlink affected CPUs */
+int cpufreq_add_dev_symlink(unsigned int cpu, struct cpufreq_policy *policy)
+{
+ unsigned int j;
+ int ret = 0;
+
+ for_each_cpu(j, policy->cpus) {
+ struct cpufreq_policy *managed_policy;
+ struct sys_device *cpu_sys_dev;
+
+ if (j == cpu)
+ continue;
+ if (!cpu_online(j))
+ continue;
+
+ dprintk("CPU %u already managed, adding link\n", j);
+ managed_policy = cpufreq_cpu_get(cpu);
+ cpu_sys_dev = get_cpu_sysdev(j);
+ ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
+ "cpufreq");
+ if (ret) {
+ cpufreq_cpu_put(managed_policy);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+int cpufreq_add_dev_interface(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
+{
+ struct cpufreq_policy new_policy;
+ struct freq_attr **drv_attr;
+ unsigned long flags;
+ int ret = 0;
+ unsigned int j;
/* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
- "cpufreq");
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ &sys_dev->kobj, "cpufreq");
if (ret)
- goto out_driver_exit;
+ return ret;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
@@ -929,28 +892,13 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- /* symlink affected CPUs */
- for_each_cpu(j, policy->cpus) {
- struct cpufreq_policy *managed_policy;
-
- if (j == cpu)
- continue;
- if (!cpu_online(j))
- continue;
-
- dprintk("CPU %u already managed, adding link\n", j);
- managed_policy = cpufreq_cpu_get(cpu);
- cpu_sys_dev = get_cpu_sysdev(j);
- ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
- "cpufreq");
- if (ret) {
- cpufreq_cpu_put(managed_policy);
- goto err_out_unregister;
- }
- }
+ ret = cpufreq_add_dev_symlink(cpu, policy);
+ if (ret)
+ goto err_out_kobj_put;
- policy->governor = NULL; /* to assure that the starting sequence is
- * run in cpufreq_set_policy */
+ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ /* assure that the starting sequence is run in __cpufreq_set_policy */
+ policy->governor = NULL;
/* set default policy */
ret = __cpufreq_set_policy(policy, &new_policy);
@@ -959,8 +907,102 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
if (ret) {
dprintk("setting policy failed\n");
- goto err_out_unregister;
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+ }
+ return ret;
+
+err_out_kobj_put:
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ return ret;
+}
+
+
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct sys_device *sys_dev)
+{
+ unsigned int cpu = sys_dev->id;
+ int ret = 0;
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+ unsigned int j;
+
+ if (cpu_is_offline(cpu))
+ return 0;
+
+ cpufreq_debug_disable_ratelimit();
+ dprintk("adding CPU %u\n", cpu);
+
+#ifdef CONFIG_SMP
+ /* check whether a different CPU already registered this
+ * CPU because it is in the same boat. */
+ policy = cpufreq_cpu_get(cpu);
+ if (unlikely(policy)) {
+ cpufreq_cpu_put(policy);
+ cpufreq_debug_enable_ratelimit();
+ return 0;
}
+#endif
+
+ if (!try_module_get(cpufreq_driver->owner)) {
+ ret = -EINVAL;
+ goto module_out;
+ }
+
+ ret = -ENOMEM;
+ policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+ if (!policy)
+ goto nomem_out;
+
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+ goto err_free_policy;
+
+ if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+ goto err_free_cpumask;
+
+ policy->cpu = cpu;
+ cpumask_copy(policy->cpus, cpumask_of(cpu));
+
+ /* Initially set CPU itself as the policy_cpu */
+ per_cpu(policy_cpu, cpu) = cpu;
+ ret = (lock_policy_rwsem_write(cpu) < 0);
+ WARN_ON(ret);
+
+ init_completion(&policy->kobj_unregister);
+ INIT_WORK(&policy->update, handle_update);
+
+ /* Set governor before ->init, so that driver could check it */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ /* call driver. From then on the cpufreq must be able
+ * to accept all calls to ->verify and ->setpolicy for this CPU
+ */
+ ret = cpufreq_driver->init(policy);
+ if (ret) {
+ dprintk("initialization failed\n");
+ goto err_unlock_policy;
+ }
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
+
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_START, policy);
+
+ ret = cpufreq_add_dev_policy(cpu, policy, sys_dev);
+ if (ret)
+ goto err_unlock_policy;
+
+ ret = cpufreq_add_dev_interface(cpu, policy, sys_dev);
+ if (ret)
+ goto err_out_unregister;
unlock_policy_rwsem_write(cpu);
@@ -978,14 +1020,9 @@ err_out_unregister:
per_cpu(cpufreq_cpu_data, j) = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-err_out_kobj_put:
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
-out_driver_exit:
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
err_unlock_policy:
unlock_policy_rwsem_write(cpu);
err_free_cpumask:
@@ -1244,13 +1281,22 @@ EXPORT_SYMBOL(cpufreq_get);
static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
{
- int cpu = sysdev->id;
int ret = 0;
+
+#ifdef __powerpc__
+ int cpu = sysdev->id;
unsigned int cur_freq = 0;
struct cpufreq_policy *cpu_policy;
dprintk("suspending cpu %u\n", cpu);
+ /*
+ * This whole bogosity is here because Powerbooks are made of fail.
+ * No sane platform should need any of the code below to be run.
+ * (it's entirely the wrong thing to do, as driver->get may
+ * reenable interrupts on some architectures).
+ */
+
if (!cpu_online(cpu))
return 0;
@@ -1309,6 +1355,7 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
out:
cpufreq_cpu_put(cpu_policy);
+#endif /* __powerpc__ */
return ret;
}
@@ -1322,12 +1369,18 @@ out:
*/
static int cpufreq_resume(struct sys_device *sysdev)
{
- int cpu = sysdev->id;
int ret = 0;
+
+#ifdef __powerpc__
+ int cpu = sysdev->id;
struct cpufreq_policy *cpu_policy;
dprintk("resuming cpu %u\n", cpu);
+ /* As with the ->suspend method, all the code below is
+ * only necessary because Powerbooks suck.
+ * See commit 42d4dc3f4e1e for jokes. */
+
if (!cpu_online(cpu))
return 0;
@@ -1391,6 +1444,7 @@ out:
schedule_work(&cpu_policy->update);
fail:
cpufreq_cpu_put(cpu_policy);
+#endif /* __powerpc__ */
return ret;
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 57490502b21c..bc33ddc9c97c 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -63,6 +63,7 @@ struct cpu_dbs_info_s {
unsigned int down_skip;
unsigned int requested_freq;
int cpu;
+ unsigned int enable:1;
/*
* percpu mutex that serializes governor limit change with
* do_dbs_timer invocation. We do not want do_dbs_timer to run
@@ -70,7 +71,7 @@ struct cpu_dbs_info_s {
*/
struct mutex timer_mutex;
};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
@@ -136,11 +137,14 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
- struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
+ struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info,
freq->cpu);
struct cpufreq_policy *policy;
+ if (!this_dbs_info->enable)
+ return 0;
+
policy = this_dbs_info->cur_policy;
/*
@@ -293,7 +297,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(cpu_dbs_info, j);
+ dbs_info = &per_cpu(cs_cpu_dbs_info, j);
dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->prev_cpu_wall);
if (dbs_tuners_ins.ignore_nice)
@@ -383,7 +387,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
cputime64_t cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
@@ -497,6 +501,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
delay -= jiffies % delay;
+ dbs_info->enable = 1;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
delay);
@@ -504,6 +509,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
+ dbs_info->enable = 0;
cancel_delayed_work_sync(&dbs_info->work);
}
@@ -515,7 +521,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int j;
int rc;
- this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
switch (event) {
case CPUFREQ_GOV_START:
@@ -532,7 +538,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index d6ba14276bb1..d7a528c80de8 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -78,7 +78,7 @@ struct cpu_dbs_info_s {
*/
struct mutex timer_mutex;
};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
@@ -149,7 +149,8 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
unsigned int freq_hi, freq_lo;
unsigned int index = 0;
unsigned int jiffies_total, jiffies_hi, jiffies_lo;
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
+ policy->cpu);
if (!dbs_info->freq_table) {
dbs_info->freq_lo = 0;
@@ -192,7 +193,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
static void ondemand_powersave_bias_init_cpu(int cpu)
{
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
dbs_info->freq_lo = 0;
}
@@ -297,7 +298,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(cpu_dbs_info, j);
+ dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->prev_cpu_wall);
if (dbs_tuners_ins.ignore_nice)
@@ -388,7 +389,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
unsigned int load, load_freq;
int freq_avg;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
@@ -535,7 +536,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int j;
int rc;
- this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
switch (event) {
case CPUFREQ_GOV_START:
@@ -553,7 +554,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_enable++;
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 5b27692372bf..1bb4b7fe4585 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -13,7 +13,6 @@ if CRYPTO_HW
config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
depends on X86 && !UML
- select CRYPTO_ALGAPI
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -39,6 +38,7 @@ config CRYPTO_DEV_PADLOCK_AES
config CRYPTO_DEV_PADLOCK_SHA
tristate "PadLock driver for SHA1 and SHA256 algorithms"
depends on CRYPTO_DEV_PADLOCK
+ select CRYPTO_HASH
select CRYPTO_SHA1
select CRYPTO_SHA256
help
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
index 61b6e1bec8c6..a33243c17b00 100644
--- a/drivers/crypto/amcc/crypto4xx_alg.c
+++ b/drivers/crypto/amcc/crypto4xx_alg.c
@@ -208,7 +208,8 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
}
}
- tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct crypto4xx_ctx));
sa = (struct dynamic_sa_ctl *) ctx->sa_in;
set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 4c0dfb2b872e..46e899ac924e 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -31,8 +31,6 @@
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
#include <asm/cacheflush.h>
-#include <crypto/internal/hash.h>
-#include <crypto/algapi.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
#include "crypto4xx_reg_def.h"
@@ -998,10 +996,15 @@ static int crypto4xx_alg_init(struct crypto_tfm *tfm)
ctx->sa_out_dma_addr = 0;
ctx->sa_len = 0;
- if (alg->cra_type == &crypto_ablkcipher_type)
+ switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ default:
tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx);
- else if (alg->cra_type == &crypto_ahash_type)
- tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx);
+ break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct crypto4xx_ctx));
+ break;
+ }
return 0;
}
@@ -1015,7 +1018,8 @@ static void crypto4xx_alg_exit(struct crypto_tfm *tfm)
}
int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
- struct crypto_alg *crypto_alg, int array_size)
+ struct crypto4xx_alg_common *crypto_alg,
+ int array_size)
{
struct crypto4xx_alg *alg;
int i;
@@ -1027,13 +1031,18 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
return -ENOMEM;
alg->alg = crypto_alg[i];
- INIT_LIST_HEAD(&alg->alg.cra_list);
- if (alg->alg.cra_init == NULL)
- alg->alg.cra_init = crypto4xx_alg_init;
- if (alg->alg.cra_exit == NULL)
- alg->alg.cra_exit = crypto4xx_alg_exit;
alg->dev = sec_dev;
- rc = crypto_register_alg(&alg->alg);
+
+ switch (alg->alg.type) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ rc = crypto_register_ahash(&alg->alg.u.hash);
+ break;
+
+ default:
+ rc = crypto_register_alg(&alg->alg.u.cipher);
+ break;
+ }
+
if (rc) {
list_del(&alg->entry);
kfree(alg);
@@ -1051,7 +1060,14 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
list_del(&alg->entry);
- crypto_unregister_alg(&alg->alg);
+ switch (alg->alg.type) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&alg->alg.u.hash);
+ break;
+
+ default:
+ crypto_unregister_alg(&alg->alg.u.cipher);
+ }
kfree(alg);
}
}
@@ -1104,17 +1120,18 @@ static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data)
/**
* Supported Crypto Algorithms
*/
-struct crypto_alg crypto4xx_alg[] = {
+struct crypto4xx_alg_common crypto4xx_alg[] = {
/* Crypto AES modes */
- {
+ { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-ppc4xx",
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
- .cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
+ .cra_init = crypto4xx_alg_init,
+ .cra_exit = crypto4xx_alg_exit,
.cra_module = THIS_MODULE,
.cra_u = {
.ablkcipher = {
@@ -1126,29 +1143,7 @@ struct crypto_alg crypto4xx_alg[] = {
.decrypt = crypto4xx_decrypt,
}
}
- },
- /* Hash SHA1 */
- {
- .cra_name = "sha1",
- .cra_driver_name = "sha1-ppc4xx",
- .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SHA1_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypto4xx_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ahash_type,
- .cra_init = crypto4xx_sha1_alg_init,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .ahash = {
- .digestsize = SHA1_DIGEST_SIZE,
- .init = crypto4xx_hash_init,
- .update = crypto4xx_hash_update,
- .final = crypto4xx_hash_final,
- .digest = crypto4xx_hash_digest,
- }
- }
- },
+ }},
};
/**
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index 1ef103449364..da9cbe3b9fc3 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -22,6 +22,8 @@
#ifndef __CRYPTO4XX_CORE_H__
#define __CRYPTO4XX_CORE_H__
+#include <crypto/internal/hash.h>
+
#define PPC460SX_SDR0_SRST 0x201
#define PPC405EX_SDR0_SRST 0x200
#define PPC460EX_SDR0_SRST 0x201
@@ -138,14 +140,31 @@ struct crypto4xx_req_ctx {
u16 sa_len;
};
+struct crypto4xx_alg_common {
+ u32 type;
+ union {
+ struct crypto_alg cipher;
+ struct ahash_alg hash;
+ } u;
+};
+
struct crypto4xx_alg {
struct list_head entry;
- struct crypto_alg alg;
+ struct crypto4xx_alg_common alg;
struct crypto4xx_device *dev;
};
-#define crypto_alg_to_crypto4xx_alg(x) \
- container_of(x, struct crypto4xx_alg, alg)
+static inline struct crypto4xx_alg *crypto_alg_to_crypto4xx_alg(
+ struct crypto_alg *x)
+{
+ switch (x->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ case CRYPTO_ALG_TYPE_AHASH:
+ return container_of(__crypto_ahash_alg(x),
+ struct crypto4xx_alg, alg.u.hash);
+ }
+
+ return container_of(x, struct crypto4xx_alg, alg.u.cipher);
+}
extern int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size);
extern void crypto4xx_free_sa(struct crypto4xx_ctx *ctx);
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index a2c8e8514b63..76cb6b345e7b 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -12,81 +12,43 @@
*
*/
-#include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
#include <crypto/sha.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/cryptohash.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/scatterlist.h>
#include <asm/i387.h>
#include "padlock.h"
-#define SHA1_DEFAULT_FALLBACK "sha1-generic"
-#define SHA256_DEFAULT_FALLBACK "sha256-generic"
+struct padlock_sha_desc {
+ struct shash_desc fallback;
+};
struct padlock_sha_ctx {
- char *data;
- size_t used;
- int bypass;
- void (*f_sha_padlock)(const char *in, char *out, int count);
- struct hash_desc fallback;
+ struct crypto_shash *fallback;
};
-static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm)
-{
- return crypto_tfm_ctx(tfm);
-}
-
-/* We'll need aligned address on the stack */
-#define NEAREST_ALIGNED(ptr) \
- ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))
-
-static struct crypto_alg sha1_alg, sha256_alg;
-
-static void padlock_sha_bypass(struct crypto_tfm *tfm)
+static int padlock_sha_init(struct shash_desc *desc)
{
- if (ctx(tfm)->bypass)
- return;
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
+ struct padlock_sha_ctx *ctx = crypto_shash_ctx(desc->tfm);
- crypto_hash_init(&ctx(tfm)->fallback);
- if (ctx(tfm)->data && ctx(tfm)->used) {
- struct scatterlist sg;
-
- sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used);
- crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
- }
-
- ctx(tfm)->used = 0;
- ctx(tfm)->bypass = 1;
-}
-
-static void padlock_sha_init(struct crypto_tfm *tfm)
-{
- ctx(tfm)->used = 0;
- ctx(tfm)->bypass = 0;
+ dctx->fallback.tfm = ctx->fallback;
+ dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ return crypto_shash_init(&dctx->fallback);
}
-static void padlock_sha_update(struct crypto_tfm *tfm,
- const uint8_t *data, unsigned int length)
+static int padlock_sha_update(struct shash_desc *desc,
+ const u8 *data, unsigned int length)
{
- /* Our buffer is always one page. */
- if (unlikely(!ctx(tfm)->bypass &&
- (ctx(tfm)->used + length > PAGE_SIZE)))
- padlock_sha_bypass(tfm);
-
- if (unlikely(ctx(tfm)->bypass)) {
- struct scatterlist sg;
- sg_init_one(&sg, (uint8_t *)data, length);
- crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
- return;
- }
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
- memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length);
- ctx(tfm)->used += length;
+ dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ return crypto_shash_update(&dctx->fallback, data, length);
}
static inline void padlock_output_block(uint32_t *src,
@@ -96,165 +58,206 @@ static inline void padlock_output_block(uint32_t *src,
*dst++ = swab32(*src++);
}
-static void padlock_do_sha1(const char *in, char *out, int count)
+static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in,
+ unsigned int count, u8 *out)
{
/* 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 buf[128+16];
- char *result = NEAREST_ALIGNED(buf);
+ char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
+ struct sha1_state state;
+ unsigned int space;
+ unsigned int leftover;
int ts_state;
+ int err;
+
+ dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = crypto_shash_export(&dctx->fallback, &state);
+ if (err)
+ goto out;
+
+ if (state.count + count > ULONG_MAX)
+ return crypto_shash_finup(&dctx->fallback, in, count, out);
+
+ leftover = ((state.count - 1) & (SHA1_BLOCK_SIZE - 1)) + 1;
+ space = SHA1_BLOCK_SIZE - leftover;
+ if (space) {
+ if (count > space) {
+ err = crypto_shash_update(&dctx->fallback, in, space) ?:
+ crypto_shash_export(&dctx->fallback, &state);
+ if (err)
+ goto out;
+ count -= space;
+ in += space;
+ } else {
+ memcpy(state.buffer + leftover, in, count);
+ in = state.buffer;
+ count += leftover;
+ state.count &= ~(SHA1_BLOCK_SIZE - 1);
+ }
+ }
+
+ memcpy(result, &state.state, SHA1_DIGEST_SIZE);
- ((uint32_t *)result)[0] = SHA1_H0;
- ((uint32_t *)result)[1] = SHA1_H1;
- ((uint32_t *)result)[2] = SHA1_H2;
- ((uint32_t *)result)[3] = SHA1_H3;
- ((uint32_t *)result)[4] = SHA1_H4;
-
/* prevent taking the spurious DNA fault with padlock. */
ts_state = irq_ts_save();
asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
- : "+S"(in), "+D"(result)
- : "c"(count), "a"(0));
+ : \
+ : "c"((unsigned long)state.count + count), \
+ "a"((unsigned long)state.count), \
+ "S"(in), "D"(result));
irq_ts_restore(ts_state);
padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);
+
+out:
+ return err;
}
-static void padlock_do_sha256(const char *in, char *out, int count)
+static int padlock_sha1_final(struct shash_desc *desc, u8 *out)
+{
+ u8 buf[4];
+
+ return padlock_sha1_finup(desc, buf, 0, out);
+}
+
+static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in,
+ unsigned int count, u8 *out)
{
/* 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 buf[128+16];
- char *result = NEAREST_ALIGNED(buf);
+ char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
+ struct sha256_state state;
+ unsigned int space;
+ unsigned int leftover;
int ts_state;
+ int err;
+
+ dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = crypto_shash_export(&dctx->fallback, &state);
+ if (err)
+ goto out;
+
+ if (state.count + count > ULONG_MAX)
+ return crypto_shash_finup(&dctx->fallback, in, count, out);
+
+ leftover = ((state.count - 1) & (SHA256_BLOCK_SIZE - 1)) + 1;
+ space = SHA256_BLOCK_SIZE - leftover;
+ if (space) {
+ if (count > space) {
+ err = crypto_shash_update(&dctx->fallback, in, space) ?:
+ crypto_shash_export(&dctx->fallback, &state);
+ if (err)
+ goto out;
+ count -= space;
+ in += space;
+ } else {
+ memcpy(state.buf + leftover, in, count);
+ in = state.buf;
+ count += leftover;
+ state.count &= ~(SHA1_BLOCK_SIZE - 1);
+ }
+ }
- ((uint32_t *)result)[0] = SHA256_H0;
- ((uint32_t *)result)[1] = SHA256_H1;
- ((uint32_t *)result)[2] = SHA256_H2;
- ((uint32_t *)result)[3] = SHA256_H3;
- ((uint32_t *)result)[4] = SHA256_H4;
- ((uint32_t *)result)[5] = SHA256_H5;
- ((uint32_t *)result)[6] = SHA256_H6;
- ((uint32_t *)result)[7] = SHA256_H7;
+ memcpy(result, &state.state, SHA256_DIGEST_SIZE);
/* prevent taking the spurious DNA fault with padlock. */
ts_state = irq_ts_save();
asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
- : "+S"(in), "+D"(result)
- : "c"(count), "a"(0));
+ : \
+ : "c"((unsigned long)state.count + count), \
+ "a"((unsigned long)state.count), \
+ "S"(in), "D"(result));
irq_ts_restore(ts_state);
padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);
+
+out:
+ return err;
}
-static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out)
+static int padlock_sha256_final(struct shash_desc *desc, u8 *out)
{
- if (unlikely(ctx(tfm)->bypass)) {
- crypto_hash_final(&ctx(tfm)->fallback, out);
- ctx(tfm)->bypass = 0;
- return;
- }
+ u8 buf[4];
- /* Pass the input buffer to PadLock microcode... */
- ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used);
-
- ctx(tfm)->used = 0;
+ return padlock_sha256_finup(desc, buf, 0, out);
}
static int padlock_cra_init(struct crypto_tfm *tfm)
{
+ struct crypto_shash *hash = __crypto_shash_cast(tfm);
const char *fallback_driver_name = tfm->__crt_alg->cra_name;
- struct crypto_hash *fallback_tfm;
-
- /* For now we'll allocate one page. This
- * could eventually be configurable one day. */
- ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL);
- if (!ctx(tfm)->data)
- return -ENOMEM;
+ struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_shash *fallback_tfm;
+ int err = -ENOMEM;
/* Allocate a fallback and abort if it failed. */
- fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK);
+ fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback_tfm)) {
printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n",
fallback_driver_name);
- free_page((unsigned long)(ctx(tfm)->data));
- return PTR_ERR(fallback_tfm);
+ err = PTR_ERR(fallback_tfm);
+ goto out;
}
- ctx(tfm)->fallback.tfm = fallback_tfm;
+ ctx->fallback = fallback_tfm;
+ hash->descsize += crypto_shash_descsize(fallback_tfm);
return 0;
-}
-
-static int padlock_sha1_cra_init(struct crypto_tfm *tfm)
-{
- ctx(tfm)->f_sha_padlock = padlock_do_sha1;
- return padlock_cra_init(tfm);
-}
-
-static int padlock_sha256_cra_init(struct crypto_tfm *tfm)
-{
- ctx(tfm)->f_sha_padlock = padlock_do_sha256;
-
- return padlock_cra_init(tfm);
+out:
+ return err;
}
static void padlock_cra_exit(struct crypto_tfm *tfm)
{
- if (ctx(tfm)->data) {
- free_page((unsigned long)(ctx(tfm)->data));
- ctx(tfm)->data = NULL;
- }
+ struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_hash(ctx(tfm)->fallback.tfm);
- ctx(tfm)->fallback.tfm = NULL;
+ crypto_free_shash(ctx->fallback);
}
-static struct crypto_alg sha1_alg = {
- .cra_name = "sha1",
- .cra_driver_name = "sha1-padlock",
- .cra_priority = PADLOCK_CRA_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA1_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct padlock_sha_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
- .cra_init = padlock_sha1_cra_init,
- .cra_exit = padlock_cra_exit,
- .cra_u = {
- .digest = {
- .dia_digestsize = SHA1_DIGEST_SIZE,
- .dia_init = padlock_sha_init,
- .dia_update = padlock_sha_update,
- .dia_final = padlock_sha_final,
- }
+static struct shash_alg sha1_alg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = padlock_sha_init,
+ .update = padlock_sha_update,
+ .finup = padlock_sha1_finup,
+ .final = padlock_sha1_final,
+ .descsize = sizeof(struct padlock_sha_desc),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = padlock_cra_init,
+ .cra_exit = padlock_cra_exit,
}
};
-static struct crypto_alg sha256_alg = {
- .cra_name = "sha256",
- .cra_driver_name = "sha256-padlock",
- .cra_priority = PADLOCK_CRA_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA256_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct padlock_sha_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
- .cra_init = padlock_sha256_cra_init,
- .cra_exit = padlock_cra_exit,
- .cra_u = {
- .digest = {
- .dia_digestsize = SHA256_DIGEST_SIZE,
- .dia_init = padlock_sha_init,
- .dia_update = padlock_sha_update,
- .dia_final = padlock_sha_final,
- }
+static struct shash_alg sha256_alg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = padlock_sha_init,
+ .update = padlock_sha_update,
+ .finup = padlock_sha256_finup,
+ .final = padlock_sha256_final,
+ .descsize = sizeof(struct padlock_sha_desc),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = padlock_cra_init,
+ .cra_exit = padlock_cra_exit,
}
};
@@ -272,11 +275,11 @@ static int __init padlock_init(void)
return -ENODEV;
}
- rc = crypto_register_alg(&sha1_alg);
+ rc = crypto_register_shash(&sha1_alg);
if (rc)
goto out;
- rc = crypto_register_alg(&sha256_alg);
+ rc = crypto_register_shash(&sha256_alg);
if (rc)
goto out_unreg1;
@@ -285,7 +288,7 @@ static int __init padlock_init(void)
return 0;
out_unreg1:
- crypto_unregister_alg(&sha1_alg);
+ crypto_unregister_shash(&sha1_alg);
out:
printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n");
return rc;
@@ -293,8 +296,8 @@ out:
static void __exit padlock_fini(void)
{
- crypto_unregister_alg(&sha1_alg);
- crypto_unregister_alg(&sha256_alg);
+ crypto_unregister_shash(&sha1_alg);
+ crypto_unregister_shash(&sha256_alg);
}
module_init(padlock_init);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 070357aaedbc..81e1020fb514 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -4,7 +4,7 @@
menuconfig DMADEVICES
bool "DMA Engine support"
- depends on !HIGHMEM64G && HAS_DMA
+ depends on HAS_DMA
help
DMA engines can do asynchronous data transfers without
involving the host CPU. Currently, this framework can be
@@ -46,6 +46,14 @@ config DW_DMAC
Support the Synopsys DesignWare AHB DMA controller. This
can be integrated in chips such as the Atmel AT32ap7000.
+config AT_HDMAC
+ tristate "Atmel AHB DMA support"
+ depends on ARCH_AT91SAM9RL
+ select DMA_ENGINE
+ help
+ Support the Atmel AHB DMA controller. This can be integrated in
+ chips such as the Atmel AT91SAM9RL.
+
config FSL_DMA
tristate "Freescale Elo and Elo Plus DMA support"
depends on FSL_SOC
@@ -108,7 +116,7 @@ config NET_DMA
config ASYNC_TX_DMA
bool "Async_tx: Offload support for the async_tx api"
- depends on DMA_ENGINE
+ depends on DMA_ENGINE && !HIGHMEM64G
help
This allows the async_tx api to take advantage of offload engines for
memcpy, memset, xor, and raid6 p+q operations. If your platform has
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a0b6564800c4..40e1e0083571 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
+obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
new file mode 100644
index 000000000000..9a1e5fb412ed
--- /dev/null
+++ b/drivers/dma/at_hdmac.c
@@ -0,0 +1,1213 @@
+/*
+ * Driver for the Atmel AHB DMA Controller (aka HDMA or DMAC on AT91 systems)
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ * This supports the Atmel AHB DMA Controller,
+ *
+ * The driver has currently been tested with the Atmel AT91SAM9RL
+ * and AT91SAM9G45 series.
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "at_hdmac_regs.h"
+
+/*
+ * Glossary
+ * --------
+ *
+ * at_hdmac : Name of the ATmel AHB DMA Controller
+ * at_dma_ / atdma : ATmel DMA controller entity related
+ * atc_ / atchan : ATmel DMA Channel entity related
+ */
+
+#define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
+#define ATC_DEFAULT_CTRLA (0)
+#define ATC_DEFAULT_CTRLB (ATC_SIF(0) \
+ |ATC_DIF(1))
+
+/*
+ * Initial number of descriptors to allocate for each channel. This could
+ * be increased during dma usage.
+ */
+static unsigned int init_nr_desc_per_channel = 64;
+module_param(init_nr_desc_per_channel, uint, 0644);
+MODULE_PARM_DESC(init_nr_desc_per_channel,
+ "initial descriptors per channel (default: 64)");
+
+
+/* prototypes */
+static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx);
+
+
+/*----------------------------------------------------------------------*/
+
+static struct at_desc *atc_first_active(struct at_dma_chan *atchan)
+{
+ return list_first_entry(&atchan->active_list,
+ struct at_desc, desc_node);
+}
+
+static struct at_desc *atc_first_queued(struct at_dma_chan *atchan)
+{
+ return list_first_entry(&atchan->queue,
+ struct at_desc, desc_node);
+}
+
+/**
+ * atc_alloc_descriptor - allocate and return an initilized descriptor
+ * @chan: the channel to allocate descriptors for
+ * @gfp_flags: GFP allocation flags
+ *
+ * Note: The ack-bit is positioned in the descriptor flag at creation time
+ * to make initial allocation more convenient. This bit will be cleared
+ * and control will be given to client at usage time (during
+ * preparation functions).
+ */
+static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan,
+ gfp_t gfp_flags)
+{
+ struct at_desc *desc = NULL;
+ struct at_dma *atdma = to_at_dma(chan->device);
+ dma_addr_t phys;
+
+ desc = dma_pool_alloc(atdma->dma_desc_pool, gfp_flags, &phys);
+ if (desc) {
+ memset(desc, 0, sizeof(struct at_desc));
+ dma_async_tx_descriptor_init(&desc->txd, chan);
+ /* txd.flags will be overwritten in prep functions */
+ desc->txd.flags = DMA_CTRL_ACK;
+ desc->txd.tx_submit = atc_tx_submit;
+ desc->txd.phys = phys;
+ }
+
+ return desc;
+}
+
+/**
+ * atc_desc_get - get a unsused descriptor from free_list
+ * @atchan: channel we want a new descriptor for
+ */
+static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
+{
+ struct at_desc *desc, *_desc;
+ struct at_desc *ret = NULL;
+ unsigned int i = 0;
+ LIST_HEAD(tmp_list);
+
+ spin_lock_bh(&atchan->lock);
+ list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) {
+ i++;
+ if (async_tx_test_ack(&desc->txd)) {
+ list_del(&desc->desc_node);
+ ret = desc;
+ break;
+ }
+ dev_dbg(chan2dev(&atchan->chan_common),
+ "desc %p not ACKed\n", desc);
+ }
+ spin_unlock_bh(&atchan->lock);
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "scanned %u descriptors on freelist\n", i);
+
+ /* no more descriptor available in initial pool: create one more */
+ if (!ret) {
+ ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC);
+ if (ret) {
+ spin_lock_bh(&atchan->lock);
+ atchan->descs_allocated++;
+ spin_unlock_bh(&atchan->lock);
+ } else {
+ dev_err(chan2dev(&atchan->chan_common),
+ "not enough descriptors available\n");
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * atc_desc_put - move a descriptor, including any children, to the free list
+ * @atchan: channel we work on
+ * @desc: descriptor, at the head of a chain, to move to free list
+ */
+static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
+{
+ if (desc) {
+ struct at_desc *child;
+
+ spin_lock_bh(&atchan->lock);
+ list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "moving child desc %p to freelist\n",
+ child);
+ list_splice_init(&desc->txd.tx_list, &atchan->free_list);
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "moving desc %p to freelist\n", desc);
+ list_add(&desc->desc_node, &atchan->free_list);
+ spin_unlock_bh(&atchan->lock);
+ }
+}
+
+/**
+ * atc_assign_cookie - compute and assign new cookie
+ * @atchan: channel we work on
+ * @desc: descriptor to asign cookie for
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static dma_cookie_t
+atc_assign_cookie(struct at_dma_chan *atchan, struct at_desc *desc)
+{
+ dma_cookie_t cookie = atchan->chan_common.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ atchan->chan_common.cookie = cookie;
+ desc->txd.cookie = cookie;
+
+ return cookie;
+}
+
+/**
+ * atc_dostart - starts the DMA engine for real
+ * @atchan: the channel we want to start
+ * @first: first descriptor in the list we want to begin with
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
+{
+ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
+
+ /* ASSERT: channel is idle */
+ if (atc_chan_is_enabled(atchan)) {
+ dev_err(chan2dev(&atchan->chan_common),
+ "BUG: Attempted to start non-idle channel\n");
+ dev_err(chan2dev(&atchan->chan_common),
+ " channel: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
+ channel_readl(atchan, SADDR),
+ channel_readl(atchan, DADDR),
+ channel_readl(atchan, CTRLA),
+ channel_readl(atchan, CTRLB),
+ channel_readl(atchan, DSCR));
+
+ /* The tasklet will hopefully advance the queue... */
+ return;
+ }
+
+ vdbg_dump_regs(atchan);
+
+ /* clear any pending interrupt */
+ while (dma_readl(atdma, EBCISR))
+ cpu_relax();
+
+ channel_writel(atchan, SADDR, 0);
+ channel_writel(atchan, DADDR, 0);
+ channel_writel(atchan, CTRLA, 0);
+ channel_writel(atchan, CTRLB, 0);
+ channel_writel(atchan, DSCR, first->txd.phys);
+ dma_writel(atdma, CHER, atchan->mask);
+
+ vdbg_dump_regs(atchan);
+}
+
+/**
+ * atc_chain_complete - finish work for one transaction chain
+ * @atchan: channel we work on
+ * @desc: descriptor at the head of the chain we want do complete
+ *
+ * Called with atchan->lock held and bh disabled */
+static void
+atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
+{
+ dma_async_tx_callback callback;
+ void *param;
+ struct dma_async_tx_descriptor *txd = &desc->txd;
+
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "descriptor %u complete\n", txd->cookie);
+
+ atchan->completed_cookie = txd->cookie;
+ callback = txd->callback;
+ param = txd->callback_param;
+
+ /* move children to free_list */
+ list_splice_init(&txd->tx_list, &atchan->free_list);
+ /* move myself to free_list */
+ list_move(&desc->desc_node, &atchan->free_list);
+
+ /* unmap dma addresses */
+ if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+ dma_unmap_single(chan2parent(&atchan->chan_common),
+ desc->lli.daddr,
+ desc->len, DMA_FROM_DEVICE);
+ else
+ dma_unmap_page(chan2parent(&atchan->chan_common),
+ desc->lli.daddr,
+ desc->len, DMA_FROM_DEVICE);
+ }
+ if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+ dma_unmap_single(chan2parent(&atchan->chan_common),
+ desc->lli.saddr,
+ desc->len, DMA_TO_DEVICE);
+ else
+ dma_unmap_page(chan2parent(&atchan->chan_common),
+ desc->lli.saddr,
+ desc->len, DMA_TO_DEVICE);
+ }
+
+ /*
+ * The API requires that no submissions are done from a
+ * callback, so we don't need to drop the lock here
+ */
+ if (callback)
+ callback(param);
+
+ dma_run_dependencies(txd);
+}
+
+/**
+ * atc_complete_all - finish work for all transactions
+ * @atchan: channel to complete transactions for
+ *
+ * Eventually submit queued descriptors if any
+ *
+ * Assume channel is idle while calling this function
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_complete_all(struct at_dma_chan *atchan)
+{
+ struct at_desc *desc, *_desc;
+ LIST_HEAD(list);
+
+ dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n");
+
+ BUG_ON(atc_chan_is_enabled(atchan));
+
+ /*
+ * Submit queued descriptors ASAP, i.e. before we go through
+ * the completed ones.
+ */
+ if (!list_empty(&atchan->queue))
+ atc_dostart(atchan, atc_first_queued(atchan));
+ /* empty active_list now it is completed */
+ list_splice_init(&atchan->active_list, &list);
+ /* empty queue list by moving descriptors (if any) to active_list */
+ list_splice_init(&atchan->queue, &atchan->active_list);
+
+ list_for_each_entry_safe(desc, _desc, &list, desc_node)
+ atc_chain_complete(atchan, desc);
+}
+
+/**
+ * atc_cleanup_descriptors - cleanup up finished descriptors in active_list
+ * @atchan: channel to be cleaned up
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_cleanup_descriptors(struct at_dma_chan *atchan)
+{
+ struct at_desc *desc, *_desc;
+ struct at_desc *child;
+
+ dev_vdbg(chan2dev(&atchan->chan_common), "cleanup descriptors\n");
+
+ list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+ if (!(desc->lli.ctrla & ATC_DONE))
+ /* This one is currently in progress */
+ return;
+
+ list_for_each_entry(child, &desc->txd.tx_list, desc_node)
+ if (!(child->lli.ctrla & ATC_DONE))
+ /* Currently in progress */
+ return;
+
+ /*
+ * No descriptors so far seem to be in progress, i.e.
+ * this chain must be done.
+ */
+ atc_chain_complete(atchan, desc);
+ }
+}
+
+/**
+ * atc_advance_work - at the end of a transaction, move forward
+ * @atchan: channel where the transaction ended
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_advance_work(struct at_dma_chan *atchan)
+{
+ dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
+
+ if (list_empty(&atchan->active_list) ||
+ list_is_singular(&atchan->active_list)) {
+ atc_complete_all(atchan);
+ } else {
+ atc_chain_complete(atchan, atc_first_active(atchan));
+ /* advance work */
+ atc_dostart(atchan, atc_first_active(atchan));
+ }
+}
+
+
+/**
+ * atc_handle_error - handle errors reported by DMA controller
+ * @atchan: channel where error occurs
+ *
+ * Called with atchan->lock held and bh disabled
+ */
+static void atc_handle_error(struct at_dma_chan *atchan)
+{
+ struct at_desc *bad_desc;
+ struct at_desc *child;
+
+ /*
+ * The descriptor currently at the head of the active list is
+ * broked. Since we don't have any way to report errors, we'll
+ * just have to scream loudly and try to carry on.
+ */
+ bad_desc = atc_first_active(atchan);
+ list_del_init(&bad_desc->desc_node);
+
+ /* As we are stopped, take advantage to push queued descriptors
+ * in active_list */
+ list_splice_init(&atchan->queue, atchan->active_list.prev);
+
+ /* Try to restart the controller */
+ if (!list_empty(&atchan->active_list))
+ atc_dostart(atchan, atc_first_active(atchan));
+
+ /*
+ * KERN_CRITICAL may seem harsh, but since this only happens
+ * when someone submits a bad physical address in a
+ * descriptor, we should consider ourselves lucky that the
+ * controller flagged an error instead of scribbling over
+ * random memory locations.
+ */
+ dev_crit(chan2dev(&atchan->chan_common),
+ "Bad descriptor submitted for DMA!\n");
+ dev_crit(chan2dev(&atchan->chan_common),
+ " cookie: %d\n", bad_desc->txd.cookie);
+ atc_dump_lli(atchan, &bad_desc->lli);
+ list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node)
+ atc_dump_lli(atchan, &child->lli);
+
+ /* Pretend the descriptor completed successfully */
+ atc_chain_complete(atchan, bad_desc);
+}
+
+
+/*-- IRQ & Tasklet ---------------------------------------------------*/
+
+static void atc_tasklet(unsigned long data)
+{
+ struct at_dma_chan *atchan = (struct at_dma_chan *)data;
+
+ /* Channel cannot be enabled here */
+ if (atc_chan_is_enabled(atchan)) {
+ dev_err(chan2dev(&atchan->chan_common),
+ "BUG: channel enabled in tasklet\n");
+ return;
+ }
+
+ spin_lock(&atchan->lock);
+ if (test_and_clear_bit(0, &atchan->error_status))
+ atc_handle_error(atchan);
+ else
+ atc_advance_work(atchan);
+
+ spin_unlock(&atchan->lock);
+}
+
+static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+{
+ struct at_dma *atdma = (struct at_dma *)dev_id;
+ struct at_dma_chan *atchan;
+ int i;
+ u32 status, pending, imr;
+ int ret = IRQ_NONE;
+
+ do {
+ imr = dma_readl(atdma, EBCIMR);
+ status = dma_readl(atdma, EBCISR);
+ pending = status & imr;
+
+ if (!pending)
+ break;
+
+ dev_vdbg(atdma->dma_common.dev,
+ "interrupt: status = 0x%08x, 0x%08x, 0x%08x\n",
+ status, imr, pending);
+
+ for (i = 0; i < atdma->dma_common.chancnt; i++) {
+ atchan = &atdma->chan[i];
+ if (pending & (AT_DMA_CBTC(i) | AT_DMA_ERR(i))) {
+ if (pending & AT_DMA_ERR(i)) {
+ /* Disable channel on AHB error */
+ dma_writel(atdma, CHDR, atchan->mask);
+ /* Give information to tasklet */
+ set_bit(0, &atchan->error_status);
+ }
+ tasklet_schedule(&atchan->tasklet);
+ ret = IRQ_HANDLED;
+ }
+ }
+
+ } while (pending);
+
+ return ret;
+}
+
+
+/*-- DMA Engine API --------------------------------------------------*/
+
+/**
+ * atc_tx_submit - set the prepared descriptor(s) to be executed by the engine
+ * @desc: descriptor at the head of the transaction chain
+ *
+ * Queue chain if DMA engine is working already
+ *
+ * Cookie increment and adding to active_list or queue must be atomic
+ */
+static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct at_desc *desc = txd_to_at_desc(tx);
+ struct at_dma_chan *atchan = to_at_dma_chan(tx->chan);
+ dma_cookie_t cookie;
+
+ spin_lock_bh(&atchan->lock);
+ cookie = atc_assign_cookie(atchan, desc);
+
+ if (list_empty(&atchan->active_list)) {
+ dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
+ desc->txd.cookie);
+ atc_dostart(atchan, desc);
+ list_add_tail(&desc->desc_node, &atchan->active_list);
+ } else {
+ dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+ desc->txd.cookie);
+ list_add_tail(&desc->desc_node, &atchan->queue);
+ }
+
+ spin_unlock_bh(&atchan->lock);
+
+ return cookie;
+}
+
+/**
+ * atc_prep_dma_memcpy - prepare a memcpy operation
+ * @chan: the channel to prepare operation on
+ * @dest: operation virtual destination address
+ * @src: operation virtual source address
+ * @len: operation length
+ * @flags: tx descriptor status flags
+ */
+static struct dma_async_tx_descriptor *
+atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_desc *desc = NULL;
+ struct at_desc *first = NULL;
+ struct at_desc *prev = NULL;
+ size_t xfer_count;
+ size_t offset;
+ unsigned int src_width;
+ unsigned int dst_width;
+ u32 ctrla;
+ u32 ctrlb;
+
+ dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d0x%x s0x%x l0x%zx f0x%lx\n",
+ dest, src, len, flags);
+
+ if (unlikely(!len)) {
+ dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+ return NULL;
+ }
+
+ ctrla = ATC_DEFAULT_CTRLA;
+ ctrlb = ATC_DEFAULT_CTRLB
+ | ATC_SRC_ADDR_MODE_INCR
+ | ATC_DST_ADDR_MODE_INCR
+ | ATC_FC_MEM2MEM;
+
+ /*
+ * We can be a lot more clever here, but this should take care
+ * of the most common optimization.
+ */
+ if (!((src | dest | len) & 3)) {
+ ctrla |= ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
+ src_width = dst_width = 2;
+ } else if (!((src | dest | len) & 1)) {
+ ctrla |= ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
+ src_width = dst_width = 1;
+ } else {
+ ctrla |= ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
+ src_width = dst_width = 0;
+ }
+
+ for (offset = 0; offset < len; offset += xfer_count << src_width) {
+ xfer_count = min_t(size_t, (len - offset) >> src_width,
+ ATC_BTSIZE_MAX);
+
+ desc = atc_desc_get(atchan);
+ if (!desc)
+ goto err_desc_get;
+
+ desc->lli.saddr = src + offset;
+ desc->lli.daddr = dest + offset;
+ desc->lli.ctrla = ctrla | xfer_count;
+ desc->lli.ctrlb = ctrlb;
+
+ desc->txd.cookie = 0;
+ async_tx_ack(&desc->txd);
+
+ if (!first) {
+ first = desc;
+ } else {
+ /* inform the HW lli about chaining */
+ prev->lli.dscr = desc->txd.phys;
+ /* insert the link descriptor to the LD ring */
+ list_add_tail(&desc->desc_node,
+ &first->txd.tx_list);
+ }
+ prev = desc;
+ }
+
+ /* First descriptor of the chain embedds additional information */
+ first->txd.cookie = -EBUSY;
+ first->len = len;
+
+ /* set end-of-link to the last link descriptor of list*/
+ set_desc_eol(desc);
+
+ desc->txd.flags = flags; /* client is in control of this ack */
+
+ return &first->txd;
+
+err_desc_get:
+ atc_desc_put(atchan, first);
+ return NULL;
+}
+
+
+/**
+ * atc_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: tx descriptor status flags
+ */
+static struct dma_async_tx_descriptor *
+atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma_slave *atslave = chan->private;
+ struct at_desc *first = NULL;
+ struct at_desc *prev = NULL;
+ u32 ctrla;
+ u32 ctrlb;
+ dma_addr_t reg;
+ unsigned int reg_width;
+ unsigned int mem_width;
+ unsigned int i;
+ struct scatterlist *sg;
+ size_t total_len = 0;
+
+ dev_vdbg(chan2dev(chan), "prep_slave_sg: %s f0x%lx\n",
+ direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
+ flags);
+
+ if (unlikely(!atslave || !sg_len)) {
+ dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+ return NULL;
+ }
+
+ reg_width = atslave->reg_width;
+
+ sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction);
+
+ ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
+ ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ ctrla |= ATC_DST_WIDTH(reg_width);
+ ctrlb |= ATC_DST_ADDR_MODE_FIXED
+ | ATC_SRC_ADDR_MODE_INCR
+ | ATC_FC_MEM2PER;
+ reg = atslave->tx_reg;
+ for_each_sg(sgl, sg, sg_len, i) {
+ struct at_desc *desc;
+ u32 len;
+ u32 mem;
+
+ desc = atc_desc_get(atchan);
+ if (!desc)
+ goto err_desc_get;
+
+ mem = sg_phys(sg);
+ len = sg_dma_len(sg);
+ mem_width = 2;
+ if (unlikely(mem & 3 || len & 3))
+ mem_width = 0;
+
+ desc->lli.saddr = mem;
+ desc->lli.daddr = reg;
+ desc->lli.ctrla = ctrla
+ | ATC_SRC_WIDTH(mem_width)
+ | len >> mem_width;
+ desc->lli.ctrlb = ctrlb;
+
+ if (!first) {
+ first = desc;
+ } else {
+ /* inform the HW lli about chaining */
+ prev->lli.dscr = desc->txd.phys;
+ /* insert the link descriptor to the LD ring */
+ list_add_tail(&desc->desc_node,
+ &first->txd.tx_list);
+ }
+ prev = desc;
+ total_len += len;
+ }
+ break;
+ case DMA_FROM_DEVICE:
+ ctrla |= ATC_SRC_WIDTH(reg_width);
+ ctrlb |= ATC_DST_ADDR_MODE_INCR
+ | ATC_SRC_ADDR_MODE_FIXED
+ | ATC_FC_PER2MEM;
+
+ reg = atslave->rx_reg;
+ for_each_sg(sgl, sg, sg_len, i) {
+ struct at_desc *desc;
+ u32 len;
+ u32 mem;
+
+ desc = atc_desc_get(atchan);
+ if (!desc)
+ goto err_desc_get;
+
+ mem = sg_phys(sg);
+ len = sg_dma_len(sg);
+ mem_width = 2;
+ if (unlikely(mem & 3 || len & 3))
+ mem_width = 0;
+
+ desc->lli.saddr = reg;
+ desc->lli.daddr = mem;
+ desc->lli.ctrla = ctrla
+ | ATC_DST_WIDTH(mem_width)
+ | len >> mem_width;
+ desc->lli.ctrlb = ctrlb;
+
+ if (!first) {
+ first = desc;
+ } else {
+ /* inform the HW lli about chaining */
+ prev->lli.dscr = desc->txd.phys;
+ /* insert the link descriptor to the LD ring */
+ list_add_tail(&desc->desc_node,
+ &first->txd.tx_list);
+ }
+ prev = desc;
+ total_len += len;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ /* set end-of-link to the last link descriptor of list*/
+ set_desc_eol(prev);
+
+ /* First descriptor of the chain embedds additional information */
+ first->txd.cookie = -EBUSY;
+ first->len = total_len;
+
+ /* last link descriptor of list is responsible of flags */
+ prev->txd.flags = flags; /* client is in control of this ack */
+
+ return &first->txd;
+
+err_desc_get:
+ dev_err(chan2dev(chan), "not enough descriptors available\n");
+ atc_desc_put(atchan, first);
+ return NULL;
+}
+
+static void atc_terminate_all(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ struct at_desc *desc, *_desc;
+ LIST_HEAD(list);
+
+ /*
+ * This is only called when something went wrong elsewhere, so
+ * we don't really care about the data. Just disable the
+ * channel. We still have to poll the channel enable bit due
+ * to AHB/HSB limitations.
+ */
+ spin_lock_bh(&atchan->lock);
+
+ dma_writel(atdma, CHDR, atchan->mask);
+
+ /* confirm that this channel is disabled */
+ while (dma_readl(atdma, CHSR) & atchan->mask)
+ cpu_relax();
+
+ /* active_list entries will end up before queued entries */
+ list_splice_init(&atchan->queue, &list);
+ list_splice_init(&atchan->active_list, &list);
+
+ spin_unlock_bh(&atchan->lock);
+
+ /* Flush all pending and queued descriptors */
+ list_for_each_entry_safe(desc, _desc, &list, desc_node)
+ atc_chain_complete(atchan, desc);
+}
+
+/**
+ * atc_is_tx_complete - poll for transaction completion
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
+ * @done: if not %NULL, updated with last completed transaction
+ * @used: if not %NULL, updated with last used transaction
+ *
+ * If @done and @used are passed in, upon return they reflect the driver
+ * internal state and can be used with dma_async_is_complete() to check
+ * the status of multiple cookies without re-checking hardware state.
+ */
+static enum dma_status
+atc_is_tx_complete(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+
+ dev_vdbg(chan2dev(chan), "is_tx_complete: %d (d%d, u%d)\n",
+ cookie, done ? *done : 0, used ? *used : 0);
+
+ spin_lock_bh(atchan->lock);
+
+ last_complete = atchan->completed_cookie;
+ last_used = chan->cookie;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret != DMA_SUCCESS) {
+ atc_cleanup_descriptors(atchan);
+
+ last_complete = atchan->completed_cookie;
+ last_used = chan->cookie;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ }
+
+ spin_unlock_bh(atchan->lock);
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ return ret;
+}
+
+/**
+ * atc_issue_pending - try to finish work
+ * @chan: target DMA channel
+ */
+static void atc_issue_pending(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+
+ dev_vdbg(chan2dev(chan), "issue_pending\n");
+
+ if (!atc_chan_is_enabled(atchan)) {
+ spin_lock_bh(&atchan->lock);
+ atc_advance_work(atchan);
+ spin_unlock_bh(&atchan->lock);
+ }
+}
+
+/**
+ * atc_alloc_chan_resources - allocate resources for DMA channel
+ * @chan: allocate descriptor resources for this channel
+ * @client: current client requesting the channel be ready for requests
+ *
+ * return - the number of allocated descriptors
+ */
+static int atc_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ struct at_desc *desc;
+ struct at_dma_slave *atslave;
+ int i;
+ u32 cfg;
+ LIST_HEAD(tmp_list);
+
+ dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
+
+ /* ASSERT: channel is idle */
+ if (atc_chan_is_enabled(atchan)) {
+ dev_dbg(chan2dev(chan), "DMA channel not idle ?\n");
+ return -EIO;
+ }
+
+ cfg = ATC_DEFAULT_CFG;
+
+ atslave = chan->private;
+ if (atslave) {
+ /*
+ * We need controller-specific data to set up slave
+ * transfers.
+ */
+ BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev);
+
+ /* if cfg configuration specified take it instad of default */
+ if (atslave->cfg)
+ cfg = atslave->cfg;
+ }
+
+ /* have we already been set up?
+ * reconfigure channel but no need to reallocate descriptors */
+ if (!list_empty(&atchan->free_list))
+ return atchan->descs_allocated;
+
+ /* Allocate initial pool of descriptors */
+ for (i = 0; i < init_nr_desc_per_channel; i++) {
+ desc = atc_alloc_descriptor(chan, GFP_KERNEL);
+ if (!desc) {
+ dev_err(atdma->dma_common.dev,
+ "Only %d initial descriptors\n", i);
+ break;
+ }
+ list_add_tail(&desc->desc_node, &tmp_list);
+ }
+
+ spin_lock_bh(&atchan->lock);
+ atchan->descs_allocated = i;
+ list_splice(&tmp_list, &atchan->free_list);
+ atchan->completed_cookie = chan->cookie = 1;
+ spin_unlock_bh(&atchan->lock);
+
+ /* channel parameters */
+ channel_writel(atchan, CFG, cfg);
+
+ dev_dbg(chan2dev(chan),
+ "alloc_chan_resources: allocated %d descriptors\n",
+ atchan->descs_allocated);
+
+ return atchan->descs_allocated;
+}
+
+/**
+ * atc_free_chan_resources - free all channel resources
+ * @chan: DMA channel
+ */
+static void atc_free_chan_resources(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ struct at_desc *desc, *_desc;
+ LIST_HEAD(list);
+
+ dev_dbg(chan2dev(chan), "free_chan_resources: (descs allocated=%u)\n",
+ atchan->descs_allocated);
+
+ /* ASSERT: channel is idle */
+ BUG_ON(!list_empty(&atchan->active_list));
+ BUG_ON(!list_empty(&atchan->queue));
+ BUG_ON(atc_chan_is_enabled(atchan));
+
+ list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) {
+ dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc);
+ list_del(&desc->desc_node);
+ /* free link descriptor */
+ dma_pool_free(atdma->dma_desc_pool, desc, desc->txd.phys);
+ }
+ list_splice_init(&atchan->free_list, &list);
+ atchan->descs_allocated = 0;
+
+ dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
+}
+
+
+/*-- Module Management -----------------------------------------------*/
+
+/**
+ * at_dma_off - disable DMA controller
+ * @atdma: the Atmel HDAMC device
+ */
+static void at_dma_off(struct at_dma *atdma)
+{
+ dma_writel(atdma, EN, 0);
+
+ /* disable all interrupts */
+ dma_writel(atdma, EBCIDR, -1L);
+
+ /* confirm that all channels are disabled */
+ while (dma_readl(atdma, CHSR) & atdma->all_chan_mask)
+ cpu_relax();
+}
+
+static int __init at_dma_probe(struct platform_device *pdev)
+{
+ struct at_dma_platform_data *pdata;
+ struct resource *io;
+ struct at_dma *atdma;
+ size_t size;
+ int irq;
+ int err;
+ int i;
+
+ /* get DMA Controller parameters from platform */
+ pdata = pdev->dev.platform_data;
+ if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS)
+ return -EINVAL;
+
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!io)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ size = sizeof(struct at_dma);
+ size += pdata->nr_channels * sizeof(struct at_dma_chan);
+ atdma = kzalloc(size, GFP_KERNEL);
+ if (!atdma)
+ return -ENOMEM;
+
+ /* discover transaction capabilites from the platform data */
+ atdma->dma_common.cap_mask = pdata->cap_mask;
+ atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
+
+ size = io->end - io->start + 1;
+ if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ atdma->regs = ioremap(io->start, size);
+ if (!atdma->regs) {
+ err = -ENOMEM;
+ goto err_release_r;
+ }
+
+ atdma->clk = clk_get(&pdev->dev, "dma_clk");
+ if (IS_ERR(atdma->clk)) {
+ err = PTR_ERR(atdma->clk);
+ goto err_clk;
+ }
+ clk_enable(atdma->clk);
+
+ /* force dma off, just in case */
+ at_dma_off(atdma);
+
+ err = request_irq(irq, at_dma_interrupt, 0, "at_hdmac", atdma);
+ if (err)
+ goto err_irq;
+
+ platform_set_drvdata(pdev, atdma);
+
+ /* create a pool of consistent memory blocks for hardware descriptors */
+ atdma->dma_desc_pool = dma_pool_create("at_hdmac_desc_pool",
+ &pdev->dev, sizeof(struct at_desc),
+ 4 /* word alignment */, 0);
+ if (!atdma->dma_desc_pool) {
+ dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
+ err = -ENOMEM;
+ goto err_pool_create;
+ }
+
+ /* clear any pending interrupt */
+ while (dma_readl(atdma, EBCISR))
+ cpu_relax();
+
+ /* initialize channels related values */
+ INIT_LIST_HEAD(&atdma->dma_common.channels);
+ for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) {
+ struct at_dma_chan *atchan = &atdma->chan[i];
+
+ atchan->chan_common.device = &atdma->dma_common;
+ atchan->chan_common.cookie = atchan->completed_cookie = 1;
+ atchan->chan_common.chan_id = i;
+ list_add_tail(&atchan->chan_common.device_node,
+ &atdma->dma_common.channels);
+
+ atchan->ch_regs = atdma->regs + ch_regs(i);
+ spin_lock_init(&atchan->lock);
+ atchan->mask = 1 << i;
+
+ INIT_LIST_HEAD(&atchan->active_list);
+ INIT_LIST_HEAD(&atchan->queue);
+ INIT_LIST_HEAD(&atchan->free_list);
+
+ tasklet_init(&atchan->tasklet, atc_tasklet,
+ (unsigned long)atchan);
+ atc_enable_irq(atchan);
+ }
+
+ /* set base routines */
+ atdma->dma_common.device_alloc_chan_resources = atc_alloc_chan_resources;
+ atdma->dma_common.device_free_chan_resources = atc_free_chan_resources;
+ atdma->dma_common.device_is_tx_complete = atc_is_tx_complete;
+ atdma->dma_common.device_issue_pending = atc_issue_pending;
+ atdma->dma_common.dev = &pdev->dev;
+
+ /* set prep routines based on capability */
+ if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask))
+ atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy;
+
+ if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) {
+ atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg;
+ atdma->dma_common.device_terminate_all = atc_terminate_all;
+ }
+
+ dma_writel(atdma, EN, AT_DMA_ENABLE);
+
+ dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n",
+ dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "",
+ dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "",
+ atdma->dma_common.chancnt);
+
+ dma_async_device_register(&atdma->dma_common);
+
+ return 0;
+
+err_pool_create:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(platform_get_irq(pdev, 0), atdma);
+err_irq:
+ clk_disable(atdma->clk);
+ clk_put(atdma->clk);
+err_clk:
+ iounmap(atdma->regs);
+ atdma->regs = NULL;
+err_release_r:
+ release_mem_region(io->start, size);
+err_kfree:
+ kfree(atdma);
+ return err;
+}
+
+static int __exit at_dma_remove(struct platform_device *pdev)
+{
+ struct at_dma *atdma = platform_get_drvdata(pdev);
+ struct dma_chan *chan, *_chan;
+ struct resource *io;
+
+ at_dma_off(atdma);
+ dma_async_device_unregister(&atdma->dma_common);
+
+ dma_pool_destroy(atdma->dma_desc_pool);
+ platform_set_drvdata(pdev, NULL);
+ free_irq(platform_get_irq(pdev, 0), atdma);
+
+ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
+ device_node) {
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+
+ /* Disable interrupts */
+ atc_disable_irq(atchan);
+ tasklet_disable(&atchan->tasklet);
+
+ tasklet_kill(&atchan->tasklet);
+ list_del(&chan->device_node);
+ }
+
+ clk_disable(atdma->clk);
+ clk_put(atdma->clk);
+
+ iounmap(atdma->regs);
+ atdma->regs = NULL;
+
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(io->start, io->end - io->start + 1);
+
+ kfree(atdma);
+
+ return 0;
+}
+
+static void at_dma_shutdown(struct platform_device *pdev)
+{
+ struct at_dma *atdma = platform_get_drvdata(pdev);
+
+ at_dma_off(platform_get_drvdata(pdev));
+ clk_disable(atdma->clk);
+}
+
+static int at_dma_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct at_dma *atdma = platform_get_drvdata(pdev);
+
+ at_dma_off(platform_get_drvdata(pdev));
+ clk_disable(atdma->clk);
+ return 0;
+}
+
+static int at_dma_resume_early(struct platform_device *pdev)
+{
+ struct at_dma *atdma = platform_get_drvdata(pdev);
+
+ clk_enable(atdma->clk);
+ dma_writel(atdma, EN, AT_DMA_ENABLE);
+ return 0;
+
+}
+
+static struct platform_driver at_dma_driver = {
+ .remove = __exit_p(at_dma_remove),
+ .shutdown = at_dma_shutdown,
+ .suspend_late = at_dma_suspend_late,
+ .resume_early = at_dma_resume_early,
+ .driver = {
+ .name = "at_hdmac",
+ },
+};
+
+static int __init at_dma_init(void)
+{
+ return platform_driver_probe(&at_dma_driver, at_dma_probe);
+}
+module_init(at_dma_init);
+
+static void __exit at_dma_exit(void)
+{
+ platform_driver_unregister(&at_dma_driver);
+}
+module_exit(at_dma_exit);
+
+MODULE_DESCRIPTION("Atmel AHB DMA Controller driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at_hdmac");
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
new file mode 100644
index 000000000000..4c972afc49ec
--- /dev/null
+++ b/drivers/dma/at_hdmac_regs.h
@@ -0,0 +1,353 @@
+/*
+ * Header file for the Atmel AHB DMA Controller driver
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef AT_HDMAC_REGS_H
+#define AT_HDMAC_REGS_H
+
+#include <mach/at_hdmac.h>
+
+#define AT_DMA_MAX_NR_CHANNELS 8
+
+
+#define AT_DMA_GCFG 0x00 /* Global Configuration Register */
+#define AT_DMA_IF_BIGEND(i) (0x1 << (i)) /* AHB-Lite Interface i in Big-endian mode */
+#define AT_DMA_ARB_CFG (0x1 << 4) /* Arbiter mode. */
+#define AT_DMA_ARB_CFG_FIXED (0x0 << 4)
+#define AT_DMA_ARB_CFG_ROUND_ROBIN (0x1 << 4)
+
+#define AT_DMA_EN 0x04 /* Controller Enable Register */
+#define AT_DMA_ENABLE (0x1 << 0)
+
+#define AT_DMA_SREQ 0x08 /* Software Single Request Register */
+#define AT_DMA_SSREQ(x) (0x1 << ((x) << 1)) /* Request a source single transfer on channel x */
+#define AT_DMA_DSREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination single transfer on channel x */
+
+#define AT_DMA_CREQ 0x0C /* Software Chunk Transfer Request Register */
+#define AT_DMA_SCREQ(x) (0x1 << ((x) << 1)) /* Request a source chunk transfer on channel x */
+#define AT_DMA_DCREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination chunk transfer on channel x */
+
+#define AT_DMA_LAST 0x10 /* Software Last Transfer Flag Register */
+#define AT_DMA_SLAST(x) (0x1 << ((x) << 1)) /* This src rq is last tx of buffer on channel x */
+#define AT_DMA_DLAST(x) (0x1 << (1 + ((x) << 1))) /* This dst rq is last tx of buffer on channel x */
+
+#define AT_DMA_SYNC 0x14 /* Request Synchronization Register */
+#define AT_DMA_SYR(h) (0x1 << (h)) /* Synchronize handshake line h */
+
+/* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */
+#define AT_DMA_EBCIER 0x18 /* Enable register */
+#define AT_DMA_EBCIDR 0x1C /* Disable register */
+#define AT_DMA_EBCIMR 0x20 /* Mask Register */
+#define AT_DMA_EBCISR 0x24 /* Status Register */
+#define AT_DMA_CBTC_OFFSET 8
+#define AT_DMA_ERR_OFFSET 16
+#define AT_DMA_BTC(x) (0x1 << (x))
+#define AT_DMA_CBTC(x) (0x1 << (AT_DMA_CBTC_OFFSET + (x)))
+#define AT_DMA_ERR(x) (0x1 << (AT_DMA_ERR_OFFSET + (x)))
+
+#define AT_DMA_CHER 0x28 /* Channel Handler Enable Register */
+#define AT_DMA_ENA(x) (0x1 << (x))
+#define AT_DMA_SUSP(x) (0x1 << ( 8 + (x)))
+#define AT_DMA_KEEP(x) (0x1 << (24 + (x)))
+
+#define AT_DMA_CHDR 0x2C /* Channel Handler Disable Register */
+#define AT_DMA_DIS(x) (0x1 << (x))
+#define AT_DMA_RES(x) (0x1 << ( 8 + (x)))
+
+#define AT_DMA_CHSR 0x30 /* Channel Handler Status Register */
+#define AT_DMA_EMPT(x) (0x1 << (16 + (x)))
+#define AT_DMA_STAL(x) (0x1 << (24 + (x)))
+
+
+#define AT_DMA_CH_REGS_BASE 0x3C /* Channel registers base address */
+#define ch_regs(x) (AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
+
+/* Hardware register offset for each channel */
+#define ATC_SADDR_OFFSET 0x00 /* Source Address Register */
+#define ATC_DADDR_OFFSET 0x04 /* Destination Address Register */
+#define ATC_DSCR_OFFSET 0x08 /* Descriptor Address Register */
+#define ATC_CTRLA_OFFSET 0x0C /* Control A Register */
+#define ATC_CTRLB_OFFSET 0x10 /* Control B Register */
+#define ATC_CFG_OFFSET 0x14 /* Configuration Register */
+#define ATC_SPIP_OFFSET 0x18 /* Src PIP Configuration Register */
+#define ATC_DPIP_OFFSET 0x1C /* Dst PIP Configuration Register */
+
+
+/* Bitfield definitions */
+
+/* Bitfields in DSCR */
+#define ATC_DSCR_IF(i) (0x3 & (i)) /* Dsc feched via AHB-Lite Interface i */
+
+/* Bitfields in CTRLA */
+#define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */
+#define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
+/* Chunck Tranfer size definitions are in at_hdmac.h */
+#define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */
+#define ATC_SRC_WIDTH(x) ((x) << 24)
+#define ATC_SRC_WIDTH_BYTE (0x0 << 24)
+#define ATC_SRC_WIDTH_HALFWORD (0x1 << 24)
+#define ATC_SRC_WIDTH_WORD (0x2 << 24)
+#define ATC_DST_WIDTH_MASK (0x3 << 28) /* Destination Single Transfer Size */
+#define ATC_DST_WIDTH(x) ((x) << 28)
+#define ATC_DST_WIDTH_BYTE (0x0 << 28)
+#define ATC_DST_WIDTH_HALFWORD (0x1 << 28)
+#define ATC_DST_WIDTH_WORD (0x2 << 28)
+#define ATC_DONE (0x1 << 31) /* Tx Done (only written back in descriptor) */
+
+/* Bitfields in CTRLB */
+#define ATC_SIF(i) (0x3 & (i)) /* Src tx done via AHB-Lite Interface i */
+#define ATC_DIF(i) ((0x3 & (i)) << 4) /* Dst tx done via AHB-Lite Interface i */
+#define ATC_SRC_PIP (0x1 << 8) /* Source Picture-in-Picture enabled */
+#define ATC_DST_PIP (0x1 << 12) /* Destination Picture-in-Picture enabled */
+#define ATC_SRC_DSCR_DIS (0x1 << 16) /* Src Descriptor fetch disable */
+#define ATC_DST_DSCR_DIS (0x1 << 20) /* Dst Descriptor fetch disable */
+#define ATC_FC_MASK (0x7 << 21) /* Choose Flow Controller */
+#define ATC_FC_MEM2MEM (0x0 << 21) /* Mem-to-Mem (DMA) */
+#define ATC_FC_MEM2PER (0x1 << 21) /* Mem-to-Periph (DMA) */
+#define ATC_FC_PER2MEM (0x2 << 21) /* Periph-to-Mem (DMA) */
+#define ATC_FC_PER2PER (0x3 << 21) /* Periph-to-Periph (DMA) */
+#define ATC_FC_PER2MEM_PER (0x4 << 21) /* Periph-to-Mem (Peripheral) */
+#define ATC_FC_MEM2PER_PER (0x5 << 21) /* Mem-to-Periph (Peripheral) */
+#define ATC_FC_PER2PER_SRCPER (0x6 << 21) /* Periph-to-Periph (Src Peripheral) */
+#define ATC_FC_PER2PER_DSTPER (0x7 << 21) /* Periph-to-Periph (Dst Peripheral) */
+#define ATC_SRC_ADDR_MODE_MASK (0x3 << 24)
+#define ATC_SRC_ADDR_MODE_INCR (0x0 << 24) /* Incrementing Mode */
+#define ATC_SRC_ADDR_MODE_DECR (0x1 << 24) /* Decrementing Mode */
+#define ATC_SRC_ADDR_MODE_FIXED (0x2 << 24) /* Fixed Mode */
+#define ATC_DST_ADDR_MODE_MASK (0x3 << 28)
+#define ATC_DST_ADDR_MODE_INCR (0x0 << 28) /* Incrementing Mode */
+#define ATC_DST_ADDR_MODE_DECR (0x1 << 28) /* Decrementing Mode */
+#define ATC_DST_ADDR_MODE_FIXED (0x2 << 28) /* Fixed Mode */
+#define ATC_IEN (0x1 << 30) /* BTC interrupt enable (active low) */
+#define ATC_AUTO (0x1 << 31) /* Auto multiple buffer tx enable */
+
+/* Bitfields in CFG */
+/* are in at_hdmac.h */
+
+/* Bitfields in SPIP */
+#define ATC_SPIP_HOLE(x) (0xFFFFU & (x))
+#define ATC_SPIP_BOUNDARY(x) ((0x3FF & (x)) << 16)
+
+/* Bitfields in DPIP */
+#define ATC_DPIP_HOLE(x) (0xFFFFU & (x))
+#define ATC_DPIP_BOUNDARY(x) ((0x3FF & (x)) << 16)
+
+
+/*-- descriptors -----------------------------------------------------*/
+
+/* LLI == Linked List Item; aka DMA buffer descriptor */
+struct at_lli {
+ /* values that are not changed by hardware */
+ dma_addr_t saddr;
+ dma_addr_t daddr;
+ /* value that may get written back: */
+ u32 ctrla;
+ /* more values that are not changed by hardware */
+ u32 ctrlb;
+ dma_addr_t dscr; /* chain to next lli */
+};
+
+/**
+ * struct at_desc - software descriptor
+ * @at_lli: hardware lli structure
+ * @txd: support for the async_tx api
+ * @desc_node: node on the channed descriptors list
+ * @len: total transaction bytecount
+ */
+struct at_desc {
+ /* FIRST values the hardware uses */
+ struct at_lli lli;
+
+ /* THEN values for driver housekeeping */
+ struct dma_async_tx_descriptor txd;
+ struct list_head desc_node;
+ size_t len;
+};
+
+static inline struct at_desc *
+txd_to_at_desc(struct dma_async_tx_descriptor *txd)
+{
+ return container_of(txd, struct at_desc, txd);
+}
+
+
+/*-- Channels --------------------------------------------------------*/
+
+/**
+ * struct at_dma_chan - internal representation of an Atmel HDMAC channel
+ * @chan_common: common dmaengine channel object members
+ * @device: parent device
+ * @ch_regs: memory mapped register base
+ * @mask: channel index in a mask
+ * @error_status: transmit error status information from irq handler
+ * to tasklet (use atomic operations)
+ * @tasklet: bottom half to finish transaction work
+ * @lock: serializes enqueue/dequeue operations to descriptors lists
+ * @completed_cookie: identifier for the most recently completed operation
+ * @active_list: list of descriptors dmaengine is being running on
+ * @queue: list of descriptors ready to be submitted to engine
+ * @free_list: list of descriptors usable by the channel
+ * @descs_allocated: records the actual size of the descriptor pool
+ */
+struct at_dma_chan {
+ struct dma_chan chan_common;
+ struct at_dma *device;
+ void __iomem *ch_regs;
+ u8 mask;
+ unsigned long error_status;
+ struct tasklet_struct tasklet;
+
+ spinlock_t lock;
+
+ /* these other elements are all protected by lock */
+ dma_cookie_t completed_cookie;
+ struct list_head active_list;
+ struct list_head queue;
+ struct list_head free_list;
+ unsigned int descs_allocated;
+};
+
+#define channel_readl(atchan, name) \
+ __raw_readl((atchan)->ch_regs + ATC_##name##_OFFSET)
+
+#define channel_writel(atchan, name, val) \
+ __raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET)
+
+static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
+{
+ return container_of(dchan, struct at_dma_chan, chan_common);
+}
+
+
+/*-- Controller ------------------------------------------------------*/
+
+/**
+ * struct at_dma - internal representation of an Atmel HDMA Controller
+ * @chan_common: common dmaengine dma_device object members
+ * @ch_regs: memory mapped register base
+ * @clk: dma controller clock
+ * @all_chan_mask: all channels availlable in a mask
+ * @dma_desc_pool: base of DMA descriptor region (DMA address)
+ * @chan: channels table to store at_dma_chan structures
+ */
+struct at_dma {
+ struct dma_device dma_common;
+ void __iomem *regs;
+ struct clk *clk;
+
+ u8 all_chan_mask;
+
+ struct dma_pool *dma_desc_pool;
+ /* AT THE END channels table */
+ struct at_dma_chan chan[0];
+};
+
+#define dma_readl(atdma, name) \
+ __raw_readl((atdma)->regs + AT_DMA_##name)
+#define dma_writel(atdma, name, val) \
+ __raw_writel((val), (atdma)->regs + AT_DMA_##name)
+
+static inline struct at_dma *to_at_dma(struct dma_device *ddev)
+{
+ return container_of(ddev, struct at_dma, dma_common);
+}
+
+
+/*-- Helper functions ------------------------------------------------*/
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+ return &chan->dev->device;
+}
+static struct device *chan2parent(struct dma_chan *chan)
+{
+ return chan->dev->device.parent;
+}
+
+#if defined(VERBOSE_DEBUG)
+static void vdbg_dump_regs(struct at_dma_chan *atchan)
+{
+ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
+
+ dev_err(chan2dev(&atchan->chan_common),
+ " channel %d : imr = 0x%x, chsr = 0x%x\n",
+ atchan->chan_common.chan_id,
+ dma_readl(atdma, EBCIMR),
+ dma_readl(atdma, CHSR));
+
+ dev_err(chan2dev(&atchan->chan_common),
+ " channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
+ channel_readl(atchan, SADDR),
+ channel_readl(atchan, DADDR),
+ channel_readl(atchan, CTRLA),
+ channel_readl(atchan, CTRLB),
+ channel_readl(atchan, CFG),
+ channel_readl(atchan, DSCR));
+}
+#else
+static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
+#endif
+
+static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
+{
+ dev_printk(KERN_CRIT, chan2dev(&atchan->chan_common),
+ " desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
+ lli->saddr, lli->daddr,
+ lli->ctrla, lli->ctrlb, lli->dscr);
+}
+
+
+static void atc_setup_irq(struct at_dma_chan *atchan, int on)
+{
+ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
+ u32 ebci;
+
+ /* enable interrupts on buffer chain completion & error */
+ ebci = AT_DMA_CBTC(atchan->chan_common.chan_id)
+ | AT_DMA_ERR(atchan->chan_common.chan_id);
+ if (on)
+ dma_writel(atdma, EBCIER, ebci);
+ else
+ dma_writel(atdma, EBCIDR, ebci);
+}
+
+static inline void atc_enable_irq(struct at_dma_chan *atchan)
+{
+ atc_setup_irq(atchan, 1);
+}
+
+static inline void atc_disable_irq(struct at_dma_chan *atchan)
+{
+ atc_setup_irq(atchan, 0);
+}
+
+
+/**
+ * atc_chan_is_enabled - test if given channel is enabled
+ * @atchan: channel we want to test status
+ */
+static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
+{
+ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
+
+ return !!(dma_readl(atdma, CHSR) & atchan->mask);
+}
+
+
+/**
+ * set_desc_eol - set end-of-link to descriptor so it will end transfer
+ * @desc: descriptor, signle or at the end of a chain, to end chain on
+ */
+static void set_desc_eol(struct at_desc *desc)
+{
+ desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
+ desc->lli.dscr = 0;
+}
+
+#endif /* AT_HDMAC_REGS_H */
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index fb7da5141e96..d93017fc7872 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -38,6 +38,11 @@ module_param(max_channels, uint, S_IRUGO);
MODULE_PARM_DESC(max_channels,
"Maximum number of channels to use (default: all)");
+static unsigned int iterations;
+module_param(iterations, uint, S_IRUGO);
+MODULE_PARM_DESC(iterations,
+ "Iterations before stopping test (default: infinite)");
+
static unsigned int xor_sources = 3;
module_param(xor_sources, uint, S_IRUGO);
MODULE_PARM_DESC(xor_sources,
@@ -114,7 +119,7 @@ static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len)
buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
for ( ; i < start + len; i++)
buf[i] = PATTERN_SRC | PATTERN_COPY
- | (~i & PATTERN_COUNT_MASK);;
+ | (~i & PATTERN_COUNT_MASK);
for ( ; i < test_buf_size; i++)
buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
buf++;
@@ -270,7 +275,8 @@ static int dmatest_func(void *data)
flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
- while (!kthread_should_stop()) {
+ while (!kthread_should_stop()
+ && !(iterations && total_tests >= iterations)) {
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx = NULL;
dma_addr_t dma_srcs[src_cnt];
@@ -416,6 +422,13 @@ err_srcbuf:
err_srcs:
pr_notice("%s: terminating after %u tests, %u failures (status %d)\n",
thread_name, total_tests, failed_tests, ret);
+
+ if (iterations > 0)
+ while (!kthread_should_stop()) {
+ DECLARE_WAIT_QUEUE_HEAD(wait_dmatest_exit);
+ interruptible_sleep_on(&wait_dmatest_exit);
+ }
+
return ret;
}
@@ -495,11 +508,11 @@ static int dmatest_add_channel(struct dma_chan *chan)
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
cnt = dmatest_add_threads(dtc, DMA_MEMCPY);
- thread_count += cnt > 0 ?: 0;
+ thread_count += cnt > 0 ? cnt : 0;
}
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
cnt = dmatest_add_threads(dtc, DMA_XOR);
- thread_count += cnt > 0 ?: 0;
+ thread_count += cnt > 0 ? cnt : 0;
}
pr_info("dmatest: Started %u threads using %s\n",
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 98c9a847bf51..933c143b6a74 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1399,8 +1399,9 @@ static void dw_shutdown(struct platform_device *pdev)
clk_disable(dw->clk);
}
-static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+static int dw_suspend_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev);
dw_dma_off(platform_get_drvdata(pdev));
@@ -1408,23 +1409,27 @@ static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg)
return 0;
}
-static int dw_resume_early(struct platform_device *pdev)
+static int dw_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev);
clk_enable(dw->clk);
dma_writel(dw, CFG, DW_CFG_DMA_EN);
return 0;
-
}
+static struct dev_pm_ops dw_dev_pm_ops = {
+ .suspend_noirq = dw_suspend_noirq,
+ .resume_noirq = dw_resume_noirq,
+};
+
static struct platform_driver dw_driver = {
.remove = __exit_p(dw_remove),
.shutdown = dw_shutdown,
- .suspend_late = dw_suspend_late,
- .resume_early = dw_resume_early,
.driver = {
.name = "dw_dmac",
+ .pm = &dw_dev_pm_ops,
},
};
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index f18d1bde0439..ef87a8984145 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -12,6 +12,11 @@
* also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc.
* The support for MPC8349 DMA contorller is also added.
*
+ * This driver instructs the DMA controller to issue the PCI Read Multiple
+ * command for PCI read operations, instead of using the default PCI Read Line
+ * command. Please be aware that this setting may result in read pre-fetching
+ * on some platforms.
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -49,9 +54,10 @@ static void dma_init(struct fsl_dma_chan *fsl_chan)
case FSL_DMA_IP_83XX:
/* Set the channel to below modes:
* EOTIE - End-of-transfer interrupt enable
+ * PRC_RM - PCI read multiple
*/
- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE,
- 32);
+ DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE
+ | FSL_DMA_MR_PRC_RM, 32);
break;
}
@@ -136,15 +142,16 @@ static int dma_is_idle(struct fsl_dma_chan *fsl_chan)
static void dma_start(struct fsl_dma_chan *fsl_chan)
{
- u32 mr_set = 0;;
+ u32 mr_set = 0;
if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32);
mr_set |= FSL_DMA_MR_EMP_EN;
- } else
+ } else if ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
& ~FSL_DMA_MR_EMP_EN, 32);
+ }
if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT)
mr_set |= FSL_DMA_MR_EMS_EN;
@@ -871,9 +878,9 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) {
case FSL_DMA_IP_85XX:
- new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
case FSL_DMA_IP_83XX:
+ new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size;
new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size;
}
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 4f21a512d848..dc7f26865797 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -38,6 +38,7 @@
/* Special MR definition for MPC8349 */
#define FSL_DMA_MR_EOTIE 0x00000080
+#define FSL_DMA_MR_PRC_RM 0x00000800
#define FSL_DMA_SR_CH 0x00000020
#define FSL_DMA_SR_PE 0x00000010
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index ddab94f51224..3f23eabe09f2 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -1176,7 +1176,7 @@ static int __devinit mv_xor_probe(struct platform_device *pdev)
if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
dma_dev->device_prep_dma_memset = mv_xor_prep_dma_memset;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
- dma_dev->max_xor = 8; ;
+ dma_dev->max_xor = 8;
dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor;
}
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 88dab52926f4..7837930146a4 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -1291,17 +1291,18 @@ static void txx9dmac_shutdown(struct platform_device *pdev)
txx9dmac_off(ddev);
}
-static int txx9dmac_suspend_late(struct platform_device *pdev,
- pm_message_t mesg)
+static int txx9dmac_suspend_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
txx9dmac_off(ddev);
return 0;
}
-static int txx9dmac_resume_early(struct platform_device *pdev)
+static int txx9dmac_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
struct txx9dmac_platform_data *pdata = pdev->dev.platform_data;
u32 mcr;
@@ -1314,6 +1315,11 @@ static int txx9dmac_resume_early(struct platform_device *pdev)
}
+static struct dev_pm_ops txx9dmac_dev_pm_ops = {
+ .suspend_noirq = txx9dmac_suspend_noirq,
+ .resume_noirq = txx9dmac_resume_noirq,
+};
+
static struct platform_driver txx9dmac_chan_driver = {
.remove = __exit_p(txx9dmac_chan_remove),
.driver = {
@@ -1324,10 +1330,9 @@ static struct platform_driver txx9dmac_chan_driver = {
static struct platform_driver txx9dmac_driver = {
.remove = __exit_p(txx9dmac_remove),
.shutdown = txx9dmac_shutdown,
- .suspend_late = txx9dmac_suspend_late,
- .resume_early = txx9dmac_resume_early,
.driver = {
.name = "txx9dmac",
+ .pm = &txx9dmac_dev_pm_ops,
},
};
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 98aa4a7db412..cfa033ce53a7 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -17,6 +17,10 @@ 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_AMD76X) += amd76x_edac.o
obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
@@ -32,7 +36,7 @@ obj-$(CONFIG_EDAC_X38) += x38_edac.o
obj-$(CONFIG_EDAC_I82860) += i82860_edac.o
obj-$(CONFIG_EDAC_R82600) += r82600_edac.o
-amd64_edac_mod-y := amd64_edac_err_types.o amd64_edac.o
+amd64_edac_mod-y := amd64_edac.o
amd64_edac_mod-$(CONFIG_EDAC_DEBUG) += amd64_edac_dbg.o
amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 858fe6037223..852cae4e6f9b 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -19,6 +19,63 @@ static struct mem_ctl_info *mci_lookup[MAX_NUMNODES];
static struct amd64_pvt *pvt_lookup[MAX_NUMNODES];
/*
+ * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only
+ * for DDR2 DRAM mapping.
+ */
+u32 revf_quad_ddr2_shift[] = {
+ 0, /* 0000b NULL DIMM (128mb) */
+ 28, /* 0001b 256mb */
+ 29, /* 0010b 512mb */
+ 29, /* 0011b 512mb */
+ 29, /* 0100b 512mb */
+ 30, /* 0101b 1gb */
+ 30, /* 0110b 1gb */
+ 31, /* 0111b 2gb */
+ 31, /* 1000b 2gb */
+ 32, /* 1001b 4gb */
+ 32, /* 1010b 4gb */
+ 33, /* 1011b 8gb */
+ 0, /* 1100b future */
+ 0, /* 1101b future */
+ 0, /* 1110b future */
+ 0 /* 1111b future */
+};
+
+/*
+ * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
+ * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
+ * or higher value'.
+ *
+ *FIXME: Produce a better mapping/linearisation.
+ */
+
+struct scrubrate scrubrates[] = {
+ { 0x01, 1600000000UL},
+ { 0x02, 800000000UL},
+ { 0x03, 400000000UL},
+ { 0x04, 200000000UL},
+ { 0x05, 100000000UL},
+ { 0x06, 50000000UL},
+ { 0x07, 25000000UL},
+ { 0x08, 12284069UL},
+ { 0x09, 6274509UL},
+ { 0x0A, 3121951UL},
+ { 0x0B, 1560975UL},
+ { 0x0C, 781440UL},
+ { 0x0D, 390720UL},
+ { 0x0E, 195300UL},
+ { 0x0F, 97650UL},
+ { 0x10, 48854UL},
+ { 0x11, 24427UL},
+ { 0x12, 12213UL},
+ { 0x13, 6101UL},
+ { 0x14, 3051UL},
+ { 0x15, 1523UL},
+ { 0x16, 761UL},
+ { 0x00, 0UL}, /* scrubbing off */
+};
+
+/*
* Memory scrubber control interface. For K8, memory scrubbing is handled by
* hardware and can involve L2 cache, dcache as well as the main memory. With
* F10, this is extended to L3 cache scrubbing on CPU models sporting that
@@ -693,7 +750,7 @@ static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
* specific.
*/
static u64 extract_error_address(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
struct amd64_pvt *pvt = mci->pvt_info;
@@ -970,7 +1027,7 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
}
for (cs = 0; cs < pvt->num_dcsm; cs++) {
- reg = K8_DCSB0 + (cs * 4);
+ reg = K8_DCSM0 + (cs * 4);
err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
&pvt->dcsm0[cs]);
if (unlikely(err))
@@ -1047,7 +1104,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
/* extract the ERROR ADDRESS for the K8 CPUs */
static u64 k8_get_error_address(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
return (((u64) (info->nbeah & 0xff)) << 32) +
(info->nbeal & ~0x03);
@@ -1090,7 +1147,7 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
}
static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info,
+ struct err_regs *info,
u64 SystemAddress)
{
struct mem_ctl_info *src_mci;
@@ -1099,8 +1156,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
u32 page, offset;
/* Extract the syndrome parts and form a 16-bit syndrome */
- syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8;
- syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh);
+ syndrome = HIGH_SYNDROME(info->nbsl) << 8;
+ syndrome |= LOW_SYNDROME(info->nbsh);
/* CHIPKILL enabled */
if (info->nbcfg & K8_NBCFG_CHIPKILL) {
@@ -1309,7 +1366,7 @@ static void amd64_teardown(struct amd64_pvt *pvt)
}
static u64 f10_get_error_address(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
return (((u64) (info->nbeah & 0xffff)) << 32) +
(info->nbeal & ~0x01);
@@ -1686,7 +1743,7 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
* The @sys_addr is usually an error address received from the hardware.
*/
static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info,
+ struct err_regs *info,
u64 sys_addr)
{
struct amd64_pvt *pvt = mci->pvt_info;
@@ -1699,8 +1756,8 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
if (csrow >= 0) {
error_address_to_page_and_offset(sys_addr, &page, &offset);
- syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8;
- syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh);
+ syndrome = HIGH_SYNDROME(info->nbsl) << 8;
+ syndrome |= LOW_SYNDROME(info->nbsh);
/*
* Is CHIPKILL on? If so, then we can attempt to use the
@@ -2043,7 +2100,7 @@ static int get_channel_from_ecc_syndrome(unsigned short syndrome)
* - 0: if no valid error is indicated
*/
static int amd64_get_error_info_regs(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *regs)
+ struct err_regs *regs)
{
struct amd64_pvt *pvt;
struct pci_dev *misc_f3_ctl;
@@ -2092,10 +2149,10 @@ err_reg:
* - 0: if no error is found
*/
static int amd64_get_error_info(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
struct amd64_pvt *pvt;
- struct amd64_error_info_regs regs;
+ struct err_regs regs;
pvt = mci->pvt_info;
@@ -2150,48 +2207,12 @@ static int amd64_get_error_info(struct mem_ctl_info *mci,
return 1;
}
-static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
-{
- u32 err_code;
- u32 ec_tt; /* error code transaction type (2b) */
- u32 ec_ll; /* error code cache level (2b) */
-
- err_code = EXTRACT_ERROR_CODE(info->nbsl);
- ec_ll = EXTRACT_LL_CODE(err_code);
- ec_tt = EXTRACT_TT_CODE(err_code);
-
- amd64_mc_printk(mci, KERN_ERR,
- "GART TLB event: transaction type(%s), "
- "cache level(%s)\n", tt_msgs[ec_tt], ll_msgs[ec_ll]);
-}
-
-static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
-{
- u32 err_code;
- u32 ec_rrrr; /* error code memory transaction (4b) */
- u32 ec_tt; /* error code transaction type (2b) */
- u32 ec_ll; /* error code cache level (2b) */
-
- err_code = EXTRACT_ERROR_CODE(info->nbsl);
- ec_ll = EXTRACT_LL_CODE(err_code);
- ec_tt = EXTRACT_TT_CODE(err_code);
- ec_rrrr = EXTRACT_RRRR_CODE(err_code);
-
- amd64_mc_printk(mci, KERN_ERR,
- "cache hierarchy error: memory transaction type(%s), "
- "transaction type(%s), cache level(%s)\n",
- rrrr_msgs[ec_rrrr], tt_msgs[ec_tt], ll_msgs[ec_ll]);
-}
-
-
/*
* Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
* ADDRESS and process.
*/
static void amd64_handle_ce(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
struct amd64_pvt *pvt = mci->pvt_info;
u64 SystemAddress;
@@ -2214,7 +2235,7 @@ static void amd64_handle_ce(struct mem_ctl_info *mci,
/* Handle any Un-correctable Errors (UEs) */
static void amd64_handle_ue(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+ struct err_regs *info)
{
int csrow;
u64 SystemAddress;
@@ -2259,59 +2280,24 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
}
}
-static void amd64_decode_bus_error(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info)
+static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
+ struct err_regs *info)
{
- u32 err_code, ext_ec;
- u32 ec_pp; /* error code participating processor (2p) */
- u32 ec_to; /* error code timed out (1b) */
- u32 ec_rrrr; /* error code memory transaction (4b) */
- u32 ec_ii; /* error code memory or I/O (2b) */
- u32 ec_ll; /* error code cache level (2b) */
+ u32 ec = ERROR_CODE(info->nbsl);
+ u32 xec = EXT_ERROR_CODE(info->nbsl);
+ int ecc_type = info->nbsh & (0x3 << 13);
- ext_ec = EXTRACT_EXT_ERROR_CODE(info->nbsl);
- err_code = EXTRACT_ERROR_CODE(info->nbsl);
-
- ec_ll = EXTRACT_LL_CODE(err_code);
- ec_ii = EXTRACT_II_CODE(err_code);
- ec_rrrr = EXTRACT_RRRR_CODE(err_code);
- ec_to = EXTRACT_TO_CODE(err_code);
- ec_pp = EXTRACT_PP_CODE(err_code);
-
- amd64_mc_printk(mci, KERN_ERR,
- "BUS ERROR:\n"
- " time-out(%s) mem or i/o(%s)\n"
- " participating processor(%s)\n"
- " memory transaction type(%s)\n"
- " cache level(%s) Error Found by: %s\n",
- to_msgs[ec_to],
- ii_msgs[ec_ii],
- pp_msgs[ec_pp],
- rrrr_msgs[ec_rrrr],
- ll_msgs[ec_ll],
- (info->nbsh & K8_NBSH_ERR_SCRUBER) ?
- "Scrubber" : "Normal Operation");
-
- /* If this was an 'observed' error, early out */
- if (ec_pp == K8_NBSL_PP_OBS)
- return; /* We aren't the node involved */
-
- /* Parse out the extended error code for ECC events */
- switch (ext_ec) {
- /* F10 changed to one Extended ECC error code */
- case F10_NBSL_EXT_ERR_RES: /* Reserved field */
- case F10_NBSL_EXT_ERR_ECC: /* F10 ECC ext err code */
- break;
+ /* Bail early out if this was an 'observed' error */
+ if (PP(ec) == K8_NBSL_PP_OBS)
+ return;
- default:
- amd64_mc_printk(mci, KERN_ERR, "NOT ECC: no special error "
- "handling for this error\n");
+ /* Do only ECC errors */
+ if (xec && xec != F10_NBSL_EXT_ERR_ECC)
return;
- }
- if (info->nbsh & K8_NBSH_CECC)
+ if (ecc_type == 2)
amd64_handle_ce(mci, info);
- else if (info->nbsh & K8_NBSH_UECC)
+ else if (ecc_type == 1)
amd64_handle_ue(mci, info);
/*
@@ -2322,139 +2308,26 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci,
* catastrophic.
*/
if (info->nbsh & K8_NBSH_OVERFLOW)
- edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR
- "Error Overflow set");
+ edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow");
}
-int amd64_process_error_info(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info,
- int handle_errors)
+void amd64_decode_bus_error(int node_id, struct err_regs *regs)
{
- struct amd64_pvt *pvt;
- struct amd64_error_info_regs *regs;
- u32 err_code, ext_ec;
- int gart_tlb_error = 0;
-
- pvt = mci->pvt_info;
+ struct mem_ctl_info *mci = mci_lookup[node_id];
- /* If caller doesn't want us to process the error, return */
- if (!handle_errors)
- return 1;
-
- regs = info;
-
- debugf1("NorthBridge ERROR: mci(0x%p)\n", mci);
- debugf1(" MC node(%d) Error-Address(0x%.8x-%.8x)\n",
- pvt->mc_node_id, regs->nbeah, regs->nbeal);
- debugf1(" nbsh(0x%.8x) nbsl(0x%.8x)\n",
- regs->nbsh, regs->nbsl);
- debugf1(" Valid Error=%s Overflow=%s\n",
- (regs->nbsh & K8_NBSH_VALID_BIT) ? "True" : "False",
- (regs->nbsh & K8_NBSH_OVERFLOW) ? "True" : "False");
- debugf1(" Err Uncorrected=%s MCA Error Reporting=%s\n",
- (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) ?
- "True" : "False",
- (regs->nbsh & K8_NBSH_ERR_ENABLE) ?
- "True" : "False");
- debugf1(" MiscErr Valid=%s ErrAddr Valid=%s PCC=%s\n",
- (regs->nbsh & K8_NBSH_MISC_ERR_VALID) ?
- "True" : "False",
- (regs->nbsh & K8_NBSH_VALID_ERROR_ADDR) ?
- "True" : "False",
- (regs->nbsh & K8_NBSH_PCC) ?
- "True" : "False");
- debugf1(" CECC=%s UECC=%s Found by Scruber=%s\n",
- (regs->nbsh & K8_NBSH_CECC) ?
- "True" : "False",
- (regs->nbsh & K8_NBSH_UECC) ?
- "True" : "False",
- (regs->nbsh & K8_NBSH_ERR_SCRUBER) ?
- "True" : "False");
- debugf1(" CORE0=%s CORE1=%s CORE2=%s CORE3=%s\n",
- (regs->nbsh & K8_NBSH_CORE0) ? "True" : "False",
- (regs->nbsh & K8_NBSH_CORE1) ? "True" : "False",
- (regs->nbsh & K8_NBSH_CORE2) ? "True" : "False",
- (regs->nbsh & K8_NBSH_CORE3) ? "True" : "False");
-
-
- err_code = EXTRACT_ERROR_CODE(regs->nbsl);
-
- /* Determine which error type:
- * 1) GART errors - non-fatal, developmental events
- * 2) MEMORY errors
- * 3) BUS errors
- * 4) Unknown error
- */
- if (TEST_TLB_ERROR(err_code)) {
- /*
- * GART errors are intended to help graphics driver developers
- * to detect bad GART PTEs. It is recommended by AMD to disable
- * GART table walk error reporting by default[1] (currently
- * being disabled in mce_cpu_quirks()) and according to the
- * comment in mce_cpu_quirks(), such GART errors can be
- * incorrectly triggered. We may see these errors anyway and
- * unless requested by the user, they won't be reported.
- *
- * [1] section 13.10.1 on BIOS and Kernel Developers Guide for
- * AMD NPT family 0Fh processors
- */
- if (report_gart_errors == 0)
- return 1;
-
- /*
- * Only if GART error reporting is requested should we generate
- * any logs.
- */
- gart_tlb_error = 1;
-
- debugf1("GART TLB error\n");
- amd64_decode_gart_tlb_error(mci, info);
- } else if (TEST_MEM_ERROR(err_code)) {
- debugf1("Memory/Cache error\n");
- amd64_decode_mem_cache_error(mci, info);
- } else if (TEST_BUS_ERROR(err_code)) {
- debugf1("Bus (Link/DRAM) error\n");
- amd64_decode_bus_error(mci, info);
- } else {
- /* shouldn't reach here! */
- amd64_mc_printk(mci, KERN_WARNING,
- "%s(): unknown MCE error 0x%x\n", __func__,
- err_code);
- }
-
- ext_ec = EXTRACT_EXT_ERROR_CODE(regs->nbsl);
- amd64_mc_printk(mci, KERN_ERR,
- "ExtErr=(0x%x) %s\n", ext_ec, ext_msgs[ext_ec]);
-
- if (((ext_ec >= F10_NBSL_EXT_ERR_CRC &&
- ext_ec <= F10_NBSL_EXT_ERR_TGT) ||
- (ext_ec == F10_NBSL_EXT_ERR_RMW)) &&
- EXTRACT_LDT_LINK(info->nbsh)) {
-
- amd64_mc_printk(mci, KERN_ERR,
- "Error on hypertransport link: %s\n",
- htlink_msgs[
- EXTRACT_LDT_LINK(info->nbsh)]);
- }
+ __amd64_decode_bus_error(mci, regs);
/*
* Check the UE bit of the NB status high register, if set generate some
* logs. If NOT a GART error, then process the event as a NO-INFO event.
* If it was a GART error, skip that process.
+ *
+ * FIXME: this should go somewhere else, if at all.
*/
- if (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) {
- amd64_mc_printk(mci, KERN_CRIT, "uncorrected error\n");
- if (!gart_tlb_error)
- edac_mc_handle_ue_no_info(mci, "UE bit is set\n");
- }
+ if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
+ edac_mc_handle_ue_no_info(mci, "UE bit is set");
- if (regs->nbsh & K8_NBSH_PCC)
- amd64_mc_printk(mci, KERN_CRIT,
- "PCC (processor context corrupt) set\n");
-
- return 1;
}
-EXPORT_SYMBOL_GPL(amd64_process_error_info);
/*
* The main polling 'check' function, called FROM the edac core to perform the
@@ -2462,10 +2335,12 @@ EXPORT_SYMBOL_GPL(amd64_process_error_info);
*/
static void amd64_check(struct mem_ctl_info *mci)
{
- struct amd64_error_info_regs info;
+ struct err_regs regs;
- if (amd64_get_error_info(mci, &info))
- amd64_process_error_info(mci, &info, 1);
+ if (amd64_get_error_info(mci, &regs)) {
+ struct amd64_pvt *pvt = mci->pvt_info;
+ amd_decode_nb_mce(pvt->mc_node_id, &regs, 1);
+ }
}
/*
@@ -2779,9 +2654,9 @@ static int amd64_init_csrows(struct mem_ctl_info *mci)
static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
- const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id);
+ const struct cpumask *cmsk = topology_cpu_node_cpumask(pvt->mc_node_id);
int cpu, idx = 0, err = 0;
- struct msr msrs[cpumask_weight(cpumask)];
+ struct msr msrs[cpumask_weight(cmsk)];
u32 value;
u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
@@ -2805,16 +2680,16 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
value |= mask;
pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
- rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+ rdmsr_on_cpus(cmsk, K8_MSR_MCGCTL, msrs);
- for_each_cpu(cpu, cpumask) {
+ for_each_cpu(cpu, cmsk) {
if (msrs[idx].l & K8_MSR_MCGCTL_NBE)
set_bit(idx, &pvt->old_mcgctl);
msrs[idx].l |= K8_MSR_MCGCTL_NBE;
idx++;
}
- wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+ wrmsr_on_cpus(cmsk, K8_MSR_MCGCTL, msrs);
err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value);
if (err)
@@ -2855,9 +2730,9 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
{
- const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id);
+ const struct cpumask *cmsk = topology_cpu_node_cpumask(pvt->mc_node_id);
int cpu, idx = 0, err = 0;
- struct msr msrs[cpumask_weight(cpumask)];
+ struct msr msrs[cpumask_weight(cmsk)];
u32 value;
u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
@@ -2875,43 +2750,37 @@ static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
/* restore the NB Enable MCGCTL bit */
pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
- rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+ rdmsr_on_cpus(cmsk, K8_MSR_MCGCTL, msrs);
- for_each_cpu(cpu, cpumask) {
+ for_each_cpu(cpu, cmsk) {
msrs[idx].l &= ~K8_MSR_MCGCTL_NBE;
msrs[idx].l |=
test_bit(idx, &pvt->old_mcgctl) << K8_MSR_MCGCTL_NBE;
idx++;
}
- wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs);
+ wrmsr_on_cpus(cmsk, K8_MSR_MCGCTL, msrs);
}
-static void check_mcg_ctl(void *ret)
+static bool amd64_nb_mce_bank_enabled_on_node(int nid)
{
- u64 msr_val = 0;
- u8 nbe;
-
- rdmsrl(MSR_IA32_MCG_CTL, msr_val);
- nbe = msr_val & K8_MSR_MCGCTL_NBE;
+ const struct cpumask *mask = topology_cpu_node_cpumask(nid);
+ struct msr msrs[cpumask_weight(mask)];
+ int cpu, nbe;
- debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
- raw_smp_processor_id(), msr_val,
- (nbe ? "enabled" : "disabled"));
+ rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs);
- if (!nbe)
- *(int *)ret = 0;
-}
+ for_each_cpu(cpu, mask) {
+ nbe = msrs[cpu].l & K8_MSR_MCGCTL_NBE;
-/* check MCG_CTL on all the cpus on this node */
-static int amd64_mcg_ctl_enabled_on_cpus(const cpumask_t *mask)
-{
- int ret = 1;
- preempt_disable();
- smp_call_function_many(mask, check_mcg_ctl, &ret, 1);
- preempt_enable();
+ debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
+ cpu, msrs[cpu].q,
+ (nbe ? "enabled" : "disabled"));
- return ret;
+ if (!nbe)
+ return false;
+ }
+ return true;
}
/*
@@ -2920,66 +2789,45 @@ static int amd64_mcg_ctl_enabled_on_cpus(const cpumask_t *mask)
* the memory system completely. A command line option allows to force-enable
* hardware ECC later in amd64_enable_ecc_error_reporting().
*/
+static const char *ecc_warning =
+ "WARNING: ECC is disabled by BIOS. Module will NOT be loaded.\n"
+ " Either Enable ECC in the BIOS, or set 'ecc_enable_override'.\n"
+ " Also, use of the override can cause unknown side effects.\n";
+
static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
{
u32 value;
- int err = 0, ret = 0;
+ int err = 0, ret;
u8 ecc_enabled = 0;
+ bool nb_mce_en = false;
err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value);
if (err)
debugf0("Reading K8_NBCTL failed\n");
ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
+ if (!ecc_enabled)
+ amd64_printk(KERN_WARNING, "This node reports that Memory ECC "
+ "is currently disabled, set F3x%x[22] (%s).\n",
+ K8_NBCFG, pci_name(pvt->misc_f3_ctl));
+ else
+ amd64_printk(KERN_INFO, "ECC is enabled by BIOS.\n");
- ret = amd64_mcg_ctl_enabled_on_cpus(cpumask_of_node(pvt->mc_node_id));
-
- debugf0("K8_NBCFG=0x%x, DRAM ECC is %s\n", value,
- (value & K8_NBCFG_ECC_ENABLE ? "enabled" : "disabled"));
-
- if (!ecc_enabled || !ret) {
- if (!ecc_enabled) {
- amd64_printk(KERN_WARNING, "This node reports that "
- "Memory ECC is currently "
- "disabled.\n");
+ nb_mce_en = amd64_nb_mce_bank_enabled_on_node(pvt->mc_node_id);
+ if (!nb_mce_en)
+ amd64_printk(KERN_WARNING, "NB MCE bank disabled, set MSR "
+ "0x%08x[4] on node %d to enable.\n",
+ MSR_IA32_MCG_CTL, pvt->mc_node_id);
- amd64_printk(KERN_WARNING, "bit 0x%lx in register "
- "F3x%x of the MISC_CONTROL device (%s) "
- "should be enabled\n", K8_NBCFG_ECC_ENABLE,
- K8_NBCFG, pci_name(pvt->misc_f3_ctl));
- }
- if (!ret) {
- amd64_printk(KERN_WARNING, "bit 0x%016lx in MSR 0x%08x "
- "of node %d should be enabled\n",
- K8_MSR_MCGCTL_NBE, MSR_IA32_MCG_CTL,
- pvt->mc_node_id);
- }
+ ret = 0;
+ if (!ecc_enabled || !nb_mce_en) {
if (!ecc_enable_override) {
- amd64_printk(KERN_WARNING, "WARNING: ECC is NOT "
- "currently enabled by the BIOS. Module "
- "will NOT be loaded.\n"
- " Either Enable ECC in the BIOS, "
- "or use the 'ecc_enable_override' "
- "parameter.\n"
- " Might be a BIOS bug, if BIOS says "
- "ECC is enabled\n"
- " Use of the override can cause "
- "unknown side effects.\n");
+ amd64_printk(KERN_WARNING, "%s", ecc_warning);
ret = -ENODEV;
- } else
- /*
- * enable further driver loading if ECC enable is
- * overridden.
- */
- ret = 0;
- } else {
- amd64_printk(KERN_INFO,
- "ECC is enabled by BIOS, Proceeding "
- "with EDAC module initialization\n");
-
+ }
+ } else
/* CLEAR the override, since BIOS controlled it */
ecc_enable_override = 0;
- }
return ret;
}
@@ -3156,6 +3004,13 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
mci_lookup[node_id] = mci;
pvt_lookup[node_id] = NULL;
+
+ /* register stuff with EDAC MCE */
+ if (report_gart_errors)
+ amd_report_gart_errors(true);
+
+ amd_register_ecc_decoder(amd64_decode_bus_error);
+
return 0;
err_add_mc:
@@ -3222,6 +3077,10 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
mci_lookup[pvt->mc_node_id] = NULL;
+ /* unregister from EDAC MCE */
+ amd_report_gart_errors(false);
+ amd_unregister_ecc_decoder(amd64_decode_bus_error);
+
/* Free the EDAC CORE resources */
edac_mc_free(mci);
}
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index ba73015af8e4..8ea07e2715dc 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -72,6 +72,7 @@
#include <linux/edac.h>
#include <asm/msr.h>
#include "edac_core.h"
+#include "edac_mce_amd.h"
#define amd64_printk(level, fmt, arg...) \
edac_printk(level, "amd64", fmt, ##arg)
@@ -303,21 +304,9 @@ enum {
#define K8_NBSL 0x48
-#define EXTRACT_HIGH_SYNDROME(x) (((x) >> 24) & 0xff)
-#define EXTRACT_EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f)
-
/* Family F10h: Normalized Extended Error Codes */
#define F10_NBSL_EXT_ERR_RES 0x0
-#define F10_NBSL_EXT_ERR_CRC 0x1
-#define F10_NBSL_EXT_ERR_SYNC 0x2
-#define F10_NBSL_EXT_ERR_MST 0x3
-#define F10_NBSL_EXT_ERR_TGT 0x4
-#define F10_NBSL_EXT_ERR_GART 0x5
-#define F10_NBSL_EXT_ERR_RMW 0x6
-#define F10_NBSL_EXT_ERR_WDT 0x7
#define F10_NBSL_EXT_ERR_ECC 0x8
-#define F10_NBSL_EXT_ERR_DEV 0x9
-#define F10_NBSL_EXT_ERR_LINK_DATA 0xA
/* Next two are overloaded values */
#define F10_NBSL_EXT_ERR_LINK_PROTO 0xB
@@ -348,17 +337,6 @@ enum {
#define K8_NBSL_EXT_ERR_CHIPKILL_ECC 0x8
#define K8_NBSL_EXT_ERR_DRAM_PARITY 0xD
-#define EXTRACT_ERROR_CODE(x) ((x) & 0xffff)
-#define TEST_TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010)
-#define TEST_MEM_ERROR(x) (((x) & 0xFF00) == 0x0100)
-#define TEST_BUS_ERROR(x) (((x) & 0xF800) == 0x0800)
-#define EXTRACT_TT_CODE(x) (((x) >> 2) & 0x3)
-#define EXTRACT_II_CODE(x) (((x) >> 2) & 0x3)
-#define EXTRACT_LL_CODE(x) (((x) >> 0) & 0x3)
-#define EXTRACT_RRRR_CODE(x) (((x) >> 4) & 0xf)
-#define EXTRACT_TO_CODE(x) (((x) >> 8) & 0x1)
-#define EXTRACT_PP_CODE(x) (((x) >> 9) & 0x3)
-
/*
* The following are for BUS type errors AFTER values have been normalized by
* shifting right
@@ -368,28 +346,7 @@ enum {
#define K8_NBSL_PP_OBS 0x2
#define K8_NBSL_PP_GENERIC 0x3
-
-#define K8_NBSH 0x4C
-
-#define K8_NBSH_VALID_BIT BIT(31)
-#define K8_NBSH_OVERFLOW BIT(30)
-#define K8_NBSH_UNCORRECTED_ERR BIT(29)
-#define K8_NBSH_ERR_ENABLE BIT(28)
-#define K8_NBSH_MISC_ERR_VALID BIT(27)
-#define K8_NBSH_VALID_ERROR_ADDR BIT(26)
-#define K8_NBSH_PCC BIT(25)
-#define K8_NBSH_CECC BIT(14)
-#define K8_NBSH_UECC BIT(13)
-#define K8_NBSH_ERR_SCRUBER BIT(8)
-#define K8_NBSH_CORE3 BIT(3)
-#define K8_NBSH_CORE2 BIT(2)
-#define K8_NBSH_CORE1 BIT(1)
-#define K8_NBSH_CORE0 BIT(0)
-
-#define EXTRACT_LDT_LINK(x) (((x) >> 4) & 0x7)
#define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF)
-#define EXTRACT_LOW_SYNDROME(x) (((x) >> 15) & 0xff)
-
#define K8_NBEAL 0x50
#define K8_NBEAH 0x54
@@ -455,23 +412,6 @@ enum amd64_chipset_families {
F11_CPUS,
};
-/*
- * Structure to hold:
- *
- * 1) dynamically read status and error address HW registers
- * 2) sysfs entered values
- * 3) MCE values
- *
- * Depends on entry into the modules
- */
-struct amd64_error_info_regs {
- u32 nbcfg;
- u32 nbsh;
- u32 nbsl;
- u32 nbeah;
- u32 nbeal;
-};
-
/* Error injection control structure */
struct error_injection {
u32 section;
@@ -542,7 +482,7 @@ struct amd64_pvt {
u32 online_spare; /* On-Line spare Reg */
/* temp storage for when input is received from sysfs */
- struct amd64_error_info_regs ctl_error_info;
+ struct err_regs ctl_error_info;
/* place to store error injection parameters prior to issue */
struct error_injection injection;
@@ -601,11 +541,11 @@ struct low_ops {
int (*early_channel_count)(struct amd64_pvt *pvt);
u64 (*get_error_address)(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info);
+ struct err_regs *info);
void (*read_dram_base_limit)(struct amd64_pvt *pvt, int dram);
void (*read_dram_ctl_register)(struct amd64_pvt *pvt);
void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info,
+ struct err_regs *info,
u64 SystemAddr);
int (*dbam_map_to_pages)(struct amd64_pvt *pvt, int dram_map);
};
@@ -637,8 +577,5 @@ static inline struct low_ops *family_ops(int index)
#define F10_MIN_SCRUB_RATE_BITS 0x5
#define F11_MIN_SCRUB_RATE_BITS 0x6
-int amd64_process_error_info(struct mem_ctl_info *mci,
- struct amd64_error_info_regs *info,
- int handle_errors);
int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size);
diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c
index 0a41b248a4ad..59cf2cf6e11e 100644
--- a/drivers/edac/amd64_edac_dbg.c
+++ b/drivers/edac/amd64_edac_dbg.c
@@ -24,7 +24,7 @@ static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data,
/* Process the Mapping request */
/* TODO: Add race prevention */
- amd64_process_error_info(mci, &pvt->ctl_error_info, 1);
+ amd_decode_nb_mce(pvt->mc_node_id, &pvt->ctl_error_info, 1);
return count;
}
diff --git a/drivers/edac/amd64_edac_err_types.c b/drivers/edac/amd64_edac_err_types.c
deleted file mode 100644
index f212ff12a9d8..000000000000
--- a/drivers/edac/amd64_edac_err_types.c
+++ /dev/null
@@ -1,161 +0,0 @@
-#include "amd64_edac.h"
-
-/*
- * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only
- * for DDR2 DRAM mapping.
- */
-u32 revf_quad_ddr2_shift[] = {
- 0, /* 0000b NULL DIMM (128mb) */
- 28, /* 0001b 256mb */
- 29, /* 0010b 512mb */
- 29, /* 0011b 512mb */
- 29, /* 0100b 512mb */
- 30, /* 0101b 1gb */
- 30, /* 0110b 1gb */
- 31, /* 0111b 2gb */
- 31, /* 1000b 2gb */
- 32, /* 1001b 4gb */
- 32, /* 1010b 4gb */
- 33, /* 1011b 8gb */
- 0, /* 1100b future */
- 0, /* 1101b future */
- 0, /* 1110b future */
- 0 /* 1111b future */
-};
-
-/*
- * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
- * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
- * or higher value'.
- *
- *FIXME: Produce a better mapping/linearisation.
- */
-
-struct scrubrate scrubrates[] = {
- { 0x01, 1600000000UL},
- { 0x02, 800000000UL},
- { 0x03, 400000000UL},
- { 0x04, 200000000UL},
- { 0x05, 100000000UL},
- { 0x06, 50000000UL},
- { 0x07, 25000000UL},
- { 0x08, 12284069UL},
- { 0x09, 6274509UL},
- { 0x0A, 3121951UL},
- { 0x0B, 1560975UL},
- { 0x0C, 781440UL},
- { 0x0D, 390720UL},
- { 0x0E, 195300UL},
- { 0x0F, 97650UL},
- { 0x10, 48854UL},
- { 0x11, 24427UL},
- { 0x12, 12213UL},
- { 0x13, 6101UL},
- { 0x14, 3051UL},
- { 0x15, 1523UL},
- { 0x16, 761UL},
- { 0x00, 0UL}, /* scrubbing off */
-};
-
-/*
- * string representation for the different MCA reported error types, see F3x48
- * or MSR0000_0411.
- */
-const char *tt_msgs[] = { /* transaction type */
- "instruction",
- "data",
- "generic",
- "reserved"
-};
-
-const char *ll_msgs[] = { /* cache level */
- "L0",
- "L1",
- "L2",
- "L3/generic"
-};
-
-const char *rrrr_msgs[] = {
- "generic",
- "generic read",
- "generic write",
- "data read",
- "data write",
- "inst fetch",
- "prefetch",
- "evict",
- "snoop",
- "reserved RRRR= 9",
- "reserved RRRR= 10",
- "reserved RRRR= 11",
- "reserved RRRR= 12",
- "reserved RRRR= 13",
- "reserved RRRR= 14",
- "reserved RRRR= 15"
-};
-
-const char *pp_msgs[] = { /* participating processor */
- "local node originated (SRC)",
- "local node responded to request (RES)",
- "local node observed as 3rd party (OBS)",
- "generic"
-};
-
-const char *to_msgs[] = {
- "no timeout",
- "timed out"
-};
-
-const char *ii_msgs[] = { /* memory or i/o */
- "mem access",
- "reserved",
- "i/o access",
- "generic"
-};
-
-/* Map the 5 bits of Extended Error code to the string table. */
-const char *ext_msgs[] = { /* extended error */
- "K8 ECC error/F10 reserved", /* 0_0000b */
- "CRC error", /* 0_0001b */
- "sync error", /* 0_0010b */
- "mst abort", /* 0_0011b */
- "tgt abort", /* 0_0100b */
- "GART error", /* 0_0101b */
- "RMW error", /* 0_0110b */
- "Wdog timer error", /* 0_0111b */
- "F10-ECC/K8-Chipkill error", /* 0_1000b */
- "DEV Error", /* 0_1001b */
- "Link Data error", /* 0_1010b */
- "Link or L3 Protocol error", /* 0_1011b */
- "NB Array error", /* 0_1100b */
- "DRAM Parity error", /* 0_1101b */
- "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */
- "Res 0x0ff error", /* 0_1111b */
- "Res 0x100 error", /* 1_0000b */
- "Res 0x101 error", /* 1_0001b */
- "Res 0x102 error", /* 1_0010b */
- "Res 0x103 error", /* 1_0011b */
- "Res 0x104 error", /* 1_0100b */
- "Res 0x105 error", /* 1_0101b */
- "Res 0x106 error", /* 1_0110b */
- "Res 0x107 error", /* 1_0111b */
- "Res 0x108 error", /* 1_1000b */
- "Res 0x109 error", /* 1_1001b */
- "Res 0x10A error", /* 1_1010b */
- "Res 0x10B error", /* 1_1011b */
- "L3 Cache Data error", /* 1_1100b */
- "L3 CacheTag error", /* 1_1101b */
- "L3 Cache LRU error", /* 1_1110b */
- "Res 0x1FF error" /* 1_1111b */
-};
-
-const char *htlink_msgs[] = {
- "none",
- "1",
- "2",
- "1 2",
- "3",
- "1 3",
- "2 3",
- "1 2 3"
-};
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 871c13b4c148..12f355cafdbe 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -286,7 +286,7 @@ enum scrub_type {
* is irrespective of the memory devices being mounted
* on both sides of the memory stick.
*
- * Socket set: All of the memory sticks that are required for for
+ * Socket set: All of the memory sticks that are required for
* a single memory access or all of the memory sticks
* spanned by a chip-select row. A single socket set
* has two chip-select rows and if double-sided sticks
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
new file mode 100644
index 000000000000..316ac7aa9d9a
--- /dev/null
+++ b/drivers/edac/edac_mce_amd.c
@@ -0,0 +1,422 @@
+#include <linux/module.h>
+#include "edac_mce_amd.h"
+
+static bool report_gart_errors;
+static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
+
+void amd_report_gart_errors(bool v)
+{
+ report_gart_errors = v;
+}
+EXPORT_SYMBOL_GPL(amd_report_gart_errors);
+
+void amd_register_ecc_decoder(void (*f)(int, struct err_regs *))
+{
+ nb_bus_decoder = f;
+}
+EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
+
+void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *))
+{
+ if (nb_bus_decoder) {
+ WARN_ON(nb_bus_decoder != f);
+
+ nb_bus_decoder = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
+
+/*
+ * string representation for the different MCA reported error types, see F3x48
+ * or MSR0000_0411.
+ */
+const char *tt_msgs[] = { /* transaction type */
+ "instruction",
+ "data",
+ "generic",
+ "reserved"
+};
+EXPORT_SYMBOL_GPL(tt_msgs);
+
+const char *ll_msgs[] = { /* cache level */
+ "L0",
+ "L1",
+ "L2",
+ "L3/generic"
+};
+EXPORT_SYMBOL_GPL(ll_msgs);
+
+const char *rrrr_msgs[] = {
+ "generic",
+ "generic read",
+ "generic write",
+ "data read",
+ "data write",
+ "inst fetch",
+ "prefetch",
+ "evict",
+ "snoop",
+ "reserved RRRR= 9",
+ "reserved RRRR= 10",
+ "reserved RRRR= 11",
+ "reserved RRRR= 12",
+ "reserved RRRR= 13",
+ "reserved RRRR= 14",
+ "reserved RRRR= 15"
+};
+EXPORT_SYMBOL_GPL(rrrr_msgs);
+
+const char *pp_msgs[] = { /* participating processor */
+ "local node originated (SRC)",
+ "local node responded to request (RES)",
+ "local node observed as 3rd party (OBS)",
+ "generic"
+};
+EXPORT_SYMBOL_GPL(pp_msgs);
+
+const char *to_msgs[] = {
+ "no timeout",
+ "timed out"
+};
+EXPORT_SYMBOL_GPL(to_msgs);
+
+const char *ii_msgs[] = { /* memory or i/o */
+ "mem access",
+ "reserved",
+ "i/o access",
+ "generic"
+};
+EXPORT_SYMBOL_GPL(ii_msgs);
+
+/*
+ * Map the 4 or 5 (family-specific) bits of Extended Error code to the
+ * string table.
+ */
+const char *ext_msgs[] = {
+ "K8 ECC error", /* 0_0000b */
+ "CRC error on link", /* 0_0001b */
+ "Sync error packets on link", /* 0_0010b */
+ "Master Abort during link operation", /* 0_0011b */
+ "Target Abort during link operation", /* 0_0100b */
+ "Invalid GART PTE entry during table walk", /* 0_0101b */
+ "Unsupported atomic RMW command received", /* 0_0110b */
+ "WDT error: NB transaction timeout", /* 0_0111b */
+ "ECC/ChipKill ECC error", /* 0_1000b */
+ "SVM DEV Error", /* 0_1001b */
+ "Link Data error", /* 0_1010b */
+ "Link/L3/Probe Filter Protocol error", /* 0_1011b */
+ "NB Internal Arrays Parity error", /* 0_1100b */
+ "DRAM Address/Control Parity error", /* 0_1101b */
+ "Link Transmission error", /* 0_1110b */
+ "GART/DEV Table Walk Data error" /* 0_1111b */
+ "Res 0x100 error", /* 1_0000b */
+ "Res 0x101 error", /* 1_0001b */
+ "Res 0x102 error", /* 1_0010b */
+ "Res 0x103 error", /* 1_0011b */
+ "Res 0x104 error", /* 1_0100b */
+ "Res 0x105 error", /* 1_0101b */
+ "Res 0x106 error", /* 1_0110b */
+ "Res 0x107 error", /* 1_0111b */
+ "Res 0x108 error", /* 1_1000b */
+ "Res 0x109 error", /* 1_1001b */
+ "Res 0x10A error", /* 1_1010b */
+ "Res 0x10B error", /* 1_1011b */
+ "ECC error in L3 Cache Data", /* 1_1100b */
+ "L3 Cache Tag error", /* 1_1101b */
+ "L3 Cache LRU Parity error", /* 1_1110b */
+ "Probe Filter error" /* 1_1111b */
+};
+EXPORT_SYMBOL_GPL(ext_msgs);
+
+static void amd_decode_dc_mce(u64 mc0_status)
+{
+ u32 ec = mc0_status & 0xffff;
+ u32 xec = (mc0_status >> 16) & 0xf;
+
+ pr_emerg(" Data Cache Error");
+
+ if (xec == 1 && TLB_ERROR(ec))
+ pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
+ else if (xec == 0) {
+ if (mc0_status & (1ULL << 40))
+ pr_cont(" during Data Scrub.\n");
+ else if (TLB_ERROR(ec))
+ pr_cont(": %s TLB parity error.\n", LL_MSG(ec));
+ else if (MEM_ERROR(ec)) {
+ u8 ll = ec & 0x3;
+ u8 tt = (ec >> 2) & 0x3;
+ u8 rrrr = (ec >> 4) & 0xf;
+
+ /* see F10h BKDG (31116), Table 92. */
+ if (ll == 0x1) {
+ if (tt != 0x1)
+ goto wrong_dc_mce;
+
+ pr_cont(": Data/Tag %s error.\n", RRRR_MSG(ec));
+
+ } else if (ll == 0x2 && rrrr == 0x3)
+ pr_cont(" during L1 linefill from L2.\n");
+ else
+ goto wrong_dc_mce;
+ } else if (BUS_ERROR(ec) && boot_cpu_data.x86 == 0xf)
+ pr_cont(" during system linefill.\n");
+ else
+ goto wrong_dc_mce;
+ } else
+ goto wrong_dc_mce;
+
+ return;
+
+wrong_dc_mce:
+ pr_warning("Corrupted DC MCE info?\n");
+}
+
+static void amd_decode_ic_mce(u64 mc1_status)
+{
+ u32 ec = mc1_status & 0xffff;
+ u32 xec = (mc1_status >> 16) & 0xf;
+
+ pr_emerg(" Instruction Cache Error");
+
+ if (xec == 1 && TLB_ERROR(ec))
+ pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
+ else if (xec == 0) {
+ if (TLB_ERROR(ec))
+ pr_cont(": %s TLB Parity error.\n", LL_MSG(ec));
+ else if (BUS_ERROR(ec)) {
+ if (boot_cpu_data.x86 == 0xf &&
+ (mc1_status & (1ULL << 58)))
+ pr_cont(" during system linefill.\n");
+ else
+ pr_cont(" during attempted NB data read.\n");
+ } else if (MEM_ERROR(ec)) {
+ u8 ll = ec & 0x3;
+ u8 rrrr = (ec >> 4) & 0xf;
+
+ if (ll == 0x2)
+ pr_cont(" during a linefill from L2.\n");
+ else if (ll == 0x1) {
+
+ switch (rrrr) {
+ case 0x5:
+ pr_cont(": Parity error during "
+ "data load.\n");
+ break;
+
+ case 0x7:
+ pr_cont(": Copyback Parity/Victim"
+ " error.\n");
+ break;
+
+ case 0x8:
+ pr_cont(": Tag Snoop error.\n");
+ break;
+
+ default:
+ goto wrong_ic_mce;
+ break;
+ }
+ }
+ } else
+ goto wrong_ic_mce;
+ } else
+ goto wrong_ic_mce;
+
+ return;
+
+wrong_ic_mce:
+ pr_warning("Corrupted IC MCE info?\n");
+}
+
+static void amd_decode_bu_mce(u64 mc2_status)
+{
+ u32 ec = mc2_status & 0xffff;
+ u32 xec = (mc2_status >> 16) & 0xf;
+
+ pr_emerg(" Bus Unit Error");
+
+ if (xec == 0x1)
+ pr_cont(" in the write data buffers.\n");
+ else if (xec == 0x3)
+ pr_cont(" in the victim data buffers.\n");
+ else if (xec == 0x2 && MEM_ERROR(ec))
+ pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
+ else if (xec == 0x0) {
+ if (TLB_ERROR(ec))
+ pr_cont(": %s error in a Page Descriptor Cache or "
+ "Guest TLB.\n", TT_MSG(ec));
+ else if (BUS_ERROR(ec))
+ pr_cont(": %s/ECC error in data read from NB: %s.\n",
+ RRRR_MSG(ec), PP_MSG(ec));
+ else if (MEM_ERROR(ec)) {
+ u8 rrrr = (ec >> 4) & 0xf;
+
+ if (rrrr >= 0x7)
+ pr_cont(": %s error during data copyback.\n",
+ RRRR_MSG(ec));
+ else if (rrrr <= 0x1)
+ pr_cont(": %s parity/ECC error during data "
+ "access from L2.\n", RRRR_MSG(ec));
+ else
+ goto wrong_bu_mce;
+ } else
+ goto wrong_bu_mce;
+ } else
+ goto wrong_bu_mce;
+
+ return;
+
+wrong_bu_mce:
+ pr_warning("Corrupted BU MCE info?\n");
+}
+
+static void amd_decode_ls_mce(u64 mc3_status)
+{
+ u32 ec = mc3_status & 0xffff;
+ u32 xec = (mc3_status >> 16) & 0xf;
+
+ pr_emerg(" Load Store Error");
+
+ if (xec == 0x0) {
+ u8 rrrr = (ec >> 4) & 0xf;
+
+ if (!BUS_ERROR(ec) || (rrrr != 0x3 && rrrr != 0x4))
+ goto wrong_ls_mce;
+
+ pr_cont(" during %s.\n", RRRR_MSG(ec));
+ }
+ return;
+
+wrong_ls_mce:
+ pr_warning("Corrupted LS MCE info?\n");
+}
+
+void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors)
+{
+ u32 ec = ERROR_CODE(regs->nbsl);
+ u32 xec = EXT_ERROR_CODE(regs->nbsl);
+
+ if (!handle_errors)
+ return;
+
+ pr_emerg(" Northbridge Error, node %d", node_id);
+
+ /*
+ * F10h, revD can disable ErrCpu[3:0] so check that first and also the
+ * value encoding has changed so interpret those differently
+ */
+ if ((boot_cpu_data.x86 == 0x10) &&
+ (boot_cpu_data.x86_model > 8)) {
+ if (regs->nbsh & K8_NBSH_ERR_CPU_VAL)
+ pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf));
+ } else {
+ pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf)));
+ }
+
+
+ pr_emerg("%s.\n", EXT_ERR_MSG(xec));
+
+ if (BUS_ERROR(ec) && nb_bus_decoder)
+ nb_bus_decoder(node_id, regs);
+}
+EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
+
+static void amd_decode_fr_mce(u64 mc5_status)
+{
+ /* we have only one error signature so match all fields at once. */
+ if ((mc5_status & 0xffff) == 0x0f0f)
+ pr_emerg(" FR Error: CPU Watchdog timer expire.\n");
+ else
+ pr_warning("Corrupted FR MCE info?\n");
+}
+
+static inline void amd_decode_err_code(unsigned int ec)
+{
+ if (TLB_ERROR(ec)) {
+ /*
+ * GART errors are intended to help graphics driver developers
+ * to detect bad GART PTEs. It is recommended by AMD to disable
+ * GART table walk error reporting by default[1] (currently
+ * being disabled in mce_cpu_quirks()) and according to the
+ * comment in mce_cpu_quirks(), such GART errors can be
+ * incorrectly triggered. We may see these errors anyway and
+ * unless requested by the user, they won't be reported.
+ *
+ * [1] section 13.10.1 on BIOS and Kernel Developers Guide for
+ * AMD NPT family 0Fh processors
+ */
+ if (!report_gart_errors)
+ return;
+
+ pr_emerg(" Transaction: %s, Cache Level %s\n",
+ TT_MSG(ec), LL_MSG(ec));
+ } else if (MEM_ERROR(ec)) {
+ pr_emerg(" Transaction: %s, Type: %s, Cache Level: %s",
+ RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
+ } else if (BUS_ERROR(ec)) {
+ pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, "
+ "Participating Processor: %s\n",
+ RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
+ PP_MSG(ec));
+ } else
+ pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
+}
+
+void decode_mce(struct mce *m)
+{
+ struct err_regs regs;
+ int node, ecc;
+
+ pr_emerg("MC%d_STATUS: ", m->bank);
+
+ pr_cont("%sorrected error, report: %s, MiscV: %svalid, "
+ "CPU context corrupt: %s",
+ ((m->status & MCI_STATUS_UC) ? "Unc" : "C"),
+ ((m->status & MCI_STATUS_EN) ? "yes" : "no"),
+ ((m->status & MCI_STATUS_MISCV) ? "" : "in"),
+ ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
+
+ /* do the two bits[14:13] together */
+ ecc = m->status & (3ULL << 45);
+ if (ecc)
+ pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
+
+ pr_cont("\n");
+
+ switch (m->bank) {
+ case 0:
+ amd_decode_dc_mce(m->status);
+ break;
+
+ case 1:
+ amd_decode_ic_mce(m->status);
+ break;
+
+ case 2:
+ amd_decode_bu_mce(m->status);
+ break;
+
+ case 3:
+ amd_decode_ls_mce(m->status);
+ break;
+
+ case 4:
+ regs.nbsl = (u32) m->status;
+ regs.nbsh = (u32)(m->status >> 32);
+ regs.nbeal = (u32) m->addr;
+ regs.nbeah = (u32)(m->addr >> 32);
+ node = topology_cpu_node_id(m->extcpu);
+
+ amd_decode_nb_mce(node, &regs, 1);
+ break;
+
+ case 5:
+ amd_decode_fr_mce(m->status);
+ break;
+
+ default:
+ break;
+ }
+
+ amd_decode_err_code(m->status & 0xffff);
+}
diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/edac_mce_amd.h
new file mode 100644
index 000000000000..df23ee065f79
--- /dev/null
+++ b/drivers/edac/edac_mce_amd.h
@@ -0,0 +1,69 @@
+#ifndef _EDAC_MCE_AMD_H
+#define _EDAC_MCE_AMD_H
+
+#include <asm/mce.h>
+
+#define ERROR_CODE(x) ((x) & 0xffff)
+#define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f)
+#define EXT_ERR_MSG(x) ext_msgs[EXT_ERROR_CODE(x)]
+
+#define LOW_SYNDROME(x) (((x) >> 15) & 0xff)
+#define HIGH_SYNDROME(x) (((x) >> 24) & 0xff)
+
+#define TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010)
+#define MEM_ERROR(x) (((x) & 0xFF00) == 0x0100)
+#define BUS_ERROR(x) (((x) & 0xF800) == 0x0800)
+
+#define TT(x) (((x) >> 2) & 0x3)
+#define TT_MSG(x) tt_msgs[TT(x)]
+#define II(x) (((x) >> 2) & 0x3)
+#define II_MSG(x) ii_msgs[II(x)]
+#define LL(x) (((x) >> 0) & 0x3)
+#define LL_MSG(x) ll_msgs[LL(x)]
+#define RRRR(x) (((x) >> 4) & 0xf)
+#define RRRR_MSG(x) rrrr_msgs[RRRR(x)]
+#define TO(x) (((x) >> 8) & 0x1)
+#define TO_MSG(x) to_msgs[TO(x)]
+#define PP(x) (((x) >> 9) & 0x3)
+#define PP_MSG(x) pp_msgs[PP(x)]
+
+#define K8_NBSH 0x4C
+
+#define K8_NBSH_VALID_BIT BIT(31)
+#define K8_NBSH_OVERFLOW BIT(30)
+#define K8_NBSH_UC_ERR BIT(29)
+#define K8_NBSH_ERR_EN BIT(28)
+#define K8_NBSH_MISCV BIT(27)
+#define K8_NBSH_VALID_ERROR_ADDR BIT(26)
+#define K8_NBSH_PCC BIT(25)
+#define K8_NBSH_ERR_CPU_VAL BIT(24)
+#define K8_NBSH_CECC BIT(14)
+#define K8_NBSH_UECC BIT(13)
+#define K8_NBSH_ERR_SCRUBER BIT(8)
+
+extern const char *tt_msgs[];
+extern const char *ll_msgs[];
+extern const char *rrrr_msgs[];
+extern const char *pp_msgs[];
+extern const char *to_msgs[];
+extern const char *ii_msgs[];
+extern const char *ext_msgs[];
+
+/*
+ * relevant NB regs
+ */
+struct err_regs {
+ u32 nbcfg;
+ u32 nbsh;
+ u32 nbsl;
+ u32 nbeah;
+ u32 nbeal;
+};
+
+
+void amd_report_gart_errors(bool);
+void amd_register_ecc_decoder(void (*f)(int, struct err_regs *));
+void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *));
+void amd_decode_nb_mce(int, struct err_regs *, int);
+
+#endif /* _EDAC_MCE_AMD_H */
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index 2406c2ce2844..d4ec60593176 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -30,7 +30,7 @@
/* Intel X38 register addresses - device 0 function 0 - DRAM Controller */
#define X38_MCHBAR_LOW 0x48 /* MCH Memory Mapped Register BAR */
-#define X38_MCHBAR_HIGH 0x4b
+#define X38_MCHBAR_HIGH 0x4c
#define X38_MCHBAR_MASK 0xfffffc000ULL /* bits 35:14 */
#define X38_MMR_WINDOW_SIZE 16384
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 18d65fb42ee7..b24ccb546e59 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -237,6 +237,22 @@ static ssize_t host_control_on_shutdown_store(struct device *dev,
return count;
}
+static void generate_smi(void *_smi_cmd)
+{
+ struct smi_cmd *smi_cmd = _smi_cmd;
+
+ /* generate SMI */
+ asm volatile (
+ "outb %b0,%w1"
+ : /* no output args */
+ : "a" (smi_cmd->command_code),
+ "d" (smi_cmd->command_address),
+ "b" (smi_cmd->ebx),
+ "c" (smi_cmd->ecx)
+ : "memory"
+ );
+}
+
/**
* dcdbas_smi_request: generate SMI request
*
@@ -244,9 +260,6 @@ static ssize_t host_control_on_shutdown_store(struct device *dev,
*/
int dcdbas_smi_request(struct smi_cmd *smi_cmd)
{
- cpumask_var_t old_mask;
- int ret = 0;
-
if (smi_cmd->magic != SMI_CMD_MAGIC) {
dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
__func__);
@@ -254,35 +267,9 @@ int dcdbas_smi_request(struct smi_cmd *smi_cmd)
}
/* SMI requires CPU 0 */
- if (!alloc_cpumask_var(&old_mask, GFP_KERNEL))
- return -ENOMEM;
-
- cpumask_copy(old_mask, &current->cpus_allowed);
- set_cpus_allowed_ptr(current, cpumask_of(0));
- if (smp_processor_id() != 0) {
- dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
- __func__);
- ret = -EBUSY;
- goto out;
- }
-
- /* generate SMI */
- asm volatile (
- "outb %b0,%w1"
- : /* no output args */
- : "a" (smi_cmd->command_code),
- "d" (smi_cmd->command_address),
- "b" (smi_cmd->ebx),
- "c" (smi_cmd->ecx)
- : "memory"
- );
-
-out:
- set_cpus_allowed_ptr(current, old_mask);
- free_cpumask_var(old_mask);
- return ret;
+ smp_call_function_single(0, generate_smi, smi_cmd, 1);
+ return 0;
}
-
/**
* smi_request_store:
*
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 80cc6d06d61b..bbcb2e22675b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -61,6 +61,10 @@
/* use +hsync +vsync for detailed mode */
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
+#define LEVEL_DMT 0
+#define LEVEL_GTF 1
+#define LEVEL_CVT 2
+
static struct edid_quirk {
char *vendor;
int product_id;
@@ -240,25 +244,31 @@ static void edid_fixup_preferred(struct drm_connector *connector,
/**
* drm_mode_std - convert standard mode info (width, height, refresh) into mode
* @t: standard timing params
+ * @timing_level: standard timing level
*
* Take the standard timing params (in this case width, aspect, and refresh)
- * and convert them into a real mode using CVT.
+ * and convert them into a real mode using CVT/GTF/DMT.
*
* Punts for now, but should eventually use the FB layer's CVT based mode
* generation code.
*/
struct drm_display_mode *drm_mode_std(struct drm_device *dev,
- struct std_timing *t)
+ struct std_timing *t,
+ int timing_level)
{
struct drm_display_mode *mode;
- int hsize = t->hsize * 8 + 248, vsize;
+ int hsize, vsize;
+ int vrefresh_rate;
unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
>> EDID_TIMING_ASPECT_SHIFT;
-
- mode = drm_mode_create(dev);
- if (!mode)
- return NULL;
-
+ unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
+ >> EDID_TIMING_VFREQ_SHIFT;
+
+ /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */
+ hsize = t->hsize * 8 + 248;
+ /* vrefresh_rate = vfreq + 60 */
+ vrefresh_rate = vfreq + 60;
+ /* the vdisplay is calculated based on the aspect ratio */
if (aspect_ratio == 0)
vsize = (hsize * 10) / 16;
else if (aspect_ratio == 1)
@@ -268,8 +278,23 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
else
vsize = (hsize * 9) / 16;
- drm_mode_set_name(mode);
-
+ mode = NULL;
+ switch (timing_level) {
+ case LEVEL_DMT:
+ mode = drm_mode_create(dev);
+ if (mode) {
+ mode->hdisplay = hsize;
+ mode->vdisplay = vsize;
+ drm_mode_set_name(mode);
+ }
+ break;
+ case LEVEL_GTF:
+ mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+ break;
+ case LEVEL_CVT:
+ mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+ break;
+ }
return mode;
}
@@ -451,6 +476,19 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
return modes;
}
+/**
+ * stanard_timing_level - get std. timing level(CVT/GTF/DMT)
+ * @edid: EDID block to scan
+ */
+static int standard_timing_level(struct edid *edid)
+{
+ if (edid->revision >= 2) {
+ if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
+ return LEVEL_CVT;
+ return LEVEL_GTF;
+ }
+ return LEVEL_DMT;
+}
/**
* add_standard_modes - get std. modes from EDID and add them
@@ -463,6 +501,9 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
{
struct drm_device *dev = connector->dev;
int i, modes = 0;
+ int timing_level;
+
+ timing_level = standard_timing_level(edid);
for (i = 0; i < EDID_STD_TIMINGS; i++) {
struct std_timing *t = &edid->standard_timings[i];
@@ -472,7 +513,8 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
if (t->hsize == 1 && t->vfreq_aspect == 1)
continue;
- newmode = drm_mode_std(dev, &edid->standard_timings[i]);
+ newmode = drm_mode_std(dev, &edid->standard_timings[i],
+ timing_level);
if (newmode) {
drm_mode_probed_add(connector, newmode);
modes++;
@@ -496,6 +538,9 @@ static int add_detailed_info(struct drm_connector *connector,
{
struct drm_device *dev = connector->dev;
int i, j, modes = 0;
+ int timing_level;
+
+ timing_level = standard_timing_level(edid);
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
struct detailed_timing *timing = &edid->detailed_timings[i];
@@ -541,7 +586,8 @@ static int add_detailed_info(struct drm_connector *connector,
struct drm_display_mode *newmode;
std = &data->data.timings[j];
- newmode = drm_mode_std(dev, std);
+ newmode = drm_mode_std(dev, std,
+ timing_level);
if (newmode) {
drm_mode_probed_add(connector, newmode);
modes++;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 54f492a488a9..fd489d76fbbc 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -8,6 +8,8 @@
* Copyright © 2007 Dave Airlie
* Copyright © 2007-2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright 2005-2006 Luc Verhaegen
+ * Copyright (c) 2001, Andy Ritger aritger@nvidia.com
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -62,6 +64,420 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
EXPORT_SYMBOL(drm_mode_debug_printmodeline);
/**
+ * drm_cvt_mode -create a modeline based on CVT algorithm
+ * @dev: DRM device
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @vrefresh : vrefresh rate
+ * @reduced : Whether the GTF calculation is simplified
+ * @interlaced:Whether the interlace is supported
+ *
+ * LOCKING:
+ * none.
+ *
+ * return the modeline based on CVT algorithm
+ *
+ * This function is called to generate the modeline based on CVT algorithm
+ * according to the hdisplay, vdisplay, vrefresh.
+ * It is based from the VESA(TM) Coordinated Video Timing Generator by
+ * Graham Loveridge April 9, 2003 available at
+ * http://www.vesa.org/public/CVT/CVTd6r1.xls
+ *
+ * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
+ * What I have done is to translate it by using integer calculation.
+ */
+#define HV_FACTOR 1000
+struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
+ int vdisplay, int vrefresh,
+ bool reduced, bool interlaced)
+{
+ /* 1) top/bottom margin size (% of height) - default: 1.8, */
+#define CVT_MARGIN_PERCENTAGE 18
+ /* 2) character cell horizontal granularity (pixels) - default 8 */
+#define CVT_H_GRANULARITY 8
+ /* 3) Minimum vertical porch (lines) - default 3 */
+#define CVT_MIN_V_PORCH 3
+ /* 4) Minimum number of vertical back porch lines - default 6 */
+#define CVT_MIN_V_BPORCH 6
+ /* Pixel Clock step (kHz) */
+#define CVT_CLOCK_STEP 250
+ struct drm_display_mode *drm_mode;
+ bool margins = false;
+ unsigned int vfieldrate, hperiod;
+ int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
+ int interlace;
+
+ /* allocate the drm_display_mode structure. If failure, we will
+ * return directly
+ */
+ drm_mode = drm_mode_create(dev);
+ if (!drm_mode)
+ return NULL;
+
+ /* the CVT default refresh rate is 60Hz */
+ if (!vrefresh)
+ vrefresh = 60;
+
+ /* the required field fresh rate */
+ if (interlaced)
+ vfieldrate = vrefresh * 2;
+ else
+ vfieldrate = vrefresh;
+
+ /* horizontal pixels */
+ hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
+
+ /* determine the left&right borders */
+ hmargin = 0;
+ if (margins) {
+ hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
+ hmargin -= hmargin % CVT_H_GRANULARITY;
+ }
+ /* find the total active pixels */
+ drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
+
+ /* find the number of lines per field */
+ if (interlaced)
+ vdisplay_rnd = vdisplay / 2;
+ else
+ vdisplay_rnd = vdisplay;
+
+ /* find the top & bottom borders */
+ vmargin = 0;
+ if (margins)
+ vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
+
+ drm_mode->vdisplay = vdisplay_rnd + 2 * vmargin;
+
+ /* Interlaced */
+ if (interlaced)
+ interlace = 1;
+ else
+ interlace = 0;
+
+ /* Determine VSync Width from aspect ratio */
+ if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
+ vsync = 4;
+ else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
+ vsync = 5;
+ else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
+ vsync = 6;
+ else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
+ vsync = 7;
+ else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
+ vsync = 7;
+ else /* custom */
+ vsync = 10;
+
+ if (!reduced) {
+ /* simplify the GTF calculation */
+ /* 4) Minimum time of vertical sync + back porch interval (µs)
+ * default 550.0
+ */
+ int tmp1, tmp2;
+#define CVT_MIN_VSYNC_BP 550
+ /* 3) Nominal HSync width (% of line period) - default 8 */
+#define CVT_HSYNC_PERCENTAGE 8
+ unsigned int hblank_percentage;
+ int vsyncandback_porch, vback_porch, hblank;
+
+ /* estimated the horizontal period */
+ tmp1 = HV_FACTOR * 1000000 -
+ CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
+ tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
+ interlace;
+ hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
+
+ tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
+ /* 9. Find number of lines in sync + backporch */
+ if (tmp1 < (vsync + CVT_MIN_V_PORCH))
+ vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
+ else
+ vsyncandback_porch = tmp1;
+ /* 10. Find number of lines in back porch */
+ vback_porch = vsyncandback_porch - vsync;
+ drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
+ vsyncandback_porch + CVT_MIN_V_PORCH;
+ /* 5) Definition of Horizontal blanking time limitation */
+ /* Gradient (%/kHz) - default 600 */
+#define CVT_M_FACTOR 600
+ /* Offset (%) - default 40 */
+#define CVT_C_FACTOR 40
+ /* Blanking time scaling factor - default 128 */
+#define CVT_K_FACTOR 128
+ /* Scaling factor weighting - default 20 */
+#define CVT_J_FACTOR 20
+#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
+#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
+ CVT_J_FACTOR)
+ /* 12. Find ideal blanking duty cycle from formula */
+ hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
+ hperiod / 1000;
+ /* 13. Blanking time */
+ if (hblank_percentage < 20 * HV_FACTOR)
+ hblank_percentage = 20 * HV_FACTOR;
+ hblank = drm_mode->hdisplay * hblank_percentage /
+ (100 * HV_FACTOR - hblank_percentage);
+ hblank -= hblank % (2 * CVT_H_GRANULARITY);
+ /* 14. find the total pixes per line */
+ drm_mode->htotal = drm_mode->hdisplay + hblank;
+ drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
+ drm_mode->hsync_start = drm_mode->hsync_end -
+ (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
+ drm_mode->hsync_start += CVT_H_GRANULARITY -
+ drm_mode->hsync_start % CVT_H_GRANULARITY;
+ /* fill the Vsync values */
+ drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
+ drm_mode->vsync_end = drm_mode->vsync_start + vsync;
+ } else {
+ /* Reduced blanking */
+ /* Minimum vertical blanking interval time (µs)- default 460 */
+#define CVT_RB_MIN_VBLANK 460
+ /* Fixed number of clocks for horizontal sync */
+#define CVT_RB_H_SYNC 32
+ /* Fixed number of clocks for horizontal blanking */
+#define CVT_RB_H_BLANK 160
+ /* Fixed number of lines for vertical front porch - default 3*/
+#define CVT_RB_VFPORCH 3
+ int vbilines;
+ int tmp1, tmp2;
+ /* 8. Estimate Horizontal period. */
+ tmp1 = HV_FACTOR * 1000000 -
+ CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
+ tmp2 = vdisplay_rnd + 2 * vmargin;
+ hperiod = tmp1 / (tmp2 * vfieldrate);
+ /* 9. Find number of lines in vertical blanking */
+ vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
+ /* 10. Check if vertical blanking is sufficient */
+ if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
+ vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
+ /* 11. Find total number of lines in vertical field */
+ drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
+ /* 12. Find total number of pixels in a line */
+ drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
+ /* Fill in HSync values */
+ drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
+ drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC;
+ }
+ /* 15/13. Find pixel clock frequency (kHz for xf86) */
+ drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod;
+ drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP;
+ /* 18/16. Find actual vertical frame frequency */
+ /* ignore - just set the mode flag for interlaced */
+ if (interlaced)
+ drm_mode->vtotal *= 2;
+ /* Fill the mode line name */
+ drm_mode_set_name(drm_mode);
+ if (reduced)
+ drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
+ DRM_MODE_FLAG_NVSYNC);
+ else
+ drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
+ DRM_MODE_FLAG_NHSYNC);
+ if (interlaced)
+ drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+ return drm_mode;
+}
+EXPORT_SYMBOL(drm_cvt_mode);
+
+/**
+ * drm_gtf_mode - create the modeline based on GTF algorithm
+ *
+ * @dev :drm device
+ * @hdisplay :hdisplay size
+ * @vdisplay :vdisplay size
+ * @vrefresh :vrefresh rate.
+ * @interlaced :whether the interlace is supported
+ * @margins :whether the margin is supported
+ *
+ * LOCKING.
+ * none.
+ *
+ * return the modeline based on GTF algorithm
+ *
+ * This function is to create the modeline based on the GTF algorithm.
+ * Generalized Timing Formula is derived from:
+ * GTF Spreadsheet by Andy Morrish (1/5/97)
+ * available at http://www.vesa.org
+ *
+ * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
+ * What I have done is to translate it by using integer calculation.
+ * I also refer to the function of fb_get_mode in the file of
+ * drivers/video/fbmon.c
+ */
+struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay,
+ int vdisplay, int vrefresh,
+ bool interlaced, int margins)
+{
+ /* 1) top/bottom margin size (% of height) - default: 1.8, */
+#define GTF_MARGIN_PERCENTAGE 18
+ /* 2) character cell horizontal granularity (pixels) - default 8 */
+#define GTF_CELL_GRAN 8
+ /* 3) Minimum vertical porch (lines) - default 3 */
+#define GTF_MIN_V_PORCH 1
+ /* width of vsync in lines */
+#define V_SYNC_RQD 3
+ /* width of hsync as % of total line */
+#define H_SYNC_PERCENT 8
+ /* min time of vsync + back porch (microsec) */
+#define MIN_VSYNC_PLUS_BP 550
+ /* blanking formula gradient */
+#define GTF_M 600
+ /* blanking formula offset */
+#define GTF_C 40
+ /* blanking formula scaling factor */
+#define GTF_K 128
+ /* blanking formula scaling factor */
+#define GTF_J 20
+ /* C' and M' are part of the Blanking Duty Cycle computation */
+#define GTF_C_PRIME (((GTF_C - GTF_J) * GTF_K / 256) + GTF_J)
+#define GTF_M_PRIME (GTF_K * GTF_M / 256)
+ struct drm_display_mode *drm_mode;
+ unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
+ int top_margin, bottom_margin;
+ int interlace;
+ unsigned int hfreq_est;
+ int vsync_plus_bp, vback_porch;
+ unsigned int vtotal_lines, vfieldrate_est, hperiod;
+ unsigned int vfield_rate, vframe_rate;
+ int left_margin, right_margin;
+ unsigned int total_active_pixels, ideal_duty_cycle;
+ unsigned int hblank, total_pixels, pixel_freq;
+ int hsync, hfront_porch, vodd_front_porch_lines;
+ unsigned int tmp1, tmp2;
+
+ drm_mode = drm_mode_create(dev);
+ if (!drm_mode)
+ return NULL;
+
+ /* 1. In order to give correct results, the number of horizontal
+ * pixels requested is first processed to ensure that it is divisible
+ * by the character size, by rounding it to the nearest character
+ * cell boundary:
+ */
+ hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
+ hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
+
+ /* 2. If interlace is requested, the number of vertical lines assumed
+ * by the calculation must be halved, as the computation calculates
+ * the number of vertical lines per field.
+ */
+ if (interlaced)
+ vdisplay_rnd = vdisplay / 2;
+ else
+ vdisplay_rnd = vdisplay;
+
+ /* 3. Find the frame rate required: */
+ if (interlaced)
+ vfieldrate_rqd = vrefresh * 2;
+ else
+ vfieldrate_rqd = vrefresh;
+
+ /* 4. Find number of lines in Top margin: */
+ top_margin = 0;
+ if (margins)
+ top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
+ 1000;
+ /* 5. Find number of lines in bottom margin: */
+ bottom_margin = top_margin;
+
+ /* 6. If interlace is required, then set variable interlace: */
+ if (interlaced)
+ interlace = 1;
+ else
+ interlace = 0;
+
+ /* 7. Estimate the Horizontal frequency */
+ {
+ tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
+ tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
+ 2 + interlace;
+ hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
+ }
+
+ /* 8. Find the number of lines in V sync + back porch */
+ /* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
+ vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
+ vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
+ /* 9. Find the number of lines in V back porch alone: */
+ vback_porch = vsync_plus_bp - V_SYNC_RQD;
+ /* 10. Find the total number of lines in Vertical field period: */
+ vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
+ vsync_plus_bp + GTF_MIN_V_PORCH;
+ /* 11. Estimate the Vertical field frequency: */
+ vfieldrate_est = hfreq_est / vtotal_lines;
+ /* 12. Find the actual horizontal period: */
+ hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
+
+ /* 13. Find the actual Vertical field frequency: */
+ vfield_rate = hfreq_est / vtotal_lines;
+ /* 14. Find the Vertical frame frequency: */
+ if (interlaced)
+ vframe_rate = vfield_rate / 2;
+ else
+ vframe_rate = vfield_rate;
+ /* 15. Find number of pixels in left margin: */
+ if (margins)
+ left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
+ 1000;
+ else
+ left_margin = 0;
+
+ /* 16.Find number of pixels in right margin: */
+ right_margin = left_margin;
+ /* 17.Find total number of active pixels in image and left and right */
+ total_active_pixels = hdisplay_rnd + left_margin + right_margin;
+ /* 18.Find the ideal blanking duty cycle from blanking duty cycle */
+ ideal_duty_cycle = GTF_C_PRIME * 1000 -
+ (GTF_M_PRIME * 1000000 / hfreq_est);
+ /* 19.Find the number of pixels in the blanking time to the nearest
+ * double character cell: */
+ hblank = total_active_pixels * ideal_duty_cycle /
+ (100000 - ideal_duty_cycle);
+ hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
+ hblank = hblank * 2 * GTF_CELL_GRAN;
+ /* 20.Find total number of pixels: */
+ total_pixels = total_active_pixels + hblank;
+ /* 21.Find pixel clock frequency: */
+ pixel_freq = total_pixels * hfreq_est / 1000;
+ /* Stage 1 computations are now complete; I should really pass
+ * the results to another function and do the Stage 2 computations,
+ * but I only need a few more values so I'll just append the
+ * computations here for now */
+ /* 17. Find the number of pixels in the horizontal sync period: */
+ hsync = H_SYNC_PERCENT * total_pixels / 100;
+ hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
+ hsync = hsync * GTF_CELL_GRAN;
+ /* 18. Find the number of pixels in horizontal front porch period */
+ hfront_porch = hblank / 2 - hsync;
+ /* 36. Find the number of lines in the odd front porch period: */
+ vodd_front_porch_lines = GTF_MIN_V_PORCH ;
+
+ /* finally, pack the results in the mode struct */
+ drm_mode->hdisplay = hdisplay_rnd;
+ drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
+ drm_mode->hsync_end = drm_mode->hsync_start + hsync;
+ drm_mode->htotal = total_pixels;
+ drm_mode->vdisplay = vdisplay_rnd;
+ drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
+ drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
+ drm_mode->vtotal = vtotal_lines;
+
+ drm_mode->clock = pixel_freq;
+
+ drm_mode_set_name(drm_mode);
+ drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
+
+ if (interlaced) {
+ drm_mode->vtotal *= 2;
+ drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+ }
+
+ return drm_mode;
+}
+EXPORT_SYMBOL(drm_gtf_mode);
+/**
* drm_mode_set_name - set the name on a mode
* @mode: name will be set in this mode
*
diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c
index b710fab21cb3..a53b848e0f17 100644
--- a/drivers/gpu/drm/mga/mga_state.c
+++ b/drivers/gpu/drm/mga/mga_state.c
@@ -239,7 +239,7 @@ static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv)
MGA_WR34, 0x00000000,
MGA_WR42, 0x0000ffff, MGA_WR60, 0x0000ffff);
- /* Padding required to to hardware bug.
+ /* Padding required due to hardware bug.
*/
DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff,
@@ -317,7 +317,7 @@ static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv)
MGA_WR52, MGA_G400_WR_MAGIC, /* tex1 width */
MGA_WR60, MGA_G400_WR_MAGIC); /* tex1 height */
- /* Padding required to to hardware bug */
+ /* Padding required due to hardware bug */
DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff,
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 5fae1e074b4b..013d38059943 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -13,7 +13,8 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \
radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \
radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
- rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o
+ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \
+ radeon_test.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index c0080cc9bf8d..74d034f77c6b 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -31,6 +31,132 @@
#include "atom.h"
#include "atom-bits.h"
+static void atombios_overscan_setup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ SET_CRTC_OVERSCAN_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
+ int a1, a2;
+
+ memset(&args, 0, sizeof(args));
+
+ args.usOverscanRight = 0;
+ args.usOverscanLeft = 0;
+ args.usOverscanBottom = 0;
+ args.usOverscanTop = 0;
+ args.ucCRTC = radeon_crtc->crtc_id;
+
+ switch (radeon_crtc->rmx_type) {
+ case RMX_CENTER:
+ args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
+ args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
+ args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+ args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ break;
+ case RMX_ASPECT:
+ a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
+ a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
+
+ if (a1 > a2) {
+ args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+ args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+ } else if (a2 > a1) {
+ args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+ args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+ }
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ break;
+ case RMX_FULL:
+ default:
+ args.usOverscanRight = 0;
+ args.usOverscanLeft = 0;
+ args.usOverscanBottom = 0;
+ args.usOverscanTop = 0;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ break;
+ }
+}
+
+static void atombios_scaler_setup(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ ENABLE_SCALER_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
+ /* fixme - fill in enc_priv for atom dac */
+ enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+ if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
+ return;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucScaler = radeon_crtc->crtc_id;
+
+ if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+ switch (tv_std) {
+ case TV_STD_NTSC:
+ default:
+ args.ucTVStandard = ATOM_TV_NTSC;
+ break;
+ case TV_STD_PAL:
+ args.ucTVStandard = ATOM_TV_PAL;
+ break;
+ case TV_STD_PAL_M:
+ args.ucTVStandard = ATOM_TV_PALM;
+ break;
+ case TV_STD_PAL_60:
+ args.ucTVStandard = ATOM_TV_PAL60;
+ break;
+ case TV_STD_NTSC_J:
+ args.ucTVStandard = ATOM_TV_NTSCJ;
+ break;
+ case TV_STD_SCART_PAL:
+ args.ucTVStandard = ATOM_TV_PAL; /* ??? */
+ break;
+ case TV_STD_SECAM:
+ args.ucTVStandard = ATOM_TV_SECAM;
+ break;
+ case TV_STD_PAL_CN:
+ args.ucTVStandard = ATOM_TV_PALCN;
+ break;
+ }
+ args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
+ } else if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT)) {
+ args.ucTVStandard = ATOM_TV_CV;
+ args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
+ } else {
+ switch (radeon_crtc->rmx_type) {
+ case RMX_FULL:
+ args.ucEnable = ATOM_SCALER_EXPANSION;
+ break;
+ case RMX_CENTER:
+ args.ucEnable = ATOM_SCALER_CENTER;
+ break;
+ case RMX_ASPECT:
+ args.ucEnable = ATOM_SCALER_EXPANSION;
+ break;
+ default:
+ if (ASIC_IS_AVIVO(rdev))
+ args.ucEnable = ATOM_SCALER_DISABLE;
+ else
+ args.ucEnable = ATOM_SCALER_CENTER;
+ break;
+ }
+ }
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
+ && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) {
+ atom_rv515_force_tv_scaler(rdev);
+ }
+}
+
static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -203,6 +329,12 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
if (ASIC_IS_AVIVO(rdev)) {
uint32_t ss_cntl;
+ if ((rdev->family == CHIP_RS600) ||
+ (rdev->family == CHIP_RS690) ||
+ (rdev->family == CHIP_RS740))
+ pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
+ RADEON_PLL_PREFER_CLOSEST_LOWER);
+
if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
else
@@ -321,7 +453,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_gem_object *obj;
struct drm_radeon_gem_object *obj_priv;
uint64_t fb_location;
- uint32_t fb_format, fb_pitch_pixels;
+ uint32_t fb_format, fb_pitch_pixels, tiling_flags;
if (!crtc->fb)
return -EINVAL;
@@ -358,7 +490,14 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
return -EINVAL;
}
- /* TODO tiling */
+ radeon_object_get_tiling_flags(obj->driver_private,
+ &tiling_flags, NULL);
+ if (tiling_flags & RADEON_TILING_MACRO)
+ fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
+
+ if (tiling_flags & RADEON_TILING_MICRO)
+ fb_format |= AVIVO_D1GRPH_TILED;
+
if (radeon_crtc->crtc_id == 0)
WREG32(AVIVO_D1VGA_CONTROL, 0);
else
@@ -509,6 +648,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
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;
}
@@ -516,6 +658,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
+ return false;
return true;
}
@@ -548,148 +692,3 @@ void radeon_atombios_init_crtc(struct drm_device *dev,
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
}
-
-void radeon_init_disp_bw_avivo(struct drm_device *dev,
- struct drm_display_mode *mode1,
- uint32_t pixel_bytes1,
- struct drm_display_mode *mode2,
- uint32_t pixel_bytes2)
-{
- struct radeon_device *rdev = dev->dev_private;
- fixed20_12 min_mem_eff;
- fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
- fixed20_12 sclk_ff, mclk_ff;
- uint32_t dc_lb_memory_split, temp;
-
- min_mem_eff.full = rfixed_const_8(0);
- if (rdev->disp_priority == 2) {
- uint32_t mc_init_misc_lat_timer = 0;
- if (rdev->family == CHIP_RV515)
- mc_init_misc_lat_timer =
- RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER);
- else if (rdev->family == CHIP_RS690)
- mc_init_misc_lat_timer =
- RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER);
-
- mc_init_misc_lat_timer &=
- ~(R300_MC_DISP1R_INIT_LAT_MASK <<
- R300_MC_DISP1R_INIT_LAT_SHIFT);
- mc_init_misc_lat_timer &=
- ~(R300_MC_DISP0R_INIT_LAT_MASK <<
- R300_MC_DISP0R_INIT_LAT_SHIFT);
-
- if (mode2)
- mc_init_misc_lat_timer |=
- (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
- if (mode1)
- mc_init_misc_lat_timer |=
- (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
-
- if (rdev->family == CHIP_RV515)
- WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER,
- mc_init_misc_lat_timer);
- else if (rdev->family == CHIP_RS690)
- WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER,
- mc_init_misc_lat_timer);
- }
-
- /*
- * determine is there is enough bw for current mode
- */
- temp_ff.full = rfixed_const(100);
- mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
- mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
- sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
- sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
-
- temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
- temp_ff.full = rfixed_const(temp);
- mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
- mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
-
- pix_clk.full = 0;
- pix_clk2.full = 0;
- peak_disp_bw.full = 0;
- if (mode1) {
- temp_ff.full = rfixed_const(1000);
- pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */
- pix_clk.full = rfixed_div(pix_clk, temp_ff);
- temp_ff.full = rfixed_const(pixel_bytes1);
- peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
- }
- if (mode2) {
- temp_ff.full = rfixed_const(1000);
- pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */
- pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
- temp_ff.full = rfixed_const(pixel_bytes2);
- peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
- }
-
- if (peak_disp_bw.full >= mem_bw.full) {
- DRM_ERROR
- ("You may not have enough display bandwidth for current mode\n"
- "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
- printk("peak disp bw %d, mem_bw %d\n",
- rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw));
- }
-
- /*
- * 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 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 each display controller
- * 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 allocation mode.
- * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits
- * 14:4; D2 allocation follows D1.
- */
-
- /* is auto or manual better ? */
- dc_lb_memory_split =
- RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK;
- dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
-#if 1
- /* auto */
- if (mode1 && mode2) {
- if (mode1->hdisplay > mode2->hdisplay) {
- if (mode1->hdisplay > 2560)
- dc_lb_memory_split |=
- AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
- else
- dc_lb_memory_split |=
- AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
- } else if (mode2->hdisplay > mode1->hdisplay) {
- if (mode2->hdisplay > 2560)
- dc_lb_memory_split |=
- AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
- else
- dc_lb_memory_split |=
- AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
- } else
- dc_lb_memory_split |=
- AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
- } else if (mode1) {
- dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY;
- } else if (mode2) {
- dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
- }
-#else
- /* manual */
- dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
- dc_lb_memory_split &=
- ~(AVIVO_DC_LB_DISP1_END_ADR_MASK <<
- AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
- if (mode1) {
- dc_lb_memory_split |=
- ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK)
- << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
- } else if (mode2) {
- dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
- }
-#endif
- WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split);
-}
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index c550932a108f..05a44896dffb 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -110,7 +110,7 @@ int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
if (i < 0 || i > rdev->gart.num_gpu_pages) {
return -EINVAL;
}
- rdev->gart.table.ram.ptr[i] = cpu_to_le32((uint32_t)addr);
+ rdev->gart.table.ram.ptr[i] = cpu_to_le32(lower_32_bits(addr));
return 0;
}
@@ -173,8 +173,12 @@ void r100_mc_setup(struct radeon_device *rdev)
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.vram_size);
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ 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);
@@ -215,7 +219,6 @@ int r100_mc_init(struct radeon_device *rdev)
r100_pci_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);
@@ -753,6 +756,102 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p,
}
/**
+ * r100_cs_packet_next_vline() - parse userspace VLINE packet
+ * @parser: parser structure holding parsing context.
+ *
+ * Userspace sends a special sequence for VLINE waits.
+ * PACKET0 - VLINE_START_END + value
+ * PACKET0 - WAIT_UNTIL +_value
+ * RELOC (P3) - crtc_id in reloc.
+ *
+ * This function parses this and relocates the VLINE START END
+ * and WAIT UNTIL packets to the correct crtc.
+ * It also detects a switched off crtc and nulls out the
+ * wait in that case.
+ */
+int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)
+{
+ struct radeon_cs_chunk *ib_chunk;
+ struct drm_mode_object *obj;
+ struct drm_crtc *crtc;
+ struct radeon_crtc *radeon_crtc;
+ struct radeon_cs_packet p3reloc, waitreloc;
+ int crtc_id;
+ int r;
+ uint32_t header, h_idx, reg;
+
+ ib_chunk = &p->chunks[p->chunk_ib_idx];
+
+ /* parse the wait until */
+ r = r100_cs_packet_parse(p, &waitreloc, p->idx);
+ if (r)
+ return r;
+
+ /* check its a wait until and only 1 count */
+ if (waitreloc.reg != RADEON_WAIT_UNTIL ||
+ waitreloc.count != 0) {
+ DRM_ERROR("vline wait had illegal wait until segment\n");
+ r = -EINVAL;
+ return r;
+ }
+
+ if (ib_chunk->kdata[waitreloc.idx + 1] != RADEON_WAIT_CRTC_VLINE) {
+ DRM_ERROR("vline wait had illegal wait until\n");
+ r = -EINVAL;
+ return r;
+ }
+
+ /* jump over the NOP */
+ r = r100_cs_packet_parse(p, &p3reloc, p->idx);
+ if (r)
+ return r;
+
+ h_idx = p->idx - 2;
+ p->idx += waitreloc.count;
+ p->idx += p3reloc.count;
+
+ header = ib_chunk->kdata[h_idx];
+ crtc_id = ib_chunk->kdata[h_idx + 5];
+ reg = ib_chunk->kdata[h_idx] >> 2;
+ mutex_lock(&p->rdev->ddev->mode_config.mutex);
+ obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
+ if (!obj) {
+ DRM_ERROR("cannot find crtc %d\n", crtc_id);
+ r = -EINVAL;
+ goto out;
+ }
+ crtc = obj_to_crtc(obj);
+ radeon_crtc = to_radeon_crtc(crtc);
+ crtc_id = radeon_crtc->crtc_id;
+
+ if (!crtc->enabled) {
+ /* if the CRTC isn't enabled - we need to nop out the wait until */
+ ib_chunk->kdata[h_idx + 2] = PACKET2(0);
+ ib_chunk->kdata[h_idx + 3] = PACKET2(0);
+ } else if (crtc_id == 1) {
+ switch (reg) {
+ case AVIVO_D1MODE_VLINE_START_END:
+ header &= R300_CP_PACKET0_REG_MASK;
+ header |= AVIVO_D2MODE_VLINE_START_END >> 2;
+ break;
+ case RADEON_CRTC_GUI_TRIG_VLINE:
+ header &= R300_CP_PACKET0_REG_MASK;
+ header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2;
+ break;
+ default:
+ DRM_ERROR("unknown crtc reloc\n");
+ r = -EINVAL;
+ goto out;
+ }
+ ib_chunk->kdata[h_idx] = header;
+ ib_chunk->kdata[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1;
+ }
+out:
+ mutex_unlock(&p->rdev->ddev->mode_config.mutex);
+ return r;
+}
+
+/**
* r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3
* @parser: parser structure holding parsing context.
* @data: pointer to relocation data
@@ -814,6 +913,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
unsigned idx;
bool onereg;
int r;
+ u32 tile_flags = 0;
ib = p->ib->ptr;
ib_chunk = &p->chunks[p->chunk_ib_idx];
@@ -825,6 +925,15 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
}
for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
switch (reg) {
+ case RADEON_CRTC_GUI_TRIG_VLINE:
+ r = r100_cs_packet_parse_vline(p);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ r100_cs_dump_packet(p, pkt);
+ return r;
+ }
+ break;
/* FIXME: only allow PACKET3 blit? easier to check for out of
* range access */
case RADEON_DST_PITCH_OFFSET:
@@ -838,7 +947,20 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
}
tmp = ib_chunk->kdata[idx] & 0x003fffff;
tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
- ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_DST_TILE_MACRO;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ if (reg == RADEON_SRC_PITCH_OFFSET) {
+ DRM_ERROR("Cannot src blit from microtiled surface\n");
+ r100_cs_dump_packet(p, pkt);
+ return -EINVAL;
+ }
+ tile_flags |= RADEON_DST_TILE_MICRO;
+ }
+
+ tmp |= tile_flags;
+ ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;
break;
case RADEON_RB3D_DEPTHOFFSET:
case RADEON_RB3D_COLOROFFSET:
@@ -869,6 +991,11 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
case R300_TX_OFFSET_0+52:
case R300_TX_OFFSET_0+56:
case R300_TX_OFFSET_0+60:
+ /* rn50 has no 3D engine so fail on any 3d setup */
+ if (ASIC_IS_RN50(p->rdev)) {
+ DRM_ERROR("attempt to use RN50 3D engine failed\n");
+ return -EINVAL;
+ }
r = r100_cs_packet_next_reloc(p, &reloc);
if (r) {
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
@@ -878,6 +1005,25 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
}
ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
break;
+ case R300_RB3D_COLORPITCH0:
+ case RADEON_RB3D_COLORPITCH:
+ r = r100_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ r100_cs_dump_packet(p, pkt);
+ return r;
+ }
+
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_COLOR_TILE_ENABLE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
+
+ tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+ tmp |= tile_flags;
+ ib[idx] = tmp;
+ break;
default:
/* FIXME: we don't want to allow anyothers packet */
break;
@@ -1256,29 +1402,100 @@ static void r100_vram_get_type(struct radeon_device *rdev)
}
}
-void r100_vram_info(struct radeon_device *rdev)
+static u32 r100_get_accessible_vram(struct radeon_device *rdev)
{
- r100_vram_get_type(rdev);
+ u32 aper_size;
+ u8 byte;
+
+ aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
+
+ /* Set HDP_APER_CNTL only on cards that are known not to be broken,
+ * that is has the 2nd generation multifunction PCI interface
+ */
+ if (rdev->family == CHIP_RV280 ||
+ rdev->family >= CHIP_RV350) {
+ WREG32_P(RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL,
+ ~RADEON_HDP_APER_CNTL);
+ DRM_INFO("Generation 2 PCI interface, using max accessible memory\n");
+ return aper_size * 2;
+ }
+
+ /* Older cards have all sorts of funny issues to deal with. First
+ * check if it's a multifunction card by reading the PCI config
+ * header type... Limit those to one aperture size
+ */
+ pci_read_config_byte(rdev->pdev, 0xe, &byte);
+ if (byte & 0x80) {
+ DRM_INFO("Generation 1 PCI interface in multifunction mode\n");
+ DRM_INFO("Limiting VRAM to one aperture\n");
+ return aper_size;
+ }
+
+ /* Single function older card. We read HDP_APER_CNTL to see how the BIOS
+ * have set it up. We don't write this as it's broken on some ASICs but
+ * we expect the BIOS to have done the right thing (might be too optimistic...)
+ */
+ if (RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL)
+ return aper_size * 2;
+ return aper_size;
+}
+
+void r100_vram_init_sizes(struct radeon_device *rdev)
+{
+ u64 config_aper_size;
+ u32 accessible;
+
+ config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
if (rdev->flags & RADEON_IS_IGP) {
uint32_t tom;
/* read NB_TOM to get the amount of ram stolen for the GPU */
tom = RREG32(RADEON_NB_TOM);
- rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+ rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
+ /* for IGPs we need to keep VRAM where it was put by the BIOS */
+ rdev->mc.vram_location = (tom & 0xffff) << 16;
+ WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
} else {
- rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+ rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
/* Some production boards of m6 will report 0
* if it's 8 MB
*/
- if (rdev->mc.vram_size == 0) {
- rdev->mc.vram_size = 8192 * 1024;
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+ if (rdev->mc.real_vram_size == 0) {
+ rdev->mc.real_vram_size = 8192 * 1024;
+ WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
}
+ /* let driver place VRAM */
+ rdev->mc.vram_location = 0xFFFFFFFFUL;
+ /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
+ * Novell bug 204882 + along with lots of ubuntu ones */
+ if (config_aper_size > rdev->mc.real_vram_size)
+ rdev->mc.mc_vram_size = config_aper_size;
+ else
+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
}
+ /* work out accessible VRAM */
+ accessible = r100_get_accessible_vram(rdev);
+
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+
+ if (accessible > rdev->mc.aper_size)
+ accessible = rdev->mc.aper_size;
+
+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
+ rdev->mc.mc_vram_size = rdev->mc.aper_size;
+
+ if (rdev->mc.real_vram_size > rdev->mc.aper_size)
+ rdev->mc.real_vram_size = rdev->mc.aper_size;
+}
+
+void r100_vram_info(struct radeon_device *rdev)
+{
+ r100_vram_get_type(rdev);
+
+ r100_vram_init_sizes(rdev);
}
@@ -1533,3 +1750,530 @@ int r100_debugfs_mc_info_init(struct radeon_device *rdev)
return 0;
#endif
}
+
+int r100_set_surface_reg(struct radeon_device *rdev, int reg,
+ uint32_t tiling_flags, uint32_t pitch,
+ uint32_t offset, uint32_t obj_size)
+{
+ int surf_index = reg * 16;
+ int flags = 0;
+
+ /* r100/r200 divide by 16 */
+ if (rdev->family < CHIP_R300)
+ flags = pitch / 16;
+ else
+ flags = pitch / 8;
+
+ if (rdev->family <= CHIP_RS200) {
+ if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+ == (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+ flags |= RADEON_SURF_TILE_COLOR_BOTH;
+ if (tiling_flags & RADEON_TILING_MACRO)
+ flags |= RADEON_SURF_TILE_COLOR_MACRO;
+ } else if (rdev->family <= CHIP_RV280) {
+ if (tiling_flags & (RADEON_TILING_MACRO))
+ flags |= R200_SURF_TILE_COLOR_MACRO;
+ if (tiling_flags & RADEON_TILING_MICRO)
+ flags |= R200_SURF_TILE_COLOR_MICRO;
+ } else {
+ if (tiling_flags & RADEON_TILING_MACRO)
+ flags |= R300_SURF_TILE_MACRO;
+ if (tiling_flags & RADEON_TILING_MICRO)
+ flags |= R300_SURF_TILE_MICRO;
+ }
+
+ DRM_DEBUG("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1);
+ WREG32(RADEON_SURFACE0_INFO + surf_index, flags);
+ WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset);
+ WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1);
+ return 0;
+}
+
+void r100_clear_surface_reg(struct radeon_device *rdev, int reg)
+{
+ int surf_index = reg * 16;
+ WREG32(RADEON_SURFACE0_INFO + surf_index, 0);
+}
+
+void r100_bandwidth_update(struct radeon_device *rdev)
+{
+ fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff;
+ fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff;
+ fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff;
+ uint32_t temp, data, mem_trcd, mem_trp, mem_tras;
+ fixed20_12 memtcas_ff[8] = {
+ fixed_init(1),
+ fixed_init(2),
+ fixed_init(3),
+ fixed_init(0),
+ fixed_init_half(1),
+ fixed_init_half(2),
+ fixed_init(0),
+ };
+ fixed20_12 memtcas_rs480_ff[8] = {
+ fixed_init(0),
+ fixed_init(1),
+ fixed_init(2),
+ fixed_init(3),
+ fixed_init(0),
+ fixed_init_half(1),
+ fixed_init_half(2),
+ fixed_init_half(3),
+ };
+ fixed20_12 memtcas2_ff[8] = {
+ fixed_init(0),
+ fixed_init(1),
+ fixed_init(2),
+ fixed_init(3),
+ fixed_init(4),
+ fixed_init(5),
+ fixed_init(6),
+ fixed_init(7),
+ };
+ fixed20_12 memtrbs[8] = {
+ fixed_init(1),
+ fixed_init_half(1),
+ fixed_init(2),
+ fixed_init_half(2),
+ fixed_init(3),
+ fixed_init_half(3),
+ fixed_init(4),
+ fixed_init_half(4)
+ };
+ fixed20_12 memtrbs_r4xx[8] = {
+ fixed_init(4),
+ fixed_init(5),
+ fixed_init(6),
+ fixed_init(7),
+ fixed_init(8),
+ fixed_init(9),
+ fixed_init(10),
+ fixed_init(11)
+ };
+ fixed20_12 min_mem_eff;
+ fixed20_12 mc_latency_sclk, mc_latency_mclk, k1;
+ fixed20_12 cur_latency_mclk, cur_latency_sclk;
+ fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate,
+ disp_drain_rate2, read_return_rate;
+ fixed20_12 time_disp1_drop_priority;
+ int c;
+ int cur_size = 16; /* in octawords */
+ int critical_point = 0, critical_point2;
+/* uint32_t read_return_rate, time_disp1_drop_priority; */
+ int stop_req, max_stop_req;
+ struct drm_display_mode *mode1 = NULL;
+ struct drm_display_mode *mode2 = NULL;
+ uint32_t pixel_bytes1 = 0;
+ uint32_t pixel_bytes2 = 0;
+
+ if (rdev->mode_info.crtcs[0]->base.enabled) {
+ 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;
+ }
+
+ min_mem_eff.full = rfixed_const_8(0);
+ /* get modes */
+ if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) {
+ uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER);
+ mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT);
+ mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT);
+ /* check crtc enables */
+ if (mode2)
+ mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
+ if (mode1)
+ mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
+ WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer);
+ }
+
+ /*
+ * determine is there is enough bw for current mode
+ */
+ mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
+ temp_ff.full = rfixed_const(100);
+ mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
+ sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
+ sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
+
+ temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
+ temp_ff.full = rfixed_const(temp);
+ mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
+
+ pix_clk.full = 0;
+ pix_clk2.full = 0;
+ peak_disp_bw.full = 0;
+ if (mode1) {
+ temp_ff.full = rfixed_const(1000);
+ pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */
+ pix_clk.full = rfixed_div(pix_clk, temp_ff);
+ temp_ff.full = rfixed_const(pixel_bytes1);
+ peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
+ }
+ if (mode2) {
+ temp_ff.full = rfixed_const(1000);
+ pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */
+ pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
+ temp_ff.full = rfixed_const(pixel_bytes2);
+ peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
+ }
+
+ mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
+ if (peak_disp_bw.full >= mem_bw.full) {
+ DRM_ERROR("You may not have enough display bandwidth for current mode\n"
+ "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
+ }
+
+ /* Get values from the EXT_MEM_CNTL register...converting its contents. */
+ temp = RREG32(RADEON_MEM_TIMING_CNTL);
+ if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */
+ mem_trcd = ((temp >> 2) & 0x3) + 1;
+ mem_trp = ((temp & 0x3)) + 1;
+ mem_tras = ((temp & 0x70) >> 4) + 1;
+ } else if (rdev->family == CHIP_R300 ||
+ rdev->family == CHIP_R350) { /* r300, r350 */
+ mem_trcd = (temp & 0x7) + 1;
+ mem_trp = ((temp >> 8) & 0x7) + 1;
+ mem_tras = ((temp >> 11) & 0xf) + 4;
+ } else if (rdev->family == CHIP_RV350 ||
+ rdev->family <= CHIP_RV380) {
+ /* rv3x0 */
+ mem_trcd = (temp & 0x7) + 3;
+ mem_trp = ((temp >> 8) & 0x7) + 3;
+ mem_tras = ((temp >> 11) & 0xf) + 6;
+ } else if (rdev->family == CHIP_R420 ||
+ rdev->family == CHIP_R423 ||
+ rdev->family == CHIP_RV410) {
+ /* r4xx */
+ mem_trcd = (temp & 0xf) + 3;
+ if (mem_trcd > 15)
+ mem_trcd = 15;
+ mem_trp = ((temp >> 8) & 0xf) + 3;
+ if (mem_trp > 15)
+ mem_trp = 15;
+ mem_tras = ((temp >> 12) & 0x1f) + 6;
+ if (mem_tras > 31)
+ mem_tras = 31;
+ } else { /* RV200, R200 */
+ mem_trcd = (temp & 0x7) + 1;
+ mem_trp = ((temp >> 8) & 0x7) + 1;
+ mem_tras = ((temp >> 12) & 0xf) + 4;
+ }
+ /* convert to FF */
+ trcd_ff.full = rfixed_const(mem_trcd);
+ trp_ff.full = rfixed_const(mem_trp);
+ tras_ff.full = rfixed_const(mem_tras);
+
+ /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
+ temp = RREG32(RADEON_MEM_SDRAM_MODE_REG);
+ data = (temp & (7 << 20)) >> 20;
+ if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) {
+ if (rdev->family == CHIP_RS480) /* don't think rs400 */
+ tcas_ff = memtcas_rs480_ff[data];
+ else
+ tcas_ff = memtcas_ff[data];
+ } else
+ tcas_ff = memtcas2_ff[data];
+
+ if (rdev->family == CHIP_RS400 ||
+ rdev->family == CHIP_RS480) {
+ /* extra cas latency stored in bits 23-25 0-4 clocks */
+ data = (temp >> 23) & 0x7;
+ if (data < 5)
+ tcas_ff.full += rfixed_const(data);
+ }
+
+ if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) {
+ /* on the R300, Tcas is included in Trbs.
+ */
+ temp = RREG32(RADEON_MEM_CNTL);
+ data = (R300_MEM_NUM_CHANNELS_MASK & temp);
+ if (data == 1) {
+ if (R300_MEM_USE_CD_CH_ONLY & temp) {
+ temp = RREG32(R300_MC_IND_INDEX);
+ temp &= ~R300_MC_IND_ADDR_MASK;
+ temp |= R300_MC_READ_CNTL_CD_mcind;
+ WREG32(R300_MC_IND_INDEX, temp);
+ temp = RREG32(R300_MC_IND_DATA);
+ data = (R300_MEM_RBS_POSITION_C_MASK & temp);
+ } else {
+ temp = RREG32(R300_MC_READ_CNTL_AB);
+ data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+ }
+ } else {
+ temp = RREG32(R300_MC_READ_CNTL_AB);
+ data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+ }
+ if (rdev->family == CHIP_RV410 ||
+ rdev->family == CHIP_R420 ||
+ rdev->family == CHIP_R423)
+ trbs_ff = memtrbs_r4xx[data];
+ else
+ trbs_ff = memtrbs[data];
+ tcas_ff.full += trbs_ff.full;
+ }
+
+ sclk_eff_ff.full = sclk_ff.full;
+
+ if (rdev->flags & RADEON_IS_AGP) {
+ fixed20_12 agpmode_ff;
+ agpmode_ff.full = rfixed_const(radeon_agpmode);
+ temp_ff.full = rfixed_const_666(16);
+ sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff);
+ }
+ /* TODO PCIE lanes may affect this - agpmode == 16?? */
+
+ if (ASIC_IS_R300(rdev)) {
+ sclk_delay_ff.full = rfixed_const(250);
+ } else {
+ if ((rdev->family == CHIP_RV100) ||
+ rdev->flags & RADEON_IS_IGP) {
+ if (rdev->mc.vram_is_ddr)
+ sclk_delay_ff.full = rfixed_const(41);
+ else
+ sclk_delay_ff.full = rfixed_const(33);
+ } else {
+ if (rdev->mc.vram_width == 128)
+ sclk_delay_ff.full = rfixed_const(57);
+ else
+ sclk_delay_ff.full = rfixed_const(41);
+ }
+ }
+
+ mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff);
+
+ if (rdev->mc.vram_is_ddr) {
+ if (rdev->mc.vram_width == 32) {
+ k1.full = rfixed_const(40);
+ c = 3;
+ } else {
+ k1.full = rfixed_const(20);
+ c = 1;
+ }
+ } else {
+ k1.full = rfixed_const(40);
+ c = 3;
+ }
+
+ temp_ff.full = rfixed_const(2);
+ mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff);
+ temp_ff.full = rfixed_const(c);
+ mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff);
+ temp_ff.full = rfixed_const(4);
+ mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff);
+ mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff);
+ mc_latency_mclk.full += k1.full;
+
+ mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff);
+ mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff);
+
+ /*
+ HW cursor time assuming worst case of full size colour cursor.
+ */
+ temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1))));
+ temp_ff.full += trcd_ff.full;
+ if (temp_ff.full < tras_ff.full)
+ temp_ff.full = tras_ff.full;
+ cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff);
+
+ temp_ff.full = rfixed_const(cur_size);
+ cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff);
+ /*
+ Find the total latency for the display data.
+ */
+ disp_latency_overhead.full = rfixed_const(80);
+ 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;
+
+ if (mc_latency_mclk.full > mc_latency_sclk.full)
+ disp_latency.full = mc_latency_mclk.full;
+ else
+ disp_latency.full = mc_latency_sclk.full;
+
+ /* setup Max GRPH_STOP_REQ default value */
+ if (ASIC_IS_RV100(rdev))
+ max_stop_req = 0x5c;
+ else
+ max_stop_req = 0x7c;
+
+ if (mode1) {
+ /* CRTC1
+ Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
+ GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
+ */
+ stop_req = mode1->hdisplay * pixel_bytes1 / 16;
+
+ if (stop_req > max_stop_req)
+ stop_req = max_stop_req;
+
+ /*
+ Find the drain rate of the display buffer.
+ */
+ temp_ff.full = rfixed_const((16/pixel_bytes1));
+ disp_drain_rate.full = rfixed_div(pix_clk, temp_ff);
+
+ /*
+ Find the critical point of the display buffer.
+ */
+ crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency);
+ crit_point_ff.full += rfixed_const_half(0);
+
+ critical_point = rfixed_trunc(crit_point_ff);
+
+ if (rdev->disp_priority == 2) {
+ critical_point = 0;
+ }
+
+ /*
+ The critical point should never be above max_stop_req-4. Setting
+ GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
+ */
+ if (max_stop_req - critical_point < 4)
+ critical_point = 0;
+
+ if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) {
+ /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
+ critical_point = 0x10;
+ }
+
+ temp = RREG32(RADEON_GRPH_BUFFER_CNTL);
+ temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
+ temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+ temp &= ~(RADEON_GRPH_START_REQ_MASK);
+ if ((rdev->family == CHIP_R350) &&
+ (stop_req > 0x15)) {
+ stop_req -= 0x10;
+ }
+ temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+ temp |= RADEON_GRPH_BUFFER_SIZE;
+ temp &= ~(RADEON_GRPH_CRITICAL_CNTL |
+ RADEON_GRPH_CRITICAL_AT_SOF |
+ RADEON_GRPH_STOP_CNTL);
+ /*
+ Write the result into the register.
+ */
+ WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+ (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+#if 0
+ if ((rdev->family == CHIP_RS400) ||
+ (rdev->family == CHIP_RS480)) {
+ /* attempt to program RS400 disp regs correctly ??? */
+ temp = RREG32(RS400_DISP1_REG_CNTL);
+ temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK |
+ RS400_DISP1_STOP_REQ_LEVEL_MASK);
+ WREG32(RS400_DISP1_REQ_CNTL1, (temp |
+ (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
+ (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
+ temp = RREG32(RS400_DMIF_MEM_CNTL1);
+ temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK |
+ RS400_DISP1_CRITICAL_POINT_STOP_MASK);
+ WREG32(RS400_DMIF_MEM_CNTL1, (temp |
+ (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) |
+ (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT)));
+ }
+#endif
+
+ DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n",
+ /* (unsigned int)info->SavedReg->grph_buffer_cntl, */
+ (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL));
+ }
+
+ if (mode2) {
+ u32 grph2_cntl;
+ stop_req = mode2->hdisplay * pixel_bytes2 / 16;
+
+ if (stop_req > max_stop_req)
+ stop_req = max_stop_req;
+
+ /*
+ Find the drain rate of the display buffer.
+ */
+ temp_ff.full = rfixed_const((16/pixel_bytes2));
+ disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff);
+
+ grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL);
+ grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK);
+ grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+ grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK);
+ if ((rdev->family == CHIP_R350) &&
+ (stop_req > 0x15)) {
+ stop_req -= 0x10;
+ }
+ grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+ grph2_cntl |= RADEON_GRPH_BUFFER_SIZE;
+ grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL |
+ RADEON_GRPH_CRITICAL_AT_SOF |
+ RADEON_GRPH_STOP_CNTL);
+
+ if ((rdev->family == CHIP_RS100) ||
+ (rdev->family == CHIP_RS200))
+ critical_point2 = 0;
+ else {
+ temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128;
+ temp_ff.full = rfixed_const(temp);
+ temp_ff.full = rfixed_mul(mclk_ff, temp_ff);
+ if (sclk_ff.full < temp_ff.full)
+ temp_ff.full = sclk_ff.full;
+
+ read_return_rate.full = temp_ff.full;
+
+ if (mode1) {
+ temp_ff.full = read_return_rate.full - disp_drain_rate.full;
+ time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff);
+ } else {
+ time_disp1_drop_priority.full = 0;
+ }
+ crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full;
+ crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2);
+ crit_point_ff.full += rfixed_const_half(0);
+
+ critical_point2 = rfixed_trunc(crit_point_ff);
+
+ if (rdev->disp_priority == 2) {
+ critical_point2 = 0;
+ }
+
+ if (max_stop_req - critical_point2 < 4)
+ critical_point2 = 0;
+
+ }
+
+ if (critical_point2 == 0 && rdev->family == CHIP_R300) {
+ /* some R300 cards have problem with this set to 0 */
+ critical_point2 = 0x10;
+ }
+
+ WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+ (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+ if ((rdev->family == CHIP_RS400) ||
+ (rdev->family == CHIP_RS480)) {
+#if 0
+ /* attempt to program RS400 disp2 regs correctly ??? */
+ temp = RREG32(RS400_DISP2_REQ_CNTL1);
+ temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK |
+ RS400_DISP2_STOP_REQ_LEVEL_MASK);
+ WREG32(RS400_DISP2_REQ_CNTL1, (temp |
+ (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
+ (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
+ temp = RREG32(RS400_DISP2_REQ_CNTL2);
+ temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK |
+ RS400_DISP2_CRITICAL_POINT_STOP_MASK);
+ WREG32(RS400_DISP2_REQ_CNTL2, (temp |
+ (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) |
+ (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT)));
+#endif
+ WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC);
+ WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000);
+ WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC);
+ WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
+ }
+
+ DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n",
+ (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
+ }
+}
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index e2ed5bc08170..9c8d41534a5d 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -30,6 +30,8 @@
#include "drm.h"
#include "radeon_reg.h"
#include "radeon.h"
+#include "radeon_drm.h"
+#include "radeon_share.h"
/* r300,r350,rv350,rv370,rv380 depends on : */
void r100_hdp_reset(struct radeon_device *rdev);
@@ -44,6 +46,7 @@ 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_packet_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc);
int r100_cs_parse_packet0(struct radeon_cs_parser *p,
@@ -150,8 +153,13 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
if (i < 0 || i > rdev->gart.num_gpu_pages) {
return -EINVAL;
}
- addr = (((u32)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC;
- writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4));
+ addr = (lower_32_bits(addr) >> 8) |
+ ((upper_32_bits(addr) & 0xff) << 24) |
+ 0xc;
+ /* on x86 we want this to be CPU endian, on powerpc
+ * on powerpc without HW swappers, it'll get swapped on way
+ * into VRAM - so no need for cpu_to_le32 on VRAM tables */
+ writel(addr, ((void __iomem *)ptr) + (i * 4));
return 0;
}
@@ -579,10 +587,8 @@ void r300_vram_info(struct radeon_device *rdev)
} else {
rdev->mc.vram_width = 64;
}
- rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ r100_vram_init_sizes(rdev);
}
@@ -970,7 +976,7 @@ static inline void r300_cs_track_clear(struct r300_cs_track *track)
static const unsigned r300_reg_safe_bm[159] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
@@ -1019,7 +1025,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_reloc *reloc;
struct r300_cs_track *track;
volatile uint32_t *ib;
- uint32_t tmp;
+ uint32_t tmp, tile_flags = 0;
unsigned i;
int r;
@@ -1027,6 +1033,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
ib_chunk = &p->chunks[p->chunk_ib_idx];
track = (struct r300_cs_track*)p->track;
switch(reg) {
+ case AVIVO_D1MODE_VLINE_START_END:
+ case RADEON_CRTC_GUI_TRIG_VLINE:
+ r = r100_cs_packet_parse_vline(p);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ r100_cs_dump_packet(p, pkt);
+ return r;
+ }
+ break;
case RADEON_DST_PITCH_OFFSET:
case RADEON_SRC_PITCH_OFFSET:
r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1038,7 +1054,19 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
}
tmp = ib_chunk->kdata[idx] & 0x003fffff;
tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
- ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_DST_TILE_MACRO;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ if (reg == RADEON_SRC_PITCH_OFFSET) {
+ DRM_ERROR("Cannot src blit from microtiled surface\n");
+ r100_cs_dump_packet(p, pkt);
+ return -EINVAL;
+ }
+ tile_flags |= RADEON_DST_TILE_MICRO;
+ }
+ tmp |= tile_flags;
+ ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;
break;
case R300_RB3D_COLOROFFSET0:
case R300_RB3D_COLOROFFSET1:
@@ -1127,6 +1155,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
/* RB3D_COLORPITCH1 */
/* RB3D_COLORPITCH2 */
/* RB3D_COLORPITCH3 */
+ r = r100_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ r100_cs_dump_packet(p, pkt);
+ return r;
+ }
+
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= R300_COLOR_TILE_ENABLE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= R300_COLOR_MICROTILE_ENABLE;
+
+ tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+ tmp |= tile_flags;
+ ib[idx] = tmp;
+
i = (reg - 0x4E38) >> 2;
track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE;
switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) {
@@ -1182,6 +1227,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
break;
case 0x4F24:
/* ZB_DEPTHPITCH */
+ r = r100_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ r100_cs_dump_packet(p, pkt);
+ return r;
+ }
+
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= R300_DEPTHMACROTILE_ENABLE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= R300_DEPTHMICROTILE_TILED;;
+
+ tmp = ib_chunk->kdata[idx] & ~(0x7 << 16);
+ tmp |= tile_flags;
+ ib[idx] = tmp;
+
track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC;
break;
case 0x4104:
diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h
index 70f48609515e..4b7afef35a65 100644
--- a/drivers/gpu/drm/radeon/r300_reg.h
+++ b/drivers/gpu/drm/radeon/r300_reg.h
@@ -27,7 +27,9 @@
#ifndef _R300_REG_H_
#define _R300_REG_H_
-
+#define R300_SURF_TILE_MACRO (1<<16)
+#define R300_SURF_TILE_MICRO (2<<16)
+#define R300_SURF_TILE_BOTH (3<<16)
#define R300_MC_INIT_MISC_LAT_TIMER 0x180
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 9070a1c2ce23..036691b38cb7 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -445,6 +445,7 @@
#define AVIVO_D1MODE_DATA_FORMAT 0x6528
# define AVIVO_D1MODE_INTERLEAVE_EN (1 << 0)
#define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C
+#define AVIVO_D1MODE_VLINE_START_END 0x6538
#define AVIVO_D1MODE_VIEWPORT_START 0x6580
#define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584
#define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6588
@@ -496,6 +497,7 @@
#define AVIVO_D2CUR_SIZE 0x6c10
#define AVIVO_D2CUR_POSITION 0x6c14
+#define AVIVO_D2MODE_VLINE_START_END 0x6d38
#define AVIVO_D2MODE_VIEWPORT_START 0x6d80
#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84
#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 570a244bd88b..09fb0b6ec7dd 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -28,6 +28,7 @@
#include "drmP.h"
#include "radeon_reg.h"
#include "radeon.h"
+#include "radeon_share.h"
/* r520,rv530,rv560,rv570,r580 depends on : */
void r100_hdp_reset(struct radeon_device *rdev);
@@ -94,8 +95,8 @@ int r520_mc_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
/* Write VRAM size in case we are limiting it */
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
+ tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
tmp = REG_SET(R520_MC_FB_TOP, tmp >> 16);
tmp |= REG_SET(R520_MC_FB_START, rdev->mc.vram_location >> 16);
WREG32_MC(R520_MC_FB_LOCATION, tmp);
@@ -226,9 +227,20 @@ static void r520_vram_get_type(struct radeon_device *rdev)
void r520_vram_info(struct radeon_device *rdev)
{
+ fixed20_12 a;
+
r520_vram_get_type(rdev);
- rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ r100_vram_init_sizes(rdev);
+ /* FIXME: we should enforce default clock in case GPU is not in
+ * default setup
+ */
+ a.full = rfixed_const(100);
+ rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
+ rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
+}
+
+void r520_bandwidth_update(struct radeon_device *rdev)
+{
+ rv515_bandwidth_avivo_update(rdev);
}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index c45559fc97fd..538cd907df69 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -67,7 +67,7 @@ int r600_mc_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
tmp = REG_SET(R600_MC_FB_TOP, tmp >> 24);
tmp |= REG_SET(R600_MC_FB_BASE, rdev->mc.vram_location >> 24);
WREG32(R600_MC_VM_FB_LOCATION, tmp);
@@ -140,7 +140,8 @@ void r600_vram_get_type(struct radeon_device *rdev)
void r600_vram_info(struct radeon_device *rdev)
{
r600_vram_get_type(rdev);
- rdev->mc.vram_size = RREG32(R600_CONFIG_MEMSIZE);
+ rdev->mc.real_vram_size = RREG32(R600_CONFIG_MEMSIZE);
+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
/* Could aper size report 0 ? */
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d61f2fc61df5..b1d945b8ed6c 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -64,6 +64,7 @@ extern int radeon_agpmode;
extern int radeon_vram_limit;
extern int radeon_gart_size;
extern int radeon_benchmarking;
+extern int radeon_testing;
extern int radeon_connector_table;
/*
@@ -113,6 +114,7 @@ enum radeon_family {
CHIP_RV770,
CHIP_RV730,
CHIP_RV710,
+ CHIP_RS880,
CHIP_LAST,
};
@@ -201,6 +203,14 @@ int radeon_fence_wait_last(struct radeon_device *rdev);
struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
void radeon_fence_unref(struct radeon_fence **fence);
+/*
+ * Tiling registers
+ */
+struct radeon_surface_reg {
+ struct radeon_object *robj;
+};
+
+#define RADEON_GEM_MAX_SURFACES 8
/*
* Radeon buffer.
@@ -213,6 +223,7 @@ struct radeon_object_list {
uint64_t gpu_offset;
unsigned rdomain;
unsigned wdomain;
+ uint32_t tiling_flags;
};
int radeon_object_init(struct radeon_device *rdev);
@@ -242,8 +253,15 @@ void radeon_object_list_clean(struct list_head *head);
int radeon_object_fbdev_mmap(struct radeon_object *robj,
struct vm_area_struct *vma);
unsigned long radeon_object_size(struct radeon_object *robj);
-
-
+void radeon_object_clear_surface_reg(struct radeon_object *robj);
+int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved,
+ bool force_drop);
+void radeon_object_set_tiling_flags(struct radeon_object *robj,
+ uint32_t tiling_flags, uint32_t pitch);
+void radeon_object_get_tiling_flags(struct radeon_object *robj, uint32_t *tiling_flags, uint32_t *pitch);
+void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *mem);
+void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
/*
* GEM objects.
*/
@@ -315,8 +333,11 @@ struct radeon_mc {
unsigned gtt_location;
unsigned gtt_size;
unsigned vram_location;
- unsigned vram_size;
+ /* for some chips with <= 32MB we need to lie
+ * about vram size near mc fb location */
+ unsigned mc_vram_size;
unsigned vram_width;
+ unsigned real_vram_size;
int vram_mtrr;
bool vram_is_ddr;
};
@@ -474,6 +495,39 @@ struct radeon_wb {
uint64_t gpu_addr;
};
+/**
+ * struct radeon_pm - power management datas
+ * @max_bandwidth: maximum bandwidth the gpu has (MByte/s)
+ * @igp_sideport_mclk: sideport memory clock Mhz (rs690,rs740,rs780,rs880)
+ * @igp_system_mclk: system clock Mhz (rs690,rs740,rs780,rs880)
+ * @igp_ht_link_clk: ht link clock Mhz (rs690,rs740,rs780,rs880)
+ * @igp_ht_link_width: ht link width in bits (rs690,rs740,rs780,rs880)
+ * @k8_bandwidth: k8 bandwidth the gpu has (MByte/s) (IGP)
+ * @sideport_bandwidth: sideport bandwidth the gpu has (MByte/s) (IGP)
+ * @ht_bandwidth: ht bandwidth the gpu has (MByte/s) (IGP)
+ * @core_bandwidth: core GPU bandwidth the gpu has (MByte/s) (IGP)
+ * @sclk: GPU clock Mhz (core bandwith depends of this clock)
+ * @needed_bandwidth: current bandwidth needs
+ *
+ * It keeps track of various data needed to take powermanagement decision.
+ * Bandwith need is used to determine minimun clock of the GPU and memory.
+ * Equation between gpu/memory clock and available bandwidth is hw dependent
+ * (type of memory, bus size, efficiency, ...)
+ */
+struct radeon_pm {
+ fixed20_12 max_bandwidth;
+ fixed20_12 igp_sideport_mclk;
+ fixed20_12 igp_system_mclk;
+ fixed20_12 igp_ht_link_clk;
+ fixed20_12 igp_ht_link_width;
+ fixed20_12 k8_bandwidth;
+ fixed20_12 sideport_bandwidth;
+ fixed20_12 ht_bandwidth;
+ fixed20_12 core_bandwidth;
+ fixed20_12 sclk;
+ fixed20_12 needed_bandwidth;
+};
+
/*
* Benchmarking
@@ -482,6 +536,12 @@ void radeon_benchmark(struct radeon_device *rdev);
/*
+ * Testing
+ */
+void radeon_test_moves(struct radeon_device *rdev);
+
+
+/*
* Debugfs
*/
int radeon_debugfs_add_files(struct radeon_device *rdev,
@@ -535,6 +595,11 @@ struct radeon_asic {
void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
void (*set_clock_gating)(struct radeon_device *rdev, int enable);
+ int (*set_surface_reg)(struct radeon_device *rdev, int reg,
+ uint32_t tiling_flags, uint32_t pitch,
+ uint32_t offset, uint32_t obj_size);
+ int (*clear_surface_reg)(struct radeon_device *rdev, int reg);
+ void (*bandwidth_update)(struct radeon_device *rdev);
};
union radeon_asic_config {
@@ -566,6 +631,10 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);
int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
+int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
/*
@@ -594,8 +663,8 @@ struct radeon_device {
struct radeon_object *fbdev_robj;
struct radeon_framebuffer *fbdev_rfb;
/* Register mmio */
- unsigned long rmmio_base;
- unsigned long rmmio_size;
+ resource_size_t rmmio_base;
+ resource_size_t rmmio_size;
void *rmmio;
radeon_rreg_t mm_rreg;
radeon_wreg_t mm_wreg;
@@ -619,11 +688,14 @@ struct radeon_device {
struct radeon_irq irq;
struct radeon_asic *asic;
struct radeon_gem gem;
+ struct radeon_pm pm;
struct mutex cs_mutex;
struct radeon_wb wb;
bool gpu_lockup;
bool shutdown;
bool suspend;
+ bool need_dma32;
+ struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
};
int radeon_device_init(struct radeon_device *rdev,
@@ -670,6 +742,8 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
/*
* ASICs helpers.
*/
+#define ASIC_IS_RN50(rdev) ((rdev->pdev->device == 0x515e) || \
+ (rdev->pdev->device == 0x5969))
#define ASIC_IS_RV100(rdev) ((rdev->family == CHIP_RV100) || \
(rdev->family == CHIP_RV200) || \
(rdev->family == CHIP_RS100) || \
@@ -796,5 +870,8 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
+#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
+#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r)))
+#define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev))
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index e2e567395df8..9a75876e0c3b 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -71,6 +71,11 @@ int r100_copy_blit(struct radeon_device *rdev,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence);
+int r100_set_surface_reg(struct radeon_device *rdev, int reg,
+ uint32_t tiling_flags, uint32_t pitch,
+ uint32_t offset, uint32_t obj_size);
+int r100_clear_surface_reg(struct radeon_device *rdev, int reg);
+void r100_bandwidth_update(struct radeon_device *rdev);
static struct radeon_asic r100_asic = {
.init = &r100_init,
@@ -100,6 +105,9 @@ static struct radeon_asic r100_asic = {
.set_memory_clock = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
};
@@ -128,6 +136,7 @@ int r300_copy_dma(struct radeon_device *rdev,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence);
+
static struct radeon_asic r300_asic = {
.init = &r300_init,
.errata = &r300_errata,
@@ -156,6 +165,9 @@ static struct radeon_asic r300_asic = {
.set_memory_clock = NULL,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_legacy_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
};
/*
@@ -193,6 +205,9 @@ static struct radeon_asic r420_asic = {
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
};
@@ -237,6 +252,9 @@ static struct radeon_asic rs400_asic = {
.set_memory_clock = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r100_bandwidth_update,
};
@@ -254,6 +272,7 @@ 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);
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 = &r300_init,
.errata = &rs600_errata,
@@ -282,6 +301,7 @@ static struct radeon_asic rs600_asic = {
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .bandwidth_update = &rs600_bandwidth_update,
};
@@ -294,6 +314,7 @@ int rs690_mc_init(struct radeon_device *rdev);
void rs690_mc_fini(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 = &r300_init,
.errata = &rs690_errata,
@@ -322,6 +343,9 @@ static struct radeon_asic rs690_asic = {
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &rs690_bandwidth_update,
};
@@ -339,6 +363,7 @@ void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rv515_ring_start(struct radeon_device *rdev);
uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+void rv515_bandwidth_update(struct radeon_device *rdev);
static struct radeon_asic rv515_asic = {
.init = &rv515_init,
.errata = &rv515_errata,
@@ -367,6 +392,9 @@ static struct radeon_asic rv515_asic = {
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &rv515_bandwidth_update,
};
@@ -377,6 +405,7 @@ void r520_errata(struct radeon_device *rdev);
void r520_vram_info(struct radeon_device *rdev);
int r520_mc_init(struct radeon_device *rdev);
void r520_mc_fini(struct radeon_device *rdev);
+void r520_bandwidth_update(struct radeon_device *rdev);
static struct radeon_asic r520_asic = {
.init = &rv515_init,
.errata = &r520_errata,
@@ -405,6 +434,9 @@ static struct radeon_asic r520_asic = {
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
+ .set_surface_reg = r100_set_surface_reg,
+ .clear_surface_reg = r100_clear_surface_reg,
+ .bandwidth_update = &r520_bandwidth_update,
};
/*
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 1f5a1a490984..fcfe5c02d744 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -103,7 +103,8 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device
static bool radeon_atom_apply_quirks(struct drm_device *dev,
uint32_t supported_device,
int *connector_type,
- struct radeon_i2c_bus_rec *i2c_bus)
+ struct radeon_i2c_bus_rec *i2c_bus,
+ uint8_t *line_mux)
{
/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
@@ -127,8 +128,10 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
if ((dev->pdev->device == 0x5653) &&
(dev->pdev->subsystem_vendor == 0x1462) &&
(dev->pdev->subsystem_device == 0x0291)) {
- if (*connector_type == DRM_MODE_CONNECTOR_LVDS)
+ if (*connector_type == DRM_MODE_CONNECTOR_LVDS) {
i2c_bus->valid = false;
+ *line_mux = 53;
+ }
}
/* Funky macbooks */
@@ -526,7 +529,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
if (!radeon_atom_apply_quirks
(dev, (1 << i), &bios_connectors[i].connector_type,
- &bios_connectors[i].ddc_bus))
+ &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux))
continue;
bios_connectors[i].valid = true;
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index c44403a2ca76..2e938f7496fb 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -63,7 +63,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- r = radeon_copy_dma(rdev, saddr, daddr, size >> 14, fence);
+ r = radeon_copy_dma(rdev, saddr, daddr, size / 4096, fence);
if (r) {
goto out_cleanup;
}
@@ -88,7 +88,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- r = radeon_copy_blit(rdev, saddr, daddr, size >> 14, fence);
+ r = radeon_copy_blit(rdev, saddr, daddr, size / 4096, fence);
if (r) {
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index b843f9bdfb14..a169067efc4e 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -127,17 +127,23 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
sizeof(struct drm_radeon_cs_chunk))) {
return -EFAULT;
}
+ p->chunks[i].length_dw = user_chunk.length_dw;
+ p->chunks[i].kdata = NULL;
p->chunks[i].chunk_id = user_chunk.chunk_id;
+
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {
p->chunk_relocs_idx = i;
}
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
p->chunk_ib_idx = i;
+ /* zero length IB isn't useful */
+ if (p->chunks[i].length_dw == 0)
+ return -EINVAL;
}
+
p->chunks[i].length_dw = user_chunk.length_dw;
cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data;
- p->chunks[i].kdata = NULL;
size = p->chunks[i].length_dw * sizeof(uint32_t);
p->chunks[i].kdata = kzalloc(size, GFP_KERNEL);
if (p->chunks[i].kdata == NULL) {
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 5232441f119b..b13c79e38bc0 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -111,9 +111,11 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
if (ASIC_IS_AVIVO(rdev))
WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
- else
+ else {
+ radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
/* offset is from DISP(2)_BASE_ADDRESS */
- WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, gpu_addr);
+ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
+ }
}
int radeon_crtc_cursor_set(struct drm_crtc *crtc,
@@ -245,6 +247,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
(RADEON_CUR_LOCK
| ((xorigin ? 0 : x) << 16)
| (yorigin ? 0 : y)));
+ /* offset is from DISP(2)_BASE_ADDRESS */
+ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
+ (yorigin * 256)));
}
radeon_lock_cursor(crtc, false);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index f97563db4e59..a162ade74b7f 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -48,6 +48,8 @@ static void radeon_surface_init(struct radeon_device *rdev)
i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
0);
}
+ /* enable surfaces */
+ WREG32(RADEON_SURFACE_CNTL, 0);
}
}
@@ -119,7 +121,7 @@ int radeon_mc_setup(struct radeon_device *rdev)
if (rdev->mc.vram_location != 0xFFFFFFFFUL) {
/* vram location was already setup try to put gtt after
* if it fits */
- tmp = rdev->mc.vram_location + rdev->mc.vram_size;
+ tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;
tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
rdev->mc.gtt_location = tmp;
@@ -134,13 +136,13 @@ int radeon_mc_setup(struct radeon_device *rdev)
} else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) {
/* gtt location was already setup try to put vram before
* if it fits */
- if (rdev->mc.vram_size < rdev->mc.gtt_location) {
+ if (rdev->mc.mc_vram_size < rdev->mc.gtt_location) {
rdev->mc.vram_location = 0;
} else {
tmp = rdev->mc.gtt_location + rdev->mc.gtt_size;
- tmp += (rdev->mc.vram_size - 1);
- tmp &= ~(rdev->mc.vram_size - 1);
- if ((0xFFFFFFFFUL - tmp) >= rdev->mc.vram_size) {
+ tmp += (rdev->mc.mc_vram_size - 1);
+ tmp &= ~(rdev->mc.mc_vram_size - 1);
+ if ((0xFFFFFFFFUL - tmp) >= rdev->mc.mc_vram_size) {
rdev->mc.vram_location = tmp;
} else {
printk(KERN_ERR "[drm] vram too big to fit "
@@ -150,12 +152,14 @@ int radeon_mc_setup(struct radeon_device *rdev)
}
} else {
rdev->mc.vram_location = 0;
- rdev->mc.gtt_location = rdev->mc.vram_size;
+ rdev->mc.gtt_location = rdev->mc.mc_vram_size;
}
- DRM_INFO("radeon: VRAM %uM\n", rdev->mc.vram_size >> 20);
+ DRM_INFO("radeon: VRAM %uM\n", rdev->mc.real_vram_size >> 20);
DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",
rdev->mc.vram_location,
- rdev->mc.vram_location + rdev->mc.vram_size - 1);
+ rdev->mc.vram_location + rdev->mc.mc_vram_size - 1);
+ if (rdev->mc.real_vram_size != rdev->mc.mc_vram_size)
+ DRM_INFO("radeon: VRAM less than aperture workaround enabled\n");
DRM_INFO("radeon: GTT %uM\n", rdev->mc.gtt_size >> 20);
DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n",
rdev->mc.gtt_location,
@@ -450,6 +454,7 @@ int radeon_device_init(struct radeon_device *rdev,
uint32_t flags)
{
int r, ret;
+ int dma_bits;
DRM_INFO("radeon: Initializing kernel modesetting.\n");
rdev->shutdown = false;
@@ -492,8 +497,20 @@ int radeon_device_init(struct radeon_device *rdev,
return r;
}
- /* Report DMA addressing limitation */
- r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(32));
+ /* set DMA mask + need_dma32 flags.
+ * PCIE - can handle 40-bits.
+ * IGP - can handle 40-bits (in theory)
+ * AGP - generally dma32 is safest
+ * PCI - only dma32
+ */
+ rdev->need_dma32 = false;
+ if (rdev->flags & RADEON_IS_AGP)
+ rdev->need_dma32 = true;
+ if (rdev->flags & RADEON_IS_PCI)
+ rdev->need_dma32 = true;
+
+ dma_bits = rdev->need_dma32 ? 32 : 40;
+ r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
if (r) {
printk(KERN_WARNING "radeon: No suitable DMA available.\n");
}
@@ -546,27 +563,22 @@ int radeon_device_init(struct radeon_device *rdev,
radeon_combios_asic_init(rdev->ddev);
}
}
+ /* Initialize clocks */
+ r = radeon_clocks_init(rdev);
+ if (r) {
+ return r;
+ }
/* Get vram informations */
radeon_vram_info(rdev);
- /* Device is severly broken if aper size > vram size.
- * for RN50/M6/M7 - Novell bug 204882 ?
- */
- if (rdev->mc.vram_size < rdev->mc.aper_size) {
- rdev->mc.aper_size = rdev->mc.vram_size;
- }
+
/* Add an MTRR for the VRAM */
rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size,
MTRR_TYPE_WRCOMB, 1);
DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n",
- rdev->mc.vram_size >> 20,
+ rdev->mc.real_vram_size >> 20,
(unsigned)rdev->mc.aper_size >> 20);
DRM_INFO("RAM width %dbits %cDR\n",
rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S');
- /* Initialize clocks */
- r = radeon_clocks_init(rdev);
- if (r) {
- return r;
- }
/* Initialize memory controller (also test AGP) */
r = radeon_mc_init(rdev);
if (r) {
@@ -626,6 +638,9 @@ int radeon_device_init(struct radeon_device *rdev,
if (!ret) {
DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
}
+ if (radeon_testing) {
+ radeon_test_moves(rdev);
+ }
if (radeon_benchmarking) {
radeon_benchmark(rdev);
}
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 3efcf1a526be..a8fa1bb84cf7 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -187,6 +187,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
radeon_crtc->crtc_id = index;
+ rdev->mode_info.crtcs[index] = radeon_crtc;
radeon_crtc->mode_set.crtc = &radeon_crtc->base;
radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
@@ -491,7 +492,11 @@ void radeon_compute_pll(struct radeon_pll *pll,
tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;
current_freq = radeon_div(tmp, ref_div * post_div);
- error = abs(current_freq - freq);
+ if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
+ error = freq - current_freq;
+ error = error < 0 ? 0xffffffff : error;
+ } else
+ error = abs(current_freq - freq);
vco_diff = abs(vco - best_vco);
if ((best_vco == 0 && error < best_error) ||
@@ -657,36 +662,51 @@ void radeon_modeset_fini(struct radeon_device *rdev)
}
}
-void radeon_init_disp_bandwidth(struct drm_device *dev)
+bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct radeon_device *rdev = dev->dev_private;
- struct drm_display_mode *modes[2];
- int pixel_bytes[2];
- struct drm_crtc *crtc;
-
- pixel_bytes[0] = pixel_bytes[1] = 0;
- modes[0] = modes[1] = NULL;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *encoder;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct radeon_encoder *radeon_encoder;
+ bool first = true;
- if (crtc->enabled && crtc->fb) {
- modes[radeon_crtc->crtc_id] = &crtc->mode;
- pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8;
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ radeon_encoder = to_radeon_encoder(encoder);
+ if (encoder->crtc != crtc)
+ continue;
+ if (first) {
+ radeon_crtc->rmx_type = radeon_encoder->rmx_type;
+ radeon_crtc->devices = radeon_encoder->devices;
+ memcpy(&radeon_crtc->native_mode,
+ &radeon_encoder->native_mode,
+ sizeof(struct radeon_native_mode));
+ first = false;
+ } else {
+ if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) {
+ /* WARNING: Right now this can't happen but
+ * in the future we need to check that scaling
+ * are consistent accross different encoder
+ * (ie all encoder can work with the same
+ * scaling).
+ */
+ DRM_ERROR("Scaling not consistent accross encoder.\n");
+ return false;
+ }
}
}
-
- if (ASIC_IS_AVIVO(rdev)) {
- radeon_init_disp_bw_avivo(dev,
- modes[0],
- pixel_bytes[0],
- modes[1],
- pixel_bytes[1]);
+ 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);
+ 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);
+ radeon_crtc->hsc.full = rfixed_div(a, b);
} else {
- radeon_init_disp_bw_legacy(dev,
- modes[0],
- pixel_bytes[0],
- modes[1],
- pixel_bytes[1]);
+ radeon_crtc->vsc.full = rfixed_const(1);
+ radeon_crtc->hsc.full = rfixed_const(1);
}
+ return true;
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 84ba69f48784..3cfcee17dc56 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -89,6 +89,7 @@ int radeon_agpmode = 0;
int radeon_vram_limit = 0;
int radeon_gart_size = 512; /* default gart size */
int radeon_benchmarking = 0;
+int radeon_testing = 0;
int radeon_connector_table = 0;
#endif
@@ -117,6 +118,9 @@ module_param_named(gartsize, radeon_gart_size, int, 0600);
MODULE_PARM_DESC(benchmark, "Run benchmark");
module_param_named(benchmark, radeon_benchmarking, int, 0444);
+MODULE_PARM_DESC(test, "Run tests");
+module_param_named(test, radeon_testing, int, 0444);
+
MODULE_PARM_DESC(connector_table, "Force connector table");
module_param_named(connector_table, radeon_connector_table, int, 0444);
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index c8ef0d14ffab..0a92706eac19 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -154,7 +154,6 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder,
if (mode->hdisplay < native_mode->panel_xres ||
mode->vdisplay < native_mode->panel_yres) {
- radeon_encoder->flags |= RADEON_USE_RMX;
if (ASIC_IS_AVIVO(rdev)) {
adjusted_mode->hdisplay = native_mode->panel_xres;
adjusted_mode->vdisplay = native_mode->panel_yres;
@@ -197,15 +196,13 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder,
}
}
+
static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
-
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- radeon_encoder->flags &= ~RADEON_USE_RMX;
-
drm_mode_set_crtcinfo(adjusted_mode, 0);
if (radeon_encoder->rmx_type != RMX_OFF)
@@ -808,234 +805,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
}
-static void atom_rv515_force_tv_scaler(struct radeon_device *rdev)
-{
-
- WREG32(0x659C, 0x0);
- WREG32(0x6594, 0x705);
- WREG32(0x65A4, 0x10001);
- WREG32(0x65D8, 0x0);
- WREG32(0x65B0, 0x0);
- WREG32(0x65C0, 0x0);
- WREG32(0x65D4, 0x0);
- WREG32(0x6578, 0x0);
- WREG32(0x657C, 0x841880A8);
- WREG32(0x6578, 0x1);
- WREG32(0x657C, 0x84208680);
- WREG32(0x6578, 0x2);
- WREG32(0x657C, 0xBFF880B0);
- WREG32(0x6578, 0x100);
- WREG32(0x657C, 0x83D88088);
- WREG32(0x6578, 0x101);
- WREG32(0x657C, 0x84608680);
- WREG32(0x6578, 0x102);
- WREG32(0x657C, 0xBFF080D0);
- WREG32(0x6578, 0x200);
- WREG32(0x657C, 0x83988068);
- WREG32(0x6578, 0x201);
- WREG32(0x657C, 0x84A08680);
- WREG32(0x6578, 0x202);
- WREG32(0x657C, 0xBFF080F8);
- WREG32(0x6578, 0x300);
- WREG32(0x657C, 0x83588058);
- WREG32(0x6578, 0x301);
- WREG32(0x657C, 0x84E08660);
- WREG32(0x6578, 0x302);
- WREG32(0x657C, 0xBFF88120);
- WREG32(0x6578, 0x400);
- WREG32(0x657C, 0x83188040);
- WREG32(0x6578, 0x401);
- WREG32(0x657C, 0x85008660);
- WREG32(0x6578, 0x402);
- WREG32(0x657C, 0xBFF88150);
- WREG32(0x6578, 0x500);
- WREG32(0x657C, 0x82D88030);
- WREG32(0x6578, 0x501);
- WREG32(0x657C, 0x85408640);
- WREG32(0x6578, 0x502);
- WREG32(0x657C, 0xBFF88180);
- WREG32(0x6578, 0x600);
- WREG32(0x657C, 0x82A08018);
- WREG32(0x6578, 0x601);
- WREG32(0x657C, 0x85808620);
- WREG32(0x6578, 0x602);
- WREG32(0x657C, 0xBFF081B8);
- WREG32(0x6578, 0x700);
- WREG32(0x657C, 0x82608010);
- WREG32(0x6578, 0x701);
- WREG32(0x657C, 0x85A08600);
- WREG32(0x6578, 0x702);
- WREG32(0x657C, 0x800081F0);
- WREG32(0x6578, 0x800);
- WREG32(0x657C, 0x8228BFF8);
- WREG32(0x6578, 0x801);
- WREG32(0x657C, 0x85E085E0);
- WREG32(0x6578, 0x802);
- WREG32(0x657C, 0xBFF88228);
- WREG32(0x6578, 0x10000);
- WREG32(0x657C, 0x82A8BF00);
- WREG32(0x6578, 0x10001);
- WREG32(0x657C, 0x82A08CC0);
- WREG32(0x6578, 0x10002);
- WREG32(0x657C, 0x8008BEF8);
- WREG32(0x6578, 0x10100);
- WREG32(0x657C, 0x81F0BF28);
- WREG32(0x6578, 0x10101);
- WREG32(0x657C, 0x83608CA0);
- WREG32(0x6578, 0x10102);
- WREG32(0x657C, 0x8018BED0);
- WREG32(0x6578, 0x10200);
- WREG32(0x657C, 0x8148BF38);
- WREG32(0x6578, 0x10201);
- WREG32(0x657C, 0x84408C80);
- WREG32(0x6578, 0x10202);
- WREG32(0x657C, 0x8008BEB8);
- WREG32(0x6578, 0x10300);
- WREG32(0x657C, 0x80B0BF78);
- WREG32(0x6578, 0x10301);
- WREG32(0x657C, 0x85008C20);
- WREG32(0x6578, 0x10302);
- WREG32(0x657C, 0x8020BEA0);
- WREG32(0x6578, 0x10400);
- WREG32(0x657C, 0x8028BF90);
- WREG32(0x6578, 0x10401);
- WREG32(0x657C, 0x85E08BC0);
- WREG32(0x6578, 0x10402);
- WREG32(0x657C, 0x8018BE90);
- WREG32(0x6578, 0x10500);
- WREG32(0x657C, 0xBFB8BFB0);
- WREG32(0x6578, 0x10501);
- WREG32(0x657C, 0x86C08B40);
- WREG32(0x6578, 0x10502);
- WREG32(0x657C, 0x8010BE90);
- WREG32(0x6578, 0x10600);
- WREG32(0x657C, 0xBF58BFC8);
- WREG32(0x6578, 0x10601);
- WREG32(0x657C, 0x87A08AA0);
- WREG32(0x6578, 0x10602);
- WREG32(0x657C, 0x8010BE98);
- WREG32(0x6578, 0x10700);
- WREG32(0x657C, 0xBF10BFF0);
- WREG32(0x6578, 0x10701);
- WREG32(0x657C, 0x886089E0);
- WREG32(0x6578, 0x10702);
- WREG32(0x657C, 0x8018BEB0);
- WREG32(0x6578, 0x10800);
- WREG32(0x657C, 0xBED8BFE8);
- WREG32(0x6578, 0x10801);
- WREG32(0x657C, 0x89408940);
- WREG32(0x6578, 0x10802);
- WREG32(0x657C, 0xBFE8BED8);
- WREG32(0x6578, 0x20000);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20001);
- WREG32(0x657C, 0x90008000);
- WREG32(0x6578, 0x20002);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20003);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20100);
- WREG32(0x657C, 0x80108000);
- WREG32(0x6578, 0x20101);
- WREG32(0x657C, 0x8FE0BF70);
- WREG32(0x6578, 0x20102);
- WREG32(0x657C, 0xBFE880C0);
- WREG32(0x6578, 0x20103);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20200);
- WREG32(0x657C, 0x8018BFF8);
- WREG32(0x6578, 0x20201);
- WREG32(0x657C, 0x8F80BF08);
- WREG32(0x6578, 0x20202);
- WREG32(0x657C, 0xBFD081A0);
- WREG32(0x6578, 0x20203);
- WREG32(0x657C, 0xBFF88000);
- WREG32(0x6578, 0x20300);
- WREG32(0x657C, 0x80188000);
- WREG32(0x6578, 0x20301);
- WREG32(0x657C, 0x8EE0BEC0);
- WREG32(0x6578, 0x20302);
- WREG32(0x657C, 0xBFB082A0);
- WREG32(0x6578, 0x20303);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20400);
- WREG32(0x657C, 0x80188000);
- WREG32(0x6578, 0x20401);
- WREG32(0x657C, 0x8E00BEA0);
- WREG32(0x6578, 0x20402);
- WREG32(0x657C, 0xBF8883C0);
- WREG32(0x6578, 0x20403);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x20500);
- WREG32(0x657C, 0x80188000);
- WREG32(0x6578, 0x20501);
- WREG32(0x657C, 0x8D00BE90);
- WREG32(0x6578, 0x20502);
- WREG32(0x657C, 0xBF588500);
- WREG32(0x6578, 0x20503);
- WREG32(0x657C, 0x80008008);
- WREG32(0x6578, 0x20600);
- WREG32(0x657C, 0x80188000);
- WREG32(0x6578, 0x20601);
- WREG32(0x657C, 0x8BC0BE98);
- WREG32(0x6578, 0x20602);
- WREG32(0x657C, 0xBF308660);
- WREG32(0x6578, 0x20603);
- WREG32(0x657C, 0x80008008);
- WREG32(0x6578, 0x20700);
- WREG32(0x657C, 0x80108000);
- WREG32(0x6578, 0x20701);
- WREG32(0x657C, 0x8A80BEB0);
- WREG32(0x6578, 0x20702);
- WREG32(0x657C, 0xBF0087C0);
- WREG32(0x6578, 0x20703);
- WREG32(0x657C, 0x80008008);
- WREG32(0x6578, 0x20800);
- WREG32(0x657C, 0x80108000);
- WREG32(0x6578, 0x20801);
- WREG32(0x657C, 0x8920BED0);
- WREG32(0x6578, 0x20802);
- WREG32(0x657C, 0xBED08920);
- WREG32(0x6578, 0x20803);
- WREG32(0x657C, 0x80008010);
- WREG32(0x6578, 0x30000);
- WREG32(0x657C, 0x90008000);
- WREG32(0x6578, 0x30001);
- WREG32(0x657C, 0x80008000);
- WREG32(0x6578, 0x30100);
- WREG32(0x657C, 0x8FE0BF90);
- WREG32(0x6578, 0x30101);
- WREG32(0x657C, 0xBFF880A0);
- WREG32(0x6578, 0x30200);
- WREG32(0x657C, 0x8F60BF40);
- WREG32(0x6578, 0x30201);
- WREG32(0x657C, 0xBFE88180);
- WREG32(0x6578, 0x30300);
- WREG32(0x657C, 0x8EC0BF00);
- WREG32(0x6578, 0x30301);
- WREG32(0x657C, 0xBFC88280);
- WREG32(0x6578, 0x30400);
- WREG32(0x657C, 0x8DE0BEE0);
- WREG32(0x6578, 0x30401);
- WREG32(0x657C, 0xBFA083A0);
- WREG32(0x6578, 0x30500);
- WREG32(0x657C, 0x8CE0BED0);
- WREG32(0x6578, 0x30501);
- WREG32(0x657C, 0xBF7884E0);
- WREG32(0x6578, 0x30600);
- WREG32(0x657C, 0x8BA0BED8);
- WREG32(0x6578, 0x30601);
- WREG32(0x657C, 0xBF508640);
- WREG32(0x6578, 0x30700);
- WREG32(0x657C, 0x8A60BEE8);
- WREG32(0x6578, 0x30701);
- WREG32(0x657C, 0xBF2087A0);
- WREG32(0x6578, 0x30800);
- WREG32(0x657C, 0x8900BF00);
- WREG32(0x6578, 0x30801);
- WREG32(0x657C, 0xBF008900);
-}
-
static void
atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
{
@@ -1074,129 +843,6 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
}
static void
-atombios_overscan_setup(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- SET_CRTC_OVERSCAN_PS_ALLOCATION args;
- int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
-
- memset(&args, 0, sizeof(args));
-
- args.usOverscanRight = 0;
- args.usOverscanLeft = 0;
- args.usOverscanBottom = 0;
- args.usOverscanTop = 0;
- args.ucCRTC = radeon_crtc->crtc_id;
-
- if (radeon_encoder->flags & RADEON_USE_RMX) {
- if (radeon_encoder->rmx_type == RMX_FULL) {
- args.usOverscanRight = 0;
- args.usOverscanLeft = 0;
- args.usOverscanBottom = 0;
- args.usOverscanTop = 0;
- } else if (radeon_encoder->rmx_type == RMX_CENTER) {
- args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
- args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
- args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
- args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
- } else if (radeon_encoder->rmx_type == RMX_ASPECT) {
- int a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
- int a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
-
- if (a1 > a2) {
- args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
- args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
- } else if (a2 > a1) {
- args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
- args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
- }
- }
- }
-
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-}
-
-static void
-atombios_scaler_setup(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- ENABLE_SCALER_PS_ALLOCATION args;
- int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
- /* fixme - fill in enc_priv for atom dac */
- enum radeon_tv_std tv_std = TV_STD_NTSC;
-
- if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
- return;
-
- memset(&args, 0, sizeof(args));
-
- args.ucScaler = radeon_crtc->crtc_id;
-
- if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
- switch (tv_std) {
- case TV_STD_NTSC:
- default:
- args.ucTVStandard = ATOM_TV_NTSC;
- break;
- case TV_STD_PAL:
- args.ucTVStandard = ATOM_TV_PAL;
- break;
- case TV_STD_PAL_M:
- args.ucTVStandard = ATOM_TV_PALM;
- break;
- case TV_STD_PAL_60:
- args.ucTVStandard = ATOM_TV_PAL60;
- break;
- case TV_STD_NTSC_J:
- args.ucTVStandard = ATOM_TV_NTSCJ;
- break;
- case TV_STD_SCART_PAL:
- args.ucTVStandard = ATOM_TV_PAL; /* ??? */
- break;
- case TV_STD_SECAM:
- args.ucTVStandard = ATOM_TV_SECAM;
- break;
- case TV_STD_PAL_CN:
- args.ucTVStandard = ATOM_TV_PALCN;
- break;
- }
- args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
- } else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) {
- args.ucTVStandard = ATOM_TV_CV;
- args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
- } else if (radeon_encoder->flags & RADEON_USE_RMX) {
- if (radeon_encoder->rmx_type == RMX_FULL)
- args.ucEnable = ATOM_SCALER_EXPANSION;
- else if (radeon_encoder->rmx_type == RMX_CENTER)
- args.ucEnable = ATOM_SCALER_CENTER;
- else if (radeon_encoder->rmx_type == RMX_ASPECT)
- args.ucEnable = ATOM_SCALER_EXPANSION;
- } else {
- if (ASIC_IS_AVIVO(rdev))
- args.ucEnable = ATOM_SCALER_DISABLE;
- else
- args.ucEnable = ATOM_SCALER_CENTER;
- }
-
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
- if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
- && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) {
- atom_rv515_force_tv_scaler(rdev);
- }
-
-}
-
-static void
radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
@@ -1448,8 +1094,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
radeon_encoder->pixel_clock = adjusted_mode->clock;
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
- atombios_overscan_setup(encoder, mode, adjusted_mode);
- atombios_scaler_setup(encoder);
atombios_set_encoder_crtc_source(encoder);
if (ASIC_IS_AVIVO(rdev)) {
@@ -1667,6 +1311,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
radeon_encoder->encoder_id = encoder_id;
radeon_encoder->devices = supported_device;
+ radeon_encoder->rmx_type = RMX_OFF;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 9e8f191eb64a..3206c0ad7b6c 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -101,9 +101,10 @@ static int radeonfb_setcolreg(unsigned regno,
break;
case 24:
case 32:
- fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
- (green & 0xff00) |
- ((blue & 0xff00) >> 8);
+ 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;
}
}
@@ -154,6 +155,7 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var,
var->transp.length = 0;
var->transp.offset = 0;
break;
+#ifdef __LITTLE_ENDIAN
case 15:
var->red.offset = 10;
var->green.offset = 5;
@@ -194,6 +196,28 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var,
var->transp.length = 8;
var->transp.offset = 24;
break;
+#else
+ case 24:
+ var->red.offset = 8;
+ var->green.offset = 16;
+ var->blue.offset = 24;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 32:
+ var->red.offset = 8;
+ var->green.offset = 16;
+ var->blue.offset = 24;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 8;
+ var->transp.offset = 0;
+ break;
+#endif
default:
return -EINVAL;
}
@@ -447,10 +471,10 @@ static struct notifier_block paniced = {
.notifier_call = radeonfb_panic,
};
-static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp)
+static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
{
int aligned = width;
- int align_large = (ASIC_IS_AVIVO(rdev));
+ int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
int pitch_mask = 0;
switch (bpp / 8) {
@@ -488,12 +512,13 @@ int radeonfb_create(struct radeon_device *rdev,
u64 fb_gpuaddr;
void *fbptr = NULL;
unsigned long tmp;
+ bool fb_tiled = false; /* useful for testing */
mode_cmd.width = surface_width;
mode_cmd.height = surface_height;
mode_cmd.bpp = 32;
/* need to align pitch with crtc limits */
- mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8);
+ mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
mode_cmd.depth = 24;
size = mode_cmd.pitch * mode_cmd.height;
@@ -511,6 +536,8 @@ int radeonfb_create(struct radeon_device *rdev,
}
robj = gobj->driver_private;
+ if (fb_tiled)
+ radeon_object_set_tiling_flags(robj, RADEON_TILING_MACRO|RADEON_TILING_SURFACE, mode_cmd.pitch);
mutex_lock(&rdev->ddev->struct_mutex);
fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
if (fb == NULL) {
@@ -539,6 +566,9 @@ int radeonfb_create(struct radeon_device *rdev,
}
rfbdev = info->par;
+ if (fb_tiled)
+ radeon_object_check_tiling(robj, 0, 0);
+
ret = radeon_object_kmap(robj, &fbptr);
if (ret) {
goto out_unref;
@@ -572,6 +602,11 @@ int radeonfb_create(struct radeon_device *rdev,
info->var.width = -1;
info->var.xres = fb_width;
info->var.yres = fb_height;
+
+ /* setup aperture base/size for vesafb takeover */
+ info->aperture_base = rdev->ddev->mode_config.fb_base;
+ info->aperture_size = rdev->mc.real_vram_size;
+
info->fix.mmio_start = 0;
info->fix.mmio_len = 0;
info->pixmap.size = 64*1024;
@@ -600,6 +635,7 @@ int radeonfb_create(struct radeon_device *rdev,
info->var.transp.offset = 0;
info->var.transp.length = 0;
break;
+#ifdef __LITTLE_ENDIAN
case 15:
info->var.red.offset = 10;
info->var.green.offset = 5;
@@ -639,7 +675,29 @@ int radeonfb_create(struct radeon_device *rdev,
info->var.transp.offset = 24;
info->var.transp.length = 8;
break;
+#else
+ case 24:
+ info->var.red.offset = 8;
+ info->var.green.offset = 16;
+ info->var.blue.offset = 24;
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
+ info->var.transp.offset = 0;
+ info->var.transp.length = 0;
+ break;
+ case 32:
+ info->var.red.offset = 8;
+ info->var.green.offset = 16;
+ info->var.blue.offset = 24;
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
+ info->var.transp.offset = 0;
+ info->var.transp.length = 8;
+ break;
default:
+#endif
break;
}
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 96afbf5ae2ad..b4e48dd2e859 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -195,7 +195,7 @@ retry:
r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
radeon_fence_signaled(fence), timeout);
if (unlikely(r == -ERESTARTSYS)) {
- return -ERESTART;
+ return -EBUSY;
}
} else {
r = wait_event_timeout(rdev->fence_drv.queue,
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index d343a15316ec..2977539880fb 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -177,7 +177,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
return -ENOMEM;
}
rdev->gart.pages[p] = pagelist[i];
- page_base = (uint32_t)rdev->gart.pages_addr[p];
+ page_base = rdev->gart.pages_addr[p];
for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {
radeon_gart_set_page(rdev, t, page_base);
page_base += 4096;
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index eb516034235d..cded5180c752 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -157,9 +157,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
struct radeon_device *rdev = dev->dev_private;
struct drm_radeon_gem_info *args = data;
- args->vram_size = rdev->mc.vram_size;
+ args->vram_size = rdev->mc.real_vram_size;
/* FIXME: report somethings that makes sense */
- args->vram_visible = rdev->mc.vram_size - (4 * 1024 * 1024);
+ args->vram_visible = rdev->mc.real_vram_size - (4 * 1024 * 1024);
args->gart_size = rdev->mc.gtt_size;
return 0;
}
@@ -285,3 +285,44 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
mutex_unlock(&dev->struct_mutex);
return r;
}
+
+int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct drm_radeon_gem_set_tiling *args = data;
+ struct drm_gem_object *gobj;
+ struct radeon_object *robj;
+ int r = 0;
+
+ DRM_DEBUG("%d \n", args->handle);
+ gobj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (gobj == NULL)
+ return -EINVAL;
+ robj = gobj->driver_private;
+ radeon_object_set_tiling_flags(robj, args->tiling_flags, args->pitch);
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(gobj);
+ mutex_unlock(&dev->struct_mutex);
+ return r;
+}
+
+int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct drm_radeon_gem_get_tiling *args = data;
+ struct drm_gem_object *gobj;
+ struct radeon_object *robj;
+ int r = 0;
+
+ DRM_DEBUG("\n");
+ gobj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (gobj == NULL)
+ return -EINVAL;
+ robj = gobj->driver_private;
+ radeon_object_get_tiling_flags(robj, &args->tiling_flags,
+ &args->pitch);
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(gobj);
+ mutex_unlock(&dev->struct_mutex);
+ return r;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 4612a7c146d1..937a2f1cdb46 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -291,5 +291,7 @@ struct drm_ioctl_desc radeon_ioctls_kms[] = {
DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH),
};
int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 8086ecf7f03d..7d06dc98a42a 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -29,6 +29,171 @@
#include "radeon_fixed.h"
#include "radeon.h"
+static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ int xres = mode->hdisplay;
+ int yres = mode->vdisplay;
+ bool hscale = true, vscale = true;
+ int hsync_wid;
+ int vsync_wid;
+ int hsync_start;
+ int blank_width;
+ u32 scale, inc, crtc_more_cntl;
+ 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;
+
+ fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
+ (RADEON_VERT_STRETCH_RESERVED |
+ RADEON_VERT_AUTO_RATIO_INC);
+ fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
+ (RADEON_HORZ_FP_LOOP_STRETCH |
+ RADEON_HORZ_AUTO_RATIO_INC);
+
+ crtc_more_cntl = 0;
+ if ((rdev->family == CHIP_RS100) ||
+ (rdev->family == CHIP_RS200)) {
+ /* This is to workaround the asic bug for RMX, some versions
+ of BIOS dosen't have this register initialized correctly. */
+ crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
+ }
+
+
+ fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
+ | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
+
+ hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
+ if (!hsync_wid)
+ hsync_wid = 1;
+ hsync_start = mode->crtc_hsync_start - 8;
+
+ fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
+ | ((hsync_wid & 0x3f) << 16)
+ | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
+ ? RADEON_CRTC_H_SYNC_POL
+ : 0));
+
+ fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
+ | ((mode->crtc_vdisplay - 1) << 16));
+
+ vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ if (!vsync_wid)
+ vsync_wid = 1;
+
+ fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
+ | ((vsync_wid & 0x1f) << 16)
+ | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
+ ? RADEON_CRTC_V_SYNC_POL
+ : 0));
+
+ fp_horz_vert_active = 0;
+
+ if (native_mode->panel_xres == 0 ||
+ native_mode->panel_yres == 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->panel_xres)
+ hscale = false;
+ if (yres == native_mode->panel_yres)
+ vscale = false;
+ }
+
+ switch (radeon_crtc->rmx_type) {
+ case RMX_FULL:
+ case RMX_ASPECT:
+ if (!hscale)
+ fp_horz_stretch |= ((xres/8-1) << 16);
+ 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;
+ fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
+ RADEON_HORZ_STRETCH_BLEND |
+ RADEON_HORZ_STRETCH_ENABLE |
+ ((native_mode->panel_xres/8-1) << 16));
+ }
+
+ if (!vscale)
+ fp_vert_stretch |= ((yres-1) << 12);
+ 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;
+ fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
+ RADEON_VERT_STRETCH_ENABLE |
+ RADEON_VERT_STRETCH_BLEND |
+ ((native_mode->panel_yres-1) << 12));
+ }
+ break;
+ case RMX_CENTER:
+ fp_horz_stretch |= ((xres/8-1) << 16);
+ fp_vert_stretch |= ((yres-1) << 12);
+
+ crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
+ RADEON_CRTC_AUTO_VERT_CENTER_EN);
+
+ blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
+ if (blank_width > 110)
+ blank_width = 110;
+
+ fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
+ | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
+
+ hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
+ if (!hsync_wid)
+ hsync_wid = 1;
+
+ fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
+ | ((hsync_wid & 0x3f) << 16)
+ | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
+ ? RADEON_CRTC_H_SYNC_POL
+ : 0));
+
+ fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
+ | ((mode->crtc_vdisplay - 1) << 16));
+
+ vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ if (!vsync_wid)
+ vsync_wid = 1;
+
+ fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
+ | ((vsync_wid & 0x1f) << 16)
+ | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
+ ? RADEON_CRTC_V_SYNC_POL
+ : 0)));
+
+ fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) |
+ (((native_mode->panel_xres / 8) & 0x1ff) << 16));
+ break;
+ case RMX_OFF:
+ default:
+ fp_horz_stretch |= ((xres/8-1) << 16);
+ fp_vert_stretch |= ((yres-1) << 12);
+ break;
+ }
+
+ WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch);
+ WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch);
+ WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl);
+ WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active);
+ WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid);
+ WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid);
+ WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
+ WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
+}
+
void radeon_restore_common_regs(struct drm_device *dev)
{
/* don't need this yet */
@@ -235,6 +400,7 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
uint64_t base;
uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
uint32_t crtc_pitch, pitch_pixels;
+ uint32_t tiling_flags;
DRM_DEBUG("\n");
@@ -244,7 +410,12 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &base)) {
return -EINVAL;
}
- crtc_offset = (u32)base;
+ /* if scanout was in GTT this really wouldn't work */
+ /* crtc offset is from display base addr not FB location */
+ radeon_crtc->legacy_display_base_addr = rdev->mc.vram_location;
+
+ base -= radeon_crtc->legacy_display_base_addr;
+
crtc_offset_cntl = 0;
pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
@@ -253,8 +424,12 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
(crtc->fb->bits_per_pixel * 8));
crtc_pitch |= crtc_pitch << 16;
- /* TODO tiling */
- if (0) {
+ radeon_object_get_tiling_flags(obj->driver_private,
+ &tiling_flags, NULL);
+ if (tiling_flags & RADEON_TILING_MICRO)
+ DRM_ERROR("trying to scanout microtiled buffer\n");
+
+ if (tiling_flags & RADEON_TILING_MACRO) {
if (ASIC_IS_R300(rdev))
crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
R300_CRTC_MICRO_TILE_BUFFER_DIS |
@@ -270,15 +445,13 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
}
-
- /* TODO more tiling */
- if (0) {
+ if (tiling_flags & RADEON_TILING_MACRO) {
if (ASIC_IS_R300(rdev)) {
crtc_tile_x0_y0 = x | (y << 16);
base &= ~0x7ff;
} else {
int byteshift = crtc->fb->bits_per_pixel >> 4;
- int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11;
+ int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11;
base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
crtc_offset_cntl |= (y % 16);
}
@@ -303,11 +476,9 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
base &= ~7;
- /* update sarea TODO */
-
crtc_offset = (u32)base;
- WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, rdev->mc.vram_location);
+ WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);
if (ASIC_IS_R300(rdev)) {
if (radeon_crtc->crtc_id)
@@ -751,6 +922,8 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
+ return false;
return true;
}
@@ -759,16 +932,25 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode,
int x, int y, struct drm_framebuffer *old_fb)
{
-
- DRM_DEBUG("\n");
+ 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_init_disp_bandwidth(crtc->dev);
-
+ radeon_bandwidth_update(rdev);
+ if (radeon_crtc->crtc_id == 0) {
+ radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode);
+ } else {
+ if (radeon_crtc->rmx_type != RMX_OFF) {
+ /* FIXME: only first crtc has rmx what should we
+ * do ?
+ */
+ DRM_ERROR("Mode need scaling but only first crtc can do that.\n");
+ }
+ }
return 0;
}
@@ -799,478 +981,3 @@ void radeon_legacy_init_crtc(struct drm_device *dev,
radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
}
-
-void radeon_init_disp_bw_legacy(struct drm_device *dev,
- struct drm_display_mode *mode1,
- uint32_t pixel_bytes1,
- struct drm_display_mode *mode2,
- uint32_t pixel_bytes2)
-{
- struct radeon_device *rdev = dev->dev_private;
- fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff;
- fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff;
- fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff;
- uint32_t temp, data, mem_trcd, mem_trp, mem_tras;
- fixed20_12 memtcas_ff[8] = {
- fixed_init(1),
- fixed_init(2),
- fixed_init(3),
- fixed_init(0),
- fixed_init_half(1),
- fixed_init_half(2),
- fixed_init(0),
- };
- fixed20_12 memtcas_rs480_ff[8] = {
- fixed_init(0),
- fixed_init(1),
- fixed_init(2),
- fixed_init(3),
- fixed_init(0),
- fixed_init_half(1),
- fixed_init_half(2),
- fixed_init_half(3),
- };
- fixed20_12 memtcas2_ff[8] = {
- fixed_init(0),
- fixed_init(1),
- fixed_init(2),
- fixed_init(3),
- fixed_init(4),
- fixed_init(5),
- fixed_init(6),
- fixed_init(7),
- };
- fixed20_12 memtrbs[8] = {
- fixed_init(1),
- fixed_init_half(1),
- fixed_init(2),
- fixed_init_half(2),
- fixed_init(3),
- fixed_init_half(3),
- fixed_init(4),
- fixed_init_half(4)
- };
- fixed20_12 memtrbs_r4xx[8] = {
- fixed_init(4),
- fixed_init(5),
- fixed_init(6),
- fixed_init(7),
- fixed_init(8),
- fixed_init(9),
- fixed_init(10),
- fixed_init(11)
- };
- fixed20_12 min_mem_eff;
- fixed20_12 mc_latency_sclk, mc_latency_mclk, k1;
- fixed20_12 cur_latency_mclk, cur_latency_sclk;
- fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate,
- disp_drain_rate2, read_return_rate;
- fixed20_12 time_disp1_drop_priority;
- int c;
- int cur_size = 16; /* in octawords */
- int critical_point = 0, critical_point2;
-/* uint32_t read_return_rate, time_disp1_drop_priority; */
- int stop_req, max_stop_req;
-
- min_mem_eff.full = rfixed_const_8(0);
- /* get modes */
- if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) {
- uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER);
- mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT);
- mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT);
- /* check crtc enables */
- if (mode2)
- mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
- if (mode1)
- mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
- WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer);
- }
-
- /*
- * determine is there is enough bw for current mode
- */
- mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
- temp_ff.full = rfixed_const(100);
- mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
- sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
- sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
-
- temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
- temp_ff.full = rfixed_const(temp);
- mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
-
- pix_clk.full = 0;
- pix_clk2.full = 0;
- peak_disp_bw.full = 0;
- if (mode1) {
- temp_ff.full = rfixed_const(1000);
- pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */
- pix_clk.full = rfixed_div(pix_clk, temp_ff);
- temp_ff.full = rfixed_const(pixel_bytes1);
- peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
- }
- if (mode2) {
- temp_ff.full = rfixed_const(1000);
- pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */
- pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
- temp_ff.full = rfixed_const(pixel_bytes2);
- peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
- }
-
- mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
- if (peak_disp_bw.full >= mem_bw.full) {
- DRM_ERROR("You may not have enough display bandwidth for current mode\n"
- "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
- }
-
- /* Get values from the EXT_MEM_CNTL register...converting its contents. */
- temp = RREG32(RADEON_MEM_TIMING_CNTL);
- if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */
- mem_trcd = ((temp >> 2) & 0x3) + 1;
- mem_trp = ((temp & 0x3)) + 1;
- mem_tras = ((temp & 0x70) >> 4) + 1;
- } else if (rdev->family == CHIP_R300 ||
- rdev->family == CHIP_R350) { /* r300, r350 */
- mem_trcd = (temp & 0x7) + 1;
- mem_trp = ((temp >> 8) & 0x7) + 1;
- mem_tras = ((temp >> 11) & 0xf) + 4;
- } else if (rdev->family == CHIP_RV350 ||
- rdev->family <= CHIP_RV380) {
- /* rv3x0 */
- mem_trcd = (temp & 0x7) + 3;
- mem_trp = ((temp >> 8) & 0x7) + 3;
- mem_tras = ((temp >> 11) & 0xf) + 6;
- } else if (rdev->family == CHIP_R420 ||
- rdev->family == CHIP_R423 ||
- rdev->family == CHIP_RV410) {
- /* r4xx */
- mem_trcd = (temp & 0xf) + 3;
- if (mem_trcd > 15)
- mem_trcd = 15;
- mem_trp = ((temp >> 8) & 0xf) + 3;
- if (mem_trp > 15)
- mem_trp = 15;
- mem_tras = ((temp >> 12) & 0x1f) + 6;
- if (mem_tras > 31)
- mem_tras = 31;
- } else { /* RV200, R200 */
- mem_trcd = (temp & 0x7) + 1;
- mem_trp = ((temp >> 8) & 0x7) + 1;
- mem_tras = ((temp >> 12) & 0xf) + 4;
- }
- /* convert to FF */
- trcd_ff.full = rfixed_const(mem_trcd);
- trp_ff.full = rfixed_const(mem_trp);
- tras_ff.full = rfixed_const(mem_tras);
-
- /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
- temp = RREG32(RADEON_MEM_SDRAM_MODE_REG);
- data = (temp & (7 << 20)) >> 20;
- if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) {
- if (rdev->family == CHIP_RS480) /* don't think rs400 */
- tcas_ff = memtcas_rs480_ff[data];
- else
- tcas_ff = memtcas_ff[data];
- } else
- tcas_ff = memtcas2_ff[data];
-
- if (rdev->family == CHIP_RS400 ||
- rdev->family == CHIP_RS480) {
- /* extra cas latency stored in bits 23-25 0-4 clocks */
- data = (temp >> 23) & 0x7;
- if (data < 5)
- tcas_ff.full += rfixed_const(data);
- }
-
- if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) {
- /* on the R300, Tcas is included in Trbs.
- */
- temp = RREG32(RADEON_MEM_CNTL);
- data = (R300_MEM_NUM_CHANNELS_MASK & temp);
- if (data == 1) {
- if (R300_MEM_USE_CD_CH_ONLY & temp) {
- temp = RREG32(R300_MC_IND_INDEX);
- temp &= ~R300_MC_IND_ADDR_MASK;
- temp |= R300_MC_READ_CNTL_CD_mcind;
- WREG32(R300_MC_IND_INDEX, temp);
- temp = RREG32(R300_MC_IND_DATA);
- data = (R300_MEM_RBS_POSITION_C_MASK & temp);
- } else {
- temp = RREG32(R300_MC_READ_CNTL_AB);
- data = (R300_MEM_RBS_POSITION_A_MASK & temp);
- }
- } else {
- temp = RREG32(R300_MC_READ_CNTL_AB);
- data = (R300_MEM_RBS_POSITION_A_MASK & temp);
- }
- if (rdev->family == CHIP_RV410 ||
- rdev->family == CHIP_R420 ||
- rdev->family == CHIP_R423)
- trbs_ff = memtrbs_r4xx[data];
- else
- trbs_ff = memtrbs[data];
- tcas_ff.full += trbs_ff.full;
- }
-
- sclk_eff_ff.full = sclk_ff.full;
-
- if (rdev->flags & RADEON_IS_AGP) {
- fixed20_12 agpmode_ff;
- agpmode_ff.full = rfixed_const(radeon_agpmode);
- temp_ff.full = rfixed_const_666(16);
- sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff);
- }
- /* TODO PCIE lanes may affect this - agpmode == 16?? */
-
- if (ASIC_IS_R300(rdev)) {
- sclk_delay_ff.full = rfixed_const(250);
- } else {
- if ((rdev->family == CHIP_RV100) ||
- rdev->flags & RADEON_IS_IGP) {
- if (rdev->mc.vram_is_ddr)
- sclk_delay_ff.full = rfixed_const(41);
- else
- sclk_delay_ff.full = rfixed_const(33);
- } else {
- if (rdev->mc.vram_width == 128)
- sclk_delay_ff.full = rfixed_const(57);
- else
- sclk_delay_ff.full = rfixed_const(41);
- }
- }
-
- mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff);
-
- if (rdev->mc.vram_is_ddr) {
- if (rdev->mc.vram_width == 32) {
- k1.full = rfixed_const(40);
- c = 3;
- } else {
- k1.full = rfixed_const(20);
- c = 1;
- }
- } else {
- k1.full = rfixed_const(40);
- c = 3;
- }
-
- temp_ff.full = rfixed_const(2);
- mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff);
- temp_ff.full = rfixed_const(c);
- mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff);
- temp_ff.full = rfixed_const(4);
- mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff);
- mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff);
- mc_latency_mclk.full += k1.full;
-
- mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff);
- mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff);
-
- /*
- HW cursor time assuming worst case of full size colour cursor.
- */
- temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1))));
- temp_ff.full += trcd_ff.full;
- if (temp_ff.full < tras_ff.full)
- temp_ff.full = tras_ff.full;
- cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff);
-
- temp_ff.full = rfixed_const(cur_size);
- cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff);
- /*
- Find the total latency for the display data.
- */
- disp_latency_overhead.full = rfixed_const(80);
- 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;
-
- if (mc_latency_mclk.full > mc_latency_sclk.full)
- disp_latency.full = mc_latency_mclk.full;
- else
- disp_latency.full = mc_latency_sclk.full;
-
- /* setup Max GRPH_STOP_REQ default value */
- if (ASIC_IS_RV100(rdev))
- max_stop_req = 0x5c;
- else
- max_stop_req = 0x7c;
-
- if (mode1) {
- /* CRTC1
- Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
- GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
- */
- stop_req = mode1->hdisplay * pixel_bytes1 / 16;
-
- if (stop_req > max_stop_req)
- stop_req = max_stop_req;
-
- /*
- Find the drain rate of the display buffer.
- */
- temp_ff.full = rfixed_const((16/pixel_bytes1));
- disp_drain_rate.full = rfixed_div(pix_clk, temp_ff);
-
- /*
- Find the critical point of the display buffer.
- */
- crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency);
- crit_point_ff.full += rfixed_const_half(0);
-
- critical_point = rfixed_trunc(crit_point_ff);
-
- if (rdev->disp_priority == 2) {
- critical_point = 0;
- }
-
- /*
- The critical point should never be above max_stop_req-4. Setting
- GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
- */
- if (max_stop_req - critical_point < 4)
- critical_point = 0;
-
- if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) {
- /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
- critical_point = 0x10;
- }
-
- temp = RREG32(RADEON_GRPH_BUFFER_CNTL);
- temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
- temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
- temp &= ~(RADEON_GRPH_START_REQ_MASK);
- if ((rdev->family == CHIP_R350) &&
- (stop_req > 0x15)) {
- stop_req -= 0x10;
- }
- temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
- temp |= RADEON_GRPH_BUFFER_SIZE;
- temp &= ~(RADEON_GRPH_CRITICAL_CNTL |
- RADEON_GRPH_CRITICAL_AT_SOF |
- RADEON_GRPH_STOP_CNTL);
- /*
- Write the result into the register.
- */
- WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
- (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
-
-#if 0
- if ((rdev->family == CHIP_RS400) ||
- (rdev->family == CHIP_RS480)) {
- /* attempt to program RS400 disp regs correctly ??? */
- temp = RREG32(RS400_DISP1_REG_CNTL);
- temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK |
- RS400_DISP1_STOP_REQ_LEVEL_MASK);
- WREG32(RS400_DISP1_REQ_CNTL1, (temp |
- (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
- (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
- temp = RREG32(RS400_DMIF_MEM_CNTL1);
- temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK |
- RS400_DISP1_CRITICAL_POINT_STOP_MASK);
- WREG32(RS400_DMIF_MEM_CNTL1, (temp |
- (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) |
- (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT)));
- }
-#endif
-
- DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n",
- /* (unsigned int)info->SavedReg->grph_buffer_cntl, */
- (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL));
- }
-
- if (mode2) {
- u32 grph2_cntl;
- stop_req = mode2->hdisplay * pixel_bytes2 / 16;
-
- if (stop_req > max_stop_req)
- stop_req = max_stop_req;
-
- /*
- Find the drain rate of the display buffer.
- */
- temp_ff.full = rfixed_const((16/pixel_bytes2));
- disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff);
-
- grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL);
- grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK);
- grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
- grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK);
- if ((rdev->family == CHIP_R350) &&
- (stop_req > 0x15)) {
- stop_req -= 0x10;
- }
- grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
- grph2_cntl |= RADEON_GRPH_BUFFER_SIZE;
- grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL |
- RADEON_GRPH_CRITICAL_AT_SOF |
- RADEON_GRPH_STOP_CNTL);
-
- if ((rdev->family == CHIP_RS100) ||
- (rdev->family == CHIP_RS200))
- critical_point2 = 0;
- else {
- temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128;
- temp_ff.full = rfixed_const(temp);
- temp_ff.full = rfixed_mul(mclk_ff, temp_ff);
- if (sclk_ff.full < temp_ff.full)
- temp_ff.full = sclk_ff.full;
-
- read_return_rate.full = temp_ff.full;
-
- if (mode1) {
- temp_ff.full = read_return_rate.full - disp_drain_rate.full;
- time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff);
- } else {
- time_disp1_drop_priority.full = 0;
- }
- crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full;
- crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2);
- crit_point_ff.full += rfixed_const_half(0);
-
- critical_point2 = rfixed_trunc(crit_point_ff);
-
- if (rdev->disp_priority == 2) {
- critical_point2 = 0;
- }
-
- if (max_stop_req - critical_point2 < 4)
- critical_point2 = 0;
-
- }
-
- if (critical_point2 == 0 && rdev->family == CHIP_R300) {
- /* some R300 cards have problem with this set to 0 */
- critical_point2 = 0x10;
- }
-
- WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
- (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
-
- if ((rdev->family == CHIP_RS400) ||
- (rdev->family == CHIP_RS480)) {
-#if 0
- /* attempt to program RS400 disp2 regs correctly ??? */
- temp = RREG32(RS400_DISP2_REQ_CNTL1);
- temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK |
- RS400_DISP2_STOP_REQ_LEVEL_MASK);
- WREG32(RS400_DISP2_REQ_CNTL1, (temp |
- (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
- (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
- temp = RREG32(RS400_DISP2_REQ_CNTL2);
- temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK |
- RS400_DISP2_CRITICAL_POINT_STOP_MASK);
- WREG32(RS400_DISP2_REQ_CNTL2, (temp |
- (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) |
- (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT)));
-#endif
- WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC);
- WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000);
- WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC);
- WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
- }
-
- DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n",
- (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
- }
-}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 2c2f42de1d4c..34d0f58eb944 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -30,170 +30,6 @@
#include "atom.h"
-static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- int xres = mode->hdisplay;
- int yres = mode->vdisplay;
- bool hscale = true, vscale = true;
- int hsync_wid;
- int vsync_wid;
- int hsync_start;
- uint32_t scale, inc;
- uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active;
- uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp;
- struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
-
- DRM_DEBUG("\n");
-
- fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
- (RADEON_VERT_STRETCH_RESERVED |
- RADEON_VERT_AUTO_RATIO_INC);
- fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
- (RADEON_HORZ_FP_LOOP_STRETCH |
- RADEON_HORZ_AUTO_RATIO_INC);
-
- crtc_more_cntl = 0;
- if ((rdev->family == CHIP_RS100) ||
- (rdev->family == CHIP_RS200)) {
- /* This is to workaround the asic bug for RMX, some versions
- of BIOS dosen't have this register initialized correctly. */
- crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
- }
-
-
- fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
- | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
-
- hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
- if (!hsync_wid)
- hsync_wid = 1;
- hsync_start = mode->crtc_hsync_start - 8;
-
- fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
- | ((hsync_wid & 0x3f) << 16)
- | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
- ? RADEON_CRTC_H_SYNC_POL
- : 0));
-
- fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
- | ((mode->crtc_vdisplay - 1) << 16));
-
- vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
- if (!vsync_wid)
- vsync_wid = 1;
-
- fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
- | ((vsync_wid & 0x1f) << 16)
- | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
- ? RADEON_CRTC_V_SYNC_POL
- : 0));
-
- fp_horz_vert_active = 0;
-
- if (native_mode->panel_xres == 0 ||
- native_mode->panel_yres == 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->panel_xres)
- hscale = false;
- if (yres == native_mode->panel_yres)
- vscale = false;
- }
-
- if (radeon_encoder->flags & RADEON_USE_RMX) {
- if (radeon_encoder->rmx_type != RMX_CENTER) {
- if (!hscale)
- fp_horz_stretch |= ((xres/8-1) << 16);
- 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;
- fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
- RADEON_HORZ_STRETCH_BLEND |
- RADEON_HORZ_STRETCH_ENABLE |
- ((native_mode->panel_xres/8-1) << 16));
- }
-
- if (!vscale)
- fp_vert_stretch |= ((yres-1) << 12);
- 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;
- fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
- RADEON_VERT_STRETCH_ENABLE |
- RADEON_VERT_STRETCH_BLEND |
- ((native_mode->panel_yres-1) << 12));
- }
- } else if (radeon_encoder->rmx_type == RMX_CENTER) {
- int blank_width;
-
- fp_horz_stretch |= ((xres/8-1) << 16);
- fp_vert_stretch |= ((yres-1) << 12);
-
- crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
- RADEON_CRTC_AUTO_VERT_CENTER_EN);
-
- blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
- if (blank_width > 110)
- blank_width = 110;
-
- fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
- | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
-
- hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
- if (!hsync_wid)
- hsync_wid = 1;
-
- fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
- | ((hsync_wid & 0x3f) << 16)
- | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
- ? RADEON_CRTC_H_SYNC_POL
- : 0));
-
- fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
- | ((mode->crtc_vdisplay - 1) << 16));
-
- vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
- if (!vsync_wid)
- vsync_wid = 1;
-
- fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
- | ((vsync_wid & 0x1f) << 16)
- | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
- ? RADEON_CRTC_V_SYNC_POL
- : 0)));
-
- fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) |
- (((native_mode->panel_xres / 8) & 0x1ff) << 16));
- }
- } else {
- fp_horz_stretch |= ((xres/8-1) << 16);
- fp_vert_stretch |= ((yres-1) << 12);
- }
-
- WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch);
- WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch);
- WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl);
- WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active);
- WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid);
- WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid);
- WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
- WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
-
-}
-
static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
@@ -287,9 +123,6 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
DRM_DEBUG("\n");
- if (radeon_crtc->crtc_id == 0)
- radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
-
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN;
@@ -318,7 +151,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
if (radeon_crtc->crtc_id == 0) {
if (ASIC_IS_R300(rdev)) {
- if (radeon_encoder->flags & RADEON_USE_RMX)
+ if (radeon_encoder->rmx_type != RMX_OFF)
lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX;
} else
lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2;
@@ -350,8 +183,6 @@ static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder,
drm_mode_set_crtcinfo(adjusted_mode, 0);
- radeon_encoder->flags &= ~RADEON_USE_RMX;
-
if (radeon_encoder->rmx_type != RMX_OFF)
radeon_rmx_mode_fixup(encoder, mode, adjusted_mode);
@@ -455,9 +286,6 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder,
DRM_DEBUG("\n");
- if (radeon_crtc->crtc_id == 0)
- radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
-
if (radeon_crtc->crtc_id == 0) {
if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) &
@@ -653,9 +481,6 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
DRM_DEBUG("\n");
- if (radeon_crtc->crtc_id == 0)
- radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
-
tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL);
tmp &= 0xfffff;
if (rdev->family == CHIP_RV280) {
@@ -711,7 +536,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
if (radeon_crtc->crtc_id == 0) {
if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
- if (radeon_encoder->flags & RADEON_USE_RMX)
+ if (radeon_encoder->rmx_type != RMX_OFF)
fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
else
fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
@@ -820,9 +645,6 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
DRM_DEBUG("\n");
- if (radeon_crtc->crtc_id == 0)
- radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
-
if (rdev->is_atom_bios) {
radeon_encoder->pixel_clock = adjusted_mode->clock;
atombios_external_tmds_setup(encoder, ATOM_ENABLE);
@@ -856,7 +678,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
if (radeon_crtc->crtc_id == 0) {
if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {
fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
- if (radeon_encoder->flags & RADEON_USE_RMX)
+ if (radeon_encoder->rmx_type != RMX_OFF)
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;
else
fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1;
@@ -1014,9 +836,6 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
DRM_DEBUG("\n");
- if (radeon_crtc->crtc_id == 0)
- radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
-
if (rdev->family != CHIP_R200) {
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
if (rdev->family == CHIP_R420 ||
@@ -1243,6 +1062,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t
radeon_encoder->encoder_id = encoder_id;
radeon_encoder->devices = supported_device;
+ radeon_encoder->rmx_type = RMX_OFF;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 9173b687462b..3b09a1f2d8f9 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -36,6 +36,9 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
+#include "radeon_fixed.h"
+
+struct radeon_device;
#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)
#define to_radeon_connector(x) container_of(x, struct radeon_connector, base)
@@ -124,6 +127,7 @@ struct radeon_tmds_pll {
#define RADEON_PLL_PREFER_LOW_POST_DIV (1 << 8)
#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9)
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
+#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
struct radeon_pll {
uint16_t reference_freq;
@@ -170,6 +174,18 @@ struct radeon_mode_info {
struct atom_context *atom_context;
enum radeon_connector_table connector_table;
bool mode_config_initialized;
+ struct radeon_crtc *crtcs[2];
+};
+
+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;
};
struct radeon_crtc {
@@ -185,19 +201,13 @@ struct radeon_crtc {
uint64_t cursor_addr;
int cursor_width;
int cursor_height;
-};
-
-#define RADEON_USE_RMX 1
-
-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;
+ uint32_t legacy_display_base_addr;
+ uint32_t legacy_cursor_offset;
+ enum radeon_rmx_type rmx_type;
+ uint32_t devices;
+ fixed20_12 vsc;
+ fixed20_12 hsc;
+ struct radeon_native_mode native_mode;
};
struct radeon_encoder_primary_dac {
@@ -383,16 +393,9 @@ void radeon_enc_destroy(struct drm_encoder *encoder);
void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj);
void radeon_combios_asic_init(struct drm_device *dev);
extern int radeon_static_clocks_init(struct drm_device *dev);
-void radeon_init_disp_bw_legacy(struct drm_device *dev,
- struct drm_display_mode *mode1,
- uint32_t pixel_bytes1,
- struct drm_display_mode *mode2,
- uint32_t pixel_bytes2);
-void radeon_init_disp_bw_avivo(struct drm_device *dev,
- struct drm_display_mode *mode1,
- uint32_t pixel_bytes1,
- struct drm_display_mode *mode2,
- uint32_t pixel_bytes2);
-void radeon_init_disp_bandwidth(struct drm_device *dev);
+bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+void atom_rv515_force_tv_scaler(struct radeon_device *rdev);
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index bac0d06c52ac..dd9ac2fed6d6 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -44,6 +44,9 @@ struct radeon_object {
uint64_t gpu_addr;
void *kptr;
bool is_iomem;
+ uint32_t tiling_flags;
+ uint32_t pitch;
+ int surface_reg;
};
int radeon_ttm_init(struct radeon_device *rdev);
@@ -70,6 +73,7 @@ static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj)
robj = container_of(tobj, struct radeon_object, tobj);
list_del_init(&robj->list);
+ radeon_object_clear_surface_reg(robj);
kfree(robj);
}
@@ -99,16 +103,16 @@ static inline uint32_t radeon_object_flags_from_domain(uint32_t domain)
{
uint32_t flags = 0;
if (domain & RADEON_GEM_DOMAIN_VRAM) {
- flags |= TTM_PL_FLAG_VRAM;
+ flags |= TTM_PL_FLAG_VRAM | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;
}
if (domain & RADEON_GEM_DOMAIN_GTT) {
- flags |= TTM_PL_FLAG_TT;
+ flags |= TTM_PL_FLAG_TT | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;
}
if (domain & RADEON_GEM_DOMAIN_CPU) {
- flags |= TTM_PL_FLAG_SYSTEM;
+ flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;
}
if (!flags) {
- flags |= TTM_PL_FLAG_SYSTEM;
+ flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;
}
return flags;
}
@@ -141,6 +145,7 @@ int radeon_object_create(struct radeon_device *rdev,
}
robj->rdev = rdev;
robj->gobj = gobj;
+ robj->surface_reg = -1;
INIT_LIST_HEAD(&robj->list);
flags = radeon_object_flags_from_domain(domain);
@@ -304,7 +309,7 @@ int radeon_object_wait(struct radeon_object *robj)
}
spin_lock(&robj->tobj.lock);
if (robj->tobj.sync_obj) {
- r = ttm_bo_wait(&robj->tobj, true, false, false);
+ r = ttm_bo_wait(&robj->tobj, true, true, false);
}
spin_unlock(&robj->tobj.lock);
radeon_object_unreserve(robj);
@@ -403,7 +408,6 @@ int radeon_object_list_validate(struct list_head *head, void *fence)
struct radeon_object *robj;
struct radeon_fence *old_fence = NULL;
struct list_head *i;
- uint32_t flags;
int r;
r = radeon_object_list_reserve(head);
@@ -414,27 +418,25 @@ int radeon_object_list_validate(struct list_head *head, void *fence)
list_for_each(i, head) {
lobj = list_entry(i, struct radeon_object_list, list);
robj = lobj->robj;
- if (lobj->wdomain) {
- flags = radeon_object_flags_from_domain(lobj->wdomain);
- flags |= TTM_PL_FLAG_TT;
- } else {
- flags = radeon_object_flags_from_domain(lobj->rdomain);
- flags |= TTM_PL_FLAG_TT;
- flags |= TTM_PL_FLAG_VRAM;
- }
if (!robj->pin_count) {
- robj->tobj.proposed_placement = flags | TTM_PL_MASK_CACHING;
+ if (lobj->wdomain) {
+ robj->tobj.proposed_placement =
+ radeon_object_flags_from_domain(lobj->wdomain);
+ } else {
+ robj->tobj.proposed_placement =
+ radeon_object_flags_from_domain(lobj->rdomain);
+ }
r = ttm_buffer_object_validate(&robj->tobj,
robj->tobj.proposed_placement,
true, false);
if (unlikely(r)) {
- radeon_object_list_unreserve(head);
DRM_ERROR("radeon: failed to validate.\n");
return r;
}
radeon_object_gpu_addr(robj);
}
lobj->gpu_offset = robj->gpu_addr;
+ lobj->tiling_flags = robj->tiling_flags;
if (fence) {
old_fence = (struct radeon_fence *)robj->tobj.sync_obj;
robj->tobj.sync_obj = radeon_fence_ref(fence);
@@ -479,3 +481,127 @@ unsigned long radeon_object_size(struct radeon_object *robj)
{
return robj->tobj.num_pages << PAGE_SHIFT;
}
+
+int radeon_object_get_surface_reg(struct radeon_object *robj)
+{
+ struct radeon_device *rdev = robj->rdev;
+ struct radeon_surface_reg *reg;
+ struct radeon_object *old_object;
+ int steal;
+ int i;
+
+ if (!robj->tiling_flags)
+ return 0;
+
+ if (robj->surface_reg >= 0) {
+ reg = &rdev->surface_regs[robj->surface_reg];
+ i = robj->surface_reg;
+ goto out;
+ }
+
+ steal = -1;
+ for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
+
+ reg = &rdev->surface_regs[i];
+ if (!reg->robj)
+ break;
+
+ old_object = reg->robj;
+ if (old_object->pin_count == 0)
+ steal = i;
+ }
+
+ /* if we are all out */
+ if (i == RADEON_GEM_MAX_SURFACES) {
+ if (steal == -1)
+ return -ENOMEM;
+ /* find someone with a surface reg and nuke their BO */
+ reg = &rdev->surface_regs[steal];
+ old_object = reg->robj;
+ /* blow away the mapping */
+ DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object);
+ ttm_bo_unmap_virtual(&old_object->tobj);
+ old_object->surface_reg = -1;
+ i = steal;
+ }
+
+ robj->surface_reg = i;
+ reg->robj = robj;
+
+out:
+ radeon_set_surface_reg(rdev, i, robj->tiling_flags, robj->pitch,
+ robj->tobj.mem.mm_node->start << PAGE_SHIFT,
+ robj->tobj.num_pages << PAGE_SHIFT);
+ return 0;
+}
+
+void radeon_object_clear_surface_reg(struct radeon_object *robj)
+{
+ struct radeon_device *rdev = robj->rdev;
+ struct radeon_surface_reg *reg;
+
+ if (robj->surface_reg == -1)
+ return;
+
+ reg = &rdev->surface_regs[robj->surface_reg];
+ radeon_clear_surface_reg(rdev, robj->surface_reg);
+
+ reg->robj = NULL;
+ robj->surface_reg = -1;
+}
+
+void radeon_object_set_tiling_flags(struct radeon_object *robj,
+ uint32_t tiling_flags, uint32_t pitch)
+{
+ robj->tiling_flags = tiling_flags;
+ robj->pitch = pitch;
+}
+
+void radeon_object_get_tiling_flags(struct radeon_object *robj,
+ uint32_t *tiling_flags,
+ uint32_t *pitch)
+{
+ if (tiling_flags)
+ *tiling_flags = robj->tiling_flags;
+ if (pitch)
+ *pitch = robj->pitch;
+}
+
+int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved,
+ bool force_drop)
+{
+ if (!(robj->tiling_flags & RADEON_TILING_SURFACE))
+ return 0;
+
+ if (force_drop) {
+ radeon_object_clear_surface_reg(robj);
+ return 0;
+ }
+
+ if (robj->tobj.mem.mem_type != TTM_PL_VRAM) {
+ if (!has_moved)
+ return 0;
+
+ if (robj->surface_reg >= 0)
+ radeon_object_clear_surface_reg(robj);
+ return 0;
+ }
+
+ if ((robj->surface_reg >= 0) && !has_moved)
+ return 0;
+
+ return radeon_object_get_surface_reg(robj);
+}
+
+void radeon_bo_move_notify(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *mem)
+{
+ struct radeon_object *robj = container_of(bo, struct radeon_object, tobj);
+ radeon_object_check_tiling(robj, 0, 1);
+}
+
+void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
+{
+ struct radeon_object *robj = container_of(bo, struct radeon_object, tobj);
+ radeon_object_check_tiling(robj, 0, 0);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index a853261d1881..60d159308b88 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -126,32 +126,19 @@ static void radeon_ib_align(struct radeon_device *rdev, struct radeon_ib *ib)
}
}
-static void radeon_ib_cpu_flush(struct radeon_device *rdev,
- struct radeon_ib *ib)
-{
- unsigned long tmp;
- unsigned i;
-
- /* To force CPU cache flush ugly but seems reliable */
- for (i = 0; i < ib->length_dw; i += (rdev->cp.align_mask + 1)) {
- tmp = readl(&ib->ptr[i]);
- }
-}
-
int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
{
int r = 0;
mutex_lock(&rdev->ib_pool.mutex);
radeon_ib_align(rdev, ib);
- radeon_ib_cpu_flush(rdev, ib);
if (!ib->length_dw || !rdev->cp.ready) {
/* TODO: Nothings in the ib we should report. */
mutex_unlock(&rdev->ib_pool.mutex);
DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx);
return -EINVAL;
}
- /* 64 dwords should be enought for fence too */
+ /* 64 dwords should be enough for fence too */
r = radeon_ring_lock(rdev, 64);
if (r) {
DRM_ERROR("radeon: scheduling IB failled (%d).\n", r);
diff --git a/drivers/gpu/drm/radeon/radeon_share.h b/drivers/gpu/drm/radeon/radeon_share.h
new file mode 100644
index 000000000000..63a773578f17
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_share.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __RADEON_SHARE_H__
+#define __RADEON_SHARE_H__
+
+void r100_vram_init_sizes(struct radeon_device *rdev);
+
+void rs690_line_buffer_adjust(struct radeon_device *rdev,
+ struct drm_display_mode *mode1,
+ struct drm_display_mode *mode2);
+
+void rv515_bandwidth_avivo_update(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
new file mode 100644
index 000000000000..03c33cf4e14c
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2009 VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Michel Dänzer
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon_reg.h"
+#include "radeon.h"
+
+
+/* Test BO GTT->VRAM and VRAM->GTT GPU copies across the whole GTT aperture */
+void radeon_test_moves(struct radeon_device *rdev)
+{
+ struct radeon_object *vram_obj = NULL;
+ struct radeon_object **gtt_obj = NULL;
+ struct radeon_fence *fence = NULL;
+ uint64_t gtt_addr, vram_addr;
+ unsigned i, n, size;
+ int r;
+
+ size = 1024 * 1024;
+
+ /* Number of tests =
+ * (Total GTT - IB pool - writeback page - ring buffer) / test size
+ */
+ n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - 4096 -
+ rdev->cp.ring_size) / size;
+
+ gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
+ if (!gtt_obj) {
+ DRM_ERROR("Failed to allocate %d pointers\n", n);
+ r = 1;
+ goto out_cleanup;
+ }
+
+ r = radeon_object_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM,
+ false, &vram_obj);
+ if (r) {
+ DRM_ERROR("Failed to create VRAM object\n");
+ goto out_cleanup;
+ }
+
+ r = radeon_object_pin(vram_obj, RADEON_GEM_DOMAIN_VRAM, &vram_addr);
+ if (r) {
+ DRM_ERROR("Failed to pin VRAM object\n");
+ goto out_cleanup;
+ }
+
+ for (i = 0; i < n; i++) {
+ void *gtt_map, *vram_map;
+ void **gtt_start, **gtt_end;
+ void **vram_start, **vram_end;
+
+ r = radeon_object_create(rdev, NULL, size, true,
+ RADEON_GEM_DOMAIN_GTT, false, gtt_obj + i);
+ if (r) {
+ DRM_ERROR("Failed to create GTT object %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_object_pin(gtt_obj[i], RADEON_GEM_DOMAIN_GTT, &gtt_addr);
+ if (r) {
+ DRM_ERROR("Failed to pin GTT object %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_object_kmap(gtt_obj[i], &gtt_map);
+ if (r) {
+ DRM_ERROR("Failed to map GTT object %d\n", i);
+ goto out_cleanup;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size;
+ gtt_start < gtt_end;
+ gtt_start++)
+ *gtt_start = gtt_start;
+
+ radeon_object_kunmap(gtt_obj[i]);
+
+ r = radeon_fence_create(rdev, &fence);
+ if (r) {
+ DRM_ERROR("Failed to create GTT->VRAM fence %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_copy(rdev, gtt_addr, vram_addr, size / 4096, fence);
+ if (r) {
+ DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_fence_wait(fence, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i);
+ goto out_cleanup;
+ }
+
+ radeon_fence_unref(&fence);
+
+ r = radeon_object_kmap(vram_obj, &vram_map);
+ if (r) {
+ DRM_ERROR("Failed to map VRAM object after copy %d\n", i);
+ goto out_cleanup;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size,
+ vram_start = vram_map, vram_end = vram_map + size;
+ vram_start < vram_end;
+ gtt_start++, vram_start++) {
+ if (*vram_start != gtt_start) {
+ DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, "
+ "expected 0x%p (GTT map 0x%p-0x%p)\n",
+ i, *vram_start, gtt_start, gtt_map,
+ gtt_end);
+ radeon_object_kunmap(vram_obj);
+ goto out_cleanup;
+ }
+ *vram_start = vram_start;
+ }
+
+ radeon_object_kunmap(vram_obj);
+
+ r = radeon_fence_create(rdev, &fence);
+ if (r) {
+ DRM_ERROR("Failed to create VRAM->GTT fence %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_copy(rdev, vram_addr, gtt_addr, size / 4096, fence);
+ if (r) {
+ DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
+ goto out_cleanup;
+ }
+
+ r = radeon_fence_wait(fence, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i);
+ goto out_cleanup;
+ }
+
+ radeon_fence_unref(&fence);
+
+ r = radeon_object_kmap(gtt_obj[i], &gtt_map);
+ if (r) {
+ DRM_ERROR("Failed to map GTT object after copy %d\n", i);
+ goto out_cleanup;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size,
+ vram_start = vram_map, vram_end = vram_map + size;
+ gtt_start < gtt_end;
+ gtt_start++, vram_start++) {
+ if (*gtt_start != vram_start) {
+ DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, "
+ "expected 0x%p (VRAM map 0x%p-0x%p)\n",
+ i, *gtt_start, vram_start, vram_map,
+ vram_end);
+ radeon_object_kunmap(gtt_obj[i]);
+ goto out_cleanup;
+ }
+ }
+
+ radeon_object_kunmap(gtt_obj[i]);
+
+ DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n",
+ gtt_addr - rdev->mc.gtt_location);
+ }
+
+out_cleanup:
+ if (vram_obj) {
+ radeon_object_unpin(vram_obj);
+ radeon_object_unref(&vram_obj);
+ }
+ if (gtt_obj) {
+ for (i = 0; i < n; i++) {
+ if (gtt_obj[i]) {
+ radeon_object_unpin(gtt_obj[i]);
+ radeon_object_unref(&gtt_obj[i]);
+ }
+ }
+ kfree(gtt_obj);
+ }
+ if (fence) {
+ radeon_fence_unref(&fence);
+ }
+ if (r) {
+ printk(KERN_WARNING "Error while testing BO move.\n");
+ }
+}
+
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 1227a97f5169..15c3531377ed 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -355,23 +355,26 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
if (!rdev->cp.ready) {
/* use memcpy */
DRM_ERROR("CP is not ready use memcpy.\n");
- return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+ goto memcpy;
}
if (old_mem->mem_type == TTM_PL_VRAM &&
new_mem->mem_type == TTM_PL_SYSTEM) {
- return radeon_move_vram_ram(bo, evict, interruptible,
+ r = radeon_move_vram_ram(bo, evict, interruptible,
no_wait, new_mem);
} else if (old_mem->mem_type == TTM_PL_SYSTEM &&
new_mem->mem_type == TTM_PL_VRAM) {
- return radeon_move_ram_vram(bo, evict, interruptible,
+ r = radeon_move_ram_vram(bo, evict, interruptible,
no_wait, new_mem);
} else {
r = radeon_move_blit(bo, evict, no_wait, new_mem, old_mem);
- if (unlikely(r)) {
- return r;
- }
}
+
+ if (r) {
+memcpy:
+ r = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+ }
+
return r;
}
@@ -429,6 +432,8 @@ static struct ttm_bo_driver radeon_bo_driver = {
.sync_obj_flush = &radeon_sync_obj_flush,
.sync_obj_unref = &radeon_sync_obj_unref,
.sync_obj_ref = &radeon_sync_obj_ref,
+ .move_notify = &radeon_bo_move_notify,
+ .fault_reserve_notify = &radeon_bo_fault_reserve_notify,
};
int radeon_ttm_init(struct radeon_device *rdev)
@@ -442,13 +447,14 @@ int radeon_ttm_init(struct radeon_device *rdev)
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&rdev->mman.bdev,
rdev->mman.mem_global_ref.object,
- &radeon_bo_driver, DRM_FILE_PAGE_OFFSET);
+ &radeon_bo_driver, DRM_FILE_PAGE_OFFSET,
+ rdev->need_dma32);
if (r) {
DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
return r;
}
r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, 0,
- ((rdev->mc.aper_size) >> PAGE_SHIFT));
+ ((rdev->mc.real_vram_size) >> PAGE_SHIFT));
if (r) {
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
@@ -465,7 +471,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
return r;
}
DRM_INFO("radeon: %uM of VRAM memory ready\n",
- rdev->mc.vram_size / (1024 * 1024));
+ rdev->mc.real_vram_size / (1024 * 1024));
r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, 0,
((rdev->mc.gtt_size) >> PAGE_SHIFT));
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index cc074b5a8f74..b29affd9c5d8 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -29,6 +29,7 @@
#include <drm/drmP.h>
#include "radeon_reg.h"
#include "radeon.h"
+#include "radeon_share.h"
/* rs400,rs480 depends on : */
void r100_hdp_reset(struct radeon_device *rdev);
@@ -164,7 +165,9 @@ int rs400_gart_enable(struct radeon_device *rdev)
WREG32(RADEON_BUS_CNTL, tmp);
}
/* Table should be in 32bits address space so ignore bits above. */
- tmp = rdev->gart.table_addr & 0xfffff000;
+ tmp = (u32)rdev->gart.table_addr & 0xfffff000;
+ tmp |= (upper_32_bits(rdev->gart.table_addr) & 0xff) << 4;
+
WREG32_MC(RS480_GART_BASE, tmp);
/* TODO: more tweaking here */
WREG32_MC(RS480_GART_FEATURE_ID,
@@ -201,10 +204,17 @@ void rs400_gart_disable(struct radeon_device *rdev)
int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
{
+ uint32_t entry;
+
if (i < 0 || i > rdev->gart.num_gpu_pages) {
return -EINVAL;
}
- rdev->gart.table.ram.ptr[i] = cpu_to_le32(((uint32_t)addr) | 0xC);
+
+ entry = (lower_32_bits(addr) & PAGE_MASK) |
+ ((upper_32_bits(addr) & 0xff) << 4) |
+ 0xc;
+ entry = cpu_to_le32(entry);
+ rdev->gart.table.ram.ptr[i] = entry;
return 0;
}
@@ -223,10 +233,9 @@ int rs400_mc_init(struct radeon_device *rdev)
rs400_gpu_init(rdev);
rs400_gart_disable(rdev);
- rdev->mc.gtt_location = rdev->mc.vram_size;
+ 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;
@@ -238,7 +247,7 @@ int rs400_mc_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ 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);
@@ -284,21 +293,12 @@ void rs400_gpu_init(struct radeon_device *rdev)
*/
void rs400_vram_info(struct radeon_device *rdev)
{
- uint32_t tom;
-
rs400_gart_adjust_size(rdev);
/* DDR for all card after R300 & IGP */
rdev->mc.vram_is_ddr = true;
rdev->mc.vram_width = 128;
- /* read NB_TOM to get the amount of ram stolen for the GPU */
- tom = RREG32(RADEON_NB_TOM);
- rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
-
- /* Could aper size report 0 ? */
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ r100_vram_init_sizes(rdev);
}
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index ab0c967553e6..bbea6dee4a94 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -223,7 +223,7 @@ int rs600_mc_init(struct radeon_device *rdev)
printk(KERN_WARNING "Failed to wait MC idle while "
"programming pipes. Bad things might happen.\n");
}
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ 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);
@@ -301,6 +301,11 @@ void rs600_vram_info(struct radeon_device *rdev)
rdev->mc.vram_width = 128;
}
+void rs600_bandwidth_update(struct radeon_device *rdev)
+{
+ /* FIXME: implement, should this be like rs690 ? */
+}
+
/*
* Indirect registers accessor
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 79ba85042b5f..839595b00728 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -28,6 +28,9 @@
#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);
@@ -64,7 +67,7 @@ int rs690_mc_init(struct radeon_device *rdev)
rs400_gart_disable(rdev);
/* Setup GPU memory space */
- rdev->mc.gtt_location = rdev->mc.vram_size;
+ 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;
@@ -79,7 +82,7 @@ int rs690_mc_init(struct radeon_device *rdev)
printk(KERN_WARNING "Failed to wait MC idle while "
"programming pipes. Bad things might happen.\n");
}
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ 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);
@@ -138,9 +141,82 @@ void rs690_gpu_init(struct radeon_device *rdev)
/*
* VRAM info.
*/
+void rs690_pm_info(struct radeon_device *rdev)
+{
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ struct _ATOM_INTEGRATED_SYSTEM_INFO *info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *info_v2;
+ void *ptr;
+ uint16_t data_offset;
+ uint8_t frev, crev;
+ fixed20_12 tmp;
+
+ atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
+ &frev, &crev, &data_offset);
+ ptr = rdev->mode_info.atom_context->bios + data_offset;
+ info = (struct _ATOM_INTEGRATED_SYSTEM_INFO *)ptr;
+ info_v2 = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *)ptr;
+ /* Get various system informations from bios */
+ switch (crev) {
+ case 1:
+ tmp.full = rfixed_const(100);
+ rdev->pm.igp_sideport_mclk.full = rfixed_const(info->ulBootUpMemoryClock);
+ rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp);
+ rdev->pm.igp_system_mclk.full = rfixed_const(le16_to_cpu(info->usK8MemoryClock));
+ rdev->pm.igp_ht_link_clk.full = rfixed_const(le16_to_cpu(info->usFSBClock));
+ rdev->pm.igp_ht_link_width.full = rfixed_const(info->ucHTLinkWidth);
+ break;
+ case 2:
+ tmp.full = rfixed_const(100);
+ rdev->pm.igp_sideport_mclk.full = rfixed_const(info_v2->ulBootUpSidePortClock);
+ rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp);
+ rdev->pm.igp_system_mclk.full = rfixed_const(info_v2->ulBootUpUMAClock);
+ rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp);
+ rdev->pm.igp_ht_link_clk.full = rfixed_const(info_v2->ulHTLinkFreq);
+ rdev->pm.igp_ht_link_clk.full = rfixed_div(rdev->pm.igp_ht_link_clk, tmp);
+ rdev->pm.igp_ht_link_width.full = rfixed_const(le16_to_cpu(info_v2->usMinHTLinkWidth));
+ break;
+ default:
+ tmp.full = rfixed_const(100);
+ /* We assume the slower possible clock ie worst case */
+ /* DDR 333Mhz */
+ rdev->pm.igp_sideport_mclk.full = rfixed_const(333);
+ /* FIXME: system clock ? */
+ rdev->pm.igp_system_mclk.full = rfixed_const(100);
+ rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp);
+ rdev->pm.igp_ht_link_clk.full = rfixed_const(200);
+ rdev->pm.igp_ht_link_width.full = rfixed_const(8);
+ DRM_ERROR("No integrated system info for your GPU, using safe default\n");
+ break;
+ }
+ /* Compute various bandwidth */
+ /* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4 */
+ tmp.full = rfixed_const(4);
+ rdev->pm.k8_bandwidth.full = rfixed_mul(rdev->pm.igp_system_mclk, tmp);
+ /* ht_bandwidth = ht_clk * 2 * ht_width / 8 * 0.8
+ * = ht_clk * ht_width / 5
+ */
+ tmp.full = rfixed_const(5);
+ rdev->pm.ht_bandwidth.full = rfixed_mul(rdev->pm.igp_ht_link_clk,
+ rdev->pm.igp_ht_link_width);
+ rdev->pm.ht_bandwidth.full = rfixed_div(rdev->pm.ht_bandwidth, tmp);
+ if (tmp.full < rdev->pm.max_bandwidth.full) {
+ /* HT link is a limiting factor */
+ rdev->pm.max_bandwidth.full = tmp.full;
+ }
+ /* sideport_bandwidth = (sideport_clk / 2) * 2 * 2 * 0.7
+ * = (sideport_clk * 14) / 10
+ */
+ tmp.full = rfixed_const(14);
+ rdev->pm.sideport_bandwidth.full = rfixed_mul(rdev->pm.igp_sideport_mclk, tmp);
+ tmp.full = rfixed_const(10);
+ rdev->pm.sideport_bandwidth.full = rfixed_div(rdev->pm.sideport_bandwidth, tmp);
+}
+
void rs690_vram_info(struct radeon_device *rdev)
{
uint32_t tmp;
+ fixed20_12 a;
rs400_gart_adjust_size(rdev);
/* DDR for all card after R300 & IGP */
@@ -152,12 +228,409 @@ void rs690_vram_info(struct radeon_device *rdev)
} else {
rdev->mc.vram_width = 64;
}
- rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+ rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rs690_pm_info(rdev);
+ /* FIXME: we should enforce default clock in case GPU is not in
+ * default setup
+ */
+ a.full = rfixed_const(100);
+ rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
+ rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
+ a.full = rfixed_const(16);
+ /* core_bandwidth = sclk(Mhz) * 16 */
+ rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a);
+}
+
+void rs690_line_buffer_adjust(struct radeon_device *rdev,
+ struct drm_display_mode *mode1,
+ struct drm_display_mode *mode2)
+{
+ u32 tmp;
+
+ /*
+ * 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
+ * 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
+ * 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;
+ /* auto */
+ if (mode1 && mode2) {
+ if (mode1->hdisplay > mode2->hdisplay) {
+ if (mode1->hdisplay > 2560)
+ tmp |= DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
+ else
+ tmp |= 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;
+ else
+ tmp |= DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+ } else
+ tmp |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+ } else if (mode1) {
+ tmp |= DC_LB_MEMORY_SPLIT_D1_ONLY;
+ } else if (mode2) {
+ tmp |= DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
+ }
+ WREG32(DC_LB_MEMORY_SPLIT, tmp);
}
+struct rs690_watermark {
+ u32 lb_request_fifo_depth;
+ fixed20_12 num_line_pair;
+ fixed20_12 estimated_width;
+ fixed20_12 worst_case_latency;
+ fixed20_12 consumption_rate;
+ fixed20_12 active_time;
+ fixed20_12 dbpp;
+ fixed20_12 priority_mark_max;
+ fixed20_12 priority_mark;
+ fixed20_12 sclk;
+};
+
+void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
+ struct radeon_crtc *crtc,
+ struct rs690_watermark *wm)
+{
+ struct drm_display_mode *mode = &crtc->base.mode;
+ fixed20_12 a, b, c;
+ fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
+ fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+ /* FIXME: detect IGP with sideport memory, i don't think there is any
+ * such product available
+ */
+ bool sideport = false;
+
+ if (!crtc->base.enabled) {
+ /* FIXME: wouldn't it better to set priority mark to maximum */
+ wm->lb_request_fifo_depth = 4;
+ return;
+ }
+
+ if (crtc->vsc.full > rfixed_const(2))
+ wm->num_line_pair.full = rfixed_const(2);
+ else
+ wm->num_line_pair.full = rfixed_const(1);
+
+ b.full = rfixed_const(mode->crtc_hdisplay);
+ c.full = rfixed_const(256);
+ a.full = rfixed_mul(wm->num_line_pair, b);
+ request_fifo_depth.full = rfixed_div(a, c);
+ if (a.full < rfixed_const(4)) {
+ wm->lb_request_fifo_depth = 4;
+ } else {
+ wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth);
+ }
+
+ /* Determine consumption rate
+ * pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000)
+ * vtaps = number of vertical taps,
+ * vsc = vertical scaling ratio, defined as source/destination
+ * hsc = horizontal scaling ration, defined as source/destination
+ */
+ a.full = rfixed_const(mode->clock);
+ b.full = rfixed_const(1000);
+ a.full = rfixed_div(a, b);
+ pclk.full = rfixed_div(b, a);
+ if (crtc->rmx_type != RMX_OFF) {
+ b.full = rfixed_const(2);
+ if (crtc->vsc.full > b.full)
+ b.full = crtc->vsc.full;
+ b.full = rfixed_mul(b, crtc->hsc);
+ c.full = rfixed_const(2);
+ b.full = rfixed_div(b, c);
+ consumption_time.full = rfixed_div(pclk, b);
+ } else {
+ consumption_time.full = pclk.full;
+ }
+ a.full = rfixed_const(1);
+ wm->consumption_rate.full = rfixed_div(a, consumption_time);
+
+
+ /* Determine line time
+ * LineTime = total time for one line of displayhtotal
+ * LineTime = total number of horizontal pixels
+ * pclk = pixel clock period(ns)
+ */
+ a.full = rfixed_const(crtc->base.mode.crtc_htotal);
+ line_time.full = rfixed_mul(a, pclk);
+
+ /* Determine active time
+ * ActiveTime = time of active region of display within one line,
+ * hactive = total number of horizontal active pixels
+ * htotal = total number of horizontal pixels
+ */
+ a.full = rfixed_const(crtc->base.mode.crtc_htotal);
+ b.full = rfixed_const(crtc->base.mode.crtc_hdisplay);
+ wm->active_time.full = rfixed_mul(line_time, b);
+ wm->active_time.full = rfixed_div(wm->active_time, a);
+
+ /* Maximun bandwidth is the minimun bandwidth of all component */
+ rdev->pm.max_bandwidth = rdev->pm.core_bandwidth;
+ if (sideport) {
+ if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
+ rdev->pm.sideport_bandwidth.full)
+ rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth;
+ read_delay_latency.full = rfixed_const(370 * 800 * 1000);
+ read_delay_latency.full = rfixed_div(read_delay_latency,
+ rdev->pm.igp_sideport_mclk);
+ } else {
+ if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
+ rdev->pm.k8_bandwidth.full)
+ rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth;
+ if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full &&
+ rdev->pm.ht_bandwidth.full)
+ rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth;
+ read_delay_latency.full = rfixed_const(5000);
+ }
+
+ /* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */
+ a.full = rfixed_const(16);
+ rdev->pm.sclk.full = rfixed_mul(rdev->pm.max_bandwidth, a);
+ a.full = rfixed_const(1000);
+ rdev->pm.sclk.full = rfixed_div(a, rdev->pm.sclk);
+ /* Determine chunk time
+ * ChunkTime = the time it takes the DCP to send one chunk of data
+ * to the LB which consists of pipeline delay and inter chunk gap
+ * sclk = system clock(ns)
+ */
+ a.full = rfixed_const(256 * 13);
+ chunk_time.full = rfixed_mul(rdev->pm.sclk, a);
+ a.full = rfixed_const(10);
+ chunk_time.full = rfixed_div(chunk_time, a);
+
+ /* Determine the worst case latency
+ * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines)
+ * WorstCaseLatency = worst case time from urgent to when the MC starts
+ * to return data
+ * READ_DELAY_IDLE_MAX = constant of 1us
+ * ChunkTime = time it takes the DCP to send one chunk of data to the LB
+ * which consists of pipeline delay and inter chunk gap
+ */
+ if (rfixed_trunc(wm->num_line_pair) > 1) {
+ a.full = rfixed_const(3);
+ wm->worst_case_latency.full = rfixed_mul(a, chunk_time);
+ wm->worst_case_latency.full += read_delay_latency.full;
+ } else {
+ a.full = rfixed_const(2);
+ wm->worst_case_latency.full = rfixed_mul(a, chunk_time);
+ wm->worst_case_latency.full += read_delay_latency.full;
+ }
+
+ /* Determine the tolerable latency
+ * TolerableLatency = Any given request has only 1 line time
+ * for the data to be returned
+ * LBRequestFifoDepth = Number of chunk requests the LB can
+ * put into the request FIFO for a display
+ * LineTime = total time for one line of display
+ * ChunkTime = the time it takes the DCP to send one chunk
+ * of data to the LB which consists of
+ * pipeline delay and inter chunk gap
+ */
+ if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) {
+ tolerable_latency.full = line_time.full;
+ } else {
+ tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2);
+ tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full;
+ tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time);
+ tolerable_latency.full = line_time.full - tolerable_latency.full;
+ }
+ /* We assume worst case 32bits (4 bytes) */
+ wm->dbpp.full = rfixed_const(4 * 8);
+
+ /* Determine the maximum priority mark
+ * width = viewport width in pixels
+ */
+ a.full = rfixed_const(16);
+ wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay);
+ wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a);
+
+ /* Determine estimated width */
+ estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full;
+ estimated_width.full = rfixed_div(estimated_width, consumption_time);
+ if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) {
+ wm->priority_mark.full = rfixed_const(10);
+ } else {
+ a.full = rfixed_const(16);
+ wm->priority_mark.full = rfixed_div(estimated_width, a);
+ wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full;
+ }
+}
+
+void rs690_bandwidth_update(struct radeon_device *rdev)
+{
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+ struct rs690_watermark wm0;
+ struct rs690_watermark wm1;
+ u32 tmp;
+ fixed20_12 priority_mark02, priority_mark12, fill_rate;
+ fixed20_12 a, b;
+
+ if (rdev->mode_info.crtcs[0]->base.enabled)
+ mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+ if (rdev->mode_info.crtcs[1]->base.enabled)
+ mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+ /*
+ * Set display0/1 priority up in the memory controller for
+ * modes if the user specifies HIGH for displaypriority
+ * 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);
+ if (mode0)
+ tmp |= (1 << MC_DISP0R_INIT_LAT_SHIFT);
+ WREG32_MC(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);
+ if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
+ WREG32(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);
+
+ if (mode0 && mode1) {
+ if (rfixed_trunc(wm0.dbpp) > 64)
+ a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair);
+ else
+ a.full = wm0.num_line_pair.full;
+ if (rfixed_trunc(wm1.dbpp) > 64)
+ b.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair);
+ else
+ b.full = wm1.num_line_pair.full;
+ a.full += b.full;
+ fill_rate.full = rfixed_div(wm0.sclk, a);
+ if (wm0.consumption_rate.full > fill_rate.full) {
+ b.full = wm0.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm0.active_time);
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ a.full = a.full + b.full;
+ b.full = rfixed_const(16 * 1000);
+ priority_mark02.full = rfixed_div(a, b);
+ } else {
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark02.full = rfixed_div(a, b);
+ }
+ if (wm1.consumption_rate.full > fill_rate.full) {
+ b.full = wm1.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm1.active_time);
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ a.full = a.full + b.full;
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ } else {
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ }
+ if (wm0.priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark.full;
+ if (rfixed_trunc(priority_mark02) < 0)
+ priority_mark02.full = 0;
+ if (wm0.priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark_max.full;
+ if (wm1.priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1.priority_mark.full;
+ if (rfixed_trunc(priority_mark12) < 0)
+ 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));
+ } else if (mode0) {
+ if (rfixed_trunc(wm0.dbpp) > 64)
+ a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair);
+ else
+ a.full = wm0.num_line_pair.full;
+ fill_rate.full = rfixed_div(wm0.sclk, a);
+ if (wm0.consumption_rate.full > fill_rate.full) {
+ b.full = wm0.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm0.active_time);
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ a.full = a.full + b.full;
+ b.full = rfixed_const(16 * 1000);
+ priority_mark02.full = rfixed_div(a, b);
+ } else {
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark02.full = rfixed_div(a, b);
+ }
+ if (wm0.priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark.full;
+ if (rfixed_trunc(priority_mark02) < 0)
+ 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);
+ } else {
+ if (rfixed_trunc(wm1.dbpp) > 64)
+ a.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair);
+ else
+ a.full = wm1.num_line_pair.full;
+ fill_rate.full = rfixed_div(wm1.sclk, a);
+ if (wm1.consumption_rate.full > fill_rate.full) {
+ b.full = wm1.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm1.active_time);
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ a.full = a.full + b.full;
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ } else {
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ }
+ if (wm1.priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1.priority_mark.full;
+ if (rfixed_trunc(priority_mark12) < 0)
+ 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));
+ }
+}
/*
* Indirect registers accessor
diff --git a/drivers/gpu/drm/radeon/rs690r.h b/drivers/gpu/drm/radeon/rs690r.h
new file mode 100644
index 000000000000..c0d9faa2175b
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs690r.h
@@ -0,0 +1,99 @@
+/*
+ * 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/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index ffea37b1b3e2..551e608702e4 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -27,8 +27,9 @@
*/
#include <linux/seq_file.h>
#include "drmP.h"
-#include "radeon_reg.h"
+#include "rv515r.h"
#include "radeon.h"
+#include "radeon_share.h"
/* rv515 depends on : */
void r100_hdp_reset(struct radeon_device *rdev);
@@ -99,26 +100,26 @@ int rv515_mc_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
/* Write VRAM size in case we are limiting it */
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
- tmp = REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16);
+ WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
+ tmp = REG_SET(MC_FB_START, rdev->mc.vram_location >> 16);
WREG32(0x134, tmp);
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
- tmp = REG_SET(RV515_MC_FB_TOP, tmp >> 16);
- tmp |= REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16);
- WREG32_MC(RV515_MC_FB_LOCATION, tmp);
- WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
+ tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
+ tmp = REG_SET(MC_FB_TOP, tmp >> 16);
+ tmp |= REG_SET(MC_FB_START, rdev->mc.vram_location >> 16);
+ WREG32_MC(MC_FB_LOCATION, tmp);
+ WREG32(HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
WREG32(0x310, rdev->mc.vram_location);
if (rdev->flags & RADEON_IS_AGP) {
tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- tmp = REG_SET(RV515_MC_AGP_TOP, tmp >> 16);
- tmp |= REG_SET(RV515_MC_AGP_START, rdev->mc.gtt_location >> 16);
- WREG32_MC(RV515_MC_AGP_LOCATION, tmp);
- WREG32_MC(RV515_MC_AGP_BASE, rdev->mc.agp_base);
- WREG32_MC(RV515_MC_AGP_BASE_2, 0);
+ tmp = REG_SET(MC_AGP_TOP, tmp >> 16);
+ tmp |= REG_SET(MC_AGP_START, rdev->mc.gtt_location >> 16);
+ WREG32_MC(MC_AGP_LOCATION, tmp);
+ WREG32_MC(MC_AGP_BASE, rdev->mc.agp_base);
+ WREG32_MC(MC_AGP_BASE_2, 0);
} else {
- WREG32_MC(RV515_MC_AGP_LOCATION, 0x0FFFFFFF);
- WREG32_MC(RV515_MC_AGP_BASE, 0);
- WREG32_MC(RV515_MC_AGP_BASE_2, 0);
+ WREG32_MC(MC_AGP_LOCATION, 0x0FFFFFFF);
+ WREG32_MC(MC_AGP_BASE, 0);
+ WREG32_MC(MC_AGP_BASE_2, 0);
}
return 0;
}
@@ -136,95 +137,67 @@ void rv515_mc_fini(struct radeon_device *rdev)
*/
void rv515_ring_start(struct radeon_device *rdev)
{
- unsigned gb_tile_config;
int r;
- /* Sub pixel 1/12 so we can have 4K rendering according to doc */
- gb_tile_config = R300_ENABLE_TILING | R300_TILE_SIZE_16;
- switch (rdev->num_gb_pipes) {
- case 2:
- gb_tile_config |= R300_PIPE_COUNT_R300;
- break;
- case 3:
- gb_tile_config |= R300_PIPE_COUNT_R420_3P;
- break;
- case 4:
- gb_tile_config |= R300_PIPE_COUNT_R420;
- break;
- case 1:
- default:
- gb_tile_config |= R300_PIPE_COUNT_RV350;
- break;
- }
-
r = radeon_ring_lock(rdev, 64);
if (r) {
return;
}
- radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0));
- radeon_ring_write(rdev,
- RADEON_ISYNC_ANY2D_IDLE3D |
- RADEON_ISYNC_ANY3D_IDLE2D |
- RADEON_ISYNC_WAIT_IDLEGUI |
- RADEON_ISYNC_CPSCRATCH_IDLEGUI);
- radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0));
- radeon_ring_write(rdev, gb_tile_config);
- radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, PACKET0(ISYNC_CNTL, 0));
radeon_ring_write(rdev,
- RADEON_WAIT_2D_IDLECLEAN |
- RADEON_WAIT_3D_IDLECLEAN);
+ ISYNC_ANY2D_IDLE3D |
+ ISYNC_ANY3D_IDLE2D |
+ ISYNC_WAIT_IDLEGUI |
+ ISYNC_CPSCRATCH_IDLEGUI);
+ radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN);
radeon_ring_write(rdev, PACKET0(0x170C, 0));
radeon_ring_write(rdev, 1 << 31);
- radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0));
+ radeon_ring_write(rdev, PACKET0(GB_SELECT, 0));
radeon_ring_write(rdev, 0);
- radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0));
+ radeon_ring_write(rdev, PACKET0(GB_ENABLE, 0));
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, PACKET0(0x42C8, 0));
radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1);
- radeon_ring_write(rdev, PACKET0(R500_VAP_INDEX_OFFSET, 0));
+ radeon_ring_write(rdev, PACKET0(VAP_INDEX_OFFSET, 0));
radeon_ring_write(rdev, 0);
- radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
- radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
- radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
- radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
- radeon_ring_write(rdev,
- RADEON_WAIT_2D_IDLECLEAN |
- RADEON_WAIT_3D_IDLECLEAN);
- radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0));
+ radeon_ring_write(rdev, PACKET0(RB3D_DSTCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, RB3D_DC_FLUSH | RB3D_DC_FREE);
+ radeon_ring_write(rdev, PACKET0(ZB_ZCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, ZC_FLUSH | ZC_FREE);
+ radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0));
+ radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN);
+ radeon_ring_write(rdev, PACKET0(GB_AA_CONFIG, 0));
radeon_ring_write(rdev, 0);
- radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
- radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
- radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
- radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0));
- radeon_ring_write(rdev,
- ((6 << R300_MS_X0_SHIFT) |
- (6 << R300_MS_Y0_SHIFT) |
- (6 << R300_MS_X1_SHIFT) |
- (6 << R300_MS_Y1_SHIFT) |
- (6 << R300_MS_X2_SHIFT) |
- (6 << R300_MS_Y2_SHIFT) |
- (6 << R300_MSBD0_Y_SHIFT) |
- (6 << R300_MSBD0_X_SHIFT)));
- radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0));
+ radeon_ring_write(rdev, PACKET0(RB3D_DSTCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, RB3D_DC_FLUSH | RB3D_DC_FREE);
+ radeon_ring_write(rdev, PACKET0(ZB_ZCACHE_CTLSTAT, 0));
+ radeon_ring_write(rdev, ZC_FLUSH | ZC_FREE);
+ radeon_ring_write(rdev, PACKET0(GB_MSPOS0, 0));
radeon_ring_write(rdev,
- ((6 << R300_MS_X3_SHIFT) |
- (6 << R300_MS_Y3_SHIFT) |
- (6 << R300_MS_X4_SHIFT) |
- (6 << R300_MS_Y4_SHIFT) |
- (6 << R300_MS_X5_SHIFT) |
- (6 << R300_MS_Y5_SHIFT) |
- (6 << R300_MSBD1_SHIFT)));
- radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0));
- radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL);
- radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0));
+ ((6 << MS_X0_SHIFT) |
+ (6 << MS_Y0_SHIFT) |
+ (6 << MS_X1_SHIFT) |
+ (6 << MS_Y1_SHIFT) |
+ (6 << MS_X2_SHIFT) |
+ (6 << MS_Y2_SHIFT) |
+ (6 << MSBD0_Y_SHIFT) |
+ (6 << MSBD0_X_SHIFT)));
+ radeon_ring_write(rdev, PACKET0(GB_MSPOS1, 0));
radeon_ring_write(rdev,
- R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE);
- radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0));
- radeon_ring_write(rdev,
- R300_GEOMETRY_ROUND_NEAREST |
- R300_COLOR_ROUND_NEAREST);
+ ((6 << MS_X3_SHIFT) |
+ (6 << MS_Y3_SHIFT) |
+ (6 << MS_X4_SHIFT) |
+ (6 << MS_Y4_SHIFT) |
+ (6 << MS_X5_SHIFT) |
+ (6 << MS_Y5_SHIFT) |
+ (6 << MSBD1_SHIFT)));
+ radeon_ring_write(rdev, PACKET0(GA_ENHANCE, 0));
+ radeon_ring_write(rdev, GA_DEADLOCK_CNTL | GA_FASTSYNC_CNTL);
+ radeon_ring_write(rdev, PACKET0(GA_POLY_MODE, 0));
+ radeon_ring_write(rdev, FRONT_PTYPE_TRIANGE | BACK_PTYPE_TRIANGE);
+ radeon_ring_write(rdev, PACKET0(GA_ROUND_MODE, 0));
+ radeon_ring_write(rdev, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST);
radeon_ring_write(rdev, PACKET0(0x20C8, 0));
radeon_ring_write(rdev, 0);
radeon_ring_unlock_commit(rdev);
@@ -242,8 +215,8 @@ int rv515_mc_wait_for_idle(struct radeon_device *rdev)
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
- tmp = RREG32_MC(RV515_MC_STATUS);
- if (tmp & RV515_MC_STATUS_IDLE) {
+ tmp = RREG32_MC(MC_STATUS);
+ if (tmp & MC_STATUS_IDLE) {
return 0;
}
DRM_UDELAY(1);
@@ -291,33 +264,33 @@ int rv515_ga_reset(struct radeon_device *rdev)
reinit_cp = rdev->cp.ready;
rdev->cp.ready = false;
for (i = 0; i < rdev->usec_timeout; i++) {
- WREG32(RADEON_CP_CSQ_MODE, 0);
- WREG32(RADEON_CP_CSQ_CNTL, 0);
- WREG32(RADEON_RBBM_SOFT_RESET, 0x32005);
- (void)RREG32(RADEON_RBBM_SOFT_RESET);
+ WREG32(CP_CSQ_MODE, 0);
+ WREG32(CP_CSQ_CNTL, 0);
+ WREG32(RBBM_SOFT_RESET, 0x32005);
+ (void)RREG32(RBBM_SOFT_RESET);
udelay(200);
- WREG32(RADEON_RBBM_SOFT_RESET, 0);
+ WREG32(RBBM_SOFT_RESET, 0);
/* Wait to prevent race in RBBM_STATUS */
mdelay(1);
- tmp = RREG32(RADEON_RBBM_STATUS);
+ tmp = RREG32(RBBM_STATUS);
if (tmp & ((1 << 20) | (1 << 26))) {
DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp);
/* GA still busy soft reset it */
WREG32(0x429C, 0x200);
- WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
+ WREG32(VAP_PVS_STATE_FLUSH_REG, 0);
WREG32(0x43E0, 0);
WREG32(0x43E4, 0);
WREG32(0x24AC, 0);
}
/* Wait to prevent race in RBBM_STATUS */
mdelay(1);
- tmp = RREG32(RADEON_RBBM_STATUS);
+ tmp = RREG32(RBBM_STATUS);
if (!(tmp & ((1 << 20) | (1 << 26)))) {
break;
}
}
for (i = 0; i < rdev->usec_timeout; i++) {
- tmp = RREG32(RADEON_RBBM_STATUS);
+ tmp = RREG32(RBBM_STATUS);
if (!(tmp & ((1 << 20) | (1 << 26)))) {
DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
tmp);
@@ -331,7 +304,7 @@ int rv515_ga_reset(struct radeon_device *rdev)
}
DRM_UDELAY(1);
}
- tmp = RREG32(RADEON_RBBM_STATUS);
+ tmp = RREG32(RBBM_STATUS);
DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
return -1;
}
@@ -341,7 +314,7 @@ int rv515_gpu_reset(struct radeon_device *rdev)
uint32_t status;
/* reset order likely matter */
- status = RREG32(RADEON_RBBM_STATUS);
+ status = RREG32(RBBM_STATUS);
/* reset HDP */
r100_hdp_reset(rdev);
/* reset rb2d */
@@ -353,12 +326,12 @@ int rv515_gpu_reset(struct radeon_device *rdev)
rv515_ga_reset(rdev);
}
/* reset CP */
- status = RREG32(RADEON_RBBM_STATUS);
+ status = RREG32(RBBM_STATUS);
if (status & (1 << 16)) {
r100_cp_reset(rdev);
}
/* Check if GPU is idle */
- status = RREG32(RADEON_RBBM_STATUS);
+ status = RREG32(RBBM_STATUS);
if (status & (1 << 31)) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
return -1;
@@ -377,8 +350,7 @@ static void rv515_vram_get_type(struct radeon_device *rdev)
rdev->mc.vram_width = 128;
rdev->mc.vram_is_ddr = true;
- tmp = RREG32_MC(RV515_MC_CNTL);
- tmp &= RV515_MEM_NUM_CHANNELS_MASK;
+ tmp = RREG32_MC(RV515_MC_CNTL) & MEM_NUM_CHANNELS_MASK;
switch (tmp) {
case 0:
rdev->mc.vram_width = 64;
@@ -394,11 +366,16 @@ static void rv515_vram_get_type(struct radeon_device *rdev)
void rv515_vram_info(struct radeon_device *rdev)
{
+ fixed20_12 a;
+
rv515_vram_get_type(rdev);
- rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ /* FIXME: we should enforce default clock in case GPU is not in
+ * default setup
+ */
+ a.full = rfixed_const(100);
+ rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
+ rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
}
@@ -409,35 +386,35 @@ uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg)
{
uint32_t r;
- WREG32(R520_MC_IND_INDEX, 0x7f0000 | (reg & 0xffff));
- r = RREG32(R520_MC_IND_DATA);
- WREG32(R520_MC_IND_INDEX, 0);
+ WREG32(MC_IND_INDEX, 0x7f0000 | (reg & 0xffff));
+ r = RREG32(MC_IND_DATA);
+ WREG32(MC_IND_INDEX, 0);
return r;
}
void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
- WREG32(R520_MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff));
- WREG32(R520_MC_IND_DATA, (v));
- WREG32(R520_MC_IND_INDEX, 0);
+ WREG32(MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff));
+ WREG32(MC_IND_DATA, (v));
+ WREG32(MC_IND_INDEX, 0);
}
uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg)
{
uint32_t r;
- WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff));
- (void)RREG32(RADEON_PCIE_INDEX);
- r = RREG32(RADEON_PCIE_DATA);
+ WREG32(PCIE_INDEX, ((reg) & 0x7ff));
+ (void)RREG32(PCIE_INDEX);
+ r = RREG32(PCIE_DATA);
return r;
}
void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
- WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff));
- (void)RREG32(RADEON_PCIE_INDEX);
- WREG32(RADEON_PCIE_DATA, (v));
- (void)RREG32(RADEON_PCIE_DATA);
+ WREG32(PCIE_INDEX, ((reg) & 0x7ff));
+ (void)RREG32(PCIE_INDEX);
+ WREG32(PCIE_DATA, (v));
+ (void)RREG32(PCIE_DATA);
}
@@ -452,13 +429,13 @@ static int rv515_debugfs_pipes_info(struct seq_file *m, void *data)
struct radeon_device *rdev = dev->dev_private;
uint32_t tmp;
- tmp = RREG32(R400_GB_PIPE_SELECT);
+ tmp = RREG32(GB_PIPE_SELECT);
seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp);
- tmp = RREG32(R500_SU_REG_DEST);
+ tmp = RREG32(SU_REG_DEST);
seq_printf(m, "SU_REG_DEST 0x%08x\n", tmp);
- tmp = RREG32(R300_GB_TILE_CONFIG);
+ tmp = RREG32(GB_TILE_CONFIG);
seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp);
- tmp = RREG32(R300_DST_PIPE_CONFIG);
+ tmp = RREG32(DST_PIPE_CONFIG);
seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp);
return 0;
}
@@ -509,9 +486,9 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
/*
* Asic initialization
*/
-static const unsigned r500_reg_safe_bm[159] = {
+static const unsigned r500_reg_safe_bm[219] = {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
@@ -549,14 +526,575 @@ static const unsigned r500_reg_safe_bm[159] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x0003FC01, 0x3FFFFCF8, 0xFE800B19,
+ 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
};
-
-
int rv515_init(struct radeon_device *rdev)
{
rdev->config.r300.reg_safe_bm = r500_reg_safe_bm;
rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm);
return 0;
}
+
+void atom_rv515_force_tv_scaler(struct radeon_device *rdev)
+{
+
+ WREG32(0x659C, 0x0);
+ WREG32(0x6594, 0x705);
+ WREG32(0x65A4, 0x10001);
+ WREG32(0x65D8, 0x0);
+ WREG32(0x65B0, 0x0);
+ WREG32(0x65C0, 0x0);
+ WREG32(0x65D4, 0x0);
+ WREG32(0x6578, 0x0);
+ WREG32(0x657C, 0x841880A8);
+ WREG32(0x6578, 0x1);
+ WREG32(0x657C, 0x84208680);
+ WREG32(0x6578, 0x2);
+ WREG32(0x657C, 0xBFF880B0);
+ WREG32(0x6578, 0x100);
+ WREG32(0x657C, 0x83D88088);
+ WREG32(0x6578, 0x101);
+ WREG32(0x657C, 0x84608680);
+ WREG32(0x6578, 0x102);
+ WREG32(0x657C, 0xBFF080D0);
+ WREG32(0x6578, 0x200);
+ WREG32(0x657C, 0x83988068);
+ WREG32(0x6578, 0x201);
+ WREG32(0x657C, 0x84A08680);
+ WREG32(0x6578, 0x202);
+ WREG32(0x657C, 0xBFF080F8);
+ WREG32(0x6578, 0x300);
+ WREG32(0x657C, 0x83588058);
+ WREG32(0x6578, 0x301);
+ WREG32(0x657C, 0x84E08660);
+ WREG32(0x6578, 0x302);
+ WREG32(0x657C, 0xBFF88120);
+ WREG32(0x6578, 0x400);
+ WREG32(0x657C, 0x83188040);
+ WREG32(0x6578, 0x401);
+ WREG32(0x657C, 0x85008660);
+ WREG32(0x6578, 0x402);
+ WREG32(0x657C, 0xBFF88150);
+ WREG32(0x6578, 0x500);
+ WREG32(0x657C, 0x82D88030);
+ WREG32(0x6578, 0x501);
+ WREG32(0x657C, 0x85408640);
+ WREG32(0x6578, 0x502);
+ WREG32(0x657C, 0xBFF88180);
+ WREG32(0x6578, 0x600);
+ WREG32(0x657C, 0x82A08018);
+ WREG32(0x6578, 0x601);
+ WREG32(0x657C, 0x85808620);
+ WREG32(0x6578, 0x602);
+ WREG32(0x657C, 0xBFF081B8);
+ WREG32(0x6578, 0x700);
+ WREG32(0x657C, 0x82608010);
+ WREG32(0x6578, 0x701);
+ WREG32(0x657C, 0x85A08600);
+ WREG32(0x6578, 0x702);
+ WREG32(0x657C, 0x800081F0);
+ WREG32(0x6578, 0x800);
+ WREG32(0x657C, 0x8228BFF8);
+ WREG32(0x6578, 0x801);
+ WREG32(0x657C, 0x85E085E0);
+ WREG32(0x6578, 0x802);
+ WREG32(0x657C, 0xBFF88228);
+ WREG32(0x6578, 0x10000);
+ WREG32(0x657C, 0x82A8BF00);
+ WREG32(0x6578, 0x10001);
+ WREG32(0x657C, 0x82A08CC0);
+ WREG32(0x6578, 0x10002);
+ WREG32(0x657C, 0x8008BEF8);
+ WREG32(0x6578, 0x10100);
+ WREG32(0x657C, 0x81F0BF28);
+ WREG32(0x6578, 0x10101);
+ WREG32(0x657C, 0x83608CA0);
+ WREG32(0x6578, 0x10102);
+ WREG32(0x657C, 0x8018BED0);
+ WREG32(0x6578, 0x10200);
+ WREG32(0x657C, 0x8148BF38);
+ WREG32(0x6578, 0x10201);
+ WREG32(0x657C, 0x84408C80);
+ WREG32(0x6578, 0x10202);
+ WREG32(0x657C, 0x8008BEB8);
+ WREG32(0x6578, 0x10300);
+ WREG32(0x657C, 0x80B0BF78);
+ WREG32(0x6578, 0x10301);
+ WREG32(0x657C, 0x85008C20);
+ WREG32(0x6578, 0x10302);
+ WREG32(0x657C, 0x8020BEA0);
+ WREG32(0x6578, 0x10400);
+ WREG32(0x657C, 0x8028BF90);
+ WREG32(0x6578, 0x10401);
+ WREG32(0x657C, 0x85E08BC0);
+ WREG32(0x6578, 0x10402);
+ WREG32(0x657C, 0x8018BE90);
+ WREG32(0x6578, 0x10500);
+ WREG32(0x657C, 0xBFB8BFB0);
+ WREG32(0x6578, 0x10501);
+ WREG32(0x657C, 0x86C08B40);
+ WREG32(0x6578, 0x10502);
+ WREG32(0x657C, 0x8010BE90);
+ WREG32(0x6578, 0x10600);
+ WREG32(0x657C, 0xBF58BFC8);
+ WREG32(0x6578, 0x10601);
+ WREG32(0x657C, 0x87A08AA0);
+ WREG32(0x6578, 0x10602);
+ WREG32(0x657C, 0x8010BE98);
+ WREG32(0x6578, 0x10700);
+ WREG32(0x657C, 0xBF10BFF0);
+ WREG32(0x6578, 0x10701);
+ WREG32(0x657C, 0x886089E0);
+ WREG32(0x6578, 0x10702);
+ WREG32(0x657C, 0x8018BEB0);
+ WREG32(0x6578, 0x10800);
+ WREG32(0x657C, 0xBED8BFE8);
+ WREG32(0x6578, 0x10801);
+ WREG32(0x657C, 0x89408940);
+ WREG32(0x6578, 0x10802);
+ WREG32(0x657C, 0xBFE8BED8);
+ WREG32(0x6578, 0x20000);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20001);
+ WREG32(0x657C, 0x90008000);
+ WREG32(0x6578, 0x20002);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20003);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20100);
+ WREG32(0x657C, 0x80108000);
+ WREG32(0x6578, 0x20101);
+ WREG32(0x657C, 0x8FE0BF70);
+ WREG32(0x6578, 0x20102);
+ WREG32(0x657C, 0xBFE880C0);
+ WREG32(0x6578, 0x20103);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20200);
+ WREG32(0x657C, 0x8018BFF8);
+ WREG32(0x6578, 0x20201);
+ WREG32(0x657C, 0x8F80BF08);
+ WREG32(0x6578, 0x20202);
+ WREG32(0x657C, 0xBFD081A0);
+ WREG32(0x6578, 0x20203);
+ WREG32(0x657C, 0xBFF88000);
+ WREG32(0x6578, 0x20300);
+ WREG32(0x657C, 0x80188000);
+ WREG32(0x6578, 0x20301);
+ WREG32(0x657C, 0x8EE0BEC0);
+ WREG32(0x6578, 0x20302);
+ WREG32(0x657C, 0xBFB082A0);
+ WREG32(0x6578, 0x20303);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20400);
+ WREG32(0x657C, 0x80188000);
+ WREG32(0x6578, 0x20401);
+ WREG32(0x657C, 0x8E00BEA0);
+ WREG32(0x6578, 0x20402);
+ WREG32(0x657C, 0xBF8883C0);
+ WREG32(0x6578, 0x20403);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x20500);
+ WREG32(0x657C, 0x80188000);
+ WREG32(0x6578, 0x20501);
+ WREG32(0x657C, 0x8D00BE90);
+ WREG32(0x6578, 0x20502);
+ WREG32(0x657C, 0xBF588500);
+ WREG32(0x6578, 0x20503);
+ WREG32(0x657C, 0x80008008);
+ WREG32(0x6578, 0x20600);
+ WREG32(0x657C, 0x80188000);
+ WREG32(0x6578, 0x20601);
+ WREG32(0x657C, 0x8BC0BE98);
+ WREG32(0x6578, 0x20602);
+ WREG32(0x657C, 0xBF308660);
+ WREG32(0x6578, 0x20603);
+ WREG32(0x657C, 0x80008008);
+ WREG32(0x6578, 0x20700);
+ WREG32(0x657C, 0x80108000);
+ WREG32(0x6578, 0x20701);
+ WREG32(0x657C, 0x8A80BEB0);
+ WREG32(0x6578, 0x20702);
+ WREG32(0x657C, 0xBF0087C0);
+ WREG32(0x6578, 0x20703);
+ WREG32(0x657C, 0x80008008);
+ WREG32(0x6578, 0x20800);
+ WREG32(0x657C, 0x80108000);
+ WREG32(0x6578, 0x20801);
+ WREG32(0x657C, 0x8920BED0);
+ WREG32(0x6578, 0x20802);
+ WREG32(0x657C, 0xBED08920);
+ WREG32(0x6578, 0x20803);
+ WREG32(0x657C, 0x80008010);
+ WREG32(0x6578, 0x30000);
+ WREG32(0x657C, 0x90008000);
+ WREG32(0x6578, 0x30001);
+ WREG32(0x657C, 0x80008000);
+ WREG32(0x6578, 0x30100);
+ WREG32(0x657C, 0x8FE0BF90);
+ WREG32(0x6578, 0x30101);
+ WREG32(0x657C, 0xBFF880A0);
+ WREG32(0x6578, 0x30200);
+ WREG32(0x657C, 0x8F60BF40);
+ WREG32(0x6578, 0x30201);
+ WREG32(0x657C, 0xBFE88180);
+ WREG32(0x6578, 0x30300);
+ WREG32(0x657C, 0x8EC0BF00);
+ WREG32(0x6578, 0x30301);
+ WREG32(0x657C, 0xBFC88280);
+ WREG32(0x6578, 0x30400);
+ WREG32(0x657C, 0x8DE0BEE0);
+ WREG32(0x6578, 0x30401);
+ WREG32(0x657C, 0xBFA083A0);
+ WREG32(0x6578, 0x30500);
+ WREG32(0x657C, 0x8CE0BED0);
+ WREG32(0x6578, 0x30501);
+ WREG32(0x657C, 0xBF7884E0);
+ WREG32(0x6578, 0x30600);
+ WREG32(0x657C, 0x8BA0BED8);
+ WREG32(0x6578, 0x30601);
+ WREG32(0x657C, 0xBF508640);
+ WREG32(0x6578, 0x30700);
+ WREG32(0x657C, 0x8A60BEE8);
+ WREG32(0x6578, 0x30701);
+ WREG32(0x657C, 0xBF2087A0);
+ WREG32(0x6578, 0x30800);
+ WREG32(0x657C, 0x8900BF00);
+ WREG32(0x6578, 0x30801);
+ WREG32(0x657C, 0xBF008900);
+}
+
+struct rv515_watermark {
+ u32 lb_request_fifo_depth;
+ fixed20_12 num_line_pair;
+ fixed20_12 estimated_width;
+ fixed20_12 worst_case_latency;
+ fixed20_12 consumption_rate;
+ fixed20_12 active_time;
+ fixed20_12 dbpp;
+ fixed20_12 priority_mark_max;
+ fixed20_12 priority_mark;
+ fixed20_12 sclk;
+};
+
+void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
+ struct radeon_crtc *crtc,
+ struct rv515_watermark *wm)
+{
+ struct drm_display_mode *mode = &crtc->base.mode;
+ fixed20_12 a, b, c;
+ fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
+ fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+
+ if (!crtc->base.enabled) {
+ /* FIXME: wouldn't it better to set priority mark to maximum */
+ wm->lb_request_fifo_depth = 4;
+ return;
+ }
+
+ if (crtc->vsc.full > rfixed_const(2))
+ wm->num_line_pair.full = rfixed_const(2);
+ else
+ wm->num_line_pair.full = rfixed_const(1);
+
+ b.full = rfixed_const(mode->crtc_hdisplay);
+ c.full = rfixed_const(256);
+ a.full = rfixed_mul(wm->num_line_pair, b);
+ request_fifo_depth.full = rfixed_div(a, c);
+ if (a.full < rfixed_const(4)) {
+ wm->lb_request_fifo_depth = 4;
+ } else {
+ wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth);
+ }
+
+ /* Determine consumption rate
+ * pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000)
+ * vtaps = number of vertical taps,
+ * vsc = vertical scaling ratio, defined as source/destination
+ * hsc = horizontal scaling ration, defined as source/destination
+ */
+ a.full = rfixed_const(mode->clock);
+ b.full = rfixed_const(1000);
+ a.full = rfixed_div(a, b);
+ pclk.full = rfixed_div(b, a);
+ if (crtc->rmx_type != RMX_OFF) {
+ b.full = rfixed_const(2);
+ if (crtc->vsc.full > b.full)
+ b.full = crtc->vsc.full;
+ b.full = rfixed_mul(b, crtc->hsc);
+ c.full = rfixed_const(2);
+ b.full = rfixed_div(b, c);
+ consumption_time.full = rfixed_div(pclk, b);
+ } else {
+ consumption_time.full = pclk.full;
+ }
+ a.full = rfixed_const(1);
+ wm->consumption_rate.full = rfixed_div(a, consumption_time);
+
+
+ /* Determine line time
+ * LineTime = total time for one line of displayhtotal
+ * LineTime = total number of horizontal pixels
+ * pclk = pixel clock period(ns)
+ */
+ a.full = rfixed_const(crtc->base.mode.crtc_htotal);
+ line_time.full = rfixed_mul(a, pclk);
+
+ /* Determine active time
+ * ActiveTime = time of active region of display within one line,
+ * hactive = total number of horizontal active pixels
+ * htotal = total number of horizontal pixels
+ */
+ a.full = rfixed_const(crtc->base.mode.crtc_htotal);
+ b.full = rfixed_const(crtc->base.mode.crtc_hdisplay);
+ wm->active_time.full = rfixed_mul(line_time, b);
+ wm->active_time.full = rfixed_div(wm->active_time, a);
+
+ /* Determine chunk time
+ * ChunkTime = the time it takes the DCP to send one chunk of data
+ * to the LB which consists of pipeline delay and inter chunk gap
+ * sclk = system clock(Mhz)
+ */
+ a.full = rfixed_const(600 * 1000);
+ chunk_time.full = rfixed_div(a, rdev->pm.sclk);
+ read_delay_latency.full = rfixed_const(1000);
+
+ /* Determine the worst case latency
+ * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines)
+ * WorstCaseLatency = worst case time from urgent to when the MC starts
+ * to return data
+ * READ_DELAY_IDLE_MAX = constant of 1us
+ * ChunkTime = time it takes the DCP to send one chunk of data to the LB
+ * which consists of pipeline delay and inter chunk gap
+ */
+ if (rfixed_trunc(wm->num_line_pair) > 1) {
+ a.full = rfixed_const(3);
+ wm->worst_case_latency.full = rfixed_mul(a, chunk_time);
+ wm->worst_case_latency.full += read_delay_latency.full;
+ } else {
+ wm->worst_case_latency.full = chunk_time.full + read_delay_latency.full;
+ }
+
+ /* Determine the tolerable latency
+ * TolerableLatency = Any given request has only 1 line time
+ * for the data to be returned
+ * LBRequestFifoDepth = Number of chunk requests the LB can
+ * put into the request FIFO for a display
+ * LineTime = total time for one line of display
+ * ChunkTime = the time it takes the DCP to send one chunk
+ * of data to the LB which consists of
+ * pipeline delay and inter chunk gap
+ */
+ if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) {
+ tolerable_latency.full = line_time.full;
+ } else {
+ tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2);
+ tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full;
+ tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time);
+ tolerable_latency.full = line_time.full - tolerable_latency.full;
+ }
+ /* We assume worst case 32bits (4 bytes) */
+ wm->dbpp.full = rfixed_const(2 * 16);
+
+ /* Determine the maximum priority mark
+ * width = viewport width in pixels
+ */
+ a.full = rfixed_const(16);
+ wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay);
+ wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a);
+
+ /* Determine estimated width */
+ estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full;
+ estimated_width.full = rfixed_div(estimated_width, consumption_time);
+ if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) {
+ wm->priority_mark.full = rfixed_const(10);
+ } else {
+ a.full = rfixed_const(16);
+ wm->priority_mark.full = rfixed_div(estimated_width, a);
+ wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full;
+ }
+}
+
+void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
+{
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+ struct rv515_watermark wm0;
+ struct rv515_watermark wm1;
+ u32 tmp;
+ fixed20_12 priority_mark02, priority_mark12, fill_rate;
+ fixed20_12 a, b;
+
+ if (rdev->mode_info.crtcs[0]->base.enabled)
+ mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+ if (rdev->mode_info.crtcs[1]->base.enabled)
+ mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+ rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
+
+ tmp = wm0.lb_request_fifo_depth;
+ tmp |= wm1.lb_request_fifo_depth << 16;
+ WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+
+ if (mode0 && mode1) {
+ if (rfixed_trunc(wm0.dbpp) > 64)
+ a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair);
+ else
+ a.full = wm0.num_line_pair.full;
+ if (rfixed_trunc(wm1.dbpp) > 64)
+ b.full = rfixed_div(wm1.dbpp, wm1.num_line_pair);
+ else
+ b.full = wm1.num_line_pair.full;
+ a.full += b.full;
+ fill_rate.full = rfixed_div(wm0.sclk, a);
+ if (wm0.consumption_rate.full > fill_rate.full) {
+ b.full = wm0.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm0.active_time);
+ a.full = rfixed_const(16);
+ b.full = rfixed_div(b, a);
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ priority_mark02.full = a.full + b.full;
+ } else {
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark02.full = rfixed_div(a, b);
+ }
+ if (wm1.consumption_rate.full > fill_rate.full) {
+ b.full = wm1.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm1.active_time);
+ a.full = rfixed_const(16);
+ b.full = rfixed_div(b, a);
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ priority_mark12.full = a.full + b.full;
+ } else {
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ }
+ if (wm0.priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark.full;
+ if (rfixed_trunc(priority_mark02) < 0)
+ priority_mark02.full = 0;
+ if (wm0.priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark_max.full;
+ if (wm1.priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1.priority_mark.full;
+ if (rfixed_trunc(priority_mark12) < 0)
+ 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));
+ } else if (mode0) {
+ if (rfixed_trunc(wm0.dbpp) > 64)
+ a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair);
+ else
+ a.full = wm0.num_line_pair.full;
+ fill_rate.full = rfixed_div(wm0.sclk, a);
+ if (wm0.consumption_rate.full > fill_rate.full) {
+ b.full = wm0.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm0.active_time);
+ a.full = rfixed_const(16);
+ b.full = rfixed_div(b, a);
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ priority_mark02.full = a.full + b.full;
+ } else {
+ a.full = rfixed_mul(wm0.worst_case_latency,
+ wm0.consumption_rate);
+ b.full = rfixed_const(16);
+ priority_mark02.full = rfixed_div(a, b);
+ }
+ if (wm0.priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0.priority_mark.full;
+ if (rfixed_trunc(priority_mark02) < 0)
+ 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);
+ } else {
+ if (rfixed_trunc(wm1.dbpp) > 64)
+ a.full = rfixed_div(wm1.dbpp, wm1.num_line_pair);
+ else
+ a.full = wm1.num_line_pair.full;
+ fill_rate.full = rfixed_div(wm1.sclk, a);
+ if (wm1.consumption_rate.full > fill_rate.full) {
+ b.full = wm1.consumption_rate.full - fill_rate.full;
+ b.full = rfixed_mul(b, wm1.active_time);
+ a.full = rfixed_const(16);
+ b.full = rfixed_div(b, a);
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ priority_mark12.full = a.full + b.full;
+ } else {
+ a.full = rfixed_mul(wm1.worst_case_latency,
+ wm1.consumption_rate);
+ b.full = rfixed_const(16 * 1000);
+ priority_mark12.full = rfixed_div(a, b);
+ }
+ if (wm1.priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1.priority_mark.full;
+ if (rfixed_trunc(priority_mark12) < 0)
+ 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));
+ }
+}
+
+void rv515_bandwidth_update(struct radeon_device *rdev)
+{
+ uint32_t tmp;
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+
+ if (rdev->mode_info.crtcs[0]->base.enabled)
+ mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+ if (rdev->mode_info.crtcs[1]->base.enabled)
+ mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+ /*
+ * Set display0/1 priority up in the memory controller for
+ * modes if the user specifies HIGH for displaypriority
+ * option.
+ */
+ if (rdev->disp_priority == 2) {
+ tmp = RREG32_MC(MC_MISC_LAT_TIMER);
+ tmp &= ~MC_DISP1R_INIT_LAT_MASK;
+ tmp &= ~MC_DISP0R_INIT_LAT_MASK;
+ if (mode1)
+ tmp |= (1 << MC_DISP1R_INIT_LAT_SHIFT);
+ if (mode0)
+ tmp |= (1 << MC_DISP0R_INIT_LAT_SHIFT);
+ WREG32_MC(MC_MISC_LAT_TIMER, tmp);
+ }
+ rv515_bandwidth_avivo_update(rdev);
+}
diff --git a/drivers/gpu/drm/radeon/rv515r.h b/drivers/gpu/drm/radeon/rv515r.h
new file mode 100644
index 000000000000..f3cf84039906
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv515r.h
@@ -0,0 +1,170 @@
+/*
+ * 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 RV515R_H
+#define RV515R_H
+
+/* RV515 registers */
+#define PCIE_INDEX 0x0030
+#define PCIE_DATA 0x0034
+#define MC_IND_INDEX 0x0070
+#define MC_IND_WR_EN (1 << 24)
+#define MC_IND_DATA 0x0074
+#define RBBM_SOFT_RESET 0x00F0
+#define CONFIG_MEMSIZE 0x00F8
+#define HDP_FB_LOCATION 0x0134
+#define CP_CSQ_CNTL 0x0740
+#define CP_CSQ_MODE 0x0744
+#define CP_CSQ_ADDR 0x07F0
+#define CP_CSQ_DATA 0x07F4
+#define CP_CSQ_STAT 0x07F8
+#define CP_CSQ2_STAT 0x07FC
+#define RBBM_STATUS 0x0E40
+#define DST_PIPE_CONFIG 0x170C
+#define WAIT_UNTIL 0x1720
+#define WAIT_2D_IDLE (1 << 14)
+#define WAIT_3D_IDLE (1 << 15)
+#define WAIT_2D_IDLECLEAN (1 << 16)
+#define WAIT_3D_IDLECLEAN (1 << 17)
+#define ISYNC_CNTL 0x1724
+#define ISYNC_ANY2D_IDLE3D (1 << 0)
+#define ISYNC_ANY3D_IDLE2D (1 << 1)
+#define ISYNC_TRIG2D_IDLE3D (1 << 2)
+#define ISYNC_TRIG3D_IDLE2D (1 << 3)
+#define ISYNC_WAIT_IDLEGUI (1 << 4)
+#define ISYNC_CPSCRATCH_IDLEGUI (1 << 5)
+#define VAP_INDEX_OFFSET 0x208C
+#define VAP_PVS_STATE_FLUSH_REG 0x2284
+#define GB_ENABLE 0x4008
+#define GB_MSPOS0 0x4010
+#define MS_X0_SHIFT 0
+#define MS_Y0_SHIFT 4
+#define MS_X1_SHIFT 8
+#define MS_Y1_SHIFT 12
+#define MS_X2_SHIFT 16
+#define MS_Y2_SHIFT 20
+#define MSBD0_Y_SHIFT 24
+#define MSBD0_X_SHIFT 28
+#define GB_MSPOS1 0x4014
+#define MS_X3_SHIFT 0
+#define MS_Y3_SHIFT 4
+#define MS_X4_SHIFT 8
+#define MS_Y4_SHIFT 12
+#define MS_X5_SHIFT 16
+#define MS_Y5_SHIFT 20
+#define MSBD1_SHIFT 24
+#define GB_TILE_CONFIG 0x4018
+#define ENABLE_TILING (1 << 0)
+#define PIPE_COUNT_MASK 0x0000000E
+#define PIPE_COUNT_SHIFT 1
+#define TILE_SIZE_8 (0 << 4)
+#define TILE_SIZE_16 (1 << 4)
+#define TILE_SIZE_32 (2 << 4)
+#define SUBPIXEL_1_12 (0 << 16)
+#define SUBPIXEL_1_16 (1 << 16)
+#define GB_SELECT 0x401C
+#define GB_AA_CONFIG 0x4020
+#define GB_PIPE_SELECT 0x402C
+#define GA_ENHANCE 0x4274
+#define GA_DEADLOCK_CNTL (1 << 0)
+#define GA_FASTSYNC_CNTL (1 << 1)
+#define GA_POLY_MODE 0x4288
+#define FRONT_PTYPE_POINT (0 << 4)
+#define FRONT_PTYPE_LINE (1 << 4)
+#define FRONT_PTYPE_TRIANGE (2 << 4)
+#define BACK_PTYPE_POINT (0 << 7)
+#define BACK_PTYPE_LINE (1 << 7)
+#define BACK_PTYPE_TRIANGE (2 << 7)
+#define GA_ROUND_MODE 0x428C
+#define GEOMETRY_ROUND_TRUNC (0 << 0)
+#define GEOMETRY_ROUND_NEAREST (1 << 0)
+#define COLOR_ROUND_TRUNC (0 << 2)
+#define COLOR_ROUND_NEAREST (1 << 2)
+#define SU_REG_DEST 0x42C8
+#define RB3D_DSTCACHE_CTLSTAT 0x4E4C
+#define RB3D_DC_FLUSH (2 << 0)
+#define RB3D_DC_FREE (2 << 2)
+#define RB3D_DC_FINISH (1 << 4)
+#define ZB_ZCACHE_CTLSTAT 0x4F18
+#define ZC_FLUSH (1 << 0)
+#define ZC_FREE (1 << 1)
+#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 D2MODE_PRIORITY_A_CNT 0x6D48
+#define D2MODE_PRIORITY_B_CNT 0x6D4C
+
+/* ix[MC] registers */
+#define MC_FB_LOCATION 0x01
+#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 MC_AGP_LOCATION 0x02
+#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 MC_AGP_BASE 0x03
+#define MC_AGP_BASE_2 0x04
+#define MC_CNTL 0x5
+#define MEM_NUM_CHANNELS_MASK 0x00000003
+#define MC_STATUS 0x08
+#define MC_STATUS_IDLE (1 << 4)
+#define MC_MISC_LAT_TIMER 0x09
+#define MC_CPR_INIT_LAT_MASK 0x0000000F
+#define MC_VF_INIT_LAT_MASK 0x000000F0
+#define MC_DISP0R_INIT_LAT_MASK 0x00000F00
+#define MC_DISP0R_INIT_LAT_SHIFT 8
+#define MC_DISP1R_INIT_LAT_MASK 0x0000F000
+#define MC_DISP1R_INIT_LAT_SHIFT 12
+#define MC_FIXED_INIT_LAT_MASK 0x000F0000
+#define MC_E2R_INIT_LAT_MASK 0x00F00000
+#define SAME_PAGE_PRIO_MASK 0x0F000000
+#define MC_GLOBW_INIT_LAT_MASK 0xF0000000
+
+
+#endif
+
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index da50cc51ede3..21d8ffd57308 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -67,7 +67,7 @@ int rv770_mc_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n");
}
- tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+ tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
tmp = REG_SET(R700_MC_FB_TOP, tmp >> 24);
tmp |= REG_SET(R700_MC_FB_BASE, rdev->mc.vram_location >> 24);
WREG32(R700_MC_VM_FB_LOCATION, tmp);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index c1c407f7cca3..6538d4236989 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -43,7 +43,6 @@
#define TTM_BO_HASH_ORDER 13
static int ttm_bo_setup_vm(struct ttm_buffer_object *bo);
-static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
static int ttm_bo_swapout(struct ttm_mem_shrink *shrink);
static inline uint32_t ttm_bo_type_flags(unsigned type)
@@ -224,6 +223,9 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
TTM_ASSERT_LOCKED(&bo->mutex);
bo->ttm = NULL;
+ if (bdev->need_dma32)
+ page_flags |= TTM_PAGE_FLAG_DMA32;
+
switch (bo->type) {
case ttm_bo_type_device:
if (zero_alloc)
@@ -304,6 +306,9 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
}
+ if (bdev->driver->move_notify)
+ bdev->driver->move_notify(bo, mem);
+
if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
ret = ttm_bo_move_ttm(bo, evict, no_wait, mem);
@@ -655,31 +660,52 @@ retry_pre_get:
return 0;
}
+static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
+ uint32_t cur_placement,
+ uint32_t proposed_placement)
+{
+ uint32_t caching = proposed_placement & TTM_PL_MASK_CACHING;
+ uint32_t result = proposed_placement & ~TTM_PL_MASK_CACHING;
+
+ /**
+ * Keep current caching if possible.
+ */
+
+ if ((cur_placement & caching) != 0)
+ result |= (cur_placement & caching);
+ else if ((man->default_caching & caching) != 0)
+ result |= man->default_caching;
+ else if ((TTM_PL_FLAG_CACHED & caching) != 0)
+ result |= TTM_PL_FLAG_CACHED;
+ else if ((TTM_PL_FLAG_WC & caching) != 0)
+ result |= TTM_PL_FLAG_WC;
+ else if ((TTM_PL_FLAG_UNCACHED & caching) != 0)
+ result |= TTM_PL_FLAG_UNCACHED;
+
+ return result;
+}
+
+
static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
bool disallow_fixed,
uint32_t mem_type,
- uint32_t mask, uint32_t *res_mask)
+ uint32_t proposed_placement,
+ uint32_t *masked_placement)
{
uint32_t cur_flags = ttm_bo_type_flags(mem_type);
if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && disallow_fixed)
return false;
- if ((cur_flags & mask & TTM_PL_MASK_MEM) == 0)
+ if ((cur_flags & proposed_placement & TTM_PL_MASK_MEM) == 0)
return false;
- if ((mask & man->available_caching) == 0)
+ if ((proposed_placement & man->available_caching) == 0)
return false;
- if (mask & man->default_caching)
- cur_flags |= man->default_caching;
- else if (mask & TTM_PL_FLAG_CACHED)
- cur_flags |= TTM_PL_FLAG_CACHED;
- else if (mask & TTM_PL_FLAG_WC)
- cur_flags |= TTM_PL_FLAG_WC;
- else
- cur_flags |= TTM_PL_FLAG_UNCACHED;
- *res_mask = cur_flags;
+ cur_flags |= (proposed_placement & man->available_caching);
+
+ *masked_placement = cur_flags;
return true;
}
@@ -723,6 +749,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
if (!type_ok)
continue;
+ cur_flags = ttm_bo_select_caching(man, bo->mem.placement,
+ cur_flags);
+
if (mem_type == TTM_PL_SYSTEM)
break;
@@ -779,6 +808,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
proposed_placement, &cur_flags))
continue;
+ cur_flags = ttm_bo_select_caching(man, bo->mem.placement,
+ cur_flags);
+
ret = ttm_bo_mem_force_space(bdev, mem, mem_type,
interruptible, no_wait);
@@ -1305,7 +1337,8 @@ EXPORT_SYMBOL(ttm_bo_device_release);
int ttm_bo_device_init(struct ttm_bo_device *bdev,
struct ttm_mem_global *mem_glob,
- struct ttm_bo_driver *driver, uint64_t file_page_offset)
+ struct ttm_bo_driver *driver, uint64_t file_page_offset,
+ bool need_dma32)
{
int ret = -EINVAL;
@@ -1342,6 +1375,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
INIT_LIST_HEAD(&bdev->ddestroy);
INIT_LIST_HEAD(&bdev->swap_lru);
bdev->dev_mapping = NULL;
+ bdev->need_dma32 = need_dma32;
ttm_mem_init_shrink(&bdev->shrink, ttm_bo_swapout);
ret = ttm_mem_register_shrink(mem_glob, &bdev->shrink);
if (unlikely(ret != 0)) {
@@ -1419,6 +1453,7 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);
}
+EXPORT_SYMBOL(ttm_bo_unmap_virtual);
static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
{
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index bdec583901eb..ce2e6f38ea01 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -136,7 +136,8 @@ static int ttm_copy_io_page(void *dst, void *src, unsigned long page)
}
static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
- unsigned long page)
+ unsigned long page,
+ pgprot_t prot)
{
struct page *d = ttm_tt_get_page(ttm, page);
void *dst;
@@ -145,17 +146,35 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
return -ENOMEM;
src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
- dst = kmap(d);
+
+#ifdef CONFIG_X86
+ dst = kmap_atomic_prot(d, KM_USER0, prot);
+#else
+ if (prot != PAGE_KERNEL)
+ dst = vmap(&d, 1, 0, prot);
+ else
+ dst = kmap(d);
+#endif
if (!dst)
return -ENOMEM;
memcpy_fromio(dst, src, PAGE_SIZE);
- kunmap(d);
+
+#ifdef CONFIG_X86
+ kunmap_atomic(dst, KM_USER0);
+#else
+ if (prot != PAGE_KERNEL)
+ vunmap(dst);
+ else
+ kunmap(d);
+#endif
+
return 0;
}
static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
- unsigned long page)
+ unsigned long page,
+ pgprot_t prot)
{
struct page *s = ttm_tt_get_page(ttm, page);
void *src;
@@ -164,12 +183,28 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
return -ENOMEM;
dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
- src = kmap(s);
+#ifdef CONFIG_X86
+ src = kmap_atomic_prot(s, KM_USER0, prot);
+#else
+ if (prot != PAGE_KERNEL)
+ src = vmap(&s, 1, 0, prot);
+ else
+ src = kmap(s);
+#endif
if (!src)
return -ENOMEM;
memcpy_toio(dst, src, PAGE_SIZE);
- kunmap(s);
+
+#ifdef CONFIG_X86
+ kunmap_atomic(src, KM_USER0);
+#else
+ if (prot != PAGE_KERNEL)
+ vunmap(src);
+ else
+ kunmap(s);
+#endif
+
return 0;
}
@@ -214,11 +249,17 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
for (i = 0; i < new_mem->num_pages; ++i) {
page = i * dir + add;
- if (old_iomap == NULL)
- ret = ttm_copy_ttm_io_page(ttm, new_iomap, page);
- else if (new_iomap == NULL)
- ret = ttm_copy_io_ttm_page(ttm, old_iomap, page);
- else
+ if (old_iomap == NULL) {
+ pgprot_t prot = ttm_io_prot(old_mem->placement,
+ PAGE_KERNEL);
+ ret = ttm_copy_ttm_io_page(ttm, new_iomap, page,
+ prot);
+ } else if (new_iomap == NULL) {
+ pgprot_t prot = ttm_io_prot(new_mem->placement,
+ PAGE_KERNEL);
+ ret = ttm_copy_io_ttm_page(ttm, old_iomap, page,
+ prot);
+ } else
ret = ttm_copy_io_page(new_iomap, old_iomap, page);
if (ret)
goto out1;
@@ -509,8 +550,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
if (evict) {
ret = ttm_bo_wait(bo, false, false, false);
spin_unlock(&bo->lock);
- driver->sync_obj_unref(&bo->sync_obj);
-
+ if (tmp_obj)
+ driver->sync_obj_unref(&tmp_obj);
if (ret)
return ret;
@@ -532,6 +573,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
spin_unlock(&bo->lock);
+ if (tmp_obj)
+ driver->sync_obj_unref(&tmp_obj);
ret = ttm_buffer_object_transfer(bo, &ghost_obj);
if (ret)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index fe949a12fe40..33de7637c0c6 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -101,6 +101,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return VM_FAULT_NOPAGE;
}
+ if (bdev->driver->fault_reserve_notify)
+ bdev->driver->fault_reserve_notify(bo);
+
/*
* Wait for buffer data in transit, due to a pipelined
* move.
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 75dc8bd24592..b8b6c4a5f983 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -86,10 +86,16 @@ void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages)
unsigned long i;
for (i = 0; i < num_pages; ++i) {
- if (pages[i]) {
- unsigned long start = (unsigned long)page_address(pages[i]);
- flush_dcache_range(start, start + PAGE_SIZE);
- }
+ struct page *page = pages[i];
+ void *page_virtual;
+
+ if (unlikely(page == NULL))
+ continue;
+
+ page_virtual = kmap_atomic(page, KM_USER0);
+ flush_dcache_range((unsigned long) page_virtual,
+ (unsigned long) page_virtual + PAGE_SIZE);
+ kunmap_atomic(page_virtual, KM_USER0);
}
#else
if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0)
@@ -131,10 +137,17 @@ static void ttm_tt_free_page_directory(struct ttm_tt *ttm)
static struct page *ttm_tt_alloc_page(unsigned page_flags)
{
+ gfp_t gfp_flags = GFP_USER;
+
if (page_flags & TTM_PAGE_FLAG_ZERO_ALLOC)
- return alloc_page(GFP_HIGHUSER | __GFP_ZERO);
+ gfp_flags |= __GFP_ZERO;
+
+ if (page_flags & TTM_PAGE_FLAG_DMA32)
+ gfp_flags |= __GFP_DMA32;
+ else
+ gfp_flags |= __GFP_HIGHMEM;
- return alloc_page(GFP_HIGHUSER);
+ return alloc_page(gfp_flags);
}
static void ttm_tt_free_user_pages(struct ttm_tt *ttm)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7831a0318d3c..111afbe8de03 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -31,21 +31,6 @@ config HID
If unsure, say Y.
-config HID_DEBUG
- bool "HID debugging support"
- default y
- depends on HID
- ---help---
- This option lets the HID layer output diagnostics about its internal
- state, resolve HID usages, dump HID fields, etc. Individual HID drivers
- use this debugging facility to output information about individual HID
- devices, etc.
-
- This feature is useful for those who are either debugging the HID parser
- or any HID hardware device.
-
- If unsure, say Y.
-
config HIDRAW
bool "/dev/hidraw raw HID device support"
depends on HID
@@ -152,6 +137,13 @@ config HID_GYRATION
---help---
Support for Gyration remote control.
+config HID_TWINHAN
+ tristate "Twinhan" if EMBEDDED
+ depends on USB_HID
+ default !EMBEDDED
+ ---help---
+ Support for Twinhan IR remote control.
+
config HID_KENSINGTON
tristate "Kensington" if EMBEDDED
depends on USB_HID
@@ -176,6 +168,7 @@ config LOGITECH_FF
- Logitech WingMan Cordless RumblePad 2
- Logitech WingMan Force 3D
- Logitech Formula Force EX
+ - Logitech WingMan Formula Force GP
- Logitech MOMO Force wheel
and if you want to enable force feedback for them.
@@ -314,9 +307,9 @@ config THRUSTMASTER_FF
depends on HID_THRUSTMASTER
select INPUT_FF_MEMLESS
---help---
- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
- a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and
- want to enable force feedback support for it.
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3,
+ a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT
+ Rumble Force or Force Feedback Wheel.
config HID_WACOM
tristate "Wacom Bluetooth devices support" if EMBEDDED
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index db35151673b1..0de2dff5542c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -3,9 +3,12 @@
#
hid-objs := hid-core.o hid-input.o
+ifdef CONFIG_DEBUG_FS
+ hid-objs += hid-debug.o
+endif
+
obj-$(CONFIG_HID) += hid.o
-hid-$(CONFIG_HID_DEBUG) += hid-debug.o
hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-objs := hid-lg.o
@@ -40,6 +43,7 @@ obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
+obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 42ea359e94cf..df474c699fb8 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -145,12 +145,12 @@ static struct hid_driver a4_driver = {
.remove = a4_remove,
};
-static int a4_init(void)
+static int __init a4_init(void)
{
return hid_register_driver(&a4_driver);
}
-static void a4_exit(void)
+static void __exit a4_exit(void)
{
hid_unregister_driver(&a4_driver);
}
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 303ccce05bb3..4b96e7a898cf 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -451,7 +451,7 @@ static struct hid_driver apple_driver = {
.input_mapped = apple_input_mapped,
};
-static int apple_init(void)
+static int __init apple_init(void)
{
int ret;
@@ -462,7 +462,7 @@ static int apple_init(void)
return ret;
}
-static void apple_exit(void)
+static void __exit apple_exit(void)
{
hid_unregister_driver(&apple_driver);
}
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index 2f6723133a4b..4ce7aa3a519f 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -88,12 +88,12 @@ static struct hid_driver belkin_driver = {
.probe = belkin_probe,
};
-static int belkin_init(void)
+static int __init belkin_init(void)
{
return hid_register_driver(&belkin_driver);
}
-static void belkin_exit(void)
+static void __exit belkin_exit(void)
{
hid_unregister_driver(&belkin_driver);
}
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index ab8209e7e45c..7e597d7f770f 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -70,12 +70,12 @@ static struct hid_driver ch_driver = {
.input_mapping = ch_input_mapping,
};
-static int ch_init(void)
+static int __init ch_init(void)
{
return hid_register_driver(&ch_driver);
}
-static void ch_exit(void)
+static void __exit ch_exit(void)
{
hid_unregister_driver(&ch_driver);
}
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
index 7f91076d8493..8965ad93d510 100644
--- a/drivers/hid/hid-chicony.c
+++ b/drivers/hid/hid-chicony.c
@@ -63,12 +63,12 @@ static struct hid_driver ch_driver = {
.input_mapping = ch_input_mapping,
};
-static int ch_init(void)
+static int __init ch_init(void)
{
return hid_register_driver(&ch_driver);
}
-static void ch_exit(void)
+static void __exit ch_exit(void)
{
hid_unregister_driver(&ch_driver);
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5eb10c2ce665..ca69cc3fc926 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -44,12 +44,10 @@
#define DRIVER_DESC "HID core driver"
#define DRIVER_LICENSE "GPL"
-#ifdef CONFIG_HID_DEBUG
int hid_debug = 0;
module_param_named(debug, hid_debug, int, 0600);
-MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
+MODULE_PARM_DESC(debug, "toggle HID debugging messages");
EXPORT_SYMBOL_GPL(hid_debug);
-#endif
/*
* Register a new report for a device.
@@ -861,7 +859,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
struct hid_driver *hdrv = hid->driver;
int ret;
- hid_dump_input(usage, value);
+ hid_dump_input(hid, usage, value);
if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
ret = hdrv->event(hid, field, usage, value);
@@ -983,11 +981,10 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
{
unsigned size = field->report_size;
- hid_dump_input(field->usage + offset, value);
+ hid_dump_input(field->report->device, field->usage + offset, value);
if (offset >= field->report_count) {
dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count);
- hid_dump_field(field, 8);
return -1;
}
if (field->logical_minimum < 0) {
@@ -1078,6 +1075,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
struct hid_report *report;
+ char *buf;
unsigned int i;
int ret;
@@ -1091,18 +1089,38 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
return -1;
}
- dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+ buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE,
+ interrupt ? GFP_ATOMIC : GFP_KERNEL);
+
+ if (!buf) {
+ report = hid_get_report(report_enum, data);
+ goto nomem;
+ }
+
+ snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+ "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+ hid_debug_event(hid, buf);
report = hid_get_report(report_enum, data);
- if (!report)
+ if (!report) {
+ kfree(buf);
return -1;
+ }
/* dump the report */
- dbg_hid("report %d (size %u) = ", report->id, size);
- for (i = 0; i < size; i++)
- dbg_hid_line(" %02x", data[i]);
- dbg_hid_line("\n");
+ snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+ "report %d (size %u) = ", report->id, size);
+ hid_debug_event(hid, buf);
+ for (i = 0; i < size; i++) {
+ snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+ " %02x", data[i]);
+ hid_debug_event(hid, buf);
+ }
+ hid_debug_event(hid, "\n");
+ kfree(buf);
+
+nomem:
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size);
if (ret != 0)
@@ -1292,6 +1310,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
@@ -1311,9 +1330,12 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
@@ -1725,6 +1747,8 @@ int hid_add_device(struct hid_device *hdev)
if (!ret)
hdev->status |= HID_STAT_ADDED;
+ hid_debug_register(hdev, dev_name(&hdev->dev));
+
return ret;
}
EXPORT_SYMBOL_GPL(hid_add_device);
@@ -1761,6 +1785,9 @@ struct hid_device *hid_allocate_device(void)
for (i = 0; i < HID_REPORT_TYPES; i++)
INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+ init_waitqueue_head(&hdev->debug_wait);
+ INIT_LIST_HEAD(&hdev->debug_list);
+
return hdev;
err:
put_device(&hdev->dev);
@@ -1772,6 +1799,7 @@ static void hid_remove_device(struct hid_device *hdev)
{
if (hdev->status & HID_STAT_ADDED) {
device_del(&hdev->dev);
+ hid_debug_unregister(hdev);
hdev->status &= ~HID_STAT_ADDED;
}
}
@@ -1847,6 +1875,10 @@ static int __init hid_init(void)
{
int ret;
+ if (hid_debug)
+ printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
+ "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
+
ret = bus_register(&hid_bus_type);
if (ret) {
printk(KERN_ERR "HID: can't register hid bus\n");
@@ -1857,6 +1889,8 @@ static int __init hid_init(void)
if (ret)
goto err_bus;
+ hid_debug_init();
+
return 0;
err_bus:
bus_unregister(&hid_bus_type);
@@ -1866,6 +1900,7 @@ err:
static void __exit hid_exit(void)
{
+ hid_debug_exit();
hidraw_exit();
bus_unregister(&hid_bus_type);
}
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 9d6d3b91773b..62e9cb10e88c 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -141,12 +141,12 @@ static struct hid_driver cp_driver = {
.probe = cp_probe,
};
-static int cp_init(void)
+static int __init cp_init(void)
{
return hid_register_driver(&cp_driver);
}
-static void cp_exit(void)
+static void __exit cp_exit(void)
{
hid_unregister_driver(&cp_driver);
}
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 04359ed64b87..3e425f78ba3a 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -1,9 +1,9 @@
/*
* (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
* (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
- * (c) 2007 Jiri Kosina
+ * (c) 2007-2009 Jiri Kosina
*
- * Some debug stuff for the HID parser.
+ * HID debugging support
*/
/*
@@ -26,9 +26,17 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+
#include <linux/hid.h>
#include <linux/hid-debug.h>
+static struct dentry *hid_debug_root;
+
struct hid_usage_entry {
unsigned page;
unsigned usage;
@@ -339,72 +347,120 @@ static const struct hid_usage_entry hid_usage_table[] = {
{ 0, 0, NULL }
};
-static void resolv_usage_page(unsigned page) {
+/* Either output directly into simple seq_file, or (if f == NULL)
+ * allocate a separate buffer that will then be passed to the 'events'
+ * ringbuffer.
+ *
+ * This is because these functions can be called both for "one-shot"
+ * "rdesc" while resolving, or for blocking "events".
+ *
+ * This holds both for resolv_usage_page() and hid_resolv_usage().
+ */
+static char *resolv_usage_page(unsigned page, struct seq_file *f) {
const struct hid_usage_entry *p;
+ char *buf = NULL;
+
+ if (!f) {
+ buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+ }
for (p = hid_usage_table; p->description; p++)
if (p->page == page) {
- printk("%s", p->description);
- return;
+ if (!f) {
+ snprintf(buf, HID_DEBUG_BUFSIZE, "%s",
+ p->description);
+ return buf;
+ }
+ else {
+ seq_printf(f, "%s", p->description);
+ return NULL;
+ }
}
- printk("%04x", page);
+ if (!f)
+ snprintf(buf, HID_DEBUG_BUFSIZE, "%04x", page);
+ else
+ seq_printf(f, "%04x", page);
+ return buf;
}
-void hid_resolv_usage(unsigned usage) {
+char *hid_resolv_usage(unsigned usage, struct seq_file *f) {
const struct hid_usage_entry *p;
+ char *buf = NULL;
+ int len = 0;
+
+ buf = resolv_usage_page(usage >> 16, f);
+ if (IS_ERR(buf)) {
+ printk(KERN_ERR "error allocating HID debug buffer\n");
+ return NULL;
+ }
- if (!hid_debug)
- return;
- resolv_usage_page(usage >> 16);
- printk(".");
+ if (!f) {
+ len = strlen(buf);
+ snprintf(buf+len, max(0, HID_DEBUG_BUFSIZE - len), ".");
+ len++;
+ }
+ else {
+ seq_printf(f, ".");
+ }
for (p = hid_usage_table; p->description; p++)
if (p->page == (usage >> 16)) {
for(++p; p->description && p->usage != 0; p++)
if (p->usage == (usage & 0xffff)) {
- printk("%s", p->description);
- return;
+ if (!f)
+ snprintf(buf + len,
+ max(0,HID_DEBUG_BUFSIZE - len - 1),
+ "%s", p->description);
+ else
+ seq_printf(f,
+ "%s",
+ p->description);
+ return buf;
}
break;
}
- printk("%04x", usage & 0xffff);
+ if (!f)
+ snprintf(buf + len, max(0, HID_DEBUG_BUFSIZE - len - 1),
+ "%04x", usage & 0xffff);
+ else
+ seq_printf(f, "%04x", usage & 0xffff);
+ return buf;
}
EXPORT_SYMBOL_GPL(hid_resolv_usage);
-static void tab(int n) {
- printk(KERN_DEBUG "%*s", n, "");
+static void tab(int n, struct seq_file *f) {
+ seq_printf(f, "%*s", n, "");
}
-void hid_dump_field(struct hid_field *field, int n) {
+void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) {
int j;
- if (!hid_debug)
- return;
-
if (field->physical) {
- tab(n);
- printk("Physical(");
- hid_resolv_usage(field->physical); printk(")\n");
+ tab(n, f);
+ seq_printf(f, "Physical(");
+ hid_resolv_usage(field->physical, f); seq_printf(f, ")\n");
}
if (field->logical) {
- tab(n);
- printk("Logical(");
- hid_resolv_usage(field->logical); printk(")\n");
+ tab(n, f);
+ seq_printf(f, "Logical(");
+ hid_resolv_usage(field->logical, f); seq_printf(f, ")\n");
}
- tab(n); printk("Usage(%d)\n", field->maxusage);
+ tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage);
for (j = 0; j < field->maxusage; j++) {
- tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
+ tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n");
}
if (field->logical_minimum != field->logical_maximum) {
- tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
- tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+ tab(n, f); seq_printf(f, "Logical Minimum(%d)\n", field->logical_minimum);
+ tab(n, f); seq_printf(f, "Logical Maximum(%d)\n", field->logical_maximum);
}
if (field->physical_minimum != field->physical_maximum) {
- tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
- tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+ tab(n, f); seq_printf(f, "Physical Minimum(%d)\n", field->physical_minimum);
+ tab(n, f); seq_printf(f, "Physical Maximum(%d)\n", field->physical_maximum);
}
if (field->unit_exponent) {
- tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+ tab(n, f); seq_printf(f, "Unit Exponent(%d)\n", field->unit_exponent);
}
if (field->unit) {
static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
@@ -425,77 +481,75 @@ void hid_dump_field(struct hid_field *field, int n) {
data >>= 4;
if(sys > 4) {
- tab(n); printk("Unit(Invalid)\n");
+ tab(n, f); seq_printf(f, "Unit(Invalid)\n");
}
else {
int earlier_unit = 0;
- tab(n); printk("Unit(%s : ", systems[sys]);
+ tab(n, f); seq_printf(f, "Unit(%s : ", systems[sys]);
for (i=1 ; i<sizeof(__u32)*2 ; i++) {
char nibble = data & 0xf;
data >>= 4;
if (nibble != 0) {
if(earlier_unit++ > 0)
- printk("*");
- printk("%s", units[sys][i]);
+ seq_printf(f, "*");
+ seq_printf(f, "%s", units[sys][i]);
if(nibble != 1) {
/* This is a _signed_ nibble(!) */
int val = nibble & 0x7;
if(nibble & 0x08)
val = -((0x7 & ~val) +1);
- printk("^%d", val);
+ seq_printf(f, "^%d", val);
}
}
}
- printk(")\n");
+ seq_printf(f, ")\n");
}
}
- tab(n); printk("Report Size(%u)\n", field->report_size);
- tab(n); printk("Report Count(%u)\n", field->report_count);
- tab(n); printk("Report Offset(%u)\n", field->report_offset);
+ tab(n, f); seq_printf(f, "Report Size(%u)\n", field->report_size);
+ tab(n, f); seq_printf(f, "Report Count(%u)\n", field->report_count);
+ tab(n, f); seq_printf(f, "Report Offset(%u)\n", field->report_offset);
- tab(n); printk("Flags( ");
+ tab(n, f); seq_printf(f, "Flags( ");
j = field->flags;
- printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
- printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
- printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
- printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
- printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
- printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
- printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
- printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
- printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
- printk(")\n");
+ seq_printf(f, "%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+ seq_printf(f, "%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+ seq_printf(f, "%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+ seq_printf(f, "%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+ seq_printf(f, ")\n");
}
EXPORT_SYMBOL_GPL(hid_dump_field);
-void hid_dump_device(struct hid_device *device) {
+void hid_dump_device(struct hid_device *device, struct seq_file *f)
+{
struct hid_report_enum *report_enum;
struct hid_report *report;
struct list_head *list;
unsigned i,k;
static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
- if (!hid_debug)
- return;
-
for (i = 0; i < HID_REPORT_TYPES; i++) {
report_enum = device->report_enum + i;
list = report_enum->report_list.next;
while (list != &report_enum->report_list) {
report = (struct hid_report *) list;
- tab(2);
- printk("%s", table[i]);
+ tab(2, f);
+ seq_printf(f, "%s", table[i]);
if (report->id)
- printk("(%d)", report->id);
- printk("[%s]", table[report->type]);
- printk("\n");
+ seq_printf(f, "(%d)", report->id);
+ seq_printf(f, "[%s]", table[report->type]);
+ seq_printf(f, "\n");
for (k = 0; k < report->maxfield; k++) {
- tab(4);
- printk("Field(%d)\n", k);
- hid_dump_field(report->field[k], 6);
+ tab(4, f);
+ seq_printf(f, "Field(%d)\n", k);
+ hid_dump_field(report->field[k], 6, f);
}
list = list->next;
}
@@ -503,13 +557,37 @@ void hid_dump_device(struct hid_device *device) {
}
EXPORT_SYMBOL_GPL(hid_dump_device);
-void hid_dump_input(struct hid_usage *usage, __s32 value) {
- if (hid_debug < 2)
+/* enqueue string to 'events' ring buffer */
+void hid_debug_event(struct hid_device *hdev, char *buf)
+{
+ int i;
+ struct hid_debug_list *list;
+
+ list_for_each_entry(list, &hdev->debug_list, node) {
+ for (i = 0; i <= strlen(buf); i++)
+ list->hid_debug_buf[(list->tail + i) % (HID_DEBUG_BUFSIZE - 1)] =
+ buf[i];
+ list->tail = (list->tail + i) % (HID_DEBUG_BUFSIZE - 1);
+ }
+}
+EXPORT_SYMBOL_GPL(hid_debug_event);
+
+void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value)
+{
+ char *buf;
+ int len;
+
+ buf = hid_resolv_usage(usage->hid, NULL);
+ if (!buf)
return;
+ len = strlen(buf);
+ snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %d\n", value);
+
+ hid_debug_event(hdev, buf);
+
+ kfree(buf);
+ wake_up_interruptible(&hdev->debug_wait);
- printk(KERN_DEBUG "hid-debug: input ");
- hid_resolv_usage(usage->hid);
- printk(" = %d\n", value);
}
EXPORT_SYMBOL_GPL(hid_dump_input);
@@ -786,12 +864,220 @@ static const char **names[EV_MAX + 1] = {
[EV_SND] = sounds, [EV_REP] = repeats,
};
-void hid_resolv_event(__u8 type, __u16 code) {
+void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) {
- if (!hid_debug)
- return;
-
- printk("%s.%s", events[type] ? events[type] : "?",
+ seq_printf(f, "%s.%s", events[type] ? events[type] : "?",
names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
}
-EXPORT_SYMBOL_GPL(hid_resolv_event);
+
+void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
+{
+ int i, j, k;
+ struct hid_report *report;
+ struct hid_usage *usage;
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+ list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
+ for (i = 0; i < report->maxfield; i++) {
+ for ( j = 0; j < report->field[i]->maxusage; j++) {
+ usage = report->field[i]->usage + j;
+ hid_resolv_usage(usage->hid, f);
+ seq_printf(f, " ---> ");
+ hid_resolv_event(usage->type, usage->code, f);
+ seq_printf(f, "\n");
+ }
+ }
+ }
+ }
+
+}
+
+
+static int hid_debug_rdesc_show(struct seq_file *f, void *p)
+{
+ struct hid_device *hdev = f->private;
+ int i;
+
+ /* dump HID report descriptor */
+ for (i = 0; i < hdev->rsize; i++)
+ seq_printf(f, "%02x ", hdev->rdesc[i]);
+ seq_printf(f, "\n\n");
+
+ /* dump parsed data and input mappings */
+ hid_dump_device(hdev, f);
+ seq_printf(f, "\n");
+ hid_dump_input_mapping(hdev, f);
+
+ return 0;
+}
+
+static int hid_debug_rdesc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, hid_debug_rdesc_show, inode->i_private);
+}
+
+static int hid_debug_events_open(struct inode *inode, struct file *file)
+{
+ int err = 0;
+ struct hid_debug_list *list;
+
+ if (!(list = kzalloc(sizeof(struct hid_debug_list), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto out;
+ }
+ list->hdev = (struct hid_device *) inode->i_private;
+ file->private_data = list;
+ mutex_init(&list->read_mutex);
+
+ list_add_tail(&list->node, &list->hdev->debug_list);
+
+out:
+ return err;
+}
+
+static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct hid_debug_list *list = file->private_data;
+ int ret = 0, len;
+ DECLARE_WAITQUEUE(wait, current);
+
+ while (ret == 0) {
+ mutex_lock(&list->read_mutex);
+ if (list->head == list->tail) {
+ add_wait_queue(&list->hdev->debug_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (list->head == list->tail) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ if (!list->hdev || !list->hdev->debug) {
+ ret = -EIO;
+ break;
+ }
+
+ /* allow O_NONBLOCK from other threads */
+ mutex_unlock(&list->read_mutex);
+ schedule();
+ mutex_lock(&list->read_mutex);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&list->hdev->debug_wait, &wait);
+ }
+
+ if (ret)
+ goto out;
+
+ /* pass the ringbuffer contents to userspace */
+copy_rest:
+ if (list->tail == list->head)
+ goto out;
+ if (list->tail > list->head) {
+ len = list->tail - list->head;
+
+ if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret += len;
+ list->head += len;
+ } else {
+ len = HID_DEBUG_BUFSIZE - list->head;
+
+ if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ list->head = 0;
+ ret += len;
+ goto copy_rest;
+ }
+
+ }
+out:
+ mutex_unlock(&list->read_mutex);
+ return ret;
+}
+
+static unsigned int hid_debug_events_poll(struct file *file, poll_table *wait)
+{
+ struct hid_debug_list *list = file->private_data;
+
+ poll_wait(file, &list->hdev->debug_wait, wait);
+ if (list->head != list->tail)
+ return POLLIN | POLLRDNORM;
+ if (!list->hdev->debug)
+ return POLLERR | POLLHUP;
+ return 0;
+}
+
+static int hid_debug_events_release(struct inode *inode, struct file *file)
+{
+ struct hid_debug_list *list = file->private_data;
+
+ list_del(&list->node);
+ kfree(list->hid_debug_buf);
+ kfree(list);
+
+ return 0;
+}
+
+static const struct file_operations hid_debug_rdesc_fops = {
+ .open = hid_debug_rdesc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations hid_debug_events_fops = {
+ .owner = THIS_MODULE,
+ .open = hid_debug_events_open,
+ .read = hid_debug_events_read,
+ .poll = hid_debug_events_poll,
+ .release = hid_debug_events_release,
+};
+
+
+void hid_debug_register(struct hid_device *hdev, const char *name)
+{
+ hdev->debug_dir = debugfs_create_dir(name, hid_debug_root);
+ hdev->debug_rdesc = debugfs_create_file("rdesc", 0400,
+ hdev->debug_dir, hdev, &hid_debug_rdesc_fops);
+ hdev->debug_events = debugfs_create_file("events", 0400,
+ hdev->debug_dir, hdev, &hid_debug_events_fops);
+ hdev->debug = 1;
+}
+
+void hid_debug_unregister(struct hid_device *hdev)
+{
+ hdev->debug = 0;
+ wake_up_interruptible(&hdev->debug_wait);
+ debugfs_remove(hdev->debug_rdesc);
+ debugfs_remove(hdev->debug_events);
+ debugfs_remove(hdev->debug_dir);
+}
+
+void hid_debug_init(void)
+{
+ hid_debug_root = debugfs_create_dir("hid", NULL);
+}
+
+void hid_debug_exit(void)
+{
+ debugfs_remove_recursive(hid_debug_root);
+}
+
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
index 0a1fe054799b..ca1163e9d42d 100644
--- a/drivers/hid/hid-ezkey.c
+++ b/drivers/hid/hid-ezkey.c
@@ -78,12 +78,12 @@ static struct hid_driver ez_driver = {
.event = ez_event,
};
-static int ez_init(void)
+static int __init ez_init(void)
{
return hid_register_driver(&ez_driver);
}
-static void ez_exit(void)
+static void __exit ez_exit(void)
{
hid_unregister_driver(&ez_driver);
}
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index d42d222097a8..cab13e8c7d29 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -81,12 +81,12 @@ static struct hid_driver gyration_driver = {
.event = gyration_event,
};
-static int gyration_init(void)
+static int __init gyration_init(void)
{
return hid_register_driver(&gyration_driver);
}
-static void gyration_exit(void)
+static void __exit gyration_exit(void)
{
hid_unregister_driver(&gyration_driver);
}
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 630101037921..3058e472aeb5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -296,6 +296,7 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
@@ -403,6 +404,9 @@
#define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+#define USB_VENDOR_ID_TWINHAN 0x6253
+#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
+
#define USB_VENDOR_ID_UCLOGIC 0x5543
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7f183b7147e1..5862b0f3b55d 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -159,17 +159,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput;
- dbg_hid("Mapping: ");
- hid_resolv_usage(usage->hid);
- dbg_hid_line(" ---> ");
-
if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore;
/* only LED usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT &&
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
- dbg_hid_line(" [non-LED output field] ");
goto ignore;
}
@@ -561,15 +556,9 @@ mapped:
set_bit(MSC_SCAN, input->mscbit);
}
- hid_resolv_event(usage->type, usage->code);
-
- dbg_hid_line("\n");
-
- return;
-
ignore:
- dbg_hid_line("IGNORED\n");
return;
+
}
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c
index 7353bd79cbe9..a5b4016e9bd7 100644
--- a/drivers/hid/hid-kensington.c
+++ b/drivers/hid/hid-kensington.c
@@ -48,12 +48,12 @@ static struct hid_driver ks_driver = {
.input_mapping = ks_input_mapping,
};
-static int ks_init(void)
+static int __init ks_init(void)
{
return hid_register_driver(&ks_driver);
}
-static void ks_exit(void)
+static void __exit ks_exit(void)
{
hid_unregister_driver(&ks_driver);
}
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index 72ee3fec56d9..f8871712b7b5 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -54,12 +54,12 @@ static struct hid_driver kye_driver = {
.report_fixup = kye_report_fixup,
};
-static int kye_init(void)
+static int __init kye_init(void)
{
return hid_register_driver(&kye_driver);
}
-static void kye_exit(void)
+static void __exit kye_exit(void)
{
hid_unregister_driver(&kye_driver);
}
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 7afbaa0efd18..0f870a3243ed 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -299,6 +299,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
+ .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
.driver_data = LG_FF2 },
{ }
@@ -315,12 +317,12 @@ static struct hid_driver lg_driver = {
.probe = lg_probe,
};
-static int lg_init(void)
+static int __init lg_init(void)
{
return hid_register_driver(&lg_driver);
}
-static void lg_exit(void)
+static void __exit lg_exit(void)
{
hid_unregister_driver(&lg_driver);
}
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 56099709581c..987abebe0829 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -67,6 +67,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
{ 0x046d, 0xc286, ff_joystick_ac },
+ { 0x046d, 0xc293, ff_joystick },
{ 0x046d, 0xc294, ff_wheel },
{ 0x046d, 0xc295, ff_joystick },
{ 0x046d, 0xca03, ff_wheel },
@@ -150,11 +151,6 @@ int lgff_init(struct hid_device* hid)
/* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list);
- if (!report) {
- err_hid("NULL output report");
- return -1;
- }
-
field = report->field[0];
if (!field) {
err_hid("NULL field");
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 5e9e37a0506d..359cc447c6c6 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -197,12 +197,12 @@ static struct hid_driver ms_driver = {
.probe = ms_probe,
};
-static int ms_init(void)
+static int __init ms_init(void)
{
return hid_register_driver(&ms_driver);
}
-static void ms_exit(void)
+static void __exit ms_exit(void)
{
hid_unregister_driver(&ms_driver);
}
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index 240f87618be6..2cd05aa244b9 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -65,12 +65,12 @@ static struct hid_driver mr_driver = {
.input_mapping = mr_input_mapping,
};
-static int mr_init(void)
+static int __init mr_init(void)
{
return hid_register_driver(&mr_driver);
}
-static void mr_exit(void)
+static void __exit mr_exit(void)
{
hid_unregister_driver(&mr_driver);
}
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 75ed9d2c1a36..49ce69d7bba7 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -27,6 +27,9 @@
struct ntrig_data {
__s32 x, y, id, w, h;
char reading_a_point, found_contact_id;
+ char pen_active;
+ char finger_active;
+ char inverted;
};
/*
@@ -63,10 +66,7 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
/* we do not want to map these for now */
- case HID_DG_INVERT: /* value is always 0 */
- case HID_DG_ERASER: /* value is always 0 */
case HID_DG_CONTACTID: /* value is useless */
- case HID_DG_BARRELSWITCH: /* doubtful */
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
case HID_DG_CONTACTCOUNT:
@@ -125,6 +125,18 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) {
+
+ case HID_DG_INRANGE:
+ if (field->application & 0x3)
+ nd->pen_active = (value != 0);
+ else
+ nd->finger_active = (value != 0);
+ return 0;
+
+ case HID_DG_INVERT:
+ nd->inverted = value;
+ return 0;
+
case HID_GD_X:
nd->x = value;
nd->reading_a_point = 1;
@@ -147,7 +159,11 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
* report received in a finger event. We want
* to emit a normal (X, Y) position
*/
- if (! nd->found_contact_id) {
+ if (!nd->found_contact_id) {
+ if (nd->pen_active && nd->finger_active) {
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
+ }
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
}
@@ -159,6 +175,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
* to emit a normal (X, Y) position
*/
if (! nd->found_contact_id) {
+ if (nd->pen_active && nd->finger_active) {
+ input_report_key(input,
+ nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
+ , 0);
+ input_report_key(input,
+ nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
+ , 1);
+ }
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
input_event(input, EV_ABS, ABS_PRESSURE, value);
@@ -233,6 +257,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
kfree (nd);
+
return ret;
}
@@ -265,12 +290,12 @@ static struct hid_driver ntrig_driver = {
.event = ntrig_event,
};
-static int ntrig_init(void)
+static int __init ntrig_init(void)
{
return hid_register_driver(&ntrig_driver);
}
-static void ntrig_exit(void)
+static void __exit ntrig_exit(void)
{
hid_unregister_driver(&ntrig_driver);
}
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 2e83e8ff891a..500fbd0652dc 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -105,12 +105,12 @@ static struct hid_driver pl_driver = {
.probe = pl_probe,
};
-static int pl_init(void)
+static int __init pl_init(void)
{
return hid_register_driver(&pl_driver);
}
-static void pl_exit(void)
+static void __exit pl_exit(void)
{
hid_unregister_driver(&pl_driver);
}
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 4db9a3483760..c6d7dbc935b1 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -217,12 +217,12 @@ static struct hid_driver pl_driver = {
.probe = pl_probe,
};
-static int pl_init(void)
+static int __init pl_init(void)
{
return hid_register_driver(&pl_driver);
}
-static void pl_exit(void)
+static void __exit pl_exit(void)
{
hid_unregister_driver(&pl_driver);
}
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 07083aa6c19a..5b222eed0692 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -25,25 +25,48 @@
/*
* Samsung IrDA remote controller (reports as Cypress USB Mouse).
*
+ * There are several variants for 0419:0001:
+ *
+ * 1. 184 byte report descriptor
* Vendor specific report #4 has a size of 48 bit,
* and therefore is not accepted when inspecting the descriptors.
* As a workaround we reinterpret the report as:
* Variable type, count 6, size 8 bit, log. maximum 255
* The burden to reconstruct the data is moved into user space.
+ *
+ * 2. 203 byte report descriptor
+ * Report #4 has an array field with logical range 0..18 instead of 1..15.
+ *
+ * 3. 135 byte report descriptor
+ * Report #4 has an array field with logical range 0..17 instead of 1..14.
*/
static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int rsize)
{
- if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+ if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
rdesc[182] == 0x40) {
- dev_info(&hdev->dev, "fixing up Samsung IrDA report "
- "descriptor\n");
+ dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
+ "descriptor\n", 184);
rdesc[176] = 0xff;
rdesc[178] = 0x08;
rdesc[180] = 0x06;
rdesc[182] = 0x42;
+ } else
+ if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
+ rdesc[194] == 0x25 && rdesc[195] == 0x12) {
+ dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
+ "descriptor\n", 203);
+ rdesc[193] = 0x1;
+ rdesc[195] = 0xf;
+ } else
+ if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
+ rdesc[126] == 0x25 && rdesc[127] == 0x11) {
+ dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
+ "descriptor\n", 135);
+ rdesc[125] = 0x1;
+ rdesc[127] = 0xe;
}
}
@@ -51,6 +74,7 @@ static int samsung_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
+ unsigned int cmask = HID_CONNECT_DEFAULT;
ret = hid_parse(hdev);
if (ret) {
@@ -58,8 +82,13 @@ static int samsung_probe(struct hid_device *hdev,
goto err_free;
}
- ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) |
- HID_CONNECT_HIDDEV_FORCE);
+ if (hdev->rsize == 184) {
+ /* disable hidinput, force hiddev */
+ cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
+ HID_CONNECT_HIDDEV_FORCE;
+ }
+
+ ret = hid_hw_start(hdev, cmask);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto err_free;
@@ -83,12 +112,12 @@ static struct hid_driver samsung_driver = {
.probe = samsung_probe,
};
-static int samsung_init(void)
+static int __init samsung_init(void)
{
return hid_register_driver(&samsung_driver);
}
-static void samsung_exit(void)
+static void __exit samsung_exit(void)
{
hid_unregister_driver(&samsung_driver);
}
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index eab169e5c371..203c438b016f 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -163,12 +163,12 @@ static struct hid_driver sjoy_driver = {
.probe = sjoy_probe,
};
-static int sjoy_init(void)
+static int __init sjoy_init(void)
{
return hid_register_driver(&sjoy_driver);
}
-static void sjoy_exit(void)
+static void __exit sjoy_exit(void)
{
hid_unregister_driver(&sjoy_driver);
}
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index c2599388a350..4e8450228a24 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -135,12 +135,12 @@ static struct hid_driver sony_driver = {
.report_fixup = sony_report_fixup,
};
-static int sony_init(void)
+static int __init sony_init(void)
{
return hid_register_driver(&sony_driver);
}
-static void sony_exit(void)
+static void __exit sony_exit(void)
{
hid_unregister_driver(&sony_driver);
}
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index e0a8fd36a85b..438107d9f1b2 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -65,12 +65,12 @@ static struct hid_driver sp_driver = {
.input_mapping = sp_input_mapping,
};
-static int sp_init(void)
+static int __init sp_init(void)
{
return hid_register_driver(&sp_driver);
}
-static void sp_exit(void)
+static void __exit sp_exit(void)
{
hid_unregister_driver(&sp_driver);
}
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index fcd6ccd02fee..167ea746fb9c 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -243,7 +243,11 @@ err:
static const struct hid_device_id tm_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300),
.driver_data = (unsigned long)ff_rumble },
- { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), /* FireStorm Dual Power 2 (and 3) */
+ .driver_data = (unsigned long)ff_rumble },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323), /* Dual Trigger 3-in-1 (PC Mode) */
+ .driver_data = (unsigned long)ff_rumble },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */
.driver_data = (unsigned long)ff_rumble },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */
.driver_data = (unsigned long)ff_rumble },
@@ -259,12 +263,12 @@ static struct hid_driver tm_driver = {
.probe = tm_probe,
};
-static int tm_init(void)
+static int __init tm_init(void)
{
return hid_register_driver(&tm_driver);
}
-static void tm_exit(void)
+static void __exit tm_exit(void)
{
hid_unregister_driver(&tm_driver);
}
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 152ccfabeba5..6925eda1081a 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -60,12 +60,12 @@ static struct hid_driver ts_driver = {
.input_mapping = ts_input_mapping,
};
-static int ts_init(void)
+static int __init ts_init(void)
{
return hid_register_driver(&ts_driver);
}
-static void ts_exit(void)
+static void __exit ts_exit(void)
{
hid_unregister_driver(&ts_driver);
}
diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c
new file mode 100644
index 000000000000..b05f602c051e
--- /dev/null
+++ b/drivers/hid/hid-twinhan.c
@@ -0,0 +1,147 @@
+/*
+ * HID driver for TwinHan IR remote control
+ *
+ * Based on hid-gyration.c
+ *
+ * Copyright (c) 2009 Bruno Prémont <bonbons@linux-vserver.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.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* Remote control key layout + listing:
+ *
+ * Full Screen Power
+ * KEY_SCREEN KEY_POWER2
+ *
+ * 1 2 3
+ * KEY_NUMERIC_1 KEY_NUMERIC_2 KEY_NUMERIC_3
+ *
+ * 4 5 6
+ * KEY_NUMERIC_4 KEY_NUMERIC_5 KEY_NUMERIC_6
+ *
+ * 7 8 9
+ * KEY_NUMERIC_7 KEY_NUMERIC_8 KEY_NUMERIC_9
+ *
+ * REC 0 Favorite
+ * KEY_RECORD KEY_NUMERIC_0 KEY_FAVORITES
+ *
+ * Rewind Forward
+ * KEY_REWIND CH+ KEY_FORWARD
+ * KEY_CHANNELUP
+ *
+ * VOL- > VOL+
+ * KEY_VOLUMEDOWN KEY_PLAY KEY_VOLUMEUP
+ *
+ * CH-
+ * KEY_CHANNELDOWN
+ * Recall Stop
+ * KEY_RESTART KEY_STOP
+ *
+ * Timeshift/Pause Mute Cancel
+ * KEY_PAUSE KEY_MUTE KEY_CANCEL
+ *
+ * Capture Preview EPG
+ * KEY_PRINT KEY_PROGRAM KEY_EPG
+ *
+ * Record List Tab Teletext
+ * KEY_LIST KEY_TAB KEY_TEXT
+ */
+
+#define th_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int twinhan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ /* Map all keys from Twinhan Remote */
+ case 0x004: th_map_key_clear(KEY_TEXT); break;
+ case 0x006: th_map_key_clear(KEY_RESTART); break;
+ case 0x008: th_map_key_clear(KEY_EPG); break;
+ case 0x00c: th_map_key_clear(KEY_REWIND); break;
+ case 0x00e: th_map_key_clear(KEY_PROGRAM); break;
+ case 0x00f: th_map_key_clear(KEY_LIST); break;
+ case 0x010: th_map_key_clear(KEY_MUTE); break;
+ case 0x011: th_map_key_clear(KEY_FORWARD); break;
+ case 0x013: th_map_key_clear(KEY_PRINT); break;
+ case 0x017: th_map_key_clear(KEY_PAUSE); break;
+ case 0x019: th_map_key_clear(KEY_FAVORITES); break;
+ case 0x01d: th_map_key_clear(KEY_SCREEN); break;
+ case 0x01e: th_map_key_clear(KEY_NUMERIC_1); break;
+ case 0x01f: th_map_key_clear(KEY_NUMERIC_2); break;
+ case 0x020: th_map_key_clear(KEY_NUMERIC_3); break;
+ case 0x021: th_map_key_clear(KEY_NUMERIC_4); break;
+ case 0x022: th_map_key_clear(KEY_NUMERIC_5); break;
+ case 0x023: th_map_key_clear(KEY_NUMERIC_6); break;
+ case 0x024: th_map_key_clear(KEY_NUMERIC_7); break;
+ case 0x025: th_map_key_clear(KEY_NUMERIC_8); break;
+ case 0x026: th_map_key_clear(KEY_NUMERIC_9); break;
+ case 0x027: th_map_key_clear(KEY_NUMERIC_0); break;
+ case 0x028: th_map_key_clear(KEY_PLAY); break;
+ case 0x029: th_map_key_clear(KEY_CANCEL); break;
+ case 0x02b: th_map_key_clear(KEY_TAB); break;
+ /* Power = 0x0e0 + 0x0e1 + 0x0e2 + 0x03f */
+ case 0x03f: th_map_key_clear(KEY_POWER2); break;
+ case 0x04a: th_map_key_clear(KEY_RECORD); break;
+ case 0x04b: th_map_key_clear(KEY_CHANNELUP); break;
+ case 0x04d: th_map_key_clear(KEY_STOP); break;
+ case 0x04e: th_map_key_clear(KEY_CHANNELDOWN); break;
+ /* Volume down = 0x0e1 + 0x051 */
+ case 0x051: th_map_key_clear(KEY_VOLUMEDOWN); break;
+ /* Volume up = 0x0e1 + 0x052 */
+ case 0x052: th_map_key_clear(KEY_VOLUMEUP); break;
+ /* Kill the extra keys used for multi-key "power" and "volume" keys
+ * as well as continuously to release CTRL,ALT,META,... keys */
+ case 0x0e0:
+ case 0x0e1:
+ case 0x0e2:
+ case 0x0e3:
+ case 0x0e4:
+ case 0x0e5:
+ case 0x0e6:
+ case 0x0e7:
+ default:
+ return -1;
+ }
+ return 1;
+}
+
+static const struct hid_device_id twinhan_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, twinhan_devices);
+
+static struct hid_driver twinhan_driver = {
+ .name = "twinhan",
+ .id_table = twinhan_devices,
+ .input_mapping = twinhan_input_mapping,
+};
+
+static int twinhan_init(void)
+{
+ return hid_register_driver(&twinhan_driver);
+}
+
+static void twinhan_exit(void)
+{
+ hid_unregister_driver(&twinhan_driver);
+}
+
+module_init(twinhan_init);
+module_exit(twinhan_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 1f9237f511e3..747542172242 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -237,7 +237,7 @@ static struct hid_driver wacom_driver = {
.raw_event = wacom_raw_event,
};
-static int wacom_init(void)
+static int __init wacom_init(void)
{
int ret;
@@ -248,7 +248,7 @@ static int wacom_init(void)
return ret;
}
-static void wacom_exit(void)
+static void __exit wacom_exit(void)
{
hid_unregister_driver(&wacom_driver);
}
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index 57f710757bf4..a79f0d78c6be 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -152,12 +152,12 @@ static struct hid_driver zp_driver = {
.probe = zp_probe,
};
-static int zp_init(void)
+static int __init zp_init(void)
{
return hid_register_driver(&zp_driver);
}
-static void zp_exit(void)
+static void __exit zp_exit(void)
{
hid_unregister_driver(&zp_driver);
}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 3c1fcb7640ab..1e185a345d94 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -4,8 +4,8 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006-2008 Jiri Kosina
* Copyright (c) 2007-2008 Oliver Neukum
+ * Copyright (c) 2006-2009 Jiri Kosina
*/
/*
@@ -885,11 +885,6 @@ static int usbhid_parse(struct hid_device *hid)
goto err;
}
- dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
- for (n = 0; n < rsize; n++)
- dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
- dbg_hid_line("\n");
-
ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc);
if (ret) {
@@ -986,7 +981,6 @@ static int usbhid_start(struct hid_device *hid)
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
- spin_lock_init(&usbhid->lock);
usbhid->intf = intf;
usbhid->ifnum = interface->desc.bInterfaceNumber;
@@ -1004,7 +998,6 @@ static int usbhid_start(struct hid_device *hid)
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
usbhid_init_reports(hid);
- hid_dump_device(hid);
set_bit(HID_STARTED, &usbhid->iofl);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d5016691d40..a897732af4a9 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -797,6 +797,16 @@ config SENSORS_TMP401
This driver can also be built as a module. If so, the module
will be called tmp401.
+config SENSORS_TMP421
+ tristate "Texas Instruments TMP421 and compatible"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for Texas Instruments TMP421,
+ TMP422 and TMP423 temperature sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called tmp421.
+
config SENSORS_VIA686A
tristate "VIA686A"
depends on PCI
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce6bed5..537daac4b35a 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
+obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index bff0103610c1..fe4fa29c9219 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -593,7 +593,11 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
sensor->data = data;
sensor->id = flags->integer.value;
sensor->limit1 = limit1->integer.value;
- sensor->limit2 = limit2->integer.value;
+ if (data->old_interface)
+ sensor->limit2 = limit2->integer.value;
+ else
+ /* The upper limit is expressed as delta from lower limit */
+ sensor->limit2 = sensor->limit1 + limit2->integer.value;
snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
"%s%d_input", base_name, start + *num);
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index bfc296145bba..bf0862a803c0 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -179,8 +179,14 @@ struct vrm_model {
static struct vrm_model vrm_models[] = {
{X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */
{X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */
- {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* NPT family 0Fh */
+ /* In theory, all NPT family 0Fh processors have 6 VID pins and should
+ thus use vrm 25, however in practice not all mainboards route the
+ 6th VID pin because it is never needed. So we use the 5 VID pin
+ variant (vrm 24) for the models which exist today. */
+ {X86_VENDOR_AMD, 0xF, 0x7F, ANY, 24}, /* NPT family 0Fh */
+ {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* future fam. 0Fh */
{X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */
+
{X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */
{X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */
{X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */
@@ -191,12 +197,14 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */
{X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */
{X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */
+
{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */
{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
{X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */
+
{X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */
};
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 3a8a0f7a7736..05f4ba8586e8 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -435,7 +435,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
/* This will need to be revisited when we add support for
temperature and voltage monitoring. */
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+ if (!request_region(res->start, resource_size(res), DRVNAME)) {
err = -EBUSY;
dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
(unsigned long)res->start, (unsigned long)res->end);
@@ -475,7 +475,7 @@ exit_remove_files:
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
}
exit_release_region:
- release_region(res->start, res->end - res->start + 1);
+ release_region(res->start, resource_size(res));
exit_kfree:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -500,7 +500,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, res->end - res->start + 1);
+ release_region(res->start, resource_size(res));
return 0;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index a92dbb97ee99..ba75bfcf14ce 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -86,6 +86,7 @@ superio_exit(void)
#define SUPERIO_REG_ACT 0x30
#define SUPERIO_REG_BASE 0x60
#define SUPERIO_REG_DEVID 0x20
+#define SUPERIO_REG_DEVREV 0x21
/* Logical device registers */
@@ -429,6 +430,9 @@ static int __init smsc47m1_find(unsigned short *addr,
* The LPC47M292 (device id 0x6B) is somewhat compatible, but it
* supports a 3rd fan, and the pin configuration registers are
* unfortunately different.
+ * The LPC47M233 has the same device id (0x6B) but is not compatible.
+ * We check the high bit of the device revision register to
+ * differentiate them.
*/
switch (val) {
case 0x51:
@@ -448,6 +452,13 @@ static int __init smsc47m1_find(unsigned short *addr,
sio_data->type = smsc47m1;
break;
case 0x6B:
+ if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
+ pr_debug(DRVNAME ": "
+ "Found SMSC LPC47M233, unsupported\n");
+ superio_exit();
+ return -ENODEV;
+ }
+
pr_info(DRVNAME ": Found SMSC LPC47M292\n");
sio_data->type = smsc47m2;
break;
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
new file mode 100644
index 000000000000..20924343431b
--- /dev/null
+++ b/drivers/hwmon/tmp421.c
@@ -0,0 +1,347 @@
+/* tmp421.c
+ *
+ * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
+ * Preliminary support by:
+ * Melvin Rook, Raymond Ng
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ */
+
+/*
+ * Driver for the Texas Instruments TMP421 SMBus temperature sensor IC.
+ * Supported models: TMP421, TMP422, TMP423
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
+ I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_3(tmp421, tmp422, tmp423);
+
+/* The TMP421 registers */
+#define TMP421_CONFIG_REG_1 0x09
+#define TMP421_CONVERSION_RATE_REG 0x0B
+#define TMP421_MANUFACTURER_ID_REG 0xFE
+#define TMP421_DEVICE_ID_REG 0xFF
+
+static const u8 TMP421_TEMP_MSB[4] = { 0x00, 0x01, 0x02, 0x03 };
+static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 };
+
+/* Flags */
+#define TMP421_CONFIG_SHUTDOWN 0x40
+#define TMP421_CONFIG_RANGE 0x04
+
+/* Manufacturer / Device ID's */
+#define TMP421_MANUFACTURER_ID 0x55
+#define TMP421_DEVICE_ID 0x21
+#define TMP422_DEVICE_ID 0x22
+#define TMP423_DEVICE_ID 0x23
+
+static const struct i2c_device_id tmp421_id[] = {
+ { "tmp421", tmp421 },
+ { "tmp422", tmp422 },
+ { "tmp423", tmp423 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp421_id);
+
+struct tmp421_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid;
+ unsigned long last_updated;
+ int kind;
+ u8 config;
+ s16 temp[4];
+};
+
+static int temp_from_s16(s16 reg)
+{
+ int temp = reg;
+
+ return (temp * 1000 + 128) / 256;
+}
+
+static int temp_from_u16(u16 reg)
+{
+ int temp = reg;
+
+ /* Add offset for extended temperature range. */
+ temp -= 64 * 256;
+
+ return (temp * 1000 + 128) / 256;
+}
+
+static struct tmp421_data *tmp421_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tmp421_data *data = i2c_get_clientdata(client);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+ data->config = i2c_smbus_read_byte_data(client,
+ TMP421_CONFIG_REG_1);
+
+ for (i = 0; i <= data->kind; i++) {
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ TMP421_TEMP_MSB[i]) << 8;
+ data->temp[i] |= i2c_smbus_read_byte_data(client,
+ TMP421_TEMP_LSB[i]);
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static ssize_t show_temp_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct tmp421_data *data = tmp421_update_device(dev);
+ int temp;
+
+ mutex_lock(&data->update_lock);
+ if (data->config & TMP421_CONFIG_RANGE)
+ temp = temp_from_u16(data->temp[index]);
+ else
+ temp = temp_from_s16(data->temp[index]);
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct tmp421_data *data = tmp421_update_device(dev);
+
+ /*
+ * The OPEN bit signals a fault. This is bit 0 of the temperature
+ * register (low byte).
+ */
+ if (data->temp[index] & 0x01)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static mode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a,
+ int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct tmp421_data *data = dev_get_drvdata(dev);
+ struct device_attribute *devattr;
+ unsigned int index;
+
+ devattr = container_of(a, struct device_attribute, attr);
+ index = to_sensor_dev_attr(devattr)->index;
+
+ if (data->kind > index)
+ return a->mode;
+
+ return 0;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
+
+static struct attribute *tmp421_attr[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group tmp421_group = {
+ .attrs = tmp421_attr,
+ .is_visible = tmp421_is_visible,
+};
+
+static int tmp421_init_client(struct i2c_client *client)
+{
+ int config, config_orig;
+
+ /* Set the conversion rate to 2 Hz */
+ i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05);
+
+ /* Start conversions (disable shutdown if necessary) */
+ config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
+ if (config < 0) {
+ dev_err(&client->dev, "Could not read configuration"
+ " register (%d)\n", config);
+ return -ENODEV;
+ }
+
+ config_orig = config;
+ config &= ~TMP421_CONFIG_SHUTDOWN;
+
+ if (config != config_orig) {
+ dev_info(&client->dev, "Enable monitoring chip\n");
+ i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config);
+ }
+
+ return 0;
+}
+
+static int tmp421_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ const char *names[] = { "TMP421", "TMP422", "TMP423" };
+
+ 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;
+ }
+ }
+ 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);
+
+ return 0;
+}
+
+static int tmp421_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tmp421_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct tmp421_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+ data->kind = id->driver_data;
+
+ err = tmp421_init_client(client);
+ if (err)
+ goto exit_free;
+
+ err = sysfs_create_group(&client->dev.kobj, &tmp421_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ data->hwmon_dev = NULL;
+ goto exit_remove;
+ }
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &tmp421_group);
+
+exit_free:
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+
+ return err;
+}
+
+static int tmp421_remove(struct i2c_client *client)
+{
+ struct tmp421_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &tmp421_group);
+
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+
+ return 0;
+}
+
+static struct i2c_driver tmp421_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "tmp421",
+ },
+ .probe = tmp421_probe,
+ .remove = tmp421_remove,
+ .id_table = tmp421_id,
+ .detect = tmp421_detect,
+ .address_data = &addr_data,
+};
+
+static int __init tmp421_init(void)
+{
+ return i2c_add_driver(&tmp421_driver);
+}
+
+static void __exit tmp421_exit(void)
+{
+ i2c_del_driver(&tmp421_driver);
+}
+
+MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
+MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
+ " driver");
+MODULE_LICENSE("GPL");
+
+module_init(tmp421_init);
+module_exit(tmp421_exit);
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 73f77a9b8b18..30624f44a054 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -1136,7 +1136,7 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+ if (!request_region(res->start, resource_size(res), DRVNAME)) {
err = -EBUSY;
dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
(unsigned long)res->start, (unsigned long)res->end);
@@ -1209,7 +1209,7 @@ EXIT_DEV_REMOVE:
dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
EXIT_DEV_REMOVE_SILENT:
vt1211_remove_sysfs(pdev);
- release_region(res->start, res->end - res->start + 1);
+ release_region(res->start, resource_size(res));
EXIT_KFREE:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -1228,7 +1228,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, res->end - res->start + 1);
+ release_region(res->start, resource_size(res));
return 0;
}
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index fdd83277c8a8..d258b02aef44 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -672,9 +672,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
break;
}
+ err = 0;
+complete:
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
- err = 0;
if (stat & OMAP_I2C_STAT_NACK) {
err |= OMAP_I2C_STAT_NACK;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
@@ -685,16 +686,19 @@ omap_i2c_isr(int this_irq, void *dev_id)
err |= OMAP_I2C_STAT_AL;
}
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL))
+ OMAP_I2C_STAT_AL)) {
omap_i2c_complete_cmd(dev, err);
+ return IRQ_HANDLED;
+ }
if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
u8 num_bytes = 1;
if (dev->fifo_size) {
if (stat & OMAP_I2C_STAT_RRDY)
num_bytes = dev->fifo_size;
- else
- num_bytes = omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG);
+ else /* read RXSTAT on RDR interrupt */
+ num_bytes = (omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG)
+ >> 8) & 0x3F;
}
while (num_bytes) {
num_bytes--;
@@ -731,9 +735,10 @@ omap_i2c_isr(int this_irq, void *dev_id)
if (dev->fifo_size) {
if (stat & OMAP_I2C_STAT_XRDY)
num_bytes = dev->fifo_size;
- else
+ else /* read TXSTAT on XDR interrupt */
num_bytes = omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG);
+ OMAP_I2C_BUFSTAT_REG)
+ & 0x3F;
}
while (num_bytes) {
num_bytes--;
@@ -760,6 +765,27 @@ omap_i2c_isr(int this_irq, void *dev_id)
"data to send\n");
break;
}
+
+ /*
+ * OMAP3430 Errata 1.153: When an XRDY/XDR
+ * is hit, wait for XUDF before writing data
+ * to DATA_REG. Otherwise some data bytes can
+ * be lost while transferring them from the
+ * memory to the I2C interface.
+ */
+
+ if (cpu_is_omap34xx()) {
+ while (!(stat & OMAP_I2C_STAT_XUDF)) {
+ if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+ err |= OMAP_I2C_STAT_XUDF;
+ goto complete;
+ }
+ cpu_relax();
+ stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+ }
+
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
}
omap_i2c_ack_stat(dev,
@@ -879,7 +905,7 @@ omap_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON;
- strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
adap->algo = &omap_i2c_algo;
adap->dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 762e1e530882..049555777f67 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1134,35 +1134,44 @@ static int __exit i2c_pxa_remove(struct platform_device *dev)
}
#ifdef CONFIG_PM
-static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state)
+static int i2c_pxa_suspend_noirq(struct device *dev)
{
- struct pxa_i2c *i2c = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pxa_i2c *i2c = platform_get_drvdata(pdev);
+
clk_disable(i2c->clk);
+
return 0;
}
-static int i2c_pxa_resume_early(struct platform_device *dev)
+static int i2c_pxa_resume_noirq(struct device *dev)
{
- struct pxa_i2c *i2c = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pxa_i2c *i2c = platform_get_drvdata(pdev);
clk_enable(i2c->clk);
i2c_pxa_reset(i2c);
return 0;
}
+
+static struct dev_pm_ops i2c_pxa_dev_pm_ops = {
+ .suspend_noirq = i2c_pxa_suspend_noirq,
+ .resume_noirq = i2c_pxa_resume_noirq,
+};
+
+#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops)
#else
-#define i2c_pxa_suspend_late NULL
-#define i2c_pxa_resume_early NULL
+#define I2C_PXA_DEV_PM_OPS NULL
#endif
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
.remove = __exit_p(i2c_pxa_remove),
- .suspend_late = i2c_pxa_suspend_late,
- .resume_early = i2c_pxa_resume_early,
.driver = {
.name = "pxa2xx-i2c",
.owner = THIS_MODULE,
+ .pm = I2C_PXA_DEV_PM_OPS,
},
.id_table = i2c_pxa_id_table,
};
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 8f42a4536cdf..96aafb91b69a 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -763,11 +763,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
- /* check for s3c2440 i2c controller */
-
- if (s3c24xx_i2c_is2440(i2c))
- writel(0x0, i2c->regs + S3C2440_IICLC);
-
return 0;
}
@@ -951,17 +946,20 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int s3c24xx_i2c_suspend_late(struct platform_device *dev,
- pm_message_t msg)
+static int s3c24xx_i2c_suspend_noirq(struct device *dev)
{
- struct s3c24xx_i2c *i2c = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
i2c->suspended = 1;
+
return 0;
}
-static int s3c24xx_i2c_resume(struct platform_device *dev)
+static int s3c24xx_i2c_resume(struct device *dev)
{
- struct s3c24xx_i2c *i2c = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 0;
s3c24xx_i2c_init(i2c);
@@ -969,9 +967,14 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)
return 0;
}
+static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+ .suspend_noirq = s3c24xx_i2c_suspend_noirq,
+ .resume = s3c24xx_i2c_resume,
+};
+
+#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
#else
-#define s3c24xx_i2c_suspend_late NULL
-#define s3c24xx_i2c_resume NULL
+#define S3C24XX_DEV_PM_OPS NULL
#endif
/* device driver for platform bus bits */
@@ -990,12 +993,11 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
+ .pm = S3C24XX_DEV_PM_OPS,
},
};
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 4f3d99cd1692..820487d0d5c7 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -637,7 +637,7 @@ static void __exit sh_mobile_i2c_adap_exit(void)
platform_driver_unregister(&sh_mobile_i2c_driver);
}
-module_init(sh_mobile_i2c_adap_init);
+subsys_initcall(sh_mobile_i2c_adap_init);
module_exit(sh_mobile_i2c_adap_exit);
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
index 224aa12ee7c8..dd39c1eb03ed 100644
--- a/drivers/i2c/busses/i2c-taos-evm.c
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -32,10 +32,12 @@
#define TAOS_STATE_INIT 0
#define TAOS_STATE_IDLE 1
-#define TAOS_STATE_SEND 2
+#define TAOS_STATE_EOFF 2
#define TAOS_STATE_RECV 3
#define TAOS_CMD_RESET 0x12
+#define TAOS_CMD_ECHO_ON '+'
+#define TAOS_CMD_ECHO_OFF '-'
static DECLARE_WAIT_QUEUE_HEAD(wq);
@@ -102,17 +104,9 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
/* Send the transaction to the TAOS EVM */
dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
- taos->pos = 0;
- taos->state = TAOS_STATE_SEND;
- serio_write(serio, taos->buffer[0]);
- wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
- msecs_to_jiffies(250));
- if (taos->state != TAOS_STATE_IDLE) {
- dev_err(&adapter->dev, "Transaction failed "
- "(state=%d, pos=%d)\n", taos->state, taos->pos);
- taos->addr = 0;
- return -EIO;
- }
+ for (p = taos->buffer; *p; p++)
+ serio_write(serio, *p);
+
taos->addr = addr;
/* Start the transaction and read the answer */
@@ -122,7 +116,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
msecs_to_jiffies(150));
if (taos->state != TAOS_STATE_IDLE
- || taos->pos != 6) {
+ || taos->pos != 5) {
dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
taos->pos);
return -EIO;
@@ -130,7 +124,7 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
/* Interpret the returned string */
- p = taos->buffer + 2;
+ p = taos->buffer + 1;
p[3] = '\0';
if (!strcmp(p, "NAK"))
return -ENODEV;
@@ -173,13 +167,9 @@ static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
wake_up_interruptible(&wq);
}
break;
- case TAOS_STATE_SEND:
- if (taos->buffer[++taos->pos])
- serio_write(serio, taos->buffer[taos->pos]);
- else {
- taos->state = TAOS_STATE_IDLE;
- wake_up_interruptible(&wq);
- }
+ case TAOS_STATE_EOFF:
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
break;
case TAOS_STATE_RECV:
taos->buffer[taos->pos++] = data;
@@ -257,6 +247,19 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
}
strlcpy(adapter->name, name, sizeof(adapter->name));
+ /* Turn echo off for better performance */
+ taos->state = TAOS_STATE_EOFF;
+ serio_write(serio, TAOS_CMD_ECHO_OFF);
+
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(250));
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_err(&adapter->dev, "Echo off failed "
+ "(state=%d)\n", taos->state);
+ goto exit_close;
+ }
+
err = i2c_add_adapter(adapter);
if (err)
goto exit_close;
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
index 1a9cc135219f..aa96bd2d27ea 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/i2c/chips/tsl2550.c
@@ -24,10 +24,9 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#define TSL2550_DRV_NAME "tsl2550"
-#define DRIVER_VERSION "1.1.1"
+#define DRIVER_VERSION "1.2"
/*
* Defines
@@ -96,32 +95,13 @@ static int tsl2550_set_power_state(struct i2c_client *client, int state)
static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
{
- unsigned long end;
- int loop = 0, ret = 0;
+ int ret;
- /*
- * Read ADC channel waiting at most 400ms (see data sheet for further
- * info).
- * To avoid long busy wait we spin for few milliseconds then
- * start sleeping.
- */
- end = jiffies + msecs_to_jiffies(400);
- while (time_before(jiffies, end)) {
- i2c_smbus_write_byte(client, cmd);
-
- if (loop++ < 5)
- mdelay(1);
- else
- msleep(1);
-
- ret = i2c_smbus_read_byte(client);
- if (ret < 0)
- return ret;
- else if (ret & 0x0080)
- break;
- }
+ ret = i2c_smbus_read_byte_data(client, cmd);
+ if (ret < 0)
+ return ret;
if (!(ret & 0x80))
- return -EIO;
+ return -EAGAIN;
return ret & 0x7f; /* remove the "valid" bit */
}
@@ -189,13 +169,16 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
u8 r = 128;
/* Avoid division by 0 and count 1 cannot be greater than count 0 */
- if (c0 && (c1 <= c0))
- r = c1 * 128 / c0;
+ if (c1 <= c0)
+ if (c0) {
+ r = c1 * 128 / c0;
+
+ /* Calculate LUX */
+ lux = ((c0 - c1) * ratio_lut[r]) / 256;
+ } else
+ lux = 0;
else
- return -1;
-
- /* Calculate LUX */
- lux = ((c0 - c1) * ratio_lut[r]) / 256;
+ return -EAGAIN;
/* LUX range check */
return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
@@ -282,8 +265,6 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
return ret;
ch0 = ret;
- mdelay(1);
-
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
if (ret < 0)
return ret;
@@ -342,11 +323,10 @@ static int tsl2550_init_client(struct i2c_client *client)
* Probe the chip. To do so we try to power up the device and then to
* read back the 0x03 code
*/
- err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
+ err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
if (err < 0)
return err;
- mdelay(1);
- if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
+ if (err != TSL2550_POWER_UP)
return -ENODEV;
data->power_state = 1;
@@ -371,7 +351,8 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
struct tsl2550_data *data;
int *opmode, err = 0;
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+ | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
err = -EIO;
goto exit;
}
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index c509c9916464..c0cf45a11b93 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -114,8 +114,6 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
unsigned int bus, devnum, func;
acpi_integer addr;
acpi_handle dev_handle;
- struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
- .pointer = NULL};
acpi_status status;
struct acpi_device_info *dinfo = NULL;
int ret = -ENODEV;
@@ -134,12 +132,11 @@ static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
goto err;
}
- status = acpi_get_object_info(dev_handle, &buffer);
+ status = acpi_get_object_info(dev_handle, &dinfo);
if (ACPI_FAILURE(status)) {
DEBPRINT("get_object_info for device failed\n");
goto err;
}
- dinfo = buffer.pointer;
if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
dinfo->address == addr) {
*pcidevfn = addr;
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index da5f8829b503..0bc3d78ce7b1 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -2272,8 +2272,10 @@ static ssize_t raw1394_write(struct file *file, const char __user * buffer,
return -EFAULT;
}
- if (!mutex_trylock(&fi->state_mutex))
+ if (!mutex_trylock(&fi->state_mutex)) {
+ free_pending_request(req);
return -EAGAIN;
+ }
switch (fi->state) {
case opened:
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index 0384144c0b34..c94d2c24c352 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -26,11 +26,17 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
-#include <net/ieee802154/af_ieee802154.h>
-#include <net/ieee802154/netdevice.h>
-#include <net/ieee802154/mac_def.h>
-#include <net/ieee802154/nl802154.h>
-
+#include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/ieee802154.h>
+#include <net/nl802154.h>
+
+/**
+ * fake_get_pan_id - Retrieve the PAN ID of the device.
+ * @dev: The network device to retrieve the PAN of.
+ *
+ * Return the ID of the PAN from the PIB.
+ */
static u16 fake_get_pan_id(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -38,6 +44,14 @@ static u16 fake_get_pan_id(struct net_device *dev)
return 0xeba1;
}
+/**
+ * fake_get_short_addr - Retrieve the short address of the device.
+ * @dev: The network device to retrieve the short address of.
+ *
+ * Returns the IEEE 802.15.4 short-form address cached for this
+ * device. If the device has not yet had a short address assigned
+ * then this should return 0xFFFF to indicate a lack of association.
+ */
static u16 fake_get_short_addr(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -45,6 +59,19 @@ static u16 fake_get_short_addr(struct net_device *dev)
return 0x1;
}
+/**
+ * fake_get_dsn - Retrieve the DSN of the device.
+ * @dev: The network device to retrieve the DSN for.
+ *
+ * Returns the IEEE 802.15.4 DSN for the network device.
+ * The DSN is the sequence number which will be added to each
+ * packet or MAC command frame by the MAC during transmission.
+ *
+ * DSN means 'Data Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
static u8 fake_get_dsn(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -52,6 +79,19 @@ static u8 fake_get_dsn(struct net_device *dev)
return 0x00; /* DSN are implemented in HW, so return just 0 */
}
+/**
+ * fake_get_bsn - Retrieve the BSN of the device.
+ * @dev: The network device to retrieve the BSN for.
+ *
+ * Returns the IEEE 802.15.4 BSN for the network device.
+ * The BSN is the sequence number which will be added to each
+ * beacon frame sent by the MAC.
+ *
+ * BSN means 'Beacon Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
static u8 fake_get_bsn(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -59,6 +99,19 @@ static u8 fake_get_bsn(struct net_device *dev)
return 0x00; /* BSN are implemented in HW, so return just 0 */
}
+/**
+ * fake_assoc_req - Make an association request to the HW.
+ * @dev: The network device which we are associating to a network.
+ * @addr: The coordinator with which we wish to associate.
+ * @channel: The channel on which to associate.
+ * @cap: The capability information field to use in the association.
+ *
+ * Start an association with a coordinator. The coordinator's address
+ * and PAN ID can be found in @addr.
+ *
+ * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
static int fake_assoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 cap)
{
@@ -67,18 +120,70 @@ static int fake_assoc_req(struct net_device *dev,
IEEE802154_SUCCESS);
}
+/**
+ * fake_assoc_resp - Send an association response to a device.
+ * @dev: The network device on which to send the response.
+ * @addr: The address of the device to respond to.
+ * @short_addr: The assigned short address for the device (if any).
+ * @status: The result of the association request.
+ *
+ * Queue the association response of the coordinator to another
+ * device's attempt to associate with the network which we
+ * coordinate. This is then added to the indirect-send queue to be
+ * transmitted to the end device when it polls for data.
+ *
+ * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
static int fake_assoc_resp(struct net_device *dev,
struct ieee802154_addr *addr, u16 short_addr, u8 status)
{
return 0;
}
+/**
+ * fake_disassoc_req - Disassociate a device from a network.
+ * @dev: The network device on which we're disassociating a device.
+ * @addr: The device to disassociate from the network.
+ * @reason: The reason to give to the device for being disassociated.
+ *
+ * This sends a disassociation notification to the device being
+ * disassociated from the network.
+ *
+ * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
+ * document, with the reason described in 7.3.3.2.
+ */
static int fake_disassoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 reason)
{
return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
}
+/**
+ * fake_start_req - Start an IEEE 802.15.4 PAN.
+ * @dev: The network device on which to start the PAN.
+ * @addr: The coordinator address to use when starting the PAN.
+ * @channel: The channel on which to start the PAN.
+ * @bcn_ord: Beacon order.
+ * @sf_ord: Superframe order.
+ * @pan_coord: Whether or not we are the PAN coordinator or just
+ * requesting a realignment perhaps?
+ * @blx: Battery Life Extension feature bitfield.
+ * @coord_realign: Something to realign something else.
+ *
+ * If pan_coord is non-zero then this starts a network with the
+ * provided parameters, otherwise it attempts a coordinator
+ * realignment of the stated network instead.
+ *
+ * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
+ * document, with 7.3.8 describing coordinator realignment.
+ *
+ * Note: There is currently no way to notify the coordinator userland
+ * program of whether or not the PAN has started successfully. As
+ * such, the coordinator program cannot know when the MAC has
+ * completed starting the network and will simply have to assume
+ * completeness based on some form of time delay.
+ */
static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
u8 channel,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
@@ -87,6 +192,21 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
return 0;
}
+/**
+ * fake_scan_req - Start a channel scan.
+ * @dev: The network device on which to perform a channel scan.
+ * @type: The type of scan to perform.
+ * @channels: The channel bitmask to scan.
+ * @duration: How long to spend on each channel.
+ *
+ * This starts either a passive (energy) scan or an active (PAN) scan
+ * on the channels indicated in the @channels bitmask. The duration of
+ * the scan is measured in terms of superframe duration. Specifically,
+ * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
+ * channel.
+ *
+ * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
+ */
static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
u8 duration)
{
@@ -132,7 +252,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev)
/* FIXME: do hardware work here ... */
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index de922a04ca2d..5cef8f87b96b 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -51,8 +51,7 @@ static struct list_head ib_mad_port_list;
static u32 ib_mad_client_id = 0;
/* Port list lock */
-static spinlock_t ib_mad_port_list_lock;
-
+static DEFINE_SPINLOCK(ib_mad_port_list_lock);
/* Forward declarations */
static int method_in_use(struct ib_mad_mgmt_method_table **method,
@@ -2984,8 +2983,6 @@ static int __init ib_mad_init_module(void)
{
int ret;
- spin_lock_init(&ib_mad_port_list_lock);
-
ib_mad_cache = kmem_cache_create("ib_mad",
sizeof(struct ib_mad_private),
0,
@@ -3021,4 +3018,3 @@ static void __exit ib_mad_cleanup_module(void)
module_init(ib_mad_init_module);
module_exit(ib_mad_cleanup_module);
-
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 1865049e80f7..82543716d59e 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -109,10 +109,10 @@ static struct ib_client sa_client = {
.remove = ib_sa_remove_one
};
-static spinlock_t idr_lock;
+static DEFINE_SPINLOCK(idr_lock);
static DEFINE_IDR(query_idr);
-static spinlock_t tid_lock;
+static DEFINE_SPINLOCK(tid_lock);
static u32 tid;
#define PATH_REC_FIELD(field) \
@@ -1077,9 +1077,6 @@ static int __init ib_sa_init(void)
{
int ret;
- spin_lock_init(&idr_lock);
- spin_lock_init(&tid_lock);
-
get_random_bytes(&tid, sizeof tid);
ret = ib_register_client(&sa_client);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index eb36a81dd09b..1a3ac3d882b8 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -73,7 +73,7 @@ DEFINE_IDR(ib_uverbs_cq_idr);
DEFINE_IDR(ib_uverbs_qp_idr);
DEFINE_IDR(ib_uverbs_srq_idr);
-static spinlock_t map_lock;
+static DEFINE_SPINLOCK(map_lock);
static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES];
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -836,8 +836,6 @@ static int __init ib_uverbs_init(void)
{
int ret;
- spin_lock_init(&map_lock);
-
ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES,
"infiniband_verbs");
if (ret) {
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index fab18a2c74a8..5b635aa5947e 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,7 @@
#include "ehca_tools.h"
#include "hcp_if.h"
-#define HCAD_VERSION "0028"
+#define HCAD_VERSION "0029"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
@@ -64,7 +64,7 @@ static int ehca_hw_level = 0;
static int ehca_poll_all_eqs = 1;
int ehca_debug_level = 0;
-int ehca_nr_ports = 2;
+int ehca_nr_ports = -1;
int ehca_use_hp_mr = 0;
int ehca_port_act_time = 30;
int ehca_static_rate = -1;
@@ -95,8 +95,8 @@ MODULE_PARM_DESC(hw_level,
"Hardware level (0: autosensing (default), "
"0x10..0x14: eHCA, 0x20..0x23: eHCA2)");
MODULE_PARM_DESC(nr_ports,
- "number of connected ports (-1: autodetect, 1: port one only, "
- "2: two ports (default)");
+ "number of connected ports (-1: autodetect (default), "
+ "1: port one only, 2: two ports)");
MODULE_PARM_DESC(use_hp_mr,
"Use high performance MRs (default: no)");
MODULE_PARM_DESC(port_act_time,
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 02831ad070b8..4bd39c8af80f 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -809,7 +809,7 @@ static int ipath_setup_ht_reset(struct ipath_devdata *dd)
* errors. We only bother to do this at load time, because it's OK if
* it happened before we were loaded (first time after boot/reset),
* but any time after that, it's fatal anyway. Also need to not check
- * for for upper byte errors if we are in 8 bit mode, so figure out
+ * for upper byte errors if we are in 8 bit mode, so figure out
* our width. For now, at least, also complain if it's 8 bit.
*/
static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev,
diff --git a/drivers/infiniband/hw/mthca/mthca_config_reg.h b/drivers/infiniband/hw/mthca/mthca_config_reg.h
index 75671f75cac4..155bc66395be 100644
--- a/drivers/infiniband/hw/mthca/mthca_config_reg.h
+++ b/drivers/infiniband/hw/mthca/mthca_config_reg.h
@@ -34,8 +34,6 @@
#ifndef MTHCA_CONFIG_REG_H
#define MTHCA_CONFIG_REG_H
-#include <asm/page.h>
-
#define MTHCA_HCR_BASE 0x80680
#define MTHCA_HCR_SIZE 0x0001c
#define MTHCA_ECR_BASE 0x80700
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c
index acb6817f6060..2a13a163d337 100644
--- a/drivers/infiniband/hw/mthca/mthca_reset.c
+++ b/drivers/infiniband/hw/mthca/mthca_reset.c
@@ -30,7 +30,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 753a983a5fdc..ddb5cd717db9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -79,7 +79,6 @@ enum {
IPOIB_NUM_WC = 4,
IPOIB_MAX_PATH_REC_QUEUE = 3,
- IPOIB_MAX_MCAST_QUEUE = 3,
IPOIB_FLAG_OPER_UP = 0,
IPOIB_FLAG_INITIALIZED = 1,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 181b1f32325f..8f4b4fca2a1d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -31,7 +31,6 @@
*/
#include <rdma/ib_cm.h>
-#include <rdma/ib_cache.h>
#include <net/dst.h>
#include <net/icmp.h>
#include <linux/icmpv6.h>
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index e7e5adf84e84..e35f4a0ea9d5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
-#include <rdma/ib_cache.h>
#include <linux/ip.h>
#include <linux/tcp.h>
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index a0e97532e714..a98c86e265c7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -685,12 +685,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
}
if (!mcast->ah) {
- if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
- skb_queue_tail(&mcast->pkt_queue, skb);
- else {
- ++dev->stats.tx_dropped;
- dev_kfree_skb_any(skb);
- }
+ skb_queue_tail(&mcast->pkt_queue, skb);
if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_dbg_mcast(priv, "no address vector, "
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 95fe0452dae4..cf45d2a7751a 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -227,7 +227,7 @@ struct atkbd {
};
/*
- * System-specific ketymap fixup routine
+ * System-specific keymap fixup routine
*/
static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
static void *atkbd_platform_fixup_data;
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index d427f322e207..fe376a27fe57 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
int i, error;
if (!pdata->rows || !pdata->cols || !pdata->keymap) {
- printk(KERN_ERR DRV_NAME
- ": No rows, cols or keymap from pdata\n");
+ dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n");
return -EINVAL;
}
if (!pdata->keymapsize ||
pdata->keymapsize > (pdata->rows * pdata->cols)) {
- printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
+ dev_err(&pdev->dev, "invalid keymapsize\n");
return -EINVAL;
}
@@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
!pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
- printk(KERN_WARNING DRV_NAME
- ": Invalid Debounce/Columndrive Time in platform data\n");
+ dev_warn(&pdev->dev,
+ "invalid platform debounce/columndrive time\n");
bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
} else {
bfin_write_KPAD_MSEL(
@@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
+ dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out0;
}
if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
+ dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out1;
}
@@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
0, DRV_NAME, pdev);
if (error) {
- printk(KERN_ERR DRV_NAME
- ": unable to claim irq %d; error %d\n",
- bf54x_kpad->irq, error);
+ dev_err(&pdev->dev, "unable to claim irq %d\n",
+ bf54x_kpad->irq);
goto out2;
}
@@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error) {
- printk(KERN_ERR DRV_NAME
- ": Unable to register input device (%d)\n", error);
+ dev_err(&pdev->dev, "unable to register input device\n");
goto out4;
}
@@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- printk(KERN_ERR DRV_NAME
- ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
-
return 0;
out4:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index efed0c9e242e..a88aff3816a0 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
-static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
+static int gpio_keys_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int gpio_keys_resume(struct platform_device *pdev)
+static int gpio_keys_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define gpio_keys_suspend NULL
-#define gpio_keys_resume NULL
+
+static const struct dev_pm_ops gpio_keys_pm_ops = {
+ .suspend = gpio_keys_suspend,
+ .resume = gpio_keys_resume,
+};
#endif
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
- .suspend = gpio_keys_suspend,
- .resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_keys_pm_ops,
+#endif
}
};
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 0d2fc64a5e1c..c987cc75674c 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -25,6 +25,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/input/matrix_keypad.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -107,7 +108,7 @@ struct pxa27x_keypad {
int irq;
/* matrix key code map */
- unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
+ unsigned short matrix_keycodes[MAX_MATRIX_KEY_NUM];
/* state row bits of each column scan */
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
@@ -124,21 +125,21 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
- unsigned int *key;
int i;
- key = &pdata->matrix_key_map[0];
- for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
- int row = ((*key) >> 28) & 0xf;
- int col = ((*key) >> 24) & 0xf;
- int code = (*key) & 0xffffff;
+ for (i = 0; i < pdata->matrix_key_map_size; i++) {
+ unsigned int key = pdata->matrix_key_map[i];
+ unsigned int row = KEY_ROW(key);
+ unsigned int col = KEY_COL(key);
+ unsigned short code = KEY_VAL(key);
keypad->matrix_keycodes[(row << 3) + col] = code;
- set_bit(code, input_dev->keybit);
+ __set_bit(code, input_dev->keybit);
}
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
for (i = 0; i < pdata->direct_key_num; i++)
- set_bit(pdata->direct_key_map[i], input_dev->keybit);
+ __set_bit(pdata->direct_key_map[i], input_dev->keybit);
keypad->rotary_up_key[0] = pdata->rotary0_up_key;
keypad->rotary_up_key[1] = pdata->rotary1_up_key;
@@ -149,18 +150,18 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
if (pdata->enable_rotary0) {
if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
- set_bit(pdata->rotary0_up_key, input_dev->keybit);
- set_bit(pdata->rotary0_down_key, input_dev->keybit);
+ __set_bit(pdata->rotary0_up_key, input_dev->keybit);
+ __set_bit(pdata->rotary0_down_key, input_dev->keybit);
} else
- set_bit(pdata->rotary0_rel_code, input_dev->relbit);
+ __set_bit(pdata->rotary0_rel_code, input_dev->relbit);
}
if (pdata->enable_rotary1) {
if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
- set_bit(pdata->rotary1_up_key, input_dev->keybit);
- set_bit(pdata->rotary1_down_key, input_dev->keybit);
+ __set_bit(pdata->rotary1_up_key, input_dev->keybit);
+ __set_bit(pdata->rotary1_down_key, input_dev->keybit);
} else
- set_bit(pdata->rotary1_rel_code, input_dev->relbit);
+ __set_bit(pdata->rotary1_rel_code, input_dev->relbit);
}
}
@@ -388,8 +389,9 @@ static void pxa27x_keypad_close(struct input_dev *dev)
}
#ifdef CONFIG_PM
-static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
+static int pxa27x_keypad_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
clk_disable(keypad->clk);
@@ -400,8 +402,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat
return 0;
}
-static int pxa27x_keypad_resume(struct platform_device *pdev)
+static int pxa27x_keypad_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
@@ -420,12 +423,12 @@ static int pxa27x_keypad_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define pxa27x_keypad_suspend NULL
-#define pxa27x_keypad_resume NULL
-#endif
-#define res_size(res) ((res)->end - (res)->start + 1)
+static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
+ .suspend = pxa27x_keypad_suspend,
+ .resume = pxa27x_keypad_resume,
+};
+#endif
static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
{
@@ -461,14 +464,14 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
goto failed_free;
}
- res = request_mem_region(res->start, res_size(res), pdev->name);
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
if (res == NULL) {
dev_err(&pdev->dev, "failed to request I/O memory\n");
error = -EBUSY;
goto failed_free;
}
- keypad->mmio_base = ioremap(res->start, res_size(res));
+ keypad->mmio_base = ioremap(res->start, resource_size(res));
if (keypad->mmio_base == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
error = -ENXIO;
@@ -540,7 +543,7 @@ failed_put_clk:
failed_free_io:
iounmap(keypad->mmio_base);
failed_free_mem:
- release_mem_region(res->start, res_size(res));
+ release_mem_region(res->start, resource_size(res));
failed_free:
kfree(keypad);
return error;
@@ -552,8 +555,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
struct resource *res;
free_irq(keypad->irq, pdev);
-
- clk_disable(keypad->clk);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
@@ -562,7 +563,7 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
iounmap(keypad->mmio_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res_size(res));
+ release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
kfree(keypad);
@@ -575,11 +576,12 @@ MODULE_ALIAS("platform:pxa27x-keypad");
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = __devexit_p(pxa27x_keypad_remove),
- .suspend = pxa27x_keypad_suspend,
- .resume = pxa27x_keypad_resume,
.driver = {
.name = "pxa27x-keypad",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pxa27x_keypad_pm_ops,
+#endif
},
};
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index cea70e6a1031..0714bf2c28fc 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -128,7 +128,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
struct resource *res;
struct input_dev *input;
char clk_name[8];
- int i, k;
+ int i;
int irq, error;
if (!pdev->dev.platform_data) {
@@ -195,17 +195,19 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0100;
+ input->keycode = pdata->keycodes;
+ input->keycodesize = sizeof(pdata->keycodes[0]);
+ input->keycodemax = ARRAY_SIZE(pdata->keycodes);
+
error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto err4;
}
- for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
- k = pdata->keycodes[i];
- if (k)
- input_set_capability(input, EV_KEY, k);
- }
+ for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
+ __set_bit(pdata->keycodes[i], input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
error = input_register_device(input);
if (error) {
@@ -221,7 +223,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
device_init_wakeup(&pdev->dev, 1);
+
return 0;
+
err5:
free_irq(irq, pdev);
err4:
@@ -252,6 +256,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
kfree(priv);
+
return 0;
}
@@ -267,11 +272,12 @@ static int sh_keysc_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
value |= 0x80;
enable_irq_wake(irq);
- }
- else
+ } else {
value &= ~0x80;
+ }
iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+
return 0;
}
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 1acfa3a05aad..cbe21bc96b52 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -269,4 +269,14 @@ config INPUT_DM355EVM
To compile this driver as a module, choose M here: the
module will be called dm355evm_keys.
+
+config INPUT_BFIN_ROTARY
+ tristate "Blackfin Rotary support"
+ depends on BF54x || BF52x
+ help
+ Say Y here if you want to use the Blackfin Rotary.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin-rotary.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 0d979fd4cd57..79c1e9a5ea31 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
+obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
new file mode 100644
index 000000000000..690f3fafa03b
--- /dev/null
+++ b/drivers/input/misc/bfin_rotary.c
@@ -0,0 +1,283 @@
+/*
+ * Rotary counter driver for Analog Devices Blackfin Processors
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+#include <asm/portmux.h>
+#include <asm/bfin_rotary.h>
+
+static const u16 per_cnt[] = {
+ P_CNT_CUD,
+ P_CNT_CDG,
+ P_CNT_CZM,
+ 0
+};
+
+struct bfin_rot {
+ struct input_dev *input;
+ int irq;
+ unsigned int up_key;
+ unsigned int down_key;
+ unsigned int button_key;
+ unsigned int rel_code;
+ unsigned short cnt_config;
+ unsigned short cnt_imask;
+ unsigned short cnt_debounce;
+};
+
+static void report_key_event(struct input_dev *input, int keycode)
+{
+ /* simulate a press-n-release */
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+}
+
+static void report_rotary_event(struct bfin_rot *rotary, int delta)
+{
+ struct input_dev *input = rotary->input;
+
+ if (rotary->up_key) {
+ report_key_event(input,
+ delta > 0 ? rotary->up_key : rotary->down_key);
+ } else {
+ input_report_rel(input, rotary->rel_code, delta);
+ input_sync(input);
+ }
+}
+
+static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct bfin_rot *rotary = platform_get_drvdata(pdev);
+ int delta;
+
+ switch (bfin_read_CNT_STATUS()) {
+
+ case ICII:
+ break;
+
+ case UCII:
+ case DCII:
+ delta = bfin_read_CNT_COUNTER();
+ if (delta)
+ report_rotary_event(rotary, delta);
+ break;
+
+ case CZMII:
+ report_key_event(rotary->input, rotary->button_key);
+ break;
+
+ default:
+ break;
+ }
+
+ bfin_write_CNT_COMMAND(W1LCNT_ZERO); /* Clear COUNTER */
+ bfin_write_CNT_STATUS(-1); /* Clear STATUS */
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit bfin_rotary_probe(struct platform_device *pdev)
+{
+ struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data;
+ struct bfin_rot *rotary;
+ struct input_dev *input;
+ int error;
+
+ /* Basic validation */
+ if ((pdata->rotary_up_key && !pdata->rotary_down_key) ||
+ (!pdata->rotary_up_key && pdata->rotary_down_key)) {
+ return -EINVAL;
+ }
+
+ error = peripheral_request_list(per_cnt, dev_name(&pdev->dev));
+ if (error) {
+ dev_err(&pdev->dev, "requesting peripherals failed\n");
+ return error;
+ }
+
+ rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!rotary || !input) {
+ error = -ENOMEM;
+ goto out1;
+ }
+
+ rotary->input = input;
+
+ rotary->up_key = pdata->rotary_up_key;
+ rotary->down_key = pdata->rotary_down_key;
+ rotary->button_key = pdata->rotary_button_key;
+ rotary->rel_code = pdata->rotary_rel_code;
+
+ error = rotary->irq = platform_get_irq(pdev, 0);
+ if (error < 0)
+ goto out1;
+
+ input->name = pdev->name;
+ input->phys = "bfin-rotary/input0";
+ input->dev.parent = &pdev->dev;
+
+ input_set_drvdata(input, rotary);
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ if (rotary->up_key) {
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(rotary->up_key, input->keybit);
+ __set_bit(rotary->down_key, input->keybit);
+ } else {
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(rotary->rel_code, input->relbit);
+ }
+
+ if (rotary->button_key) {
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(rotary->button_key, input->keybit);
+ }
+
+ error = request_irq(rotary->irq, bfin_rotary_isr,
+ 0, dev_name(&pdev->dev), pdev);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to claim irq %d; error %d\n",
+ rotary->irq, error);
+ goto out1;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device (%d)\n", error);
+ goto out2;
+ }
+
+ if (pdata->rotary_button_key)
+ bfin_write_CNT_IMASK(CZMIE);
+
+ if (pdata->mode & ROT_DEBE)
+ bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE);
+
+ if (pdata->mode)
+ bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
+ (pdata->mode & ~CNTE));
+
+ bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE);
+ bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE);
+
+ platform_set_drvdata(pdev, rotary);
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+
+out2:
+ free_irq(rotary->irq, pdev);
+out1:
+ input_free_device(input);
+ kfree(rotary);
+ peripheral_free_list(per_cnt);
+
+ return error;
+}
+
+static int __devexit bfin_rotary_remove(struct platform_device *pdev)
+{
+ struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+ bfin_write_CNT_CONFIG(0);
+ bfin_write_CNT_IMASK(0);
+
+ free_irq(rotary->irq, pdev);
+ input_unregister_device(rotary->input);
+ peripheral_free_list(per_cnt);
+
+ kfree(rotary);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_rotary_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+ rotary->cnt_config = bfin_read_CNT_CONFIG();
+ rotary->cnt_imask = bfin_read_CNT_IMASK();
+ rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE();
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(rotary->irq);
+
+ return 0;
+}
+
+static int bfin_rotary_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+ bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce);
+ bfin_write_CNT_IMASK(rotary->cnt_imask);
+ bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(rotary->irq);
+
+ if (rotary->cnt_config & CNTE)
+ bfin_write_CNT_CONFIG(rotary->cnt_config);
+
+ return 0;
+}
+
+static struct dev_pm_ops bfin_rotary_pm_ops = {
+ .suspend = bfin_rotary_suspend,
+ .resume = bfin_rotary_resume,
+};
+#endif
+
+static struct platform_driver bfin_rotary_device_driver = {
+ .probe = bfin_rotary_probe,
+ .remove = __devexit_p(bfin_rotary_remove),
+ .driver = {
+ .name = "bfin-rotary",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &bfin_rotary_pm_ops,
+#endif
+ },
+};
+
+static int __init bfin_rotary_init(void)
+{
+ return platform_driver_register(&bfin_rotary_device_driver);
+}
+module_init(bfin_rotary_init);
+
+static void __exit bfin_rotary_exit(void)
+{
+ platform_driver_unregister(&bfin_rotary_device_driver);
+}
+module_exit(bfin_rotary_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
+MODULE_ALIAS("platform:bfin-rotary");
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
index d114d3a9e1e9..ee73d7219c92 100644
--- a/drivers/input/misc/cobalt_btns.c
+++ b/drivers/input/misc/cobalt_btns.c
@@ -116,7 +116,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
}
bdev->poll_dev = poll_dev;
- bdev->reg = ioremap(res->start, res->end - res->start + 1);
+ bdev->reg = ioremap(res->start, resource_size(res));
dev_set_drvdata(&pdev->dev, bdev);
error = input_register_polled_device(poll_dev);
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c
index a63315ce4a6c..0918acae584a 100644
--- a/drivers/input/misc/dm355evm_keys.c
+++ b/drivers/input/misc/dm355evm_keys.c
@@ -23,30 +23,16 @@
* pressed, or its autorepeat kicks in, an event is sent. This driver
* read those events from the small (32 event) queue and reports them.
*
- * Because we communicate with the MSP430 using I2C, and all I2C calls
- * in Linux sleep, we need to cons up a kind of threaded IRQ handler
- * using a work_struct. The IRQ is active low, but we use it through
- * the GPIO controller so we can trigger on falling edges.
- *
* Note that physically there can only be one of these devices.
*
* This driver was tested with firmware revision A4.
*/
struct dm355evm_keys {
- struct work_struct work;
struct input_dev *input;
struct device *dev;
int irq;
};
-static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
-{
- struct dm355evm_keys *keys = _keys;
-
- schedule_work(&keys->work);
- return IRQ_HANDLED;
-}
-
/* These initial keycodes can be remapped by dm355evm_setkeycode(). */
static struct {
u16 event;
@@ -110,13 +96,12 @@ static struct {
{ 0x3169, KEY_PAUSE, },
};
-static void dm355evm_keys_work(struct work_struct *work)
+/* runs in an IRQ thread -- can (and will!) sleep */
+static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
{
- struct dm355evm_keys *keys;
+ struct dm355evm_keys *keys = _keys;
int status;
- keys = container_of(work, struct dm355evm_keys, work);
-
/* For simplicity we ignore INPUT_COUNT and just read
* events until we get the "queue empty" indicator.
* Reading INPUT_LOW decrements the count.
@@ -183,6 +168,19 @@ static void dm355evm_keys_work(struct work_struct *work)
input_report_key(keys->input, keycode, 0);
input_sync(keys->input);
}
+ return IRQ_HANDLED;
+}
+
+/*
+ * Because we communicate with the MSP430 using I2C, and all I2C calls
+ * in Linux sleep, we use a threaded IRQ handler. The IRQ itself is
+ * active low, but we go through the GPIO controller so we can trigger
+ * on falling edges and not worry about enabling/disabling the IRQ in
+ * the keypress handling path.
+ */
+static irqreturn_t dm355evm_keys_hardirq(int irq, void *_keys)
+{
+ return IRQ_WAKE_THREAD;
}
static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
@@ -233,7 +231,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
keys->dev = &pdev->dev;
keys->input = input;
- INIT_WORK(&keys->work, dm355evm_keys_work);
/* set up "threaded IRQ handler" */
status = platform_get_irq(pdev, 0);
@@ -260,9 +257,10 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
/* REVISIT: flush the event queue? */
- status = request_irq(keys->irq, dm355evm_keys_irq,
- IRQF_TRIGGER_FALLING,
- dev_name(&pdev->dev), keys);
+ status = request_threaded_irq(keys->irq,
+ dm355evm_keys_hardirq, dm355evm_keys_irq,
+ IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), keys);
if (status < 0)
goto fail1;
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
index 41fda8c67b1e..a6fb7a3dcc46 100644
--- a/drivers/input/serio/at32psif.c
+++ b/drivers/input/serio/at32psif.c
@@ -231,7 +231,7 @@ static int __init psif_probe(struct platform_device *pdev)
goto out_free_io;
}
- psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ psif->regs = ioremap(regs->start, resource_size(regs));
if (!psif->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 582245c497eb..9f5c0506242f 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -923,41 +923,27 @@ static void i8042_dritek_enable(void)
#ifdef CONFIG_PM
-static bool i8042_suspended;
-
/*
- * Here we try to restore the original BIOS settings. We only want to
- * do that once, when we really suspend, not when we taking memory
- * snapshot for swsusp (in this case we'll perform required cleanup
- * as part of shutdown process).
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
*/
-static int i8042_suspend(struct platform_device *dev, pm_message_t state)
+static int i8042_pm_reset(struct device *dev)
{
- if (!i8042_suspended && state.event == PM_EVENT_SUSPEND)
- i8042_controller_reset();
-
- i8042_suspended = state.event == PM_EVENT_SUSPEND ||
- state.event == PM_EVENT_FREEZE;
+ i8042_controller_reset();
return 0;
}
-
/*
- * Here we try to reset everything back to a state in which suspended
+ * Here we try to reset everything back to a state we had
+ * before suspending.
*/
-static int i8042_resume(struct platform_device *dev)
+static int i8042_pm_restore(struct device *dev)
{
int error;
-/*
- * Do not bother with restoring state if we haven't suspened yet
- */
- if (!i8042_suspended)
- return 0;
-
error = i8042_controller_check();
if (error)
return error;
@@ -1001,11 +987,18 @@ static int i8042_resume(struct platform_device *dev)
if (i8042_ports[I8042_KBD_PORT_NO].serio)
i8042_enable_kbd_port();
- i8042_suspended = false;
i8042_interrupt(0, NULL);
return 0;
}
+
+static const struct dev_pm_ops i8042_pm_ops = {
+ .suspend = i8042_pm_reset,
+ .resume = i8042_pm_restore,
+ .poweroff = i8042_pm_reset,
+ .restore = i8042_pm_restore,
+};
+
#endif /* CONFIG_PM */
/*
@@ -1251,14 +1244,13 @@ static struct platform_driver i8042_driver = {
.driver = {
.name = "i8042",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &i8042_pm_ops,
+#endif
},
.probe = i8042_probe,
.remove = __devexit_p(i8042_remove),
.shutdown = i8042_shutdown,
-#ifdef CONFIG_PM
- .suspend = i8042_suspend,
- .resume = i8042_resume,
-#endif
};
static int __init i8042_init(void)
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index d66f4944f2a0..0236f0d5fd91 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -931,15 +931,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_PM
-static int serio_suspend(struct device *dev, pm_message_t state)
+static int serio_suspend(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (!serio->suspended && state.event == PM_EVENT_SUSPEND)
- serio_cleanup(serio);
-
- serio->suspended = state.event == PM_EVENT_SUSPEND ||
- state.event == PM_EVENT_FREEZE;
+ serio_cleanup(serio);
return 0;
}
@@ -952,13 +948,17 @@ static int serio_resume(struct device *dev)
* Driver reconnect can take a while, so better let kseriod
* deal with it.
*/
- if (serio->suspended) {
- serio->suspended = false;
- serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
- }
+ serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
return 0;
}
+
+static const struct dev_pm_ops serio_pm_ops = {
+ .suspend = serio_suspend,
+ .resume = serio_resume,
+ .poweroff = serio_suspend,
+ .restore = serio_resume,
+};
#endif /* CONFIG_PM */
/* called from serio_driver->connect/disconnect methods under serio_mutex */
@@ -1015,8 +1015,7 @@ static struct bus_type serio_bus = {
.remove = serio_driver_remove,
.shutdown = serio_shutdown,
#ifdef CONFIG_PM
- .suspend = serio_suspend,
- .resume = serio_resume,
+ .pm = &serio_pm_ops,
#endif
};
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 72e2712c7e2a..87a1ae63bcc4 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL
be called atmel-wm97xx.
config TOUCHSCREEN_WM97XX_MAINSTONE
- tristate "WM97xx Mainstone accelerated touch"
+ tristate "WM97xx Mainstone/Palm accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
help
Say Y here for support for streaming mode with WM97xx touchscreens
- on Mainstone systems.
+ on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
If unsure, say N.
@@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- IRTOUCHSYSTEMS/UNITOP
- IdealTEK URTC1000
- GoTop Super_Q2/GogoPen/PenPower tablets
+ - JASTEC USB Touch Controller/DigiTech DTR-02U
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -468,6 +469,16 @@ config TOUCHSCREEN_USB_GOTOP
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
+config TOUCHSCREEN_USB_JASTEC
+ default y
+ bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_E2I
+ default y
+ bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
@@ -492,6 +503,7 @@ config TOUCHSCREEN_TSC2007
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
+ depends on HAVE_CLK
help
Say Y here if you have a W90P910 based touchscreen.
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
index 055969e8be13..9c7fce4d74d0 100644
--- a/drivers/input/touchscreen/atmel_tsadcc.c
+++ b/drivers/input/touchscreen/atmel_tsadcc.c
@@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
goto err_free_dev;
}
- if (!request_mem_region(res->start, res->end - res->start + 1,
+ if (!request_mem_region(res->start, resource_size(res),
"atmel tsadcc regs")) {
dev_err(&pdev->dev, "resources is unavailable.\n");
err = -EBUSY;
goto err_free_dev;
}
- tsc_base = ioremap(res->start, res->end - res->start + 1);
+ tsc_base = ioremap(res->start, resource_size(res));
if (!tsc_base) {
dev_err(&pdev->dev, "failed to map registers.\n");
err = -ENOMEM;
@@ -286,7 +286,7 @@ err_free_irq:
err_unmap_regs:
iounmap(tsc_base);
err_release_mem:
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
err_free_dev:
input_free_device(ts_dev->input);
err_free_mem:
@@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap(tsc_base);
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
clk_disable(ts_dev->clk);
clk_put(ts_dev->clk);
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index 4cc047a5116e..8fc3b08deb3b 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -31,9 +31,11 @@
#include <linux/interrupt.h>
#include <linux/wm97xx.h>
#include <linux/io.h>
+#include <linux/gpio.h>
+
#include <mach/regs-ac97.h>
-#define VERSION "0.13"
+#include <asm/mach-types.h>
struct continuous {
u16 id; /* codec id */
@@ -62,6 +64,7 @@ static const struct continuous cinfo[] = {
/* continuous speed index */
static int sp_idx;
static u16 last, tries;
+static int irq;
/*
* Pen sampling frequency (Hz) in continuous mode.
@@ -171,7 +174,7 @@ up:
static int wm97xx_acc_startup(struct wm97xx *wm)
{
- int idx = 0;
+ int idx = 0, ret = 0;
/* check we have a codec */
if (wm->ac97 == NULL)
@@ -191,18 +194,40 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
"mainstone accelerated touchscreen driver, %d samples/sec\n",
cinfo[sp_idx].speed);
+ /* IRQ driven touchscreen is used on Palm hardware */
+ if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
+ pen_int = 1;
+ irq = 27;
+ /* There is some obscure mutant of WM9712 interbred with WM9713
+ * used on Palm HW */
+ wm->variant = WM97xx_WM1613;
+ } else if (machine_is_mainstone() && pen_int)
+ irq = 4;
+
+ if (irq) {
+ ret = gpio_request(irq, "Touchscreen IRQ");
+ if (ret)
+ goto out;
+
+ ret = gpio_direction_input(irq);
+ if (ret) {
+ gpio_free(irq);
+ goto out;
+ }
+
+ wm->pen_irq = gpio_to_irq(irq);
+ set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
+ } else /* pen irq not supported */
+ pen_int = 0;
+
/* codec specific irq config */
if (pen_int) {
switch (wm->id) {
case WM9705_ID2:
- wm->pen_irq = IRQ_GPIO(4);
- set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH);
break;
case WM9712_ID2:
case WM9713_ID2:
- /* enable pen down interrupt */
/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
- wm->pen_irq = MAINSTONE_AC97_IRQ;
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_STICKY,
@@ -220,23 +245,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
}
}
- return 0;
+out:
+ return ret;
}
static void wm97xx_acc_shutdown(struct wm97xx *wm)
{
/* codec specific deconfig */
if (pen_int) {
- switch (wm->id & 0xffff) {
- case WM9705_ID2:
- wm->pen_irq = 0;
- break;
- case WM9712_ID2:
- case WM9713_ID2:
- /* disable interrupt */
- wm->pen_irq = 0;
- break;
- }
+ if (irq)
+ gpio_free(irq);
+ wm->pen_irq = 0;
}
}
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 880f58c6a7c4..f710af4d0ff7 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -21,15 +21,14 @@
*/
#include <linux/module.h>
-#include <linux/hrtimer.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
-#define TS_POLL_DELAY (10 * 1000) /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000) /* ns delay between samples */
+#define TS_POLL_DELAY 1 /* ms delay between samples */
+#define TS_POLL_PERIOD 1 /* ms delay between samples */
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -70,17 +69,15 @@ struct ts_event {
struct tsc2007 {
struct input_dev *input;
char phys[32];
- struct hrtimer timer;
+ struct delayed_work work;
struct ts_event tc;
struct i2c_client *client;
- spinlock_t lock;
-
u16 model;
u16 x_plate_ohms;
- unsigned pendown;
+ bool pendown;
int irq;
int (*get_pendown_state)(void);
@@ -135,25 +132,24 @@ static void tsc2007_send_event(void *tsc)
} else
rt = 0;
- /* Sample found inconsistent by debouncing or pressure is beyond
+ /*
+ * Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
if (rt > MAX_12BIT) {
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
-
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
return;
}
- /* NOTE: We can't rely on the pressure to determine the pen down
+ /*
+ * NOTE: We can't rely on the pressure to determine the pen down
* state, even this controller has a pressure sensor. The pressure
* value can fluctuate for quite a while after lifting the pen and
* in some cases may not even settle at the expected value.
*
* The only safe way to check for the pen up condition is in the
- * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
+ * work function by reading the pen signal state (it's a GPIO and IRQ).
*/
if (rt) {
struct input_dev *input = ts->input;
@@ -162,7 +158,7 @@ static void tsc2007_send_event(void *tsc)
dev_dbg(&ts->client->dev, "DOWN\n");
input_report_key(input, BTN_TOUCH, 1);
- ts->pendown = 1;
+ ts->pendown = true;
}
input_report_abs(input, ABS_X, x);
@@ -174,9 +170,6 @@ static void tsc2007_send_event(void *tsc)
dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
x, y, rt);
}
-
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
}
static int tsc2007_read_values(struct tsc2007 *tsc)
@@ -191,18 +184,16 @@ static int tsc2007_read_values(struct tsc2007 *tsc)
tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
- /* power down */
+ /* Prepare for next touch reading - power down ADC, enable PENIRQ */
tsc2007_xfer(tsc, PWRDOWN);
return 0;
}
-static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
+static void tsc2007_work(struct work_struct *work)
{
- struct tsc2007 *ts = container_of(handle, struct tsc2007, timer);
- unsigned long flags;
-
- spin_lock_irqsave(&ts->lock, flags);
+ struct tsc2007 *ts =
+ container_of(to_delayed_work(work), struct tsc2007, work);
if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
struct input_dev *input = ts->input;
@@ -213,7 +204,7 @@ static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
- ts->pendown = 0;
+ ts->pendown = false;
enable_irq(ts->irq);
} else {
/* pen is still down, continue with the measurement */
@@ -221,36 +212,43 @@ static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
tsc2007_read_values(ts);
tsc2007_send_event(ts);
- }
-
- spin_unlock_irqrestore(&ts->lock, flags);
- return HRTIMER_NORESTART;
+ schedule_delayed_work(&ts->work,
+ msecs_to_jiffies(TS_POLL_PERIOD));
+ }
}
static irqreturn_t tsc2007_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;
- unsigned long flags;
-
- spin_lock_irqsave(&ts->lock, flags);
if (likely(ts->get_pendown_state())) {
disable_irq_nosync(ts->irq);
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_MODE_REL);
+ schedule_delayed_work(&ts->work,
+ msecs_to_jiffies(TS_POLL_DELAY));
}
if (ts->clear_penirq)
ts->clear_penirq();
- spin_unlock_irqrestore(&ts->lock, flags);
-
return IRQ_HANDLED;
}
-static int tsc2007_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static void tsc2007_free_irq(struct tsc2007 *ts)
+{
+ free_irq(ts->irq, ts);
+ if (cancel_delayed_work_sync(&ts->work)) {
+ /*
+ * Work was pending, therefore we need to enable
+ * IRQ here to balance the disable_irq() done in the
+ * interrupt handler.
+ */
+ enable_irq(ts->irq);
+ }
+}
+
+static int __devinit tsc2007_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tsc2007 *ts;
struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
@@ -274,22 +272,15 @@ static int tsc2007_probe(struct i2c_client *client,
}
ts->client = client;
- i2c_set_clientdata(client, ts);
-
+ ts->irq = client->irq;
ts->input = input_dev;
-
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ts->timer.function = tsc2007_timer;
-
- spin_lock_init(&ts->lock);
+ INIT_DELAYED_WORK(&ts->work, tsc2007_work);
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
- pdata->init_platform_hw();
-
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@@ -304,9 +295,8 @@ static int tsc2007_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
- tsc2007_read_values(ts);
-
- ts->irq = client->irq;
+ if (pdata->init_platform_hw)
+ pdata->init_platform_hw();
err = request_irq(ts->irq, tsc2007_irq, 0,
client->dev.driver->name, ts);
@@ -319,29 +309,33 @@ static int tsc2007_probe(struct i2c_client *client,
if (err)
goto err_free_irq;
- dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
+ i2c_set_clientdata(client, ts);
+
+ /* Prepare for touch readings - power down ADC and enable PENIRQ */
+ tsc2007_xfer(ts, PWRDOWN);
return 0;
err_free_irq:
- free_irq(ts->irq, ts);
- hrtimer_cancel(&ts->timer);
+ tsc2007_free_irq(ts);
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return err;
}
-static int tsc2007_remove(struct i2c_client *client)
+static int __devexit tsc2007_remove(struct i2c_client *client)
{
struct tsc2007 *ts = i2c_get_clientdata(client);
- struct tsc2007_platform_data *pdata;
+ struct tsc2007_platform_data *pdata = client->dev.platform_data;
- pdata = client->dev.platform_data;
- pdata->exit_platform_hw();
+ tsc2007_free_irq(ts);
+
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
- free_irq(ts->irq, ts);
- hrtimer_cancel(&ts->timer);
input_unregister_device(ts->input);
kfree(ts);
@@ -362,7 +356,7 @@ static struct i2c_driver tsc2007_driver = {
},
.id_table = tsc2007_idtable,
.probe = tsc2007_probe,
- .remove = tsc2007_remove,
+ .remove = __devexit_p(tsc2007_remove),
};
static int __init tsc2007_init(void)
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 6954f5500108..e85483578bd4 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -128,9 +128,10 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
return ucb1400_adc_read(ucb->ac97, 0, adcsync);
}
-static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97)
+static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
{
unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
+
return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
}
@@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb)
msleep(10);
- if (ucb1400_ts_pen_down(ucb->ac97)) {
+ if (ucb1400_ts_pen_up(ucb->ac97)) {
ucb1400_ts_irq_enable(ucb->ac97);
/*
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index fb7cb9bdfbd5..68ece5801a58 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -13,6 +13,7 @@
* - IdealTEK URTC1000
* - General Touch
* - GoTop Super_Q2/GogoPen/PenPower tablets
+ * - JASTEC USB touch controller/DigiTech DTR-02U
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -118,6 +119,8 @@ enum {
DEVTYPE_IDEALTEK,
DEVTYPE_GENERAL_TOUCH,
DEVTYPE_GOTOP,
+ DEVTYPE_JASTEC,
+ DEVTYPE_E2I,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -191,11 +194,51 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+ {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+ {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
+#endif
{}
};
/*****************************************************************************
+ * e2i Part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+static int e2i_init(struct usbtouch_usb *usbtouch)
+{
+ int ret;
+
+ ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ 0x01, 0x02, 0x0000, 0x0081,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+ dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
+ __func__, ret);
+ return ret;
+}
+
+static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ int tmp = (pkt[0] << 8) | pkt[1];
+ dev->x = (pkt[2] << 8) | pkt[3];
+ dev->y = (pkt[4] << 8) | pkt[5];
+
+ tmp = tmp - 0xA000;
+ dev->touch = (tmp > 0);
+ dev->press = (tmp > 0 ? tmp : 0);
+
+ return 1;
+}
+#endif
+
+
+/*****************************************************************************
* eGalax part
*/
@@ -559,6 +602,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
dev->touch = pkt[0] & 0x01;
+
+ return 1;
+}
+#endif
+
+/*****************************************************************************
+ * JASTEC Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
+ dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
+ dev->touch = (pkt[0] & 0x40) >> 6;
+
return 1;
}
#endif
@@ -702,6 +760,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = gotop_read_data,
},
#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+ [DEVTYPE_JASTEC] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = jastec_read_data,
+ },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+ [DEVTYPE_E2I] = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 6,
+ .init = e2i_init,
+ .read_data = e2i_read_data,
+ },
+#endif
};
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c
index 6071f5882572..dc4c9d6b67c7 100644
--- a/drivers/input/touchscreen/w90p910_ts.c
+++ b/drivers/input/touchscreen/w90p910_ts.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -47,8 +48,8 @@ enum ts_state {
struct w90p910_ts {
struct input_dev *input;
struct timer_list timer;
+ struct clk *clk;
int irq_num;
- void __iomem *clocken;
void __iomem *ts_reg;
spinlock_t lock;
enum ts_state state;
@@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev)
unsigned long val;
/* enable the ADC clock */
- val = __raw_readl(w90p910_ts->clocken);
- __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
+ clk_enable(w90p910_ts->clk);
__raw_writel(ADC_RST1, w90p910_ts->ts_reg);
msleep(1);
@@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev)
del_timer_sync(&w90p910_ts->timer);
/* stop the ADC clock */
- val = __raw_readl(w90p910_ts->clocken);
- __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
+ clk_disable(w90p910_ts->clk);
}
static int __devinit w90x900ts_probe(struct platform_device *pdev)
@@ -241,26 +240,24 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
goto fail1;
}
- if (!request_mem_region(res->start, res->end - res->start + 1,
+ if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
err = -EBUSY;
goto fail1;
}
- w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
+ w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
if (!w90p910_ts->ts_reg) {
err = -ENOMEM;
goto fail2;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- err = -ENXIO;
+ w90p910_ts->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(w90p910_ts->clk)) {
+ err = PTR_ERR(w90p910_ts->clk);
goto fail3;
}
- w90p910_ts->clocken = (void __iomem *)res->start;
-
input_dev->name = "W90P910 TouchScreen";
input_dev->phys = "w90p910ts/event0";
input_dev->id.bustype = BUS_HOST;
@@ -283,20 +280,21 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
err = -EBUSY;
- goto fail3;
+ goto fail4;
}
err = input_register_device(w90p910_ts->input);
if (err)
- goto fail4;
+ goto fail5;
platform_set_drvdata(pdev, w90p910_ts);
return 0;
-fail4: free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail5: free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail4: clk_put(w90p910_ts->clk);
fail3: iounmap(w90p910_ts->ts_reg);
-fail2: release_mem_region(res->start, res->end - res->start + 1);
+fail2: release_mem_region(res->start, resource_size(res));
fail1: input_free_device(input_dev);
kfree(w90p910_ts);
return err;
@@ -311,8 +309,10 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev)
del_timer_sync(&w90p910_ts->timer);
iounmap(w90p910_ts->ts_reg);
+ clk_put(w90p910_ts->clk);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
input_unregister_device(w90p910_ts->input);
kfree(w90p910_ts);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 2957d48e0045..252eb11fe9db 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
else
reg &= ~gpio;
- if (wm->id == WM9712_ID2)
+ if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
else
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
@@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work)
WM97XX_GPIO_13);
}
- if (wm->id == WM9712_ID2)
+ if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
~WM97XX_GPIO_13) << 1);
else
@@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev)
wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
+ wm->variant = WM97xx_GENERIC;
+
dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
switch (wm->id & 0xff) {
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 02bdca6f95c3..022a19452953 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,8 +21,6 @@ menuconfig ISDN
if ISDN
-source "drivers/isdn/mISDN/Kconfig"
-
menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
---help---
@@ -41,9 +39,9 @@ menuconfig ISDN_I4L
It is still available, though, for use with adapters that are not
supported by the new CAPI subsystem yet.
-if ISDN_I4L
+source "drivers/isdn/mISDN/Kconfig"
+
source "drivers/isdn/i4l/Kconfig"
-endif
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
index 946c38cf6f8a..1f0a94906465 100644
--- a/drivers/isdn/act2000/capi.c
+++ b/drivers/isdn/act2000/capi.c
@@ -78,7 +78,6 @@ static actcapi_msgdsc valid_msg[] = {
#endif
{{ 0x00, 0x00}, NULL},
};
-#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
#define num_valid_imsg 27 /* MANUFACTURER_IND */
/*
@@ -1025,7 +1024,7 @@ actcapi_debug_msg(struct sk_buff *skb, int direction)
#ifdef DEBUG_DUMP_SKB
dump_skb(skb);
#endif
- for (i = 0; i < num_valid_msg; i++)
+ for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
(msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
descr = valid_msg[i].description;
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index 8325022e2bed..f774e12bb64d 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -23,7 +23,6 @@ static unsigned short act2000_isa_ports[] =
0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
};
-#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
static act2000_card *cards = (act2000_card *) NULL;
@@ -686,21 +685,21 @@ act2000_addcard(int bus, int port, int irq, char *id)
* This may result in more than one card detected.
*/
switch (bus) {
- case ACT2000_BUS_ISA:
- for (i = 0; i < ISA_NRPORTS; i++)
- if (act2000_isa_detect(act2000_isa_ports[i])) {
- printk(KERN_INFO
- "act2000: Detected ISA card at port 0x%x\n",
- act2000_isa_ports[i]);
- act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
- }
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: addcard: Invalid BUS type %d\n",
- bus);
+ case ACT2000_BUS_ISA:
+ for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++)
+ if (act2000_isa_detect(act2000_isa_ports[i])) {
+ printk(KERN_INFO "act2000: Detected "
+ "ISA card at port 0x%x\n",
+ act2000_isa_ports[i]);
+ act2000_alloccard(bus,
+ act2000_isa_ports[i], irq, id);
+ }
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: addcard: Invalid BUS type %d\n", bus);
}
}
if (!cards)
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 31f91c18c698..27d5dd68f4fb 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -551,9 +551,7 @@ word api_put(APPL * appl, CAPI_MSG * msg)
dbug(1,dprintf("com=%x",msg->header.command));
for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
- for(i=0, ret = _BAD_MSG;
- i<(sizeof(ftable)/sizeof(struct _ftable));
- i++) {
+ for(i=0, ret = _BAD_MSG; i < ARRAY_SIZE(ftable); i++) {
if(ftable[i].command==msg->header.command) {
/* break loop if the message is correct, otherwise continue scan */
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
index c964b8d91ada..cb7616c5b60a 100644
--- a/drivers/isdn/hardware/eicon/os_4bri.c
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -149,8 +149,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a)
diva_os_xdi_adapter_t *diva_current;
diva_os_xdi_adapter_t *adapter_list[4];
PISDN_ADAPTER Slave;
- unsigned long bar_length[sizeof(_4bri_bar_length) /
- sizeof(_4bri_bar_length[0])];
+ unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)];
int v2 = _4bri_is_rev_2_card(a->CardOrdinal);
int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
int factor = (tasks == 1) ? 1 : 2;
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index 3024566dd099..bde55d7287fa 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -39,3 +39,54 @@ config MISDN_HFCUSB
Enable support for USB ISDN TAs with Cologne Chip AG's
HFC-S USB ISDN Controller
+config MISDN_AVMFRITZ
+ tristate "Support for AVM FRITZ!CARD PCI"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ help
+ Enable support for AVMs FRITZ!CARD PCI cards
+
+config MISDN_SPEEDFAX
+ tristate "Support for Sedlbauer Speedfax+"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ select MISDN_ISAR
+ help
+ Enable support for Sedlbauer Speedfax+.
+
+config MISDN_INFINEON
+ tristate "Support for cards with Infineon chipset"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ help
+ Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
+ chip from Infineon (former manufacturer Siemens).
+
+config MISDN_W6692
+ tristate "Support for cards with Winbond 6692"
+ depends on MISDN
+ depends on PCI
+ help
+ Enable support for Winbond 6692 PCI chip based cards.
+
+config MISDN_NETJET
+ tristate "Support for NETJet cards"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ select ISDN_HDLC
+ help
+ Enable support for Traverse Technologies NETJet PCI cards.
+
+
+config MISDN_IPAC
+ tristate
+ depends on MISDN
+
+config MISDN_ISAR
+ tristate
+ depends on MISDN
+
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index b0403526bbba..2987d990993f 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -6,3 +6,11 @@
obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
+obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
+obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
+obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
+obj-$(CONFIG_MISDN_W6692) += w6692.o
+obj-$(CONFIG_MISDN_NETJET) += netjet.o
+# chip modules
+obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
+obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
new file mode 100644
index 000000000000..81ac541d40d9
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -0,0 +1,1152 @@
+/*
+ * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards
+ * Thanks to AVM, Berlin for informations
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include <asm/unaligned.h>
+#include "ipac.h"
+
+
+#define AVMFRITZ_REV "2.1"
+
+static int AVM_cnt;
+static int debug;
+
+enum {
+ AVM_FRITZ_PCI,
+ AVM_FRITZ_PCIV2,
+};
+
+#define HDLC_FIFO 0x0
+#define HDLC_STATUS 0x4
+#define CHIP_WINDOW 0x10
+
+#define CHIP_INDEX 0x4
+#define AVM_HDLC_1 0x00
+#define AVM_HDLC_2 0x01
+#define AVM_ISAC_FIFO 0x02
+#define AVM_ISAC_REG_LOW 0x04
+#define AVM_ISAC_REG_HIGH 0x06
+
+#define AVM_STATUS0_IRQ_ISAC 0x01
+#define AVM_STATUS0_IRQ_HDLC 0x02
+#define AVM_STATUS0_IRQ_TIMER 0x04
+#define AVM_STATUS0_IRQ_MASK 0x07
+
+#define AVM_STATUS0_RESET 0x01
+#define AVM_STATUS0_DIS_TIMER 0x02
+#define AVM_STATUS0_RES_TIMER 0x04
+#define AVM_STATUS0_ENA_IRQ 0x08
+#define AVM_STATUS0_TESTBIT 0x10
+
+#define AVM_STATUS1_INT_SEL 0x0f
+#define AVM_STATUS1_ENA_IOM 0x80
+
+#define HDLC_MODE_ITF_FLG 0x01
+#define HDLC_MODE_TRANS 0x02
+#define HDLC_MODE_CCR_7 0x04
+#define HDLC_MODE_CCR_16 0x08
+#define HDLC_MODE_TESTLOOP 0x80
+
+#define HDLC_INT_XPR 0x80
+#define HDLC_INT_XDU 0x40
+#define HDLC_INT_RPR 0x20
+#define HDLC_INT_MASK 0xE0
+
+#define HDLC_STAT_RME 0x01
+#define HDLC_STAT_RDO 0x10
+#define HDLC_STAT_CRCVFRRAB 0x0E
+#define HDLC_STAT_CRCVFR 0x06
+#define HDLC_STAT_RML_MASK 0x3f00
+
+#define HDLC_CMD_XRS 0x80
+#define HDLC_CMD_XME 0x01
+#define HDLC_CMD_RRS 0x20
+#define HDLC_CMD_XML_MASK 0x3f00
+#define HDLC_FIFO_SIZE 32
+
+/* Fritz PCI v2.0 */
+
+#define AVM_HDLC_FIFO_1 0x10
+#define AVM_HDLC_FIFO_2 0x18
+
+#define AVM_HDLC_STATUS_1 0x14
+#define AVM_HDLC_STATUS_2 0x1c
+
+#define AVM_ISACX_INDEX 0x04
+#define AVM_ISACX_DATA 0x08
+
+/* data struct */
+#define LOG_SIZE 63
+
+struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+ u8 fill;
+ u8 mode;
+ u8 xml;
+ u8 cmd;
+#else
+ u8 cmd;
+ u8 xml;
+ u8 mode;
+ u8 fill;
+#endif
+} __attribute__((packed));
+
+struct hdlc_hw {
+ union {
+ u32 ctrl;
+ struct hdlc_stat_reg sr;
+ } ctrl;
+ u32 stat;
+};
+
+struct fritzcard {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u8 type;
+ u8 ctrlreg;
+ u16 irq;
+ u32 irqcnt;
+ u32 addr;
+ spinlock_t lock; /* hw lock */
+ struct isac_hw isac;
+ struct hdlc_hw hdlc[2];
+ struct bchannel bch[2];
+ char log[LOG_SIZE + 1];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct fritzcard *card)
+{
+ card->isac.dch.debug = debug;
+ card->bch[0].debug = debug;
+ card->bch[1].debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct fritzcard *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(AVMFRITZ_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "avmfritz debug mask");
+
+/* Interface functions */
+
+static u8
+ReadISAC_V1(void *p, u8 offset)
+{
+ struct fritzcard *fc = p;
+ u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+
+ outb(idx, fc->addr + CHIP_INDEX);
+ return inb(fc->addr + CHIP_WINDOW + (offset & 0xf));
+}
+
+static void
+WriteISAC_V1(void *p, u8 offset, u8 value)
+{
+ struct fritzcard *fc = p;
+ u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+
+ outb(idx, fc->addr + CHIP_INDEX);
+ outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf));
+}
+
+static void
+ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+
+ outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
+ insb(fc->addr + CHIP_WINDOW, data, size);
+}
+
+static void
+WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+
+ outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
+ outsb(fc->addr + CHIP_WINDOW, data, size);
+}
+
+static u8
+ReadISAC_V2(void *p, u8 offset)
+{
+ struct fritzcard *fc = p;
+
+ outl(offset, fc->addr + AVM_ISACX_INDEX);
+ return 0xff & inl(fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+WriteISAC_V2(void *p, u8 offset, u8 value)
+{
+ struct fritzcard *fc = p;
+
+ outl(offset, fc->addr + AVM_ISACX_INDEX);
+ outl(value, fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+ int i;
+
+ outl(off, fc->addr + AVM_ISACX_INDEX);
+ for (i = 0; i < size; i++)
+ data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+ int i;
+
+ outl(off, fc->addr + AVM_ISACX_INDEX);
+ for (i = 0; i < size; i++)
+ outl(data[i], fc->addr + AVM_ISACX_DATA);
+}
+
+static struct bchannel *
+Sel_BCS(struct fritzcard *fc, u32 channel)
+{
+ if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) &&
+ (fc->bch[0].nr & channel))
+ return &fc->bch[0];
+ else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) &&
+ (fc->bch[1].nr & channel))
+ return &fc->bch[1];
+ else
+ return NULL;
+}
+
+static inline void
+__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
+ u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1;
+
+ outl(idx, fc->addr + CHIP_INDEX);
+ outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline void
+__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
+ outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
+ AVM_HDLC_STATUS_1));
+}
+
+void
+write_ctrl(struct bchannel *bch, int which) {
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr,
+ which, hdlc->ctrl.ctrl);
+ switch (fc->type) {
+ case AVM_FRITZ_PCIV2:
+ __write_ctrl_pciv2(fc, hdlc, bch->nr);
+ break;
+ case AVM_FRITZ_PCI:
+ __write_ctrl_pci(fc, hdlc, bch->nr);
+ break;
+ }
+}
+
+
+static inline u32
+__read_status_pci(u_long addr, u32 channel)
+{
+ outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
+ return inl(addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline u32
+__read_status_pciv2(u_long addr, u32 channel)
+{
+ return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
+ AVM_HDLC_STATUS_1));
+}
+
+
+static u32
+read_status(struct fritzcard *fc, u32 channel)
+{
+ switch (fc->type) {
+ case AVM_FRITZ_PCIV2:
+ return __read_status_pciv2(fc->addr, channel);
+ case AVM_FRITZ_PCI:
+ return __read_status_pci(fc->addr, channel);
+ }
+ /* dummy */
+ return 0;
+}
+
+static void
+enable_hwirq(struct fritzcard *fc)
+{
+ fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
+ outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static void
+disable_hwirq(struct fritzcard *fc)
+{
+ fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ;
+ outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static int
+modehdlc(struct bchannel *bch, int protocol)
+{
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
+ '@' + bch->nr, bch->state, protocol, bch->nr);
+ hdlc->ctrl.ctrl = 0;
+ switch (protocol) {
+ case -1: /* used for init */
+ bch->state = -1;
+ case ISDN_P_NONE:
+ if (bch->state == ISDN_P_NONE)
+ break;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ write_ctrl(bch, 5);
+ bch->state = ISDN_P_NONE;
+ test_and_clear_bit(FLG_HDLC, &bch->Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case ISDN_P_B_RAW:
+ bch->state = protocol;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ write_ctrl(bch, 5);
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd = 0;
+ test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ bch->state = protocol;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+ write_ctrl(bch, 5);
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd = 0;
+ test_and_set_bit(FLG_HDLC, &bch->Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", fc->name, protocol);
+ return -ENOPROTOOPT;
+ }
+ return 0;
+}
+
+static void
+hdlc_empty_fifo(struct bchannel *bch, int count)
+{
+ u32 *ptr;
+ u8 *p;
+ u32 val, addr;
+ int cnt = 0;
+ struct fritzcard *fc = bch->hw;
+
+ pr_debug("%s: %s %d\n", fc->name, __func__, count);
+ if (!bch->rx_skb) {
+ bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
+ if (!bch->rx_skb) {
+ pr_info("%s: B receive out of memory\n",
+ fc->name);
+ return;
+ }
+ }
+ if ((bch->rx_skb->len + count) > bch->maxlen) {
+ pr_debug("%s: overrun %d\n", fc->name,
+ bch->rx_skb->len + count);
+ return;
+ }
+ p = skb_put(bch->rx_skb, count);
+ ptr = (u32 *)p;
+ if (AVM_FRITZ_PCIV2 == fc->type)
+ addr = fc->addr + (bch->nr == 2 ?
+ AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
+ else {
+ addr = fc->addr + CHIP_WINDOW;
+ outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
+ }
+ while (cnt < count) {
+ val = le32_to_cpu(inl(addr));
+ put_unaligned(val, ptr);
+ ptr++;
+ cnt += 4;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
+ bch->nr, fc->name, count);
+ print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hdlc_fill_fifo(struct bchannel *bch)
+{
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+ int count, cnt = 0;
+ u8 *p;
+ u32 *ptr, val, addr;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ if (!bch->tx_skb)
+ return;
+ count = bch->tx_skb->len - bch->tx_idx;
+ if (count <= 0)
+ return;
+ p = bch->tx_skb->data + bch->tx_idx;
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
+ if (count > HDLC_FIFO_SIZE) {
+ count = HDLC_FIFO_SIZE;
+ } else {
+ if (test_bit(FLG_HDLC, &bch->Flags))
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
+ }
+ pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
+ bch->tx_idx, bch->tx_skb->len);
+ ptr = (u32 *)p;
+ bch->tx_idx += count;
+ hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
+ if (AVM_FRITZ_PCIV2 == fc->type) {
+ __write_ctrl_pciv2(fc, hdlc, bch->nr);
+ addr = fc->addr + (bch->nr == 2 ?
+ AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
+ } else {
+ __write_ctrl_pci(fc, hdlc, bch->nr);
+ addr = fc->addr + CHIP_WINDOW;
+ }
+ while (cnt < count) {
+ val = get_unaligned(ptr);
+ outl(cpu_to_le32(val), addr);
+ ptr++;
+ cnt += 4;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ",
+ bch->nr, fc->name, count);
+ print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+HDLC_irq_xpr(struct bchannel *bch)
+{
+ if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
+ hdlc_fill_fifo(bch);
+ else {
+ if (bch->tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &bch->Flags))
+ confirm_Bsend(bch);
+ dev_kfree_skb(bch->tx_skb);
+ }
+ if (get_next_bframe(bch))
+ hdlc_fill_fifo(bch);
+ }
+}
+
+static void
+HDLC_irq(struct bchannel *bch, u32 stat)
+{
+ struct fritzcard *fc = bch->hw;
+ int len;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
+ if (stat & HDLC_INT_RPR) {
+ if (stat & HDLC_STAT_RDO) {
+ hdlc->ctrl.sr.xml = 0;
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+ write_ctrl(bch, 1);
+ if (bch->rx_skb)
+ skb_trim(bch->rx_skb, 0);
+ } else {
+ len = (stat & HDLC_STAT_RML_MASK) >> 8;
+ if (!len)
+ len = 32;
+ hdlc_empty_fifo(bch, len);
+ if (!bch->rx_skb)
+ goto handle_tx;
+ if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,
+ &bch->Flags)) {
+ if (((stat & HDLC_STAT_CRCVFRRAB) ==
+ HDLC_STAT_CRCVFR) ||
+ test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ recv_Bchannel(bch, 0);
+ } else {
+ pr_debug("%s: got invalid frame\n",
+ fc->name);
+ skb_trim(bch->rx_skb, 0);
+ }
+ }
+ }
+ }
+handle_tx:
+ if (stat & HDLC_INT_XDU) {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame on HDLC
+ * in transparent mode we send the next data
+ */
+ if (bch->tx_skb)
+ pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
+ fc->name, bch->nr, bch->tx_skb->len,
+ bch->tx_idx, bch->Flags);
+ else
+ pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
+ fc->name, bch->nr, bch->Flags);
+ if (bch->tx_skb && bch->tx_skb->len) {
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ bch->tx_idx = 0;
+ }
+ hdlc->ctrl.sr.xml = 0;
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+ HDLC_irq_xpr(bch);
+ return;
+ } else if (stat & HDLC_INT_XPR)
+ HDLC_irq_xpr(bch);
+}
+
+static inline void
+HDLC_irq_main(struct fritzcard *fc)
+{
+ u32 stat;
+ struct bchannel *bch;
+
+ stat = read_status(fc, 1);
+ if (stat & HDLC_INT_MASK) {
+ bch = Sel_BCS(fc, 1);
+ if (bch)
+ HDLC_irq(bch, stat);
+ else
+ pr_debug("%s: spurious ch1 IRQ\n", fc->name);
+ }
+ stat = read_status(fc, 2);
+ if (stat & HDLC_INT_MASK) {
+ bch = Sel_BCS(fc, 2);
+ if (bch)
+ HDLC_irq(bch, stat);
+ else
+ pr_debug("%s: spurious ch2 IRQ\n", fc->name);
+ }
+}
+
+static irqreturn_t
+avm_fritz_interrupt(int intno, void *dev_id)
+{
+ struct fritzcard *fc = dev_id;
+ u8 val;
+ u8 sval;
+
+ spin_lock(&fc->lock);
+ sval = inb(fc->addr + 2);
+ pr_debug("%s: irq stat0 %x\n", fc->name, sval);
+ if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
+ /* shared IRQ from other HW */
+ spin_unlock(&fc->lock);
+ return IRQ_NONE;
+ }
+ fc->irqcnt++;
+
+ if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
+ val = ReadISAC_V1(fc, ISAC_ISTA);
+ mISDNisac_irq(&fc->isac, val);
+ }
+ if (!(sval & AVM_STATUS0_IRQ_HDLC))
+ HDLC_irq_main(fc);
+ spin_unlock(&fc->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+avm_fritzv2_interrupt(int intno, void *dev_id)
+{
+ struct fritzcard *fc = dev_id;
+ u8 val;
+ u8 sval;
+
+ spin_lock(&fc->lock);
+ sval = inb(fc->addr + 2);
+ pr_debug("%s: irq stat0 %x\n", fc->name, sval);
+ if (!(sval & AVM_STATUS0_IRQ_MASK)) {
+ /* shared IRQ from other HW */
+ spin_unlock(&fc->lock);
+ return IRQ_NONE;
+ }
+ fc->irqcnt++;
+
+ if (sval & AVM_STATUS0_IRQ_HDLC)
+ HDLC_irq_main(fc);
+ if (sval & AVM_STATUS0_IRQ_ISAC) {
+ val = ReadISAC_V2(fc, ISACX_ISTA);
+ mISDNisac_irq(&fc->isac, val);
+ }
+ if (sval & AVM_STATUS0_IRQ_TIMER) {
+ pr_debug("%s: timer irq\n", fc->name);
+ outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
+ udelay(1);
+ outb(fc->ctrlreg, fc->addr + 2);
+ }
+ spin_unlock(&fc->lock);
+ return IRQ_HANDLED;
+}
+
+static int
+avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct fritzcard *fc = bch->hw;
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ hdlc_fill_fifo(bch);
+ ret = 0;
+ spin_unlock_irqrestore(&fc->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&fc->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = modehdlc(bch, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&fc->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ mISDN_clear_bchannel(bch);
+ modehdlc(bch, ISDN_P_NONE);
+ spin_unlock_irqrestore(&fc->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static void
+inithdlc(struct fritzcard *fc)
+{
+ modehdlc(&fc->bch[0], -1);
+ modehdlc(&fc->bch[1], -1);
+}
+
+void
+clear_pending_hdlc_ints(struct fritzcard *fc)
+{
+ u32 val;
+
+ val = read_status(fc, 1);
+ pr_debug("%s: HDLC 1 STA %x\n", fc->name, val);
+ val = read_status(fc, 2);
+ pr_debug("%s: HDLC 2 STA %x\n", fc->name, val);
+}
+
+static void
+reset_avm(struct fritzcard *fc)
+{
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;
+ break;
+ case AVM_FRITZ_PCIV2:
+ fc->ctrlreg = AVM_STATUS0_RESET;
+ break;
+ }
+ if (debug & DEBUG_HW)
+ pr_notice("%s: reset\n", fc->name);
+ disable_hwirq(fc);
+ mdelay(5);
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
+ disable_hwirq(fc);
+ outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
+ break;
+ case AVM_FRITZ_PCIV2:
+ fc->ctrlreg = 0;
+ disable_hwirq(fc);
+ break;
+ }
+ mdelay(1);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: S0/S1 %x/%x\n", fc->name,
+ inb(fc->addr + 2), inb(fc->addr + 3));
+}
+
+static int
+init_card(struct fritzcard *fc)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ reset_avm(fc); /* disable IRQ */
+ if (fc->type == AVM_FRITZ_PCIV2)
+ ret = request_irq(fc->irq, avm_fritzv2_interrupt,
+ IRQF_SHARED, fc->name, fc);
+ else
+ ret = request_irq(fc->irq, avm_fritz_interrupt,
+ IRQF_SHARED, fc->name, fc);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n",
+ fc->name, fc->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&fc->lock, flags);
+ ret = fc->isac.init(&fc->isac);
+ if (ret) {
+ spin_unlock_irqrestore(&fc->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ fc->name, ret);
+ break;
+ }
+ clear_pending_hdlc_ints(fc);
+ inithdlc(fc);
+ enable_hwirq(fc);
+ /* RESET Receiver and Transmitter */
+ if (AVM_FRITZ_PCIV2 == fc->type) {
+ WriteISAC_V2(fc, ISACX_MASK, 0);
+ WriteISAC_V2(fc, ISACX_CMDRD, 0x41);
+ } else {
+ WriteISAC_V1(fc, ISAC_MASK, 0);
+ WriteISAC_V1(fc, ISAC_CMDR, 0x41);
+ }
+ spin_unlock_irqrestore(&fc->lock, flags);
+ /* Timeout 10ms */
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", fc->name,
+ fc->irq, fc->irqcnt);
+ if (!fc->irqcnt) {
+ pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
+ fc->name, fc->irq, 3 - cnt);
+ reset_avm(fc);
+ } else
+ return 0;
+ }
+ free_irq(fc->irq, fc);
+ return -EIO;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+ struct fritzcard *fc = bch->hw;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct fritzcard *fc = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&fc->lock, flags);
+ mISDN_freebchannel(bch);
+ test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+ modehdlc(bch, ISDN_P_NONE);
+ spin_unlock_irqrestore(&fc->lock, flags);
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct fritzcard *fc, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &fc->bch[rq->adr.channel - 1];
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+/*
+ * device control function
+ */
+static int
+avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct fritzcard *fc = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = fc->isac.open(&fc->isac, rq);
+ else
+ err = open_bchannel(fc, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", fc->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id,
+ __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(fc, arg);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n",
+ fc->name, __func__, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+int
+setup_fritz(struct fritzcard *fc)
+{
+ u32 val, ver;
+
+ if (!request_region(fc->addr, 32, fc->name)) {
+ pr_info("%s: AVM config port %x-%x already in use\n",
+ fc->name, fc->addr, fc->addr + 31);
+ return -EIO;
+ }
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ val = inl(fc->addr);
+ outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);
+ ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;
+ if (debug & DEBUG_HW) {
+ pr_notice("%s: PCI stat %#x\n", fc->name, val);
+ pr_notice("%s: PCI Class %X Rev %d\n", fc->name,
+ val & 0xff, (val >> 8) & 0xff);
+ pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
+ }
+ ASSIGN_FUNC(V1, ISAC, fc->isac);
+ fc->isac.type = IPAC_TYPE_ISAC;
+ break;
+ case AVM_FRITZ_PCIV2:
+ val = inl(fc->addr);
+ ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;
+ if (debug & DEBUG_HW) {
+ pr_notice("%s: PCI V2 stat %#x\n", fc->name, val);
+ pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name,
+ val & 0xff, (val>>8) & 0xff);
+ pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
+ }
+ ASSIGN_FUNC(V2, ISAC, fc->isac);
+ fc->isac.type = IPAC_TYPE_ISACX;
+ break;
+ default:
+ release_region(fc->addr, 32);
+ pr_info("%s: AVM unknown type %d\n", fc->name, fc->type);
+ return -ENODEV;
+ }
+ pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name,
+ (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" :
+ "AVM Fritz!CARD PCIv2", fc->irq, fc->addr);
+ return 0;
+}
+
+static void
+release_card(struct fritzcard *card)
+{
+ u_long flags;
+
+ disable_hwirq(card);
+ spin_lock_irqsave(&card->lock, flags);
+ modehdlc(&card->bch[0], ISDN_P_NONE);
+ modehdlc(&card->bch[1], ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->isac.release(&card->isac);
+ free_irq(card->irq, card);
+ mISDN_freebchannel(&card->bch[1]);
+ mISDN_freebchannel(&card->bch[0]);
+ mISDN_unregister_device(&card->isac.dch.dev);
+ release_region(card->addr, 32);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ AVM_cnt--;
+}
+
+static int __devinit
+setup_instance(struct fritzcard *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->isac.name = card->name;
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->isac.dch.dev.D.ctrl = avm_dctrl;
+ for (i = 0; i < 2; i++) {
+ card->bch[i].nr = i + 1;
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+ card->bch[i].hw = card;
+ card->bch[i].ch.send = avm_l2l1B;
+ card->bch[i].ch.ctrl = avm_bctrl;
+ card->bch[i].ch.nr = i + 1;
+ list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels);
+ }
+ err = setup_fritz(card);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error_reg;
+ err = init_card(card);
+ if (!err) {
+ AVM_cnt++;
+ pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt);
+ return 0;
+ }
+ mISDN_unregister_device(&card->isac.dch.dev);
+error_reg:
+ release_region(card->addr, 32);
+error:
+ card->isac.release(&card->isac);
+ mISDN_freebchannel(&card->bch[1]);
+ mISDN_freebchannel(&card->bch[0]);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct fritzcard *card;
+
+ card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL);
+ if (!card) {
+ pr_info("No kmem for fritzcard\n");
+ return err;
+ }
+ if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
+ card->type = AVM_FRITZ_PCIV2;
+ else
+ card->type = AVM_FRITZ_PCI;
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ pr_notice("mISDN: found adapter %s at %s\n",
+ (char *) ent->driver_data, pci_name(pdev));
+
+ card->addr = pci_resource_start(pdev, 1);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+fritz_remove_pci(struct pci_dev *pdev)
+{
+ struct fritzcard *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ if (debug)
+ pr_info("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id fcpci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI"},
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI v2" },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+static struct pci_driver fcpci_driver = {
+ .name = "fcpci",
+ .probe = fritzpci_probe,
+ .remove = __devexit_p(fritz_remove_pci),
+ .id_table = fcpci_ids,
+};
+
+static int __init AVM_init(void)
+{
+ int err;
+
+ pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV);
+ err = pci_register_driver(&fcpci_driver);
+ return err;
+}
+
+static void __exit AVM_cleanup(void)
+{
+ pci_unregister_driver(&fcpci_driver);
+}
+
+module_init(AVM_init);
+module_exit(AVM_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index e1dab30aed30..faed794cf75a 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3416,22 +3416,8 @@ deactivate_bchannel(struct bchannel *bch)
u_long flags;
spin_lock_irqsave(&hc->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
+ mISDN_clear_bchannel(bch);
hc->chan[bch->slot].coeff_count = 0;
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
hc->chan[bch->slot].rx_off = 0;
hc->chan[bch->slot].conf = -1;
mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0);
@@ -5384,9 +5370,10 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
printk(KERN_ERR
- "Unknown HFC multiport controller (vendor:%x device:%x "
- "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device,
- ent->subvendor, ent->subdevice);
+ "Unknown HFC multiport controller (vendor:%04x device:%04x "
+ "subvendor:%04x subdevice:%04x)\n", pdev->vendor,
+ pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
printk(KERN_ERR
"Please contact the driver maintainer for support.\n");
return -ENODEV;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 228ffbed1286..70e6b0e01121 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1522,22 +1522,8 @@ deactivate_bchannel(struct bchannel *bch)
u_long flags;
spin_lock_irqsave(&hc->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
+ mISDN_clear_bchannel(bch);
mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
spin_unlock_irqrestore(&hc->lock, flags);
}
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 6b7704c41b94..fc46a26cb14f 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1809,21 +1809,7 @@ deactivate_bchannel(struct bchannel *bch)
hw->name, __func__, bch->nr);
spin_lock_irqsave(&hw->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
- clear_bit(FLG_ACTIVE, &bch->Flags);
- clear_bit(FLG_TX_BUSY, &bch->Flags);
+ mISDN_clear_bchannel(bch);
spin_unlock_irqrestore(&hw->lock, flags);
hfcsusb_setup_bch(bch, ISDN_P_NONE);
hfcsusb_stop_endpoint(hw, bch->nr);
diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h
new file mode 100644
index 000000000000..b438981107ae
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/iohelper.h
@@ -0,0 +1,109 @@
+/*
+ * iohelper.h
+ * helper for define functions to access ISDN hardware
+ * supported are memory mapped IO
+ * indirect port IO (one port for address, one for data)
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _IOHELPER_H
+#define _IOHELPER_H
+
+typedef u8 (read_reg_func)(void *hwp, u8 offset);
+typedef void (write_reg_func)(void *hwp, u8 offset, u8 value);
+typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size);
+
+struct _ioport {
+ u32 port;
+ u32 ale;
+};
+
+#define IOFUNC_IO(name, hws, ap) \
+ static u8 Read##name##_IO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return inb(hw->ap.port + off);\
+ } \
+ static void Write##name##_IO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(val, hw->ap.port + off);\
+ } \
+ static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ insb(hw->ap.port + off, dp, size);\
+ } \
+ static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outsb(hw->ap.port + off, dp, size);\
+ }
+
+#define IOFUNC_IND(name, hws, ap) \
+ static u8 Read##name##_IND(void *p, u8 off) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ return inb(hw->ap.port);\
+ } \
+ static void Write##name##_IND(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outb(val, hw->ap.port);\
+ } \
+ static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ insb(hw->ap.port, dp, size);\
+ } \
+ static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outsb(hw->ap.port, dp, size);\
+ }
+
+#define IOFUNC_MEMIO(name, hws, typ, adr) \
+ static u8 Read##name##_MIO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return readb(((typ *)hw->adr) + off);\
+ } \
+ static void Write##name##_MIO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ writeb(val, ((typ *)hw->adr) + off);\
+ } \
+ static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ while (size--)\
+ *dp++ = readb(((typ *)hw->adr) + off);\
+ } \
+ static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ while (size--)\
+ writeb(*dp++, ((typ *)hw->adr) + off);\
+ }
+
+#define ASSIGN_FUNC(typ, name, dest) do {\
+ dest.read_reg = &Read##name##_##typ;\
+ dest.write_reg = &Write##name##_##typ;\
+ dest.read_fifo = &ReadFiFo##name##_##typ;\
+ dest.write_fifo = &WriteFiFo##name##_##typ;\
+ } while (0)
+#define ASSIGN_FUNC_IPAC(typ, target) do {\
+ ASSIGN_FUNC(typ, ISAC, target.isac);\
+ ASSIGN_FUNC(typ, IPAC, target);\
+ } while (0)
+
+#endif
diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h
new file mode 100644
index 000000000000..74a6ccf9065c
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/ipac.h
@@ -0,0 +1,405 @@
+/*
+ *
+ * ipac.h Defines for the Infineon (former Siemens) ISDN
+ * chip series
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "iohelper.h"
+
+struct isac_hw {
+ struct dchannel dch;
+ u32 type;
+ u32 off; /* offset to isac regs */
+ char *name;
+ spinlock_t *hwlock; /* lock HW acccess */
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ int (*monitor)(void *, u32, u8 *, int);
+ void (*release)(struct isac_hw *);
+ int (*init)(struct isac_hw *);
+ int (*ctrl)(struct isac_hw *, u32, u_long);
+ int (*open)(struct isac_hw *, struct channel_req *);
+ u8 *mon_tx;
+ u8 *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ struct arcofi_msg *arcofi_list;
+ struct timer_list arcofitimer;
+ wait_queue_head_t arcofi_wait;
+ u8 arcofi_bc;
+ u8 arcofi_state;
+ u8 mocr;
+ u8 adf2;
+ u8 state;
+};
+
+struct ipac_hw;
+
+struct hscx_hw {
+ struct bchannel bch;
+ struct ipac_hw *ip;
+ u8 fifo_size;
+ u8 off; /* offset to ICA or ICB */
+ u8 slot;
+ char log[64];
+};
+
+struct ipac_hw {
+ struct isac_hw isac;
+ struct hscx_hw hscx[2];
+ char *name;
+ void *hw;
+ spinlock_t *hwlock; /* lock HW acccess */
+ struct module *owner;
+ u32 type;
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ void (*release)(struct ipac_hw *);
+ int (*init)(struct ipac_hw *);
+ int (*ctrl)(struct ipac_hw *, u32, u_long);
+ u8 conf;
+};
+
+#define IPAC_TYPE_ISAC 0x0010
+#define IPAC_TYPE_IPAC 0x0020
+#define IPAC_TYPE_ISACX 0x0040
+#define IPAC_TYPE_IPACX 0x0080
+#define IPAC_TYPE_HSCX 0x0100
+
+#define ISAC_USE_ARCOFI 0x1000
+
+/* Monitor functions */
+#define MONITOR_RX_0 0x1000
+#define MONITOR_RX_1 0x1001
+#define MONITOR_TX_0 0x2000
+#define MONITOR_TX_1 0x2001
+
+/* All registers original Siemens Spec */
+/* IPAC/ISAC registers */
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_EXIR 0x24
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_SQRR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define IPAC_D_TIN2 0x01
+
+/* IPAC/HSCX */
+#define IPAC_ISTAB 0x20 /* RD */
+#define IPAC_MASKB 0x20 /* WR */
+#define IPAC_STARB 0x21 /* RD */
+#define IPAC_CMDRB 0x21 /* WR */
+#define IPAC_MODEB 0x22 /* R/W */
+#define IPAC_EXIRB 0x24 /* RD */
+#define IPAC_RBCLB 0x25 /* RD */
+#define IPAC_RAH1 0x26 /* WR */
+#define IPAC_RAH2 0x27 /* WR */
+#define IPAC_RSTAB 0x27 /* RD */
+#define IPAC_RAL1 0x28 /* R/W */
+#define IPAC_RAL2 0x29 /* WR */
+#define IPAC_RHCRB 0x29 /* RD */
+#define IPAC_XBCL 0x2A /* WR */
+#define IPAC_CCR2 0x2C /* R/W */
+#define IPAC_RBCHB 0x2D /* RD */
+#define IPAC_XBCH 0x2D /* WR */
+#define HSCX_VSTR 0x2E /* RD */
+#define IPAC_RLCR 0x2E /* WR */
+#define IPAC_CCR1 0x2F /* R/W */
+#define IPAC_TSAX 0x30 /* WR */
+#define IPAC_TSAR 0x31 /* WR */
+#define IPAC_XCCR 0x32 /* WR */
+#define IPAC_RCCR 0x33 /* WR */
+
+/* IPAC_ISTAB/IPAC_MASKB bits */
+#define IPAC_B_XPR 0x10
+#define IPAC_B_RPF 0x40
+#define IPAC_B_RME 0x80
+#define IPAC_B_ON 0x2F
+
+/* IPAC_EXIRB bits */
+#define IPAC_B_RFS 0x04
+#define IPAC_B_RFO 0x10
+#define IPAC_B_XDU 0x40
+#define IPAC_B_XMR 0x80
+
+/* IPAC special registers */
+#define IPAC_CONF 0xC0 /* R/W */
+#define IPAC_ISTA 0xC1 /* RD */
+#define IPAC_MASK 0xC1 /* WR */
+#define IPAC_ID 0xC2 /* RD */
+#define IPAC_ACFG 0xC3 /* R/W */
+#define IPAC_AOE 0xC4 /* R/W */
+#define IPAC_ARX 0xC5 /* RD */
+#define IPAC_ATX 0xC5 /* WR */
+#define IPAC_PITA1 0xC6 /* R/W */
+#define IPAC_PITA2 0xC7 /* R/W */
+#define IPAC_POTA1 0xC8 /* R/W */
+#define IPAC_POTA2 0xC9 /* R/W */
+#define IPAC_PCFG 0xCA /* R/W */
+#define IPAC_SCFG 0xCB /* R/W */
+#define IPAC_TIMR2 0xCC /* R/W */
+
+/* IPAC_ISTA/_MASK bits */
+#define IPAC__EXB 0x01
+#define IPAC__ICB 0x02
+#define IPAC__EXA 0x04
+#define IPAC__ICA 0x08
+#define IPAC__EXD 0x10
+#define IPAC__ICD 0x20
+#define IPAC__INT0 0x40
+#define IPAC__INT1 0x80
+#define IPAC__ON 0xC0
+
+/* HSCX ISTA/MASK bits */
+#define HSCX__EXB 0x01
+#define HSCX__EXA 0x02
+#define HSCX__ICA 0x04
+
+/* ISAC/ISACX/IPAC/IPACX L1 commands */
+#define ISAC_CMD_TIM 0x0
+#define ISAC_CMD_RS 0x1
+#define ISAC_CMD_SCZ 0x4
+#define ISAC_CMD_SSZ 0x2
+#define ISAC_CMD_AR8 0x8
+#define ISAC_CMD_AR10 0x9
+#define ISAC_CMD_ARL 0xA
+#define ISAC_CMD_DUI 0xF
+
+/* ISAC/ISACX/IPAC/IPACX L1 indications */
+#define ISAC_IND_RS 0x1
+#define ISAC_IND_PU 0x7
+#define ISAC_IND_DR 0x0
+#define ISAC_IND_SD 0x2
+#define ISAC_IND_DIS 0x3
+#define ISAC_IND_EI 0x6
+#define ISAC_IND_RSY 0x4
+#define ISAC_IND_ARD 0x8
+#define ISAC_IND_TI 0xA
+#define ISAC_IND_ATI 0xB
+#define ISAC_IND_AI8 0xC
+#define ISAC_IND_AI10 0xD
+#define ISAC_IND_DID 0xF
+
+/* the new ISACX / IPACX */
+/* D-channel registers */
+#define ISACX_RFIFOD 0x00 /* RD */
+#define ISACX_XFIFOD 0x00 /* WR */
+#define ISACX_ISTAD 0x20 /* RD */
+#define ISACX_MASKD 0x20 /* WR */
+#define ISACX_STARD 0x21 /* RD */
+#define ISACX_CMDRD 0x21 /* WR */
+#define ISACX_MODED 0x22 /* R/W */
+#define ISACX_EXMD1 0x23 /* R/W */
+#define ISACX_TIMR1 0x24 /* R/W */
+#define ISACX_SAP1 0x25 /* WR */
+#define ISACX_SAP2 0x26 /* WR */
+#define ISACX_RBCLD 0x26 /* RD */
+#define ISACX_RBCHD 0x27 /* RD */
+#define ISACX_TEI1 0x27 /* WR */
+#define ISACX_TEI2 0x28 /* WR */
+#define ISACX_RSTAD 0x28 /* RD */
+#define ISACX_TMD 0x29 /* R/W */
+#define ISACX_CIR0 0x2E /* RD */
+#define ISACX_CIX0 0x2E /* WR */
+#define ISACX_CIR1 0x2F /* RD */
+#define ISACX_CIX1 0x2F /* WR */
+
+/* Transceiver registers */
+#define ISACX_TR_CONF0 0x30 /* R/W */
+#define ISACX_TR_CONF1 0x31 /* R/W */
+#define ISACX_TR_CONF2 0x32 /* R/W */
+#define ISACX_TR_STA 0x33 /* RD */
+#define ISACX_TR_CMD 0x34 /* R/W */
+#define ISACX_SQRR1 0x35 /* RD */
+#define ISACX_SQXR1 0x35 /* WR */
+#define ISACX_SQRR2 0x36 /* RD */
+#define ISACX_SQXR2 0x36 /* WR */
+#define ISACX_SQRR3 0x37 /* RD */
+#define ISACX_SQXR3 0x37 /* WR */
+#define ISACX_ISTATR 0x38 /* RD */
+#define ISACX_MASKTR 0x39 /* R/W */
+#define ISACX_TR_MODE 0x3A /* R/W */
+#define ISACX_ACFG1 0x3C /* R/W */
+#define ISACX_ACFG2 0x3D /* R/W */
+#define ISACX_AOE 0x3E /* R/W */
+#define ISACX_ARX 0x3F /* RD */
+#define ISACX_ATX 0x3F /* WR */
+
+/* IOM: Timeslot, DPS, CDA */
+#define ISACX_CDA10 0x40 /* R/W */
+#define ISACX_CDA11 0x41 /* R/W */
+#define ISACX_CDA20 0x42 /* R/W */
+#define ISACX_CDA21 0x43 /* R/W */
+#define ISACX_CDA_TSDP10 0x44 /* R/W */
+#define ISACX_CDA_TSDP11 0x45 /* R/W */
+#define ISACX_CDA_TSDP20 0x46 /* R/W */
+#define ISACX_CDA_TSDP21 0x47 /* R/W */
+#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */
+#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */
+#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */
+#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */
+#define ISACX_TR_TSDP_BC1 0x4C /* R/W */
+#define ISACX_TR_TSDP_BC2 0x4D /* R/W */
+#define ISACX_CDA1_CR 0x4E /* R/W */
+#define ISACX_CDA2_CR 0x4F /* R/W */
+
+/* IOM: Contol, Sync transfer, Monitor */
+#define ISACX_TR_CR 0x50 /* R/W */
+#define ISACX_TRC_CR 0x50 /* R/W */
+#define ISACX_BCHA_CR 0x51 /* R/W */
+#define ISACX_BCHB_CR 0x52 /* R/W */
+#define ISACX_DCI_CR 0x53 /* R/W */
+#define ISACX_DCIC_CR 0x53 /* R/W */
+#define ISACX_MON_CR 0x54 /* R/W */
+#define ISACX_SDS1_CR 0x55 /* R/W */
+#define ISACX_SDS2_CR 0x56 /* R/W */
+#define ISACX_IOM_CR 0x57 /* R/W */
+#define ISACX_STI 0x58 /* RD */
+#define ISACX_ASTI 0x58 /* WR */
+#define ISACX_MSTI 0x59 /* R/W */
+#define ISACX_SDS_CONF 0x5A /* R/W */
+#define ISACX_MCDA 0x5B /* RD */
+#define ISACX_MOR 0x5C /* RD */
+#define ISACX_MOX 0x5C /* WR */
+#define ISACX_MOSR 0x5D /* RD */
+#define ISACX_MOCR 0x5E /* R/W */
+#define ISACX_MSTA 0x5F /* RD */
+#define ISACX_MCONF 0x5F /* WR */
+
+/* Interrupt and general registers */
+#define ISACX_ISTA 0x60 /* RD */
+#define ISACX_MASK 0x60 /* WR */
+#define ISACX_AUXI 0x61 /* RD */
+#define ISACX_AUXM 0x61 /* WR */
+#define ISACX_MODE1 0x62 /* R/W */
+#define ISACX_MODE2 0x63 /* R/W */
+#define ISACX_ID 0x64 /* RD */
+#define ISACX_SRES 0x64 /* WR */
+#define ISACX_TIMR2 0x65 /* R/W */
+
+/* Register Bits */
+/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */
+#define ISACX_D_XDU 0x04
+#define ISACX_D_XMR 0x08
+#define ISACX_D_XPR 0x10
+#define ISACX_D_RFO 0x20
+#define ISACX_D_RPF 0x40
+#define ISACX_D_RME 0x80
+
+/* ISACX/IPACX _ISTA (R) and _MASK (W) */
+#define ISACX__ICD 0x01
+#define ISACX__MOS 0x02
+#define ISACX__TRAN 0x04
+#define ISACX__AUX 0x08
+#define ISACX__CIC 0x10
+#define ISACX__ST 0x20
+#define IPACX__ICB 0x40
+#define IPACX__ICA 0x80
+#define IPACX__ON 0x2C
+
+/* ISACX/IPACX _CMDRD (W) */
+#define ISACX_CMDRD_XRES 0x01
+#define ISACX_CMDRD_XME 0x02
+#define ISACX_CMDRD_XTF 0x08
+#define ISACX_CMDRD_STI 0x10
+#define ISACX_CMDRD_RRES 0x40
+#define ISACX_CMDRD_RMC 0x80
+
+/* ISACX/IPACX _RSTAD (R) */
+#define ISACX_RSTAD_TA 0x01
+#define ISACX_RSTAD_CR 0x02
+#define ISACX_RSTAD_SA0 0x04
+#define ISACX_RSTAD_SA1 0x08
+#define ISACX_RSTAD_RAB 0x10
+#define ISACX_RSTAD_CRC 0x20
+#define ISACX_RSTAD_RDO 0x40
+#define ISACX_RSTAD_VFR 0x80
+
+/* ISACX/IPACX _CIR0 (R) */
+#define ISACX_CIR0_BAS 0x01
+#define ISACX_CIR0_SG 0x08
+#define ISACX_CIR0_CIC1 0x08
+#define ISACX_CIR0_CIC0 0x08
+
+/* B-channel registers */
+#define IPACX_OFF_ICA 0x70
+#define IPACX_OFF_ICB 0x80
+
+/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */
+
+#define IPACX_ISTAB 0x00 /* RD */
+#define IPACX_MASKB 0x00 /* WR */
+#define IPACX_STARB 0x01 /* RD */
+#define IPACX_CMDRB 0x01 /* WR */
+#define IPACX_MODEB 0x02 /* R/W */
+#define IPACX_EXMB 0x03 /* R/W */
+#define IPACX_RAH1 0x05 /* WR */
+#define IPACX_RAH2 0x06 /* WR */
+#define IPACX_RBCLB 0x06 /* RD */
+#define IPACX_RBCHB 0x07 /* RD */
+#define IPACX_RAL1 0x07 /* WR */
+#define IPACX_RAL2 0x08 /* WR */
+#define IPACX_RSTAB 0x08 /* RD */
+#define IPACX_TMB 0x09 /* R/W */
+#define IPACX_RFIFOB 0x0A /* RD */
+#define IPACX_XFIFOB 0x0A /* WR */
+
+/* IPACX_ISTAB / IPACX_MASKB bits */
+#define IPACX_B_XDU 0x04
+#define IPACX_B_XPR 0x10
+#define IPACX_B_RFO 0x20
+#define IPACX_B_RPF 0x40
+#define IPACX_B_RME 0x80
+
+#define IPACX_B_ON 0x0B
+
+extern int mISDNisac_init(struct isac_hw *, void *);
+extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8);
+extern u32 mISDNipac_init(struct ipac_hw *, void *);
+extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int);
diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h
new file mode 100644
index 000000000000..4a134acd44d0
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/isar.h
@@ -0,0 +1,269 @@
+/*
+ *
+ * isar.h ISAR (Siemens PSB 7110) specific defines
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "iohelper.h"
+
+struct isar_hw;
+
+struct isar_ch {
+ struct bchannel bch;
+ struct isar_hw *is;
+ struct timer_list ftimer;
+ u8 nr;
+ u8 dpath;
+ u8 mml;
+ u8 state;
+ u8 cmd;
+ u8 mod;
+ u8 newcmd;
+ u8 newmod;
+ u8 try_mod;
+ u8 conmsg[16];
+};
+
+struct isar_hw {
+ struct isar_ch ch[2];
+ void *hw;
+ spinlock_t *hwlock; /* lock HW acccess */
+ char *name;
+ struct module *owner;
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ int (*ctrl)(void *, u32, u_long);
+ void (*release)(struct isar_hw *);
+ int (*init)(struct isar_hw *);
+ int (*open)(struct isar_hw *, struct channel_req *);
+ int (*firmware)(struct isar_hw *, const u8 *, int);
+ unsigned long Flags;
+ int version;
+ u8 bstat;
+ u8 iis;
+ u8 cmsb;
+ u8 clsb;
+ u8 buf[256];
+ u8 log[256];
+};
+
+#define ISAR_IRQMSK 0x04
+#define ISAR_IRQSTA 0x04
+#define ISAR_IRQBIT 0x75
+#define ISAR_CTRL_H 0x61
+#define ISAR_CTRL_L 0x60
+#define ISAR_IIS 0x58
+#define ISAR_IIA 0x58
+#define ISAR_HIS 0x50
+#define ISAR_HIA 0x50
+#define ISAR_MBOX 0x4c
+#define ISAR_WADR 0x4a
+#define ISAR_RADR 0x48
+
+#define ISAR_HIS_VNR 0x14
+#define ISAR_HIS_DKEY 0x02
+#define ISAR_HIS_FIRM 0x1e
+#define ISAR_HIS_STDSP 0x08
+#define ISAR_HIS_DIAG 0x05
+#define ISAR_HIS_P0CFG 0x3c
+#define ISAR_HIS_P12CFG 0x24
+#define ISAR_HIS_SARTCFG 0x25
+#define ISAR_HIS_PUMPCFG 0x26
+#define ISAR_HIS_PUMPCTRL 0x2a
+#define ISAR_HIS_IOM2CFG 0x27
+#define ISAR_HIS_IOM2REQ 0x07
+#define ISAR_HIS_IOM2CTRL 0x2b
+#define ISAR_HIS_BSTREQ 0x0c
+#define ISAR_HIS_PSTREQ 0x0e
+#define ISAR_HIS_SDATA 0x20
+#define ISAR_HIS_DPS1 0x40
+#define ISAR_HIS_DPS2 0x80
+#define SET_DPS(x) ((x<<6) & 0xc0)
+
+#define ISAR_IIS_MSCMSD 0x3f
+#define ISAR_IIS_VNR 0x15
+#define ISAR_IIS_DKEY 0x03
+#define ISAR_IIS_FIRM 0x1f
+#define ISAR_IIS_STDSP 0x09
+#define ISAR_IIS_DIAG 0x25
+#define ISAR_IIS_GSTEV 0x00
+#define ISAR_IIS_BSTEV 0x28
+#define ISAR_IIS_BSTRSP 0x2c
+#define ISAR_IIS_PSTRSP 0x2e
+#define ISAR_IIS_PSTEV 0x2a
+#define ISAR_IIS_IOM2RSP 0x27
+#define ISAR_IIS_RDATA 0x20
+#define ISAR_IIS_INVMSG 0x3f
+
+#define ISAR_CTRL_SWVER 0x10
+#define ISAR_CTRL_STST 0x40
+
+#define ISAR_MSG_HWVER 0x20
+
+#define ISAR_DP1_USE 1
+#define ISAR_DP2_USE 2
+#define ISAR_RATE_REQ 3
+
+#define PMOD_DISABLE 0
+#define PMOD_FAX 1
+#define PMOD_DATAMODEM 2
+#define PMOD_HALFDUPLEX 3
+#define PMOD_V110 4
+#define PMOD_DTMF 5
+#define PMOD_DTMF_TRANS 6
+#define PMOD_BYPASS 7
+
+#define PCTRL_ORIG 0x80
+#define PV32P2_V23R 0x40
+#define PV32P2_V22A 0x20
+#define PV32P2_V22B 0x10
+#define PV32P2_V22C 0x08
+#define PV32P2_V21 0x02
+#define PV32P2_BEL 0x01
+
+/* LSB MSB in ISAR doc wrong !!! Arghhh */
+#define PV32P3_AMOD 0x80
+#define PV32P3_V32B 0x02
+#define PV32P3_V23B 0x01
+#define PV32P4_48 0x11
+#define PV32P5_48 0x05
+#define PV32P4_UT48 0x11
+#define PV32P5_UT48 0x0d
+#define PV32P4_96 0x11
+#define PV32P5_96 0x03
+#define PV32P4_UT96 0x11
+#define PV32P5_UT96 0x0f
+#define PV32P4_B96 0x91
+#define PV32P5_B96 0x0b
+#define PV32P4_UTB96 0xd1
+#define PV32P5_UTB96 0x0f
+#define PV32P4_120 0xb1
+#define PV32P5_120 0x09
+#define PV32P4_UT120 0xf1
+#define PV32P5_UT120 0x0f
+#define PV32P4_144 0x99
+#define PV32P5_144 0x09
+#define PV32P4_UT144 0xf9
+#define PV32P5_UT144 0x0f
+#define PV32P6_CTN 0x01
+#define PV32P6_ATN 0x02
+
+#define PFAXP2_CTN 0x01
+#define PFAXP2_ATN 0x04
+
+#define PSEV_10MS_TIMER 0x02
+#define PSEV_CON_ON 0x18
+#define PSEV_CON_OFF 0x19
+#define PSEV_V24_OFF 0x20
+#define PSEV_CTS_ON 0x21
+#define PSEV_CTS_OFF 0x22
+#define PSEV_DCD_ON 0x23
+#define PSEV_DCD_OFF 0x24
+#define PSEV_DSR_ON 0x25
+#define PSEV_DSR_OFF 0x26
+#define PSEV_REM_RET 0xcc
+#define PSEV_REM_REN 0xcd
+#define PSEV_GSTN_CLR 0xd4
+
+#define PSEV_RSP_READY 0xbc
+#define PSEV_LINE_TX_H 0xb3
+#define PSEV_LINE_TX_B 0xb2
+#define PSEV_LINE_RX_H 0xb1
+#define PSEV_LINE_RX_B 0xb0
+#define PSEV_RSP_CONN 0xb5
+#define PSEV_RSP_DISC 0xb7
+#define PSEV_RSP_FCERR 0xb9
+#define PSEV_RSP_SILDET 0xbe
+#define PSEV_RSP_SILOFF 0xab
+#define PSEV_FLAGS_DET 0xba
+
+#define PCTRL_CMD_TDTMF 0x5a
+
+#define PCTRL_CMD_FTH 0xa7
+#define PCTRL_CMD_FRH 0xa5
+#define PCTRL_CMD_FTM 0xa8
+#define PCTRL_CMD_FRM 0xa6
+#define PCTRL_CMD_SILON 0xac
+#define PCTRL_CMD_CONT 0xa2
+#define PCTRL_CMD_ESC 0xa4
+#define PCTRL_CMD_SILOFF 0xab
+#define PCTRL_CMD_HALT 0xa9
+
+#define PCTRL_LOC_RET 0xcf
+#define PCTRL_LOC_REN 0xce
+
+#define SMODE_DISABLE 0
+#define SMODE_V14 2
+#define SMODE_HDLC 3
+#define SMODE_BINARY 4
+#define SMODE_FSK_V14 5
+
+#define SCTRL_HDMC_BOTH 0x00
+#define SCTRL_HDMC_DTX 0x80
+#define SCTRL_HDMC_DRX 0x40
+#define S_P1_OVSP 0x40
+#define S_P1_SNP 0x20
+#define S_P1_EOP 0x10
+#define S_P1_EDP 0x08
+#define S_P1_NSB 0x04
+#define S_P1_CHS_8 0x03
+#define S_P1_CHS_7 0x02
+#define S_P1_CHS_6 0x01
+#define S_P1_CHS_5 0x00
+
+#define S_P2_BFT_DEF 0x10
+
+#define IOM_CTRL_ENA 0x80
+#define IOM_CTRL_NOPCM 0x00
+#define IOM_CTRL_ALAW 0x02
+#define IOM_CTRL_ULAW 0x04
+#define IOM_CTRL_RCV 0x01
+
+#define IOM_P1_TXD 0x10
+
+#define HDLC_FED 0x40
+#define HDLC_FSD 0x20
+#define HDLC_FST 0x20
+#define HDLC_ERROR 0x1c
+#define HDLC_ERR_FAD 0x10
+#define HDLC_ERR_RER 0x08
+#define HDLC_ERR_CER 0x04
+#define SART_NMD 0x01
+
+#define BSTAT_RDM0 0x1
+#define BSTAT_RDM1 0x2
+#define BSTAT_RDM2 0x4
+#define BSTAT_RDM3 0x8
+#define BSTEV_TBO 0x1f
+#define BSTEV_RBO 0x2f
+
+/* FAX State Machine */
+#define STFAX_NULL 0
+#define STFAX_READY 1
+#define STFAX_LINE 2
+#define STFAX_CONT 3
+#define STFAX_ACTIV 4
+#define STFAX_ESCAPE 5
+#define STFAX_SILDET 6
+
+extern u32 mISDNisar_init(struct isar_hw *, void *);
+extern void mISDNisar_irq(struct isar_hw *);
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
new file mode 100644
index 000000000000..62441ba53b95
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -0,0 +1,1178 @@
+/*
+ * mISDNinfineon.c
+ * Support for cards based on following Infineon ISDN chipsets
+ * - ISAC + HSCX
+ * - IPAC and IPAC-X
+ * - ISAC-SX + HSCX
+ *
+ * Supported cards:
+ * - Dialogic Diva 2.0
+ * - Dialogic Diva 2.0U
+ * - Dialogic Diva 2.01
+ * - Dialogic Diva 2.02
+ * - Sedlbauer Speedwin
+ * - HST Saphir3
+ * - Develo (former ELSA) Microlink PCI (Quickstep 1000)
+ * - Develo (former ELSA) Quickstep 3000
+ * - Berkom Scitel BRIX Quadro
+ * - Dr.Neuhaus (Sagem) Niccy
+ *
+ *
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+
+#define INFINEON_REV "1.0"
+
+static int inf_cnt;
+static u32 debug;
+static u32 irqloops = 4;
+
+enum inf_types {
+ INF_NONE,
+ INF_DIVA20,
+ INF_DIVA20U,
+ INF_DIVA201,
+ INF_DIVA202,
+ INF_SPEEDWIN,
+ INF_SAPHIR3,
+ INF_QS1000,
+ INF_QS3000,
+ INF_NICCY,
+ INF_SCT_1,
+ INF_SCT_2,
+ INF_SCT_3,
+ INF_SCT_4,
+ INF_GAZEL_R685,
+ INF_GAZEL_R753
+};
+
+enum addr_mode {
+ AM_NONE = 0,
+ AM_IO,
+ AM_MEMIO,
+ AM_IND_IO,
+};
+
+struct inf_cinfo {
+ enum inf_types typ;
+ const char *full;
+ const char *name;
+ enum addr_mode cfg_mode;
+ enum addr_mode addr_mode;
+ u8 cfg_bar;
+ u8 addr_bar;
+ void *irqfunc;
+};
+
+struct _ioaddr {
+ enum addr_mode mode;
+ union {
+ void __iomem *p;
+ struct _ioport io;
+ } a;
+};
+
+struct _iohandle {
+ enum addr_mode mode;
+ resource_size_t size;
+ resource_size_t start;
+ void __iomem *p;
+};
+
+struct inf_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ const struct inf_cinfo *ci;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ struct _iohandle cfg;
+ struct _iohandle addr;
+ struct _ioaddr isac;
+ struct _ioaddr hscx;
+ spinlock_t lock; /* HW access lock */
+ struct ipac_hw ipac;
+ struct inf_hw *sc[3]; /* slave cards */
+};
+
+
+#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
+#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
+#define PCI_SUB_ID_SEDLBAUER 0x01
+
+static struct pci_device_id infineon_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
+ INF_SPEEDWIN},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000},
+ { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
+ INF_SCT_1},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, infineon_ids);
+
+/* PCI interface specific defines */
+/* Diva 2.0/2.0U */
+#define DIVA_HSCX_PORT 0x00
+#define DIVA_HSCX_ALE 0x04
+#define DIVA_ISAC_PORT 0x08
+#define DIVA_ISAC_ALE 0x0C
+#define DIVA_PCI_CTRL 0x10
+
+/* DIVA_PCI_CTRL bits */
+#define DIVA_IRQ_BIT 0x01
+#define DIVA_RESET_BIT 0x08
+#define DIVA_EEPROM_CLK 0x40
+#define DIVA_LED_A 0x10
+#define DIVA_LED_B 0x20
+#define DIVA_IRQ_CLR 0x80
+
+/* Diva 2.01/2.02 */
+/* Siemens PITA */
+#define PITA_ICR_REG 0x00
+#define PITA_INT0_STATUS 0x02
+
+#define PITA_MISC_REG 0x1c
+#define PITA_PARA_SOFTRESET 0x01000000
+#define PITA_SER_SOFTRESET 0x02000000
+#define PITA_PARA_MPX_MODE 0x04000000
+#define PITA_INT0_ENABLE 0x00020000
+
+/* TIGER 100 Registers */
+#define TIGER_RESET_ADDR 0x00
+#define TIGER_EXTERN_RESET 0x01
+#define TIGER_AUX_CTRL 0x02
+#define TIGER_AUX_DATA 0x03
+#define TIGER_AUX_IRQMASK 0x05
+#define TIGER_AUX_STATUS 0x07
+
+/* Tiger AUX BITs */
+#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */
+#define TIGER_IRQ_BIT 0x02
+
+#define TIGER_IPAC_ALE 0xC0
+#define TIGER_IPAC_PORT 0xC8
+
+/* ELSA (now Develo) PCI cards */
+#define ELSA_IRQ_ADDR 0x4c
+#define ELSA_IRQ_MASK 0x04
+#define QS1000_IRQ_OFF 0x01
+#define QS3000_IRQ_OFF 0x03
+#define QS1000_IRQ_ON 0x41
+#define QS3000_IRQ_ON 0x43
+
+/* Dr Neuhaus/Sagem Niccy */
+#define NICCY_ISAC_PORT 0x00
+#define NICCY_HSCX_PORT 0x01
+#define NICCY_ISAC_ALE 0x02
+#define NICCY_HSCX_ALE 0x03
+
+#define NICCY_IRQ_CTRL_REG 0x38
+#define NICCY_IRQ_ENABLE 0x001f00
+#define NICCY_IRQ_DISABLE 0xff0000
+#define NICCY_IRQ_BIT 0x800000
+
+
+/* Scitel PLX */
+#define SCT_PLX_IRQ_ADDR 0x4c
+#define SCT_PLX_RESET_ADDR 0x50
+#define SCT_PLX_IRQ_ENABLE 0x41
+#define SCT_PLX_RESET_BIT 0x04
+
+/* Gazel */
+#define GAZEL_IPAC_DATA_PORT 0x04
+/* Gazel PLX */
+#define GAZEL_CNTRL 0x50
+#define GAZEL_RESET 0x04
+#define GAZEL_RESET_9050 0x40000000
+#define GAZEL_INCSR 0x4C
+#define GAZEL_ISAC_EN 0x08
+#define GAZEL_INT_ISAC 0x20
+#define GAZEL_HSCX_EN 0x01
+#define GAZEL_INT_HSCX 0x04
+#define GAZEL_PCI_EN 0x40
+#define GAZEL_IPAC_EN 0x03
+
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct inf_hw *card)
+{
+ card->ipac.isac.dch.debug = debug;
+ card->ipac.hscx[0].bch.debug = debug;
+ card->ipac.hscx[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct inf_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(INFINEON_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "infineon debug mask");
+module_param(irqloops, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
+
+/* Interface functions */
+
+IOFUNC_IO(ISAC, inf_hw, isac.a.io)
+IOFUNC_IO(IPAC, inf_hw, hscx.a.io)
+IOFUNC_IND(ISAC, inf_hw, isac.a.io)
+IOFUNC_IND(IPAC, inf_hw, hscx.a.io)
+IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
+IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
+
+static irqreturn_t
+diva_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);
+ if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+diva20x_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = readb(hw->cfg.p);
+ if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+tiger_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);
+ if (val & TIGER_IRQ_BIT) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+elsa_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ if (!(val & ELSA_IRQ_MASK)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+niccy_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u32 val;
+
+ spin_lock(&hw->lock);
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+gazel_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ irqreturn_t ret;
+
+ spin_lock(&hw->lock);
+ ret = mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return ret;
+}
+
+static irqreturn_t
+ipac_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = hw->ipac.read_reg(hw, IPAC_ISTA);
+ if (!(val & 0x3f)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(PITA_INT0_ENABLE, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val |= NICCY_IRQ_ENABLE;;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w |= SCT_PLX_IRQ_ENABLE;
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ case INF_GAZEL_R753:
+ outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+disable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(0, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val &= NICCY_IRQ_DISABLE;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w &= (~SCT_PLX_IRQ_ENABLE);
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ case INF_GAZEL_R753:
+ outb(0, (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ipac_chip_reset(struct inf_hw *hw)
+{
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);
+ hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);
+}
+
+static void
+reset_inf(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: resetting card\n", hw->name);
+ switch (hw->ci->typ) {
+ case INF_DIVA20:
+ case INF_DIVA20U:
+ outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ /* Workaround PCI9060 */
+ outb(9, (u32)hw->cfg.start + 0x69);
+ outb(DIVA_RESET_BIT | DIVA_LED_A,
+ (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ break;
+ case INF_DIVA201:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_DIVA202:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
+ hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);
+ break;
+ case INF_QS1000:
+ case INF_QS3000:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);
+ hw->ipac.write_reg(hw, IPAC_ATX, 0xff);
+ break;
+ case INF_NICCY:
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ w &= (~SCT_PLX_RESET_BIT);
+ outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ mdelay(10);
+ w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ w |= SCT_PLX_RESET_BIT;
+ outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ mdelay(10);
+ break;
+ case INF_GAZEL_R685:
+ val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
+ val |= (GAZEL_RESET_9050 + GAZEL_RESET);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
+ mdelay(4);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ mdelay(10);
+ hw->ipac.isac.adf2 = 0x87;
+ hw->ipac.hscx[0].slot = 0x1f;
+ hw->ipac.hscx[0].slot = 0x23;
+ break;
+ case INF_GAZEL_R753:
+ val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
+ val |= (GAZEL_RESET_9050 + GAZEL_RESET);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
+ mdelay(4);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ mdelay(10);
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
+ hw->ipac.conf = 0x01; /* IOM off */
+ break;
+ default:
+ return;
+ }
+ enable_hwirq(hw);
+}
+
+static int
+inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case HW_RESET_REQ:
+ reset_inf(hw);
+ break;
+ default:
+ pr_info("%s: %s unknown command %x %lx\n",
+ hw->name, __func__, cmd, arg);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int __devinit
+init_irq(struct inf_hw *hw)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ if (!hw->ci->irqfunc)
+ return -EINVAL;
+ ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&hw->lock, flags);
+ reset_inf(hw);
+ ret = hw->ipac.init(&hw->ipac);
+ if (ret) {
+ spin_unlock_irqrestore(&hw->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ hw->name, ret);
+ break;
+ }
+ spin_unlock_irqrestore(&hw->lock, flags);
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", hw->name,
+ hw->irq, hw->irqcnt);
+ if (!hw->irqcnt) {
+ pr_info("%s: IRQ(%d) got no requests during init %d\n",
+ hw->name, hw->irq, 3 - cnt);
+ } else
+ return 0;
+ }
+ free_irq(hw->irq, hw);
+ return -EIO;
+}
+
+static void
+release_io(struct inf_hw *hw)
+{
+ if (hw->cfg.mode) {
+ if (hw->cfg.p) {
+ release_mem_region(hw->cfg.start, hw->cfg.size);
+ iounmap(hw->cfg.p);
+ } else
+ release_region(hw->cfg.start, hw->cfg.size);
+ hw->cfg.mode = AM_NONE;
+ }
+ if (hw->addr.mode) {
+ if (hw->addr.p) {
+ release_mem_region(hw->addr.start, hw->addr.size);
+ iounmap(hw->addr.p);
+ } else
+ release_region(hw->addr.start, hw->addr.size);
+ hw->addr.mode = AM_NONE;
+ }
+}
+
+static int __devinit
+setup_io(struct inf_hw *hw)
+{
+ int err = 0;
+
+ if (hw->ci->cfg_mode) {
+ hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);
+ hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);
+ if (hw->ci->cfg_mode == AM_MEMIO) {
+ if (!request_mem_region(hw->cfg.start, hw->cfg.size,
+ hw->name))
+ err = -EBUSY;
+ } else {
+ if (!request_region(hw->cfg.start, hw->cfg.size,
+ hw->name))
+ err = -EBUSY;
+ }
+ if (err) {
+ pr_info("mISDN: %s config port %lx (%lu bytes)"
+ "already in use\n", hw->name,
+ (ulong)hw->cfg.start, (ulong)hw->cfg.size);
+ return err;
+ }
+ if (hw->ci->cfg_mode == AM_MEMIO)
+ hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
+ hw->cfg.mode = hw->ci->cfg_mode;
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",
+ hw->name, (ulong)hw->cfg.start,
+ (ulong)hw->cfg.size, hw->ci->cfg_mode);
+
+ }
+ if (hw->ci->addr_mode) {
+ hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);
+ hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);
+ if (hw->ci->addr_mode == AM_MEMIO) {
+ if (!request_mem_region(hw->addr.start, hw->addr.size,
+ hw->name))
+ err = -EBUSY;
+ } else {
+ if (!request_region(hw->addr.start, hw->addr.size,
+ hw->name))
+ err = -EBUSY;
+ }
+ if (err) {
+ pr_info("mISDN: %s address port %lx (%lu bytes)"
+ "already in use\n", hw->name,
+ (ulong)hw->addr.start, (ulong)hw->addr.size);
+ return err;
+ }
+ if (hw->ci->addr_mode == AM_MEMIO)
+ hw->addr.p = ioremap(hw->addr.start, hw->addr.size);
+ hw->addr.mode = hw->ci->addr_mode;
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",
+ hw->name, (ulong)hw->addr.start,
+ (ulong)hw->addr.size, hw->ci->addr_mode);
+
+ }
+
+ switch (hw->ci->typ) {
+ case INF_DIVA20:
+ case INF_DIVA20U:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->isac.mode = hw->cfg.mode;
+ hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;
+ hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;
+ hw->hscx.mode = hw->cfg.mode;
+ hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;
+ hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;
+ break;
+ case INF_DIVA201:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.p = hw->addr.p;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.p = hw->addr.p;
+ break;
+ case INF_DIVA202:
+ hw->ipac.type = IPAC_TYPE_IPACX;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.p = hw->addr.p;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.p = hw->addr.p;
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->cfg.mode;
+ hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
+ hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
+ hw->hscx.mode = hw->cfg.mode;
+ hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
+ hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
+ outb(0xff, (ulong)hw->cfg.start);
+ mdelay(1);
+ outb(0x00, (ulong)hw->cfg.start);
+ mdelay(1);
+ outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);
+ break;
+ case INF_QS1000:
+ case INF_QS3000:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = (u32)hw->addr.start + 1;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = (u32)hw->addr.start;
+ hw->hscx.a.io.port = (u32)hw->addr.start + 1;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_NICCY:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;
+ hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;
+ hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;
+ break;
+ case INF_SCT_1:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_2:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_3:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_4:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_GAZEL_R685:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.port = (u32)hw->addr.start;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ break;
+ case INF_GAZEL_R753:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (hw->isac.mode) {
+ case AM_MEMIO:
+ ASSIGN_FUNC_IPAC(MIO, hw->ipac);
+ break;
+ case AM_IND_IO:
+ ASSIGN_FUNC_IPAC(IND, hw->ipac);
+ break;
+ case AM_IO:
+ ASSIGN_FUNC_IPAC(IO, hw->ipac);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+release_card(struct inf_hw *card) {
+ ulong flags;
+ int i;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->ipac.isac.release(&card->ipac.isac);
+ free_irq(card->irq, card);
+ mISDN_unregister_device(&card->ipac.isac.dch.dev);
+ release_io(card);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ switch (card->ci->typ) {
+ case INF_SCT_2:
+ case INF_SCT_3:
+ case INF_SCT_4:
+ break;
+ case INF_SCT_1:
+ for (i = 0; i < 3; i++) {
+ if (card->sc[i])
+ release_card(card->sc[i]);
+ card->sc[i] = NULL;
+ }
+ default:
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ break;
+ }
+ kfree(card);
+ inf_cnt--;
+}
+
+static int __devinit
+setup_instance(struct inf_hw *card)
+{
+ int err;
+ ulong flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,
+ inf_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->ipac.isac.name = card->name;
+ card->ipac.name = card->name;
+ card->ipac.owner = THIS_MODULE;
+ spin_lock_init(&card->lock);
+ card->ipac.isac.hwlock = &card->lock;
+ card->ipac.hwlock = &card->lock;
+ card->ipac.ctrl = (void *)&inf_ctrl;
+
+ err = setup_io(card);
+ if (err)
+ goto error_setup;
+
+ card->ipac.isac.dch.dev.Bprotocols =
+ mISDNipac_init(&card->ipac, card);
+
+ if (card->ipac.isac.dch.dev.Bprotocols == 0)
+ goto error_setup;;
+
+ err = mISDN_register_device(&card->ipac.isac.dch.dev,
+ &card->pdev->dev, card->name);
+ if (err)
+ goto error;
+
+ err = init_irq(card);
+ if (!err) {
+ inf_cnt++;
+ pr_notice("Infineon %d cards installed\n", inf_cnt);
+ return 0;
+ }
+ mISDN_unregister_device(&card->ipac.isac.dch.dev);
+error:
+ card->ipac.release(&card->ipac);
+error_setup:
+ release_io(card);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ return err;
+}
+
+static const struct inf_cinfo inf_card_info[] = {
+ {
+ INF_DIVA20,
+ "Dialogic Diva 2.0",
+ "diva20",
+ AM_IND_IO, AM_NONE, 2, 0,
+ &diva_irq
+ },
+ {
+ INF_DIVA20U,
+ "Dialogic Diva 2.0U",
+ "diva20U",
+ AM_IND_IO, AM_NONE, 2, 0,
+ &diva_irq
+ },
+ {
+ INF_DIVA201,
+ "Dialogic Diva 2.01",
+ "diva201",
+ AM_MEMIO, AM_MEMIO, 0, 1,
+ &diva20x_irq
+ },
+ {
+ INF_DIVA202,
+ "Dialogic Diva 2.02",
+ "diva202",
+ AM_MEMIO, AM_MEMIO, 0, 1,
+ &diva20x_irq
+ },
+ {
+ INF_SPEEDWIN,
+ "Sedlbauer SpeedWin PCI",
+ "speedwin",
+ AM_IND_IO, AM_NONE, 0, 0,
+ &tiger_irq
+ },
+ {
+ INF_SAPHIR3,
+ "HST Saphir 3",
+ "saphir",
+ AM_IND_IO, AM_NONE, 0, 0,
+ &tiger_irq
+ },
+ {
+ INF_QS1000,
+ "Develo Microlink PCI",
+ "qs1000",
+ AM_IO, AM_IND_IO, 1, 3,
+ &elsa_irq
+ },
+ {
+ INF_QS3000,
+ "Develo QuickStep 3000",
+ "qs3000",
+ AM_IO, AM_IND_IO, 1, 3,
+ &elsa_irq
+ },
+ {
+ INF_NICCY,
+ "Sagem NICCY",
+ "niccy",
+ AM_IO, AM_IND_IO, 0, 1,
+ &niccy_irq
+ },
+ {
+ INF_SCT_1,
+ "SciTel Quadro",
+ "p1_scitel",
+ AM_IO, AM_IND_IO, 1, 5,
+ &ipac_irq
+ },
+ {
+ INF_SCT_2,
+ "SciTel Quadro",
+ "p2_scitel",
+ AM_NONE, AM_IND_IO, 0, 4,
+ &ipac_irq
+ },
+ {
+ INF_SCT_3,
+ "SciTel Quadro",
+ "p3_scitel",
+ AM_NONE, AM_IND_IO, 0, 3,
+ &ipac_irq
+ },
+ {
+ INF_SCT_4,
+ "SciTel Quadro",
+ "p4_scitel",
+ AM_NONE, AM_IND_IO, 0, 2,
+ &ipac_irq
+ },
+ {
+ INF_GAZEL_R685,
+ "Gazel R685",
+ "gazel685",
+ AM_IO, AM_IO, 1, 2,
+ &gazel_irq
+ },
+ {
+ INF_GAZEL_R753,
+ "Gazel R753",
+ "gazel753",
+ AM_IO, AM_IND_IO, 1, 2,
+ &ipac_irq
+ },
+ {
+ INF_NONE,
+ }
+};
+
+static const struct inf_cinfo * __devinit
+get_card_info(enum inf_types typ)
+{
+ const struct inf_cinfo *ci = inf_card_info;
+
+ while (ci->typ != INF_NONE) {
+ if (ci->typ == typ)
+ return ci;
+ ci++;
+ }
+ return NULL;
+}
+
+static int __devinit
+inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct inf_hw *card;
+
+ card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
+ if (!card) {
+ pr_info("No memory for Infineon ISDN card\n");
+ return err;
+ }
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+ card->ci = get_card_info(ent->driver_data);
+ if (!card->ci) {
+ pr_info("mISDN: do not have informations about adapter at %s\n",
+ pci_name(pdev));
+ kfree(card);
+ return -EINVAL;
+ } else
+ pr_notice("mISDN: found adapter %s at %s\n",
+ card->ci->full, pci_name(pdev));
+
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err) {
+ pci_disable_device(card->pdev);
+ kfree(card);
+ pci_set_drvdata(pdev, NULL);
+ } else if (ent->driver_data == INF_SCT_1) {
+ int i;
+ struct inf_hw *sc;
+
+ for (i = 1; i < 4; i++) {
+ sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
+ if (!sc) {
+ release_card(card);
+ return -ENOMEM;
+ }
+ sc->irq = card->irq;
+ sc->pdev = card->pdev;
+ sc->ci = card->ci + i;
+ err = setup_instance(sc);
+ if (err) {
+ kfree(sc);
+ release_card(card);
+ } else
+ card->sc[i - 1] = sc;
+ }
+ }
+ return err;
+}
+
+static void __devexit
+inf_remove(struct pci_dev *pdev)
+{
+ struct inf_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ pr_debug("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_driver infineon_driver = {
+ .name = "ISDN Infineon pci",
+ .probe = inf_probe,
+ .remove = __devexit_p(inf_remove),
+ .id_table = infineon_ids,
+};
+
+static int __init
+infineon_init(void)
+{
+ int err;
+
+ pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);
+ err = pci_register_driver(&infineon_driver);
+ return err;
+}
+
+static void __exit
+infineon_cleanup(void)
+{
+ pci_unregister_driver(&infineon_driver);
+}
+
+module_init(infineon_init);
+module_exit(infineon_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
new file mode 100644
index 000000000000..613ba0435372
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -0,0 +1,1655 @@
+/*
+ * isac.c ISAC specific routines
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 1
+
+#define ISAC_REV "2.0"
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_VERSION(ISAC_REV);
+MODULE_LICENSE("GPL v2");
+
+#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off))
+#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v))
+#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o))
+#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v))
+#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o))
+#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v))
+
+static inline void
+ph_command(struct isac_hw *isac, u8 command)
+{
+ pr_debug("%s: ph_command %x\n", isac->name, command);
+ if (isac->type & IPAC_TYPE_ISACX)
+ WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);
+ else
+ WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+static void
+isac_ph_state_change(struct isac_hw *isac)
+{
+ switch (isac->state) {
+ case (ISAC_IND_RS):
+ case (ISAC_IND_EI):
+ ph_command(isac, ISAC_CMD_DUI);
+ }
+ schedule_event(&isac->dch, FLG_PHCHANGE);
+}
+
+static void
+isac_ph_state_bh(struct dchannel *dch)
+{
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+
+ switch (isac->state) {
+ case ISAC_IND_RS:
+ case ISAC_IND_EI:
+ dch->state = 0;
+ l1_event(dch->l1, HW_RESET_IND);
+ break;
+ case ISAC_IND_DID:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_CNF);
+ break;
+ case ISAC_IND_DR:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_IND);
+ break;
+ case ISAC_IND_PU:
+ dch->state = 4;
+ l1_event(dch->l1, HW_POWERUP_IND);
+ break;
+ case ISAC_IND_RSY:
+ if (dch->state <= 5) {
+ dch->state = 5;
+ l1_event(dch->l1, ANYSIGNAL);
+ } else {
+ dch->state = 8;
+ l1_event(dch->l1, LOSTFRAMING);
+ }
+ break;
+ case ISAC_IND_ARD:
+ dch->state = 6;
+ l1_event(dch->l1, INFO2);
+ break;
+ case ISAC_IND_AI8:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P8);
+ break;
+ case ISAC_IND_AI10:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P10);
+ break;
+ }
+ pr_debug("%s: TE newstate %x\n", isac->name, dch->state);
+}
+
+void
+isac_empty_fifo(struct isac_hw *isac, int count)
+{
+ u8 *ptr;
+
+ pr_debug("%s: %s %d\n", isac->name, __func__, count);
+
+ if (!isac->dch.rx_skb) {
+ isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);
+ if (!isac->dch.rx_skb) {
+ pr_info("%s: D receive out of memory\n", isac->name);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ return;
+ }
+ }
+ if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {
+ pr_debug("%s: %s overrun %d\n", isac->name, __func__,
+ isac->dch.rx_skb->len + count);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ return;
+ }
+ ptr = skb_put(isac->dch.rx_skb, count);
+ isac->read_fifo(isac->dch.hw, isac->off, ptr, count);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ if (isac->dch.debug & DEBUG_HW_DFIFO) {
+ char pfx[MISDN_MAX_IDLEN + 16];
+
+ snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",
+ isac->name, count);
+ print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+isac_fill_fifo(struct isac_hw *isac)
+{
+ int count, more;
+ u8 *ptr;
+
+ if (!isac->dch.tx_skb)
+ return;
+ count = isac->dch.tx_skb->len - isac->dch.tx_idx;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ pr_debug("%s: %s %d\n", isac->name, __func__, count);
+ ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;
+ isac->dch.tx_idx += count;
+ isac->write_fifo(isac->dch.hw, isac->off, ptr, count);
+ WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);
+ if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
+ pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);
+ del_timer(&isac->dch.timer);
+ }
+ init_timer(&isac->dch.timer);
+ isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+ add_timer(&isac->dch.timer);
+ if (isac->dch.debug & DEBUG_HW_DFIFO) {
+ char pfx[MISDN_MAX_IDLEN + 16];
+
+ snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",
+ isac->name, count);
+ print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+isac_rme_irq(struct isac_hw *isac)
+{
+ u8 val, count;
+
+ val = ReadISAC(isac, ISAC_RSTA);
+ if ((val & 0x70) != 0x20) {
+ if (val & 0x40) {
+ pr_debug("%s: ISAC RDO\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_rx++;
+#endif
+ }
+ if (!(val & 0x20)) {
+ pr_debug("%s: ISAC CRC error\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_crc++;
+#endif
+ }
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ if (isac->dch.rx_skb)
+ dev_kfree_skb(isac->dch.rx_skb);
+ isac->dch.rx_skb = NULL;
+ } else {
+ count = ReadISAC(isac, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(isac, count);
+ recv_Dchannel(&isac->dch);
+ }
+}
+
+static void
+isac_xpr_irq(struct isac_hw *isac)
+{
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
+ del_timer(&isac->dch.timer);
+ if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {
+ isac_fill_fifo(isac);
+ } else {
+ if (isac->dch.tx_skb)
+ dev_kfree_skb(isac->dch.tx_skb);
+ if (get_next_dframe(&isac->dch))
+ isac_fill_fifo(isac);
+ }
+}
+
+static void
+isac_retransmit(struct isac_hw *isac)
+{
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
+ del_timer(&isac->dch.timer);
+ if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {
+ /* Restart frame */
+ isac->dch.tx_idx = 0;
+ isac_fill_fifo(isac);
+ } else if (isac->dch.tx_skb) { /* should not happen */
+ pr_info("%s: tx_skb exist but not busy\n", isac->name);
+ test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);
+ isac->dch.tx_idx = 0;
+ isac_fill_fifo(isac);
+ } else {
+ pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);
+ if (get_next_dframe(&isac->dch))
+ isac_fill_fifo(isac);
+ }
+}
+
+static void
+isac_mos_irq(struct isac_hw *isac)
+{
+ u8 val;
+ int ret;
+
+ val = ReadISAC(isac, ISAC_MOSR);
+ pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);
+#if ARCOFI_USE
+ if (val & 0x08) {
+ if (!isac->mon_rx) {
+ isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
+ if (!isac->mon_rx) {
+ pr_info("%s: ISAC MON RX out of memory!\n",
+ isac->name);
+ isac->mocr &= 0xf0;
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ goto afterMONR0;
+ } else
+ isac->mon_rxp = 0;
+ }
+ if (isac->mon_rxp >= MAX_MON_FRAME) {
+ isac->mocr &= 0xf0;
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mon_rxp = 0;
+ pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
+ goto afterMONR0;
+ }
+ isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);
+ pr_debug("%s: ISAC MOR0 %02x\n", isac->name,
+ isac->mon_rx[isac->mon_rxp - 1]);
+ if (isac->mon_rxp == 1) {
+ isac->mocr |= 0x04;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ }
+ }
+afterMONR0:
+ if (val & 0x80) {
+ if (!isac->mon_rx) {
+ isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
+ if (!isac->mon_rx) {
+ pr_info("%s: ISAC MON RX out of memory!\n",
+ isac->name);
+ isac->mocr &= 0x0f;
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ goto afterMONR1;
+ } else
+ isac->mon_rxp = 0;
+ }
+ if (isac->mon_rxp >= MAX_MON_FRAME) {
+ isac->mocr &= 0x0f;
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mon_rxp = 0;
+ pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
+ goto afterMONR1;
+ }
+ isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);
+ pr_debug("%s: ISAC MOR1 %02x\n", isac->name,
+ isac->mon_rx[isac->mon_rxp - 1]);
+ isac->mocr |= 0x40;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ }
+afterMONR1:
+ if (val & 0x04) {
+ isac->mocr &= 0xf0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->monitor) {
+ ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,
+ isac->mon_rx, isac->mon_rxp);
+ if (ret)
+ kfree(isac->mon_rx);
+ } else {
+ pr_info("%s: MONITOR 0 received %d but no user\n",
+ isac->name, isac->mon_rxp);
+ kfree(isac->mon_rx);
+ }
+ isac->mon_rx = NULL;
+ isac->mon_rxp = 0;
+ }
+ if (val & 0x40) {
+ isac->mocr &= 0x0f;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->monitor) {
+ ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,
+ isac->mon_rx, isac->mon_rxp);
+ if (ret)
+ kfree(isac->mon_rx);
+ } else {
+ pr_info("%s: MONITOR 1 received %d but no user\n",
+ isac->name, isac->mon_rxp);
+ kfree(isac->mon_rx);
+ }
+ isac->mon_rx = NULL;
+ isac->mon_rxp = 0;
+ }
+ if (val & 0x02) {
+ if ((!isac->mon_tx) || (isac->mon_txc &&
+ (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
+ isac->mocr &= 0xf0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_0, NULL, 0);
+ }
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX0;
+ }
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_0, NULL, 0);
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX0;
+ }
+ WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);
+ pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,
+ isac->mon_tx[isac->mon_txp - 1]);
+ }
+AfterMOX0:
+ if (val & 0x20) {
+ if ((!isac->mon_tx) || (isac->mon_txc &&
+ (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
+ isac->mocr &= 0x0f;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_1, NULL, 0);
+ }
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX1;
+ }
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_1, NULL, 0);
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX1;
+ }
+ WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
+ pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,
+ isac->mon_tx[isac->mon_txp - 1]);
+ }
+AfterMOX1:
+ val = 0; /* dummy to avoid warning */
+#endif
+}
+
+static void
+isac_cisq_irq(struct isac_hw *isac) {
+ u8 val;
+
+ val = ReadISAC(isac, ISAC_CIR0);
+ pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);
+ if (val & 2) {
+ pr_debug("%s: ph_state change %x->%x\n", isac->name,
+ isac->state, (val >> 2) & 0xf);
+ isac->state = (val >> 2) & 0xf;
+ isac_ph_state_change(isac);
+ }
+ if (val & 1) {
+ val = ReadISAC(isac, ISAC_CIR1);
+ pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);
+ }
+}
+
+static void
+isacsx_cic_irq(struct isac_hw *isac)
+{
+ u8 val;
+
+ val = ReadISAC(isac, ISACX_CIR0);
+ pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
+ if (val & ISACX_CIR0_CIC0) {
+ pr_debug("%s: ph_state change %x->%x\n", isac->name,
+ isac->state, val >> 4);
+ isac->state = val >> 4;
+ isac_ph_state_change(isac);
+ }
+}
+
+static void
+isacsx_rme_irq(struct isac_hw *isac)
+{
+ int count;
+ u8 val;
+
+ val = ReadISAC(isac, ISACX_RSTAD);
+ if ((val & (ISACX_RSTAD_VFR |
+ ISACX_RSTAD_RDO |
+ ISACX_RSTAD_CRC |
+ ISACX_RSTAD_RAB))
+ != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {
+ pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);
+#ifdef ERROR_STATISTIC
+ if (val & ISACX_RSTAD_CRC)
+ isac->dch.err_rx++;
+ else
+ isac->dch.err_crc++;
+#endif
+ WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
+ if (isac->dch.rx_skb)
+ dev_kfree_skb(isac->dch.rx_skb);
+ isac->dch.rx_skb = NULL;
+ } else {
+ count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(isac, count);
+ if (isac->dch.rx_skb) {
+ skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);
+ pr_debug("%s: dchannel received %d\n", isac->name,
+ isac->dch.rx_skb->len);
+ recv_Dchannel(&isac->dch);
+ }
+ }
+}
+
+irqreturn_t
+mISDNisac_irq(struct isac_hw *isac, u8 val)
+{
+ if (unlikely(!val))
+ return IRQ_NONE;
+ pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);
+ if (isac->type & IPAC_TYPE_ISACX) {
+ if (val & ISACX__CIC)
+ isacsx_cic_irq(isac);
+ if (val & ISACX__ICD) {
+ val = ReadISAC(isac, ISACX_ISTAD);
+ pr_debug("%s: ISTAD %02x\n", isac->name, val);
+ if (val & ISACX_D_XDU) {
+ pr_debug("%s: ISAC XDU\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & ISACX_D_XMR) {
+ pr_debug("%s: ISAC XMR\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & ISACX_D_XPR)
+ isac_xpr_irq(isac);
+ if (val & ISACX_D_RFO) {
+ pr_debug("%s: ISAC RFO\n", isac->name);
+ WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
+ }
+ if (val & ISACX_D_RME)
+ isacsx_rme_irq(isac);
+ if (val & ISACX_D_RPF)
+ isac_empty_fifo(isac, 0x20);
+ }
+ } else {
+ if (val & 0x80) /* RME */
+ isac_rme_irq(isac);
+ if (val & 0x40) /* RPF */
+ isac_empty_fifo(isac, 32);
+ if (val & 0x10) /* XPR */
+ isac_xpr_irq(isac);
+ if (val & 0x04) /* CISQ */
+ isac_cisq_irq(isac);
+ if (val & 0x20) /* RSC - never */
+ pr_debug("%s: ISAC RSC interrupt\n", isac->name);
+ if (val & 0x02) /* SIN - never */
+ pr_debug("%s: ISAC SIN interrupt\n", isac->name);
+ if (val & 0x01) { /* EXI */
+ val = ReadISAC(isac, ISAC_EXIR);
+ pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);
+ if (val & 0x80) /* XMR */
+ pr_debug("%s: ISAC XMR\n", isac->name);
+ if (val & 0x40) { /* XDU */
+ pr_debug("%s: ISAC XDU\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & 0x04) /* MOS */
+ isac_mos_irq(isac);
+ }
+ }
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(mISDNisac_irq);
+
+static int
+isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ret = dchannel_senddata(dch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ isac_fill_fifo(isac);
+ ret = 0;
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ case PH_DEACTIVATE_REQ:
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ }
+
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para)
+{
+ u8 tl = 0;
+ u_long flags;
+
+ switch (cmd) {
+ case HW_TESTLOOP:
+ spin_lock_irqsave(isac->hwlock, flags);
+ if (!(isac->type & IPAC_TYPE_ISACX)) {
+ /* TODO: implement for IPAC_TYPE_ISACX */
+ if (para & 1) /* B1 */
+ tl |= 0x0c;
+ else if (para & 2) /* B2 */
+ tl |= 0x3;
+ /* we only support IOM2 mode */
+ WriteISAC(isac, ISAC_SPCR, tl);
+ if (tl)
+ WriteISAC(isac, ISAC_ADF1, 0x8);
+ else
+ WriteISAC(isac, ISAC_ADF1, 0x0);
+ }
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x %lx\n", isac->name,
+ __func__, cmd, para);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+isac_l1cmd(struct dchannel *dch, u32 cmd)
+{
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ u_long flags;
+
+ pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);
+ switch (cmd) {
+ case INFO3_P8:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_AR8);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case INFO3_P10:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_AR10);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case HW_RESET_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ if ((isac->state == ISAC_IND_EI) ||
+ (isac->state == ISAC_IND_DR) ||
+ (isac->state == ISAC_IND_RS))
+ ph_command(isac, ISAC_CMD_TIM);
+ else
+ ph_command(isac, ISAC_CMD_RS);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case HW_DEACT_REQ:
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+ break;
+ case HW_POWERUP_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_TIM);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case PH_ACTIVATE_IND:
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ case PH_DEACTIVATE_IND:
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n", isac->name,
+ __func__, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+isac_release(struct isac_hw *isac)
+{
+ if (isac->type & IPAC_TYPE_ISACX)
+ WriteISAC(isac, ISACX_MASK, 0xff);
+ else
+ WriteISAC(isac, ISAC_MASK, 0xff);
+ if (isac->dch.timer.function != NULL) {
+ del_timer(&isac->dch.timer);
+ isac->dch.timer.function = NULL;
+ }
+ kfree(isac->mon_rx);
+ isac->mon_rx = NULL;
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ if (isac->dch.l1)
+ l1_event(isac->dch.l1, CLOSE_CHANNEL);
+ mISDN_freedchannel(&isac->dch);
+}
+
+static void
+dbusy_timer_handler(struct isac_hw *isac)
+{
+ int rbch, star;
+ u_long flags;
+
+ if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
+ spin_lock_irqsave(isac->hwlock, flags);
+ rbch = ReadISAC(isac, ISAC_RBCH);
+ star = ReadISAC(isac, ISAC_STAR);
+ pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
+ isac->name, rbch, star);
+ if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);
+ else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);
+ if (isac->dch.tx_idx)
+ isac->dch.tx_idx = 0;
+ else
+ pr_info("%s: ISAC D-Channel Busy no tx_idx\n",
+ isac->name);
+ /* Transmitter reset */
+ WriteISAC(isac, ISAC_CMDR, 0x01);
+ }
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ }
+}
+
+static int
+open_dchannel(struct isac_hw *isac, struct channel_req *rq)
+{
+ pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,
+ isac->dch.dev.id, __builtin_return_address(1));
+ if (rq->protocol != ISDN_P_TE_S0)
+ return -EINVAL;
+ if (rq->adr.channel == 1)
+ /* E-Channel not supported */
+ return -EINVAL;
+ rq->ch = &isac->dch.dev.D;
+ rq->ch->protocol = rq->protocol;
+ if (isac->dch.state == 7)
+ _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ return 0;
+}
+
+static const char *ISACVer[] =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+static int
+isac_init(struct isac_hw *isac)
+{
+ u8 val;
+ int err = 0;
+
+ if (!isac->dch.l1) {
+ err = create_l1(&isac->dch, isac_l1cmd);
+ if (err)
+ return err;
+ }
+ isac->mon_tx = NULL;
+ isac->mon_rx = NULL;
+ isac->dch.timer.function = (void *) dbusy_timer_handler;
+ isac->dch.timer.data = (long)isac;
+ init_timer(&isac->dch.timer);
+ isac->mocr = 0xaa;
+ if (isac->type & IPAC_TYPE_ISACX) {
+ /* Disable all IRQ */
+ WriteISAC(isac, ISACX_MASK, 0xff);
+ val = ReadISAC(isac, ISACX_STARD);
+ pr_debug("%s: ISACX STARD %x\n", isac->name, val);
+ val = ReadISAC(isac, ISACX_ISTAD);
+ pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);
+ val = ReadISAC(isac, ISACX_ISTA);
+ pr_debug("%s: ISACX ISTA %x\n", isac->name, val);
+ /* clear LDD */
+ WriteISAC(isac, ISACX_TR_CONF0, 0x00);
+ /* enable transmitter */
+ WriteISAC(isac, ISACX_TR_CONF2, 0x00);
+ /* transparent mode 0, RAC, stop/go */
+ WriteISAC(isac, ISACX_MODED, 0xc9);
+ /* all HDLC IRQ unmasked */
+ val = ReadISAC(isac, ISACX_ID);
+ if (isac->dch.debug & DEBUG_HW)
+ pr_notice("%s: ISACX Design ID %x\n",
+ isac->name, val & 0x3f);
+ val = ReadISAC(isac, ISACX_CIR0);
+ pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
+ isac->state = val >> 4;
+ isac_ph_state_change(isac);
+ ph_command(isac, ISAC_CMD_RS);
+ WriteISAC(isac, ISACX_MASK, IPACX__ON);
+ WriteISAC(isac, ISACX_MASKD, 0x00);
+ } else { /* old isac */
+ WriteISAC(isac, ISAC_MASK, 0xff);
+ val = ReadISAC(isac, ISAC_STAR);
+ pr_debug("%s: ISAC STAR %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_MODE);
+ pr_debug("%s: ISAC MODE %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_ADF2);
+ pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISAC ISTA %x\n", isac->name, val);
+ if (val & 0x01) {
+ val = ReadISAC(isac, ISAC_EXIR);
+ pr_debug("%s: ISAC EXIR %x\n", isac->name, val);
+ }
+ val = ReadISAC(isac, ISAC_RBCH);
+ if (isac->dch.debug & DEBUG_HW)
+ pr_notice("%s: ISAC version (%x): %s\n", isac->name,
+ val, ISACVer[(val >> 5) & 3]);
+ isac->type |= ((val >> 5) & 3);
+ if (!isac->adf2)
+ isac->adf2 = 0x80;
+ if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */
+ pr_info("%s: only support IOM2 mode but adf2=%02x\n",
+ isac->name, isac->adf2);
+ isac_release(isac);
+ return -EINVAL;
+ }
+ WriteISAC(isac, ISAC_ADF2, isac->adf2);
+ WriteISAC(isac, ISAC_SQXR, 0x2f);
+ WriteISAC(isac, ISAC_SPCR, 0x00);
+ WriteISAC(isac, ISAC_STCR, 0x70);
+ WriteISAC(isac, ISAC_MODE, 0xc9);
+ WriteISAC(isac, ISAC_TIMR, 0x00);
+ WriteISAC(isac, ISAC_ADF1, 0x00);
+ val = ReadISAC(isac, ISAC_CIR0);
+ pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);
+ isac->state = (val >> 2) & 0xf;
+ isac_ph_state_change(isac);
+ ph_command(isac, ISAC_CMD_RS);
+ WriteISAC(isac, ISAC_MASK, 0);
+ }
+ return err;
+}
+
+int
+mISDNisac_init(struct isac_hw *isac, void *hw)
+{
+ mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);
+ isac->dch.hw = hw;
+ isac->dch.dev.D.send = isac_l1hw;
+ isac->init = isac_init;
+ isac->release = isac_release;
+ isac->ctrl = isac_ctrl;
+ isac->open = open_dchannel;
+ isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
+ isac->dch.dev.nrbchan = 2;
+ return 0;
+}
+EXPORT_SYMBOL(mISDNisac_init);
+
+static void
+waitforCEC(struct hscx_hw *hx)
+{
+ u8 starb, to = 50;
+
+ while (to) {
+ starb = ReadHSCX(hx, IPAC_STARB);
+ if (!(starb & 0x04))
+ break;
+ udelay(1);
+ to--;
+ }
+ if (to < 50)
+ pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,
+ 50 - to);
+ if (!to)
+ pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);
+}
+
+
+static void
+waitforXFW(struct hscx_hw *hx)
+{
+ u8 starb, to = 50;
+
+ while (to) {
+ starb = ReadHSCX(hx, IPAC_STARB);
+ if ((starb & 0x44) == 0x40)
+ break;
+ udelay(1);
+ to--;
+ }
+ if (to < 50)
+ pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,
+ 50 - to);
+ if (!to)
+ pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);
+}
+
+static void
+hscx_cmdr(struct hscx_hw *hx, u8 cmd)
+{
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ WriteHSCX(hx, IPACX_CMDRB, cmd);
+ else {
+ waitforCEC(hx);
+ WriteHSCX(hx, IPAC_CMDRB, cmd);
+ }
+}
+
+static void
+hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
+{
+ u8 *p;
+
+ pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
+ if (!hscx->bch.rx_skb) {
+ hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
+ if (!hscx->bch.rx_skb) {
+ pr_info("%s: B receive out of memory\n",
+ hscx->ip->name);
+ hscx_cmdr(hscx, 0x80); /* RMC */
+ return;
+ }
+ }
+ if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
+ pr_debug("%s: overrun %d\n", hscx->ip->name,
+ hscx->bch.rx_skb->len + count);
+ skb_trim(hscx->bch.rx_skb, 0);
+ hscx_cmdr(hscx, 0x80); /* RMC */
+ return;
+ }
+ p = skb_put(hscx->bch.rx_skb, count);
+
+ if (hscx->ip->type & IPAC_TYPE_IPACX)
+ hscx->ip->read_fifo(hscx->ip->hw,
+ hscx->off + IPACX_RFIFOB, p, count);
+ else
+ hscx->ip->read_fifo(hscx->ip->hw,
+ hscx->off, p, count);
+
+ hscx_cmdr(hscx, 0x80); /* RMC */
+
+ if (hscx->bch.debug & DEBUG_HW_BFIFO) {
+ snprintf(hscx->log, 64, "B%1d-recv %s %d ",
+ hscx->bch.nr, hscx->ip->name, count);
+ print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hscx_fill_fifo(struct hscx_hw *hscx)
+{
+ int count, more;
+ u8 *p;
+
+ if (!hscx->bch.tx_skb)
+ return;
+ count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
+ if (count <= 0)
+ return;
+ p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
+
+ more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
+ if (count > hscx->fifo_size) {
+ count = hscx->fifo_size;
+ more = 1;
+ }
+ pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count,
+ hscx->bch.tx_idx, hscx->bch.tx_skb->len);
+ hscx->bch.tx_idx += count;
+
+ if (hscx->ip->type & IPAC_TYPE_IPACX)
+ hscx->ip->write_fifo(hscx->ip->hw,
+ hscx->off + IPACX_XFIFOB, p, count);
+ else {
+ waitforXFW(hscx);
+ hscx->ip->write_fifo(hscx->ip->hw,
+ hscx->off, p, count);
+ }
+ hscx_cmdr(hscx, more ? 0x08 : 0x0a);
+
+ if (hscx->bch.debug & DEBUG_HW_BFIFO) {
+ snprintf(hscx->log, 64, "B%1d-send %s %d ",
+ hscx->bch.nr, hscx->ip->name, count);
+ print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hscx_xpr(struct hscx_hw *hx)
+{
+ if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len)
+ hscx_fill_fifo(hx);
+ else {
+ if (hx->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))
+ confirm_Bsend(&hx->bch);
+ dev_kfree_skb(hx->bch.tx_skb);
+ }
+ if (get_next_bframe(&hx->bch))
+ hscx_fill_fifo(hx);
+ }
+}
+
+static void
+ipac_rme(struct hscx_hw *hx)
+{
+ int count;
+ u8 rstab;
+
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ rstab = ReadHSCX(hx, IPACX_RSTAB);
+ else
+ rstab = ReadHSCX(hx, IPAC_RSTAB);
+ pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);
+ if ((rstab & 0xf0) != 0xa0) {
+ /* !(VFR && !RDO && CRC && !RAB) */
+ if (!(rstab & 0x80)) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d invalid frame\n",
+ hx->ip->name, hx->bch.nr);
+ }
+ if (rstab & 0x40) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d RDO proto=%x\n",
+ hx->ip->name, hx->bch.nr,
+ hx->bch.state);
+ }
+ if (!(rstab & 0x20)) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d CRC error\n",
+ hx->ip->name, hx->bch.nr);
+ }
+ hscx_cmdr(hx, 0x80); /* Do RMC */
+ return;
+ }
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ count = ReadHSCX(hx, IPACX_RBCLB);
+ else
+ count = ReadHSCX(hx, IPAC_RBCLB);
+ count &= (hx->fifo_size - 1);
+ if (count == 0)
+ count = hx->fifo_size;
+ hscx_empty_fifo(hx, count);
+ if (!hx->bch.rx_skb)
+ return;
+ if (hx->bch.rx_skb->len < 2) {
+ pr_debug("%s: B%1d frame to short %d\n",
+ hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);
+ skb_trim(hx->bch.rx_skb, 0);
+ } else {
+ skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);
+ recv_Bchannel(&hx->bch, 0);
+ }
+}
+
+static void
+ipac_irq(struct hscx_hw *hx, u8 ista)
+{
+ u8 istab, m, exirb = 0;
+
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ istab = ReadHSCX(hx, IPACX_ISTAB);
+ else if (hx->ip->type & IPAC_TYPE_IPAC) {
+ istab = ReadHSCX(hx, IPAC_ISTAB);
+ m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;
+ if (m & ista) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ } else if (hx->bch.nr & 2) { /* HSCX B */
+ if (ista & (HSCX__EXA | HSCX__ICA))
+ ipac_irq(&hx->ip->hscx[0], ista);
+ if (ista & HSCX__EXB) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ istab = ista & 0xF8;
+ } else { /* HSCX A */
+ istab = ReadHSCX(hx, IPAC_ISTAB);
+ if (ista & HSCX__EXA) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ istab = istab & 0xF8;
+ }
+ if (exirb & IPAC_B_XDU)
+ istab |= IPACX_B_XDU;
+ if (exirb & IPAC_B_RFO)
+ istab |= IPACX_B_RFO;
+ pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);
+
+ if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))
+ return;
+
+ if (istab & IPACX_B_RME)
+ ipac_rme(hx);
+
+ if (istab & IPACX_B_RPF) {
+ hscx_empty_fifo(hx, hx->fifo_size);
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
+ /* receive transparent audio data */
+ if (hx->bch.rx_skb)
+ recv_Bchannel(&hx->bch, 0);
+ }
+ }
+
+ if (istab & IPACX_B_RFO) {
+ pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);
+ hscx_cmdr(hx, 0x40); /* RRES */
+ }
+
+ if (istab & IPACX_B_XPR)
+ hscx_xpr(hx);
+
+ if (istab & IPACX_B_XDU) {
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
+ hscx_fill_fifo(hx);
+ return;
+ }
+ pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,
+ hx->bch.nr, hx->bch.tx_idx);
+ hx->bch.tx_idx = 0;
+ hscx_cmdr(hx, 0x01); /* XRES */
+ }
+}
+
+irqreturn_t
+mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
+{
+ int cnt = maxloop + 1;
+ u8 ista, istad;
+ struct isac_hw *isac = &ipac->isac;
+
+ if (ipac->type & IPAC_TYPE_IPACX) {
+ ista = ReadIPAC(ipac, ISACX_ISTA);
+ while (ista && cnt--) {
+ pr_debug("%s: ISTA %02x\n", ipac->name, ista);
+ if (ista & IPACX__ICA)
+ ipac_irq(&ipac->hscx[0], ista);
+ if (ista & IPACX__ICB)
+ ipac_irq(&ipac->hscx[1], ista);
+ if (ista & (ISACX__ICD | ISACX__CIC))
+ mISDNisac_irq(&ipac->isac, ista);
+ ista = ReadIPAC(ipac, ISACX_ISTA);
+ }
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ ista = ReadIPAC(ipac, IPAC_ISTA);
+ while (ista && cnt--) {
+ pr_debug("%s: ISTA %02x\n", ipac->name, ista);
+ if (ista & (IPAC__ICD | IPAC__EXD)) {
+ istad = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
+ if (istad & IPAC_D_TIN2)
+ pr_debug("%s TIN2 irq\n", ipac->name);
+ if (ista & IPAC__EXD)
+ istad |= 1; /* ISAC EXI */
+ mISDNisac_irq(isac, istad);
+ }
+ if (ista & (IPAC__ICA | IPAC__EXA))
+ ipac_irq(&ipac->hscx[0], ista);
+ if (ista & (IPAC__ICB | IPAC__EXB))
+ ipac_irq(&ipac->hscx[1], ista);
+ ista = ReadIPAC(ipac, IPAC_ISTA);
+ }
+ } else if (ipac->type & IPAC_TYPE_HSCX) {
+ while (cnt) {
+ ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
+ pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
+ if (ista)
+ ipac_irq(&ipac->hscx[1], ista);
+ istad = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
+ if (istad)
+ mISDNisac_irq(isac, istad);
+ if (0 == (ista | istad))
+ break;
+ cnt--;
+ }
+ }
+ if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
+ return IRQ_NONE;
+ if (cnt < maxloop)
+ pr_debug("%s: %d irqloops cpu%d\n", ipac->name,
+ maxloop - cnt, smp_processor_id());
+ if (maxloop && !cnt)
+ pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,
+ maxloop, smp_processor_id());
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(mISDNipac_irq);
+
+static int
+hscx_mode(struct hscx_hw *hscx, u32 bprotocol)
+{
+ pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,
+ '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);
+ if (hscx->ip->type & IPAC_TYPE_IPACX) {
+ if (hscx->bch.nr & 1) { /* B1 and ICA */
+ WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);
+ WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);
+ } else { /* B2 and ICB */
+ WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);
+ WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);
+ }
+ switch (bprotocol) {
+ case ISDN_P_NONE: /* init */
+ WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */
+ WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */
+ WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */
+ hscx_cmdr(hscx, 0x41);
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */
+ WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */
+ WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ WriteHSCX(hscx, IPAC_CCR2, 0x30);
+ WriteHSCX(hscx, IPAC_XCCR, 0x07);
+ WriteHSCX(hscx, IPAC_RCCR, 0x07);
+ WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
+ WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
+ switch (bprotocol) {
+ case ISDN_P_NONE:
+ WriteHSCX(hscx, IPAC_TSAX, 0x1F);
+ WriteHSCX(hscx, IPAC_TSAR, 0x1F);
+ WriteHSCX(hscx, IPAC_MODEB, 0x84);
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPAC_MODEB, 0x8c);
+ WriteHSCX(hscx, IPAC_CCR1, 0x8a);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ WriteHSCX(hscx, IPAC_CCR2, 0x30);
+ WriteHSCX(hscx, IPAC_XCCR, 0x07);
+ WriteHSCX(hscx, IPAC_RCCR, 0x07);
+ WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
+ WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
+ switch (bprotocol) {
+ case ISDN_P_NONE:
+ WriteHSCX(hscx, IPAC_TSAX, 0x1F);
+ WriteHSCX(hscx, IPAC_TSAR, 0x1F);
+ WriteHSCX(hscx, IPAC_MODEB, 0x84);
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPAC_MODEB, 0x8c);
+ WriteHSCX(hscx, IPAC_CCR1, 0x8d);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else
+ return -EINVAL;
+ hscx->bch.state = bprotocol;
+ return 0;
+}
+
+static int
+hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ hscx_fill_fifo(hx);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = hscx_mode(hx, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ mISDN_clear_bchannel(bch);
+ hscx_mode(hx, ISDN_P_NONE);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ hx->ip->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ mISDN_freebchannel(bch);
+ hscx_mode(hx, ISDN_P_NONE);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(hx->ip->owner);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ hx->ip->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static void
+free_ipac(struct ipac_hw *ipac)
+{
+ isac_release(&ipac->isac);
+}
+
+static const char *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+
+
+static void
+hscx_init(struct hscx_hw *hx)
+{
+ u8 val;
+
+ WriteHSCX(hx, IPAC_RAH2, 0xFF);
+ WriteHSCX(hx, IPAC_XBCH, 0x00);
+ WriteHSCX(hx, IPAC_RLCR, 0x00);
+
+ if (hx->ip->type & IPAC_TYPE_HSCX) {
+ WriteHSCX(hx, IPAC_CCR1, 0x85);
+ val = ReadHSCX(hx, HSCX_VSTR);
+ pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);
+ if (hx->bch.debug & DEBUG_HW)
+ pr_notice("%s: HSCX version %s\n", hx->ip->name,
+ HSCXVer[val & 0x0f]);
+ } else
+ WriteHSCX(hx, IPAC_CCR1, 0x82);
+ WriteHSCX(hx, IPAC_CCR2, 0x30);
+ WriteHSCX(hx, IPAC_XCCR, 0x07);
+ WriteHSCX(hx, IPAC_RCCR, 0x07);
+}
+
+static int
+ipac_init(struct ipac_hw *ipac)
+{
+ u8 val;
+
+ if (ipac->type & IPAC_TYPE_HSCX) {
+ hscx_init(&ipac->hscx[0]);
+ hscx_init(&ipac->hscx[1]);
+ val = ReadIPAC(ipac, IPAC_ID);
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ hscx_init(&ipac->hscx[0]);
+ hscx_init(&ipac->hscx[1]);
+ WriteIPAC(ipac, IPAC_MASK, IPAC__ON);
+ val = ReadIPAC(ipac, IPAC_CONF);
+ /* conf is default 0, but can be overwritten by card setup */
+ pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,
+ val, ipac->conf);
+ WriteIPAC(ipac, IPAC_CONF, ipac->conf);
+ val = ReadIPAC(ipac, IPAC_ID);
+ if (ipac->hscx[0].bch.debug & DEBUG_HW)
+ pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);
+ }
+ /* nothing special for IPACX to do here */
+ return isac_init(&ipac->isac);
+}
+
+static int
+open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &ipac->hscx[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+static int
+channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = open_dchannel(isac, rq);
+ else
+ err = open_bchannel(ipac, rq);
+ if (err)
+ break;
+ if (!try_module_get(ipac->owner))
+ pr_info("%s: cannot get module\n", ipac->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", ipac->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(ipac->owner);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(ipac, arg);
+ break;
+ default:
+ pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+u32
+mISDNipac_init(struct ipac_hw *ipac, void *hw)
+{
+ u32 ret;
+ u8 i;
+
+ ipac->hw = hw;
+ if (ipac->isac.dch.debug & DEBUG_HW)
+ pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);
+ if (ipac->type & IPAC_TYPE_HSCX) {
+ ipac->isac.type = IPAC_TYPE_ISAC;
+ ipac->hscx[0].off = 0;
+ ipac->hscx[1].off = 0x40;
+ ipac->hscx[0].fifo_size = 32;
+ ipac->hscx[1].fifo_size = 32;
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;
+ ipac->hscx[0].off = 0;
+ ipac->hscx[1].off = 0x40;
+ ipac->hscx[0].fifo_size = 64;
+ ipac->hscx[1].fifo_size = 64;
+ } else if (ipac->type & IPAC_TYPE_IPACX) {
+ ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;
+ ipac->hscx[0].off = IPACX_OFF_ICA;
+ ipac->hscx[1].off = IPACX_OFF_ICB;
+ ipac->hscx[0].fifo_size = 64;
+ ipac->hscx[1].fifo_size = 64;
+ } else
+ return 0;
+
+ mISDNisac_init(&ipac->isac, hw);
+
+ ipac->isac.dch.dev.D.ctrl = ipac_dctrl;
+
+ for (i = 0; i < 2; i++) {
+ ipac->hscx[i].bch.nr = i + 1;
+ set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
+ list_add(&ipac->hscx[i].bch.ch.list,
+ &ipac->isac.dch.dev.bchannels);
+ mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM);
+ ipac->hscx[i].bch.ch.nr = i + 1;
+ ipac->hscx[i].bch.ch.send = &hscx_l2l1;
+ ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
+ ipac->hscx[i].bch.hw = hw;
+ ipac->hscx[i].ip = ipac;
+ /* default values for IOM time slots
+ * can be overwriten by card */
+ ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;
+ }
+
+ ipac->init = ipac_init;
+ ipac->release = free_ipac;
+
+ ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ return ret;
+}
+EXPORT_SYMBOL(mISDNipac_init);
+
+static int __init
+isac_mod_init(void)
+{
+ pr_notice("mISDNipac module version %s\n", ISAC_REV);
+ return 0;
+}
+
+static void __exit
+isac_mod_cleanup(void)
+{
+ pr_notice("mISDNipac module unloaded\n");
+}
+module_init(isac_mod_init);
+module_exit(isac_mod_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
new file mode 100644
index 000000000000..de352a17673a
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -0,0 +1,1726 @@
+/*
+ * mISDNisar.c ISAR (Siemens PSB 7110) specific functions
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* define this to enable static debug messages, if you kernel supports
+ * dynamic debugging, you should use debugfs for this
+ */
+/* #define DEBUG */
+
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/mISDNhw.h>
+#include "isar.h"
+
+#define ISAR_REV "2.1"
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ISAR_REV);
+
+#define DEBUG_HW_FIRMWARE_FIFO 0x10000
+
+static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146";
+static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121,
+ 122, 145, 146};
+#define FAXMODCNT 13
+
+static void isar_setup(struct isar_hw *);
+
+static inline int
+waitforHIA(struct isar_hw *isar, int timeout)
+{
+ int t = timeout;
+ u8 val = isar->read_reg(isar->hw, ISAR_HIA);
+
+ while ((val & 1) && t) {
+ udelay(1);
+ t--;
+ val = isar->read_reg(isar->hw, ISAR_HIA);
+ }
+ pr_debug("%s: HIA after %dus\n", isar->name, timeout - t);
+ return timeout;
+}
+
+/*
+ * send msg to ISAR mailbox
+ * if msg is NULL use isar->buf
+ */
+static int
+send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg)
+{
+ if (!waitforHIA(isar, 1000))
+ return 0;
+ pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len);
+ isar->write_reg(isar->hw, ISAR_CTRL_H, creg);
+ isar->write_reg(isar->hw, ISAR_CTRL_L, len);
+ isar->write_reg(isar->hw, ISAR_WADR, 0);
+ if (!msg)
+ msg = isar->buf;
+ if (msg && len) {
+ isar->write_fifo(isar->hw, ISAR_MBOX, msg, len);
+ if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
+ int l = 0;
+
+ while (l < (int)len) {
+ hex_dump_to_buffer(msg + l, len - l, 32, 1,
+ isar->log, 256, 1);
+ pr_debug("%s: %s %02x: %s\n", isar->name,
+ __func__, l, isar->log);
+ l += 32;
+ }
+ }
+ }
+ isar->write_reg(isar->hw, ISAR_HIS, his);
+ waitforHIA(isar, 1000);
+ return 1;
+}
+
+/*
+ * receive message from ISAR mailbox
+ * if msg is NULL use isar->buf
+ */
+static void
+rcv_mbox(struct isar_hw *isar, u8 *msg)
+{
+ if (!msg)
+ msg = isar->buf;
+ isar->write_reg(isar->hw, ISAR_RADR, 0);
+ if (msg && isar->clsb) {
+ isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb);
+ if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
+ int l = 0;
+
+ while (l < (int)isar->clsb) {
+ hex_dump_to_buffer(msg + l, isar->clsb - l, 32,
+ 1, isar->log, 256, 1);
+ pr_debug("%s: %s %02x: %s\n", isar->name,
+ __func__, l, isar->log);
+ l += 32;
+ }
+ }
+ }
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+}
+
+static inline void
+get_irq_infos(struct isar_hw *isar)
+{
+ isar->iis = isar->read_reg(isar->hw, ISAR_IIS);
+ isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H);
+ isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L);
+ pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name,
+ isar->iis, isar->cmsb, isar->clsb);
+}
+
+/*
+ * poll answer message from ISAR mailbox
+ * should be used only with ISAR IRQs disabled before DSP was started
+ *
+ */
+static int
+poll_mbox(struct isar_hw *isar, int maxdelay)
+{
+ int t = maxdelay;
+ u8 irq;
+
+ irq = isar->read_reg(isar->hw, ISAR_IRQBIT);
+ while (t && !(irq & ISAR_IRQSTA)) {
+ udelay(1);
+ t--;
+ }
+ if (t) {
+ get_irq_infos(isar);
+ rcv_mbox(isar, NULL);
+ }
+ pr_debug("%s: pulled %d bytes after %d us\n",
+ isar->name, isar->clsb, maxdelay - t);
+ return t;
+}
+
+static int
+ISARVersion(struct isar_hw *isar)
+{
+ int ver;
+
+ /* disable ISAR IRQ */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ isar->buf[0] = ISAR_MSG_HWVER;
+ isar->buf[1] = 0;
+ isar->buf[2] = 1;
+ if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL))
+ return -1;
+ if (!poll_mbox(isar, 1000))
+ return -2;
+ if (isar->iis == ISAR_IIS_VNR) {
+ if (isar->clsb == 1) {
+ ver = isar->buf[0] & 0xf;
+ return ver;
+ }
+ return -3;
+ }
+ return -4;
+}
+
+static int
+load_firmware(struct isar_hw *isar, const u8 *buf, int size)
+{
+ u32 saved_debug = isar->ch[0].bch.debug;
+ int ret, cnt;
+ u8 nom, noc;
+ u16 left, val, *sp = (u16 *)buf;
+ u8 *mp;
+ u_long flags;
+
+ struct {
+ u16 sadr;
+ u16 len;
+ u16 d_key;
+ } blk_head;
+
+ if (1 != isar->version) {
+ pr_err("%s: ISAR wrong version %d firmware download aborted\n",
+ isar->name, isar->version);
+ return -EINVAL;
+ }
+ if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO))
+ isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO;
+ pr_debug("%s: load firmware %d words (%d bytes)\n",
+ isar->name, size/2, size);
+ cnt = 0;
+ size /= 2;
+ /* disable ISAR IRQ */
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ while (cnt < size) {
+ blk_head.sadr = le16_to_cpu(*sp++);
+ blk_head.len = le16_to_cpu(*sp++);
+ blk_head.d_key = le16_to_cpu(*sp++);
+ cnt += 3;
+ pr_debug("ISAR firmware block (%#x,%d,%#x)\n",
+ blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
+ left = blk_head.len;
+ if (cnt + left > size) {
+ pr_info("%s: firmware error have %d need %d words\n",
+ isar->name, size, cnt + left);
+ ret = -EINVAL;
+ goto reterrflg;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff,
+ 0, NULL)) {
+ pr_info("ISAR send_mbox dkey failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_warning("ISAR poll_mbox dkey failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong dkey response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = 1;
+ goto reterrflg;
+ }
+ while (left > 0) {
+ if (left > 126)
+ noc = 126;
+ else
+ noc = left;
+ nom = (2 * noc) + 3;
+ mp = isar->buf;
+ /* the ISAR is big endian */
+ *mp++ = blk_head.sadr >> 8;
+ *mp++ = blk_head.sadr & 0xFF;
+ left -= noc;
+ cnt += noc;
+ *mp++ = noc;
+ pr_debug("%s: load %3d words at %04x\n", isar->name,
+ noc, blk_head.sadr);
+ blk_head.sadr += noc;
+ while (noc) {
+ val = le16_to_cpu(*sp++);
+ *mp++ = val >> 8;
+ *mp++ = val & 0xFF;;
+ noc--;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) {
+ pr_info("ISAR send_mbox prog failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_info("ISAR poll_mbox prog failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ if ((isar->iis != ISAR_IIS_FIRM) ||
+ isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong prog response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ }
+ pr_debug("%s: ISAR firmware block %d words loaded\n",
+ isar->name, blk_head.len);
+ }
+ isar->ch[0].bch.debug = saved_debug;
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ mdelay(1);
+ isar->buf[0] = 0xff;
+ isar->buf[1] = 0xfe;
+ isar->bstat = 0;
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) {
+ pr_info("ISAR send_mbox start dsp failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_info("ISAR poll_mbox start dsp failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong start dsp response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = -EIO;
+ goto reterror;
+ } else
+ pr_debug("%s: ISAR start dsp success\n", isar->name);
+
+ /* NORMAL mode entered */
+ /* Enable IRQs of ISAR */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 1000; /* max 1s */
+ while ((!isar->bstat) && cnt) {
+ mdelay(1);
+ cnt--;
+ }
+ if (!cnt) {
+ pr_info("ISAR no general status event received\n");
+ ret = -ETIME;
+ goto reterrflg;
+ } else
+ pr_debug("%s: ISAR general status event %x\n",
+ isar->name, isar->bstat);
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ mdelay(1);
+ isar->iis = 0;
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
+ pr_info("ISAR send_mbox self tst failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 10000; /* max 100 ms */
+ while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
+ udelay(10);
+ cnt--;
+ }
+ mdelay(1);
+ if (!cnt) {
+ pr_info("ISAR no self tst response\n");
+ ret = -ETIME;
+ goto reterrflg;
+ }
+ if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1)
+ && (isar->buf[0] == 0))
+ pr_debug("%s: ISAR selftest OK\n", isar->name);
+ else {
+ pr_info("ISAR selftest not OK %x/%x/%x\n",
+ isar->cmsb, isar->clsb, isar->buf[0]);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar->iis = 0;
+ if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
+ pr_info("ISAR RQST SVN failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 30000; /* max 300 ms */
+ while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
+ udelay(10);
+ cnt--;
+ }
+ mdelay(1);
+ if (!cnt) {
+ pr_info("ISAR no SVN response\n");
+ ret = -ETIME;
+ goto reterrflg;
+ } else {
+ if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) {
+ pr_notice("%s: ISAR software version %#x\n",
+ isar->name, isar->buf[0]);
+ } else {
+ pr_info("%s: ISAR wrong swver response (%x,%x)"
+ " cnt(%d)\n", isar->name, isar->cmsb,
+ isar->clsb, cnt);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar_setup(isar);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ ret = 0;
+reterrflg:
+ spin_lock_irqsave(isar->hwlock, flags);
+reterror:
+ isar->ch[0].bch.debug = saved_debug;
+ if (ret)
+ /* disable ISAR IRQ */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ return ret;
+}
+
+static inline void
+deliver_status(struct isar_ch *ch, int status)
+{
+ pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status);
+ _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC);
+}
+
+static inline void
+isar_rcv_frame(struct isar_ch *ch)
+{
+ u8 *ptr;
+
+ if (!ch->is->clsb) {
+ pr_debug("%s; ISAR zero len frame\n", ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ return;
+ }
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n",
+ ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ case ISDN_P_B_MODEM_ASYNC:
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
+ recv_Bchannel(&ch->bch, 0);
+ break;
+ case ISDN_P_B_HDLC:
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ if ((ch->bch.rx_skb->len + ch->is->clsb) >
+ (ch->bch.maxlen + 2)) {
+ pr_debug("%s: incoming packet too large\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_ERROR) {
+ pr_debug("%s: ISAR frame error %x len %d\n",
+ ch->is->name, ch->is->cmsb, ch->is->clsb);
+#ifdef ERROR_STATISTIC
+ if (ch->is->cmsb & HDLC_ERR_RER)
+ ch->bch.err_inv++;
+ if (ch->is->cmsb & HDLC_ERR_CER)
+ ch->bch.err_crc++;
+#endif
+ skb_trim(ch->bch.rx_skb, 0);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_FSD)
+ skb_trim(ch->bch.rx_skb, 0);
+ ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
+ rcv_mbox(ch->is, ptr);
+ if (ch->is->cmsb & HDLC_FED) {
+ if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
+ pr_debug("%s: ISAR frame to short %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
+ recv_Bchannel(&ch->bch, 0);
+ }
+ break;
+ case ISDN_P_B_T30_FAX:
+ if (ch->state != STFAX_ACTIV) {
+ pr_debug("%s: isar_rcv_frame: not ACTIV\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ __func__);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ if (ch->cmd == PCTRL_CMD_FRM) {
+ rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
+ pr_debug("%s: isar_rcv_frame: %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ if (ch->is->cmsb & SART_NMD) { /* ABORT */
+ pr_debug("%s: isar_rcv_frame: no more data\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ ch->state = STFAX_ESCAPE;
+ /* set_skb_flag(skb, DF_NOMOREDATA); */
+ }
+ recv_Bchannel(&ch->bch, 0);
+ if (ch->is->cmsb & SART_NMD)
+ deliver_status(ch, HW_MOD_NOCARR);
+ break;
+ }
+ if (ch->cmd != PCTRL_CMD_FRH) {
+ pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n",
+ ch->is->name, ch->cmd);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ /* PCTRL_CMD_FRH */
+ if ((ch->bch.rx_skb->len + ch->is->clsb) >
+ (ch->bch.maxlen + 2)) {
+ pr_info("%s: %s incoming packet too large\n",
+ ch->is->name, __func__);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ } else if (ch->is->cmsb & HDLC_ERROR) {
+ pr_info("%s: ISAR frame error %x len %d\n",
+ ch->is->name, ch->is->cmsb, ch->is->clsb);
+ skb_trim(ch->bch.rx_skb, 0);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_FSD)
+ skb_trim(ch->bch.rx_skb, 0);
+ ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
+ rcv_mbox(ch->is, ptr);
+ if (ch->is->cmsb & HDLC_FED) {
+ if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
+ pr_info("%s: ISAR frame to short %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
+ recv_Bchannel(&ch->bch, 0);
+ }
+ if (ch->is->cmsb & SART_NMD) { /* ABORT */
+ pr_debug("%s: isar_rcv_frame: no more data\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ ch->state = STFAX_ESCAPE;
+ deliver_status(ch, HW_MOD_NOCARR);
+ }
+ break;
+ default:
+ pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+}
+
+static void
+isar_fill_fifo(struct isar_ch *ch)
+{
+ int count;
+ u8 msb;
+ u8 *ptr;
+
+ pr_debug("%s: ch%d tx_skb %p tx_idx %d\n",
+ ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx);
+ if (!ch->bch.tx_skb)
+ return;
+ count = ch->bch.tx_skb->len - ch->bch.tx_idx;
+ if (count <= 0)
+ return;
+ if (!(ch->is->bstat &
+ (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
+ return;
+ if (count > ch->mml) {
+ msb = 0;
+ count = ch->mml;
+ } else {
+ msb = HDLC_FED;
+ }
+ ptr = ch->bch.tx_skb->data + ch->bch.tx_idx;
+ if (!ch->bch.tx_idx) {
+ pr_debug("%s: frame start\n", ch->is->name);
+ if ((ch->bch.state == ISDN_P_B_T30_FAX) &&
+ (ch->cmd == PCTRL_CMD_FTH)) {
+ if (count > 1) {
+ if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) {
+ /* last frame */
+ test_and_set_bit(FLG_LASTDATA,
+ &ch->bch.Flags);
+ pr_debug("%s: set LASTDATA\n",
+ ch->is->name);
+ if (msb == HDLC_FED)
+ test_and_set_bit(FLG_DLEETX,
+ &ch->bch.Flags);
+ }
+ }
+ }
+ msb |= HDLC_FST;
+ }
+ ch->bch.tx_idx += count;
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ pr_info("%s: wrong protocol 0\n", __func__);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ case ISDN_P_B_MODEM_ASYNC:
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ break;
+ case ISDN_P_B_HDLC:
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ break;
+ case ISDN_P_B_T30_FAX:
+ if (ch->state != STFAX_ACTIV)
+ pr_debug("%s: not ACTIV\n", ch->is->name);
+ else if (ch->cmd == PCTRL_CMD_FTH)
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ else if (ch->cmd == PCTRL_CMD_FTM)
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ else
+ pr_debug("%s: not FTH/FTM\n", ch->is->name);
+ break;
+ default:
+ pr_info("%s: protocol(%x) error\n",
+ __func__, ch->bch.state);
+ break;
+ }
+}
+
+static inline struct isar_ch *
+sel_bch_isar(struct isar_hw *isar, u8 dpath)
+{
+ struct isar_ch *base = &isar->ch[0];
+
+ if ((!dpath) || (dpath > 2))
+ return NULL;
+ if (base->dpath == dpath)
+ return base;
+ base++;
+ if (base->dpath == dpath)
+ return base;
+ return NULL;
+}
+
+static void
+send_next(struct isar_ch *ch)
+{
+ pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n",
+ ch->is->name, __func__, ch->bch.nr,
+ ch->bch.tx_skb, ch->bch.tx_idx);
+ if (ch->bch.state == ISDN_P_B_T30_FAX) {
+ if (ch->cmd == PCTRL_CMD_FTH) {
+ if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) {
+ pr_debug("set NMD_DATA\n");
+ test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
+ }
+ } else if (ch->cmd == PCTRL_CMD_FTM) {
+ if (test_bit(FLG_DLEETX, &ch->bch.Flags)) {
+ test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags);
+ test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
+ }
+ }
+ }
+ if (ch->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags))
+ confirm_Bsend(&ch->bch);
+ dev_kfree_skb(ch->bch.tx_skb);
+ }
+ if (get_next_bframe(&ch->bch))
+ isar_fill_fifo(ch);
+ else {
+ if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) {
+ if (test_and_clear_bit(FLG_LASTDATA,
+ &ch->bch.Flags)) {
+ if (test_and_clear_bit(FLG_NMD_DATA,
+ &ch->bch.Flags)) {
+ u8 zd = 0;
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_SDATA, 0x01, 1, &zd);
+ }
+ test_and_set_bit(FLG_LL_OK, &ch->bch.Flags);
+ } else {
+ deliver_status(ch, HW_MOD_CONNECT);
+ }
+ }
+ }
+}
+
+static void
+check_send(struct isar_hw *isar, u8 rdm)
+{
+ struct isar_ch *ch;
+
+ pr_debug("%s: rdm %x\n", isar->name, rdm);
+ if (rdm & BSTAT_RDM1) {
+ ch = sel_bch_isar(isar, 1);
+ if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
+ if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
+ ch->bch.tx_idx))
+ isar_fill_fifo(ch);
+ else
+ send_next(ch);
+ }
+ }
+ if (rdm & BSTAT_RDM2) {
+ ch = sel_bch_isar(isar, 2);
+ if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
+ if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
+ ch->bch.tx_idx))
+ isar_fill_fifo(ch);
+ else
+ send_next(ch);
+ }
+ }
+}
+
+const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
+ "300", "600", "1200", "2400", "4800", "7200",
+ "9600nt", "9600t", "12000", "14400", "WRONG"};
+const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+ "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
+
+static void
+isar_pump_status_rsp(struct isar_ch *ch) {
+ u8 ril = ch->is->buf[0];
+ u8 rim;
+
+ if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags))
+ return;
+ if (ril > 14) {
+ pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril);
+ ril = 15;
+ }
+ switch (ch->is->buf[1]) {
+ case 0:
+ rim = 0;
+ break;
+ case 0x20:
+ rim = 2;
+ break;
+ case 0x40:
+ rim = 3;
+ break;
+ case 0x41:
+ rim = 4;
+ break;
+ case 0x51:
+ rim = 5;
+ break;
+ case 0x61:
+ rim = 6;
+ break;
+ case 0x71:
+ rim = 7;
+ break;
+ case 0x82:
+ rim = 8;
+ break;
+ case 0x92:
+ rim = 9;
+ break;
+ case 0xa2:
+ rim = 10;
+ break;
+ default:
+ rim = 1;
+ break;
+ }
+ sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]);
+ pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg);
+}
+
+static void
+isar_pump_statev_modem(struct isar_ch *ch, u8 devt) {
+ u8 dps = SET_DPS(ch->dpath);
+
+ switch (devt) {
+ case PSEV_10MS_TIMER:
+ pr_debug("%s: pump stev TIMER\n", ch->is->name);
+ break;
+ case PSEV_CON_ON:
+ pr_debug("%s: pump stev CONNECT\n", ch->is->name);
+ deliver_status(ch, HW_MOD_CONNECT);
+ break;
+ case PSEV_CON_OFF:
+ pr_debug("%s: pump stev NO CONNECT\n", ch->is->name);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ deliver_status(ch, HW_MOD_NOCARR);
+ break;
+ case PSEV_V24_OFF:
+ pr_debug("%s: pump stev V24 OFF\n", ch->is->name);
+ break;
+ case PSEV_CTS_ON:
+ pr_debug("%s: pump stev CTS ON\n", ch->is->name);
+ break;
+ case PSEV_CTS_OFF:
+ pr_debug("%s pump stev CTS OFF\n", ch->is->name);
+ break;
+ case PSEV_DCD_ON:
+ pr_debug("%s: pump stev CARRIER ON\n", ch->is->name);
+ test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ break;
+ case PSEV_DCD_OFF:
+ pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name);
+ break;
+ case PSEV_DSR_ON:
+ pr_debug("%s: pump stev DSR ON\n", ch->is->name);
+ break;
+ case PSEV_DSR_OFF:
+ pr_debug("%s: pump stev DSR_OFF\n", ch->is->name);
+ break;
+ case PSEV_REM_RET:
+ pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name);
+ break;
+ case PSEV_REM_REN:
+ pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name);
+ break;
+ case PSEV_GSTN_CLR:
+ pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name);
+ break;
+ default:
+ pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt);
+ break;
+ }
+}
+
+static void
+isar_pump_statev_fax(struct isar_ch *ch, u8 devt) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 p1;
+
+ switch (devt) {
+ case PSEV_10MS_TIMER:
+ pr_debug("%s: pump stev TIMER\n", ch->is->name);
+ break;
+ case PSEV_RSP_READY:
+ pr_debug("%s: pump stev RSP_READY\n", ch->is->name);
+ ch->state = STFAX_READY;
+ deliver_status(ch, HW_MOD_READY);
+#ifdef AUTOCON
+ if (test_bit(BC_FLG_ORIG, &ch->bch.Flags))
+ isar_pump_cmd(bch, HW_MOD_FRH, 3);
+ else
+ isar_pump_cmd(bch, HW_MOD_FTH, 3);
+#endif
+ break;
+ case PSEV_LINE_TX_H:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_TX_H wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_RX_H:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_RX_H wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_TX_B:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_TX_B wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_RX_B:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_RX_B wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_RSP_CONN:
+ if (ch->state == STFAX_CONT) {
+ pr_debug("%s: pump stev RSP_CONN\n", ch->is->name);
+ ch->state = STFAX_ACTIV;
+ test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ if (ch->cmd == PCTRL_CMD_FTH) {
+ int delay = (ch->mod == 3) ? 1000 : 200;
+ /* 1s (200 ms) Flags before data */
+ if (test_and_set_bit(FLG_FTI_RUN,
+ &ch->bch.Flags))
+ del_timer(&ch->ftimer);
+ ch->ftimer.expires =
+ jiffies + ((delay * HZ)/1000);
+ test_and_set_bit(FLG_LL_CONN,
+ &ch->bch.Flags);
+ add_timer(&ch->ftimer);
+ } else {
+ deliver_status(ch, HW_MOD_CONNECT);
+ }
+ } else {
+ pr_debug("%s: pump stev RSP_CONN wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_FLAGS_DET:
+ pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name);
+ break;
+ case PSEV_RSP_DISC:
+ pr_debug("%s: pump stev RSP_DISC state(%d)\n",
+ ch->is->name, ch->state);
+ if (ch->state == STFAX_ESCAPE) {
+ p1 = 5;
+ switch (ch->newcmd) {
+ case 0:
+ ch->state = STFAX_READY;
+ break;
+ case PCTRL_CMD_FTM:
+ p1 = 2;
+ case PCTRL_CMD_FTH:
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_SILON, 1, &p1);
+ ch->state = STFAX_SILDET;
+ break;
+ case PCTRL_CMD_FRH:
+ case PCTRL_CMD_FRM:
+ ch->mod = ch->newmod;
+ p1 = ch->newmod;
+ ch->newmod = 0;
+ ch->cmd = ch->newcmd;
+ ch->newcmd = 0;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &p1);
+ ch->state = STFAX_LINE;
+ ch->try_mod = 3;
+ break;
+ default:
+ pr_debug("%s: RSP_DISC unknown newcmd %x\n",
+ ch->is->name, ch->newcmd);
+ break;
+ }
+ } else if (ch->state == STFAX_ACTIV) {
+ if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags))
+ deliver_status(ch, HW_MOD_OK);
+ else if (ch->cmd == PCTRL_CMD_FRM)
+ deliver_status(ch, HW_MOD_NOCARR);
+ else
+ deliver_status(ch, HW_MOD_FCERROR);
+ ch->state = STFAX_READY;
+ } else if (ch->state != STFAX_SILDET) {
+ /* ignore in STFAX_SILDET */
+ ch->state = STFAX_READY;
+ deliver_status(ch, HW_MOD_FCERROR);
+ }
+ break;
+ case PSEV_RSP_SILDET:
+ pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name);
+ if (ch->state == STFAX_SILDET) {
+ ch->mod = ch->newmod;
+ p1 = ch->newmod;
+ ch->newmod = 0;
+ ch->cmd = ch->newcmd;
+ ch->newcmd = 0;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &p1);
+ ch->state = STFAX_LINE;
+ ch->try_mod = 3;
+ }
+ break;
+ case PSEV_RSP_SILOFF:
+ pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name);
+ break;
+ case PSEV_RSP_FCERR:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev RSP_FCERR try %d\n",
+ ch->is->name, ch->try_mod);
+ if (ch->try_mod--) {
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &ch->mod);
+ break;
+ }
+ }
+ pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name);
+ ch->state = STFAX_ESCAPE;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ deliver_status(ch, HW_MOD_FCERROR);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+mISDNisar_irq(struct isar_hw *isar)
+{
+ struct isar_ch *ch;
+
+ get_irq_infos(isar);
+ switch (isar->iis & ISAR_IIS_MSCMSD) {
+ case ISAR_IIS_RDATA:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch)
+ isar_rcv_frame(ch);
+ else {
+ pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_GSTEV:
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ isar->bstat |= isar->cmsb;
+ check_send(isar, isar->cmsb);
+ break;
+ case ISAR_IIS_BSTEV:
+#ifdef ERROR_STATISTIC
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ if (isar->cmsb == BSTEV_TBO)
+ ch->bch.err_tx++;
+ if (isar->cmsb == BSTEV_RBO)
+ ch->bch.err_rdo++;
+ }
+#endif
+ pr_debug("%s: Buffer STEV dpath%d msb(%x)\n",
+ isar->name, isar->iis>>6, isar->cmsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ break;
+ case ISAR_IIS_PSTEV:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ rcv_mbox(isar, NULL);
+ if (ch->bch.state == ISDN_P_B_MODEM_ASYNC)
+ isar_pump_statev_modem(ch, isar->cmsb);
+ else if (ch->bch.state == ISDN_P_B_T30_FAX)
+ isar_pump_statev_fax(ch, isar->cmsb);
+ else if (ch->bch.state == ISDN_P_B_RAW) {
+ int tt;
+ tt = isar->cmsb | 0x30;
+ if (tt == 0x3e)
+ tt = '*';
+ else if (tt == 0x3f)
+ tt = '#';
+ else if (tt > '9')
+ tt += 7;
+ tt |= DTMF_TONE_VAL;
+ _queue_data(&ch->bch.ch, PH_CONTROL_IND,
+ MISDN_ID_ANY, sizeof(tt), &tt,
+ GFP_ATOMIC);
+ } else
+ pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n",
+ isar->name, ch->bch.state,
+ isar->cmsb);
+ } else {
+ pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_PSTRSP:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ rcv_mbox(isar, NULL);
+ isar_pump_status_rsp(ch);
+ } else {
+ pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_DIAG:
+ case ISAR_IIS_BSTRSP:
+ case ISAR_IIS_IOM2RSP:
+ rcv_mbox(isar, NULL);
+ break;
+ case ISAR_IIS_INVMSG:
+ rcv_mbox(isar, NULL);
+ pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb);
+ break;
+ default:
+ rcv_mbox(isar, NULL);
+ pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n",
+ isar->name, isar->iis, isar->cmsb, isar->clsb);
+ break;
+ }
+}
+EXPORT_SYMBOL(mISDNisar_irq);
+
+static void
+ftimer_handler(unsigned long data)
+{
+ struct isar_ch *ch = (struct isar_ch *)data;
+
+ pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags);
+ test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags);
+ if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags))
+ deliver_status(ch, HW_MOD_CONNECT);
+}
+
+static void
+setup_pump(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl, param[6];
+
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
+ break;
+ case ISDN_P_B_L2DTMF:
+ if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) {
+ param[0] = 5; /* TOA 5 db */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
+ PMOD_DTMF_TRANS, 1, param);
+ } else {
+ param[0] = 40; /* REL -46 dbm */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
+ PMOD_DTMF, 1, param);
+ }
+ case ISDN_P_B_MODEM_ASYNC:
+ ctrl = PMOD_DATAMODEM;
+ if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
+ ctrl |= PCTRL_ORIG;
+ param[5] = PV32P6_CTN;
+ } else {
+ param[5] = PV32P6_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
+ PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
+ param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
+ param[3] = PV32P4_UT144;
+ param[4] = PV32P5_UT144;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
+ break;
+ case ISDN_P_B_T30_FAX:
+ ctrl = PMOD_FAX;
+ if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
+ ctrl |= PCTRL_ORIG;
+ param[1] = PFAXP2_CTN;
+ } else {
+ param[1] = PFAXP2_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+ ch->state = STFAX_NULL;
+ ch->newcmd = 0;
+ ch->newmod = 0;
+ test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags);
+ break;
+ }
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static void
+setup_sart(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl, param[2] = {0, 0};
+
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE,
+ 0, NULL);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY,
+ 2, param);
+ break;
+ case ISDN_P_B_HDLC:
+ case ISDN_P_B_T30_FAX:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC,
+ 1, param);
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
+ param[0] = S_P1_CHS_8;
+ param[1] = S_P2_BFT_DEF;
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param);
+ break;
+ }
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static void
+setup_iom2(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0};
+
+ if (ch->bch.nr == 2) {
+ msg[1] = 1;
+ msg[3] = 1;
+ }
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ cmsb = 0;
+ /* dummy slot */
+ msg[1] = ch->dpath + 2;
+ msg[3] = ch->dpath + 2;
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ case ISDN_P_B_T30_FAX:
+ cmsb |= IOM_CTRL_RCV;
+ case ISDN_P_B_L2DTMF:
+ if (test_bit(FLG_DTMFSEND, &ch->bch.Flags))
+ cmsb |= IOM_CTRL_RCV;
+ cmsb |= IOM_CTRL_ALAW;
+ break;
+ }
+ send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static int
+modeisar(struct isar_ch *ch, u32 bprotocol)
+{
+ /* Here we are selecting the best datapath for requested protocol */
+ if (ch->bch.state == ISDN_P_NONE) { /* New Setup */
+ switch (bprotocol) {
+ case ISDN_P_NONE: /* init */
+ if (!ch->dpath)
+ /* no init for dpath 0 */
+ return 0;
+ test_and_clear_bit(FLG_HDLC, &ch->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ /* best is datapath 2 */
+ if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags))
+ ch->dpath = 2;
+ else if (!test_and_set_bit(ISAR_DP1_USE,
+ &ch->is->Flags))
+ ch->dpath = 1;
+ else {
+ pr_info("modeisar both pathes in use\n");
+ return -EBUSY;
+ }
+ if (bprotocol == ISDN_P_B_HDLC)
+ test_and_set_bit(FLG_HDLC, &ch->bch.Flags);
+ else
+ test_and_set_bit(FLG_TRANSPARENT,
+ &ch->bch.Flags);
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ case ISDN_P_B_T30_FAX:
+ case ISDN_P_B_L2DTMF:
+ /* only datapath 1 */
+ if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags))
+ ch->dpath = 1;
+ else {
+ pr_info("%s: ISAR modeisar analog functions"
+ "only with DP1\n", ch->is->name);
+ return -EBUSY;
+ }
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", ch->is->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ }
+ pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name,
+ ch->bch.nr, ch->dpath, ch->bch.state, bprotocol);
+ ch->bch.state = bprotocol;
+ setup_pump(ch);
+ setup_iom2(ch);
+ setup_sart(ch);
+ if (ch->bch.state == ISDN_P_NONE) {
+ /* Clear resources */
+ if (ch->dpath == 1)
+ test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags);
+ else if (ch->dpath == 2)
+ test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags);
+ ch->dpath = 0;
+ ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr);
+ } else
+ ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr);
+ return 0;
+}
+
+static void
+isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para)
+{
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl = 0, nom = 0, p1 = 0;
+
+ pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n",
+ ch->is->name, cmd, para, ch->bch.state);
+ switch (cmd) {
+ case HW_MOD_FTM:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTM;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FTM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FTH:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTH;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FTH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FRM:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRM;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FRM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FRH:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRH;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FRH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case PCTRL_CMD_TDTMF:
+ p1 = para;
+ nom = 1;
+ ctrl = PCTRL_CMD_TDTMF;
+ break;
+ }
+ if (ctrl)
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
+static void
+isar_setup(struct isar_hw *isar)
+{
+ u8 msg;
+ int i;
+
+ /* Dpath 1, 2 */
+ msg = 61;
+ for (i = 0; i < 2; i++) {
+ /* Buffer Config */
+ send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+ ISAR_HIS_P12CFG, 4, 1, &msg);
+ isar->ch[i].mml = msg;
+ isar->ch[i].bch.state = 0;
+ isar->ch[i].dpath = i + 1;
+ modeisar(&isar->ch[i], ISDN_P_NONE);
+ }
+}
+
+static int
+isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id, *val;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ isar_fill_fifo(ich);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = modeisar(ich, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ mISDN_clear_bchannel(bch);
+ modeisar(ich, ISDN_P_NONE);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ case PH_CONTROL_REQ:
+ val = (u32 *)skb->data;
+ pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name,
+ hh->id, *val);
+ if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) ==
+ DTMF_TONE_VAL)) {
+ if (bch->state == ISDN_P_B_L2DTMF) {
+ char tt = *val & DTMF_TONE_MASK;
+
+ if (tt == '*')
+ tt = 0x1e;
+ else if (tt == '#')
+ tt = 0x1f;
+ else if (tt > '9')
+ tt -= 7;
+ tt &= 0x1f;
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ } else {
+ pr_info("%s: DTMF send wrong protocol %x\n",
+ __func__, bch->state);
+ return -EINVAL;
+ }
+ } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) ||
+ (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) {
+ for (id = 0; id < FAXMODCNT; id++)
+ if (faxmodulation[id] == *val)
+ break;
+ if ((FAXMODCNT > id) &&
+ test_bit(FLG_INITIALIZED, &bch->Flags)) {
+ pr_debug("%s: isar: new mod\n", ich->is->name);
+ isar_pump_cmd(ich, hh->id, *val);
+ ret = 0;
+ } else {
+ pr_info("%s: wrong modulation\n",
+ ich->is->name);
+ ret = -EINVAL;
+ }
+ } else if (hh->id == HW_MOD_LASTDATA)
+ test_and_set_bit(FLG_DLEETX, &bch->Flags);
+ else {
+ pr_info("%s: unknown PH_CONTROL_REQ %x\n",
+ ich->is->name, hh->id);
+ ret = -EINVAL;
+ }
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ ich->is->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ mISDN_freebchannel(bch);
+ modeisar(ich, ISDN_P_NONE);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(ich->is->owner);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ ich->is->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static void
+free_isar(struct isar_hw *isar)
+{
+ modeisar(&isar->ch[0], ISDN_P_NONE);
+ modeisar(&isar->ch[1], ISDN_P_NONE);
+ del_timer(&isar->ch[0].ftimer);
+ del_timer(&isar->ch[1].ftimer);
+ test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
+ test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
+}
+
+static int
+init_isar(struct isar_hw *isar)
+{
+ int cnt = 3;
+
+ while (cnt--) {
+ isar->version = ISARVersion(isar);
+ if (isar->ch[0].bch.debug & DEBUG_HW)
+ pr_notice("%s: Testing version %d (%d time)\n",
+ isar->name, isar->version, 3 - cnt);
+ if (isar->version == 1)
+ break;
+ isar->ctrl(isar->hw, HW_RESET_REQ, 0);
+ }
+ if (isar->version != 1)
+ return -EINVAL;
+ isar->ch[0].ftimer.function = &ftimer_handler;
+ isar->ch[0].ftimer.data = (long)&isar->ch[0];
+ init_timer(&isar->ch[0].ftimer);
+ test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
+ isar->ch[1].ftimer.function = &ftimer_handler;
+ isar->ch[1].ftimer.data = (long)&isar->ch[1];
+ init_timer(&isar->ch[1].ftimer);
+ test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
+ return 0;
+}
+
+static int
+isar_open(struct isar_hw *isar, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &isar->ch[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+u32
+mISDNisar_init(struct isar_hw *isar, void *hw)
+{
+ u32 ret, i;
+
+ isar->hw = hw;
+ for (i = 0; i < 2; i++) {
+ isar->ch[i].bch.nr = i + 1;
+ mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM);
+ isar->ch[i].bch.ch.nr = i + 1;
+ isar->ch[i].bch.ch.send = &isar_l2l1;
+ isar->ch[i].bch.ch.ctrl = isar_bctrl;
+ isar->ch[i].bch.hw = hw;
+ isar->ch[i].is = isar;
+ }
+
+ isar->init = &init_isar;
+ isar->release = &free_isar;
+ isar->firmware = &load_firmware;
+ isar->open = &isar_open;
+
+ ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK));
+
+ return ret;
+}
+EXPORT_SYMBOL(mISDNisar_init);
+
+static int isar_mod_init(void)
+{
+ pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV);
+ return 0;
+}
+
+static void isar_mod_cleanup(void)
+{
+ pr_notice("mISDN: ISAR module unloaded\n");
+}
+module_init(isar_mod_init);
+module_exit(isar_mod_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
new file mode 100644
index 000000000000..6c1b164937a9
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -0,0 +1,1156 @@
+/*
+ * NETJet mISDN driver
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+#include "iohelper.h"
+#include "netjet.h"
+#include <linux/isdn/hdlc.h>
+
+#define NETJET_REV "2.0"
+
+enum nj_types {
+ NETJET_S_TJ300,
+ NETJET_S_TJ320,
+ ENTERNOW__TJ320,
+};
+
+struct tiger_dma {
+ size_t size;
+ u32 *start;
+ int idx;
+ u32 dmastart;
+ u32 dmairq;
+ u32 dmaend;
+ u32 dmacur;
+};
+
+struct tiger_hw;
+
+struct tiger_ch {
+ struct bchannel bch;
+ struct tiger_hw *nj;
+ int idx;
+ int free;
+ int lastrx;
+ u16 rxstate;
+ u16 txstate;
+ struct isdnhdlc_vars hsend;
+ struct isdnhdlc_vars hrecv;
+ u8 *hsbuf;
+ u8 *hrbuf;
+};
+
+#define TX_INIT 0x0001
+#define TX_IDLE 0x0002
+#define TX_RUN 0x0004
+#define TX_UNDERRUN 0x0100
+#define RX_OVERRUN 0x0100
+
+#define LOG_SIZE 64
+
+struct tiger_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ enum nj_types typ;
+ int irq;
+ u32 irqcnt;
+ u32 base;
+ size_t base_s;
+ dma_addr_t dma;
+ void *dma_p;
+ spinlock_t lock; /* lock HW */
+ struct isac_hw isac;
+ struct tiger_dma send;
+ struct tiger_dma recv;
+ struct tiger_ch bc[2];
+ u8 ctrlreg;
+ u8 dmactrl;
+ u8 auxd;
+ u8 last_is0;
+ u8 irqmask0;
+ char log[LOG_SIZE];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+static u32 debug;
+static int nj_cnt;
+
+static void
+_set_debug(struct tiger_hw *card)
+{
+ card->isac.dch.debug = debug;
+ card->bc[0].bch.debug = debug;
+ card->bc[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct tiger_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(NETJET_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Netjet debug mask");
+
+static void
+nj_disable_hwirq(struct tiger_hw *card)
+{
+ outb(0, card->base + NJ_IRQMASK0);
+ outb(0, card->base + NJ_IRQMASK1);
+}
+
+
+static u8
+ReadISAC_nj(void *p, u8 offset)
+{
+ struct tiger_hw *card = p;
+ u8 ret;
+
+ card->auxd &= 0xfc;
+ card->auxd |= (offset >> 4) & 3;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+ return ret;
+}
+
+static void
+WriteISAC_nj(void *p, u8 offset, u8 value)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ card->auxd |= (offset >> 4) & 3;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+}
+
+static void
+ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ insb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ outsb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ u32 mask = 0xff, val;
+
+ pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,
+ bc->bch.nr, fill, cnt, idx, card->send.idx);
+ if (bc->bch.nr & 2) {
+ fill <<= 8;
+ mask <<= 8;
+ }
+ mask ^= 0xffffffff;
+ while (cnt--) {
+ val = card->send.start[idx];
+ val &= mask;
+ val |= fill;
+ card->send.start[idx++] = val;
+ if (idx >= card->send.size)
+ idx = 0;
+ }
+}
+
+static int
+mode_tiger(struct tiger_ch *bc, u32 protocol)
+{
+ struct tiger_hw *card = bc->bch.hw;
+
+ pr_debug("%s: B%1d protocol %x-->%x\n", card->name,
+ bc->bch.nr, bc->bch.state, protocol);
+ switch (protocol) {
+ case ISDN_P_NONE:
+ if (bc->bch.state == ISDN_P_NONE)
+ break;
+ fill_mem(bc, 0, card->send.size, 0xff);
+ bc->bch.state = protocol;
+ /* only stop dma and interrupts if both channels NULL */
+ if ((card->bc[0].bch.state == ISDN_P_NONE) &&
+ (card->bc[1].bch.state == ISDN_P_NONE)) {
+ card->dmactrl = 0;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0, card->base + NJ_IRQMASK0);
+ }
+ test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+ bc->txstate = 0;
+ bc->rxstate = 0;
+ bc->lastrx = -1;
+ break;
+ case ISDN_P_B_RAW:
+ test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+ bc->bch.state = protocol;
+ bc->idx = 0;
+ bc->free = card->send.size/2;
+ bc->rxstate = 0;
+ bc->txstate = TX_INIT | TX_IDLE;
+ bc->lastrx = -1;
+ if (!card->dmactrl) {
+ card->dmactrl = 1;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0x0f, card->base + NJ_IRQMASK0);
+ }
+ break;
+ case ISDN_P_B_HDLC:
+ test_and_set_bit(FLG_HDLC, &bc->bch.Flags);
+ bc->bch.state = protocol;
+ bc->idx = 0;
+ bc->free = card->send.size/2;
+ bc->rxstate = 0;
+ bc->txstate = TX_INIT | TX_IDLE;
+ isdnhdlc_rcv_init(&bc->hrecv, 0);
+ isdnhdlc_out_init(&bc->hsend, 0);
+ bc->lastrx = -1;
+ if (!card->dmactrl) {
+ card->dmactrl = 1;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0x0f, card->base + NJ_IRQMASK0);
+ }
+ break;
+ default:
+ pr_info("%s: %s protocol %x not handled\n", card->name,
+ __func__, protocol);
+ return -ENOPROTOOPT;
+ }
+ card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);
+ card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+ pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n",
+ card->name, __func__,
+ inb(card->base + NJ_DMACTRL),
+ inb(card->base + NJ_IRQMASK0),
+ inb(card->base + NJ_IRQSTAT0),
+ card->send.idx,
+ card->recv.idx);
+ return 0;
+}
+
+static void
+nj_reset(struct tiger_hw *card)
+{
+ outb(0xff, card->base + NJ_CTRL); /* Reset On */
+ mdelay(1);
+
+ /* now edge triggered for TJ320 GE 13/07/00 */
+ /* see comment in IRQ function */
+ if (card->typ == NETJET_S_TJ320) /* TJ320 */
+ card->ctrlreg = 0x40; /* Reset Off and status read clear */
+ else
+ card->ctrlreg = 0x00; /* Reset Off and status read clear */
+ outb(card->ctrlreg, card->base + NJ_CTRL);
+ mdelay(10);
+
+ /* configure AUX pins (all output except ISAC IRQ pin) */
+ card->auxd = 0;
+ card->dmactrl = 0;
+ outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);
+ outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1);
+ outb(card->auxd, card->base + NJ_AUXDATA);
+}
+
+static int
+inittiger(struct tiger_hw *card)
+{
+ int i;
+
+ card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE,
+ &card->dma);
+ if (!card->dma_p) {
+ pr_info("%s: No DMA memory\n", card->name);
+ return -ENOMEM;
+ }
+ if ((u64)card->dma > 0xffffffff) {
+ pr_info("%s: DMA outside 32 bit\n", card->name);
+ return -ENOMEM;
+ }
+ for (i = 0; i < 2; i++) {
+ card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL);
+ if (!card->bc[i].hsbuf) {
+ pr_info("%s: no B%d send buffer\n", card->name, i + 1);
+ return -ENOMEM;
+ }
+ card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL);
+ if (!card->bc[i].hrbuf) {
+ pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
+ return -ENOMEM;
+ }
+ }
+ memset(card->dma_p, 0xff, NJ_DMA_SIZE);
+
+ card->send.start = card->dma_p;
+ card->send.dmastart = (u32)card->dma;
+ card->send.dmaend = card->send.dmastart +
+ (4 * (NJ_DMA_TXSIZE - 1));
+ card->send.dmairq = card->send.dmastart +
+ (4 * ((NJ_DMA_TXSIZE / 2) - 1));
+ card->send.size = NJ_DMA_TXSIZE;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p"
+ " size %zu u32\n", card->name,
+ card->send.dmastart, card->send.dmairq,
+ card->send.dmaend, card->send.start, card->send.size);
+
+ outl(card->send.dmastart, card->base + NJ_DMA_READ_START);
+ outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);
+ outl(card->send.dmaend, card->base + NJ_DMA_READ_END);
+
+ card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);
+ card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2);
+ card->recv.dmaend = card->recv.dmastart +
+ (4 * (NJ_DMA_RXSIZE - 1));
+ card->recv.dmairq = card->recv.dmastart +
+ (4 * ((NJ_DMA_RXSIZE / 2) - 1));
+ card->recv.size = NJ_DMA_RXSIZE;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p"
+ " size %zu u32\n", card->name,
+ card->recv.dmastart, card->recv.dmairq,
+ card->recv.dmaend, card->recv.start, card->recv.size);
+
+ outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);
+ outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);
+ outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);
+ return 0;
+}
+
+static void
+read_dma(struct tiger_ch *bc, u32 idx, int cnt)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int i, stat;
+ u32 val;
+ u8 *p, *pn;
+
+ if (bc->lastrx == idx) {
+ bc->rxstate |= RX_OVERRUN;
+ pr_info("%s: B%1d overrun at idx %d\n", card->name,
+ bc->bch.nr, idx);
+ }
+ bc->lastrx = idx;
+ if (!bc->bch.rx_skb) {
+ bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);
+ if (!bc->bch.rx_skb) {
+ pr_info("%s: B%1d receive out of memory\n",
+ card->name, bc->bch.nr);
+ return;
+ }
+ }
+
+ if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
+ if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {
+ pr_debug("%s: B%1d overrun %d\n", card->name,
+ bc->bch.nr, bc->bch.rx_skb->len + cnt);
+ skb_trim(bc->bch.rx_skb, 0);
+ return;
+ }
+ p = skb_put(bc->bch.rx_skb, cnt);
+ } else
+ p = bc->hrbuf;
+
+ for (i = 0; i < cnt; i++) {
+ val = card->recv.start[idx++];
+ if (bc->bch.nr & 2)
+ val >>= 8;
+ if (idx >= card->recv.size)
+ idx = 0;
+ p[i] = val & 0xff;
+ }
+ pn = bc->hrbuf;
+next_frame:
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
+ bc->bch.rx_skb->data, bc->bch.maxlen);
+ if (stat > 0) /* valid frame received */
+ p = skb_put(bc->bch.rx_skb, stat);
+ else if (stat == -HDLC_CRC_ERROR)
+ pr_info("%s: B%1d receive frame CRC error\n",
+ card->name, bc->bch.nr);
+ else if (stat == -HDLC_FRAMING_ERROR)
+ pr_info("%s: B%1d receive framing error\n",
+ card->name, bc->bch.nr);
+ else if (stat == -HDLC_LENGTH_ERROR)
+ pr_info("%s: B%1d receive frame too long (> %d)\n",
+ card->name, bc->bch.nr, bc->bch.maxlen);
+ } else
+ stat = cnt;
+
+ if (stat > 0) {
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",
+ bc->bch.nr, card->name, stat);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,
+ p, stat);
+ }
+ recv_Bchannel(&bc->bch, 0);
+ }
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ pn += i;
+ cnt -= i;
+ if (!bc->bch.rx_skb) {
+ bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,
+ GFP_ATOMIC);
+ if (!bc->bch.rx_skb) {
+ pr_info("%s: B%1d receive out of memory\n",
+ card->name, bc->bch.nr);
+ return;
+ }
+ }
+ if (cnt > 0)
+ goto next_frame;
+ }
+}
+
+static void
+recv_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+ u32 idx;
+ int cnt = card->recv.size / 2;
+
+ /* Note receive is via the WRITE DMA channel */
+ card->last_is0 &= ~NJ_IRQM0_WR_MASK;
+ card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);
+
+ if (irq_stat & NJ_IRQM0_WR_END)
+ idx = cnt - 1;
+ else
+ idx = card->recv.size - 1;
+
+ if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))
+ read_dma(&card->bc[0], idx, cnt);
+ if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))
+ read_dma(&card->bc[1], idx, cnt);
+}
+
+/* sync with current DMA address at start or after exception */
+static void
+resync(struct tiger_ch *bc, struct tiger_hw *card)
+{
+ card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ if (bc->free > card->send.size / 2)
+ bc->free = card->send.size / 2;
+ /* currently we simple sync to the next complete free area
+ * this hast the advantage that we have always maximum time to
+ * handle TX irq
+ */
+ if (card->send.idx < ((card->send.size / 2) - 1))
+ bc->idx = (card->recv.size / 2) - 1;
+ else
+ bc->idx = card->recv.size - 1;
+ bc->txstate = TX_RUN;
+ pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);
+}
+
+static int bc_next_frame(struct tiger_ch *);
+
+static void
+fill_hdlc_flag(struct tiger_ch *bc)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int count, i;
+ u32 m, v;
+ u8 *p;
+
+ if (bc->free == 0)
+ return;
+ pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, bc->free, bc->txstate,
+ bc->idx, card->send.idx);
+ if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+ resync(bc, card);
+ count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,
+ bc->hsbuf, bc->free);
+ pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,
+ bc->bch.nr, count);
+ bc->free -= count;
+ p = bc->hsbuf;
+ m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+ for (i = 0; i < count; i++) {
+ if (bc->idx >= card->send.size)
+ bc->idx = 0;
+ v = card->send.start[bc->idx];
+ v &= m;
+ v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+ card->send.start[bc->idx++] = v;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+ bc->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+fill_dma(struct tiger_ch *bc)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int count, i;
+ u32 m, v;
+ u8 *p;
+
+ if (bc->free == 0)
+ return;
+ count = bc->bch.tx_skb->len - bc->bch.tx_idx;
+ if (count <= 0)
+ return;
+ pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,
+ bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);
+ if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+ resync(bc, card);
+ p = bc->bch.tx_skb->data + bc->bch.tx_idx;
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ count = isdnhdlc_encode(&bc->hsend, p, count, &i,
+ bc->hsbuf, bc->free);
+ pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
+ bc->bch.nr, i, count);
+ bc->bch.tx_idx += i;
+ bc->free -= count;
+ p = bc->hsbuf;
+ } else {
+ if (count > bc->free)
+ count = bc->free;
+ bc->bch.tx_idx += count;
+ bc->free -= count;
+ }
+ m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+ for (i = 0; i < count; i++) {
+ if (bc->idx >= card->send.size)
+ bc->idx = 0;
+ v = card->send.start[bc->idx];
+ v &= m;
+ v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+ card->send.start[bc->idx++] = v;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+ bc->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+ if (bc->free)
+ bc_next_frame(bc);
+}
+
+
+static int
+bc_next_frame(struct tiger_ch *bc)
+{
+ if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)
+ fill_dma(bc);
+ else {
+ if (bc->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
+ confirm_Bsend(&bc->bch);
+ dev_kfree_skb(bc->bch.tx_skb);
+ }
+ if (get_next_bframe(&bc->bch))
+ fill_dma(bc);
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static void
+send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)
+{
+ int ret;
+
+ bc->free += card->send.size / 2;
+ if (bc->free >= card->send.size) {
+ if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {
+ pr_info("%s: B%1d TX underrun state %x\n", card->name,
+ bc->bch.nr, bc->txstate);
+ bc->txstate |= TX_UNDERRUN;
+ }
+ bc->free = card->send.size;
+ }
+ ret = bc_next_frame(bc);
+ if (!ret) {
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ fill_hdlc_flag(bc);
+ return;
+ }
+ pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,
+ bc->bch.nr, bc->free, bc->idx, card->send.idx);
+ if (!(bc->txstate & (TX_IDLE | TX_INIT))) {
+ fill_mem(bc, bc->idx, bc->free, 0xff);
+ if (bc->free == card->send.size)
+ bc->txstate |= TX_IDLE;
+ }
+ }
+}
+
+static void
+send_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+ int i;
+
+ /* Note send is via the READ DMA channel */
+ if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {
+ pr_info("%s: tiger warn write double dma %x/%x\n",
+ card->name, irq_stat, card->last_is0);
+ return;
+ } else {
+ card->last_is0 &= ~NJ_IRQM0_RD_MASK;
+ card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);
+ }
+ for (i = 0; i < 2; i++) {
+ if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))
+ send_tiger_bc(card, &card->bc[i]);
+ }
+}
+
+static irqreturn_t
+nj_irq(int intno, void *dev_id)
+{
+ struct tiger_hw *card = dev_id;
+ u8 val, s1val, s0val;
+
+ spin_lock(&card->lock);
+ s0val = inb(card->base | NJ_IRQSTAT0);
+ s1val = inb(card->base | NJ_IRQSTAT1);
+ if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {
+ /* shared IRQ */
+ spin_unlock(&card->lock);
+ return IRQ_NONE;
+ }
+ pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);
+ card->irqcnt++;
+ if (!(s1val & NJ_ISACIRQ)) {
+ val = ReadISAC_nj(card, ISAC_ISTA);
+ if (val)
+ mISDNisac_irq(&card->isac, val);
+ }
+
+ if (s0val)
+ /* write to clear */
+ outb(s0val, card->base | NJ_IRQSTAT0);
+ else
+ goto end;
+ s1val = s0val;
+ /* set bits in sval to indicate which page is free */
+ card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);
+ card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+ if (card->recv.dmacur < card->recv.dmairq)
+ s0val = 0x08; /* the 2nd write area is free */
+ else
+ s0val = 0x04; /* the 1st write area is free */
+
+ card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ if (card->send.dmacur < card->send.dmairq)
+ s0val |= 0x02; /* the 2nd read area is free */
+ else
+ s0val |= 0x01; /* the 1st read area is free */
+
+ pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,
+ s1val, s0val, card->last_is0,
+ card->recv.idx, card->send.idx);
+ /* test if we have a DMA interrupt */
+ if (s0val != card->last_is0) {
+ if ((s0val & NJ_IRQM0_RD_MASK) !=
+ (card->last_is0 & NJ_IRQM0_RD_MASK))
+ /* got a write dma int */
+ send_tiger(card, s0val);
+ if ((s0val & NJ_IRQM0_WR_MASK) !=
+ (card->last_is0 & NJ_IRQM0_WR_MASK))
+ /* got a read dma int */
+ recv_tiger(card, s0val);
+ }
+end:
+ spin_unlock(&card->lock);
+ return IRQ_HANDLED;
+}
+
+static int
+nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ int ret = -EINVAL;
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+ struct tiger_hw *card = bch->hw;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ fill_dma(bc);
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = mode_tiger(bc, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_clear_bchannel(bch);
+ mode_tiger(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+ struct tiger_hw *card = bc->bch.hw;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+ struct tiger_hw *card = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+ mode_tiger(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bc, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct tiger_hw *card, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &card->bc[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+/*
+ * device control function
+ */
+static int
+nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct tiger_hw *card = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = card->isac.open(&card->isac, rq);
+ else
+ err = open_bchannel(card, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", card->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,
+ __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(card, arg);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n",
+ card->name, __func__, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int
+nj_init_card(struct tiger_hw *card)
+{
+ u_long flags;
+ int ret;
+
+ spin_lock_irqsave(&card->lock, flags);
+ nj_disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ card->irq = card->pdev->irq;
+ if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {
+ pr_info("%s: couldn't get interrupt %d\n",
+ card->name, card->irq);
+ card->irq = -1;
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&card->lock, flags);
+ nj_reset(card);
+ ret = card->isac.init(&card->isac);
+ if (ret)
+ goto error;
+ ret = inittiger(card);
+ if (ret)
+ goto error;
+ mode_tiger(&card->bc[0], ISDN_P_NONE);
+ mode_tiger(&card->bc[1], ISDN_P_NONE);
+error:
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+}
+
+
+static void
+nj_release(struct tiger_hw *card)
+{
+ u_long flags;
+ int i;
+
+ if (card->base_s) {
+ spin_lock_irqsave(&card->lock, flags);
+ nj_disable_hwirq(card);
+ mode_tiger(&card->bc[0], ISDN_P_NONE);
+ mode_tiger(&card->bc[1], ISDN_P_NONE);
+ card->isac.release(&card->isac);
+ spin_unlock_irqrestore(&card->lock, flags);
+ release_region(card->base, card->base_s);
+ card->base_s = 0;
+ }
+ if (card->irq > 0)
+ free_irq(card->irq, card);
+ if (card->isac.dch.dev.dev.class)
+ mISDN_unregister_device(&card->isac.dch.dev);
+
+ for (i = 0; i < 2; i++) {
+ mISDN_freebchannel(&card->bc[i].bch);
+ kfree(card->bc[i].hsbuf);
+ kfree(card->bc[i].hrbuf);
+ }
+ if (card->dma_p)
+ pci_free_consistent(card->pdev, NJ_DMA_SIZE,
+ card->dma_p, card->dma);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ pci_clear_master(card->pdev);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ kfree(card);
+}
+
+
+static int
+nj_setup(struct tiger_hw *card)
+{
+ card->base = pci_resource_start(card->pdev, 0);
+ card->base_s = pci_resource_len(card->pdev, 0);
+ if (!request_region(card->base, card->base_s, card->name)) {
+ pr_info("%s: NETjet config port %#x-%#x already in use\n",
+ card->name, card->base,
+ (u32)(card->base + card->base_s - 1));
+ card->base_s = 0;
+ return -EIO;
+ }
+ ASSIGN_FUNC(nj, ISAC, card->isac);
+ return 0;
+}
+
+
+static int __devinit
+setup_instance(struct tiger_hw *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->isac.name = card->name;
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->isac.dch.dev.D.ctrl = nj_dctrl;
+ for (i = 0; i < 2; i++) {
+ card->bc[i].bch.nr = i + 1;
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ card->bc[i].bch.hw = card;
+ card->bc[i].bch.ch.send = nj_l2l1B;
+ card->bc[i].bch.ch.ctrl = nj_bctrl;
+ card->bc[i].bch.ch.nr = i + 1;
+ list_add(&card->bc[i].bch.ch.list,
+ &card->isac.dch.dev.bchannels);
+ card->bc[i].bch.hw = card;
+ }
+ err = nj_setup(card);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error;
+ err = nj_init_card(card);
+ if (!err) {
+ nj_cnt++;
+ pr_notice("Netjet %d cards installed\n", nj_cnt);
+ return 0;
+ }
+error:
+ nj_release(card);
+ return err;
+}
+
+static int __devinit
+nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ int cfg;
+ struct tiger_hw *card;
+
+ if (pdev->subsystem_vendor == 0x8086 &&
+ pdev->subsystem_device == 0x0003) {
+ pr_notice("Netjet: Digium X100P/X101P not handled\n");
+ return -ENODEV;
+ }
+
+ if (pdev->subsystem_vendor == 0x55 &&
+ pdev->subsystem_device == 0x02) {
+ pr_notice("Netjet: Enter!Now not handled yet\n");
+ return -ENODEV;
+ }
+
+ card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
+ if (!card) {
+ pr_info("No kmem for Netjet\n");
+ return err;
+ }
+
+ card->pdev = pdev;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",
+ pci_name(pdev));
+
+ pci_set_master(pdev);
+
+ /* the TJ300 and TJ320 must be detected, the IRQ handling is different
+ * unfortunately the chips use the same device ID, but the TJ320 has
+ * the bit20 in status PCI cfg register set
+ */
+ pci_read_config_dword(pdev, 0x04, &cfg);
+ if (cfg & 0x00100000)
+ card->typ = NETJET_S_TJ320;
+ else
+ card->typ = NETJET_S_TJ300;
+
+ card->base = pci_resource_start(pdev, 0);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+
+static void __devexit nj_remove(struct pci_dev *pdev)
+{
+ struct tiger_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ nj_release(card);
+ else
+ pr_info("%s drvdata already removed\n", __func__);
+}
+
+/* We cannot select cards with PCI_SUB... IDs, since here are cards with
+ * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
+ * known other cards which not work with this driver - see probe function */
+static struct pci_device_id nj_pci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, nj_pci_ids);
+
+static struct pci_driver nj_driver = {
+ .name = "netjet",
+ .probe = nj_probe,
+ .remove = __devexit_p(nj_remove),
+ .id_table = nj_pci_ids,
+};
+
+static int __init nj_init(void)
+{
+ int err;
+
+ pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);
+ err = pci_register_driver(&nj_driver);
+ return err;
+}
+
+static void __exit nj_cleanup(void)
+{
+ pci_unregister_driver(&nj_driver);
+}
+
+module_init(nj_init);
+module_exit(nj_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h
new file mode 100644
index 000000000000..d061ff995607
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.h
@@ -0,0 +1,58 @@
+/*
+ * NETjet common header file
+ *
+ * Author Karsten Keil
+ * based on work of Matt Henderson and Daniel Potts,
+ * Traverse Technologies P/L www.traverse.com.au
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define NJ_CTRL 0x00
+#define NJ_DMACTRL 0x01
+#define NJ_AUXCTRL 0x02
+#define NJ_AUXDATA 0x03
+#define NJ_IRQMASK0 0x04
+#define NJ_IRQMASK1 0x05
+#define NJ_IRQSTAT0 0x06
+#define NJ_IRQSTAT1 0x07
+#define NJ_DMA_READ_START 0x08
+#define NJ_DMA_READ_IRQ 0x0c
+#define NJ_DMA_READ_END 0x10
+#define NJ_DMA_READ_ADR 0x14
+#define NJ_DMA_WRITE_START 0x18
+#define NJ_DMA_WRITE_IRQ 0x1c
+#define NJ_DMA_WRITE_END 0x20
+#define NJ_DMA_WRITE_ADR 0x24
+#define NJ_PULSE_CNT 0x28
+
+#define NJ_ISAC_OFF 0xc0
+#define NJ_ISACIRQ 0x10
+
+#define NJ_IRQM0_RD_MASK 0x03
+#define NJ_IRQM0_RD_IRQ 0x01
+#define NJ_IRQM0_RD_END 0x02
+#define NJ_IRQM0_WR_MASK 0x0c
+#define NJ_IRQM0_WR_IRQ 0x04
+#define NJ_IRQM0_WR_END 0x08
+
+/* one page here is no need to be smaller */
+#define NJ_DMA_SIZE 4096
+/* 2 * 64 byte is a compromise between IRQ count and latency */
+#define NJ_DMA_RXSIZE 128 /* 2 * 64 */
+#define NJ_DMA_TXSIZE 128 /* 2 * 64 */
+
diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c
new file mode 100644
index 000000000000..ff3a4e290da3
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/speedfax.c
@@ -0,0 +1,526 @@
+/*
+ * speedfax.c low level stuff for Sedlbauer Speedfax+ cards
+ * based on the ISAR DSP
+ * Thanks to Sedlbauer AG for informations and HW
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include <linux/firmware.h>
+#include "ipac.h"
+#include "isar.h"
+
+#define SPEEDFAX_REV "2.0"
+
+#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
+#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
+#define PCI_SUB_ID_SEDLBAUER 0x01
+
+#define SFAX_PCI_ADDR 0xc8
+#define SFAX_PCI_ISAC 0xd0
+#define SFAX_PCI_ISAR 0xe0
+
+/* TIGER 100 Registers */
+
+#define TIGER_RESET_ADDR 0x00
+#define TIGER_EXTERN_RESET_ON 0x01
+#define TIGER_EXTERN_RESET_OFF 0x00
+#define TIGER_AUX_CTRL 0x02
+#define TIGER_AUX_DATA 0x03
+#define TIGER_AUX_IRQMASK 0x05
+#define TIGER_AUX_STATUS 0x07
+
+/* Tiger AUX BITs */
+#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */
+#define SFAX_ISAR_RESET_BIT_OFF 0x00
+#define SFAX_ISAR_RESET_BIT_ON 0x01
+#define SFAX_TIGER_IRQ_BIT 0x02
+#define SFAX_LED1_BIT 0x08
+#define SFAX_LED2_BIT 0x10
+
+#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON)
+#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT)
+
+static int sfax_cnt;
+static u32 debug;
+static u32 irqloops = 4;
+
+struct sfax_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ u32 cfg;
+ struct _ioport p_isac;
+ struct _ioport p_isar;
+ u8 aux_data;
+ spinlock_t lock; /* HW access lock */
+ struct isac_hw isac;
+ struct isar_hw isar;
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct sfax_hw *card)
+{
+ card->isac.dch.debug = debug;
+ card->isar.ch[0].bch.debug = debug;
+ card->isar.ch[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct sfax_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SPEEDFAX_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Speedfax debug mask");
+module_param(irqloops, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");
+
+IOFUNC_IND(ISAC, sfax_hw, p_isac)
+IOFUNC_IND(ISAR, sfax_hw, p_isar)
+
+static irqreturn_t
+speedfax_irq(int intno, void *dev_id)
+{
+ struct sfax_hw *sf = dev_id;
+ u8 val;
+ int cnt = irqloops;
+
+ spin_lock(&sf->lock);
+ val = inb(sf->cfg + TIGER_AUX_STATUS);
+ if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */
+ spin_unlock(&sf->lock);
+ return IRQ_NONE; /* shared */
+ }
+ sf->irqcnt++;
+ val = ReadISAR_IND(sf, ISAR_IRQBIT);
+Start_ISAR:
+ if (val & ISAR_IRQSTA)
+ mISDNisar_irq(&sf->isar);
+ val = ReadISAC_IND(sf, ISAC_ISTA);
+ if (val)
+ mISDNisac_irq(&sf->isac, val);
+ val = ReadISAR_IND(sf, ISAR_IRQBIT);
+ if ((val & ISAR_IRQSTA) && cnt--)
+ goto Start_ISAR;
+ if (cnt < irqloops)
+ pr_debug("%s: %d irqloops cpu%d\n", sf->name,
+ irqloops - cnt, smp_processor_id());
+ if (irqloops && !cnt)
+ pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,
+ irqloops, smp_processor_id());
+ spin_unlock(&sf->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(struct sfax_hw *sf)
+{
+ WriteISAC_IND(sf, ISAC_MASK, 0);
+ WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);
+ outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);
+}
+
+static void
+disable_hwirq(struct sfax_hw *sf)
+{
+ WriteISAC_IND(sf, ISAC_MASK, 0xFF);
+ WriteISAR_IND(sf, ISAR_IRQBIT, 0);
+ outb(0, sf->cfg + TIGER_AUX_IRQMASK);
+}
+
+static void
+reset_speedfax(struct sfax_hw *sf)
+{
+
+ pr_debug("%s: resetting card\n", sf->name);
+ outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);
+ outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);
+ mdelay(1);
+ outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);
+ sf->aux_data = SFAX_PCI_RESET_OFF;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ mdelay(1);
+}
+
+static int
+sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case HW_RESET_REQ:
+ reset_speedfax(sf);
+ break;
+ case HW_ACTIVATE_IND:
+ if (arg & 1)
+ sf->aux_data &= ~SFAX_LED1_BIT;
+ if (arg & 2)
+ sf->aux_data &= ~SFAX_LED2_BIT;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ break;
+ case HW_DEACT_IND:
+ if (arg & 1)
+ sf->aux_data |= SFAX_LED1_BIT;
+ if (arg & 2)
+ sf->aux_data |= SFAX_LED2_BIT;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ break;
+ default:
+ pr_info("%s: %s unknown command %x %lx\n",
+ sf->name, __func__, cmd, arg);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: unknown Op %x\n", sf->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct sfax_hw *sf = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = sf->isac.open(&sf->isac, rq);
+ else
+ err = sf->isar.open(&sf->isar, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", sf->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", sf->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(sf, arg);
+ break;
+ default:
+ pr_debug("%s: unknown command %x\n", sf->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int __devinit
+init_card(struct sfax_hw *sf)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&sf->lock, flags);
+ ret = sf->isac.init(&sf->isac);
+ if (ret) {
+ spin_unlock_irqrestore(&sf->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ sf->name, ret);
+ break;
+ }
+ enable_hwirq(sf);
+ /* RESET Receiver and Transmitter */
+ WriteISAC_IND(sf, ISAC_CMDR, 0x41);
+ spin_unlock_irqrestore(&sf->lock, flags);
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", sf->name,
+ sf->irq, sf->irqcnt);
+ if (!sf->irqcnt) {
+ pr_info("%s: IRQ(%d) got no requests during init %d\n",
+ sf->name, sf->irq, 3 - cnt);
+ } else
+ return 0;
+ }
+ free_irq(sf->irq, sf);
+ return -EIO;
+}
+
+
+static int __devinit
+setup_speedfax(struct sfax_hw *sf)
+{
+ u_long flags;
+
+ if (!request_region(sf->cfg, 256, sf->name)) {
+ pr_info("mISDN: %s config port %x-%x already in use\n",
+ sf->name, sf->cfg, sf->cfg + 255);
+ return -EIO;
+ }
+ outb(0xff, sf->cfg);
+ outb(0, sf->cfg);
+ outb(0xdd, sf->cfg + TIGER_AUX_CTRL);
+ outb(0, sf->cfg + TIGER_AUX_IRQMASK);
+
+ sf->isac.type = IPAC_TYPE_ISAC;
+ sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;
+ sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;
+ sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;
+ sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;
+ ASSIGN_FUNC(IND, ISAC, sf->isac);
+ ASSIGN_FUNC(IND, ISAR, sf->isar);
+ spin_lock_irqsave(&sf->lock, flags);
+ reset_speedfax(sf);
+ disable_hwirq(sf);
+ spin_unlock_irqrestore(&sf->lock, flags);
+ return 0;
+}
+
+static void
+release_card(struct sfax_hw *card) {
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->isac.release(&card->isac);
+ free_irq(card->irq, card);
+ card->isar.release(&card->isar);
+ mISDN_unregister_device(&card->isac.dch.dev);
+ release_region(card->cfg, 256);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ sfax_cnt--;
+}
+
+static int __devinit
+setup_instance(struct sfax_hw *card)
+{
+ const struct firmware *firmware;
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+ _set_debug(card);
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ card->isar.hwlock = &card->lock;
+ card->isar.ctrl = (void *)&sfax_ctrl;
+ card->isac.name = card->name;
+ card->isar.name = card->name;
+ card->isar.owner = THIS_MODULE;
+
+ err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);
+ if (err < 0) {
+ pr_info("%s: firmware request failed %d\n",
+ card->name, err);
+ goto error_fw;
+ }
+ if (debug & DEBUG_HW)
+ pr_notice("%s: got firmware %zu bytes\n",
+ card->name, firmware->size);
+
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.D.ctrl = sfax_dctrl;
+ card->isac.dch.dev.Bprotocols =
+ mISDNisar_init(&card->isar, card);
+ for (i = 0; i < 2; i++) {
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ list_add(&card->isar.ch[i].bch.ch.list,
+ &card->isac.dch.dev.bchannels);
+ }
+
+ err = setup_speedfax(card);
+ if (err)
+ goto error_setup;
+ err = card->isar.init(&card->isar);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev,
+ &card->pdev->dev, card->name);
+ if (err)
+ goto error;
+ err = init_card(card);
+ if (err)
+ goto error_init;
+ err = card->isar.firmware(&card->isar, firmware->data, firmware->size);
+ if (!err) {
+ release_firmware(firmware);
+ sfax_cnt++;
+ pr_notice("SpeedFax %d cards installed\n", sfax_cnt);
+ return 0;
+ }
+ disable_hwirq(card);
+ free_irq(card->irq, card);
+error_init:
+ mISDN_unregister_device(&card->isac.dch.dev);
+error:
+ release_region(card->cfg, 256);
+error_setup:
+ card->isac.release(&card->isac);
+ card->isar.release(&card->isar);
+ release_firmware(firmware);
+error_fw:
+ pci_disable_device(card->pdev);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL);
+
+ if (!card) {
+ pr_info("No memory for Speedfax+ PCI\n");
+ return err;
+ }
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ pr_notice("mISDN: Speedfax found adapter %s at %s\n",
+ (char *)ent->driver_data, pci_name(pdev));
+
+ card->cfg = pci_resource_start(pdev, 0);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+sfax_remove_pci(struct pci_dev *pdev)
+{
+ struct sfax_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ pr_debug("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id sfaxpci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
+ 0, 0, (unsigned long) "Pyramid Speedfax + PCI"
+ },
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,
+ 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI"
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, sfaxpci_ids);
+
+static struct pci_driver sfaxpci_driver = {
+ .name = "speedfax+ pci",
+ .probe = sfaxpci_probe,
+ .remove = __devexit_p(sfax_remove_pci),
+ .id_table = sfaxpci_ids,
+};
+
+static int __init
+Speedfax_init(void)
+{
+ int err;
+
+ pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",
+ SPEEDFAX_REV);
+ err = pci_register_driver(&sfaxpci_driver);
+ return err;
+}
+
+static void __exit
+Speedfax_cleanup(void)
+{
+ pci_unregister_driver(&sfaxpci_driver);
+}
+
+module_init(Speedfax_init);
+module_exit(Speedfax_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
new file mode 100644
index 000000000000..d3f1077b709b
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -0,0 +1,1440 @@
+/*
+ * w6692.c mISDN driver for Winbond w6692 based cards
+ *
+ * Author Karsten Keil <kkeil@suse.de>
+ * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "w6692.h"
+
+#define W6692_REV "2.0"
+
+#define DBUSY_TIMER_VALUE 80
+
+enum {
+ W6692_ASUS,
+ W6692_WINBOND,
+ W6692_USR
+};
+
+/* private data in the PCI devices list */
+struct w6692map {
+ u_int subtype;
+ char *name;
+};
+
+static const struct w6692map w6692_map[] =
+{
+ {W6692_ASUS, "Dynalink/AsusCom IS64PH"},
+ {W6692_WINBOND, "Winbond W6692"},
+ {W6692_USR, "USR W6692"}
+};
+
+#ifndef PCI_VENDOR_ID_USR
+#define PCI_VENDOR_ID_USR 0x16ec
+#define PCI_DEVICE_ID_USR_6692 0x3409
+#endif
+
+struct w6692_ch {
+ struct bchannel bch;
+ u32 addr;
+ struct timer_list timer;
+ u8 b_mode;
+};
+
+struct w6692_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ u32 addr;
+ u32 fmask; /* feature mask - bit set per card nr */
+ int subtype;
+ spinlock_t lock; /* hw lock */
+ u8 imask;
+ u8 pctl;
+ u8 xaddr;
+ u8 xdata;
+ u8 state;
+ struct w6692_ch bc[2];
+ struct dchannel dch;
+ char log[64];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static int w6692_cnt;
+static int debug;
+static u32 led;
+static u32 pots;
+
+static void
+_set_debug(struct w6692_hw *card)
+{
+ card->dch.debug = debug;
+ card->bc[0].bch.debug = debug;
+ card->bc[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct w6692_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(W6692_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "W6692 debug mask");
+module_param(led, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)");
+module_param(pots, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)");
+
+static inline u8
+ReadW6692(struct w6692_hw *card, u8 offset)
+{
+ return inb(card->addr + offset);
+}
+
+static inline void
+WriteW6692(struct w6692_hw *card, u8 offset, u8 value)
+{
+ outb(value, card->addr + offset);
+}
+
+static inline u8
+ReadW6692B(struct w6692_ch *bc, u8 offset)
+{
+ return inb(bc->addr + offset);
+}
+
+static inline void
+WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value)
+{
+ outb(value, bc->addr + offset);
+}
+
+static void
+enable_hwirq(struct w6692_hw *card)
+{
+ WriteW6692(card, W_IMASK, card->imask);
+}
+
+static void
+disable_hwirq(struct w6692_hw *card)
+{
+ WriteW6692(card, W_IMASK, 0xff);
+}
+
+static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"};
+
+static void
+W6692Version(struct w6692_hw *card)
+{
+ int val;
+
+ val = ReadW6692(card, W_D_RBCH);
+ pr_notice("%s: Winbond W6692 version: %s\n", card->name,
+ W6692Ver[(val >> 6) & 3]);
+}
+
+static void
+w6692_led_handler(struct w6692_hw *card, int on)
+{
+ if ((!(card->fmask & led)) || card->subtype == W6692_USR)
+ return;
+ if (on) {
+ card->xdata &= 0xfb; /* LED ON */
+ WriteW6692(card, W_XDATA, card->xdata);
+ } else {
+ card->xdata |= 0x04; /* LED OFF */
+ WriteW6692(card, W_XDATA, card->xdata);
+ }
+}
+
+static void
+ph_command(struct w6692_hw *card, u8 cmd)
+{
+ pr_debug("%s: ph_command %x\n", card->name, cmd);
+ WriteW6692(card, W_CIX, cmd);
+}
+
+static void
+W6692_new_ph(struct w6692_hw *card)
+{
+ if (card->state == W_L1CMD_RST)
+ ph_command(card, W_L1CMD_DRC);
+ schedule_event(&card->dch, FLG_PHCHANGE);
+}
+
+static void
+W6692_ph_bh(struct dchannel *dch)
+{
+ struct w6692_hw *card = dch->hw;
+
+ switch (card->state) {
+ case W_L1CMD_RST:
+ dch->state = 0;
+ l1_event(dch->l1, HW_RESET_IND);
+ break;
+ case W_L1IND_CD:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_CNF);
+ break;
+ case W_L1IND_DRD:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_IND);
+ break;
+ case W_L1IND_CE:
+ dch->state = 4;
+ l1_event(dch->l1, HW_POWERUP_IND);
+ break;
+ case W_L1IND_LD:
+ if (dch->state <= 5) {
+ dch->state = 5;
+ l1_event(dch->l1, ANYSIGNAL);
+ } else {
+ dch->state = 8;
+ l1_event(dch->l1, LOSTFRAMING);
+ }
+ break;
+ case W_L1IND_ARD:
+ dch->state = 6;
+ l1_event(dch->l1, INFO2);
+ break;
+ case W_L1IND_AI8:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P8);
+ break;
+ case W_L1IND_AI10:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P10);
+ break;
+ default:
+ pr_debug("%s: TE unknown state %02x dch state %02x\n",
+ card->name, card->state, dch->state);
+ break;
+ }
+ pr_debug("%s: TE newstate %02x\n", card->name, dch->state);
+}
+
+static void
+W6692_empty_Dfifo(struct w6692_hw *card, int count)
+{
+ struct dchannel *dch = &card->dch;
+ u8 *ptr;
+
+ pr_debug("%s: empty_Dfifo %d\n", card->name, count);
+ if (!dch->rx_skb) {
+ dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC);
+ if (!dch->rx_skb) {
+ pr_info("%s: D receive out of memory\n", card->name);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ return;
+ }
+ }
+ if ((dch->rx_skb->len + count) >= dch->maxlen) {
+ pr_debug("%s: empty_Dfifo overrun %d\n", card->name,
+ dch->rx_skb->len + count);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ return;
+ }
+ ptr = skb_put(dch->rx_skb, count);
+ insb(card->addr + W_D_RFIFO, ptr, count);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "D-recv %s %d ",
+ card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+W6692_fill_Dfifo(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+ int count;
+ u8 *ptr;
+ u8 cmd = W_D_CMDR_XMS;
+
+ pr_debug("%s: fill_Dfifo\n", card->name);
+ if (!dch->tx_skb)
+ return;
+ count = dch->tx_skb->len - dch->tx_idx;
+ if (count <= 0)
+ return;
+ if (count > W_D_FIFO_THRESH)
+ count = W_D_FIFO_THRESH;
+ else
+ cmd |= W_D_CMDR_XME;
+ ptr = dch->tx_skb->data + dch->tx_idx;
+ dch->tx_idx += count;
+ outsb(card->addr + W_D_XFIFO, ptr, count);
+ WriteW6692(card, W_D_CMDR, cmd);
+ if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+ pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name);
+ del_timer(&dch->timer);
+ }
+ init_timer(&dch->timer);
+ dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+ add_timer(&dch->timer);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "D-send %s %d ",
+ card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+d_retransmit(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+#ifdef FIXME
+ if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+ dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+ if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
+ /* Restart frame */
+ dch->tx_idx = 0;
+ W6692_fill_Dfifo(card);
+ } else if (dch->tx_skb) { /* should not happen */
+ pr_info("%s: %s without TX_BUSY\n", card->name, __func__);
+ test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
+ dch->tx_idx = 0;
+ W6692_fill_Dfifo(card);
+ } else {
+ pr_info("%s: XDU no TX_BUSY\n", card->name);
+ if (get_next_dframe(dch))
+ W6692_fill_Dfifo(card);
+ }
+}
+
+static void
+handle_rxD(struct w6692_hw *card) {
+ u8 stat;
+ int count;
+
+ stat = ReadW6692(card, W_D_RSTA);
+ if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
+ if (stat & W_D_RSTA_RDOV) {
+ pr_debug("%s: D-channel RDOV\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_rx++;
+#endif
+ }
+ if (stat & W_D_RSTA_CRCE) {
+ pr_debug("%s: D-channel CRC error\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_crc++;
+#endif
+ }
+ if (stat & W_D_RSTA_RMB) {
+ pr_debug("%s: D-channel ABORT\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_rx++;
+#endif
+ }
+ if (card->dch.rx_skb)
+ dev_kfree_skb(card->dch.rx_skb);
+ card->dch.rx_skb = NULL;
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
+ } else {
+ count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
+ if (count == 0)
+ count = W_D_FIFO_THRESH;
+ W6692_empty_Dfifo(card, count);
+ recv_Dchannel(&card->dch);
+ }
+}
+
+static void
+handle_txD(struct w6692_hw *card) {
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags))
+ del_timer(&card->dch.timer);
+ if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) {
+ W6692_fill_Dfifo(card);
+ } else {
+ if (card->dch.tx_skb)
+ dev_kfree_skb(card->dch.tx_skb);
+ if (get_next_dframe(&card->dch))
+ W6692_fill_Dfifo(card);
+ }
+}
+
+static void
+handle_statusD(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+ u8 exval, v1, cir;
+
+ exval = ReadW6692(card, W_D_EXIR);
+
+ pr_debug("%s: D_EXIR %02x\n", card->name, exval);
+ if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {
+ /* Transmit underrun/collision */
+ pr_debug("%s: D-channel underrun/collision\n", card->name);
+#ifdef ERROR_STATISTIC
+ dch->err_tx++;
+#endif
+ d_retransmit(card);
+ }
+ if (exval & W_D_EXI_RDOV) { /* RDOV */
+ pr_debug("%s: D-channel RDOV\n", card->name);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST);
+ }
+ if (exval & W_D_EXI_TIN2) /* TIN2 - never */
+ pr_debug("%s: spurious TIN2 interrupt\n", card->name);
+ if (exval & W_D_EXI_MOC) { /* MOC - not supported */
+ v1 = ReadW6692(card, W_MOSR);
+ pr_debug("%s: spurious MOC interrupt MOSR %02x\n",
+ card->name, v1);
+ }
+ if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */
+ cir = ReadW6692(card, W_CIR);
+ pr_debug("%s: ISC CIR %02X\n", card->name, cir);
+ if (cir & W_CIR_ICC) {
+ v1 = cir & W_CIR_COD_MASK;
+ pr_debug("%s: ph_state_change %x -> %x\n", card->name,
+ dch->state, v1);
+ card->state = v1;
+ if (card->fmask & led) {
+ switch (v1) {
+ case W_L1IND_AI8:
+ case W_L1IND_AI10:
+ w6692_led_handler(card, 1);
+ break;
+ default:
+ w6692_led_handler(card, 0);
+ break;
+ }
+ }
+ W6692_new_ph(card);
+ }
+ if (cir & W_CIR_SCC) {
+ v1 = ReadW6692(card, W_SQR);
+ pr_debug("%s: SCC SQR %02X\n", card->name, v1);
+ }
+ }
+ if (exval & W_D_EXI_WEXP)
+ pr_debug("%s: spurious WEXP interrupt!\n", card->name);
+ if (exval & W_D_EXI_TEXP)
+ pr_debug("%s: spurious TEXP interrupt!\n", card->name);
+}
+
+static void
+W6692_empty_Bfifo(struct w6692_ch *wch, int count)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ u8 *ptr;
+
+ pr_debug("%s: empty_Bfifo %d\n", card->name, count);
+ if (unlikely(wch->bch.state == ISDN_P_NONE)) {
+ pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ if (wch->bch.rx_skb)
+ skb_trim(wch->bch.rx_skb, 0);
+ return;
+ }
+ if (!wch->bch.rx_skb) {
+ wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC);
+ if (unlikely(!wch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n", card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RACT);
+ return;
+ }
+ }
+ if (wch->bch.rx_skb->len + count > wch->bch.maxlen) {
+ pr_debug("%s: empty_Bfifo incoming packet too large\n",
+ card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ skb_trim(wch->bch.rx_skb, 0);
+ return;
+ }
+ ptr = skb_put(wch->bch.rx_skb, count);
+ insb(wch->addr + W_B_RFIFO, ptr, count);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "B%1d-recv %s %d ",
+ wch->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+W6692_fill_Bfifo(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ int count;
+ u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS;
+
+ pr_debug("%s: fill Bfifo\n", card->name);
+ if (!wch->bch.tx_skb)
+ return;
+ count = wch->bch.tx_skb->len - wch->bch.tx_idx;
+ if (count <= 0)
+ return;
+ ptr = wch->bch.tx_skb->data + wch->bch.tx_idx;
+ if (count > W_B_FIFO_THRESH)
+ count = W_B_FIFO_THRESH;
+ else if (test_bit(FLG_HDLC, &wch->bch.Flags))
+ cmd |= W_B_CMDR_XME;
+
+ pr_debug("%s: fill Bfifo%d/%d\n", card->name,
+ count, wch->bch.tx_idx);
+ wch->bch.tx_idx += count;
+ outsb(wch->addr + W_B_XFIFO, ptr, count);
+ WriteW6692B(wch, W_B_CMDR, cmd);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "B%1d-send %s %d ",
+ wch->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static int
+setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ u16 *vol = (u16 *)skb->data;
+ u8 val;
+
+ if ((!(card->fmask & pots)) ||
+ !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ return -ENODEV;
+ if (skb->len < 2)
+ return -EINVAL;
+ if (*vol > 7)
+ return -EINVAL;
+ val = *vol & 7;
+ val = 7 - val;
+ if (mic) {
+ val <<= 3;
+ card->xaddr &= 0xc7;
+ } else {
+ card->xaddr &= 0xf8;
+ }
+ card->xaddr |= val;
+ WriteW6692(card, W_XADDR, card->xaddr);
+ return 0;
+}
+
+static int
+enable_pots(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+
+ if ((!(card->fmask & pots)) ||
+ !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ return -ENODEV;
+ wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0);
+ WriteW6692(card, W_PCTL, card->pctl);
+ return 0;
+}
+
+static int
+disable_pots(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+
+ if (!(card->fmask & pots))
+ return -ENODEV;
+ wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0);
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ return 0;
+}
+
+static int
+w6692_mode(struct w6692_ch *wch, u32 pr)
+{
+ struct w6692_hw *card;
+
+ card = wch->bch.hw;
+ pr_debug("%s: B%d protocol %x-->%x\n", card->name,
+ wch->bch.nr, wch->bch.state, pr);
+ switch (pr) {
+ case ISDN_P_NONE:
+ if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM))
+ disable_pots(wch);
+ wch->b_mode = 0;
+ mISDN_clear_bchannel(&wch->bch);
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ test_and_clear_bit(FLG_HDLC, &wch->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ wch->b_mode = W_B_MODE_MMS;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_EXIM, 0);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ wch->b_mode = W_B_MODE_ITF;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_ADM1, 0xff);
+ WriteW6692B(wch, W_B_ADM2, 0xff);
+ WriteW6692B(wch, W_B_EXIM, 0);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ test_and_set_bit(FLG_HDLC, &wch->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol %x not known\n", card->name, pr);
+ return -ENOPROTOOPT;
+ }
+ wch->bch.state = pr;
+ return 0;
+}
+
+static void
+send_next(struct w6692_ch *wch)
+{
+ if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len)
+ W6692_fill_Bfifo(wch);
+ else {
+ if (wch->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ confirm_Bsend(&wch->bch);
+ dev_kfree_skb(wch->bch.tx_skb);
+ }
+ if (get_next_bframe(&wch->bch))
+ W6692_fill_Bfifo(wch);
+ }
+}
+
+static void
+W6692B_interrupt(struct w6692_hw *card, int ch)
+{
+ struct w6692_ch *wch = &card->bc[ch];
+ int count;
+ u8 stat, star = 0;
+
+ stat = ReadW6692B(wch, W_B_EXIR);
+ pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat);
+ if (stat & W_B_EXI_RME) {
+ star = ReadW6692B(wch, W_B_STAR);
+ if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
+ if ((star & W_B_STAR_RDOV) &&
+ test_bit(FLG_ACTIVE, &wch->bch.Flags)) {
+ pr_debug("%s: B%d RDOV proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ }
+ if (test_bit(FLG_HDLC, &wch->bch.Flags)) {
+ if (star & W_B_STAR_CRCE) {
+ pr_debug("%s: B%d CRC error\n",
+ card->name, wch->bch.nr);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_crc++;
+#endif
+ }
+ if (star & W_B_STAR_RMB) {
+ pr_debug("%s: B%d message abort\n",
+ card->name, wch->bch.nr);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_inv++;
+#endif
+ }
+ }
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ if (wch->bch.rx_skb)
+ skb_trim(wch->bch.rx_skb, 0);
+ } else {
+ count = ReadW6692B(wch, W_B_RBCL) &
+ (W_B_FIFO_THRESH - 1);
+ if (count == 0)
+ count = W_B_FIFO_THRESH;
+ W6692_empty_Bfifo(wch, count);
+ recv_Bchannel(&wch->bch, 0);
+ }
+ }
+ if (stat & W_B_EXI_RMR) {
+ if (!(stat & W_B_EXI_RME))
+ star = ReadW6692B(wch, W_B_STAR);
+ if (star & W_B_STAR_RDOV) {
+ pr_debug("%s: B%d RDOV proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ } else {
+ W6692_empty_Bfifo(wch, W_B_FIFO_THRESH);
+ if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) &&
+ wch->bch.rx_skb && (wch->bch.rx_skb->len > 0))
+ recv_Bchannel(&wch->bch, 0);
+ }
+ }
+ if (stat & W_B_EXI_RDOV) {
+ /* only if it is not handled yet */
+ if (!(star & W_B_STAR_RDOV)) {
+ pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ }
+ }
+ if (stat & W_B_EXI_XFR) {
+ if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) {
+ star = ReadW6692B(wch, W_B_STAR);
+ pr_debug("%s: B%d star %02x\n", card->name,
+ wch->bch.nr, star);
+ }
+ if (star & W_B_STAR_XDOW) {
+ pr_debug("%s: B%d XDOW proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_xdu++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST |
+ W_B_CMDR_RACT);
+ /* resend */
+ if (wch->bch.tx_skb) {
+ if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ wch->bch.tx_idx = 0;
+ }
+ }
+ send_next(wch);
+ if (stat & W_B_EXI_XDUN)
+ return; /* handle XDOW only once */
+ }
+ if (stat & W_B_EXI_XDUN) {
+ pr_debug("%s: B%d XDUN proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_xdu++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+ /* resend */
+ if (wch->bch.tx_skb) {
+ if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ wch->bch.tx_idx = 0;
+ }
+ send_next(wch);
+ }
+}
+
+static irqreturn_t
+w6692_irq(int intno, void *dev_id)
+{
+ struct w6692_hw *card = dev_id;
+ u8 ista;
+
+ spin_lock(&card->lock);
+ ista = ReadW6692(card, W_ISTA);
+ if ((ista | card->imask) == card->imask) {
+ /* possible a shared IRQ reqest */
+ spin_unlock(&card->lock);
+ return IRQ_NONE;
+ }
+ card->irqcnt++;
+ pr_debug("%s: ista %02x\n", card->name, ista);
+ ista &= ~card->imask;
+ if (ista & W_INT_B1_EXI)
+ W6692B_interrupt(card, 0);
+ if (ista & W_INT_B2_EXI)
+ W6692B_interrupt(card, 1);
+ if (ista & W_INT_D_RME)
+ handle_rxD(card);
+ if (ista & W_INT_D_RMR)
+ W6692_empty_Dfifo(card, W_D_FIFO_THRESH);
+ if (ista & W_INT_D_XFR)
+ handle_txD(card);
+ if (ista & W_INT_D_EXI)
+ handle_statusD(card);
+ if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */
+ pr_debug("%s: W6692 spurious XINT!\n", card->name);
+/* End IRQ Handler */
+ spin_unlock(&card->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+dbusy_timer_handler(struct dchannel *dch)
+{
+ struct w6692_hw *card = dch->hw;
+ int rbch, star;
+ u_long flags;
+
+ if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ rbch = ReadW6692(card, W_D_RBCH);
+ star = ReadW6692(card, W_D_STAR);
+ pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
+ card->name, rbch, star);
+ if (star & W_D_STAR_XBZ) /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
+ else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
+ if (dch->tx_idx)
+ dch->tx_idx = 0;
+ else
+ pr_info("%s: W6692 D-Channel Busy no tx_idx\n",
+ card->name);
+ /* Transmitter reset */
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
+}
+
+void initW6692(struct w6692_hw *card)
+{
+ u8 val;
+
+ card->dch.timer.function = (void *)dbusy_timer_handler;
+ card->dch.timer.data = (u_long)&card->dch;
+ init_timer(&card->dch.timer);
+ w6692_mode(&card->bc[0], ISDN_P_NONE);
+ w6692_mode(&card->bc[1], ISDN_P_NONE);
+ WriteW6692(card, W_D_CTL, 0x00);
+ disable_hwirq(card);
+ WriteW6692(card, W_D_SAM, 0xff);
+ WriteW6692(card, W_D_TAM, 0xff);
+ WriteW6692(card, W_D_MODE, W_D_MODE_RACT);
+ card->state = W_L1CMD_RST;
+ ph_command(card, W_L1CMD_RST);
+ ph_command(card, W_L1CMD_ECK);
+ /* enable all IRQ but extern */
+ card->imask = 0x18;
+ WriteW6692(card, W_D_EXIM, 0x00);
+ WriteW6692B(&card->bc[0], W_B_EXIM, 0);
+ WriteW6692B(&card->bc[1], W_B_EXIM, 0);
+ /* Reset D-chan receiver and transmitter */
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
+ /* Reset B-chan receiver and transmitter */
+ WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ /* enable peripheral */
+ if (card->subtype == W6692_USR) {
+ /* seems that USR implemented some power control features
+ * Pin 79 is connected to the oscilator circuit so we
+ * have to handle it here
+ */
+ card->pctl = 0x80;
+ card->xdata = 0;
+ WriteW6692(card, W_PCTL, card->pctl);
+ WriteW6692(card, W_XDATA, card->xdata);
+ } else {
+ card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 |
+ W_PCTL_OE1 | W_PCTL_OE0;
+ card->xaddr = 0x00;/* all sw off */
+ if (card->fmask & pots)
+ card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */
+ if (card->fmask & led)
+ card->xdata |= 0x04; /* LED OFF */
+ if ((card->fmask & pots) || (card->fmask & led)) {
+ WriteW6692(card, W_PCTL, card->pctl);
+ WriteW6692(card, W_XADDR, card->xaddr);
+ WriteW6692(card, W_XDATA, card->xdata);
+ val = ReadW6692(card, W_XADDR);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: W_XADDR=%02x\n",
+ card->name, val);
+ }
+ }
+}
+
+static void
+reset_w6692(struct w6692_hw *card)
+{
+ WriteW6692(card, W_D_CTL, W_D_CTL_SRST);
+ mdelay(10);
+ WriteW6692(card, W_D_CTL, 0);
+}
+
+static int
+init_card(struct w6692_hw *card)
+{
+ int cnt = 3;
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) {
+ pr_info("%s: couldn't get interrupt %d\n", card->name,
+ card->irq);
+ return -EIO;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&card->lock, flags);
+ initW6692(card);
+ enable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ /* Timeout 10ms */
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", card->name,
+ card->irq, card->irqcnt);
+ if (!card->irqcnt) {
+ pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
+ card->name, card->irq, 3 - cnt);
+ reset_w6692(card);
+ } else
+ return 0;
+ }
+ free_irq(card->irq, card);
+ return -EIO;
+}
+
+static int
+w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
+ struct w6692_hw *card = bch->hw;
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ W6692_fill_Bfifo(bc);
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = w6692_mode(bc, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_clear_bchannel(bch);
+ w6692_mode(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ card->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct w6692_hw *card, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &card->bc[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+static int
+channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ default:
+ pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
+ struct w6692_hw *card = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ w6692_mode(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ card->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = dchannel_senddata(dch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ W6692_fill_Dfifo(card);
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ case PH_DEACTIVATE_REQ:
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ }
+
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+w6692_l1callback(struct dchannel *dch, u32 cmd)
+{
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ u_long flags;
+
+ pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state);
+ switch (cmd) {
+ case INFO3_P8:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_AR8);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case INFO3_P10:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_AR10);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case HW_RESET_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (card->state != W_L1IND_DRD)
+ ph_command(card, W_L1CMD_RST);
+ ph_command(card, W_L1CMD_ECK);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case HW_DEACT_REQ:
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+ break;
+ case HW_POWERUP_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_ECK);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case PH_ACTIVATE_IND:
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ case PH_DEACTIVATE_IND:
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n", card->name,
+ __func__, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+open_dchannel(struct w6692_hw *card, struct channel_req *rq)
+{
+ pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__,
+ card->dch.dev.id, __builtin_return_address(1));
+ if (rq->protocol != ISDN_P_TE_S0)
+ return -EINVAL;
+ if (rq->adr.channel == 1)
+ /* E-Channel not supported */
+ return -EINVAL;
+ rq->ch = &card->dch.dev.D;
+ rq->ch->protocol = rq->protocol;
+ if (card->dch.state == 7)
+ _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ return 0;
+}
+
+static int
+w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = open_dchannel(card, rq);
+ else
+ err = open_bchannel(card, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", card->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", card->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(card, arg);
+ break;
+ default:
+ pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int
+setup_w6692(struct w6692_hw *card)
+{
+ u32 val;
+
+ if (!request_region(card->addr, 256, card->name)) {
+ pr_info("%s: config port %x-%x already in use\n", card->name,
+ card->addr, card->addr + 255);
+ return -EIO;
+ }
+ W6692Version(card);
+ card->bc[0].addr = card->addr;
+ card->bc[1].addr = card->addr + 0x40;
+ val = ReadW6692(card, W_ISTA);
+ if (debug & DEBUG_HW)
+ pr_notice("%s ISTA=%02x\n", card->name, val);
+ val = ReadW6692(card, W_IMASK);
+ if (debug & DEBUG_HW)
+ pr_notice("%s IMASK=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_EXIR);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_EXIR=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_EXIM);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_EXIM=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_RSTA);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_RSTA=%02x\n", card->name, val);
+ return 0;
+}
+
+static void
+release_card(struct w6692_hw *card)
+{
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ w6692_mode(&card->bc[0], ISDN_P_NONE);
+ w6692_mode(&card->bc[1], ISDN_P_NONE);
+ if ((card->fmask & led) || card->subtype == W6692_USR) {
+ card->xdata |= 0x04; /* LED OFF */
+ WriteW6692(card, W_XDATA, card->xdata);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+ free_irq(card->irq, card);
+ l1_event(card->dch.l1, CLOSE_CHANNEL);
+ mISDN_unregister_device(&card->dch.dev);
+ release_region(card->addr, 256);
+ mISDN_freebchannel(&card->bc[1].bch);
+ mISDN_freebchannel(&card->bc[0].bch);
+ mISDN_freedchannel(&card->dch);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ kfree(card);
+}
+
+static int
+setup_instance(struct w6692_hw *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+ card->fmask = (1 << w6692_cnt);
+ _set_debug(card);
+ spin_lock_init(&card->lock);
+ mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh);
+ card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
+ card->dch.dev.D.send = w6692_l2l1D;
+ card->dch.dev.D.ctrl = w6692_dctrl;
+ card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->dch.hw = card;
+ card->dch.dev.nrbchan = 2;
+ for (i = 0; i < 2; i++) {
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ card->bc[i].bch.hw = card;
+ card->bc[i].bch.nr = i + 1;
+ card->bc[i].bch.ch.nr = i + 1;
+ card->bc[i].bch.ch.send = w6692_l2l1B;
+ card->bc[i].bch.ch.ctrl = w6692_bctrl;
+ set_channelmap(i + 1, card->dch.dev.channelmap);
+ list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels);
+ }
+ err = setup_w6692(card);
+ if (err)
+ goto error_setup;
+ err = mISDN_register_device(&card->dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error_reg;
+ err = init_card(card);
+ if (err)
+ goto error_init;
+ err = create_l1(&card->dch, w6692_l1callback);
+ if (!err) {
+ w6692_cnt++;
+ pr_notice("W6692 %d cards installed\n", w6692_cnt);
+ return 0;
+ }
+
+ free_irq(card->irq, card);
+error_init:
+ mISDN_unregister_device(&card->dch.dev);
+error_reg:
+ release_region(card->addr, 256);
+error_setup:
+ mISDN_freebchannel(&card->bc[1].bch);
+ mISDN_freebchannel(&card->bc[0].bch);
+ mISDN_freedchannel(&card->dch);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct w6692_hw *card;
+ struct w6692map *m = (struct w6692map *)ent->driver_data;
+
+ card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL);
+ if (!card) {
+ pr_info("No kmem for w6692 card\n");
+ return err;
+ }
+ card->pdev = pdev;
+ card->subtype = m->subtype;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
+ m->name, pci_name(pdev));
+
+ card->addr = pci_resource_start(pdev, 1);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+w6692_remove_pci(struct pci_dev *pdev)
+{
+ struct w6692_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ if (debug)
+ pr_notice("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id w6692_ids[] = {
+ { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]},
+ { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
+ PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0,
+ (ulong)&w6692_map[2]},
+ { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, w6692_ids);
+
+static struct pci_driver w6692_driver = {
+ .name = "w6692",
+ .probe = w6692_probe,
+ .remove = __devexit_p(w6692_remove_pci),
+ .id_table = w6692_ids,
+};
+
+static int __init w6692_init(void)
+{
+ int err;
+
+ pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV);
+
+ err = pci_register_driver(&w6692_driver);
+ return err;
+}
+
+static void __exit w6692_cleanup(void)
+{
+ pci_unregister_driver(&w6692_driver);
+}
+
+module_init(w6692_init);
+module_exit(w6692_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h
new file mode 100644
index 000000000000..f95697757fd0
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/w6692.h
@@ -0,0 +1,190 @@
+/*
+ * Winbond W6692 specific defines
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* Specifications of W6692 registers */
+
+#define W_D_RFIFO 0x00 /* R */
+#define W_D_XFIFO 0x04 /* W */
+#define W_D_CMDR 0x08 /* W */
+#define W_D_MODE 0x0c /* R/W */
+#define W_D_TIMR 0x10 /* R/W */
+#define W_ISTA 0x14 /* R_clr */
+#define W_IMASK 0x18 /* R/W */
+#define W_D_EXIR 0x1c /* R_clr */
+#define W_D_EXIM 0x20 /* R/W */
+#define W_D_STAR 0x24 /* R */
+#define W_D_RSTA 0x28 /* R */
+#define W_D_SAM 0x2c /* R/W */
+#define W_D_SAP1 0x30 /* R/W */
+#define W_D_SAP2 0x34 /* R/W */
+#define W_D_TAM 0x38 /* R/W */
+#define W_D_TEI1 0x3c /* R/W */
+#define W_D_TEI2 0x40 /* R/W */
+#define W_D_RBCH 0x44 /* R */
+#define W_D_RBCL 0x48 /* R */
+#define W_TIMR2 0x4c /* W */
+#define W_L1_RC 0x50 /* R/W */
+#define W_D_CTL 0x54 /* R/W */
+#define W_CIR 0x58 /* R */
+#define W_CIX 0x5c /* W */
+#define W_SQR 0x60 /* R */
+#define W_SQX 0x64 /* W */
+#define W_PCTL 0x68 /* R/W */
+#define W_MOR 0x6c /* R */
+#define W_MOX 0x70 /* R/W */
+#define W_MOSR 0x74 /* R_clr */
+#define W_MOCR 0x78 /* R/W */
+#define W_GCR 0x7c /* R/W */
+
+#define W_B_RFIFO 0x80 /* R */
+#define W_B_XFIFO 0x84 /* W */
+#define W_B_CMDR 0x88 /* W */
+#define W_B_MODE 0x8c /* R/W */
+#define W_B_EXIR 0x90 /* R_clr */
+#define W_B_EXIM 0x94 /* R/W */
+#define W_B_STAR 0x98 /* R */
+#define W_B_ADM1 0x9c /* R/W */
+#define W_B_ADM2 0xa0 /* R/W */
+#define W_B_ADR1 0xa4 /* R/W */
+#define W_B_ADR2 0xa8 /* R/W */
+#define W_B_RBCL 0xac /* R */
+#define W_B_RBCH 0xb0 /* R */
+
+#define W_XADDR 0xf4 /* R/W */
+#define W_XDATA 0xf8 /* R/W */
+#define W_EPCTL 0xfc /* W */
+
+/* W6692 register bits */
+
+#define W_D_CMDR_XRST 0x01
+#define W_D_CMDR_XME 0x02
+#define W_D_CMDR_XMS 0x08
+#define W_D_CMDR_STT 0x10
+#define W_D_CMDR_RRST 0x40
+#define W_D_CMDR_RACK 0x80
+
+#define W_D_MODE_RLP 0x01
+#define W_D_MODE_DLP 0x02
+#define W_D_MODE_MFD 0x04
+#define W_D_MODE_TEE 0x08
+#define W_D_MODE_TMS 0x10
+#define W_D_MODE_RACT 0x40
+#define W_D_MODE_MMS 0x80
+
+#define W_INT_B2_EXI 0x01
+#define W_INT_B1_EXI 0x02
+#define W_INT_D_EXI 0x04
+#define W_INT_XINT0 0x08
+#define W_INT_XINT1 0x10
+#define W_INT_D_XFR 0x20
+#define W_INT_D_RME 0x40
+#define W_INT_D_RMR 0x80
+
+#define W_D_EXI_WEXP 0x01
+#define W_D_EXI_TEXP 0x02
+#define W_D_EXI_ISC 0x04
+#define W_D_EXI_MOC 0x08
+#define W_D_EXI_TIN2 0x10
+#define W_D_EXI_XCOL 0x20
+#define W_D_EXI_XDUN 0x40
+#define W_D_EXI_RDOV 0x80
+
+#define W_D_STAR_DRDY 0x10
+#define W_D_STAR_XBZ 0x20
+#define W_D_STAR_XDOW 0x80
+
+#define W_D_RSTA_RMB 0x10
+#define W_D_RSTA_CRCE 0x20
+#define W_D_RSTA_RDOV 0x40
+
+#define W_D_CTL_SRST 0x20
+
+#define W_CIR_SCC 0x80
+#define W_CIR_ICC 0x40
+#define W_CIR_COD_MASK 0x0f
+
+#define W_PCTL_PCX 0x01
+#define W_PCTL_XMODE 0x02
+#define W_PCTL_OE0 0x04
+#define W_PCTL_OE1 0x08
+#define W_PCTL_OE2 0x10
+#define W_PCTL_OE3 0x20
+#define W_PCTL_OE4 0x40
+#define W_PCTL_OE5 0x80
+
+#define W_B_CMDR_XRST 0x01
+#define W_B_CMDR_XME 0x02
+#define W_B_CMDR_XMS 0x04
+#define W_B_CMDR_RACT 0x20
+#define W_B_CMDR_RRST 0x40
+#define W_B_CMDR_RACK 0x80
+
+#define W_B_MODE_FTS0 0x01
+#define W_B_MODE_FTS1 0x02
+#define W_B_MODE_SW56 0x04
+#define W_B_MODE_BSW0 0x08
+#define W_B_MODE_BSW1 0x10
+#define W_B_MODE_EPCM 0x20
+#define W_B_MODE_ITF 0x40
+#define W_B_MODE_MMS 0x80
+
+#define W_B_EXI_XDUN 0x01
+#define W_B_EXI_XFR 0x02
+#define W_B_EXI_RDOV 0x10
+#define W_B_EXI_RME 0x20
+#define W_B_EXI_RMR 0x40
+
+#define W_B_STAR_XBZ 0x01
+#define W_B_STAR_XDOW 0x04
+#define W_B_STAR_RMB 0x10
+#define W_B_STAR_CRCE 0x20
+#define W_B_STAR_RDOV 0x40
+
+#define W_B_RBCH_LOV 0x20
+
+/* W6692 Layer1 commands */
+
+#define W_L1CMD_ECK 0x00
+#define W_L1CMD_RST 0x01
+#define W_L1CMD_SCP 0x04
+#define W_L1CMD_SSP 0x02
+#define W_L1CMD_AR8 0x08
+#define W_L1CMD_AR10 0x09
+#define W_L1CMD_EAL 0x0a
+#define W_L1CMD_DRC 0x0f
+
+/* W6692 Layer1 indications */
+
+#define W_L1IND_CE 0x07
+#define W_L1IND_DRD 0x00
+#define W_L1IND_LD 0x04
+#define W_L1IND_ARD 0x08
+#define W_L1IND_TI 0x0a
+#define W_L1IND_ATI 0x0b
+#define W_L1IND_AI8 0x0c
+#define W_L1IND_AI10 0x0d
+#define W_L1IND_CD 0x0f
+
+/* FIFO thresholds */
+#define W_D_FIFO_THRESH 64
+#define W_B_FIFO_THRESH 64
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 7832d8ba8e44..3464ebc4cdbc 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -391,6 +391,7 @@ comment "HiSax sub driver modules"
config HISAX_ST5481
tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
+ select ISDN_HDLC
select CRC_CCITT
select BITREVERSE
help
@@ -418,11 +419,6 @@ config HISAX_FRITZ_PCIPNP
(the latter also needs you to select "ISA Plug and Play support"
from the menu "Plug and Play configuration")
-config HISAX_HDLC
- bool
- depends on HISAX_ST5481
- default y
-
config HISAX_AVM_A1_PCMCIA
bool
depends on HISAX_AVM_A1_CS
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index c7a3794bdae4..ab638b083df9 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -16,10 +16,6 @@ obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
-ifdef CONFIG_HISAX_HDLC
-obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o
-endif
-
# Multipart objects.
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 341faf58a65c..bf526a7a63af 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -238,8 +238,6 @@ Amd7930_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 025a20d487c5..475b1a020003 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -833,8 +833,6 @@ static struct FsmNode fnlist[] __initdata =
};
/* *INDENT-ON* */
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
int __init
CallcNew(void)
{
@@ -842,7 +840,7 @@ CallcNew(void)
callcfsm.event_count = EVENT_COUNT;
callcfsm.strEvent = strEvent;
callcfsm.strState = strState;
- return FsmNew(&callcfsm, fnlist, FNCOUNT);
+ return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist));
}
void
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 3d337d924c23..d110a77940a4 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1506,8 +1506,6 @@ hfcpci_bh(struct work_struct *work)
u_long flags;
// struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (!cs->hw.hfcpci.nt_mode)
switch (cs->dc.hfcpci.ph_state) {
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index d92e8d6c2ae2..419f87cad8cb 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1255,8 +1255,6 @@ hfcsx_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
u_long flags;
- if (!cs)
- return;
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (!cs->hw.hfcsx.nt_mode)
switch (cs->dc.hfcsx.ph_state) {
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index 682cac32f259..9aba646ba221 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -83,8 +83,6 @@ icc_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index 07b1673122b8..a19354d94343 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -86,8 +86,6 @@ isac_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h
deleted file mode 100644
index cf0a95a24015..000000000000
--- a/drivers/isdn/hisax/isdnhdlc.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * isdnhdlc.h -- General purpose ISDN HDLC decoder.
- *
- * Implementation of a HDLC decoder/encoder in software.
- * Neccessary because some ISDN devices don't have HDLC
- * controllers. Also included: a bit reversal table.
- *
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ISDNHDLC_H__
-#define __ISDNHDLC_H__
-
-struct isdnhdlc_vars {
- int bit_shift;
- int hdlc_bits1;
- int data_bits;
- int ffbit_shift; // encoding only
- int state;
- int dstpos;
-
- unsigned short crc;
-
- unsigned char cbin;
- unsigned char shift_reg;
- unsigned char ffvalue;
-
- unsigned int data_received:1; // set if transferring data
- unsigned int dchannel:1; // set if D channel (send idle instead of flags)
- unsigned int do_adapt56:1; // set if 56K adaptation
- unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag
-};
-
-
-/*
- The return value from isdnhdlc_decode is
- the frame length, 0 if no complete frame was decoded,
- or a negative error number
-*/
-#define HDLC_FRAMING_ERROR 1
-#define HDLC_CRC_ERROR 2
-#define HDLC_LENGTH_ERROR 3
-
-extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
-
-extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
- unsigned char *dst, int dsize);
-
-extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
-
-extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
- unsigned char *dst,int dsize);
-
-#endif /* __ISDNHDLC_H__ */
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 317f16f516f2..9ce6abe05b1a 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -647,8 +647,6 @@ static struct FsmNode L1SFnList[] __initdata =
{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
};
-#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
-
#ifdef HISAX_UINTERFACE
static void
l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
@@ -706,8 +704,6 @@ static struct FsmNode L1UFnList[] __initdata =
{ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
};
-#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
-
#endif
static void
@@ -754,8 +750,6 @@ static struct FsmNode L1BFnList[] __initdata =
{ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
};
-#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
-
int __init
Isdnl1New(void)
{
@@ -765,7 +759,7 @@ Isdnl1New(void)
l1fsm_s.event_count = L1_EVENT_COUNT;
l1fsm_s.strEvent = strL1Event;
l1fsm_s.strState = strL1SState;
- retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
+ retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
if (retval)
return retval;
@@ -773,7 +767,7 @@ Isdnl1New(void)
l1fsm_b.event_count = L1_EVENT_COUNT;
l1fsm_b.strEvent = strL1Event;
l1fsm_b.strState = strL1BState;
- retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+ retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList));
if (retval) {
FsmFree(&l1fsm_s);
return retval;
@@ -783,7 +777,7 @@ Isdnl1New(void)
l1fsm_u.event_count = L1_EVENT_COUNT;
l1fsm_u.strEvent = strL1Event;
l1fsm_u.strState = strL1UState;
- retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+ retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList));
if (retval) {
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 3446f249d675..7b9496a63b5f 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1623,8 +1623,6 @@ static struct FsmNode L2FnList[] __initdata =
{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
};
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
static void
isdnl2_l1l2(struct PStack *st, int pr, void *arg)
{
@@ -1836,7 +1834,7 @@ Isdnl2New(void)
l2fsm.event_count = L2_EVENT_COUNT;
l2fsm.strEvent = strL2Event;
l2fsm.strState = strL2State;
- return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+ return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
}
void
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 935f23356fae..06766022d3ae 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -543,8 +543,6 @@ static struct FsmNode L3FnList[] __initdata =
};
/* *INDENT-ON* */
-#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
-
void
l3_msg(struct PStack *st, int pr, void *arg)
{
@@ -587,7 +585,7 @@ Isdnl3New(void)
l3fsm.event_count = L3_EVENT_COUNT;
l3fsm.strEvent = strL3Event;
l3fsm.strState = strL3State;
- return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+ return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
}
void
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index c5c36eeff261..b0554f80bfb3 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -698,9 +698,6 @@ static struct stateentry downstl[] =
CC_T308_2, l3_1tr6_t308_2},
};
-#define DOWNSTL_LEN \
- (sizeof(downstl) / sizeof(struct stateentry))
-
static struct stateentry datastln1[] =
{
{SBIT(0),
@@ -735,9 +732,6 @@ static struct stateentry datastln1[] =
MT_N1_REL_ACK, l3_1tr6_rel_ack}
};
-#define DATASTLN1_LEN \
- (sizeof(datastln1) / sizeof(struct stateentry))
-
static struct stateentry manstatelist[] =
{
{SBIT(2),
@@ -746,8 +740,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3_1tr6_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
static void
@@ -840,11 +832,11 @@ up1tr6(struct PStack *st, int pr, void *arg)
mt = MT_N1_INVALID;
}
}
- for (i = 0; i < DATASTLN1_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastln1); i++)
if ((mt == datastln1[i].primitive) &&
((1 << proc->state) & datastln1[i].state))
break;
- if (i == DATASTLN1_LEN) {
+ if (i == ARRAY_SIZE(datastln1)) {
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
@@ -892,11 +884,11 @@ down1tr6(struct PStack *st, int pr, void *arg)
proc = arg;
}
- for (i = 0; i < DOWNSTL_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstl); i++)
if ((pr == downstl[i].primitive) &&
((1 << proc->state) & downstl[i].state))
break;
- if (i == DOWNSTL_LEN) {
+ if (i == ARRAY_SIZE(downstl)) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "down1tr6 state %d prim %d unhandled",
proc->state, pr);
@@ -922,11 +914,11 @@ man1tr6(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 99feae8b9210..a12fa4d34903 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -2820,9 +2820,6 @@ static struct stateentry downstatelist[] =
CC_T309, l3dss1_dl_release},
};
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct stateentry))
-
static struct stateentry datastatelist[] =
{
{ALL_STATES,
@@ -2875,9 +2872,6 @@ static struct stateentry datastatelist[] =
MT_RESUME_REJECT, l3dss1_resume_rej},
};
-#define DATASLLEN \
- (sizeof(datastatelist) / sizeof(struct stateentry))
-
static struct stateentry globalmes_list[] =
{
{ALL_STATES,
@@ -2888,8 +2882,6 @@ static struct stateentry globalmes_list[] =
MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
*/
};
-#define GLOBALM_LEN \
- (sizeof(globalmes_list) / sizeof(struct stateentry))
static struct stateentry manstatelist[] =
{
@@ -2903,8 +2895,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3dss1_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
@@ -2918,11 +2908,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
struct l3_process *proc = st->l3.global;
proc->callref = skb->data[2]; /* cr flag */
- for (i = 0; i < GLOBALM_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
if ((mt == globalmes_list[i].primitive) &&
((1 << proc->state) & globalmes_list[i].state))
break;
- if (i == GLOBALM_LEN) {
+ if (i == ARRAY_SIZE(globalmes_list)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1 global state %d mt %x unhandled",
proc->state, mt);
@@ -3097,11 +3087,11 @@ dss1up(struct PStack *st, int pr, void *arg)
}
if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
l3dss1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < DATASLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
if ((mt == datastatelist[i].primitive) &&
((1 << proc->state) & datastatelist[i].state))
break;
- if (i == DATASLLEN) {
+ if (i == ARRAY_SIZE(datastatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1up%sstate %d mt %#x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
@@ -3156,11 +3146,11 @@ dss1down(struct PStack *st, int pr, void *arg)
return;
}
- for (i = 0; i < DOWNSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
if ((pr == downstatelist[i].primitive) &&
((1 << proc->state) & downstatelist[i].state))
break;
- if (i == DOWNSLLEN) {
+ if (i == ARRAY_SIZE(downstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1down state %d prim %#x unhandled",
proc->state, pr);
@@ -3184,11 +3174,11 @@ dss1man(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index f7041d5ba64e..4622d43c7e10 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -2755,9 +2755,6 @@ static struct stateentry downstatelist[] =
CC_TSPID, l3ni1_spid_tout },
};
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct stateentry))
-
static struct stateentry datastatelist[] =
{
{ALL_STATES,
@@ -2810,9 +2807,6 @@ static struct stateentry datastatelist[] =
MT_RESUME_REJECT, l3ni1_resume_rej},
};
-#define DATASLLEN \
- (sizeof(datastatelist) / sizeof(struct stateentry))
-
static struct stateentry globalmes_list[] =
{
{ALL_STATES,
@@ -2825,8 +2819,6 @@ static struct stateentry globalmes_list[] =
{ SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send },
{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid },
};
-#define GLOBALM_LEN \
- (sizeof(globalmes_list) / sizeof(struct stateentry))
static struct stateentry manstatelist[] =
{
@@ -2840,8 +2832,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3ni1_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
@@ -2858,11 +2848,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
proc->callref = skb->data[2]; /* cr flag */
else
proc->callref = 0;
- for (i = 0; i < GLOBALM_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
if ((mt == globalmes_list[i].primitive) &&
((1 << proc->state) & globalmes_list[i].state))
break;
- if (i == GLOBALM_LEN) {
+ if (i == ARRAY_SIZE(globalmes_list)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1 global state %d mt %x unhandled",
proc->state, mt);
@@ -3049,11 +3039,11 @@ ni1up(struct PStack *st, int pr, void *arg)
}
if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
l3ni1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < DATASLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
if ((mt == datastatelist[i].primitive) &&
((1 << proc->state) & datastatelist[i].state))
break;
- if (i == DATASLLEN) {
+ if (i == ARRAY_SIZE(datastatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
@@ -3108,11 +3098,11 @@ ni1down(struct PStack *st, int pr, void *arg)
return;
}
- for (i = 0; i < DOWNSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
if ((pr == downstatelist[i].primitive) &&
((1 << proc->state) & downstatelist[i].state))
break;
- if (i == DOWNSLLEN) {
+ if (i == ARRAY_SIZE(downstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1down state %d prim %#x unhandled",
proc->state, pr);
@@ -3136,11 +3126,11 @@ ni1man(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index aacbf0d14b64..8b853d58e820 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -140,7 +140,7 @@ struct MessageType {
}
};
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
+#define MTSIZE ARRAY_SIZE(mtlist)
static
struct MessageType mt_n0[] =
@@ -157,7 +157,7 @@ struct MessageType mt_n0[] =
{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
};
-#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType))
+#define MT_N0_LEN ARRAY_SIZE(mt_n0)
static
struct MessageType mt_n1[] =
@@ -194,7 +194,7 @@ struct MessageType mt_n1[] =
{MT_N1_STAT, "STATus"}
};
-#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
+#define MT_N1_LEN ARRAY_SIZE(mt_n1)
static int
@@ -438,7 +438,7 @@ struct CauseValue {
},
};
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
+#define CVSIZE ARRAY_SIZE(cvlist)
static
int
@@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] =
{CAUSE_UserInfoDiscarded, "User Info Discarded"}
};
-static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
static int
prcause_1tr6(char *dest, u_char * p)
@@ -865,7 +865,7 @@ struct DTag { /* Display tags */
{ 0x96, "Redirection name" },
{ 0x9e, "Text" },
};
-#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
+#define DTAGSIZE ARRAY_SIZE(dtaglist)
static int
disptext_ni1(char *dest, u_char * p)
@@ -1074,7 +1074,7 @@ struct InformationElement {
};
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+#define IESIZE ARRAY_SIZE(ielist)
static
struct InformationElement ielist_ni1[] = {
@@ -1102,7 +1102,7 @@ struct InformationElement ielist_ni1[] = {
};
-#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
+#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
static
struct InformationElement ielist_ni1_cs5[] = {
@@ -1110,14 +1110,14 @@ struct InformationElement ielist_ni1_cs5[] = {
{ 0x2a, "Display text", disptext_ni1 },
};
-#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
+#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
static
struct InformationElement ielist_ni1_cs6[] = {
{ 0x7b, "Call appearance", general_ni1 },
};
-#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
+#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
static struct InformationElement we_0[] =
{
@@ -1133,7 +1133,7 @@ static struct InformationElement we_0[] =
{WE0_userInfo, "User Info", general}
};
-#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement))
+#define WE_0_LEN ARRAY_SIZE(we_0)
static struct InformationElement we_6[] =
{
@@ -1145,7 +1145,7 @@ static struct InformationElement we_6[] =
{WE6_statusCalled, "Status Called", general},
{WE6_addTransAttr, "Additional Transmission Attributes", general}
};
-#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
+#define WE_6_LEN ARRAY_SIZE(we_6)
int
QuickHex(char *txt, u_char * p, int cnt)
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index cff7a6354334..64f78a8c28c5 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -226,7 +226,7 @@ printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define INFO(format, arg...) \
printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
-#include "isdnhdlc.h"
+#include <linux/isdn/hdlc.h>
#include "fsm.h"
#include "hisax_if.h"
#include <linux/skbuff.h>
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
index 0074b600a0ef..95b1cdd97958 100644
--- a/drivers/isdn/hisax/st5481_b.c
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode)
if (bcs->mode != L1_MODE_NULL) {
// Open the B channel
if (bcs->mode != L1_MODE_TRANS) {
- isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+ u32 features = HDLC_BITREVERSE;
+ if (bcs->mode == L1_MODE_HDLC_56K)
+ features |= HDLC_56KBIT;
+ isdnhdlc_out_init(&b_out->hdlc_state, features);
}
st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index 077991c1cd05..39e8e49cfd2d 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
DBG(2,"len=%d",skb->len);
- isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
+ isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE);
if (test_and_set_bit(buf_nr, &d_out->busy)) {
WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index 2b3a055059ea..10d41c5d73ed 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode)
usb_unlink_urb(in->urb[1]);
if (in->mode != L1_MODE_NULL) {
- if (in->mode != L1_MODE_TRANS)
- isdnhdlc_rcv_init(&in->hdlc_state,
- in->mode == L1_MODE_HDLC_56K);
-
+ if (in->mode != L1_MODE_TRANS) {
+ u32 features = HDLC_BITREVERSE;
+
+ if (in->mode == L1_MODE_HDLC_56K)
+ features |= HDLC_56KBIT;
+ isdnhdlc_rcv_init(&in->hdlc_state, features);
+ }
st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
st5481_usb_device_ctrl_msg(in->adapter, in->counter,
in->packet_size,
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index ceb0df92fd3e..6e65424f1f04 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -447,8 +447,6 @@ static struct FsmNode TeiFnList[] __initdata =
{ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
};
-#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
-
int __init
TeiNew(void)
{
@@ -456,7 +454,7 @@ TeiNew(void)
teifsm.event_count = TEI_EVENT_COUNT;
teifsm.strEvent = strTeiEvent;
teifsm.strState = strTeiState;
- return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
+ return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList));
}
void
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index bb1c8dd1a230..c4d862c11a60 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -105,8 +105,6 @@ W6692_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 579974cf4c9a..c73004b3b2ac 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
if (lp->sk_count <= 3) {
schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
}
- return (0); /* success */
+ return NETDEV_TX_OK; /* success */
} /* net_send_packet */
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index ed3510f273d8..dd744ffd240b 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -2,6 +2,8 @@
# Old ISDN4Linux config
#
+if ISDN_I4L
+
config ISDN_PPP
bool "Support synchronous PPP"
depends on INET
@@ -135,3 +137,12 @@ source "drivers/isdn/act2000/Kconfig"
source "drivers/isdn/hysdn/Kconfig"
endmenu
+# end ISDN_I4L
+endif
+
+config ISDN_HDLC
+ tristate
+ depends on HISAX_ST5481
+ select CRC_CCITT
+ select BITREVERSE
+
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
index 49a06c0005dd..cb9d3bb9fae0 100644
--- a/drivers/isdn/i4l/Makefile
+++ b/drivers/isdn/i4l/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_ISDN_I4L) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
+obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
# Multipart objects.
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 7188c59a76ff..adb1e8c36b46 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -761,7 +761,7 @@ isdn_getnum(char **p)
* Be aware that this is not an atomic operation when sleep != 0, even though
* interrupts are turned off! Well, like that we are currently only called
* on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for for debugging purpose only). The inode semaphore
+ * to be dangerous and for debugging purpose only). The inode semaphore
* takes care that this is not called for the same minor device number while
* we are sleeping, but access is not serialized against simultaneous read()
* from the corresponding ttyI device. Can other ugly events, like changes
@@ -873,7 +873,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
* Be aware that this is not an atomic operation when sleep != 0, even though
* interrupts are turned off! Well, like that we are currently only called
* on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for for debugging purpose only). The inode semaphore
+ * to be dangerous and for debugging purpose only). The inode semaphore
* takes care that this is not called for the same minor device number while
* we are sleeping, but access is not serialized against simultaneous read()
* from the corresponding ttyI device. Can other ugly events, like changes
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index de4aad076ebc..57bf4bf50278 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
isdn_net_dev *nd;
isdn_net_local *slp;
isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
- int retv = 0;
+ int retv = NETDEV_TX_OK;
if (((isdn_net_local *) netdev_priv(ndev))->master) {
printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* For the other encaps the header has already been built */
@@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (lp->phone[1]) {
ulong flags;
@@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if(time_before(jiffies, lp->dialwait_timer)) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
lp->dialwait_timer = 0;
}
@@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* Log packet, which triggered dialing */
if (dev->net_verbose)
@@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
dev_kfree_skb(skb);
isdn_net_unbind_channel(lp);
spin_unlock_irqrestore(&dev->lock, flags);
- return 0; /* STN (skb to nirvana) ;) */
+ return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */
}
#ifdef CONFIG_IPPP_FILTER
if (isdn_ppp_autodial_filter(skb, lp)) {
@@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&dev->lock, flags);
isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
/* Device is connected to an ISDN channel */
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index aa30b5cb3513..2d14b64202a3 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- int slot, retval = 0;
+ int slot, retval = NETDEV_TX_OK;
mlp = (isdn_net_local *) netdev_priv(netdev);
nd = mlp->netdev; /* get master lp */
@@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
if (ipts->debug & 0x1)
printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
- retval = 1;
+ retval = NETDEV_TX_BUSY;
goto out;
}
@@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
- retval = 1;
+ retval = NETDEV_TX_BUSY;
goto out;
}
/* we have our lp locked from now on */
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c
index c69a77a80062..c989aa35dc2f 100644
--- a/drivers/isdn/hisax/isdnhdlc.c
+++ b/drivers/isdn/i4l/isdnhdlc.c
@@ -1,29 +1,32 @@
/*
* isdnhdlc.c -- General purpose ISDN HDLC decoder.
*
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
+ * Copyright (C)
+ * 2009 Karsten Keil <keil@b1-systems.de>
+ * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ * 2001 Frode Isaksen <fisaksen@bewan.com>
+ * 2001 Kai Germaschewski <kai.germaschewski@gmx.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 free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You 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.
+ * You 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/init.h>
#include <linux/crc-ccitt.h>
-#include "isdnhdlc.h"
+#include <linux/isdn/hdlc.h>
+#include <linux/bitrev.h>
/*-------------------------------------------------------------------*/
@@ -36,44 +39,32 @@ MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------*/
enum {
- HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
- HDLC_GET_DATA,HDLC_FAST_FLAG
+ HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
+ HDLC_GET_DATA, HDLC_FAST_FLAG
};
enum {
- HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
- HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
- HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
- HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+ HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
+ HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
+ HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
+ HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
};
-void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
+void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
+ memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
hdlc->state = HDLC_GET_DATA;
- hdlc->do_adapt56 = do_adapt56;
- hdlc->dchannel = 0;
- hdlc->crc = 0;
- hdlc->cbin = 0;
- hdlc->shift_reg = 0;
- hdlc->ffvalue = 0;
- hdlc->dstpos = 0;
+ if (features & HDLC_56KBIT)
+ hdlc->do_adapt56 = 1;
+ if (features & HDLC_BITREVERSE)
+ hdlc->do_bitreverse = 1;
}
+EXPORT_SYMBOL(isdnhdlc_out_init);
-void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
- hdlc->do_closing = 0;
- hdlc->ffvalue = 0;
- if (is_d_channel) {
+ memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
+ if (features & HDLC_DCHANNEL) {
hdlc->dchannel = 1;
hdlc->state = HDLC_SEND_FIRST_FLAG;
} else {
@@ -82,16 +73,32 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada
hdlc->ffvalue = 0x7e;
}
hdlc->cbin = 0x7e;
- hdlc->bit_shift = 0;
- if(do_adapt56){
+ if (features & HDLC_56KBIT) {
hdlc->do_adapt56 = 1;
- hdlc->data_bits = 0;
hdlc->state = HDLC_SENDFLAG_B0;
- } else {
- hdlc->do_adapt56 = 0;
+ } else
hdlc->data_bits = 8;
+ if (features & HDLC_BITREVERSE)
+ hdlc->do_bitreverse = 1;
+}
+EXPORT_SYMBOL(isdnhdlc_rcv_init);
+
+static int
+check_frame(struct isdnhdlc_vars *hdlc)
+{
+ int status;
+
+ if (hdlc->dstpos < 2) /* too small - framing error */
+ status = -HDLC_FRAMING_ERROR;
+ else if (hdlc->crc != 0xf0b8) /* crc error */
+ status = -HDLC_CRC_ERROR;
+ else {
+ /* remove CRC */
+ hdlc->dstpos -= 2;
+ /* good frame */
+ status = hdlc->dstpos;
}
- hdlc->shift_reg = 0;
+ return status;
}
/*
@@ -121,40 +128,67 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada
returns - number of decoded bytes in the destination buffer and status
flag.
*/
-int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
- int slen, int *count, unsigned char *dst, int dsize)
+int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
+ int *count, u8 *dst, int dsize)
{
- int status=0;
+ int status = 0;
- static const unsigned char fast_flag[]={
- 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+ static const unsigned char fast_flag[] = {
+ 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
};
- static const unsigned char fast_flag_value[]={
- 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+ static const unsigned char fast_flag_value[] = {
+ 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
};
- static const unsigned char fast_abort[]={
- 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+ static const unsigned char fast_abort[] = {
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
};
+#define handle_fast_flag(h) \
+ do {\
+ if (h->cbin == fast_flag[h->bit_shift]) {\
+ h->ffvalue = fast_flag_value[h->bit_shift];\
+ h->state = HDLC_FAST_FLAG;\
+ h->ffbit_shift = h->bit_shift;\
+ h->bit_shift = 1;\
+ } else {\
+ h->state = HDLC_GET_DATA;\
+ h->data_received = 0;\
+ } \
+ } while (0)
+
+#define handle_abort(h) \
+ do {\
+ h->shift_reg = fast_abort[h->ffbit_shift - 1];\
+ h->hdlc_bits1 = h->ffbit_shift - 2;\
+ if (h->hdlc_bits1 < 0)\
+ h->hdlc_bits1 = 0;\
+ h->data_bits = h->ffbit_shift - 1;\
+ h->state = HDLC_GET_DATA;\
+ h->data_received = 0;\
+ } while (0)
+
*count = slen;
- while(slen > 0){
- if(hdlc->bit_shift==0){
- hdlc->cbin = *src++;
+ while (slen > 0) {
+ if (hdlc->bit_shift == 0) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ hdlc->cbin = bitrev8(*src++);
+ else
+ hdlc->cbin = *src++;
slen--;
hdlc->bit_shift = 8;
- if(hdlc->do_adapt56){
- hdlc->bit_shift --;
- }
+ if (hdlc->do_adapt56)
+ hdlc->bit_shift--;
}
- switch(hdlc->state){
+ switch (hdlc->state) {
case STOPPED:
return 0;
case HDLC_FAST_IDLE:
- if(hdlc->cbin == 0xff){
+ if (hdlc->cbin == 0xff) {
hdlc->bit_shift = 0;
break;
}
@@ -163,32 +197,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift = 8;
break;
case HDLC_GET_FLAG_B0:
- if(!(hdlc->cbin & 0x80)) {
+ if (!(hdlc->cbin & 0x80)) {
hdlc->state = HDLC_GETFLAG_B1A6;
hdlc->hdlc_bits1 = 0;
} else {
- if(!hdlc->do_adapt56){
- if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+ if ((!hdlc->do_adapt56) &&
+ (++hdlc->hdlc_bits1 >= 8) &&
+ (hdlc->bit_shift == 1))
hdlc->state = HDLC_FAST_IDLE;
- }
}
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GETFLAG_B1A6:
- if(hdlc->cbin & 0x80){
+ if (hdlc->cbin & 0x80) {
hdlc->hdlc_bits1++;
- if(hdlc->hdlc_bits1==6){
+ if (hdlc->hdlc_bits1 == 6)
hdlc->state = HDLC_GETFLAG_B7;
- }
- } else {
+ } else
hdlc->hdlc_bits1 = 0;
- }
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GETFLAG_B7:
- if(hdlc->cbin & 0x80) {
+ if (hdlc->cbin & 0x80) {
hdlc->state = HDLC_GET_FLAG_B0;
} else {
hdlc->state = HDLC_GET_DATA;
@@ -198,74 +230,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->data_bits = 0;
hdlc->data_received = 0;
}
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GET_DATA:
- if(hdlc->cbin & 0x80){
+ if (hdlc->cbin & 0x80) {
hdlc->hdlc_bits1++;
- switch(hdlc->hdlc_bits1){
+ switch (hdlc->hdlc_bits1) {
case 6:
break;
case 7:
- if(hdlc->data_received) {
- // bad frame
+ if (hdlc->data_received)
+ /* bad frame */
status = -HDLC_FRAMING_ERROR;
- }
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=1;
+ if (!hdlc->do_adapt56) {
+ if (hdlc->cbin == fast_abort
+ [hdlc->bit_shift + 1]) {
+ hdlc->state =
+ HDLC_FAST_IDLE;
+ hdlc->bit_shift = 1;
break;
}
- } else {
+ } else
hdlc->state = HDLC_GET_FLAG_B0;
- }
break;
default:
- hdlc->shift_reg>>=1;
+ hdlc->shift_reg >>= 1;
hdlc->shift_reg |= 0x80;
hdlc->data_bits++;
break;
}
} else {
- switch(hdlc->hdlc_bits1){
+ switch (hdlc->hdlc_bits1) {
case 5:
break;
case 6:
- if(hdlc->data_received){
- if (hdlc->dstpos < 2) {
- status = -HDLC_FRAMING_ERROR;
- } else if (hdlc->crc != 0xf0b8){
- // crc error
- status = -HDLC_CRC_ERROR;
- } else {
- // remove CRC
- hdlc->dstpos -= 2;
- // good frame
- status = hdlc->dstpos;
- }
- }
+ if (hdlc->data_received)
+ status = check_frame(hdlc);
hdlc->crc = 0xffff;
hdlc->shift_reg = 0;
hdlc->data_bits = 0;
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
- hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
- hdlc->state = HDLC_FAST_FLAG;
- hdlc->ffbit_shift = hdlc->bit_shift;
- hdlc->bit_shift = 1;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- } else {
+ if (!hdlc->do_adapt56)
+ handle_fast_flag(hdlc);
+ else {
hdlc->state = HDLC_GET_DATA;
hdlc->data_received = 0;
}
break;
default:
- hdlc->shift_reg>>=1;
+ hdlc->shift_reg >>= 1;
hdlc->data_bits++;
break;
}
@@ -278,16 +291,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift--;
return status;
}
- if(hdlc->data_bits==8){
+ if (hdlc->data_bits == 8) {
hdlc->data_bits = 0;
hdlc->data_received = 1;
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
+ hdlc->crc = crc_ccitt_byte(hdlc->crc,
+ hdlc->shift_reg);
- // good byte received
- if (hdlc->dstpos < dsize) {
+ /* good byte received */
+ if (hdlc->dstpos < dsize)
dst[hdlc->dstpos++] = hdlc->shift_reg;
- } else {
- // frame too long
+ else {
+ /* frame too long */
status = -HDLC_LENGTH_ERROR;
hdlc->dstpos = 0;
}
@@ -296,24 +310,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift--;
break;
case HDLC_FAST_FLAG:
- if(hdlc->cbin==hdlc->ffvalue){
+ if (hdlc->cbin == hdlc->ffvalue) {
hdlc->bit_shift = 0;
break;
} else {
- if(hdlc->cbin == 0xff){
+ if (hdlc->cbin == 0xff) {
hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=0;
- } else if(hdlc->ffbit_shift==8){
+ hdlc->bit_shift = 0;
+ } else if (hdlc->ffbit_shift == 8) {
hdlc->state = HDLC_GETFLAG_B7;
break;
- } else {
- hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
- hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
- if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = hdlc->ffbit_shift-1;
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
+ } else
+ handle_abort(hdlc);
}
break;
default:
@@ -323,7 +331,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
*count -= slen;
return 0;
}
-
+EXPORT_SYMBOL(isdnhdlc_decode);
/*
isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
@@ -343,59 +351,70 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
dsize - destination buffer size
returns - number of encoded bytes in the destination buffer
*/
-int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
- unsigned short slen, int *count,
- unsigned char *dst, int dsize)
+int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
+ int *count, u8 *dst, int dsize)
{
static const unsigned char xfast_flag_value[] = {
- 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+ 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
};
int len = 0;
*count = slen;
+ /* special handling for one byte frames */
+ if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
+ hdlc->state = HDLC_SENDFLAG_ONE;
while (dsize > 0) {
- if(hdlc->bit_shift==0){
- if(slen && !hdlc->do_closing){
+ if (hdlc->bit_shift == 0) {
+ if (slen && !hdlc->do_closing) {
hdlc->shift_reg = *src++;
slen--;
if (slen == 0)
- hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
+ /* closing sequence, CRC + flag(s) */
+ hdlc->do_closing = 1;
hdlc->bit_shift = 8;
} else {
- if(hdlc->state == HDLC_SEND_DATA){
- if(hdlc->data_received){
+ if (hdlc->state == HDLC_SEND_DATA) {
+ if (hdlc->data_received) {
hdlc->state = HDLC_SEND_CRC1;
hdlc->crc ^= 0xffff;
hdlc->bit_shift = 8;
- hdlc->shift_reg = hdlc->crc & 0xff;
- } else if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- }
+ hdlc->shift_reg =
+ hdlc->crc & 0xff;
+ } else if (!hdlc->do_adapt56)
+ hdlc->state =
+ HDLC_SEND_FAST_FLAG;
+ else
+ hdlc->state =
+ HDLC_SENDFLAG_B0;
}
}
}
- switch(hdlc->state){
+ switch (hdlc->state) {
case STOPPED:
while (dsize--)
*dst++ = 0xff;
-
return dsize;
case HDLC_SEND_FAST_FLAG:
hdlc->do_closing = 0;
- if(slen == 0){
- *dst++ = hdlc->ffvalue;
+ if (slen == 0) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->ffvalue);
+ else
+ *dst++ = hdlc->ffvalue;
len++;
dsize--;
break;
}
- if(hdlc->bit_shift==8){
- hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+ /* fall through */
+ case HDLC_SENDFLAG_ONE:
+ if (hdlc->bit_shift == 8) {
+ hdlc->cbin = hdlc->ffvalue >>
+ (8 - hdlc->data_bits);
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -413,17 +432,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->cbin <<= 1;
hdlc->data_bits++;
hdlc->cbin++;
- if(++hdlc->hdlc_bits1 == 6)
+ if (++hdlc->hdlc_bits1 == 6)
hdlc->state = HDLC_SENDFLAG_B7;
break;
case HDLC_SENDFLAG_B7:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(slen == 0){
+ if (slen == 0) {
hdlc->state = HDLC_SENDFLAG_B0;
break;
}
- if(hdlc->bit_shift==8){
+ if (hdlc->bit_shift == 8) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -432,7 +451,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
break;
case HDLC_SEND_FIRST_FLAG:
hdlc->data_received = 1;
- if(hdlc->data_bits==8){
+ if (hdlc->data_bits == 8) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -440,11 +459,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
}
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->shift_reg & 0x01)
+ if (hdlc->shift_reg & 0x01)
hdlc->cbin++;
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -453,14 +472,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_DATA:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->bit_shift==8){
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
- }
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->bit_shift == 8)
+ hdlc->crc = crc_ccitt_byte(hdlc->crc,
+ hdlc->shift_reg);
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -474,11 +493,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CRC1:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -488,7 +507,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
}
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->shift_reg = (hdlc->crc >> 8);
hdlc->state = HDLC_SEND_CRC2;
hdlc->bit_shift = 8;
@@ -497,11 +516,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CRC2:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -511,7 +530,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
}
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->shift_reg = 0x7e;
hdlc->state = HDLC_SEND_CLOSING_FLAG;
hdlc->bit_shift = 8;
@@ -520,33 +539,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CLOSING_FLAG:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01)
hdlc->cbin++;
- }
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
- hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
- if(hdlc->dchannel){
+ if (hdlc->bit_shift == 0) {
+ hdlc->ffvalue =
+ xfast_flag_value[hdlc->data_bits];
+ if (hdlc->dchannel) {
hdlc->ffvalue = 0x7e;
hdlc->state = HDLC_SEND_IDLE1;
hdlc->bit_shift = 8-hdlc->data_bits;
- if(hdlc->bit_shift==0)
- hdlc->state = HDLC_SEND_FAST_IDLE;
+ if (hdlc->bit_shift == 0)
+ hdlc->state =
+ HDLC_SEND_FAST_IDLE;
} else {
- if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
+ if (!hdlc->do_adapt56) {
+ hdlc->state =
+ HDLC_SEND_FAST_FLAG;
hdlc->data_received = 0;
} else {
hdlc->state = HDLC_SENDFLAG_B0;
hdlc->data_received = 0;
}
- // Finished with this frame, send flags
- if (dsize > 1) dsize = 1;
+ /* Finished this frame, send flags */
+ if (dsize > 1)
+ dsize = 1;
}
}
break;
@@ -556,7 +578,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->cbin++;
hdlc->data_bits++;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->state = HDLC_SEND_FAST_IDLE;
hdlc->bit_shift = 0;
}
@@ -565,12 +587,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->do_closing = 0;
hdlc->cbin = 0xff;
hdlc->data_bits = 8;
- if(hdlc->bit_shift == 8){
+ if (hdlc->bit_shift == 8) {
hdlc->cbin = 0x7e;
hdlc->state = HDLC_SEND_FIRST_FLAG;
} else {
- *dst++ = hdlc->cbin;
- hdlc->bit_shift = hdlc->data_bits = 0;
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->cbin);
+ else
+ *dst++ = hdlc->cbin;
+ hdlc->bit_shift = 0;
+ hdlc->data_bits = 0;
len++;
dsize = 0;
}
@@ -578,15 +605,19 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
default:
break;
}
- if(hdlc->do_adapt56){
- if(hdlc->data_bits==7){
+ if (hdlc->do_adapt56) {
+ if (hdlc->data_bits == 7) {
hdlc->cbin <<= 1;
hdlc->cbin++;
hdlc->data_bits++;
}
}
- if(hdlc->data_bits==8){
- *dst++ = hdlc->cbin;
+ if (hdlc->data_bits == 8) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->cbin);
+ else
+ *dst++ = hdlc->cbin;
hdlc->data_bits = 0;
len++;
dsize--;
@@ -596,8 +627,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
return len;
}
-
-EXPORT_SYMBOL(isdnhdlc_rcv_init);
-EXPORT_SYMBOL(isdnhdlc_decode);
-EXPORT_SYMBOL(isdnhdlc_out_init);
EXPORT_SYMBOL(isdnhdlc_encode);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 0481a0cdf6db..e8049be552aa 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -114,13 +114,14 @@ mISDN_freedchannel(struct dchannel *ch)
}
EXPORT_SYMBOL(mISDN_freedchannel);
-int
-mISDN_freebchannel(struct bchannel *ch)
+void
+mISDN_clear_bchannel(struct bchannel *ch)
{
if (ch->tx_skb) {
dev_kfree_skb(ch->tx_skb);
ch->tx_skb = NULL;
}
+ ch->tx_idx = 0;
if (ch->rx_skb) {
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = NULL;
@@ -129,6 +130,16 @@ mISDN_freebchannel(struct bchannel *ch)
dev_kfree_skb(ch->next_skb);
ch->next_skb = NULL;
}
+ test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+ test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+}
+EXPORT_SYMBOL(mISDN_clear_bchannel);
+
+int
+mISDN_freebchannel(struct bchannel *ch)
+{
+ mISDN_clear_bchannel(ch);
skb_queue_purge(&ch->rqueue);
ch->rcount = 0;
flush_scheduled_work();
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 990e6a7e6674..7e5f30dbc0a0 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -731,10 +731,10 @@ l1oip_socket_thread(void *data)
while (!signal_pending(current)) {
struct kvec iov = {
.iov_base = recvbuf,
- .iov_len = sizeof(recvbuf),
+ .iov_len = recvbuf_size,
};
recvlen = kernel_recvmsg(socket, &msg, &iov, 1,
- sizeof(recvbuf), 0);
+ recvbuf_size, 0);
if (recvlen > 0) {
l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
} else {
@@ -1480,7 +1480,7 @@ l1oip_init(void)
return -ENOMEM;
l1oip_cnt = 0;
- while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) {
+ while (l1oip_cnt < MAX_CARDS && type[l1oip_cnt]) {
switch (type[l1oip_cnt] & 0xff) {
case 1:
pri = 0;
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index 9c2589e986d6..e17f0044e0b6 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -1832,8 +1832,6 @@ static struct FsmNode L2FnList[] =
{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
};
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
static int
ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
{
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index a6974e9b8ebf..1e2cb846b3c9 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -1,6 +1,8 @@
-/*P:400 This contains run_guest() which actually calls into the Host<->Guest
+/*P:400
+ * This contains run_guest() which actually calls into the Host<->Guest
* Switcher and analyzes the return, such as determining if the Guest wants the
- * Host to do something. This file also contains useful helper routines. :*/
+ * Host to do something. This file also contains useful helper routines.
+:*/
#include <linux/module.h>
#include <linux/stringify.h>
#include <linux/stddef.h>
@@ -24,7 +26,8 @@ static struct page **switcher_page;
/* This One Big lock protects all inter-guest data structures. */
DEFINE_MUTEX(lguest_lock);
-/*H:010 We need to set up the Switcher at a high virtual address. Remember the
+/*H:010
+ * We need to set up the Switcher at a high virtual address. Remember the
* Switcher is a few hundred bytes of assembler code which actually changes the
* CPU to run the Guest, and then changes back to the Host when a trap or
* interrupt happens.
@@ -33,7 +36,8 @@ DEFINE_MUTEX(lguest_lock);
* Host since it will be running as the switchover occurs.
*
* Trying to map memory at a particular address is an unusual thing to do, so
- * it's not a simple one-liner. */
+ * it's not a simple one-liner.
+ */
static __init int map_switcher(void)
{
int i, err;
@@ -47,8 +51,10 @@ static __init int map_switcher(void)
* easy.
*/
- /* We allocate an array of struct page pointers. map_vm_area() wants
- * this, rather than just an array of pages. */
+ /*
+ * We allocate an array of struct page pointers. map_vm_area() wants
+ * this, rather than just an array of pages.
+ */
switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
GFP_KERNEL);
if (!switcher_page) {
@@ -56,8 +62,10 @@ static __init int map_switcher(void)
goto out;
}
- /* Now we actually allocate the pages. The Guest will see these pages,
- * so we make sure they're zeroed. */
+ /*
+ * Now we actually allocate the pages. The Guest will see these pages,
+ * so we make sure they're zeroed.
+ */
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
unsigned long addr = get_zeroed_page(GFP_KERNEL);
if (!addr) {
@@ -67,19 +75,23 @@ static __init int map_switcher(void)
switcher_page[i] = virt_to_page(addr);
}
- /* First we check that the Switcher won't overlap the fixmap area at
+ /*
+ * First we check that the Switcher won't overlap the fixmap area at
* the top of memory. It's currently nowhere near, but it could have
- * very strange effects if it ever happened. */
+ * very strange effects if it ever happened.
+ */
if (SWITCHER_ADDR + (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE > FIXADDR_START){
err = -ENOMEM;
printk("lguest: mapping switcher would thwack fixmap\n");
goto free_pages;
}
- /* Now we reserve the "virtual memory area" we want: 0xFFC00000
+ /*
+ * Now we reserve the "virtual memory area" we want: 0xFFC00000
* (SWITCHER_ADDR). We might not get it in theory, but in practice
* it's worked so far. The end address needs +1 because __get_vm_area
- * allocates an extra guard page, so we need space for that. */
+ * allocates an extra guard page, so we need space for that.
+ */
switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
VM_ALLOC, SWITCHER_ADDR, SWITCHER_ADDR
+ (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE);
@@ -89,11 +101,13 @@ static __init int map_switcher(void)
goto free_pages;
}
- /* This code actually sets up the pages we've allocated to appear at
+ /*
+ * This code actually sets up the pages we've allocated to appear at
* SWITCHER_ADDR. map_vm_area() takes the vma we allocated above, the
* kind of pages we're mapping (kernel pages), and a pointer to our
* array of struct pages. It increments that pointer, but we don't
- * care. */
+ * care.
+ */
pagep = switcher_page;
err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep);
if (err) {
@@ -101,8 +115,10 @@ static __init int map_switcher(void)
goto free_vma;
}
- /* Now the Switcher is mapped at the right address, we can't fail!
- * Copy in the compiled-in Switcher code (from <arch>_switcher.S). */
+ /*
+ * Now the Switcher is mapped at the right address, we can't fail!
+ * Copy in the compiled-in Switcher code (from <arch>_switcher.S).
+ */
memcpy(switcher_vma->addr, start_switcher_text,
end_switcher_text - start_switcher_text);
@@ -124,8 +140,7 @@ out:
}
/*:*/
-/* Cleaning up the mapping when the module is unloaded is almost...
- * too easy. */
+/* Cleaning up the mapping when the module is unloaded is almost... too easy. */
static void unmap_switcher(void)
{
unsigned int i;
@@ -151,16 +166,19 @@ static void unmap_switcher(void)
* But we can't trust the Guest: it might be trying to access the Launcher
* code. We have to check that the range is below the pfn_limit the Launcher
* gave us. We have to make sure that addr + len doesn't give us a false
- * positive by overflowing, too. */
+ * positive by overflowing, too.
+ */
bool lguest_address_ok(const struct lguest *lg,
unsigned long addr, unsigned long len)
{
return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
}
-/* This routine copies memory from the Guest. Here we can see how useful the
+/*
+ * This routine copies memory from the Guest. Here we can see how useful the
* kill_lguest() routine we met in the Launcher can be: we return a random
- * value (all zeroes) instead of needing to return an error. */
+ * value (all zeroes) instead of needing to return an error.
+ */
void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes)
{
if (!lguest_address_ok(cpu->lg, addr, bytes)
@@ -181,9 +199,11 @@ void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
}
/*:*/
-/*H:030 Let's jump straight to the the main loop which runs the Guest.
+/*H:030
+ * Let's jump straight to the the main loop which runs the Guest.
* Remember, this is called by the Launcher reading /dev/lguest, and we keep
- * going around and around until something interesting happens. */
+ * going around and around until something interesting happens.
+ */
int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
{
/* We stop running once the Guest is dead. */
@@ -195,10 +215,17 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
if (cpu->hcall)
do_hypercalls(cpu);
- /* It's possible the Guest did a NOTIFY hypercall to the
- * Launcher, in which case we return from the read() now. */
+ /*
+ * It's possible the Guest did a NOTIFY hypercall to the
+ * Launcher.
+ */
if (cpu->pending_notify) {
+ /*
+ * Does it just needs to write to a registered
+ * eventfd (ie. the appropriate virtqueue thread)?
+ */
if (!send_notify_to_eventfd(cpu)) {
+ /* OK, we tell the main Laucher. */
if (put_user(cpu->pending_notify, user))
return -EFAULT;
return sizeof(cpu->pending_notify);
@@ -209,29 +236,39 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
if (signal_pending(current))
return -ERESTARTSYS;
- /* Check if there are any interrupts which can be delivered now:
+ /*
+ * Check if there are any interrupts which can be delivered now:
* if so, this sets up the hander to be executed when we next
- * run the Guest. */
+ * run the Guest.
+ */
irq = interrupt_pending(cpu, &more);
if (irq < LGUEST_IRQS)
try_deliver_interrupt(cpu, irq, more);
- /* All long-lived kernel loops need to check with this horrible
+ /*
+ * All long-lived kernel loops need to check with this horrible
* thing called the freezer. If the Host is trying to suspend,
- * it stops us. */
+ * it stops us.
+ */
try_to_freeze();
- /* Just make absolutely sure the Guest is still alive. One of
- * those hypercalls could have been fatal, for example. */
+ /*
+ * Just make absolutely sure the Guest is still alive. One of
+ * those hypercalls could have been fatal, for example.
+ */
if (cpu->lg->dead)
break;
- /* If the Guest asked to be stopped, we sleep. The Guest's
- * clock timer will wake us. */
+ /*
+ * If the Guest asked to be stopped, we sleep. The Guest's
+ * clock timer will wake us.
+ */
if (cpu->halted) {
set_current_state(TASK_INTERRUPTIBLE);
- /* Just before we sleep, make sure no interrupt snuck in
- * which we should be doing. */
+ /*
+ * Just before we sleep, make sure no interrupt snuck in
+ * which we should be doing.
+ */
if (interrupt_pending(cpu, &more) < LGUEST_IRQS)
set_current_state(TASK_RUNNING);
else
@@ -239,8 +276,10 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
continue;
}
- /* OK, now we're ready to jump into the Guest. First we put up
- * the "Do Not Disturb" sign: */
+ /*
+ * OK, now we're ready to jump into the Guest. First we put up
+ * the "Do Not Disturb" sign:
+ */
local_irq_disable();
/* Actually run the Guest until something happens. */
@@ -327,8 +366,10 @@ static void __exit fini(void)
}
/*:*/
-/* The Host side of lguest can be a module. This is a nice way for people to
- * play with it. */
+/*
+ * The Host side of lguest can be a module. This is a nice way for people to
+ * play with it.
+ */
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index c29ffa19cb74..83511eb0923d 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -1,8 +1,10 @@
-/*P:500 Just as userspace programs request kernel operations through a system
+/*P:500
+ * Just as userspace programs request kernel operations through a system
* call, the Guest requests Host operations through a "hypercall". You might
* notice this nomenclature doesn't really follow any logic, but the name has
* been around for long enough that we're stuck with it. As you'd expect, this
- * code is basically a one big switch statement. :*/
+ * code is basically a one big switch statement.
+:*/
/* Copyright (C) 2006 Rusty Russell IBM Corporation
@@ -28,30 +30,41 @@
#include <asm/pgtable.h>
#include "lg.h"
-/*H:120 This is the core hypercall routine: where the Guest gets what it wants.
- * Or gets killed. Or, in the case of LHCALL_SHUTDOWN, both. */
+/*H:120
+ * This is the core hypercall routine: where the Guest gets what it wants.
+ * Or gets killed. Or, in the case of LHCALL_SHUTDOWN, both.
+ */
static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
{
switch (args->arg0) {
case LHCALL_FLUSH_ASYNC:
- /* This call does nothing, except by breaking out of the Guest
- * it makes us process all the asynchronous hypercalls. */
+ /*
+ * This call does nothing, except by breaking out of the Guest
+ * it makes us process all the asynchronous hypercalls.
+ */
break;
case LHCALL_SEND_INTERRUPTS:
- /* This call does nothing too, but by breaking out of the Guest
- * it makes us process any pending interrupts. */
+ /*
+ * This call does nothing too, but by breaking out of the Guest
+ * it makes us process any pending interrupts.
+ */
break;
case LHCALL_LGUEST_INIT:
- /* You can't get here unless you're already initialized. Don't
- * do that. */
+ /*
+ * You can't get here unless you're already initialized. Don't
+ * do that.
+ */
kill_guest(cpu, "already have lguest_data");
break;
case LHCALL_SHUTDOWN: {
- /* Shutdown is such a trivial hypercall that we do it in four
- * lines right here. */
char msg[128];
- /* If the lgread fails, it will call kill_guest() itself; the
- * kill_guest() with the message will be ignored. */
+ /*
+ * Shutdown is such a trivial hypercall that we do it in five
+ * lines right here.
+ *
+ * If the lgread fails, it will call kill_guest() itself; the
+ * kill_guest() with the message will be ignored.
+ */
__lgread(cpu, msg, args->arg1, sizeof(msg));
msg[sizeof(msg)-1] = '\0';
kill_guest(cpu, "CRASH: %s", msg);
@@ -60,16 +73,17 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
break;
}
case LHCALL_FLUSH_TLB:
- /* FLUSH_TLB comes in two flavors, depending on the
- * argument: */
+ /* FLUSH_TLB comes in two flavors, depending on the argument: */
if (args->arg1)
guest_pagetable_clear_all(cpu);
else
guest_pagetable_flush_user(cpu);
break;
- /* All these calls simply pass the arguments through to the right
- * routines. */
+ /*
+ * All these calls simply pass the arguments through to the right
+ * routines.
+ */
case LHCALL_NEW_PGTABLE:
guest_new_pagetable(cpu, args->arg1);
break;
@@ -112,15 +126,16 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
kill_guest(cpu, "Bad hypercall %li\n", args->arg0);
}
}
-/*:*/
-/*H:124 Asynchronous hypercalls are easy: we just look in the array in the
+/*H:124
+ * Asynchronous hypercalls are easy: we just look in the array in the
* Guest's "struct lguest_data" to see if any new ones are marked "ready".
*
* We are careful to do these in order: obviously we respect the order the
* Guest put them in the ring, but we also promise the Guest that they will
* happen before any normal hypercall (which is why we check this before
- * checking for a normal hcall). */
+ * checking for a normal hcall).
+ */
static void do_async_hcalls(struct lg_cpu *cpu)
{
unsigned int i;
@@ -133,22 +148,28 @@ static void do_async_hcalls(struct lg_cpu *cpu)
/* We process "struct lguest_data"s hcalls[] ring once. */
for (i = 0; i < ARRAY_SIZE(st); i++) {
struct hcall_args args;
- /* We remember where we were up to from last time. This makes
+ /*
+ * We remember where we were up to from last time. This makes
* sure that the hypercalls are done in the order the Guest
- * places them in the ring. */
+ * places them in the ring.
+ */
unsigned int n = cpu->next_hcall;
/* 0xFF means there's no call here (yet). */
if (st[n] == 0xFF)
break;
- /* OK, we have hypercall. Increment the "next_hcall" cursor,
- * and wrap back to 0 if we reach the end. */
+ /*
+ * OK, we have hypercall. Increment the "next_hcall" cursor,
+ * and wrap back to 0 if we reach the end.
+ */
if (++cpu->next_hcall == LHCALL_RING_SIZE)
cpu->next_hcall = 0;
- /* Copy the hypercall arguments into a local copy of
- * the hcall_args struct. */
+ /*
+ * Copy the hypercall arguments into a local copy of the
+ * hcall_args struct.
+ */
if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n],
sizeof(struct hcall_args))) {
kill_guest(cpu, "Fetching async hypercalls");
@@ -164,19 +185,25 @@ static void do_async_hcalls(struct lg_cpu *cpu)
break;
}
- /* Stop doing hypercalls if they want to notify the Launcher:
- * it needs to service this first. */
+ /*
+ * Stop doing hypercalls if they want to notify the Launcher:
+ * it needs to service this first.
+ */
if (cpu->pending_notify)
break;
}
}
-/* Last of all, we look at what happens first of all. The very first time the
- * Guest makes a hypercall, we end up here to set things up: */
+/*
+ * Last of all, we look at what happens first of all. The very first time the
+ * Guest makes a hypercall, we end up here to set things up:
+ */
static void initialize(struct lg_cpu *cpu)
{
- /* You can't do anything until you're initialized. The Guest knows the
- * rules, so we're unforgiving here. */
+ /*
+ * You can't do anything until you're initialized. The Guest knows the
+ * rules, so we're unforgiving here.
+ */
if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) {
kill_guest(cpu, "hypercall %li before INIT", cpu->hcall->arg0);
return;
@@ -185,32 +212,44 @@ static void initialize(struct lg_cpu *cpu)
if (lguest_arch_init_hypercalls(cpu))
kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
- /* The Guest tells us where we're not to deliver interrupts by putting
- * the range of addresses into "struct lguest_data". */
+ /*
+ * The Guest tells us where we're not to deliver interrupts by putting
+ * the range of addresses into "struct lguest_data".
+ */
if (get_user(cpu->lg->noirq_start, &cpu->lg->lguest_data->noirq_start)
|| get_user(cpu->lg->noirq_end, &cpu->lg->lguest_data->noirq_end))
kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
- /* We write the current time into the Guest's data page once so it can
- * set its clock. */
+ /*
+ * We write the current time into the Guest's data page once so it can
+ * set its clock.
+ */
write_timestamp(cpu);
/* page_tables.c will also do some setup. */
page_table_guest_data_init(cpu);
- /* This is the one case where the above accesses might have been the
+ /*
+ * This is the one case where the above accesses might have been the
* first write to a Guest page. This may have caused a copy-on-write
* fault, but the old page might be (read-only) in the Guest
- * pagetable. */
+ * pagetable.
+ */
guest_pagetable_clear_all(cpu);
}
/*:*/
-/*M:013 If a Guest reads from a page (so creates a mapping) that it has never
+/*M:013
+ * If a Guest reads from a page (so creates a mapping) that it has never
* written to, and then the Launcher writes to it (ie. the output of a virtual
* device), the Guest will still see the old page. In practice, this never
* happens: why would the Guest read a page which it has never written to? But
- * a similar scenario might one day bite us, so it's worth mentioning. :*/
+ * a similar scenario might one day bite us, so it's worth mentioning.
+ *
+ * Note that if we used a shared anonymous mapping in the Launcher instead of
+ * mapping /dev/zero private, we wouldn't worry about cop-on-write. And we
+ * need that to switch the Launcher to processes (away from threads) anyway.
+:*/
/*H:100
* Hypercalls
@@ -229,17 +268,22 @@ void do_hypercalls(struct lg_cpu *cpu)
return;
}
- /* The Guest has initialized.
+ /*
+ * The Guest has initialized.
*
- * Look in the hypercall ring for the async hypercalls: */
+ * Look in the hypercall ring for the async hypercalls:
+ */
do_async_hcalls(cpu);
- /* If we stopped reading the hypercall ring because the Guest did a
+ /*
+ * If we stopped reading the hypercall ring because the Guest did a
* NOTIFY to the Launcher, we want to return now. Otherwise we do
- * the hypercall. */
+ * the hypercall.
+ */
if (!cpu->pending_notify) {
do_hcall(cpu, cpu->hcall);
- /* Tricky point: we reset the hcall pointer to mark the
+ /*
+ * Tricky point: we reset the hcall pointer to mark the
* hypercall as "done". We use the hcall pointer rather than
* the trap number to indicate a hypercall is pending.
* Normally it doesn't matter: the Guest will run again and
@@ -248,13 +292,16 @@ void do_hypercalls(struct lg_cpu *cpu)
* However, if we are signalled or the Guest sends I/O to the
* Launcher, the run_guest() loop will exit without running the
* Guest. When it comes back it would try to re-run the
- * hypercall. Finding that bug sucked. */
+ * hypercall. Finding that bug sucked.
+ */
cpu->hcall = NULL;
}
}
-/* This routine supplies the Guest with time: it's used for wallclock time at
- * initial boot and as a rough time source if the TSC isn't available. */
+/*
+ * This routine supplies the Guest with time: it's used for wallclock time at
+ * initial boot and as a rough time source if the TSC isn't available.
+ */
void write_timestamp(struct lg_cpu *cpu)
{
struct timespec now;
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 0e9067b0d507..18648180db02 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -1,4 +1,5 @@
-/*P:800 Interrupts (traps) are complicated enough to earn their own file.
+/*P:800
+ * Interrupts (traps) are complicated enough to earn their own file.
* There are three classes of interrupts:
*
* 1) Real hardware interrupts which occur while we're running the Guest,
@@ -10,7 +11,8 @@
* just like real hardware would deliver them. Traps from the Guest can be set
* up to go directly back into the Guest, but sometimes the Host wants to see
* them first, so we also have a way of "reflecting" them into the Guest as if
- * they had been delivered to it directly. :*/
+ * they had been delivered to it directly.
+:*/
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -26,8 +28,10 @@ static unsigned long idt_address(u32 lo, u32 hi)
return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
}
-/* The "type" of the interrupt handler is a 4 bit field: we only support a
- * couple of types. */
+/*
+ * The "type" of the interrupt handler is a 4 bit field: we only support a
+ * couple of types.
+ */
static int idt_type(u32 lo, u32 hi)
{
return (hi >> 8) & 0xF;
@@ -39,8 +43,10 @@ static bool idt_present(u32 lo, u32 hi)
return (hi & 0x8000);
}
-/* We need a helper to "push" a value onto the Guest's stack, since that's a
- * big part of what delivering an interrupt does. */
+/*
+ * We need a helper to "push" a value onto the Guest's stack, since that's a
+ * big part of what delivering an interrupt does.
+ */
static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
{
/* Stack grows upwards: move stack then write value. */
@@ -48,7 +54,8 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
lgwrite(cpu, *gstack, u32, val);
}
-/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
+/*H:210
+ * The set_guest_interrupt() routine actually delivers the interrupt or
* trap. The mechanics of delivering traps and interrupts to the Guest are the
* same, except some traps have an "error code" which gets pushed onto the
* stack as well: the caller tells us if this is one.
@@ -59,7 +66,8 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
*
* We set up the stack just like the CPU does for a real interrupt, so it's
* identical for the Guest (and the standard "iret" instruction will undo
- * it). */
+ * it).
+ */
static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
bool has_err)
{
@@ -67,20 +75,26 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
u32 eflags, ss, irq_enable;
unsigned long virtstack;
- /* There are two cases for interrupts: one where the Guest is already
+ /*
+ * There are two cases for interrupts: one where the Guest is already
* in the kernel, and a more complex one where the Guest is in
- * userspace. We check the privilege level to find out. */
+ * userspace. We check the privilege level to find out.
+ */
if ((cpu->regs->ss&0x3) != GUEST_PL) {
- /* The Guest told us their kernel stack with the SET_STACK
- * hypercall: both the virtual address and the segment */
+ /*
+ * The Guest told us their kernel stack with the SET_STACK
+ * hypercall: both the virtual address and the segment.
+ */
virtstack = cpu->esp1;
ss = cpu->ss1;
origstack = gstack = guest_pa(cpu, virtstack);
- /* We push the old stack segment and pointer onto the new
+ /*
+ * We push the old stack segment and pointer onto the new
* stack: when the Guest does an "iret" back from the interrupt
* handler the CPU will notice they're dropping privilege
- * levels and expect these here. */
+ * levels and expect these here.
+ */
push_guest_stack(cpu, &gstack, cpu->regs->ss);
push_guest_stack(cpu, &gstack, cpu->regs->esp);
} else {
@@ -91,18 +105,22 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
origstack = gstack = guest_pa(cpu, virtstack);
}
- /* Remember that we never let the Guest actually disable interrupts, so
+ /*
+ * Remember that we never let the Guest actually disable interrupts, so
* the "Interrupt Flag" bit is always set. We copy that bit from the
* Guest's "irq_enabled" field into the eflags word: we saw the Guest
- * copy it back in "lguest_iret". */
+ * copy it back in "lguest_iret".
+ */
eflags = cpu->regs->eflags;
if (get_user(irq_enable, &cpu->lg->lguest_data->irq_enabled) == 0
&& !(irq_enable & X86_EFLAGS_IF))
eflags &= ~X86_EFLAGS_IF;
- /* An interrupt is expected to push three things on the stack: the old
+ /*
+ * An interrupt is expected to push three things on the stack: the old
* "eflags" word, the old code segment, and the old instruction
- * pointer. */
+ * pointer.
+ */
push_guest_stack(cpu, &gstack, eflags);
push_guest_stack(cpu, &gstack, cpu->regs->cs);
push_guest_stack(cpu, &gstack, cpu->regs->eip);
@@ -111,15 +129,19 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
if (has_err)
push_guest_stack(cpu, &gstack, cpu->regs->errcode);
- /* Now we've pushed all the old state, we change the stack, the code
- * segment and the address to execute. */
+ /*
+ * Now we've pushed all the old state, we change the stack, the code
+ * segment and the address to execute.
+ */
cpu->regs->ss = ss;
cpu->regs->esp = virtstack + (gstack - origstack);
cpu->regs->cs = (__KERNEL_CS|GUEST_PL);
cpu->regs->eip = idt_address(lo, hi);
- /* There are two kinds of interrupt handlers: 0xE is an "interrupt
- * gate" which expects interrupts to be disabled on entry. */
+ /*
+ * There are two kinds of interrupt handlers: 0xE is an "interrupt
+ * gate" which expects interrupts to be disabled on entry.
+ */
if (idt_type(lo, hi) == 0xE)
if (put_user(0, &cpu->lg->lguest_data->irq_enabled))
kill_guest(cpu, "Disabling interrupts");
@@ -130,7 +152,8 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
*
* interrupt_pending() returns the first pending interrupt which isn't blocked
* by the Guest. It is called before every entry to the Guest, and just before
- * we go to sleep when the Guest has halted itself. */
+ * we go to sleep when the Guest has halted itself.
+ */
unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more)
{
unsigned int irq;
@@ -140,8 +163,10 @@ unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more)
if (!cpu->lg->lguest_data)
return LGUEST_IRQS;
- /* Take our "irqs_pending" array and remove any interrupts the Guest
- * wants blocked: the result ends up in "blk". */
+ /*
+ * Take our "irqs_pending" array and remove any interrupts the Guest
+ * wants blocked: the result ends up in "blk".
+ */
if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
sizeof(blk)))
return LGUEST_IRQS;
@@ -154,16 +179,20 @@ unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more)
return irq;
}
-/* This actually diverts the Guest to running an interrupt handler, once an
- * interrupt has been identified by interrupt_pending(). */
+/*
+ * This actually diverts the Guest to running an interrupt handler, once an
+ * interrupt has been identified by interrupt_pending().
+ */
void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
{
struct desc_struct *idt;
BUG_ON(irq >= LGUEST_IRQS);
- /* They may be in the middle of an iret, where they asked us never to
- * deliver interrupts. */
+ /*
+ * They may be in the middle of an iret, where they asked us never to
+ * deliver interrupts.
+ */
if (cpu->regs->eip >= cpu->lg->noirq_start &&
(cpu->regs->eip < cpu->lg->noirq_end))
return;
@@ -187,29 +216,37 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
}
}
- /* Look at the IDT entry the Guest gave us for this interrupt. The
+ /*
+ * Look at the IDT entry the Guest gave us for this interrupt. The
* first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
- * over them. */
+ * over them.
+ */
idt = &cpu->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
/* If they don't have a handler (yet?), we just ignore it */
if (idt_present(idt->a, idt->b)) {
/* OK, mark it no longer pending and deliver it. */
clear_bit(irq, cpu->irqs_pending);
- /* set_guest_interrupt() takes the interrupt descriptor and a
+ /*
+ * set_guest_interrupt() takes the interrupt descriptor and a
* flag to say whether this interrupt pushes an error code onto
- * the stack as well: virtual interrupts never do. */
+ * the stack as well: virtual interrupts never do.
+ */
set_guest_interrupt(cpu, idt->a, idt->b, false);
}
- /* Every time we deliver an interrupt, we update the timestamp in the
+ /*
+ * Every time we deliver an interrupt, we update the timestamp in the
* Guest's lguest_data struct. It would be better for the Guest if we
* did this more often, but it can actually be quite slow: doing it
* here is a compromise which means at least it gets updated every
- * timer interrupt. */
+ * timer interrupt.
+ */
write_timestamp(cpu);
- /* If there are no other interrupts we want to deliver, clear
- * the pending flag. */
+ /*
+ * If there are no other interrupts we want to deliver, clear
+ * the pending flag.
+ */
if (!more)
put_user(0, &cpu->lg->lguest_data->irq_pending);
}
@@ -217,24 +254,29 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
/* And this is the routine when we want to set an interrupt for the Guest. */
void set_interrupt(struct lg_cpu *cpu, unsigned int irq)
{
- /* Next time the Guest runs, the core code will see if it can deliver
- * this interrupt. */
+ /*
+ * Next time the Guest runs, the core code will see if it can deliver
+ * this interrupt.
+ */
set_bit(irq, cpu->irqs_pending);
- /* Make sure it sees it; it might be asleep (eg. halted), or
- * running the Guest right now, in which case kick_process()
- * will knock it out. */
+ /*
+ * Make sure it sees it; it might be asleep (eg. halted), or running
+ * the Guest right now, in which case kick_process() will knock it out.
+ */
if (!wake_up_process(cpu->tsk))
kick_process(cpu->tsk);
}
/*:*/
-/* Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent
+/*
+ * Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent
* me a patch, so we support that too. It'd be a big step for lguest if half
* the Plan 9 user base were to start using it.
*
* Actually now I think of it, it's possible that Ron *is* half the Plan 9
- * userbase. Oh well. */
+ * userbase. Oh well.
+ */
static bool could_be_syscall(unsigned int num)
{
/* Normal Linux SYSCALL_VECTOR or reserved vector? */
@@ -274,9 +316,11 @@ void free_interrupts(void)
clear_bit(syscall_vector, used_vectors);
}
-/*H:220 Now we've got the routines to deliver interrupts, delivering traps like
+/*H:220
+ * Now we've got the routines to deliver interrupts, delivering traps like
* page fault is easy. The only trick is that Intel decided that some traps
- * should have error codes: */
+ * should have error codes:
+ */
static bool has_err(unsigned int trap)
{
return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
@@ -285,13 +329,17 @@ static bool has_err(unsigned int trap)
/* deliver_trap() returns true if it could deliver the trap. */
bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
{
- /* Trap numbers are always 8 bit, but we set an impossible trap number
- * for traps inside the Switcher, so check that here. */
+ /*
+ * Trap numbers are always 8 bit, but we set an impossible trap number
+ * for traps inside the Switcher, so check that here.
+ */
if (num >= ARRAY_SIZE(cpu->arch.idt))
return false;
- /* Early on the Guest hasn't set the IDT entries (or maybe it put a
- * bogus one in): if we fail here, the Guest will be killed. */
+ /*
+ * Early on the Guest hasn't set the IDT entries (or maybe it put a
+ * bogus one in): if we fail here, the Guest will be killed.
+ */
if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
return false;
set_guest_interrupt(cpu, cpu->arch.idt[num].a,
@@ -299,7 +347,8 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
return true;
}
-/*H:250 Here's the hard part: returning to the Host every time a trap happens
+/*H:250
+ * Here's the hard part: returning to the Host every time a trap happens
* and then calling deliver_trap() and re-entering the Guest is slow.
* Particularly because Guest userspace system calls are traps (usually trap
* 128).
@@ -311,69 +360,87 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
* the other hypervisors would beat it up at lunchtime.
*
* This routine indicates if a particular trap number could be delivered
- * directly. */
+ * directly.
+ */
static bool direct_trap(unsigned int num)
{
- /* Hardware interrupts don't go to the Guest at all (except system
- * call). */
+ /*
+ * Hardware interrupts don't go to the Guest at all (except system
+ * call).
+ */
if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
return false;
- /* The Host needs to see page faults (for shadow paging and to save the
+ /*
+ * The Host needs to see page faults (for shadow paging and to save the
* fault address), general protection faults (in/out emulation) and
* device not available (TS handling), invalid opcode fault (kvm hcall),
- * and of course, the hypercall trap. */
+ * and of course, the hypercall trap.
+ */
return num != 14 && num != 13 && num != 7 &&
num != 6 && num != LGUEST_TRAP_ENTRY;
}
/*:*/
-/*M:005 The Guest has the ability to turn its interrupt gates into trap gates,
+/*M:005
+ * The Guest has the ability to turn its interrupt gates into trap gates,
* if it is careful. The Host will let trap gates can go directly to the
* Guest, but the Guest needs the interrupts atomically disabled for an
* interrupt gate. It can do this by pointing the trap gate at instructions
- * within noirq_start and noirq_end, where it can safely disable interrupts. */
+ * within noirq_start and noirq_end, where it can safely disable interrupts.
+ */
-/*M:006 The Guests do not use the sysenter (fast system call) instruction,
+/*M:006
+ * The Guests do not use the sysenter (fast system call) instruction,
* because it's hardcoded to enter privilege level 0 and so can't go direct.
* It's about twice as fast as the older "int 0x80" system call, so it might
* still be worthwhile to handle it in the Switcher and lcall down to the
* Guest. The sysenter semantics are hairy tho: search for that keyword in
- * entry.S :*/
+ * entry.S
+:*/
-/*H:260 When we make traps go directly into the Guest, we need to make sure
+/*H:260
+ * When we make traps go directly into the Guest, we need to make sure
* the kernel stack is valid (ie. mapped in the page tables). Otherwise, the
* CPU trying to deliver the trap will fault while trying to push the interrupt
* words on the stack: this is called a double fault, and it forces us to kill
* the Guest.
*
- * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */
+ * Which is deeply unfair, because (literally!) it wasn't the Guests' fault.
+ */
void pin_stack_pages(struct lg_cpu *cpu)
{
unsigned int i;
- /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
- * two pages of stack space. */
+ /*
+ * Depending on the CONFIG_4KSTACKS option, the Guest can have one or
+ * two pages of stack space.
+ */
for (i = 0; i < cpu->lg->stack_pages; i++)
- /* The stack grows *upwards*, so the address we're given is the
+ /*
+ * The stack grows *upwards*, so the address we're given is the
* start of the page after the kernel stack. Subtract one to
* get back onto the first stack page, and keep subtracting to
- * get to the rest of the stack pages. */
+ * get to the rest of the stack pages.
+ */
pin_page(cpu, cpu->esp1 - 1 - i * PAGE_SIZE);
}
-/* Direct traps also mean that we need to know whenever the Guest wants to use
+/*
+ * Direct traps also mean that we need to know whenever the Guest wants to use
* a different kernel stack, so we can change the IDT entries to use that
* stack. The IDT entries expect a virtual address, so unlike most addresses
* the Guest gives us, the "esp" (stack pointer) value here is virtual, not
* physical.
*
* In Linux each process has its own kernel stack, so this happens a lot: we
- * change stacks on each context switch. */
+ * change stacks on each context switch.
+ */
void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages)
{
- /* You are not allowed have a stack segment with privilege level 0: bad
- * Guest! */
+ /*
+ * You're not allowed a stack segment with privilege level 0: bad Guest!
+ */
if ((seg & 0x3) != GUEST_PL)
kill_guest(cpu, "bad stack segment %i", seg);
/* We only expect one or two stack pages. */
@@ -387,11 +454,15 @@ void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages)
pin_stack_pages(cpu);
}
-/* All this reference to mapping stacks leads us neatly into the other complex
- * part of the Host: page table handling. */
+/*
+ * All this reference to mapping stacks leads us neatly into the other complex
+ * part of the Host: page table handling.
+ */
-/*H:235 This is the routine which actually checks the Guest's IDT entry and
- * transfers it into the entry in "struct lguest": */
+/*H:235
+ * This is the routine which actually checks the Guest's IDT entry and
+ * transfers it into the entry in "struct lguest":
+ */
static void set_trap(struct lg_cpu *cpu, struct desc_struct *trap,
unsigned int num, u32 lo, u32 hi)
{
@@ -407,30 +478,38 @@ static void set_trap(struct lg_cpu *cpu, struct desc_struct *trap,
if (type != 0xE && type != 0xF)
kill_guest(cpu, "bad IDT type %i", type);
- /* We only copy the handler address, present bit, privilege level and
+ /*
+ * We only copy the handler address, present bit, privilege level and
* type. The privilege level controls where the trap can be triggered
* manually with an "int" instruction. This is usually GUEST_PL,
- * except for system calls which userspace can use. */
+ * except for system calls which userspace can use.
+ */
trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
trap->b = (hi&0xFFFFEF00);
}
-/*H:230 While we're here, dealing with delivering traps and interrupts to the
+/*H:230
+ * While we're here, dealing with delivering traps and interrupts to the
* Guest, we might as well complete the picture: how the Guest tells us where
* it wants them to go. This would be simple, except making traps fast
* requires some tricks.
*
* We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the
- * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */
+ * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here.
+ */
void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi)
{
- /* Guest never handles: NMI, doublefault, spurious interrupt or
- * hypercall. We ignore when it tries to set them. */
+ /*
+ * Guest never handles: NMI, doublefault, spurious interrupt or
+ * hypercall. We ignore when it tries to set them.
+ */
if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
return;
- /* Mark the IDT as changed: next time the Guest runs we'll know we have
- * to copy this again. */
+ /*
+ * Mark the IDT as changed: next time the Guest runs we'll know we have
+ * to copy this again.
+ */
cpu->changed |= CHANGED_IDT;
/* Check that the Guest doesn't try to step outside the bounds. */
@@ -440,9 +519,11 @@ void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi)
set_trap(cpu, &cpu->arch.idt[num], num, lo, hi);
}
-/* The default entry for each interrupt points into the Switcher routines which
+/*
+ * The default entry for each interrupt points into the Switcher routines which
* simply return to the Host. The run_guest() loop will then call
- * deliver_trap() to bounce it back into the Guest. */
+ * deliver_trap() to bounce it back into the Guest.
+ */
static void default_idt_entry(struct desc_struct *idt,
int trap,
const unsigned long handler,
@@ -451,13 +532,17 @@ static void default_idt_entry(struct desc_struct *idt,
/* A present interrupt gate. */
u32 flags = 0x8e00;
- /* Set the privilege level on the entry for the hypercall: this allows
- * the Guest to use the "int" instruction to trigger it. */
+ /*
+ * Set the privilege level on the entry for the hypercall: this allows
+ * the Guest to use the "int" instruction to trigger it.
+ */
if (trap == LGUEST_TRAP_ENTRY)
flags |= (GUEST_PL << 13);
else if (base)
- /* Copy priv. level from what Guest asked for. This allows
- * debug (int 3) traps from Guest userspace, for example. */
+ /*
+ * Copy privilege level from what Guest asked for. This allows
+ * debug (int 3) traps from Guest userspace, for example.
+ */
flags |= (base->b & 0x6000);
/* Now pack it into the IDT entry in its weird format. */
@@ -475,16 +560,20 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
default_idt_entry(&state->guest_idt[i], i, def[i], NULL);
}
-/*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
+/*H:240
+ * We don't use the IDT entries in the "struct lguest" directly, instead
* we copy them into the IDT which we've set up for Guests on this CPU, just
- * before we run the Guest. This routine does that copy. */
+ * before we run the Guest. This routine does that copy.
+ */
void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
const unsigned long *def)
{
unsigned int i;
- /* We can simply copy the direct traps, otherwise we use the default
- * ones in the Switcher: they will return to the Host. */
+ /*
+ * We can simply copy the direct traps, otherwise we use the default
+ * ones in the Switcher: they will return to the Host.
+ */
for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) {
const struct desc_struct *gidt = &cpu->arch.idt[i];
@@ -492,14 +581,16 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
if (!direct_trap(i))
continue;
- /* Only trap gates (type 15) can go direct to the Guest.
+ /*
+ * Only trap gates (type 15) can go direct to the Guest.
* Interrupt gates (type 14) disable interrupts as they are
* entered, which we never let the Guest do. Not present
* entries (type 0x0) also can't go direct, of course.
*
* If it can't go direct, we still need to copy the priv. level:
* they might want to give userspace access to a software
- * interrupt. */
+ * interrupt.
+ */
if (idt_type(gidt->a, gidt->b) == 0xF)
idt[i] = *gidt;
else
@@ -518,7 +609,8 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
* the next timer interrupt (in nanoseconds). We use the high-resolution timer
* infrastructure to set a callback at that time.
*
- * 0 means "turn off the clock". */
+ * 0 means "turn off the clock".
+ */
void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta)
{
ktime_t expires;
@@ -529,9 +621,11 @@ void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta)
return;
}
- /* We use wallclock time here, so the Guest might not be running for
+ /*
+ * We use wallclock time here, so the Guest might not be running for
* all the time between now and the timer interrupt it asked for. This
- * is almost always the right thing to do. */
+ * is almost always the right thing to do.
+ */
expires = ktime_add_ns(ktime_get_real(), delta);
hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS);
}
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 01c591923793..bc28745d05af 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -16,15 +16,13 @@
void free_pagetables(void);
int init_pagetables(struct page **switcher_page, unsigned int pages);
-struct pgdir
-{
+struct pgdir {
unsigned long gpgdir;
pgd_t *pgdir;
};
/* We have two pages shared with guests, per cpu. */
-struct lguest_pages
-{
+struct lguest_pages {
/* This is the stack page mapped rw in guest */
char spare[PAGE_SIZE - sizeof(struct lguest_regs)];
struct lguest_regs regs;
@@ -54,13 +52,13 @@ struct lg_cpu {
unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
- /* At end of a page shared mapped over lguest_pages in guest. */
+ /* At end of a page shared mapped over lguest_pages in guest. */
unsigned long regs_page;
struct lguest_regs *regs;
struct lguest_pages *last_pages;
- int cpu_pgd; /* which pgd this cpu is currently using */
+ int cpu_pgd; /* Which pgd this cpu is currently using */
/* If a hypercall was asked for, this points to the arguments. */
struct hcall_args *hcall;
@@ -89,15 +87,17 @@ struct lg_eventfd_map {
};
/* The private info the thread maintains about the guest. */
-struct lguest
-{
+struct lguest {
struct lguest_data __user *lguest_data;
struct lg_cpu cpus[NR_CPUS];
unsigned int nr_cpus;
u32 pfn_limit;
- /* This provides the offset to the base of guest-physical
- * memory in the Launcher. */
+
+ /*
+ * This provides the offset to the base of guest-physical memory in the
+ * Launcher.
+ */
void __user *mem_base;
unsigned long kernel_address;
@@ -122,11 +122,13 @@ bool lguest_address_ok(const struct lguest *lg,
void __lgread(struct lg_cpu *, void *, unsigned long, unsigned);
void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned);
-/*H:035 Using memory-copy operations like that is usually inconvient, so we
+/*H:035
+ * Using memory-copy operations like that is usually inconvient, so we
* have the following helper macros which read and write a specific type (often
* an unsigned long).
*
- * This reads into a variable of the given type then returns that. */
+ * This reads into a variable of the given type then returns that.
+ */
#define lgread(cpu, addr, type) \
({ type _v; __lgread((cpu), &_v, (addr), sizeof(_v)); _v; })
@@ -140,9 +142,11 @@ void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned);
int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
-/* Helper macros to obtain the first 12 or the last 20 bits, this is only the
+/*
+ * Helper macros to obtain the first 12 or the last 20 bits, this is only the
* first step in the migration to the kernel types. pte_pfn is already defined
- * in the kernel. */
+ * in the kernel.
+ */
#define pgd_flags(x) (pgd_val(x) & ~PAGE_MASK)
#define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT)
#define pmd_flags(x) (pmd_val(x) & ~PAGE_MASK)
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index e082cdac88b4..b6200bc39b58 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -1,10 +1,12 @@
-/*P:050 Lguest guests use a very simple method to describe devices. It's a
+/*P:050
+ * Lguest guests use a very simple method to describe devices. It's a
* series of device descriptors contained just above the top of normal Guest
* memory.
*
* We use the standard "virtio" device infrastructure, which provides us with a
* console, a network and a block driver. Each one expects some configuration
- * information and a "virtqueue" or two to send and receive data. :*/
+ * information and a "virtqueue" or two to send and receive data.
+:*/
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/lguest_launcher.h>
@@ -20,8 +22,10 @@
/* The pointer to our (page) of device descriptions. */
static void *lguest_devices;
-/* For Guests, device memory can be used as normal memory, so we cast away the
- * __iomem to quieten sparse. */
+/*
+ * For Guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse.
+ */
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
{
return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
@@ -32,8 +36,10 @@ static inline void lguest_unmap(void *addr)
iounmap((__force void __iomem *)addr);
}
-/*D:100 Each lguest device is just a virtio device plus a pointer to its entry
- * in the lguest_devices page. */
+/*D:100
+ * Each lguest device is just a virtio device plus a pointer to its entry
+ * in the lguest_devices page.
+ */
struct lguest_device {
struct virtio_device vdev;
@@ -41,9 +47,11 @@ struct lguest_device {
struct lguest_device_desc *desc;
};
-/* Since the virtio infrastructure hands us a pointer to the virtio_device all
+/*
+ * Since the virtio infrastructure hands us a pointer to the virtio_device all
* the time, it helps to have a curt macro to get a pointer to the struct
- * lguest_device it's enclosed in. */
+ * lguest_device it's enclosed in.
+ */
#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)
/*D:130
@@ -55,7 +63,8 @@ struct lguest_device {
* the driver will look at them during setup.
*
* A convenient routine to return the device's virtqueue config array:
- * immediately after the descriptor. */
+ * immediately after the descriptor.
+ */
static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
{
return (void *)(desc + 1);
@@ -98,10 +107,12 @@ static u32 lg_get_features(struct virtio_device *vdev)
return features;
}
-/* The virtio core takes the features the Host offers, and copies the
- * ones supported by the driver into the vdev->features array. Once
- * that's all sorted out, this routine is called so we can tell the
- * Host which features we understand and accept. */
+/*
+ * The virtio core takes the features the Host offers, and copies the ones
+ * supported by the driver into the vdev->features array. Once that's all
+ * sorted out, this routine is called so we can tell the Host which features we
+ * understand and accept.
+ */
static void lg_finalize_features(struct virtio_device *vdev)
{
unsigned int i, bits;
@@ -112,10 +123,11 @@ static void lg_finalize_features(struct virtio_device *vdev)
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
- /* The vdev->feature array is a Linux bitmask: this isn't the
- * same as a the simple array of bits used by lguest devices
- * for features. So we do this slow, manual conversion which is
- * completely general. */
+ /*
+ * The vdev->feature array is a Linux bitmask: this isn't the same as a
+ * the simple array of bits used by lguest devices for features. So we
+ * do this slow, manual conversion which is completely general.
+ */
memset(out_features, 0, desc->feature_len);
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
@@ -146,15 +158,19 @@ static void lg_set(struct virtio_device *vdev, unsigned int offset,
memcpy(lg_config(desc) + offset, buf, len);
}
-/* The operations to get and set the status word just access the status field
- * of the device descriptor. */
+/*
+ * The operations to get and set the status word just access the status field
+ * of the device descriptor.
+ */
static u8 lg_get_status(struct virtio_device *vdev)
{
return to_lgdev(vdev)->desc->status;
}
-/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
- * descriptor address of the device. A zero status means "reset". */
+/*
+ * To notify on status updates, we (ab)use the NOTIFY hypercall, with the
+ * descriptor address of the device. A zero status means "reset".
+ */
static void set_status(struct virtio_device *vdev, u8 status)
{
unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
@@ -191,8 +207,7 @@ static void lg_reset(struct virtio_device *vdev)
*/
/*D:140 This is the information we remember about each virtqueue. */
-struct lguest_vq_info
-{
+struct lguest_vq_info {
/* A copy of the information contained in the device config. */
struct lguest_vqconfig config;
@@ -200,13 +215,17 @@ struct lguest_vq_info
void *pages;
};
-/* When the virtio_ring code wants to prod the Host, it calls us here and we
+/*
+ * When the virtio_ring code wants to prod the Host, it calls us here and we
* make a hypercall. We hand the physical address of the virtqueue so the Host
- * knows which virtqueue we're talking about. */
+ * knows which virtqueue we're talking about.
+ */
static void lg_notify(struct virtqueue *vq)
{
- /* We store our virtqueue information in the "priv" pointer of the
- * virtqueue structure. */
+ /*
+ * We store our virtqueue information in the "priv" pointer of the
+ * virtqueue structure.
+ */
struct lguest_vq_info *lvq = vq->priv;
kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT);
@@ -215,7 +234,8 @@ static void lg_notify(struct virtqueue *vq)
/* An extern declaration inside a C file is bad form. Don't do it. */
extern void lguest_setup_irq(unsigned int irq);
-/* This routine finds the first virtqueue described in the configuration of
+/*
+ * This routine finds the Nth virtqueue described in the configuration of
* this device and sets it up.
*
* This is kind of an ugly duckling. It'd be nicer to have a standard
@@ -223,9 +243,7 @@ extern void lguest_setup_irq(unsigned int irq);
* everyone wants to do it differently. The KVM coders want the Guest to
* allocate its own pages and tell the Host where they are, but for lguest it's
* simpler for the Host to simply tell us where the pages are.
- *
- * So we provide drivers with a "find the Nth virtqueue and set it up"
- * function. */
+ */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
unsigned index,
void (*callback)(struct virtqueue *vq),
@@ -244,9 +262,11 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
if (!lvq)
return ERR_PTR(-ENOMEM);
- /* Make a copy of the "struct lguest_vqconfig" entry, which sits after
+ /*
+ * Make a copy of the "struct lguest_vqconfig" entry, which sits after
* the descriptor. We need a copy because the config space might not
- * be aligned correctly. */
+ * be aligned correctly.
+ */
memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
printk("Mapping virtqueue %i addr %lx\n", index,
@@ -261,8 +281,10 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
goto free_lvq;
}
- /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
- * and we've got a pointer to its pages. */
+ /*
+ * OK, tell virtio_ring.c to set up a virtqueue now we know its size
+ * and we've got a pointer to its pages.
+ */
vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
vdev, lvq->pages, lg_notify, callback, name);
if (!vq) {
@@ -273,18 +295,23 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
/* Make sure the interrupt is allocated. */
lguest_setup_irq(lvq->config.irq);
- /* Tell the interrupt for this virtqueue to go to the virtio_ring
- * interrupt handler. */
- /* FIXME: We used to have a flag for the Host to tell us we could use
+ /*
+ * Tell the interrupt for this virtqueue to go to the virtio_ring
+ * interrupt handler.
+ *
+ * FIXME: We used to have a flag for the Host to tell us we could use
* the interrupt as a source of randomness: it'd be nice to have that
- * back.. */
+ * back.
+ */
err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
dev_name(&vdev->dev), vq);
if (err)
goto destroy_vring;
- /* Last of all we hook up our 'struct lguest_vq_info" to the
- * virtqueue's priv pointer. */
+ /*
+ * Last of all we hook up our 'struct lguest_vq_info" to the
+ * virtqueue's priv pointer.
+ */
vq->priv = lvq;
return vq;
@@ -358,11 +385,14 @@ static struct virtio_config_ops lguest_config_ops = {
.del_vqs = lg_del_vqs,
};
-/* The root device for the lguest virtio devices. This makes them appear as
- * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */
+/*
+ * The root device for the lguest virtio devices. This makes them appear as
+ * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2.
+ */
static struct device *lguest_root;
-/*D:120 This is the core of the lguest bus: actually adding a new device.
+/*D:120
+ * This is the core of the lguest bus: actually adding a new device.
* It's a separate function because it's neater that way, and because an
* earlier version of the code supported hotplug and unplug. They were removed
* early on because they were never used.
@@ -371,14 +401,14 @@ static struct device *lguest_root;
*
* It's worth reading this carefully: we start with a pointer to the new device
* descriptor in the "lguest_devices" page, and the offset into the device
- * descriptor page so we can uniquely identify it if things go badly wrong. */
+ * descriptor page so we can uniquely identify it if things go badly wrong.
+ */
static void add_lguest_device(struct lguest_device_desc *d,
unsigned int offset)
{
struct lguest_device *ldev;
- /* Start with zeroed memory; Linux's device layer seems to count on
- * it. */
+ /* Start with zeroed memory; Linux's device layer counts on it. */
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev) {
printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
@@ -388,17 +418,25 @@ static void add_lguest_device(struct lguest_device_desc *d,
/* This devices' parent is the lguest/ dir. */
ldev->vdev.dev.parent = lguest_root;
- /* We have a unique device index thanks to the dev_index counter. */
+ /*
+ * The device type comes straight from the descriptor. There's also a
+ * device vendor field in the virtio_device struct, which we leave as
+ * 0.
+ */
ldev->vdev.id.device = d->type;
- /* We have a simple set of routines for querying the device's
- * configuration information and setting its status. */
+ /*
+ * We have a simple set of routines for querying the device's
+ * configuration information and setting its status.
+ */
ldev->vdev.config = &lguest_config_ops;
/* And we remember the device's descriptor for lguest_config_ops. */
ldev->desc = d;
- /* register_virtio_device() sets up the generic fields for the struct
+ /*
+ * register_virtio_device() sets up the generic fields for the struct
* virtio_device and calls device_register(). This makes the bus
- * infrastructure look for a matching driver. */
+ * infrastructure look for a matching driver.
+ */
if (register_virtio_device(&ldev->vdev) != 0) {
printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
offset, d->type);
@@ -406,8 +444,10 @@ static void add_lguest_device(struct lguest_device_desc *d,
}
}
-/*D:110 scan_devices() simply iterates through the device page. The type 0 is
- * reserved to mean "end of devices". */
+/*D:110
+ * scan_devices() simply iterates through the device page. The type 0 is
+ * reserved to mean "end of devices".
+ */
static void scan_devices(void)
{
unsigned int i;
@@ -426,7 +466,8 @@ static void scan_devices(void)
}
}
-/*D:105 Fairly early in boot, lguest_devices_init() is called to set up the
+/*D:105
+ * Fairly early in boot, lguest_devices_init() is called to set up the
* lguest device infrastructure. We check that we are a Guest by checking
* pv_info.name: there are other ways of checking, but this seems most
* obvious to me.
@@ -437,7 +478,8 @@ static void scan_devices(void)
* correct sysfs incantation).
*
* Finally we call scan_devices() which adds all the devices found in the
- * lguest_devices page. */
+ * lguest_devices page.
+ */
static int __init lguest_devices_init(void)
{
if (strcmp(pv_info.name, "lguest") != 0)
@@ -456,11 +498,13 @@ static int __init lguest_devices_init(void)
/* We do this after core stuff, but before the drivers. */
postcore_initcall(lguest_devices_init);
-/*D:150 At this point in the journey we used to now wade through the lguest
+/*D:150
+ * At this point in the journey we used to now wade through the lguest
* devices themselves: net, block and console. Since they're all now virtio
* devices rather than lguest-specific, I've decided to ignore them. Mostly,
* they're kind of boring. But this does mean you'll never experience the
* thrill of reading the forbidden love scene buried deep in the block driver.
*
* "make Launcher" beckons, where we answer questions like "Where do Guests
- * come from?", and "What do you do when someone asks for optimization?". */
+ * come from?", and "What do you do when someone asks for optimization?".
+ */
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 9f9a2953b383..b4d3f7ca554f 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -1,8 +1,9 @@
/*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
* controls and communicates with the Guest. For example, the first write will
- * tell us the Guest's memory layout, pagetable, entry point and kernel address
- * offset. A read will run the Guest until something happens, such as a signal
- * or the Guest doing a NOTIFY out to the Launcher. :*/
+ * tell us the Guest's memory layout and entry point. A read will run the
+ * Guest until something happens, such as a signal or the Guest doing a NOTIFY
+ * out to the Launcher.
+:*/
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
@@ -11,14 +12,41 @@
#include <linux/file.h>
#include "lg.h"
+/*L:056
+ * Before we move on, let's jump ahead and look at what the kernel does when
+ * it needs to look up the eventfds. That will complete our picture of how we
+ * use RCU.
+ *
+ * The notification value is in cpu->pending_notify: we return true if it went
+ * to an eventfd.
+ */
bool send_notify_to_eventfd(struct lg_cpu *cpu)
{
unsigned int i;
struct lg_eventfd_map *map;
- /* lg->eventfds is RCU-protected */
+ /*
+ * This "rcu_read_lock()" helps track when someone is still looking at
+ * the (RCU-using) eventfds array. It's not actually a lock at all;
+ * indeed it's a noop in many configurations. (You didn't expect me to
+ * explain all the RCU secrets here, did you?)
+ */
rcu_read_lock();
+ /*
+ * rcu_dereference is the counter-side of rcu_assign_pointer(); it
+ * makes sure we don't access the memory pointed to by
+ * cpu->lg->eventfds before cpu->lg->eventfds is set. Sounds crazy,
+ * but Alpha allows this! Paul McKenney points out that a really
+ * aggressive compiler could have the same effect:
+ * http://lists.ozlabs.org/pipermail/lguest/2009-July/001560.html
+ *
+ * So play safe, use rcu_dereference to get the rcu-protected pointer:
+ */
map = rcu_dereference(cpu->lg->eventfds);
+ /*
+ * Simple array search: even if they add an eventfd while we do this,
+ * we'll continue to use the old array and just won't see the new one.
+ */
for (i = 0; i < map->num; i++) {
if (map->map[i].addr == cpu->pending_notify) {
eventfd_signal(map->map[i].event, 1);
@@ -26,19 +54,50 @@ bool send_notify_to_eventfd(struct lg_cpu *cpu)
break;
}
}
+ /* We're done with the rcu-protected variable cpu->lg->eventfds. */
rcu_read_unlock();
+
+ /* If we cleared the notification, it's because we found a match. */
return cpu->pending_notify == 0;
}
+/*L:055
+ * One of the more tricksy tricks in the Linux Kernel is a technique called
+ * Read Copy Update. Since one point of lguest is to teach lguest journeyers
+ * about kernel coding, I use it here. (In case you're curious, other purposes
+ * include learning about virtualization and instilling a deep appreciation for
+ * simplicity and puppies).
+ *
+ * We keep a simple array which maps LHCALL_NOTIFY values to eventfds, but we
+ * add new eventfds without ever blocking readers from accessing the array.
+ * The current Launcher only does this during boot, so that never happens. But
+ * Read Copy Update is cool, and adding a lock risks damaging even more puppies
+ * than this code does.
+ *
+ * We allocate a brand new one-larger array, copy the old one and add our new
+ * element. Then we make the lg eventfd pointer point to the new array.
+ * That's the easy part: now we need to free the old one, but we need to make
+ * sure no slow CPU somewhere is still looking at it. That's what
+ * synchronize_rcu does for us: waits until every CPU has indicated that it has
+ * moved on to know it's no longer using the old one.
+ *
+ * If that's unclear, see http://en.wikipedia.org/wiki/Read-copy-update.
+ */
static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
{
struct lg_eventfd_map *new, *old = lg->eventfds;
+ /*
+ * We don't allow notifications on value 0 anyway (pending_notify of
+ * 0 means "nothing pending").
+ */
if (!addr)
return -EINVAL;
- /* Replace the old array with the new one, carefully: others can
- * be accessing it at the same time */
+ /*
+ * Replace the old array with the new one, carefully: others can
+ * be accessing it at the same time.
+ */
new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
GFP_KERNEL);
if (!new)
@@ -52,22 +111,41 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
new->map[new->num].addr = addr;
new->map[new->num].event = eventfd_ctx_fdget(fd);
if (IS_ERR(new->map[new->num].event)) {
+ int err = PTR_ERR(new->map[new->num].event);
kfree(new);
- return PTR_ERR(new->map[new->num].event);
+ return err;
}
new->num++;
- /* Now put new one in place. */
+ /*
+ * Now put new one in place: rcu_assign_pointer() is a fancy way of
+ * doing "lg->eventfds = new", but it uses memory barriers to make
+ * absolutely sure that the contents of "new" written above is nailed
+ * down before we actually do the assignment.
+ *
+ * We have to think about these kinds of things when we're operating on
+ * live data without locks.
+ */
rcu_assign_pointer(lg->eventfds, new);
- /* We're not in a big hurry. Wait until noone's looking at old
- * version, then delete it. */
+ /*
+ * We're not in a big hurry. Wait until noone's looking at old
+ * version, then free it.
+ */
synchronize_rcu();
kfree(old);
return 0;
}
+/*L:052
+ * Receiving notifications from the Guest is usually done by attaching a
+ * particular LHCALL_NOTIFY value to an event filedescriptor. The eventfd will
+ * become readable when the Guest does an LHCALL_NOTIFY with that value.
+ *
+ * This is really convenient for processing each virtqueue in a separate
+ * thread.
+ */
static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
{
unsigned long addr, fd;
@@ -79,15 +157,22 @@ static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
if (get_user(fd, input) != 0)
return -EFAULT;
+ /*
+ * Just make sure two callers don't add eventfds at once. We really
+ * only need to lock against callers adding to the same Guest, so using
+ * the Big Lguest Lock is overkill. But this is setup, not a fast path.
+ */
mutex_lock(&lguest_lock);
err = add_eventfd(lg, addr, fd);
mutex_unlock(&lguest_lock);
- return 0;
+ return err;
}
-/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
- * number to /dev/lguest. */
+/*L:050
+ * Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
+ * number to /dev/lguest.
+ */
static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
{
unsigned long irq;
@@ -97,12 +182,18 @@ static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
if (irq >= LGUEST_IRQS)
return -EINVAL;
+ /*
+ * Next time the Guest runs, the core code will see if it can deliver
+ * this interrupt.
+ */
set_interrupt(cpu, irq);
return 0;
}
-/*L:040 Once our Guest is initialized, the Launcher makes it run by reading
- * from /dev/lguest. */
+/*L:040
+ * Once our Guest is initialized, the Launcher makes it run by reading
+ * from /dev/lguest.
+ */
static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
{
struct lguest *lg = file->private_data;
@@ -138,8 +229,10 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
return len;
}
- /* If we returned from read() last time because the Guest sent I/O,
- * clear the flag. */
+ /*
+ * If we returned from read() last time because the Guest sent I/O,
+ * clear the flag.
+ */
if (cpu->pending_notify)
cpu->pending_notify = 0;
@@ -147,8 +240,10 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
return run_guest(cpu, (unsigned long __user *)user);
}
-/*L:025 This actually initializes a CPU. For the moment, a Guest is only
- * uniprocessor, so "id" is always 0. */
+/*L:025
+ * This actually initializes a CPU. For the moment, a Guest is only
+ * uniprocessor, so "id" is always 0.
+ */
static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
{
/* We have a limited number the number of CPUs in the lguest struct. */
@@ -163,8 +258,10 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
/* Each CPU has a timer it can set. */
init_clockdev(cpu);
- /* We need a complete page for the Guest registers: they are accessible
- * to the Guest and we can only grant it access to whole pages. */
+ /*
+ * We need a complete page for the Guest registers: they are accessible
+ * to the Guest and we can only grant it access to whole pages.
+ */
cpu->regs_page = get_zeroed_page(GFP_KERNEL);
if (!cpu->regs_page)
return -ENOMEM;
@@ -172,29 +269,38 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
/* We actually put the registers at the bottom of the page. */
cpu->regs = (void *)cpu->regs_page + PAGE_SIZE - sizeof(*cpu->regs);
- /* Now we initialize the Guest's registers, handing it the start
- * address. */
+ /*
+ * Now we initialize the Guest's registers, handing it the start
+ * address.
+ */
lguest_arch_setup_regs(cpu, start_ip);
- /* We keep a pointer to the Launcher task (ie. current task) for when
- * other Guests want to wake this one (eg. console input). */
+ /*
+ * We keep a pointer to the Launcher task (ie. current task) for when
+ * other Guests want to wake this one (eg. console input).
+ */
cpu->tsk = current;
- /* We need to keep a pointer to the Launcher's memory map, because if
+ /*
+ * We need to keep a pointer to the Launcher's memory map, because if
* the Launcher dies we need to clean it up. If we don't keep a
- * reference, it is destroyed before close() is called. */
+ * reference, it is destroyed before close() is called.
+ */
cpu->mm = get_task_mm(cpu->tsk);
- /* We remember which CPU's pages this Guest used last, for optimization
- * when the same Guest runs on the same CPU twice. */
+ /*
+ * We remember which CPU's pages this Guest used last, for optimization
+ * when the same Guest runs on the same CPU twice.
+ */
cpu->last_pages = NULL;
/* No error == success. */
return 0;
}
-/*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit)
- * values (in addition to the LHREQ_INITIALIZE value). These are:
+/*L:020
+ * The initialization write supplies 3 pointer sized (32 or 64 bit) values (in
+ * addition to the LHREQ_INITIALIZE value). These are:
*
* base: The start of the Guest-physical memory inside the Launcher memory.
*
@@ -206,14 +312,15 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
*/
static int initialize(struct file *file, const unsigned long __user *input)
{
- /* "struct lguest" contains everything we (the Host) know about a
- * Guest. */
+ /* "struct lguest" contains all we (the Host) know about a Guest. */
struct lguest *lg;
int err;
unsigned long args[3];
- /* We grab the Big Lguest lock, which protects against multiple
- * simultaneous initializations. */
+ /*
+ * We grab the Big Lguest lock, which protects against multiple
+ * simultaneous initializations.
+ */
mutex_lock(&lguest_lock);
/* You can't initialize twice! Close the device and start again... */
if (file->private_data) {
@@ -248,8 +355,10 @@ static int initialize(struct file *file, const unsigned long __user *input)
if (err)
goto free_eventfds;
- /* Initialize the Guest's shadow page tables, using the toplevel
- * address the Launcher gave us. This allocates memory, so can fail. */
+ /*
+ * Initialize the Guest's shadow page tables, using the toplevel
+ * address the Launcher gave us. This allocates memory, so can fail.
+ */
err = init_guest_pagetable(lg);
if (err)
goto free_regs;
@@ -274,20 +383,24 @@ unlock:
return err;
}
-/*L:010 The first operation the Launcher does must be a write. All writes
+/*L:010
+ * The first operation the Launcher does must be a write. All writes
* start with an unsigned long number: for the first write this must be
* LHREQ_INITIALIZE to set up the Guest. After that the Launcher can use
- * writes of other values to send interrupts.
+ * writes of other values to send interrupts or set up receipt of notifications.
*
* Note that we overload the "offset" in the /dev/lguest file to indicate what
- * CPU number we're dealing with. Currently this is always 0, since we only
+ * CPU number we're dealing with. Currently this is always 0 since we only
* support uniprocessor Guests, but you can see the beginnings of SMP support
- * here. */
+ * here.
+ */
static ssize_t write(struct file *file, const char __user *in,
size_t size, loff_t *off)
{
- /* Once the Guest is initialized, we hold the "struct lguest" in the
- * file private data. */
+ /*
+ * Once the Guest is initialized, we hold the "struct lguest" in the
+ * file private data.
+ */
struct lguest *lg = file->private_data;
const unsigned long __user *input = (const unsigned long __user *)in;
unsigned long req;
@@ -322,13 +435,15 @@ static ssize_t write(struct file *file, const char __user *in,
}
}
-/*L:060 The final piece of interface code is the close() routine. It reverses
+/*L:060
+ * The final piece of interface code is the close() routine. It reverses
* everything done in initialize(). This is usually called because the
* Launcher exited.
*
* Note that the close routine returns 0 or a negative error number: it can't
* really fail, but it can whine. I blame Sun for this wart, and K&R C for
- * letting them do it. :*/
+ * letting them do it.
+:*/
static int close(struct inode *inode, struct file *file)
{
struct lguest *lg = file->private_data;
@@ -338,8 +453,10 @@ static int close(struct inode *inode, struct file *file)
if (!lg)
return 0;
- /* We need the big lock, to protect from inter-guest I/O and other
- * Launchers initializing guests. */
+ /*
+ * We need the big lock, to protect from inter-guest I/O and other
+ * Launchers initializing guests.
+ */
mutex_lock(&lguest_lock);
/* Free up the shadow page tables for the Guest. */
@@ -350,8 +467,10 @@ static int close(struct inode *inode, struct file *file)
hrtimer_cancel(&lg->cpus[i].hrt);
/* We can free up the register page we allocated. */
free_page(lg->cpus[i].regs_page);
- /* Now all the memory cleanups are done, it's safe to release
- * the Launcher's memory management structure. */
+ /*
+ * Now all the memory cleanups are done, it's safe to release
+ * the Launcher's memory management structure.
+ */
mmput(lg->cpus[i].mm);
}
@@ -360,8 +479,10 @@ static int close(struct inode *inode, struct file *file)
eventfd_ctx_put(lg->eventfds->map[i].event);
kfree(lg->eventfds);
- /* If lg->dead doesn't contain an error code it will be NULL or a
- * kmalloc()ed string, either of which is ok to hand to kfree(). */
+ /*
+ * If lg->dead doesn't contain an error code it will be NULL or a
+ * kmalloc()ed string, either of which is ok to hand to kfree().
+ */
if (!IS_ERR(lg->dead))
kfree(lg->dead);
/* Free the memory allocated to the lguest_struct */
@@ -385,7 +506,8 @@ static int close(struct inode *inode, struct file *file)
*
* We begin our understanding with the Host kernel interface which the Launcher
* uses: reading and writing a character device called /dev/lguest. All the
- * work happens in the read(), write() and close() routines: */
+ * work happens in the read(), write() and close() routines:
+ */
static struct file_operations lguest_fops = {
.owner = THIS_MODULE,
.release = close,
@@ -393,8 +515,10 @@ static struct file_operations lguest_fops = {
.read = read,
};
-/* This is a textbook example of a "misc" character device. Populate a "struct
- * miscdevice" and register it with misc_register(). */
+/*
+ * This is a textbook example of a "misc" character device. Populate a "struct
+ * miscdevice" and register it with misc_register().
+ */
static struct miscdevice lguest_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "lguest",
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index a6fe1abda240..c610b8218d20 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -1,9 +1,11 @@
-/*P:700 The pagetable code, on the other hand, still shows the scars of
+/*P:700
+ * The pagetable code, on the other hand, still shows the scars of
* previous encounters. It's functional, and as neat as it can be in the
* circumstances, but be wary, for these things are subtle and break easily.
* The Guest provides a virtual to physical mapping, but we can neither trust
* it nor use it: we verify and convert it here then point the CPU to the
- * converted Guest pages when running the Guest. :*/
+ * converted Guest pages when running the Guest.
+:*/
/* Copyright (C) Rusty Russell IBM Corporation 2006.
* GPL v2 and any later version */
@@ -17,18 +19,20 @@
#include <asm/bootparam.h>
#include "lg.h"
-/*M:008 We hold reference to pages, which prevents them from being swapped.
+/*M:008
+ * We hold reference to pages, which prevents them from being swapped.
* It'd be nice to have a callback in the "struct mm_struct" when Linux wants
* to swap out. If we had this, and a shrinker callback to trim PTE pages, we
- * could probably consider launching Guests as non-root. :*/
+ * could probably consider launching Guests as non-root.
+:*/
/*H:300
* The Page Table Code
*
- * We use two-level page tables for the Guest. If you're not entirely
- * comfortable with virtual addresses, physical addresses and page tables then
- * I recommend you review arch/x86/lguest/boot.c's "Page Table Handling" (with
- * diagrams!).
+ * We use two-level page tables for the Guest, or three-level with PAE. If
+ * you're not entirely comfortable with virtual addresses, physical addresses
+ * and page tables then I recommend you review arch/x86/lguest/boot.c's "Page
+ * Table Handling" (with diagrams!).
*
* The Guest keeps page tables, but we maintain the actual ones here: these are
* called "shadow" page tables. Which is a very Guest-centric name: these are
@@ -45,16 +49,18 @@
* (v) Flushing (throwing away) page tables,
* (vi) Mapping the Switcher when the Guest is about to run,
* (vii) Setting up the page tables initially.
- :*/
+:*/
-
-/* 1024 entries in a page table page maps 1024 pages: 4MB. The Switcher is
- * conveniently placed at the top 4MB, so it uses a separate, complete PTE
- * page. */
+/*
+ * The Switcher uses the complete top PTE page. That's 1024 PTE entries (4MB)
+ * or 512 PTE entries with PAE (2MB).
+ */
#define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1)
-/* For PAE we need the PMD index as well. We use the last 2MB, so we
- * will need the last pmd entry of the last pmd page. */
+/*
+ * For PAE we need the PMD index as well. We use the last 2MB, so we
+ * will need the last pmd entry of the last pmd page.
+ */
#ifdef CONFIG_X86_PAE
#define SWITCHER_PMD_INDEX (PTRS_PER_PMD - 1)
#define RESERVE_MEM 2U
@@ -64,14 +70,18 @@
#define CHECK_GPGD_MASK _PAGE_TABLE
#endif
-/* We actually need a separate PTE page for each CPU. Remember that after the
+/*
+ * We actually need a separate PTE page for each CPU. Remember that after the
* Switcher code itself comes two pages for each CPU, and we don't want this
- * CPU's guest to see the pages of any other CPU. */
+ * CPU's guest to see the pages of any other CPU.
+ */
static DEFINE_PER_CPU(pte_t *, switcher_pte_pages);
#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
-/*H:320 The page table code is curly enough to need helper functions to keep it
- * clear and clean.
+/*H:320
+ * The page table code is curly enough to need helper functions to keep it
+ * clear and clean. The kernel itself provides many of them; one advantage
+ * of insisting that the Guest and Host use the same CONFIG_PAE setting.
*
* There are two functions which return pointers to the shadow (aka "real")
* page tables.
@@ -79,7 +89,8 @@ static DEFINE_PER_CPU(pte_t *, switcher_pte_pages);
* spgd_addr() takes the virtual address and returns a pointer to the top-level
* page directory entry (PGD) for that address. Since we keep track of several
* page tables, the "i" argument tells us which one we're interested in (it's
- * usually the current one). */
+ * usually the current one).
+ */
static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr)
{
unsigned int index = pgd_index(vaddr);
@@ -96,9 +107,11 @@ static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr)
}
#ifdef CONFIG_X86_PAE
-/* This routine then takes the PGD entry given above, which contains the
+/*
+ * This routine then takes the PGD entry given above, which contains the
* address of the PMD page. It then returns a pointer to the PMD entry for the
- * given address. */
+ * given address.
+ */
static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
{
unsigned int index = pmd_index(vaddr);
@@ -119,9 +132,11 @@ static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
}
#endif
-/* This routine then takes the page directory entry returned above, which
+/*
+ * This routine then takes the page directory entry returned above, which
* contains the address of the page table entry (PTE) page. It then returns a
- * pointer to the PTE entry for the given address. */
+ * pointer to the PTE entry for the given address.
+ */
static pte_t *spte_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
{
#ifdef CONFIG_X86_PAE
@@ -139,8 +154,10 @@ static pte_t *spte_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
return &page[pte_index(vaddr)];
}
-/* These two functions just like the above two, except they access the Guest
- * page tables. Hence they return a Guest address. */
+/*
+ * These functions are just like the above two, except they access the Guest
+ * page tables. Hence they return a Guest address.
+ */
static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr)
{
unsigned int index = vaddr >> (PGDIR_SHIFT);
@@ -148,6 +165,7 @@ static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr)
}
#ifdef CONFIG_X86_PAE
+/* Follow the PGD to the PMD. */
static unsigned long gpmd_addr(pgd_t gpgd, unsigned long vaddr)
{
unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
@@ -155,6 +173,7 @@ static unsigned long gpmd_addr(pgd_t gpgd, unsigned long vaddr)
return gpage + pmd_index(vaddr) * sizeof(pmd_t);
}
+/* Follow the PMD to the PTE. */
static unsigned long gpte_addr(struct lg_cpu *cpu,
pmd_t gpmd, unsigned long vaddr)
{
@@ -164,6 +183,7 @@ static unsigned long gpte_addr(struct lg_cpu *cpu,
return gpage + pte_index(vaddr) * sizeof(pte_t);
}
#else
+/* Follow the PGD to the PTE (no mid-level for !PAE). */
static unsigned long gpte_addr(struct lg_cpu *cpu,
pgd_t gpgd, unsigned long vaddr)
{
@@ -175,17 +195,21 @@ static unsigned long gpte_addr(struct lg_cpu *cpu,
#endif
/*:*/
-/*M:014 get_pfn is slow: we could probably try to grab batches of pages here as
- * an optimization (ie. pre-faulting). :*/
+/*M:014
+ * get_pfn is slow: we could probably try to grab batches of pages here as
+ * an optimization (ie. pre-faulting).
+:*/
-/*H:350 This routine takes a page number given by the Guest and converts it to
+/*H:350
+ * This routine takes a page number given by the Guest and converts it to
* an actual, physical page number. It can fail for several reasons: the
* virtual address might not be mapped by the Launcher, the write flag is set
* and the page is read-only, or the write flag was set and the page was
* shared so had to be copied, but we ran out of memory.
*
* This holds a reference to the page, so release_pte() is careful to put that
- * back. */
+ * back.
+ */
static unsigned long get_pfn(unsigned long virtpfn, int write)
{
struct page *page;
@@ -198,33 +222,41 @@ static unsigned long get_pfn(unsigned long virtpfn, int write)
return -1UL;
}
-/*H:340 Converting a Guest page table entry to a shadow (ie. real) page table
+/*H:340
+ * Converting a Guest page table entry to a shadow (ie. real) page table
* entry can be a little tricky. The flags are (almost) the same, but the
* Guest PTE contains a virtual page number: the CPU needs the real page
- * number. */
+ * number.
+ */
static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write)
{
unsigned long pfn, base, flags;
- /* The Guest sets the global flag, because it thinks that it is using
+ /*
+ * The Guest sets the global flag, because it thinks that it is using
* PGE. We only told it to use PGE so it would tell us whether it was
* flushing a kernel mapping or a userspace mapping. We don't actually
- * use the global bit, so throw it away. */
+ * use the global bit, so throw it away.
+ */
flags = (pte_flags(gpte) & ~_PAGE_GLOBAL);
/* The Guest's pages are offset inside the Launcher. */
base = (unsigned long)cpu->lg->mem_base / PAGE_SIZE;
- /* We need a temporary "unsigned long" variable to hold the answer from
+ /*
+ * We need a temporary "unsigned long" variable to hold the answer from
* get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
* fit in spte.pfn. get_pfn() finds the real physical number of the
- * page, given the virtual number. */
+ * page, given the virtual number.
+ */
pfn = get_pfn(base + pte_pfn(gpte), write);
if (pfn == -1UL) {
kill_guest(cpu, "failed to get page %lu", pte_pfn(gpte));
- /* When we destroy the Guest, we'll go through the shadow page
+ /*
+ * When we destroy the Guest, we'll go through the shadow page
* tables and release_pte() them. Make sure we don't think
- * this one is valid! */
+ * this one is valid!
+ */
flags = 0;
}
/* Now we assemble our shadow PTE from the page number and flags. */
@@ -234,8 +266,10 @@ static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write)
/*H:460 And to complete the chain, release_pte() looks like this: */
static void release_pte(pte_t pte)
{
- /* Remember that get_user_pages_fast() took a reference to the page, in
- * get_pfn()? We have to put it back now. */
+ /*
+ * Remember that get_user_pages_fast() took a reference to the page, in
+ * get_pfn()? We have to put it back now.
+ */
if (pte_flags(pte) & _PAGE_PRESENT)
put_page(pte_page(pte));
}
@@ -273,7 +307,8 @@ static void check_gpmd(struct lg_cpu *cpu, pmd_t gpmd)
* and return to the Guest without it knowing.
*
* If we fixed up the fault (ie. we mapped the address), this routine returns
- * true. Otherwise, it was a real fault and we need to tell the Guest. */
+ * true. Otherwise, it was a real fault and we need to tell the Guest.
+ */
bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
{
pgd_t gpgd;
@@ -282,6 +317,7 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
pte_t gpte;
pte_t *spte;
+ /* Mid level for PAE. */
#ifdef CONFIG_X86_PAE
pmd_t *spmd;
pmd_t gpmd;
@@ -298,22 +334,26 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) {
/* No shadow entry: allocate a new shadow PTE page. */
unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
- /* This is not really the Guest's fault, but killing it is
- * simple for this corner case. */
+ /*
+ * This is not really the Guest's fault, but killing it is
+ * simple for this corner case.
+ */
if (!ptepage) {
kill_guest(cpu, "out of memory allocating pte page");
return false;
}
/* We check that the Guest pgd is OK. */
check_gpgd(cpu, gpgd);
- /* And we copy the flags to the shadow PGD entry. The page
- * number in the shadow PGD is the page we just allocated. */
+ /*
+ * And we copy the flags to the shadow PGD entry. The page
+ * number in the shadow PGD is the page we just allocated.
+ */
set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags(gpgd)));
}
#ifdef CONFIG_X86_PAE
gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
- /* middle level not present? We can't map it in. */
+ /* Middle level not present? We can't map it in. */
if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
return false;
@@ -324,8 +364,10 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
/* No shadow entry: allocate a new shadow PTE page. */
unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
- /* This is not really the Guest's fault, but killing it is
- * simple for this corner case. */
+ /*
+ * This is not really the Guest's fault, but killing it is
+ * simple for this corner case.
+ */
if (!ptepage) {
kill_guest(cpu, "out of memory allocating pte page");
return false;
@@ -334,27 +376,37 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
/* We check that the Guest pmd is OK. */
check_gpmd(cpu, gpmd);
- /* And we copy the flags to the shadow PMD entry. The page
- * number in the shadow PMD is the page we just allocated. */
- native_set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd)));
+ /*
+ * And we copy the flags to the shadow PMD entry. The page
+ * number in the shadow PMD is the page we just allocated.
+ */
+ set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd)));
}
- /* OK, now we look at the lower level in the Guest page table: keep its
- * address, because we might update it later. */
+ /*
+ * OK, now we look at the lower level in the Guest page table: keep its
+ * address, because we might update it later.
+ */
gpte_ptr = gpte_addr(cpu, gpmd, vaddr);
#else
- /* OK, now we look at the lower level in the Guest page table: keep its
- * address, because we might update it later. */
+ /*
+ * OK, now we look at the lower level in the Guest page table: keep its
+ * address, because we might update it later.
+ */
gpte_ptr = gpte_addr(cpu, gpgd, vaddr);
#endif
+
+ /* Read the actual PTE value. */
gpte = lgread(cpu, gpte_ptr, pte_t);
/* If this page isn't in the Guest page tables, we can't page it in. */
if (!(pte_flags(gpte) & _PAGE_PRESENT))
return false;
- /* Check they're not trying to write to a page the Guest wants
- * read-only (bit 2 of errcode == write). */
+ /*
+ * Check they're not trying to write to a page the Guest wants
+ * read-only (bit 2 of errcode == write).
+ */
if ((errcode & 2) && !(pte_flags(gpte) & _PAGE_RW))
return false;
@@ -362,8 +414,10 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
return false;
- /* Check that the Guest PTE flags are OK, and the page number is below
- * the pfn_limit (ie. not mapping the Launcher binary). */
+ /*
+ * Check that the Guest PTE flags are OK, and the page number is below
+ * the pfn_limit (ie. not mapping the Launcher binary).
+ */
check_gpte(cpu, gpte);
/* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
@@ -373,29 +427,40 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
/* Get the pointer to the shadow PTE entry we're going to set. */
spte = spte_addr(cpu, *spgd, vaddr);
- /* If there was a valid shadow PTE entry here before, we release it.
- * This can happen with a write to a previously read-only entry. */
+
+ /*
+ * If there was a valid shadow PTE entry here before, we release it.
+ * This can happen with a write to a previously read-only entry.
+ */
release_pte(*spte);
- /* If this is a write, we insist that the Guest page is writable (the
- * final arg to gpte_to_spte()). */
+ /*
+ * If this is a write, we insist that the Guest page is writable (the
+ * final arg to gpte_to_spte()).
+ */
if (pte_dirty(gpte))
*spte = gpte_to_spte(cpu, gpte, 1);
else
- /* If this is a read, don't set the "writable" bit in the page
+ /*
+ * If this is a read, don't set the "writable" bit in the page
* table entry, even if the Guest says it's writable. That way
* we will come back here when a write does actually occur, so
- * we can update the Guest's _PAGE_DIRTY flag. */
- native_set_pte(spte, gpte_to_spte(cpu, pte_wrprotect(gpte), 0));
-
- /* Finally, we write the Guest PTE entry back: we've set the
- * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
+ * we can update the Guest's _PAGE_DIRTY flag.
+ */
+ set_pte(spte, gpte_to_spte(cpu, pte_wrprotect(gpte), 0));
+
+ /*
+ * Finally, we write the Guest PTE entry back: we've set the
+ * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags.
+ */
lgwrite(cpu, gpte_ptr, pte_t, gpte);
- /* The fault is fixed, the page table is populated, the mapping
+ /*
+ * The fault is fixed, the page table is populated, the mapping
* manipulated, the result returned and the code complete. A small
* delay and a trace of alliteration are the only indications the Guest
- * has that a page fault occurred at all. */
+ * has that a page fault occurred at all.
+ */
return true;
}
@@ -408,7 +473,8 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
* mapped, so it's overkill.
*
* This is a quick version which answers the question: is this virtual address
- * mapped by the shadow page tables, and is it writable? */
+ * mapped by the shadow page tables, and is it writable?
+ */
static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
{
pgd_t *spgd;
@@ -428,21 +494,26 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
return false;
#endif
- /* Check the flags on the pte entry itself: it must be present and
- * writable. */
+ /*
+ * Check the flags on the pte entry itself: it must be present and
+ * writable.
+ */
flags = pte_flags(*(spte_addr(cpu, *spgd, vaddr)));
return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
}
-/* So, when pin_stack_pages() asks us to pin a page, we check if it's already
+/*
+ * So, when pin_stack_pages() asks us to pin a page, we check if it's already
* in the page tables, and if not, we call demand_page() with error code 2
- * (meaning "write"). */
+ * (meaning "write").
+ */
void pin_page(struct lg_cpu *cpu, unsigned long vaddr)
{
if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2))
kill_guest(cpu, "bad stack page %#lx", vaddr);
}
+/*:*/
#ifdef CONFIG_X86_PAE
static void release_pmd(pmd_t *spmd)
@@ -457,7 +528,7 @@ static void release_pmd(pmd_t *spmd)
/* Now we can free the page of PTEs */
free_page((long)ptepage);
/* And zero out the PMD entry so we never release it twice. */
- native_set_pmd(spmd, __pmd(0));
+ set_pmd(spmd, __pmd(0));
}
}
@@ -479,15 +550,21 @@ static void release_pgd(pgd_t *spgd)
}
#else /* !CONFIG_X86_PAE */
-/*H:450 If we chase down the release_pgd() code, it looks like this: */
+/*H:450
+ * If we chase down the release_pgd() code, the non-PAE version looks like
+ * this. The PAE version is almost identical, but instead of calling
+ * release_pte it calls release_pmd(), which looks much like this.
+ */
static void release_pgd(pgd_t *spgd)
{
/* If the entry's not present, there's nothing to release. */
if (pgd_flags(*spgd) & _PAGE_PRESENT) {
unsigned int i;
- /* Converting the pfn to find the actual PTE page is easy: turn
+ /*
+ * Converting the pfn to find the actual PTE page is easy: turn
* the page number into a physical address, then convert to a
- * virtual address (easy for kernel pages like this one). */
+ * virtual address (easy for kernel pages like this one).
+ */
pte_t *ptepage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
/* For each entry in the page, we might need to release it. */
for (i = 0; i < PTRS_PER_PTE; i++)
@@ -499,9 +576,12 @@ static void release_pgd(pgd_t *spgd)
}
}
#endif
-/*H:445 We saw flush_user_mappings() twice: once from the flush_user_mappings()
+
+/*H:445
+ * We saw flush_user_mappings() twice: once from the flush_user_mappings()
* hypercall and once in new_pgdir() when we re-used a top-level pgdir page.
- * It simply releases every PTE page from 0 up to the Guest's kernel address. */
+ * It simply releases every PTE page from 0 up to the Guest's kernel address.
+ */
static void flush_user_mappings(struct lguest *lg, int idx)
{
unsigned int i;
@@ -510,10 +590,12 @@ static void flush_user_mappings(struct lguest *lg, int idx)
release_pgd(lg->pgdirs[idx].pgdir + i);
}
-/*H:440 (v) Flushing (throwing away) page tables,
+/*H:440
+ * (v) Flushing (throwing away) page tables,
*
* The Guest has a hypercall to throw away the page tables: it's used when a
- * large number of mappings have been changed. */
+ * large number of mappings have been changed.
+ */
void guest_pagetable_flush_user(struct lg_cpu *cpu)
{
/* Drop the userspace part of the current page table. */
@@ -551,9 +633,11 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
}
-/* We keep several page tables. This is a simple routine to find the page
+/*
+ * We keep several page tables. This is a simple routine to find the page
* table (if any) corresponding to this top-level address the Guest has given
- * us. */
+ * us.
+ */
static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
{
unsigned int i;
@@ -563,9 +647,11 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
return i;
}
-/*H:435 And this is us, creating the new page directory. If we really do
+/*H:435
+ * And this is us, creating the new page directory. If we really do
* allocate a new one (and so the kernel parts are not there), we set
- * blank_pgdir. */
+ * blank_pgdir.
+ */
static unsigned int new_pgdir(struct lg_cpu *cpu,
unsigned long gpgdir,
int *blank_pgdir)
@@ -575,8 +661,10 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
pmd_t *pmd_table;
#endif
- /* We pick one entry at random to throw out. Choosing the Least
- * Recently Used might be better, but this is easy. */
+ /*
+ * We pick one entry at random to throw out. Choosing the Least
+ * Recently Used might be better, but this is easy.
+ */
next = random32() % ARRAY_SIZE(cpu->lg->pgdirs);
/* If it's never been allocated at all before, try now. */
if (!cpu->lg->pgdirs[next].pgdir) {
@@ -587,8 +675,10 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
next = cpu->cpu_pgd;
else {
#ifdef CONFIG_X86_PAE
- /* In PAE mode, allocate a pmd page and populate the
- * last pgd entry. */
+ /*
+ * In PAE mode, allocate a pmd page and populate the
+ * last pgd entry.
+ */
pmd_table = (pmd_t *)get_zeroed_page(GFP_KERNEL);
if (!pmd_table) {
free_page((long)cpu->lg->pgdirs[next].pgdir);
@@ -598,8 +688,10 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
set_pgd(cpu->lg->pgdirs[next].pgdir +
SWITCHER_PGD_INDEX,
__pgd(__pa(pmd_table) | _PAGE_PRESENT));
- /* This is a blank page, so there are no kernel
- * mappings: caller must map the stack! */
+ /*
+ * This is a blank page, so there are no kernel
+ * mappings: caller must map the stack!
+ */
*blank_pgdir = 1;
}
#else
@@ -615,19 +707,23 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
return next;
}
-/*H:430 (iv) Switching page tables
+/*H:430
+ * (iv) Switching page tables
*
* Now we've seen all the page table setting and manipulation, let's see
* what happens when the Guest changes page tables (ie. changes the top-level
- * pgdir). This occurs on almost every context switch. */
+ * pgdir). This occurs on almost every context switch.
+ */
void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
{
int newpgdir, repin = 0;
/* Look to see if we have this one already. */
newpgdir = find_pgdir(cpu->lg, pgtable);
- /* If not, we allocate or mug an existing one: if it's a fresh one,
- * repin gets set to 1. */
+ /*
+ * If not, we allocate or mug an existing one: if it's a fresh one,
+ * repin gets set to 1.
+ */
if (newpgdir == ARRAY_SIZE(cpu->lg->pgdirs))
newpgdir = new_pgdir(cpu, pgtable, &repin);
/* Change the current pgd index to the new one. */
@@ -637,9 +733,11 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
pin_stack_pages(cpu);
}
-/*H:470 Finally, a routine which throws away everything: all PGD entries in all
+/*H:470
+ * Finally, a routine which throws away everything: all PGD entries in all
* the shadow page tables, including the Guest's kernel mappings. This is used
- * when we destroy the Guest. */
+ * when we destroy the Guest.
+ */
static void release_all_pagetables(struct lguest *lg)
{
unsigned int i, j;
@@ -656,8 +754,10 @@ static void release_all_pagetables(struct lguest *lg)
spgd = lg->pgdirs[i].pgdir + SWITCHER_PGD_INDEX;
pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
- /* And release the pmd entries of that pmd page,
- * except for the switcher pmd. */
+ /*
+ * And release the pmd entries of that pmd page,
+ * except for the switcher pmd.
+ */
for (k = 0; k < SWITCHER_PMD_INDEX; k++)
release_pmd(&pmdpage[k]);
#endif
@@ -667,10 +767,12 @@ static void release_all_pagetables(struct lguest *lg)
}
}
-/* We also throw away everything when a Guest tells us it's changed a kernel
+/*
+ * We also throw away everything when a Guest tells us it's changed a kernel
* mapping. Since kernel mappings are in every page table, it's easiest to
* throw them all away. This traps the Guest in amber for a while as
- * everything faults back in, but it's rare. */
+ * everything faults back in, but it's rare.
+ */
void guest_pagetable_clear_all(struct lg_cpu *cpu)
{
release_all_pagetables(cpu->lg);
@@ -678,15 +780,19 @@ void guest_pagetable_clear_all(struct lg_cpu *cpu)
pin_stack_pages(cpu);
}
/*:*/
-/*M:009 Since we throw away all mappings when a kernel mapping changes, our
+
+/*M:009
+ * Since we throw away all mappings when a kernel mapping changes, our
* performance sucks for guests using highmem. In fact, a guest with
* PAGE_OFFSET 0xc0000000 (the default) and more than about 700MB of RAM is
* usually slower than a Guest with less memory.
*
* This, of course, cannot be fixed. It would take some kind of... well, I
- * don't know, but the term "puissant code-fu" comes to mind. :*/
+ * don't know, but the term "puissant code-fu" comes to mind.
+:*/
-/*H:420 This is the routine which actually sets the page table entry for then
+/*H:420
+ * This is the routine which actually sets the page table entry for then
* "idx"'th shadow page table.
*
* Normally, we can just throw out the old entry and replace it with 0: if they
@@ -715,31 +821,36 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
spmd = spmd_addr(cpu, *spgd, vaddr);
if (pmd_flags(*spmd) & _PAGE_PRESENT) {
#endif
- /* Otherwise, we start by releasing
- * the existing entry. */
+ /* Otherwise, start by releasing the existing entry. */
pte_t *spte = spte_addr(cpu, *spgd, vaddr);
release_pte(*spte);
- /* If they're setting this entry as dirty or accessed,
- * we might as well put that entry they've given us
- * in now. This shaves 10% off a
- * copy-on-write micro-benchmark. */
+ /*
+ * If they're setting this entry as dirty or accessed,
+ * we might as well put that entry they've given us in
+ * now. This shaves 10% off a copy-on-write
+ * micro-benchmark.
+ */
if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
check_gpte(cpu, gpte);
- native_set_pte(spte,
- gpte_to_spte(cpu, gpte,
+ set_pte(spte,
+ gpte_to_spte(cpu, gpte,
pte_flags(gpte) & _PAGE_DIRTY));
- } else
- /* Otherwise kill it and we can demand_page()
- * it in later. */
- native_set_pte(spte, __pte(0));
+ } else {
+ /*
+ * Otherwise kill it and we can demand_page()
+ * it in later.
+ */
+ set_pte(spte, __pte(0));
+ }
#ifdef CONFIG_X86_PAE
}
#endif
}
}
-/*H:410 Updating a PTE entry is a little trickier.
+/*H:410
+ * Updating a PTE entry is a little trickier.
*
* We keep track of several different page tables (the Guest uses one for each
* process, so it makes sense to cache at least a few). Each of these have
@@ -748,12 +859,15 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
* all the page tables, not just the current one. This is rare.
*
* The benefit is that when we have to track a new page table, we can keep all
- * the kernel mappings. This speeds up context switch immensely. */
+ * the kernel mappings. This speeds up context switch immensely.
+ */
void guest_set_pte(struct lg_cpu *cpu,
unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
{
- /* Kernel mappings must be changed on all top levels. Slow, but doesn't
- * happen often. */
+ /*
+ * Kernel mappings must be changed on all top levels. Slow, but doesn't
+ * happen often.
+ */
if (vaddr >= cpu->lg->kernel_address) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++)
@@ -780,7 +894,7 @@ void guest_set_pte(struct lg_cpu *cpu,
* tells us they've changed. When the Guest tries to use the new entry it will
* fault and demand_page() will fix it up.
*
- * So with that in mind here's our code to to update a (top-level) PGD entry:
+ * So with that in mind here's our code to update a (top-level) PGD entry:
*/
void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx)
{
@@ -795,19 +909,25 @@ void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx)
/* ... throw it away. */
release_pgd(lg->pgdirs[pgdir].pgdir + idx);
}
+
#ifdef CONFIG_X86_PAE
+/* For setting a mid-level, we just throw everything away. It's easy. */
void guest_set_pmd(struct lguest *lg, unsigned long pmdp, u32 idx)
{
guest_pagetable_clear_all(&lg->cpus[0]);
}
#endif
-/* Once we know how much memory we have we can construct simple identity
- * (which set virtual == physical) and linear mappings
- * which will get the Guest far enough into the boot to create its own.
+/*H:505
+ * To get through boot, we construct simple identity page mappings (which
+ * set virtual == physical) and linear mappings which will get the Guest far
+ * enough into the boot to create its own. The linear mapping means we
+ * simplify the Guest boot, but it makes assumptions about their PAGE_OFFSET,
+ * as you'll see.
*
* We lay them out of the way, just below the initrd (which is why we need to
- * know its size here). */
+ * know its size here).
+ */
static unsigned long setup_pagetables(struct lguest *lg,
unsigned long mem,
unsigned long initrd_size)
@@ -825,8 +945,10 @@ static unsigned long setup_pagetables(struct lguest *lg,
unsigned int phys_linear;
#endif
- /* We have mapped_pages frames to map, so we need
- * linear_pages page tables to map them. */
+ /*
+ * We have mapped_pages frames to map, so we need linear_pages page
+ * tables to map them.
+ */
mapped_pages = mem / PAGE_SIZE;
linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE;
@@ -837,10 +959,16 @@ static unsigned long setup_pagetables(struct lguest *lg,
linear = (void *)pgdir - linear_pages * PAGE_SIZE;
#ifdef CONFIG_X86_PAE
+ /*
+ * And the single mid page goes below that. We only use one, but
+ * that's enough to map 1G, which definitely gets us through boot.
+ */
pmds = (void *)linear - PAGE_SIZE;
#endif
- /* Linear mapping is easy: put every page's address into the
- * mapping in order. */
+ /*
+ * Linear mapping is easy: put every page's address into the
+ * mapping in order.
+ */
for (i = 0; i < mapped_pages; i++) {
pte_t pte;
pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER));
@@ -848,30 +976,48 @@ static unsigned long setup_pagetables(struct lguest *lg,
return -EFAULT;
}
- /* The top level points to the linear page table pages above.
- * We setup the identity and linear mappings here. */
#ifdef CONFIG_X86_PAE
+ /*
+ * Make the Guest PMD entries point to the corresponding place in the
+ * linear mapping (up to one page worth of PMD).
+ */
for (i = j = 0; i < mapped_pages && j < PTRS_PER_PMD;
i += PTRS_PER_PTE, j++) {
- native_set_pmd(&pmd, __pmd(((unsigned long)(linear + i)
- - mem_base) | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
+ pmd = pfn_pmd(((unsigned long)&linear[i] - mem_base)/PAGE_SIZE,
+ __pgrot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
if (copy_to_user(&pmds[j], &pmd, sizeof(pmd)) != 0)
return -EFAULT;
}
- set_pgd(&pgd, __pgd(((u32)pmds - mem_base) | _PAGE_PRESENT));
+ /* One PGD entry, pointing to that PMD page. */
+ pgd = __pgd(((unsigned long)pmds - mem_base) | _PAGE_PRESENT);
+ /* Copy it in as the first PGD entry (ie. addresses 0-1G). */
if (copy_to_user(&pgdir[0], &pgd, sizeof(pgd)) != 0)
return -EFAULT;
- if (copy_to_user(&pgdir[3], &pgd, sizeof(pgd)) != 0)
+ /*
+ * And the other PGD entry to make the linear mapping at PAGE_OFFSET
+ */
+ if (copy_to_user(&pgdir[KERNEL_PGD_BOUNDARY], &pgd, sizeof(pgd)))
return -EFAULT;
#else
+ /*
+ * The top level points to the linear page table pages above.
+ * We setup the identity and linear mappings here.
+ */
phys_linear = (unsigned long)linear - mem_base;
for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
pgd_t pgd;
+ /*
+ * Create a PGD entry which points to the right part of the
+ * linear PTE pages.
+ */
pgd = __pgd((phys_linear + i * sizeof(pte_t)) |
(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
+ /*
+ * Copy it into the PGD page at 0 and PAGE_OFFSET.
+ */
if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd))
|| copy_to_user(&pgdir[pgd_index(PAGE_OFFSET)
+ i / PTRS_PER_PTE],
@@ -880,15 +1026,19 @@ static unsigned long setup_pagetables(struct lguest *lg,
}
#endif
- /* We return the top level (guest-physical) address: remember where
- * this is. */
+ /*
+ * We return the top level (guest-physical) address: we remember where
+ * this is to write it into lguest_data when the Guest initializes.
+ */
return (unsigned long)pgdir - mem_base;
}
-/*H:500 (vii) Setting up the page tables initially.
+/*H:500
+ * (vii) Setting up the page tables initially.
*
* When a Guest is first created, the Launcher tells us where the toplevel of
- * its first page table is. We set some things up here: */
+ * its first page table is. We set some things up here:
+ */
int init_guest_pagetable(struct lguest *lg)
{
u64 mem;
@@ -898,21 +1048,27 @@ int init_guest_pagetable(struct lguest *lg)
pgd_t *pgd;
pmd_t *pmd_table;
#endif
- /* Get the Guest memory size and the ramdisk size from the boot header
- * located at lg->mem_base (Guest address 0). */
+ /*
+ * Get the Guest memory size and the ramdisk size from the boot header
+ * located at lg->mem_base (Guest address 0).
+ */
if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
|| get_user(initrd_size, &boot->hdr.ramdisk_size))
return -EFAULT;
- /* We start on the first shadow page table, and give it a blank PGD
- * page. */
+ /*
+ * We start on the first shadow page table, and give it a blank PGD
+ * page.
+ */
lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size);
if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir))
return lg->pgdirs[0].gpgdir;
lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
if (!lg->pgdirs[0].pgdir)
return -ENOMEM;
+
#ifdef CONFIG_X86_PAE
+ /* For PAE, we also create the initial mid-level. */
pgd = lg->pgdirs[0].pgdir;
pmd_table = (pmd_t *) get_zeroed_page(GFP_KERNEL);
if (!pmd_table)
@@ -921,27 +1077,33 @@ int init_guest_pagetable(struct lguest *lg)
set_pgd(pgd + SWITCHER_PGD_INDEX,
__pgd(__pa(pmd_table) | _PAGE_PRESENT));
#endif
+
+ /* This is the current page table. */
lg->cpus[0].cpu_pgd = 0;
return 0;
}
-/* When the Guest calls LHCALL_LGUEST_INIT we do more setup. */
+/*H:508 When the Guest calls LHCALL_LGUEST_INIT we do more setup. */
void page_table_guest_data_init(struct lg_cpu *cpu)
{
/* We get the kernel address: above this is all kernel memory. */
if (get_user(cpu->lg->kernel_address,
&cpu->lg->lguest_data->kernel_address)
- /* We tell the Guest that it can't use the top 2 or 4 MB
- * of virtual addresses used by the Switcher. */
+ /*
+ * We tell the Guest that it can't use the top 2 or 4 MB
+ * of virtual addresses used by the Switcher.
+ */
|| put_user(RESERVE_MEM * 1024 * 1024,
&cpu->lg->lguest_data->reserve_mem)
|| put_user(cpu->lg->pgdirs[0].gpgdir,
&cpu->lg->lguest_data->pgdir))
kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
- /* In flush_user_mappings() we loop from 0 to
+ /*
+ * In flush_user_mappings() we loop from 0 to
* "pgd_index(lg->kernel_address)". This assumes it won't hit the
- * Switcher mappings, so check that now. */
+ * Switcher mappings, so check that now.
+ */
#ifdef CONFIG_X86_PAE
if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX &&
pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX)
@@ -964,50 +1126,56 @@ void free_guest_pagetable(struct lguest *lg)
free_page((long)lg->pgdirs[i].pgdir);
}
-/*H:480 (vi) Mapping the Switcher when the Guest is about to run.
+/*H:480
+ * (vi) Mapping the Switcher when the Guest is about to run.
*
* The Switcher and the two pages for this CPU need to be visible in the
* Guest (and not the pages for other CPUs). We have the appropriate PTE pages
* for each CPU already set up, we just need to hook them in now we know which
- * Guest is about to run on this CPU. */
+ * Guest is about to run on this CPU.
+ */
void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
{
pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
pte_t regs_pte;
- unsigned long pfn;
#ifdef CONFIG_X86_PAE
pmd_t switcher_pmd;
pmd_t *pmd_table;
- native_set_pmd(&switcher_pmd, pfn_pmd(__pa(switcher_pte_page) >>
- PAGE_SHIFT, PAGE_KERNEL_EXEC));
+ switcher_pmd = pfn_pmd(__pa(switcher_pte_page) >> PAGE_SHIFT,
+ PAGE_KERNEL_EXEC);
+ /* Figure out where the pmd page is, by reading the PGD, and converting
+ * it to a virtual address. */
pmd_table = __va(pgd_pfn(cpu->lg->
pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX])
<< PAGE_SHIFT);
- native_set_pmd(&pmd_table[SWITCHER_PMD_INDEX], switcher_pmd);
+ /* Now write it into the shadow page table. */
+ set_pmd(&pmd_table[SWITCHER_PMD_INDEX], switcher_pmd);
#else
pgd_t switcher_pgd;
- /* Make the last PGD entry for this Guest point to the Switcher's PTE
- * page for this CPU (with appropriate flags). */
+ /*
+ * Make the last PGD entry for this Guest point to the Switcher's PTE
+ * page for this CPU (with appropriate flags).
+ */
switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL_EXEC);
cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
#endif
- /* We also change the Switcher PTE page. When we're running the Guest,
+ /*
+ * We also change the Switcher PTE page. When we're running the Guest,
* we want the Guest's "regs" page to appear where the first Switcher
* page for this CPU is. This is an optimization: when the Switcher
* saves the Guest registers, it saves them into the first page of this
* CPU's "struct lguest_pages": if we make sure the Guest's register
* page is already mapped there, we don't have to copy them out
- * again. */
- pfn = __pa(cpu->regs_page) >> PAGE_SHIFT;
- native_set_pte(&regs_pte, pfn_pte(pfn, PAGE_KERNEL));
- native_set_pte(&switcher_pte_page[pte_index((unsigned long)pages)],
- regs_pte);
+ * again.
+ */
+ regs_pte = pfn_pte(__pa(cpu->regs_page) >> PAGE_SHIFT, PAGE_KERNEL);
+ set_pte(&switcher_pte_page[pte_index((unsigned long)pages)], regs_pte);
}
/*:*/
@@ -1019,10 +1187,12 @@ static void free_switcher_pte_pages(void)
free_page((long)switcher_pte_page(i));
}
-/*H:520 Setting up the Switcher PTE page for given CPU is fairly easy, given
+/*H:520
+ * Setting up the Switcher PTE page for given CPU is fairly easy, given
* the CPU number and the "struct page"s for the Switcher code itself.
*
- * Currently the Switcher is less than a page long, so "pages" is always 1. */
+ * Currently the Switcher is less than a page long, so "pages" is always 1.
+ */
static __init void populate_switcher_pte_page(unsigned int cpu,
struct page *switcher_page[],
unsigned int pages)
@@ -1032,7 +1202,7 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
/* The first entries are easy: they map the Switcher code. */
for (i = 0; i < pages; i++) {
- native_set_pte(&pte[i], mk_pte(switcher_page[i],
+ set_pte(&pte[i], mk_pte(switcher_page[i],
__pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
}
@@ -1040,16 +1210,19 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
i = pages + cpu*2;
/* First page (Guest registers) is writable from the Guest */
- native_set_pte(&pte[i], pfn_pte(page_to_pfn(switcher_page[i]),
+ set_pte(&pte[i], pfn_pte(page_to_pfn(switcher_page[i]),
__pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW)));
- /* The second page contains the "struct lguest_ro_state", and is
- * read-only. */
- native_set_pte(&pte[i+1], pfn_pte(page_to_pfn(switcher_page[i+1]),
+ /*
+ * The second page contains the "struct lguest_ro_state", and is
+ * read-only.
+ */
+ set_pte(&pte[i+1], pfn_pte(page_to_pfn(switcher_page[i+1]),
__pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
}
-/* We've made it through the page table code. Perhaps our tired brains are
+/*
+ * We've made it through the page table code. Perhaps our tired brains are
* still processing the details, or perhaps we're simply glad it's over.
*
* If nothing else, note that all this complexity in juggling shadow page tables
@@ -1058,10 +1231,13 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
* uses exotic direct Guest pagetable manipulation, and why both Intel and AMD
* have implemented shadow page table support directly into hardware.
*
- * There is just one file remaining in the Host. */
+ * There is just one file remaining in the Host.
+ */
-/*H:510 At boot or module load time, init_pagetables() allocates and populates
- * the Switcher PTE page for each CPU. */
+/*H:510
+ * At boot or module load time, init_pagetables() allocates and populates
+ * the Switcher PTE page for each CPU.
+ */
__init int init_pagetables(struct page **switcher_page, unsigned int pages)
{
unsigned int i;
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
index 482ed5a18750..951c57b0a7e0 100644
--- a/drivers/lguest/segments.c
+++ b/drivers/lguest/segments.c
@@ -1,4 +1,5 @@
-/*P:600 The x86 architecture has segments, which involve a table of descriptors
+/*P:600
+ * The x86 architecture has segments, which involve a table of descriptors
* which can be used to do funky things with virtual address interpretation.
* We originally used to use segments so the Guest couldn't alter the
* Guest<->Host Switcher, and then we had to trim Guest segments, and restore
@@ -8,7 +9,8 @@
*
* In these modern times, the segment handling code consists of simple sanity
* checks, and the worst you'll experience reading this code is butterfly-rash
- * from frolicking through its parklike serenity. :*/
+ * from frolicking through its parklike serenity.
+:*/
#include "lg.h"
/*H:600
@@ -41,10 +43,12 @@
* begin.
*/
-/* There are several entries we don't let the Guest set. The TSS entry is the
+/*
+ * There are several entries we don't let the Guest set. The TSS entry is the
* "Task State Segment" which controls all kinds of delicate things. The
* LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
- * the Guest can't be trusted to deal with double faults. */
+ * the Guest can't be trusted to deal with double faults.
+ */
static bool ignored_gdt(unsigned int num)
{
return (num == GDT_ENTRY_TSS
@@ -53,42 +57,52 @@ static bool ignored_gdt(unsigned int num)
|| num == GDT_ENTRY_DOUBLEFAULT_TSS);
}
-/*H:630 Once the Guest gave us new GDT entries, we fix them up a little. We
+/*H:630
+ * Once the Guest gave us new GDT entries, we fix them up a little. We
* don't care if they're invalid: the worst that can happen is a General
* Protection Fault in the Switcher when it restores a Guest segment register
* which tries to use that entry. Then we kill the Guest for causing such a
- * mess: the message will be "unhandled trap 256". */
+ * mess: the message will be "unhandled trap 256".
+ */
static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
{
unsigned int i;
for (i = start; i < end; i++) {
- /* We never copy these ones to real GDT, so we don't care what
- * they say */
+ /*
+ * We never copy these ones to real GDT, so we don't care what
+ * they say
+ */
if (ignored_gdt(i))
continue;
- /* Segment descriptors contain a privilege level: the Guest is
+ /*
+ * Segment descriptors contain a privilege level: the Guest is
* sometimes careless and leaves this as 0, even though it's
- * running at privilege level 1. If so, we fix it here. */
+ * running at privilege level 1. If so, we fix it here.
+ */
if ((cpu->arch.gdt[i].b & 0x00006000) == 0)
cpu->arch.gdt[i].b |= (GUEST_PL << 13);
- /* Each descriptor has an "accessed" bit. If we don't set it
+ /*
+ * Each descriptor has an "accessed" bit. If we don't set it
* now, the CPU will try to set it when the Guest first loads
* that entry into a segment register. But the GDT isn't
- * writable by the Guest, so bad things can happen. */
+ * writable by the Guest, so bad things can happen.
+ */
cpu->arch.gdt[i].b |= 0x00000100;
}
}
-/*H:610 Like the IDT, we never simply use the GDT the Guest gives us. We keep
+/*H:610
+ * Like the IDT, we never simply use the GDT the Guest gives us. We keep
* a GDT for each CPU, and copy across the Guest's entries each time we want to
* run the Guest on that CPU.
*
* This routine is called at boot or modprobe time for each CPU to set up the
* constant GDT entries: the ones which are the same no matter what Guest we're
- * running. */
+ * running.
+ */
void setup_default_gdt_entries(struct lguest_ro_state *state)
{
struct desc_struct *gdt = state->guest_gdt;
@@ -98,30 +112,37 @@ void setup_default_gdt_entries(struct lguest_ro_state *state)
gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
- /* The TSS segment refers to the TSS entry for this particular CPU.
+ /*
+ * The TSS segment refers to the TSS entry for this particular CPU.
* Forgive the magic flags: the 0x8900 means the entry is Present, it's
* privilege level 0 Available 386 TSS system segment, and the 0x67
- * means Saturn is eclipsed by Mercury in the twelfth house. */
+ * means Saturn is eclipsed by Mercury in the twelfth house.
+ */
gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
| ((tss >> 16) & 0x000000FF);
}
-/* This routine sets up the initial Guest GDT for booting. All entries start
- * as 0 (unusable). */
+/*
+ * This routine sets up the initial Guest GDT for booting. All entries start
+ * as 0 (unusable).
+ */
void setup_guest_gdt(struct lg_cpu *cpu)
{
- /* Start with full 0-4G segments... */
+ /*
+ * Start with full 0-4G segments...except the Guest is allowed to use
+ * them, so set the privilege level appropriately in the flags.
+ */
cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
- /* ...except the Guest is allowed to use them, so set the privilege
- * level appropriately in the flags. */
cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
}
-/*H:650 An optimization of copy_gdt(), for just the three "thead-local storage"
- * entries. */
+/*H:650
+ * An optimization of copy_gdt(), for just the three "thead-local storage"
+ * entries.
+ */
void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt)
{
unsigned int i;
@@ -130,26 +151,34 @@ void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt)
gdt[i] = cpu->arch.gdt[i];
}
-/*H:640 When the Guest is run on a different CPU, or the GDT entries have
- * changed, copy_gdt() is called to copy the Guest's GDT entries across to this
- * CPU's GDT. */
+/*H:640
+ * When the Guest is run on a different CPU, or the GDT entries have changed,
+ * copy_gdt() is called to copy the Guest's GDT entries across to this CPU's
+ * GDT.
+ */
void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt)
{
unsigned int i;
- /* The default entries from setup_default_gdt_entries() are not
- * replaced. See ignored_gdt() above. */
+ /*
+ * The default entries from setup_default_gdt_entries() are not
+ * replaced. See ignored_gdt() above.
+ */
for (i = 0; i < GDT_ENTRIES; i++)
if (!ignored_gdt(i))
gdt[i] = cpu->arch.gdt[i];
}
-/*H:620 This is where the Guest asks us to load a new GDT entry
- * (LHCALL_LOAD_GDT_ENTRY). We tweak the entry and copy it in. */
+/*H:620
+ * This is where the Guest asks us to load a new GDT entry
+ * (LHCALL_LOAD_GDT_ENTRY). We tweak the entry and copy it in.
+ */
void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi)
{
- /* We assume the Guest has the same number of GDT entries as the
- * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
+ /*
+ * We assume the Guest has the same number of GDT entries as the
+ * Host, otherwise we'd have to dynamically allocate the Guest GDT.
+ */
if (num >= ARRAY_SIZE(cpu->arch.gdt))
kill_guest(cpu, "too many gdt entries %i", num);
@@ -157,15 +186,19 @@ void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi)
cpu->arch.gdt[num].a = lo;
cpu->arch.gdt[num].b = hi;
fixup_gdt_table(cpu, num, num+1);
- /* Mark that the GDT changed so the core knows it has to copy it again,
- * even if the Guest is run on the same CPU. */
+ /*
+ * Mark that the GDT changed so the core knows it has to copy it again,
+ * even if the Guest is run on the same CPU.
+ */
cpu->changed |= CHANGED_GDT;
}
-/* This is the fast-track version for just changing the three TLS entries.
+/*
+ * This is the fast-track version for just changing the three TLS entries.
* Remember that this happens on every context switch, so it's worth
* optimizing. But wouldn't it be neater to have a single hypercall to cover
- * both cases? */
+ * both cases?
+ */
void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls)
{
struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN];
@@ -175,7 +208,6 @@ void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls)
/* Note that just the TLS entries have changed. */
cpu->changed |= CHANGED_GDT_TLS;
}
-/*:*/
/*H:660
* With this, we have finished the Host.
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index eaf722fe309a..6ae388849a3b 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -17,13 +17,15 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*P:450 This file contains the x86-specific lguest code. It used to be all
+/*P:450
+ * This file contains the x86-specific lguest code. It used to be all
* mixed in with drivers/lguest/core.c but several foolhardy code slashers
* wrestled most of the dependencies out to here in preparation for porting
* lguest to other architectures (see what I mean by foolhardy?).
*
* This also contains a couple of non-obvious setup and teardown pieces which
- * were implemented after days of debugging pain. :*/
+ * were implemented after days of debugging pain.
+:*/
#include <linux/kernel.h>
#include <linux/start_kernel.h>
#include <linux/string.h>
@@ -82,25 +84,33 @@ static DEFINE_PER_CPU(struct lg_cpu *, last_cpu);
*/
static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
{
- /* Copying all this data can be quite expensive. We usually run the
+ /*
+ * Copying all this data can be quite expensive. We usually run the
* same Guest we ran last time (and that Guest hasn't run anywhere else
* meanwhile). If that's not the case, we pretend everything in the
- * Guest has changed. */
+ * Guest has changed.
+ */
if (__get_cpu_var(last_cpu) != cpu || cpu->last_pages != pages) {
__get_cpu_var(last_cpu) = cpu;
cpu->last_pages = pages;
cpu->changed = CHANGED_ALL;
}
- /* These copies are pretty cheap, so we do them unconditionally: */
- /* Save the current Host top-level page directory. */
+ /*
+ * These copies are pretty cheap, so we do them unconditionally: */
+ /* Save the current Host top-level page directory.
+ */
pages->state.host_cr3 = __pa(current->mm->pgd);
- /* Set up the Guest's page tables to see this CPU's pages (and no
- * other CPU's pages). */
+ /*
+ * Set up the Guest's page tables to see this CPU's pages (and no
+ * other CPU's pages).
+ */
map_switcher_in_guest(cpu, pages);
- /* Set up the two "TSS" members which tell the CPU what stack to use
+ /*
+ * Set up the two "TSS" members which tell the CPU what stack to use
* for traps which do directly into the Guest (ie. traps at privilege
- * level 1). */
+ * level 1).
+ */
pages->state.guest_tss.sp1 = cpu->esp1;
pages->state.guest_tss.ss1 = cpu->ss1;
@@ -125,97 +135,126 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
/* This is a dummy value we need for GCC's sake. */
unsigned int clobber;
- /* Copy the guest-specific information into this CPU's "struct
- * lguest_pages". */
+ /*
+ * Copy the guest-specific information into this CPU's "struct
+ * lguest_pages".
+ */
copy_in_guest_info(cpu, pages);
- /* Set the trap number to 256 (impossible value). If we fault while
+ /*
+ * Set the trap number to 256 (impossible value). If we fault while
* switching to the Guest (bad segment registers or bug), this will
- * cause us to abort the Guest. */
+ * cause us to abort the Guest.
+ */
cpu->regs->trapnum = 256;
- /* Now: we push the "eflags" register on the stack, then do an "lcall".
+ /*
+ * Now: we push the "eflags" register on the stack, then do an "lcall".
* This is how we change from using the kernel code segment to using
* the dedicated lguest code segment, as well as jumping into the
* Switcher.
*
* The lcall also pushes the old code segment (KERNEL_CS) onto the
* stack, then the address of this call. This stack layout happens to
- * exactly match the stack layout created by an interrupt... */
+ * exactly match the stack layout created by an interrupt...
+ */
asm volatile("pushf; lcall *lguest_entry"
- /* This is how we tell GCC that %eax ("a") and %ebx ("b")
- * are changed by this routine. The "=" means output. */
+ /*
+ * This is how we tell GCC that %eax ("a") and %ebx ("b")
+ * are changed by this routine. The "=" means output.
+ */
: "=a"(clobber), "=b"(clobber)
- /* %eax contains the pages pointer. ("0" refers to the
+ /*
+ * %eax contains the pages pointer. ("0" refers to the
* 0-th argument above, ie "a"). %ebx contains the
* physical address of the Guest's top-level page
- * directory. */
+ * directory.
+ */
: "0"(pages), "1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir))
- /* We tell gcc that all these registers could change,
+ /*
+ * We tell gcc that all these registers could change,
* which means we don't have to save and restore them in
- * the Switcher. */
+ * the Switcher.
+ */
: "memory", "%edx", "%ecx", "%edi", "%esi");
}
/*:*/
-/*M:002 There are hooks in the scheduler which we can register to tell when we
+/*M:002
+ * There are hooks in the scheduler which we can register to tell when we
* get kicked off the CPU (preempt_notifier_register()). This would allow us
* to lazily disable SYSENTER which would regain some performance, and should
* also simplify copy_in_guest_info(). Note that we'd still need to restore
* things when we exit to Launcher userspace, but that's fairly easy.
*
- * We could also try using this hooks for PGE, but that might be too expensive.
+ * We could also try using these hooks for PGE, but that might be too expensive.
*
- * The hooks were designed for KVM, but we can also put them to good use. :*/
+ * The hooks were designed for KVM, but we can also put them to good use.
+:*/
-/*H:040 This is the i386-specific code to setup and run the Guest. Interrupts
- * are disabled: we own the CPU. */
+/*H:040
+ * This is the i386-specific code to setup and run the Guest. Interrupts
+ * are disabled: we own the CPU.
+ */
void lguest_arch_run_guest(struct lg_cpu *cpu)
{
- /* Remember the awfully-named TS bit? If the Guest has asked to set it
+ /*
+ * Remember the awfully-named TS bit? If the Guest has asked to set it
* we set it now, so we can trap and pass that trap to the Guest if it
- * uses the FPU. */
+ * uses the FPU.
+ */
if (cpu->ts)
unlazy_fpu(current);
- /* SYSENTER is an optimized way of doing system calls. We can't allow
+ /*
+ * SYSENTER is an optimized way of doing system calls. We can't allow
* it because it always jumps to privilege level 0. A normal Guest
* won't try it because we don't advertise it in CPUID, but a malicious
* Guest (or malicious Guest userspace program) could, so we tell the
- * CPU to disable it before running the Guest. */
+ * CPU to disable it before running the Guest.
+ */
if (boot_cpu_has(X86_FEATURE_SEP))
wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
- /* Now we actually run the Guest. It will return when something
+ /*
+ * Now we actually run the Guest. It will return when something
* interesting happens, and we can examine its registers to see what it
- * was doing. */
+ * was doing.
+ */
run_guest_once(cpu, lguest_pages(raw_smp_processor_id()));
- /* Note that the "regs" structure contains two extra entries which are
+ /*
+ * Note that the "regs" structure contains two extra entries which are
* not really registers: a trap number which says what interrupt or
* trap made the switcher code come back, and an error code which some
- * traps set. */
+ * traps set.
+ */
/* Restore SYSENTER if it's supposed to be on. */
if (boot_cpu_has(X86_FEATURE_SEP))
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
- /* If the Guest page faulted, then the cr2 register will tell us the
+ /*
+ * If the Guest page faulted, then the cr2 register will tell us the
* bad virtual address. We have to grab this now, because once we
* re-enable interrupts an interrupt could fault and thus overwrite
- * cr2, or we could even move off to a different CPU. */
+ * cr2, or we could even move off to a different CPU.
+ */
if (cpu->regs->trapnum == 14)
cpu->arch.last_pagefault = read_cr2();
- /* Similarly, if we took a trap because the Guest used the FPU,
+ /*
+ * Similarly, if we took a trap because the Guest used the FPU,
* we have to restore the FPU it expects to see.
* math_state_restore() may sleep and we may even move off to
* a different CPU. So all the critical stuff should be done
- * before this. */
+ * before this.
+ */
else if (cpu->regs->trapnum == 7)
math_state_restore();
}
-/*H:130 Now we've examined the hypercall code; our Guest can make requests.
+/*H:130
+ * Now we've examined the hypercall code; our Guest can make requests.
* Our Guest is usually so well behaved; it never tries to do things it isn't
* allowed to, and uses hypercalls instead. Unfortunately, Linux's paravirtual
* infrastructure isn't quite complete, because it doesn't contain replacements
@@ -225,26 +264,33 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
*
* When the Guest uses one of these instructions, we get a trap (General
* Protection Fault) and come here. We see if it's one of those troublesome
- * instructions and skip over it. We return true if we did. */
+ * instructions and skip over it. We return true if we did.
+ */
static int emulate_insn(struct lg_cpu *cpu)
{
u8 insn;
unsigned int insnlen = 0, in = 0, shift = 0;
- /* The eip contains the *virtual* address of the Guest's instruction:
- * guest_pa just subtracts the Guest's page_offset. */
+ /*
+ * The eip contains the *virtual* address of the Guest's instruction:
+ * guest_pa just subtracts the Guest's page_offset.
+ */
unsigned long physaddr = guest_pa(cpu, cpu->regs->eip);
- /* This must be the Guest kernel trying to do something, not userspace!
+ /*
+ * This must be the Guest kernel trying to do something, not userspace!
* The bottom two bits of the CS segment register are the privilege
- * level. */
+ * level.
+ */
if ((cpu->regs->cs & 3) != GUEST_PL)
return 0;
/* Decoding x86 instructions is icky. */
insn = lgread(cpu, physaddr, u8);
- /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
- of the eax register. */
+ /*
+ * 0x66 is an "operand prefix". It means it's using the upper 16 bits
+ * of the eax register.
+ */
if (insn == 0x66) {
shift = 16;
/* The instruction is 1 byte so far, read the next byte. */
@@ -252,8 +298,10 @@ static int emulate_insn(struct lg_cpu *cpu)
insn = lgread(cpu, physaddr + insnlen, u8);
}
- /* We can ignore the lower bit for the moment and decode the 4 opcodes
- * we need to emulate. */
+ /*
+ * We can ignore the lower bit for the moment and decode the 4 opcodes
+ * we need to emulate.
+ */
switch (insn & 0xFE) {
case 0xE4: /* in <next byte>,%al */
insnlen += 2;
@@ -274,9 +322,11 @@ static int emulate_insn(struct lg_cpu *cpu)
return 0;
}
- /* If it was an "IN" instruction, they expect the result to be read
+ /*
+ * If it was an "IN" instruction, they expect the result to be read
* into %eax, so we change %eax. We always return all-ones, which
- * traditionally means "there's nothing there". */
+ * traditionally means "there's nothing there".
+ */
if (in) {
/* Lower bit tells is whether it's a 16 or 32 bit access */
if (insn & 0x1)
@@ -290,7 +340,8 @@ static int emulate_insn(struct lg_cpu *cpu)
return 1;
}
-/* Our hypercalls mechanism used to be based on direct software interrupts.
+/*
+ * Our hypercalls mechanism used to be based on direct software interrupts.
* After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to
* change over to using kvm hypercalls.
*
@@ -318,16 +369,20 @@ static int emulate_insn(struct lg_cpu *cpu)
*/
static void rewrite_hypercall(struct lg_cpu *cpu)
{
- /* This are the opcodes we use to patch the Guest. The opcode for "int
+ /*
+ * This are the opcodes we use to patch the Guest. The opcode for "int
* $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we
- * complete the sequence with a NOP (0x90). */
+ * complete the sequence with a NOP (0x90).
+ */
u8 insn[3] = {0xcd, 0x1f, 0x90};
__lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn));
- /* The above write might have caused a copy of that page to be made
+ /*
+ * The above write might have caused a copy of that page to be made
* (if it was read-only). We need to make sure the Guest has
* up-to-date pagetables. As this doesn't happen often, we can just
- * drop them all. */
+ * drop them all.
+ */
guest_pagetable_clear_all(cpu);
}
@@ -335,9 +390,11 @@ static bool is_hypercall(struct lg_cpu *cpu)
{
u8 insn[3];
- /* This must be the Guest kernel trying to do something.
+ /*
+ * This must be the Guest kernel trying to do something.
* The bottom two bits of the CS segment register are the privilege
- * level. */
+ * level.
+ */
if ((cpu->regs->cs & 3) != GUEST_PL)
return false;
@@ -351,86 +408,105 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
{
switch (cpu->regs->trapnum) {
case 13: /* We've intercepted a General Protection Fault. */
- /* Check if this was one of those annoying IN or OUT
+ /*
+ * Check if this was one of those annoying IN or OUT
* instructions which we need to emulate. If so, we just go
- * back into the Guest after we've done it. */
+ * back into the Guest after we've done it.
+ */
if (cpu->regs->errcode == 0) {
if (emulate_insn(cpu))
return;
}
- /* If KVM is active, the vmcall instruction triggers a
- * General Protection Fault. Normally it triggers an
- * invalid opcode fault (6): */
+ /*
+ * If KVM is active, the vmcall instruction triggers a General
+ * Protection Fault. Normally it triggers an invalid opcode
+ * fault (6):
+ */
case 6:
- /* We need to check if ring == GUEST_PL and
- * faulting instruction == vmcall. */
+ /*
+ * We need to check if ring == GUEST_PL and faulting
+ * instruction == vmcall.
+ */
if (is_hypercall(cpu)) {
rewrite_hypercall(cpu);
return;
}
break;
case 14: /* We've intercepted a Page Fault. */
- /* The Guest accessed a virtual address that wasn't mapped.
+ /*
+ * The Guest accessed a virtual address that wasn't mapped.
* This happens a lot: we don't actually set up most of the page
* tables for the Guest at all when we start: as it runs it asks
* for more and more, and we set them up as required. In this
* case, we don't even tell the Guest that the fault happened.
*
* The errcode tells whether this was a read or a write, and
- * whether kernel or userspace code. */
+ * whether kernel or userspace code.
+ */
if (demand_page(cpu, cpu->arch.last_pagefault,
cpu->regs->errcode))
return;
- /* OK, it's really not there (or not OK): the Guest needs to
+ /*
+ * OK, it's really not there (or not OK): the Guest needs to
* know. We write out the cr2 value so it knows where the
* fault occurred.
*
* Note that if the Guest were really messed up, this could
* happen before it's done the LHCALL_LGUEST_INIT hypercall, so
- * lg->lguest_data could be NULL */
+ * lg->lguest_data could be NULL
+ */
if (cpu->lg->lguest_data &&
put_user(cpu->arch.last_pagefault,
&cpu->lg->lguest_data->cr2))
kill_guest(cpu, "Writing cr2");
break;
case 7: /* We've intercepted a Device Not Available fault. */
- /* If the Guest doesn't want to know, we already restored the
- * Floating Point Unit, so we just continue without telling
- * it. */
+ /*
+ * If the Guest doesn't want to know, we already restored the
+ * Floating Point Unit, so we just continue without telling it.
+ */
if (!cpu->ts)
return;
break;
case 32 ... 255:
- /* These values mean a real interrupt occurred, in which case
+ /*
+ * These values mean a real interrupt occurred, in which case
* the Host handler has already been run. We just do a
* friendly check if another process should now be run, then
- * return to run the Guest again */
+ * return to run the Guest again
+ */
cond_resched();
return;
case LGUEST_TRAP_ENTRY:
- /* Our 'struct hcall_args' maps directly over our regs: we set
- * up the pointer now to indicate a hypercall is pending. */
+ /*
+ * Our 'struct hcall_args' maps directly over our regs: we set
+ * up the pointer now to indicate a hypercall is pending.
+ */
cpu->hcall = (struct hcall_args *)cpu->regs;
return;
}
/* We didn't handle the trap, so it needs to go to the Guest. */
if (!deliver_trap(cpu, cpu->regs->trapnum))
- /* If the Guest doesn't have a handler (either it hasn't
+ /*
+ * If the Guest doesn't have a handler (either it hasn't
* registered any yet, or it's one of the faults we don't let
- * it handle), it dies with this cryptic error message. */
+ * it handle), it dies with this cryptic error message.
+ */
kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)",
cpu->regs->trapnum, cpu->regs->eip,
cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault
: cpu->regs->errcode);
}
-/* Now we can look at each of the routines this calls, in increasing order of
+/*
+ * Now we can look at each of the routines this calls, in increasing order of
* complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
* deliver_trap() and demand_page(). After all those, we'll be ready to
* examine the Switcher, and our philosophical understanding of the Host/Guest
- * duality will be complete. :*/
+ * duality will be complete.
+:*/
static void adjust_pge(void *on)
{
if (on)
@@ -439,13 +515,16 @@ static void adjust_pge(void *on)
write_cr4(read_cr4() & ~X86_CR4_PGE);
}
-/*H:020 Now the Switcher is mapped and every thing else is ready, we need to do
- * some more i386-specific initialization. */
+/*H:020
+ * Now the Switcher is mapped and every thing else is ready, we need to do
+ * some more i386-specific initialization.
+ */
void __init lguest_arch_host_init(void)
{
int i;
- /* Most of the i386/switcher.S doesn't care that it's been moved; on
+ /*
+ * Most of the i386/switcher.S doesn't care that it's been moved; on
* Intel, jumps are relative, and it doesn't access any references to
* external code or data.
*
@@ -453,7 +532,8 @@ void __init lguest_arch_host_init(void)
* addresses are placed in a table (default_idt_entries), so we need to
* update the table with the new addresses. switcher_offset() is a
* convenience function which returns the distance between the
- * compiled-in switcher code and the high-mapped copy we just made. */
+ * compiled-in switcher code and the high-mapped copy we just made.
+ */
for (i = 0; i < IDT_ENTRIES; i++)
default_idt_entries[i] += switcher_offset();
@@ -468,63 +548,81 @@ void __init lguest_arch_host_init(void)
for_each_possible_cpu(i) {
/* lguest_pages() returns this CPU's two pages. */
struct lguest_pages *pages = lguest_pages(i);
- /* This is a convenience pointer to make the code fit one
- * statement to a line. */
+ /* This is a convenience pointer to make the code neater. */
struct lguest_ro_state *state = &pages->state;
- /* The Global Descriptor Table: the Host has a different one
+ /*
+ * The Global Descriptor Table: the Host has a different one
* for each CPU. We keep a descriptor for the GDT which says
* where it is and how big it is (the size is actually the last
- * byte, not the size, hence the "-1"). */
+ * byte, not the size, hence the "-1").
+ */
state->host_gdt_desc.size = GDT_SIZE-1;
state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
- /* All CPUs on the Host use the same Interrupt Descriptor
+ /*
+ * All CPUs on the Host use the same Interrupt Descriptor
* Table, so we just use store_idt(), which gets this CPU's IDT
- * descriptor. */
+ * descriptor.
+ */
store_idt(&state->host_idt_desc);
- /* The descriptors for the Guest's GDT and IDT can be filled
+ /*
+ * The descriptors for the Guest's GDT and IDT can be filled
* out now, too. We copy the GDT & IDT into ->guest_gdt and
- * ->guest_idt before actually running the Guest. */
+ * ->guest_idt before actually running the Guest.
+ */
state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
state->guest_idt_desc.address = (long)&state->guest_idt;
state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
state->guest_gdt_desc.address = (long)&state->guest_gdt;
- /* We know where we want the stack to be when the Guest enters
+ /*
+ * We know where we want the stack to be when the Guest enters
* the Switcher: in pages->regs. The stack grows upwards, so
- * we start it at the end of that structure. */
+ * we start it at the end of that structure.
+ */
state->guest_tss.sp0 = (long)(&pages->regs + 1);
- /* And this is the GDT entry to use for the stack: we keep a
- * couple of special LGUEST entries. */
+ /*
+ * And this is the GDT entry to use for the stack: we keep a
+ * couple of special LGUEST entries.
+ */
state->guest_tss.ss0 = LGUEST_DS;
- /* x86 can have a finegrained bitmap which indicates what I/O
+ /*
+ * x86 can have a finegrained bitmap which indicates what I/O
* ports the process can use. We set it to the end of our
- * structure, meaning "none". */
+ * structure, meaning "none".
+ */
state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
- /* Some GDT entries are the same across all Guests, so we can
- * set them up now. */
+ /*
+ * Some GDT entries are the same across all Guests, so we can
+ * set them up now.
+ */
setup_default_gdt_entries(state);
/* Most IDT entries are the same for all Guests, too.*/
setup_default_idt_entries(state, default_idt_entries);
- /* The Host needs to be able to use the LGUEST segments on this
- * CPU, too, so put them in the Host GDT. */
+ /*
+ * The Host needs to be able to use the LGUEST segments on this
+ * CPU, too, so put them in the Host GDT.
+ */
get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
}
- /* In the Switcher, we want the %cs segment register to use the
+ /*
+ * In the Switcher, we want the %cs segment register to use the
* LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
* it will be undisturbed when we switch. To change %cs and jump we
- * need this structure to feed to Intel's "lcall" instruction. */
+ * need this structure to feed to Intel's "lcall" instruction.
+ */
lguest_entry.offset = (long)switch_to_guest + switcher_offset();
lguest_entry.segment = LGUEST_CS;
- /* Finally, we need to turn off "Page Global Enable". PGE is an
+ /*
+ * Finally, we need to turn off "Page Global Enable". PGE is an
* optimization where page table entries are specially marked to show
* they never change. The Host kernel marks all the kernel pages this
* way because it's always present, even when userspace is running.
@@ -534,16 +632,21 @@ void __init lguest_arch_host_init(void)
* you'll get really weird bugs that you'll chase for two days.
*
* I used to turn PGE off every time we switched to the Guest and back
- * on when we return, but that slowed the Switcher down noticibly. */
+ * on when we return, but that slowed the Switcher down noticibly.
+ */
- /* We don't need the complexity of CPUs coming and going while we're
- * doing this. */
+ /*
+ * We don't need the complexity of CPUs coming and going while we're
+ * doing this.
+ */
get_online_cpus();
if (cpu_has_pge) { /* We have a broader idea of "global". */
/* Remember that this was originally set (for cleanup). */
cpu_had_pge = 1;
- /* adjust_pge is a helper function which sets or unsets the PGE
- * bit on its CPU, depending on the argument (0 == unset). */
+ /*
+ * adjust_pge is a helper function which sets or unsets the PGE
+ * bit on its CPU, depending on the argument (0 == unset).
+ */
on_each_cpu(adjust_pge, (void *)0, 1);
/* Turn off the feature in the global feature set. */
clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE);
@@ -590,26 +693,32 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
{
u32 tsc_speed;
- /* The pointer to the Guest's "struct lguest_data" is the only argument.
- * We check that address now. */
+ /*
+ * The pointer to the Guest's "struct lguest_data" is the only argument.
+ * We check that address now.
+ */
if (!lguest_address_ok(cpu->lg, cpu->hcall->arg1,
sizeof(*cpu->lg->lguest_data)))
return -EFAULT;
- /* Having checked it, we simply set lg->lguest_data to point straight
+ /*
+ * Having checked it, we simply set lg->lguest_data to point straight
* into the Launcher's memory at the right place and then use
* copy_to_user/from_user from now on, instead of lgread/write. I put
* this in to show that I'm not immune to writing stupid
- * optimizations. */
+ * optimizations.
+ */
cpu->lg->lguest_data = cpu->lg->mem_base + cpu->hcall->arg1;
- /* We insist that the Time Stamp Counter exist and doesn't change with
+ /*
+ * We insist that the Time Stamp Counter exist and doesn't change with
* cpu frequency. Some devious chip manufacturers decided that TSC
* changes could be handled in software. I decided that time going
* backwards might be good for benchmarks, but it's bad for users.
*
* We also insist that the TSC be stable: the kernel detects unreliable
- * TSCs for its own purposes, and we use that here. */
+ * TSCs for its own purposes, and we use that here.
+ */
if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
tsc_speed = tsc_khz;
else
@@ -625,38 +734,47 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
}
/*:*/
-/*L:030 lguest_arch_setup_regs()
+/*L:030
+ * lguest_arch_setup_regs()
*
* Most of the Guest's registers are left alone: we used get_zeroed_page() to
- * allocate the structure, so they will be 0. */
+ * allocate the structure, so they will be 0.
+ */
void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start)
{
struct lguest_regs *regs = cpu->regs;
- /* There are four "segment" registers which the Guest needs to boot:
+ /*
+ * There are four "segment" registers which the Guest needs to boot:
* The "code segment" register (cs) refers to the kernel code segment
* __KERNEL_CS, and the "data", "extra" and "stack" segment registers
* refer to the kernel data segment __KERNEL_DS.
*
* The privilege level is packed into the lower bits. The Guest runs
- * at privilege level 1 (GUEST_PL).*/
+ * at privilege level 1 (GUEST_PL).
+ */
regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
regs->cs = __KERNEL_CS|GUEST_PL;
- /* The "eflags" register contains miscellaneous flags. Bit 1 (0x002)
+ /*
+ * The "eflags" register contains miscellaneous flags. Bit 1 (0x002)
* is supposed to always be "1". Bit 9 (0x200) controls whether
* interrupts are enabled. We always leave interrupts enabled while
- * running the Guest. */
+ * running the Guest.
+ */
regs->eflags = X86_EFLAGS_IF | 0x2;
- /* The "Extended Instruction Pointer" register says where the Guest is
- * running. */
+ /*
+ * The "Extended Instruction Pointer" register says where the Guest is
+ * running.
+ */
regs->eip = start;
- /* %esi points to our boot information, at physical address 0, so don't
- * touch it. */
+ /*
+ * %esi points to our boot information, at physical address 0, so don't
+ * touch it.
+ */
- /* There are a couple of GDT entries the Guest expects when first
- * booting. */
+ /* There are a couple of GDT entries the Guest expects at boot. */
setup_guest_gdt(cpu);
}
diff --git a/drivers/lguest/x86/switcher_32.S b/drivers/lguest/x86/switcher_32.S
index 3fc15318a80f..40634b0db9f7 100644
--- a/drivers/lguest/x86/switcher_32.S
+++ b/drivers/lguest/x86/switcher_32.S
@@ -1,12 +1,15 @@
-/*P:900 This is the Switcher: code which sits at 0xFFC00000 astride both the
- * Host and Guest to do the low-level Guest<->Host switch. It is as simple as
- * it can be made, but it's naturally very specific to x86.
+/*P:900
+ * This is the Switcher: code which sits at 0xFFC00000 (or 0xFFE00000) astride
+ * both the Host and Guest to do the low-level Guest<->Host switch. It is as
+ * simple as it can be made, but it's naturally very specific to x86.
*
* You have now completed Preparation. If this has whet your appetite; if you
* are feeling invigorated and refreshed then the next, more challenging stage
- * can be found in "make Guest". :*/
+ * can be found in "make Guest".
+ :*/
-/*M:012 Lguest is meant to be simple: my rule of thumb is that 1% more LOC must
+/*M:012
+ * Lguest is meant to be simple: my rule of thumb is that 1% more LOC must
* gain at least 1% more performance. Since neither LOC nor performance can be
* measured beforehand, it generally means implementing a feature then deciding
* if it's worth it. And once it's implemented, who can say no?
@@ -31,11 +34,14 @@
* Host (which is actually really easy).
*
* Two questions remain. Would the performance gain outweigh the complexity?
- * And who would write the verse documenting it? :*/
+ * And who would write the verse documenting it?
+:*/
-/*M:011 Lguest64 handles NMI. This gave me NMI envy (until I looked at their
+/*M:011
+ * Lguest64 handles NMI. This gave me NMI envy (until I looked at their
* code). It's worth doing though, since it would let us use oprofile in the
- * Host when a Guest is running. :*/
+ * Host when a Guest is running.
+:*/
/*S:100
* Welcome to the Switcher itself!
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 529e2ba505c3..ed1038164019 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1318,7 +1318,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
{
struct crypt_config *cc = ti->private;
- return fn(ti, cc->dev, cc->start, data);
+ return fn(ti, cc->dev, cc->start, ti->len, data);
}
static struct target_type crypt_target = {
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 4e5b843cd4d7..ebe7381f47c8 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -324,12 +324,12 @@ static int delay_iterate_devices(struct dm_target *ti,
struct delay_c *dc = ti->private;
int ret = 0;
- ret = fn(ti, dc->dev_read, dc->start_read, data);
+ ret = fn(ti, dc->dev_read, dc->start_read, ti->len, data);
if (ret)
goto out;
if (dc->dev_write)
- ret = fn(ti, dc->dev_write, dc->start_write, data);
+ ret = fn(ti, dc->dev_write, dc->start_write, ti->len, data);
out:
return ret;
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 9184b6deb868..82f7d6e6b1ea 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -139,7 +139,7 @@ static int linear_iterate_devices(struct dm_target *ti,
{
struct linear_c *lc = ti->private;
- return fn(ti, lc->dev, lc->start, data);
+ return fn(ti, lc->dev, lc->start, ti->len, data);
}
static struct target_type linear_target = {
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index c70604a20897..6f0d90d4a541 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1453,7 +1453,7 @@ static int multipath_iterate_devices(struct dm_target *ti,
list_for_each_entry(pg, &m->priority_groups, list) {
list_for_each_entry(p, &pg->pgpaths, list) {
- ret = fn(ti, p->path.dev, ti->begin, data);
+ ret = fn(ti, p->path.dev, ti->begin, ti->len, data);
if (ret)
goto out;
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ce8868c768cc..76811fd94e9e 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -638,6 +638,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
spin_lock_irq(&ms->lock);
bio_list_merge(&ms->writes, &requeue);
spin_unlock_irq(&ms->lock);
+ delayed_wake(ms);
}
/*
@@ -1122,7 +1123,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
if (error == -EOPNOTSUPP)
goto out;
- if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
+ if ((error == -EWOULDBLOCK) && bio_rw_flagged(bio, BIO_RW_AHEAD))
goto out;
if (unlikely(error)) {
@@ -1292,7 +1293,7 @@ static int mirror_iterate_devices(struct dm_target *ti,
for (i = 0; !ret && i < ms->nr_mirrors; i++)
ret = fn(ti, ms->mirror[i].dev,
- ms->mirror[i].offset, data);
+ ms->mirror[i].offset, ti->len, data);
return ret;
}
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index b240e85ae39a..5aa30d1b2d6e 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -285,7 +285,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio,
if (!error)
return 0; /* I/O complete */
- if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
+ if ((error == -EWOULDBLOCK) && bio_rw_flagged(bio, BIO_RW_AHEAD))
return error;
if (error == -EOPNOTSUPP)
@@ -320,10 +320,11 @@ static int stripe_iterate_devices(struct dm_target *ti,
int ret = 0;
unsigned i = 0;
- do
+ do {
ret = fn(ti, sc->stripe[i].dev,
- sc->stripe[i].physical_start, data);
- while (!ret && ++i < sc->stripes);
+ sc->stripe[i].physical_start,
+ sc->stripe_width, data);
+ } while (!ret && ++i < sc->stripes);
return ret;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 2cba557d9e61..d952b3441913 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -346,7 +346,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
* If possible, this checks an area of a destination device is valid.
*/
static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
- sector_t start, void *data)
+ sector_t start, sector_t len, void *data)
{
struct queue_limits *limits = data;
struct block_device *bdev = dev->bdev;
@@ -359,7 +359,7 @@ static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
if (!dev_size)
return 1;
- if ((start >= dev_size) || (start + ti->len > dev_size)) {
+ if ((start >= dev_size) || (start + len > dev_size)) {
DMWARN("%s: %s too small for target",
dm_device_name(ti->table->md), bdevname(bdev, b));
return 0;
@@ -377,11 +377,11 @@ static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev,
return 0;
}
- if (ti->len & (logical_block_size_sectors - 1)) {
+ if (len & (logical_block_size_sectors - 1)) {
DMWARN("%s: len=%llu not aligned to h/w "
"logical block size %hu of %s",
dm_device_name(ti->table->md),
- (unsigned long long)ti->len,
+ (unsigned long long)len,
limits->logical_block_size, bdevname(bdev, b));
return 0;
}
@@ -482,7 +482,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
- sector_t start, void *data)
+ sector_t start, sector_t len, void *data)
{
struct queue_limits *limits = data;
struct block_device *bdev = dev->bdev;
@@ -830,11 +830,6 @@ unsigned dm_table_get_type(struct dm_table *t)
return t->type;
}
-bool dm_table_bio_based(struct dm_table *t)
-{
- return dm_table_get_type(t) == DM_TYPE_BIO_BASED;
-}
-
bool dm_table_request_based(struct dm_table *t)
{
return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 9acd54a5cffb..82350f590d98 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -586,7 +586,7 @@ static void dec_pending(struct dm_io *io, int error)
*/
spin_lock_irqsave(&md->deferred_lock, flags);
if (__noflush_suspending(md)) {
- if (!bio_barrier(io->bio))
+ if (!bio_rw_flagged(io->bio, BIO_RW_BARRIER))
bio_list_add_head(&md->deferred,
io->bio);
} else
@@ -598,7 +598,7 @@ static void dec_pending(struct dm_io *io, int error)
io_error = io->error;
bio = io->bio;
- if (bio_barrier(bio)) {
+ if (bio_rw_flagged(bio, BIO_RW_BARRIER)) {
/*
* There can be just one barrier request so we use
* a per-device variable for error reporting.
@@ -1204,7 +1204,7 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
ci.map = dm_get_table(md);
if (unlikely(!ci.map)) {
- if (!bio_barrier(bio))
+ if (!bio_rw_flagged(bio, BIO_RW_BARRIER))
bio_io_error(bio);
else
if (!md->barrier_error)
@@ -1316,7 +1316,7 @@ static int _dm_request(struct request_queue *q, struct bio *bio)
* we have to queue this io for later.
*/
if (unlikely(test_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags)) ||
- unlikely(bio_barrier(bio))) {
+ unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
up_read(&md->io_lock);
if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) &&
@@ -1339,7 +1339,7 @@ static int dm_make_request(struct request_queue *q, struct bio *bio)
{
struct mapped_device *md = q->queuedata;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -2159,7 +2159,7 @@ static void dm_wq_work(struct work_struct *work)
if (dm_request_based(md))
generic_make_request(c);
else {
- if (bio_barrier(c))
+ if (bio_rw_flagged(c, BIO_RW_BARRIER))
process_barrier(md, c);
else
__split_and_process_bio(md, c);
@@ -2203,16 +2203,6 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
goto out;
}
- /*
- * It is enought that blk_queue_ordered() is called only once when
- * the first bio-based table is bound.
- *
- * This setting should be moved to alloc_dev() when request-based dm
- * supports barrier.
- */
- if (!md->map && dm_table_bio_based(table))
- blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
-
__unbind(md);
r = __bind(md, table, &limits);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 23278ae80f08..a7663eba17e2 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -61,7 +61,6 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits);
int dm_table_any_busy_target(struct dm_table *t);
int dm_table_set_type(struct dm_table *t);
unsigned dm_table_get_type(struct dm_table *t);
-bool dm_table_bio_based(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
int dm_table_alloc_md_mempools(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 5810fa906af0..ea4842905444 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -220,6 +220,7 @@ static int linear_run (mddev_t *mddev)
mddev->queue->unplug_fn = linear_unplug;
mddev->queue->backing_dev_info.congested_fn = linear_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
+ md_integrity_register(mddev);
return 0;
}
@@ -256,6 +257,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
rcu_assign_pointer(mddev->private, newconf);
md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
call_rcu(&oldconf->rcu, free_conf);
return 0;
}
@@ -286,7 +288,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
sector_t start_sector;
int cpu;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d4351ff0849f..5b98bea4ff9b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1308,7 +1308,12 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
}
if (mddev->level != LEVEL_MULTIPATH) {
int role;
- role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
+ if (rdev->desc_nr < 0 ||
+ rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
+ role = 0xffff;
+ rdev->desc_nr = -1;
+ } else
+ role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
break;
@@ -1394,8 +1399,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
if (rdev2->desc_nr+1 > max_dev)
max_dev = rdev2->desc_nr+1;
- if (max_dev > le32_to_cpu(sb->max_dev))
+ if (max_dev > le32_to_cpu(sb->max_dev)) {
+ int bmask;
sb->max_dev = cpu_to_le32(max_dev);
+ rdev->sb_size = max_dev * 2 + 256;
+ bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
+ if (rdev->sb_size & bmask)
+ rdev->sb_size = (rdev->sb_size | bmask) + 1;
+ }
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1487,37 +1498,76 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
static LIST_HEAD(pending_raid_disks);
-static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev)
+/*
+ * Try to register data integrity profile for an mddev
+ *
+ * This is called when an array is started and after a disk has been kicked
+ * from the array. It only succeeds if all working and active component devices
+ * are integrity capable with matching profiles.
+ */
+int md_integrity_register(mddev_t *mddev)
+{
+ mdk_rdev_t *rdev, *reference = NULL;
+
+ if (list_empty(&mddev->disks))
+ return 0; /* nothing to do */
+ if (blk_get_integrity(mddev->gendisk))
+ return 0; /* already registered */
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
+ /* skip spares and non-functional disks */
+ if (test_bit(Faulty, &rdev->flags))
+ continue;
+ if (rdev->raid_disk < 0)
+ continue;
+ /*
+ * If at least one rdev is not integrity capable, we can not
+ * enable data integrity for the md device.
+ */
+ if (!bdev_get_integrity(rdev->bdev))
+ return -EINVAL;
+ if (!reference) {
+ /* Use the first rdev as the reference */
+ reference = rdev;
+ continue;
+ }
+ /* does this rdev's profile match the reference profile? */
+ if (blk_integrity_compare(reference->bdev->bd_disk,
+ rdev->bdev->bd_disk) < 0)
+ return -EINVAL;
+ }
+ /*
+ * All component devices are integrity capable and have matching
+ * profiles, register the common profile for the md device.
+ */
+ if (blk_integrity_register(mddev->gendisk,
+ bdev_get_integrity(reference->bdev)) != 0) {
+ printk(KERN_ERR "md: failed to register integrity for %s\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ printk(KERN_NOTICE "md: data integrity on %s enabled\n",
+ mdname(mddev));
+ return 0;
+}
+EXPORT_SYMBOL(md_integrity_register);
+
+/* Disable data integrity if non-capable/non-matching disk is being added */
+void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
{
- struct mdk_personality *pers = mddev->pers;
- struct gendisk *disk = mddev->gendisk;
struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
- struct blk_integrity *bi_mddev = blk_get_integrity(disk);
+ struct blk_integrity *bi_mddev = blk_get_integrity(mddev->gendisk);
- /* Data integrity passthrough not supported on RAID 4, 5 and 6 */
- if (pers && pers->level >= 4 && pers->level <= 6)
+ if (!bi_mddev) /* nothing to do */
return;
-
- /* If rdev is integrity capable, register profile for mddev */
- if (!bi_mddev && bi_rdev) {
- if (blk_integrity_register(disk, bi_rdev))
- printk(KERN_ERR "%s: %s Could not register integrity!\n",
- __func__, disk->disk_name);
- else
- printk(KERN_NOTICE "Enabling data integrity on %s\n",
- disk->disk_name);
+ if (rdev->raid_disk < 0) /* skip spares */
return;
- }
-
- /* Check that mddev and rdev have matching profiles */
- if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) {
- printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__,
- disk->disk_name, rdev->bdev->bd_disk->disk_name);
- printk(KERN_NOTICE "Disabling data integrity on %s\n",
- disk->disk_name);
- blk_integrity_unregister(disk);
- }
+ if (bi_rdev && blk_integrity_compare(mddev->gendisk,
+ rdev->bdev->bd_disk) >= 0)
+ return;
+ printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
+ blk_integrity_unregister(mddev->gendisk);
}
+EXPORT_SYMBOL(md_integrity_add_rdev);
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
{
@@ -1591,7 +1641,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
/* May as well allow recovery to be retried once */
mddev->recovery_disabled = 0;
- md_integrity_check(rdev, mddev);
return 0;
fail:
@@ -2657,6 +2706,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
ssize_t rv = len;
struct mdk_personality *pers;
void *priv;
+ mdk_rdev_t *rdev;
if (mddev->pers == NULL) {
if (len == 0)
@@ -2736,6 +2786,12 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
mddev_suspend(mddev);
mddev->pers->stop(mddev);
module_put(mddev->pers->owner);
+ /* Invalidate devices that are now superfluous */
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ if (rdev->raid_disk >= mddev->raid_disks) {
+ rdev->raid_disk = -1;
+ clear_bit(In_sync, &rdev->flags);
+ }
mddev->pers = pers;
mddev->private = priv;
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
@@ -3685,17 +3741,8 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
mddev->array_sectors = sectors;
set_capacity(mddev->gendisk, mddev->array_sectors);
- if (mddev->pers) {
- struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
-
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
- }
+ if (mddev->pers)
+ revalidate_disk(mddev->gendisk);
return len;
}
@@ -4048,10 +4095,6 @@ static int do_md_run(mddev_t * mddev)
}
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
- if (pers->level >= 4 && pers->level <= 6)
- /* Cannot support integrity (yet) */
- blk_integrity_unregister(mddev->gendisk);
-
if (mddev->reshape_position != MaxSector &&
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
@@ -4189,6 +4232,7 @@ static int do_md_run(mddev_t * mddev)
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
+ revalidate_disk(mddev->gendisk);
mddev->changed = 1;
md_new_event(mddev);
sysfs_notify_dirent(mddev->sysfs_state);
@@ -5087,18 +5131,8 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
return -ENOSPC;
}
rv = mddev->pers->resize(mddev, num_sectors);
- if (!rv) {
- struct block_device *bdev;
-
- bdev = bdget_disk(mddev->gendisk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
- }
+ if (!rv)
+ revalidate_disk(mddev->gendisk);
return rv;
}
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 9430a110db93..24abefb0a926 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -201,7 +201,7 @@ struct mddev_s
* INTR: resync needs to be aborted for some reason
* DONE: thread is done and is waiting to be reaped
* REQUEST: user-space has requested a sync (used with SYNC)
- * CHECK: user-space request for for check-only, no repair
+ * CHECK: user-space request for check-only, no repair
* RESHAPE: A reshape is happening
*
* If neither SYNC or RESHAPE are set, then it is a recovery.
@@ -431,5 +431,7 @@ extern int md_allow_write(mddev_t *mddev);
extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(mddev_t *mddev);
+extern int md_integrity_register(mddev_t *mddev);
+void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
#endif /* _MD_MD_H */
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 237fe3fd235c..89e76819f61f 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -90,7 +90,7 @@ static void multipath_end_request(struct bio *bio, int error)
if (uptodate)
multipath_end_bh_io(mp_bh, 0);
- else if (!bio_rw_ahead(bio)) {
+ else if (!bio_rw_flagged(bio, BIO_RW_AHEAD)) {
/*
* oops, IO error:
*/
@@ -144,7 +144,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
const int rw = bio_data_dir(bio);
int cpu;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -313,6 +313,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
set_bit(In_sync, &rdev->flags);
rcu_assign_pointer(p->rdev, rdev);
err = 0;
+ md_integrity_add_rdev(rdev, mddev);
break;
}
@@ -345,7 +346,9 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -519,7 +522,7 @@ static int multipath_run (mddev_t *mddev)
mddev->queue->unplug_fn = multipath_unplug;
mddev->queue->backing_dev_info.congested_fn = multipath_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
-
+ md_integrity_register(mddev);
return 0;
out_free_conf:
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 335f490dcad6..f845ed98fec9 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -351,6 +351,7 @@ static int raid0_run(mddev_t *mddev)
blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
dump_zones(mddev);
+ md_integrity_register(mddev);
return 0;
}
@@ -447,7 +448,7 @@ static int raid0_make_request(struct request_queue *q, struct bio *bio)
const int rw = bio_data_dir(bio);
int cpu;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 0569efba0c02..ff7ed3335995 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -782,8 +782,9 @@ static int make_request(struct request_queue *q, struct bio * bio)
struct bio_list bl;
struct page **behind_pages = NULL;
const int rw = bio_data_dir(bio);
- const int do_sync = bio_sync(bio);
- int cpu, do_barriers;
+ const bool do_sync = bio_rw_flagged(bio, BIO_RW_SYNCIO);
+ int cpu;
+ bool do_barriers;
mdk_rdev_t *blocked_rdev;
/*
@@ -797,7 +798,8 @@ static int make_request(struct request_queue *q, struct bio * bio)
md_write_start(mddev, bio); /* wait on superblock update early */
- if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
+ if (unlikely(!mddev->barriers_work &&
+ bio_rw_flagged(bio, BIO_RW_BARRIER))) {
if (rw == WRITE)
md_write_end(mddev);
bio_endio(bio, -EOPNOTSUPP);
@@ -925,7 +927,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
atomic_set(&r1_bio->remaining, 0);
atomic_set(&r1_bio->behind_remaining, 0);
- do_barriers = bio_barrier(bio);
+ do_barriers = bio_rw_flagged(bio, BIO_RW_BARRIER);
if (do_barriers)
set_bit(R1BIO_Barrier, &r1_bio->state);
@@ -1144,7 +1146,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
rcu_assign_pointer(p->rdev, rdev);
break;
}
-
+ md_integrity_add_rdev(rdev, mddev);
print_conf(conf);
return err;
}
@@ -1178,7 +1180,9 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -1598,7 +1602,7 @@ static void raid1d(mddev_t *mddev)
* We already have a nr_pending reference on these rdevs.
*/
int i;
- const int do_sync = bio_sync(r1_bio->master_bio);
+ const bool do_sync = bio_rw_flagged(r1_bio->master_bio, BIO_RW_SYNCIO);
clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
clear_bit(R1BIO_Barrier, &r1_bio->state);
for (i=0; i < conf->raid_disks; i++)
@@ -1652,7 +1656,7 @@ static void raid1d(mddev_t *mddev)
(unsigned long long)r1_bio->sector);
raid_end_bio_io(r1_bio);
} else {
- const int do_sync = bio_sync(r1_bio->master_bio);
+ const bool do_sync = bio_rw_flagged(r1_bio->master_bio, BIO_RW_SYNCIO);
r1_bio->bios[r1_bio->read_disk] =
mddev->ro ? IO_BLOCKED : NULL;
r1_bio->read_disk = disk;
@@ -2067,7 +2071,7 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid1_unplug;
mddev->queue->backing_dev_info.congested_fn = raid1_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
-
+ md_integrity_register(mddev);
return 0;
out_no_mem:
@@ -2132,6 +2136,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
return -EINVAL;
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
+ revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->dev_sectors;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7298a5e5a183..d0a2152e064f 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -796,12 +796,12 @@ static int make_request(struct request_queue *q, struct bio * bio)
int i;
int chunk_sects = conf->chunk_mask + 1;
const int rw = bio_data_dir(bio);
- const int do_sync = bio_sync(bio);
+ const bool do_sync = bio_rw_flagged(bio, BIO_RW_SYNCIO);
struct bio_list bl;
unsigned long flags;
mdk_rdev_t *blocked_rdev;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -1170,6 +1170,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
break;
}
+ md_integrity_add_rdev(rdev, mddev);
print_conf(conf);
return err;
}
@@ -1203,7 +1204,9 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
/* lost the race, try later */
err = -EBUSY;
p->rdev = rdev;
+ goto abort;
}
+ md_integrity_register(mddev);
}
abort:
@@ -1607,7 +1610,7 @@ static void raid10d(mddev_t *mddev)
raid_end_bio_io(r10_bio);
bio_put(bio);
} else {
- const int do_sync = bio_sync(r10_bio->master_bio);
+ const bool do_sync = bio_rw_flagged(r10_bio->master_bio, BIO_RW_SYNCIO);
bio_put(bio);
rdev = conf->mirrors[mirror].rdev;
if (printk_ratelimit())
@@ -2225,6 +2228,7 @@ static int run(mddev_t *mddev)
if (conf->near_copies < mddev->raid_disks)
blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
+ md_integrity_register(mddev);
return 0;
out_free_conf:
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 37835538b58e..3233b98bdd9d 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3606,7 +3606,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
const int rw = bio_data_dir(bi);
int cpu, remaining;
- if (unlikely(bio_barrier(bi))) {
+ if (unlikely(bio_rw_flagged(bi, BIO_RW_BARRIER))) {
bio_endio(bi, -EOPNOTSUPP);
return 0;
}
@@ -3999,6 +3999,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
return 0;
}
+ /* Allow raid5_quiesce to complete */
+ wait_event(conf->wait_for_overlap, conf->quiesce != 2);
+
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return reshape_request(mddev, sector_nr, skipped);
@@ -4316,6 +4319,15 @@ raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks)
return sectors * (raid_disks - conf->max_degraded);
}
+static void free_conf(raid5_conf_t *conf)
+{
+ shrink_stripes(conf);
+ safe_put_page(conf->spare_page);
+ kfree(conf->disks);
+ kfree(conf->stripe_hashtbl);
+ kfree(conf);
+}
+
static raid5_conf_t *setup_conf(mddev_t *mddev)
{
raid5_conf_t *conf;
@@ -4447,11 +4459,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
abort:
if (conf) {
- shrink_stripes(conf);
- safe_put_page(conf->spare_page);
- kfree(conf->disks);
- kfree(conf->stripe_hashtbl);
- kfree(conf);
+ free_conf(conf);
return ERR_PTR(-EIO);
} else
return ERR_PTR(-ENOMEM);
@@ -4629,12 +4637,8 @@ abort:
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
if (conf) {
- shrink_stripes(conf);
print_raid5_conf(conf);
- safe_put_page(conf->spare_page);
- kfree(conf->disks);
- kfree(conf->stripe_hashtbl);
- kfree(conf);
+ free_conf(conf);
}
mddev->private = NULL;
printk(KERN_ALERT "raid5: failed to run raid set %s\n", mdname(mddev));
@@ -4649,13 +4653,10 @@ static int stop(mddev_t *mddev)
md_unregister_thread(mddev->thread);
mddev->thread = NULL;
- shrink_stripes(conf);
- kfree(conf->stripe_hashtbl);
mddev->queue->backing_dev_info.congested_fn = NULL;
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
- kfree(conf->disks);
- kfree(conf);
+ free_conf(conf);
mddev->private = NULL;
return 0;
}
@@ -4857,6 +4858,7 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
return -EINVAL;
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
+ revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->dev_sectors;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -5002,7 +5004,7 @@ static int raid5_start_reshape(mddev_t *mddev)
spin_unlock_irqrestore(&conf->device_lock, flags);
}
mddev->raid_disks = conf->raid_disks;
- mddev->reshape_position = 0;
+ mddev->reshape_position = conf->reshape_progress;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
@@ -5057,7 +5059,6 @@ static void end_reshape(raid5_conf_t *conf)
*/
static void raid5_finish_reshape(mddev_t *mddev)
{
- struct block_device *bdev;
raid5_conf_t *conf = mddev->private;
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@@ -5066,15 +5067,7 @@ static void raid5_finish_reshape(mddev_t *mddev)
md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev->changed = 1;
-
- bdev = bdget_disk(mddev->gendisk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode,
- (loff_t)mddev->array_sectors << 9);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
+ revalidate_disk(mddev->gendisk);
} else {
int d;
mddev->degraded = conf->raid_disks;
@@ -5106,12 +5099,18 @@ static void raid5_quiesce(mddev_t *mddev, int state)
case 1: /* stop all writes */
spin_lock_irq(&conf->device_lock);
- conf->quiesce = 1;
+ /* '2' tells resync/reshape to pause so that all
+ * active stripes can drain
+ */
+ conf->quiesce = 2;
wait_event_lock_irq(conf->wait_for_stripe,
atomic_read(&conf->active_stripes) == 0 &&
atomic_read(&conf->active_aligned_reads) == 0,
conf->device_lock, /* nothing */);
+ conf->quiesce = 1;
spin_unlock_irq(&conf->device_lock);
+ /* allow reshape to continue */
+ wake_up(&conf->wait_for_overlap);
break;
case 0: /* re-enable writes */
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c
index 825aa1412e6f..9f5dba244cb8 100644
--- a/drivers/media/common/tuners/qt1010.c
+++ b/drivers/media/common/tuners/qt1010.c
@@ -64,24 +64,22 @@ static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
/* dump all registers */
static void qt1010_dump_regs(struct qt1010_priv *priv)
{
- char buf[52], buf2[4];
u8 reg, val;
for (reg = 0; ; reg++) {
if (reg % 16 == 0) {
if (reg)
- printk("%s\n", buf);
- sprintf(buf, "%02x: ", reg);
+ printk(KERN_CONT "\n");
+ printk(KERN_DEBUG "%02x:", reg);
}
if (qt1010_readreg(priv, reg, &val) == 0)
- sprintf(buf2, "%02x ", val);
+ printk(KERN_CONT " %02x", val);
else
- strcpy(buf2, "-- ");
- strcat(buf, buf2);
+ printk(KERN_CONT " --");
if (reg == 0x2f)
break;
}
- printk("%s\n", buf);
+ printk(KERN_CONT "\n");
}
static int qt1010_set_params(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 6a7f1a417c27..5c6ef1e23c94 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1301,6 +1301,25 @@ static struct tuner_params tuner_fq1216lme_mk3_params[] = {
},
};
+/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */
+
+static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = {
+ /* The datasheet specified channel ranges and the bandswitch byte */
+ /* The control byte value of 0x8e is just a guess */
+ { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */
+ { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */
+ { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */
+};
+
+static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_partsnic_pti_5nf05_ranges,
+ .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges),
+ .cb_first_if_lower_freq = 1, /* not specified but safe to do */
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1753,6 +1772,12 @@ struct tunertype tuners[] = {
.params = tuner_fq1216lme_mk3_params,
.count = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
},
+
+ [TUNER_PARTSNIC_PTI_5NF05] = {
+ .name = "Partsnic (Daewoo) PTI-5NF05",
+ .params = tuner_partsnic_pti_5nf05_params,
+ .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index efb4a6c2b57a..850a6c606750 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -20,8 +20,14 @@
#include "tuner-simple.h"
#include "stv0297.h"
+
+/* Can we use the specified front-end? Remember that if we are compiled
+ * into the kernel we can't call code that's in modules. */
+#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
+ (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
+
/* lnb control */
-#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
+#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct flexcop_device *fc = fe->dvb->priv;
@@ -49,8 +55,7 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
}
#endif
-#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
- || defined(CONFIG_DVB_MT312_MODULE)
+#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
static int flexcop_sleep(struct dvb_frontend* fe)
{
struct flexcop_device *fc = fe->dvb->priv;
@@ -61,7 +66,7 @@ static int flexcop_sleep(struct dvb_frontend* fe)
#endif
/* SkyStar2 DVB-S rev 2.3 */
-#if defined(CONFIG_DVB_MT312_MODULE)
+#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
@@ -150,53 +155,34 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = {
.demod_address = 0x0e,
};
-static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
- .len = sizeof(buf) };
- struct flexcop_device *fc = fe->dvb->priv;
- div = (params->frequency + (125/2)) / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = (div >> 0) & 0xff;
- buf[2] = 0x84 | ((div >> 10) & 0x60);
- buf[3] = 0x80;
-
- if (params->frequency < 1550000)
- buf[3] |= 0x02;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
static int skystar2_rev23_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
+ struct dvb_frontend_ops *ops;
+
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
- if (fc->fe != NULL) {
- struct dvb_frontend_ops *ops = &fc->fe->ops;
- ops->tuner_ops.set_params =
- skystar23_samsung_tbdu18132_tuner_set_params;
- ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
- ops->diseqc_send_burst = flexcop_diseqc_send_burst;
- ops->set_tone = flexcop_set_tone;
- ops->set_voltage = flexcop_set_voltage;
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
- return 1;
- }
- return 0;
+ if (!fc->fe)
+ return 0;
+
+ if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+ DVB_PLL_SAMSUNG_TBDU18132))
+ return 0;
+
+ ops = &fc->fe->ops;
+ ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+ ops->diseqc_send_burst = flexcop_diseqc_send_burst;
+ ops->set_tone = flexcop_set_tone;
+ ops->set_voltage = flexcop_set_voltage;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+ return 1;
}
+#else
+#define skystar2_rev23_attach NULL
#endif
/* SkyStar2 DVB-S rev 2.6 */
-#if defined(CONFIG_DVB_STV0299_MODULE)
+#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
@@ -225,31 +211,6 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
return 0;
}
-static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = {
- .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct flexcop_device *fc = fe->dvb->priv;
- div = params->frequency / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; /* 0xC4 */
- buf[3] = 0x08;
-
- if (params->frequency < 1500000)
- buf[3] |= 0x10;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
static u8 samsung_tbmu24112_inittab[] = {
0x01, 0x15,
0x02, 0x30,
@@ -311,20 +272,25 @@ static int skystar2_rev26_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
- if (fc->fe != NULL) {
- struct dvb_frontend_ops *ops = &fc->fe->ops;
- ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
- ops->set_voltage = flexcop_set_voltage;
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
- return 1;
- }
- return 0;
+ if (!fc->fe)
+ return 0;
+
+ if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+ DVB_PLL_SAMSUNG_TBMU24112))
+ return 0;
+
+ fc->fe->ops.set_voltage = flexcop_set_voltage;
+ fc->fe_sleep = fc->fe->ops.sleep;
+ fc->fe->ops.sleep = flexcop_sleep;
+ return 1;
+
}
+#else
+#define skystar2_rev26_attach NULL
#endif
/* SkyStar2 DVB-S rev 2.7 */
-#if defined(CONFIG_DVB_S5H1420_MODULE)
+#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
@@ -385,10 +351,12 @@ fail:
fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
}
+#else
+#define skystar2_rev27_attach NULL
#endif
/* SkyStar2 rev 2.8 */
-#if defined(CONFIG_DVB_CX24123_MODULE)
+#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
static struct cx24123_config skystar2_rev2_8_cx24123_config = {
.demod_address = 0x55,
.dont_use_pll = 1,
@@ -410,7 +378,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
if (!fc->fe)
return 0;
- i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
+ i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
if (!i2c_tuner)
return 0;
@@ -433,10 +401,12 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
* IR-receiver (PIC16F818) - but the card has no input for that ??? */
return 1;
}
+#else
+#define skystar2_rev28_attach NULL
#endif
/* AirStar DVB-T */
-#if defined(CONFIG_DVB_MT352_MODULE)
+#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
{
static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
@@ -454,32 +424,6 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
return 0;
}
-static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
- u32 div;
- unsigned char bs = 0;
-
- if (buf_len < 5)
- return -EINVAL;
-
-#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- if (params->frequency >= 48000000 && params->frequency <= 154000000) \
- bs = 0x09;
- if (params->frequency >= 161000000 && params->frequency <= 439000000) \
- bs = 0x0a;
- if (params->frequency >= 447000000 && params->frequency <= 863000000) \
- bs = 0x08;
-
- pllbuf[0] = 0x61;
- pllbuf[1] = div >> 8;
- pllbuf[2] = div & 0xff;
- pllbuf[3] = 0xcc;
- pllbuf[4] = bs;
- return 5;
-}
-
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
@@ -489,16 +433,18 @@ static int airstar_dvbt_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
- if (fc->fe != NULL) {
- fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
- return 1;
- }
- return 0;
+ if (!fc->fe)
+ return 0;
+
+ return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+ DVB_PLL_SAMSUNG_TDTC9251DH0);
}
+#else
+#define airstar_dvbt_attach NULL
#endif
/* AirStar ATSC 1st generation */
-#if defined(CONFIG_DVB_BCM3510_MODULE)
+#if FE_SUPPORTED(BCM3510)
static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
const struct firmware **fw, char* name)
{
@@ -517,10 +463,12 @@ static int airstar_atsc1_attach(struct flexcop_device *fc,
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
return fc->fe != NULL;
}
+#else
+#define airstar_atsc1_attach NULL
#endif
/* AirStar ATSC 2nd generation */
-#if defined(CONFIG_DVB_NXT200X_MODULE)
+#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
};
@@ -535,10 +483,12 @@ static int airstar_atsc2_attach(struct flexcop_device *fc,
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TBMV);
}
+#else
+#define airstar_atsc2_attach NULL
#endif
/* AirStar ATSC 3rd generation */
-#if defined(CONFIG_DVB_LGDT330X_MODULE)
+#if FE_SUPPORTED(LGDT330X)
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
@@ -556,57 +506,12 @@ static int airstar_atsc3_attach(struct flexcop_device *fc,
return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
TUNER_LG_TDVS_H06XF);
}
+#else
+#define airstar_atsc3_attach NULL
#endif
/* CableStar2 DVB-C */
-#if defined(CONFIG_DVB_STV0297_MODULE)
-static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
-{
- struct flexcop_device *fc = fe->dvb->priv;
- u8 buf[4];
- u16 div;
- int ret;
-
-/* 62.5 kHz * 10 */
-#define REF_FREQ 625
-#define FREQ_OFFSET 36125
-
- div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
-/* 4 MHz = 4000 KHz */
-
- buf[0] = (u8)( div >> 8) & 0x7f;
- buf[1] = (u8) div & 0xff;
-
-/* F(osc) = N * Reference Freq. (62.5 kHz)
- * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
- * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
- * byte 4 : 1 * * AGD R3 R2 R1 R0
- * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
- * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
- buf[2] = 0x95;
-
-/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
- * 47 - 153 0 * 0 0 0 0 0 1 0x01
- * 153 - 430 0 * 0 0 0 0 1 0 0x02
- * 430 - 822 0 * 0 0 1 0 0 0 0x08
- * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
-
- if (fep->frequency <= 153000000) buf[3] = 0x01;
- else if (fep->frequency <= 430000000) buf[3] = 0x02;
- else if (fep->frequency <= 822000000) buf[3] = 0x08;
- else buf[3] = 0x88;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
- buf[0], buf[1], buf[2], buf[3]);
- ret = fc->i2c_request(&fc->fc_i2c_adap[2],
- FC_WRITE, 0x61, buf[0], &buf[1], 3);
- deb_tuner("tuner write returned: %d\n",ret);
- return ret;
-}
-
+#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x01,
0x80, 0x00,
@@ -690,47 +595,43 @@ static int cablestar2_attach(struct flexcop_device *fc,
{
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
- if (!fc->fe) {
- /* Reset for next frontend to try */
- fc->fc_i2c_adap[0].no_base_addr = 0;
- return 0;
- }
- fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+ if (!fc->fe)
+ goto fail;
+
+ /* This tuner doesn't use the stv0297's I2C gate, but instead the
+ * tuner is connected to a different flexcop I2C adapter. */
+ if (fc->fe->ops.i2c_gate_ctrl)
+ fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
+ fc->fe->ops.i2c_gate_ctrl = NULL;
+
+ if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
+ &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
+ goto fail;
+
return 1;
+
+fail:
+ /* Reset for next frontend to try */
+ fc->fc_i2c_adap[0].no_base_addr = 0;
+ return 0;
}
+#else
+#define cablestar2_attach NULL
#endif
static struct {
flexcop_device_type_t type;
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = {
-#if defined(CONFIG_DVB_S5H1420_MODULE)
{ FC_SKY_REV27, skystar2_rev27_attach },
-#endif
-#if defined(CONFIG_DVB_CX24123_MODULE)
{ FC_SKY_REV28, skystar2_rev28_attach },
-#endif
-#if defined(CONFIG_DVB_STV0299_MODULE)
{ FC_SKY_REV26, skystar2_rev26_attach },
-#endif
-#if defined(CONFIG_DVB_MT352_MODULE)
{ FC_AIR_DVBT, airstar_dvbt_attach },
-#endif
-#if defined(CONFIG_DVB_NXT200X_MODULE)
{ FC_AIR_ATSC2, airstar_atsc2_attach },
-#endif
-#if defined(CONFIG_DVB_LGDT330X_MODULE)
{ FC_AIR_ATSC3, airstar_atsc3_attach },
-#endif
-#if defined(CONFIG_DVB_BCM3510_MODULE)
{ FC_AIR_ATSC1, airstar_atsc1_attach },
-#endif
-#if defined(CONFIG_DVB_STV0297_MODULE)
{ FC_CABLE, cablestar2_attach },
-#endif
-#if defined(CONFIG_DVB_MT312_MODULE)
{ FC_SKY_REV23, skystar2_rev23_attach },
-#endif
};
/* try to figure out the frontend */
@@ -738,6 +639,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
{
int i;
for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+ if (!flexcop_frontends[i].attach)
+ continue;
/* type needs to be set before, because of some workarounds
* done based on the probed card type */
fc->dev_type = flexcop_frontends[i].type;
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index 4dbd7d4185af..c662fa65a339 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -44,6 +44,14 @@
#include "cx24116.h"
#include "z0194a.h"
+#define UNSET (-1U)
+
+#define DM1105_BOARD_NOAUTO UNSET
+#define DM1105_BOARD_UNKNOWN 0
+#define DM1105_BOARD_DVBWORLD_2002 1
+#define DM1105_BOARD_DVBWORLD_2004 2
+#define DM1105_BOARD_AXESS_DM05 3
+
/* ----------------------------------------------- */
/*
* PCI ID's
@@ -153,20 +161,105 @@
/* GPIO's for LNB power control */
#define DM1105_LNB_MASK 0x00000000
+#define DM1105_LNB_OFF 0x00020000
#define DM1105_LNB_13V 0x00010100
#define DM1105_LNB_18V 0x00000100
/* GPIO's for LNB power control for Axess DM05 */
#define DM05_LNB_MASK 0x00000000
+#define DM05_LNB_OFF 0x00020000/* actually 13v */
#define DM05_LNB_13V 0x00020000
#define DM05_LNB_18V 0x00030000
+static unsigned int card[] = {[0 ... 3] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
static int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+static unsigned int dm1105_devcount;
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+struct dm1105_board {
+ char *name;
+};
+
+struct dm1105_subid {
+ u16 subvendor;
+ u16 subdevice;
+ u32 card;
+};
+
+static const struct dm1105_board dm1105_boards[] = {
+ [DM1105_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ },
+ [DM1105_BOARD_DVBWORLD_2002] = {
+ .name = "DVBWorld PCI 2002",
+ },
+ [DM1105_BOARD_DVBWORLD_2004] = {
+ .name = "DVBWorld PCI 2004",
+ },
+ [DM1105_BOARD_AXESS_DM05] = {
+ .name = "Axess/EasyTv DM05",
+ },
+};
+
+static const struct dm1105_subid dm1105_subids[] = {
+ {
+ .subvendor = 0x0000,
+ .subdevice = 0x2002,
+ .card = DM1105_BOARD_DVBWORLD_2002,
+ }, {
+ .subvendor = 0x0001,
+ .subdevice = 0x2002,
+ .card = DM1105_BOARD_DVBWORLD_2002,
+ }, {
+ .subvendor = 0x0000,
+ .subdevice = 0x2004,
+ .card = DM1105_BOARD_DVBWORLD_2004,
+ }, {
+ .subvendor = 0x0001,
+ .subdevice = 0x2004,
+ .card = DM1105_BOARD_DVBWORLD_2004,
+ }, {
+ .subvendor = 0x195d,
+ .subdevice = 0x1105,
+ .card = DM1105_BOARD_AXESS_DM05,
+ },
+};
+
+static void dm1105_card_list(struct pci_dev *pci)
+{
+ int i;
+
+ if (0 == pci->subsystem_vendor &&
+ 0 == pci->subsystem_device) {
+ printk(KERN_ERR
+ "dm1105: Your board has no valid PCI Subsystem ID\n"
+ "dm1105: and thus can't be autodetected\n"
+ "dm1105: Please pass card=<n> insmod option to\n"
+ "dm1105: workaround that. Redirect complaints to\n"
+ "dm1105: the vendor of the TV card. Best regards,\n"
+ "dm1105: -- tux\n");
+ } else {
+ printk(KERN_ERR
+ "dm1105: Your board isn't known (yet) to the driver.\n"
+ "dm1105: You can try to pick one of the existing\n"
+ "dm1105: card configs via card=<n> insmod option.\n"
+ "dm1105: Updating to the latest version might help\n"
+ "dm1105: as well.\n");
+ }
+ printk(KERN_ERR "Here is a list of valid choices for the card=<n> "
+ "insmod option:\n");
+ for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
+ printk(KERN_ERR "dm1105: card=%d -> %s\n",
+ i, dm1105_boards[i].name);
+}
+
/* infrared remote control */
struct infrared {
struct input_dev *input_dev;
@@ -193,6 +286,8 @@ struct dm1105dvb {
struct dvb_frontend *fe;
struct dvb_net dvbnet;
unsigned int full_ts_users;
+ unsigned int boardnr;
+ int nr;
/* i2c */
struct i2c_adapter i2c_adap;
@@ -211,7 +306,6 @@ struct dm1105dvb {
unsigned int PacketErrorCount;
unsigned int dmarst;
spinlock_t lock;
-
};
#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
@@ -326,16 +420,20 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
- u32 lnb_mask, lnb_13v, lnb_18v;
+ u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
- switch (dm1105dvb->pdev->subsystem_device) {
- case PCI_DEVICE_ID_DM05:
+ switch (dm1105dvb->boardnr) {
+ case DM1105_BOARD_AXESS_DM05:
lnb_mask = DM05_LNB_MASK;
+ lnb_off = DM05_LNB_OFF;
lnb_13v = DM05_LNB_13V;
lnb_18v = DM05_LNB_18V;
break;
+ case DM1105_BOARD_DVBWORLD_2002:
+ case DM1105_BOARD_DVBWORLD_2004:
default:
lnb_mask = DM1105_LNB_MASK;
+ lnb_off = DM1105_LNB_OFF;
lnb_13v = DM1105_LNB_13V;
lnb_18v = DM1105_LNB_18V;
}
@@ -343,8 +441,10 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
if (voltage == SEC_VOLTAGE_18)
outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
- else
+ else if (voltage == SEC_VOLTAGE_13)
outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
+ else
+ outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
return 0;
}
@@ -589,8 +689,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
{
int ret;
- switch (dm1105dvb->pdev->subsystem_device) {
- case PCI_DEVICE_ID_DW2004:
+ switch (dm1105dvb->boardnr) {
+ case DM1105_BOARD_DVBWORLD_2004:
dm1105dvb->fe = dvb_attach(
cx24116_attach, &serit_sp2633_config,
&dm1105dvb->i2c_adap);
@@ -598,6 +698,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
break;
+ case DM1105_BOARD_DVBWORLD_2002:
+ case DM1105_BOARD_AXESS_DM05:
default:
dm1105dvb->fe = dvb_attach(
stv0299_attach, &sharp_z0194a_config,
@@ -676,11 +778,31 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
int ret = -ENOMEM;
+ int i;
dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
if (!dm1105dvb)
return -ENOMEM;
+ /* board config */
+ dm1105dvb->nr = dm1105_devcount;
+ dm1105dvb->boardnr = UNSET;
+ if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
+ dm1105dvb->boardnr = card[dm1105dvb->nr];
+ for (i = 0; UNSET == dm1105dvb->boardnr &&
+ i < ARRAY_SIZE(dm1105_subids); i++)
+ if (pdev->subsystem_vendor ==
+ dm1105_subids[i].subvendor &&
+ pdev->subsystem_device ==
+ dm1105_subids[i].subdevice)
+ dm1105dvb->boardnr = dm1105_subids[i].card;
+
+ if (UNSET == dm1105dvb->boardnr) {
+ dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
+ dm1105_card_list(pdev);
+ }
+
+ dm1105_devcount++;
dm1105dvb->pdev = pdev;
dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
dm1105dvb->PacketErrorCount = 0;
@@ -853,6 +975,7 @@ static void __devexit dm1105_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
+ dm1105_devcount--;
kfree(dm1105dvb);
}
@@ -861,17 +984,12 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
.vendor = PCI_VENDOR_ID_TRIGEM,
.device = PCI_DEVICE_ID_DM1105,
.subvendor = PCI_ANY_ID,
- .subdevice = PCI_DEVICE_ID_DW2002,
- }, {
- .vendor = PCI_VENDOR_ID_TRIGEM,
- .device = PCI_DEVICE_ID_DM1105,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_DEVICE_ID_DW2004,
+ .subdevice = PCI_ANY_ID,
}, {
.vendor = PCI_VENDOR_ID_AXESS,
.device = PCI_DEVICE_ID_DM05,
- .subvendor = PCI_VENDOR_ID_AXESS,
- .subdevice = PCI_DEVICE_ID_DM05,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
}, {
/* empty */
},
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 6d6121eb5d59..3750ff48cba1 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
/* stop feed but only mark the specified filter as stopped (state set) */
static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
{
+ struct dmxdev_feed *feed;
+
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
switch (dmxdevfilter->type) {
@@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
break;
case DMXDEV_TYPE_PES:
- dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+ feed->ts->stop_filtering(feed->ts);
break;
default:
return -EINVAL;
@@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
/* start feed associated with the specified filter */
static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
{
+ struct dmxdev_feed *feed;
+ int ret;
+
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
return filter->feed.sec->start_filtering(filter->feed.sec);
case DMXDEV_TYPE_PES:
- return filter->feed.ts->start_filtering(filter->feed.ts);
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = feed->ts->start_filtering(feed->ts);
+ if (ret < 0) {
+ dvb_dmxdev_feed_stop(filter);
+ return ret;
+ }
+ }
+ break;
default:
return -EINVAL;
}
@@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
{
+ struct dmxdev_feed *feed;
+ struct dmx_demux *demux;
+
if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
@@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
dmxdevfilter->feed.sec = NULL;
break;
case DMXDEV_TYPE_PES:
- if (!dmxdevfilter->feed.ts)
- break;
dvb_dmxdev_feed_stop(dmxdevfilter);
- dmxdevfilter->dev->demux->
- release_ts_feed(dmxdevfilter->dev->demux,
- dmxdevfilter->feed.ts);
- dmxdevfilter->feed.ts = NULL;
+ demux = dmxdevfilter->dev->demux;
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+ demux->release_ts_feed(demux, feed->ts);
+ feed->ts = NULL;
+ }
break;
default:
if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
@@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
return 0;
}
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ /* delete all PIDs */
+ list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+ list_del(&feed->next);
+ kfree(feed);
+ }
+
+ BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
{
if (dmxdevfilter->state < DMXDEV_STATE_SET)
return 0;
+ if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+ dvb_dmxdev_delete_pids(dmxdevfilter);
+
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
return 0;
}
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmxdev_feed *feed)
+{
+ struct timespec timeout = { 0 };
+ struct dmx_pes_filter_params *para = &filter->params.pes;
+ dmx_output_t otype;
+ int ret;
+ int ts_type;
+ enum dmx_ts_pes ts_pes;
+ struct dmx_ts_feed *tsfeed;
+
+ feed->ts = NULL;
+ otype = para->output;
+
+ ts_pes = (enum dmx_ts_pes)para->pes_type;
+
+ if (ts_pes < DMX_PES_OTHER)
+ ts_type = TS_DECODER;
+ else
+ ts_type = 0;
+
+ if (otype == DMX_OUT_TS_TAP)
+ ts_type |= TS_PACKET;
+ else if (otype == DMX_OUT_TSDEMUX_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX;
+ else if (otype == DMX_OUT_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+ ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+ dvb_dmxdev_ts_callback);
+ if (ret < 0)
+ return ret;
+
+ tsfeed = feed->ts;
+ tsfeed->priv = filter;
+
+ ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ ret = tsfeed->start_filtering(tsfeed);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ return 0;
+}
+
static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
{
struct dmxdev *dmxdev = filter->dev;
+ struct dmxdev_feed *feed;
void *mem;
int ret, i;
@@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
break;
}
case DMXDEV_TYPE_PES:
- {
- struct timespec timeout = { 0 };
- struct dmx_pes_filter_params *para = &filter->params.pes;
- dmx_output_t otype;
- int ts_type;
- enum dmx_ts_pes ts_pes;
- struct dmx_ts_feed **tsfeed = &filter->feed.ts;
-
- filter->feed.ts = NULL;
- otype = para->output;
-
- ts_pes = (enum dmx_ts_pes)para->pes_type;
-
- if (ts_pes < DMX_PES_OTHER)
- ts_type = TS_DECODER;
- else
- ts_type = 0;
-
- if (otype == DMX_OUT_TS_TAP)
- ts_type |= TS_PACKET;
- else if (otype == DMX_OUT_TSDEMUX_TAP)
- ts_type |= TS_PACKET | TS_DEMUX;
- else if (otype == DMX_OUT_TAP)
- ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
-
- ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
- tsfeed,
- dvb_dmxdev_ts_callback);
- if (ret < 0)
- return ret;
-
- (*tsfeed)->priv = filter;
-
- ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
- 32768, timeout);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux,
- *tsfeed);
- return ret;
- }
-
- ret = filter->feed.ts->start_filtering(filter->feed.ts);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux,
- *tsfeed);
- return ret;
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+ if (ret < 0) {
+ dvb_dmxdev_filter_stop(filter);
+ return ret;
+ }
}
-
break;
- }
default:
return -EINVAL;
}
@@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- dmxdevfilter->feed.ts = NULL;
+ INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
init_timer(&dmxdevfilter->timer);
dvbdev->users++;
@@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter)
filter->mode[i] ^= 0xff;
}
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ /* only TS packet filters may have multiple PIDs */
+ if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+ (!list_empty(&filter->feed.ts)))
+ return -EINVAL;
+
+ feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+ if (feed == NULL)
+ return -ENOMEM;
+
+ feed->pid = pid;
+ list_add(&feed->next, &filter->feed.ts);
+
+ if (filter->state >= DMXDEV_STATE_GO)
+ return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+ return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+ if ((feed->pid == pid) && (feed->ts != NULL)) {
+ feed->ts->stop_filtering(feed->ts);
+ filter->dev->demux->release_ts_feed(filter->dev->demux,
+ feed->ts);
+ list_del(&feed->next);
+ kfree(feed);
+ }
+ }
+
+ return 0;
+}
+
static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params)
@@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_pes_filter_params *params)
{
+ int ret;
+
dvb_dmxdev_filter_stop(dmxdevfilter);
+ dvb_dmxdev_filter_reset(dmxdevfilter);
if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
return -EINVAL;
@@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+ dmxdevfilter->params.pes.pid);
+ if (ret < 0)
+ return ret;
+
if (params->flags & DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter);
@@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
&((struct dmx_stc *)parg)->base);
break;
+ case DMX_ADD_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_REMOVE_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 29746e70d325..c1379b56dfb4 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -53,13 +53,20 @@ enum dmxdev_state {
DMXDEV_STATE_TIMEDOUT
};
+struct dmxdev_feed {
+ u16 pid;
+ struct dmx_ts_feed *ts;
+ struct list_head next;
+};
+
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
} filter;
union {
- struct dmx_ts_feed *ts;
+ /* list of TS and PES feeds (struct dmxdev_feed) */
+ struct list_head ts;
struct dmx_section_feed *sec;
} feed;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index cfe2768d24af..eef6d3616626 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -425,13 +425,9 @@ no_dvb_demux_tscheck:
if ((DVR_FEED(feed)) && (dvr_done++))
continue;
- if (feed->pid == pid) {
+ if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf);
- if (DVR_FEED(feed))
- continue;
- }
-
- if (feed->pid == 0x2000)
+ else if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
}
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 8280f8d66a38..8c9ae0a3a272 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
{
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 4cb31e7c13c2..00fbaf56c61b 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -81,7 +81,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
switch (req->cmd) {
case GET_CONFIG:
- case BOOT:
case READ_MEMORY:
case RECONNECT_USB:
case GET_IR_CODE:
@@ -100,6 +99,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
case WRITE_VIRTUAL_MEMORY:
case COPY_FIRMWARE:
case DOWNLOAD_FIRMWARE:
+ case BOOT:
break;
default:
err("unknown command:%d", req->cmd);
@@ -538,24 +538,22 @@ exit:
/* dump eeprom */
static int af9015_eeprom_dump(struct dvb_usb_device *d)
{
- char buf[4+3*16+1], buf2[4];
u8 reg, val;
for (reg = 0; ; reg++) {
if (reg % 16 == 0) {
if (reg)
- deb_info("%s\n", buf);
- sprintf(buf, "%02x: ", reg);
+ deb_info(KERN_CONT "\n");
+ deb_info(KERN_DEBUG "%02x:", reg);
}
if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
- sprintf(buf2, "%02x ", val);
+ deb_info(KERN_CONT " %02x", val);
else
- strcpy(buf2, "-- ");
- strcat(buf, buf2);
+ deb_info(KERN_CONT " --");
if (reg == 0xff)
break;
}
- deb_info("%s\n", buf);
+ deb_info(KERN_CONT "\n");
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 818b2ab584bf..49fd78118a64 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -310,7 +310,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
struct i2c_adapter *tun_i2c;
tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
- &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+ &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
}
/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 136c5863d81b..12e018b4107d 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -527,6 +527,10 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
u8 i, buf[3] = {0, 0, 0};
*auto_mode = 0; /* set if parameters are requested to auto set */
+ /* Try auto-detect transmission parameters in case of AUTO requested or
+ garbage parameters given by application for compatibility.
+ MPlayer seems to provide garbage parameters currently. */
+
switch (params->transmission_mode) {
case TRANSMISSION_MODE_AUTO:
*auto_mode = 1;
@@ -536,7 +540,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[0] |= (1 << 0);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid transmission_mode\n", __func__);
+ *auto_mode = 1;
}
switch (params->guard_interval) {
@@ -554,7 +559,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[0] |= (3 << 2);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid guard_interval\n", __func__);
+ *auto_mode = 1;
}
switch (params->hierarchy_information) {
@@ -572,7 +578,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[0] |= (3 << 4);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid hierarchy_information\n", __func__);
+ *auto_mode = 1;
};
switch (params->constellation) {
@@ -587,7 +594,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[1] |= (2 << 6);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid constellation\n", __func__);
+ *auto_mode = 1;
}
/* Use HP. How and which case we can switch to LP? */
@@ -611,7 +619,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[2] |= (4 << 0);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid code_rate_HP\n", __func__);
+ *auto_mode = 1;
}
switch (params->code_rate_LP) {
@@ -638,7 +647,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
if (params->hierarchy_information == HIERARCHY_AUTO)
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid code_rate_LP\n", __func__);
+ *auto_mode = 1;
}
switch (params->bandwidth) {
@@ -651,7 +661,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
buf[1] |= (2 << 2);
break;
default:
- return -EINVAL;
+ deb_info("%s: invalid bandwidth\n", __func__);
+ buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */
}
/* program */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 0592f043ea64..d8f921b6fafd 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -458,7 +458,7 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
/* check if symbol rate is within limits */
if ((srate > state->frontend.ops.info.symbol_rate_max) ||
(srate < state->frontend.ops.info.symbol_rate_min))
- return -EOPNOTSUPP;;
+ return -EOPNOTSUPP;
/* choose the sampling rate high enough for the required operation,
while optimizing the power consumed by the demodulator */
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
index fe895bf7b18f..da92cbe1b8ea 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -167,7 +167,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
break;
case BAND_SBAND:
LO4_SET_VCO_HFDIV(lo4, 0, 0);
- LO4_SET_CTRIM(lo4, 1);;
+ LO4_SET_CTRIM(lo4, 1);
c = 1;
break;
case BAND_UHF:
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 9f6349964cda..6d865d6161d7 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -389,6 +389,77 @@ static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
}
};
+/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
+static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
+ .name = "Samsung TDTC9251DH0",
+ .min = 48000000,
+ .max = 863000000,
+ .iffreq = 36166667,
+ .count = 3,
+ .entries = {
+ { 157500000, 166667, 0xcc, 0x09 },
+ { 443000000, 166667, 0xcc, 0x0a },
+ { 863000000, 166667, 0xcc, 0x08 },
+ }
+};
+
+/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
+static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
+ .name = "Samsung TBDU18132",
+ .min = 950000,
+ .max = 2150000, /* guesses */
+ .iffreq = 0,
+ .count = 2,
+ .entries = {
+ { 1550000, 125, 0x84, 0x82 },
+ { 4095937, 125, 0x84, 0x80 },
+ }
+ /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
+ * by this driver. The two extra bits are 0x60 in the third byte. 15
+ * bits is enough for over 4 GHz, which is enough to cover the range
+ * of this tuner. We could use the additional divisor bits by adding
+ * more entries, e.g.
+ { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
+ { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
+ { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
+};
+
+/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
+static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
+ .name = "Samsung TBMU24112",
+ .min = 950000,
+ .max = 2150000, /* guesses */
+ .iffreq = 0,
+ .count = 2,
+ .entries = {
+ { 1500000, 125, 0x84, 0x18 },
+ { 9999999, 125, 0x84, 0x08 },
+ }
+};
+
+/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
+/* byte 4 : 1 * * AGD R3 R2 R1 R0
+ * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
+ * Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+ * 47 - 153 0 * 0 0 0 0 0 1 0x01
+ * 153 - 430 0 * 0 0 0 0 1 0 0x02
+ * 430 - 822 0 * 0 0 1 0 0 0 0x08
+ * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
+static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
+ .name = "ALPS TDEE4",
+ .min = 47000000,
+ .max = 862000000,
+ .iffreq = 36125000,
+ .count = 4,
+ .entries = {
+ { 153000000, 62500, 0x95, 0x01 },
+ { 430000000, 62500, 0x95, 0x02 },
+ { 822000000, 62500, 0x95, 0x08 },
+ { 999999999, 62500, 0x95, 0x88 },
+ }
+};
+
/* ----------------------------------------------------------- */
static struct dvb_pll_desc *pll_list[] = {
@@ -402,11 +473,15 @@ static struct dvb_pll_desc *pll_list[] = {
[DVB_PLL_TUA6034] = &dvb_pll_tua6034,
[DVB_PLL_TDA665X] = &dvb_pll_tda665x,
[DVB_PLL_TDED4] = &dvb_pll_tded4,
+ [DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4,
[DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
[DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
+ [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0,
+ [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132,
+ [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112,
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 05239f579ccf..086964344c38 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -23,6 +23,10 @@
#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
#define DVB_PLL_OPERA1 13
#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
+#define DVB_PLL_SAMSUNG_TDTC9251DH0 15
+#define DVB_PLL_SAMSUNG_TBDU18132 16
+#define DVB_PLL_SAMSUNG_TBMU24112 17
+#define DVB_PLL_TDEE4 18
/**
* Attach a dvb-pll to the supplied frontend structure.
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index fde27645bbed..eabcadc425d5 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -1,9 +1,9 @@
/*
- * Support for Legend Silicon DMB-TH demodulator
- * LGS8913, LGS8GL5
+ * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ * LGS8913, LGS8GL5, LGS8G75
* experimental support LGS8G42, LGS8G52
*
- * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
@@ -46,6 +46,42 @@ module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
"Signal strength calculation is slow.(default:on).");
+static const u8 lgs8g75_initdat[] = {
+ 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
+ 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
+ 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
+ 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
+ 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
+ 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
+ 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
+ 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
+ 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
+ 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
+ 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
+ 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
+ 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
+ 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
+ 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
+ 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
+ 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
+ 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
+ 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
+ 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
+ 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
+ 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
+ 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
+ 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
+ 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
+ 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
+};
+
/* LGS8GXX internal helper functions */
static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
msg.addr = priv->config->demod_address;
- if (reg >= 0xC0)
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
msg.addr += 0x02;
if (debug >= 2)
@@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
};
dev_addr = priv->config->demod_address;
- if (reg >= 0xC0)
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
dev_addr += 0x02;
msg[1].addr = msg[0].addr = dev_addr;
@@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
return 0;
}
+static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
+ u8 val, u8 delay, u8 tries)
+{
+ u8 t;
+ int i;
+
+ for (i = 0; i < tries; i++) {
+ lgs8gxx_read_reg(priv, reg, &t);
+
+ if ((t & mask) == val)
+ return 0;
+ msleep(delay);
+ }
+
+ return 1;
+}
+
static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
{
const struct lgs8gxx_config *config = priv->config;
u8 if_conf;
- if_conf = 0x10; /* AGC output on; */
+ if_conf = 0x10; /* AGC output on, RF_AGC output off; */
if_conf |=
((config->ext_adc) ? 0x80 : 0x00) |
((config->if_neg_center) ? 0x04 : 0x00) |
((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
- ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) |
- ((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00);
+ ((config->adc_signed) ? 0x02 : 0x00) |
+ ((config->if_neg_edge) ? 0x01 : 0x00);
if (config->ext_adc &&
(config->prod == LGS8GXX_PROD_LGS8G52)) {
@@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
}
dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
- lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
- lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
- lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
- lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
+ lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
+ lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
+ lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
+ } else {
+ lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
+ lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
+ lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
+ lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+ }
+
+ return 0;
+}
+
+static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
+{
+ u64 val;
+ u32 v32 = 0;
+ u8 reg_addr, t;
+ int i;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ reg_addr = 0x23;
+ else
+ reg_addr = 0x48;
+
+ for (i = 0; i < 4; i++) {
+ lgs8gxx_read_reg(priv, reg_addr, &t);
+ v32 <<= 8;
+ v32 |= t;
+ reg_addr--;
+ }
+ val = v32;
+ val *= priv->config->if_clk_freq;
+ val /= (u64)1 << 32;
+ dprintk("AFC = %u kHz\n", (u32)val);
return 0;
}
static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
{
u8 t;
+ u8 prod = priv->config->prod;
- if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+ if (prod == LGS8GXX_PROD_LGS8913)
lgs8gxx_write_reg(priv, 0xC6, 0x01);
- lgs8gxx_read_reg(priv, 0x7E, &t);
- lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
-
- /* clear FEC self reset */
- lgs8gxx_read_reg(priv, 0xC5, &t);
- lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+ if (prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ t &= (~0x04);
+ lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ } else if (prod == LGS8GXX_PROD_LGS8913 ||
+ prod == LGS8GXX_PROD_LGS8GL5 ||
+ prod == LGS8GXX_PROD_LGS8G42 ||
+ prod == LGS8GXX_PROD_LGS8G52 ||
+ prod == LGS8GXX_PROD_LGS8G54) {
+ lgs8gxx_read_reg(priv, 0x7E, &t);
+ lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
+
+ /* clear FEC self reset */
+ lgs8gxx_read_reg(priv, 0xC5, &t);
+ lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+ }
- if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+ if (prod == LGS8GXX_PROD_LGS8913) {
/* FEC auto detect */
lgs8gxx_write_reg(priv, 0xC1, 0x03);
lgs8gxx_read_reg(priv, 0x7C, &t);
t = (t & 0x8C) | 0x03;
lgs8gxx_write_reg(priv, 0x7C, t);
- }
-
- if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
/* BER test mode */
lgs8gxx_read_reg(priv, 0xC3, &t);
t = (t & 0xEF) | 0x10;
@@ -207,6 +303,32 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
int ret = 0;
u8 t;
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ u8 t2;
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ t &= (~0x80);
+ lgs8gxx_write_reg(priv, 0x0C, t);
+
+ lgs8gxx_read_reg(priv, 0x0C, &t);
+ lgs8gxx_read_reg(priv, 0x19, &t2);
+
+ if (((t&0x03) == 0x01) && (t2&0x01)) {
+ lgs8gxx_write_reg(priv, 0x6E, 0x05);
+ lgs8gxx_write_reg(priv, 0x39, 0x02);
+ lgs8gxx_write_reg(priv, 0x39, 0x03);
+ lgs8gxx_write_reg(priv, 0x3D, 0x05);
+ lgs8gxx_write_reg(priv, 0x3E, 0x28);
+ lgs8gxx_write_reg(priv, 0x53, 0x80);
+ } else {
+ lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ }
+
+ lgs8gxx_soft_reset(priv);
+ return 0;
+ }
+
/* turn off auto-detect; manual settings */
lgs8gxx_write_reg(priv, 0x7E, 0);
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
@@ -226,11 +348,39 @@ static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
int ret = 0;
u8 t;
- ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ ret = lgs8gxx_read_reg(priv, 0x13, &t);
+ else
+ ret = lgs8gxx_read_reg(priv, 0x4B, &t);
if (ret != 0)
return ret;
- *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ *locked = ((t & 0x80) == 0x80) ? 1 : 0;
+ else
+ *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+ return 0;
+}
+
+/* Wait for Code Acquisition Lock */
+static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
+{
+ int ret = 0;
+ u8 reg, mask, val;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg = 0x13;
+ mask = 0x80;
+ val = 0x80;
+ } else {
+ reg = 0x4B;
+ mask = 0xC0;
+ val = 0xC0;
+ }
+
+ ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
+ *locked = (ret == 0) ? 1 : 0;
+
return 0;
}
@@ -238,21 +388,30 @@ static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
u8 *finished)
{
int ret = 0;
- u8 t;
+ u8 reg, mask, val;
- ret = lgs8gxx_read_reg(priv, 0xA4, &t);
- if (ret != 0)
- return ret;
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg = 0x1f;
+ mask = 0xC0;
+ val = 0x80;
+ } else {
+ reg = 0xA4;
+ mask = 0x03;
+ val = 0x01;
+ }
- *finished = ((t & 0x3) == 0x1) ? 1 : 0;
+ ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
+ *finished = (ret == 0) ? 1 : 0;
return 0;
}
-static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
+static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
+ u8 *locked)
{
- int err;
+ int err = 0;
u8 ad_fini = 0;
+ u8 t1, t2;
if (gi == GI_945)
dprintk("try GI 945\n");
@@ -260,17 +419,29 @@ static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
dprintk("try GI 595\n");
else if (gi == GI_420)
dprintk("try GI 420\n");
- lgs8gxx_write_reg(priv, 0x04, gi);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x0C, &t1);
+ lgs8gxx_read_reg(priv, 0x18, &t2);
+ t1 &= ~(GI_MASK);
+ t1 |= gi;
+ t2 &= 0xFE;
+ t2 |= cpn ? 0x01 : 0x00;
+ lgs8gxx_write_reg(priv, 0x0C, t1);
+ lgs8gxx_write_reg(priv, 0x18, t2);
+ } else {
+ lgs8gxx_write_reg(priv, 0x04, gi);
+ }
lgs8gxx_soft_reset(priv);
- msleep(50);
+ err = lgs8gxx_wait_ca_lock(priv, locked);
+ if (err || !(*locked))
+ return err;
err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
if (err != 0)
return err;
if (ad_fini) {
- err = lgs8gxx_is_locked(priv, locked);
- if (err != 0)
- return err;
- }
+ dprintk("auto detect finished\n");
+ } else
+ *locked = 0;
return 0;
}
@@ -285,13 +456,18 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
dprintk("%s\n", __func__);
lgs8gxx_set_mode_auto(priv);
- /* Guard Interval */
- lgs8gxx_write_reg(priv, 0x03, 00);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_write_reg(priv, 0x67, 0xAA);
+ lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+ } else {
+ /* Guard Interval */
+ lgs8gxx_write_reg(priv, 0x03, 00);
+ }
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
tmp_gi = GI_945;
- err = lgs8gxx_autolock_gi(priv, GI_945, &locked);
+ err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
if (err)
goto out;
if (locked)
@@ -299,14 +475,14 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
}
for (j = 0; j < 2; j++) {
tmp_gi = GI_420;
- err = lgs8gxx_autolock_gi(priv, GI_420, &locked);
+ err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
if (err)
goto out;
if (locked)
goto locked;
}
tmp_gi = GI_595;
- err = lgs8gxx_autolock_gi(priv, GI_595, &locked);
+ err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
if (err)
goto out;
if (locked)
@@ -317,8 +493,13 @@ locked:
if ((err == 0) && (locked == 1)) {
u8 t;
- lgs8gxx_read_reg(priv, 0xA2, &t);
- *detected_param = t;
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0xA2, &t);
+ *detected_param = t;
+ } else {
+ lgs8gxx_read_reg(priv, 0x1F, &t);
+ *detected_param = t & 0x3F;
+ }
if (tmp_gi == GI_945)
dprintk("GI 945 locked\n");
@@ -345,18 +526,28 @@ static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
if (err != 0) {
dprintk("lgs8gxx_auto_detect failed\n");
- }
+ } else
+ dprintk("detected param = 0x%02X\n", detected_param);
/* Apply detected parameters */
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
u8 inter_leave_len = detected_param & TIM_MASK ;
- inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40;
+ /* Fix 8913 time interleaver detection bug */
+ inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
detected_param |= inter_leave_len;
}
- lgs8gxx_write_reg(priv, 0x7D, detected_param);
- if (priv->config->prod == LGS8GXX_PROD_LGS8913)
- lgs8gxx_write_reg(priv, 0xC0, detected_param);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ u8 t;
+ lgs8gxx_read_reg(priv, 0x19, &t);
+ t &= 0x81;
+ t |= detected_param << 1;
+ lgs8gxx_write_reg(priv, 0x19, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0x7D, detected_param);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+ lgs8gxx_write_reg(priv, 0xC0, detected_param);
+ }
/* lgs8gxx_soft_reset(priv); */
/* Enter manual mode */
@@ -378,9 +569,10 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
u8 serial, u8 clk_pol, u8 clk_gated)
{
int ret = 0;
- u8 t;
+ u8 t, reg_addr;
- ret = lgs8gxx_read_reg(priv, 0xC2, &t);
+ reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
+ ret = lgs8gxx_read_reg(priv, reg_addr, &t);
if (ret != 0)
return ret;
@@ -389,13 +581,29 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
- ret = lgs8gxx_write_reg(priv, 0xC2, t);
+ ret = lgs8gxx_write_reg(priv, reg_addr, t);
if (ret != 0)
return ret;
return 0;
}
+/* A/D input peak-to-peak voltage range */
+static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
+ u8 sel)
+{
+ u8 r26 = 0x73, r27 = 0x90;
+
+ if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
+ return 0;
+
+ r26 |= (sel & 0x01) << 7;
+ r27 |= (sel & 0x02) >> 1;
+ lgs8gxx_write_reg(priv, 0x26, r26);
+ lgs8gxx_write_reg(priv, 0x27, r27);
+
+ return 0;
+}
/* LGS8913 demod frontend functions */
@@ -417,6 +625,34 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
return 0;
}
+static int lgs8g75_init_data(struct lgs8gxx_state *priv)
+{
+ const u8 *p = lgs8g75_initdat;
+ int i;
+
+ lgs8gxx_write_reg(priv, 0xC6, 0x40);
+
+ lgs8gxx_write_reg(priv, 0x3D, 0x04);
+ lgs8gxx_write_reg(priv, 0x39, 0x00);
+
+ lgs8gxx_write_reg(priv, 0x3A, 0x00);
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+ lgs8gxx_write_reg(priv, 0x3B, 0x00);
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+ for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+ lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
+ lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
+ lgs8gxx_write_reg(priv, 0x3C, *p);
+ p++;
+ }
+
+ lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+ return 0;
+}
+
static int lgs8gxx_init(struct dvb_frontend *fe)
{
struct lgs8gxx_state *priv =
@@ -429,6 +665,9 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
lgs8gxx_read_reg(priv, 0, &data);
dprintk("reg 0 = 0x%02X\n", data);
+ if (config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8g75_set_adc_vpp(priv, config->adc_vpp);
+
/* Setup MPEG output format */
err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
config->ts_clk_pol,
@@ -439,8 +678,7 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
if (config->prod == LGS8GXX_PROD_LGS8913)
lgs8913_init(priv);
lgs8gxx_set_if_freq(priv, priv->config->if_freq);
- if (config->prod != LGS8GXX_PROD_LGS8913)
- lgs8gxx_set_ad_mode(priv);
+ lgs8gxx_set_ad_mode(priv);
return 0;
}
@@ -489,9 +727,6 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
static int lgs8gxx_get_fe(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fe_params)
{
- struct lgs8gxx_state *priv = fe->demodulator_priv;
- u8 t;
-
dprintk("%s\n", __func__);
/* TODO: get real readings from device */
@@ -501,29 +736,10 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
/* bandwidth */
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-
- lgs8gxx_read_reg(priv, 0x7D, &t);
fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
- /* constellation */
- switch (t & SC_MASK) {
- case SC_QAM64:
- fe_params->u.ofdm.constellation = QAM_64;
- break;
- case SC_QAM32:
- fe_params->u.ofdm.constellation = QAM_32;
- break;
- case SC_QAM16:
- fe_params->u.ofdm.constellation = QAM_16;
- break;
- case SC_QAM4:
- case SC_QAM4NR:
- fe_params->u.ofdm.constellation = QPSK;
- break;
- default:
- fe_params->u.ofdm.constellation = QAM_64;
- }
+ fe_params->u.ofdm.constellation = QAM_AUTO;
/* transmission mode */
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
@@ -552,9 +768,19 @@ static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
s8 ret;
- u8 t;
+ u8 t, locked = 0;
dprintk("%s\n", __func__);
+ *fe_status = 0;
+
+ lgs8gxx_get_afc_phase(priv);
+ lgs8gxx_is_locked(priv, &locked);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ if (locked)
+ *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ return 0;
+ }
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
if (ret != 0)
@@ -658,12 +884,33 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
return 0;
}
+static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+ u8 t;
+ s16 v = 0;
+
+ dprintk("%s\n", __func__);
+
+ lgs8gxx_read_reg(priv, 0xB1, &t);
+ v |= t;
+ v <<= 8;
+ lgs8gxx_read_reg(priv, 0xB0, &t);
+ v |= t;
+
+ *signal = v;
+ dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+ return 0;
+}
+
static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
return lgs8913_read_signal_strength(priv, signal);
+ else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ return lgs8g75_read_signal_strength(priv, signal);
else
return lgs8gxx_read_signal_agc(priv, signal);
}
@@ -674,7 +921,10 @@ static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
u8 t;
*snr = 0;
- lgs8gxx_read_reg(priv, 0x95, &t);
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8gxx_read_reg(priv, 0x34, &t);
+ else
+ lgs8gxx_read_reg(priv, 0x95, &t);
dprintk("AVG Noise=0x%02X\n", t);
*snr = 256 - t;
*snr <<= 8;
@@ -690,31 +940,68 @@ static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
+static void packet_counter_start(struct lgs8gxx_state *priv)
+{
+ u8 orig, t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x30, &orig);
+ orig &= 0xE7;
+ t = orig | 0x10;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ t = orig | 0x18;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ t = orig | 0x10;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0xC6, 0x01);
+ lgs8gxx_write_reg(priv, 0xC6, 0x41);
+ lgs8gxx_write_reg(priv, 0xC6, 0x01);
+ }
+}
+
+static void packet_counter_stop(struct lgs8gxx_state *priv)
+{
+ u8 t;
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ lgs8gxx_read_reg(priv, 0x30, &t);
+ t &= 0xE7;
+ lgs8gxx_write_reg(priv, 0x30, t);
+ } else {
+ lgs8gxx_write_reg(priv, 0xC6, 0x81);
+ }
+}
+
static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
- u8 r0, r1, r2, r3;
- u32 total_cnt, err_cnt;
+ u8 reg_err, reg_total, t;
+ u32 total_cnt = 0, err_cnt = 0;
+ int i;
dprintk("%s\n", __func__);
- lgs8gxx_write_reg(priv, 0xc6, 0x01);
- lgs8gxx_write_reg(priv, 0xc6, 0x41);
- lgs8gxx_write_reg(priv, 0xc6, 0x01);
-
+ packet_counter_start(priv);
msleep(200);
+ packet_counter_stop(priv);
+
+ if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+ reg_total = 0x28; reg_err = 0x2C;
+ } else {
+ reg_total = 0xD0; reg_err = 0xD4;
+ }
- lgs8gxx_write_reg(priv, 0xc6, 0x81);
- lgs8gxx_read_reg(priv, 0xd0, &r0);
- lgs8gxx_read_reg(priv, 0xd1, &r1);
- lgs8gxx_read_reg(priv, 0xd2, &r2);
- lgs8gxx_read_reg(priv, 0xd3, &r3);
- total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
- lgs8gxx_read_reg(priv, 0xd4, &r0);
- lgs8gxx_read_reg(priv, 0xd5, &r1);
- lgs8gxx_read_reg(priv, 0xd6, &r2);
- lgs8gxx_read_reg(priv, 0xd7, &r3);
- err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
+ for (i = 0; i < 4; i++) {
+ total_cnt <<= 8;
+ lgs8gxx_read_reg(priv, reg_total+3-i, &t);
+ total_cnt |= t;
+ }
+ for (i = 0; i < 4; i++) {
+ err_cnt <<= 8;
+ lgs8gxx_read_reg(priv, reg_err+3-i, &t);
+ err_cnt |= t;
+ }
dprintk("error=%d total=%d\n", err_cnt, total_cnt);
if (total_cnt == 0)
@@ -801,6 +1088,9 @@ struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
sizeof(struct dvb_frontend_ops));
priv->frontend.demodulator_priv = priv;
+ if (config->prod == LGS8GXX_PROD_LGS8G75)
+ lgs8g75_init_data(priv);
+
return &priv->frontend;
error_out:
diff --git a/drivers/media/dvb/frontends/lgs8gxx.h b/drivers/media/dvb/frontends/lgs8gxx.h
index 321d366a8307..33c3c5e162fa 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.h
+++ b/drivers/media/dvb/frontends/lgs8gxx.h
@@ -1,9 +1,9 @@
/*
- * Support for Legend Silicon DMB-TH demodulator
- * LGS8913, LGS8GL5
+ * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ * LGS8913, LGS8GL5, LGS8G75
* experimental support LGS8G42, LGS8G52
*
- * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
@@ -34,6 +34,7 @@
#define LGS8GXX_PROD_LGS8G42 3
#define LGS8GXX_PROD_LGS8G52 4
#define LGS8GXX_PROD_LGS8G54 5
+#define LGS8GXX_PROD_LGS8G75 6
struct lgs8gxx_config {
@@ -70,6 +71,10 @@ struct lgs8gxx_config {
/*IF use Negative center frequency*/
u8 if_neg_center;
+ /*8G75 internal ADC input range selection*/
+ /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
+ u8 adc_vpp;
+
/* slave address and configuration of the tuner */
u8 tuner_address;
};
diff --git a/drivers/media/dvb/frontends/lgs8gxx_priv.h b/drivers/media/dvb/frontends/lgs8gxx_priv.h
index 9776d30686dc..8ef376f1414d 100644
--- a/drivers/media/dvb/frontends/lgs8gxx_priv.h
+++ b/drivers/media/dvb/frontends/lgs8gxx_priv.h
@@ -1,9 +1,9 @@
/*
- * Support for Legend Silicon DMB-TH demodulator
- * LGS8913, LGS8GL5
+ * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ * LGS8913, LGS8GL5, LGS8G75
* experimental support LGS8G42, LGS8G52
*
- * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
*
@@ -38,7 +38,7 @@ struct lgs8gxx_state {
#define SC_QAM64 0x10 /* 64QAM modulation */
#define SC_QAM32 0x0C /* 32QAM modulation */
#define SC_QAM16 0x08 /* 16QAM modulation */
-#define SC_QAM4NR 0x04 /* 4QAM modulation */
+#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */
#define SC_QAM4 0x00 /* 4QAM modulation */
#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */
@@ -47,8 +47,8 @@ struct lgs8gxx_state {
#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */
#define TIM_MASK 0x20 /* Time Interleave Length Mask */
-#define TIM_LONG 0x00 /* Time Interleave Length = 720 */
-#define TIM_MIDDLE 0x20 /* Time Interleave Length = 240 */
+#define TIM_LONG 0x20 /* Time Interleave Length = 720 */
+#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */
#define CF_MASK 0x80 /* Control Frame Mask */
#define CF_EN 0x80 /* Control Frame On */
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index a621f727935f..071328d7b859 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -85,7 +85,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
int i;
dprintk("R(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
- printk(" %02x", buf[i]);
+ printk(KERN_CONT " %02x", buf[i]);
printk("\n");
}
@@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
int i;
dprintk("W(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
- printk(" %02x", src[i]);
+ printk(KERN_CONT " %02x", src[i]);
printk("\n");
}
@@ -744,7 +744,8 @@ static struct dvb_frontend_ops mt312_ops = {
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
- .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
+ /* FIXME: adjust freq to real used xtal */
+ .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
.symbol_rate_max = MT312_SYS_CLK / 2,
.caps =
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 1da045fbb4ef..3bde3324a032 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -230,8 +230,8 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5c);
stv0900_write_reg(i_params, R0900_P1_TNRCFG, 0x6c);
stv0900_write_reg(i_params, R0900_P2_TNRCFG, 0x6f);
- stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x24);
- stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x24);
+ stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x20);
+ stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x20);
stv0900_write_reg(i_params, R0900_NCOARSE, 0x13);
msleep(3);
stv0900_write_reg(i_params, R0900_I2CCFG, 0x08);
@@ -370,8 +370,8 @@ static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
u32 fi2c;
dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
- if (enable)
- stv0900_write_bits(i_params, fi2c, 1);
+
+ stv0900_write_bits(i_params, fi2c, enable);
return 0;
}
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index a5a31536cbcb..962fde1437ce 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -1721,7 +1721,7 @@ static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_front
s32 srate, demod_timeout,
fec_timeout, freq1, freq0;
- enum fe_stv0900_signal_type signal_type = STV0900_NODATA;;
+ enum fe_stv0900_signal_type signal_type = STV0900_NODATA;
switch (demod) {
case STV0900_DEMOD_1:
diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c
index 70efac869d28..dcf1b21ea974 100644
--- a/drivers/media/dvb/frontends/stv6110.c
+++ b/drivers/media/dvb/frontends/stv6110.c
@@ -36,6 +36,7 @@ struct stv6110_priv {
struct i2c_adapter *i2c;
u32 mclk;
+ u8 clk_div;
u8 regs[8];
};
@@ -100,35 +101,25 @@ static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
struct stv6110_priv *priv = fe->tuner_priv;
int rc;
u8 reg[] = { start };
- struct i2c_msg msg_wr = {
- .addr = priv->i2c_address,
- .flags = 0,
- .buf = reg,
- .len = 1,
+ struct i2c_msg msg[] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = reg,
+ .len = 1,
+ }, {
+ .addr = priv->i2c_address,
+ .flags = I2C_M_RD,
+ .buf = regs,
+ .len = len,
+ },
};
- struct i2c_msg msg_rd = {
- .addr = priv->i2c_address,
- .flags = I2C_M_RD,
- .buf = regs,
- .len = len,
- };
- /* write subaddr */
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- rc = i2c_transfer(priv->i2c, &msg_wr, 1);
- if (rc != 1)
- dprintk("%s: i2c error\n", __func__);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- /* read registers */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- rc = i2c_transfer(priv->i2c, &msg_rd, 1);
- if (rc != 1)
+ rc = i2c_transfer(priv->i2c, msg, 2);
+ if (rc != 2)
dprintk("%s: i2c error\n", __func__);
if (fe->ops.i2c_gate_ctrl)
@@ -221,6 +212,10 @@ static int stv6110_init(struct dvb_frontend *fe)
priv->regs[RSTV6110_CTRL1] |=
((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
+ /* divisor value for the output clock */
+ priv->regs[RSTV6110_CTRL2] &= ~0xc0;
+ priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6);
+
stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
msleep(1);
stv6110_set_bandwidth(fe, 72000000);
@@ -418,6 +413,10 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
};
int ret;
+ /* divisor value for the output clock */
+ reg0[2] &= ~0xc0;
+ reg0[2] |= (config->clk_div << 6);
+
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -436,6 +435,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
priv->i2c_address = config->i2c_address;
priv->i2c = i2c;
priv->mclk = config->mclk;
+ priv->clk_div = config->clk_div;
memcpy(&priv->regs, &reg0[1], 8);
diff --git a/drivers/media/dvb/frontends/stv6110.h b/drivers/media/dvb/frontends/stv6110.h
index 1c0314d6aa55..9db2402410f6 100644
--- a/drivers/media/dvb/frontends/stv6110.h
+++ b/drivers/media/dvb/frontends/stv6110.h
@@ -41,7 +41,7 @@
struct stv6110_config {
u8 i2c_address;
u32 mclk;
- int iq_wiring;
+ u8 clk_div; /* divisor value for the output clock */
};
#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
index e22a0b381dc4..4e814ff22b23 100644
--- a/drivers/media/dvb/frontends/zl10036.c
+++ b/drivers/media/dvb/frontends/zl10036.c
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/dvb/frontend.h>
-#include <asm/types.h>
+#include <linux/types.h>
#include "zl10036.h"
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 148b6f7f6cb2..66f5c1fb3074 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -98,7 +98,6 @@ static int zl10353_read_register(struct zl10353_state *state, u8 reg)
static void zl10353_dump_regs(struct dvb_frontend *fe)
{
struct zl10353_state *state = fe->demodulator_priv;
- char buf[52], buf2[4];
int ret;
u8 reg;
@@ -106,19 +105,18 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
for (reg = 0; ; reg++) {
if (reg % 16 == 0) {
if (reg)
- printk(KERN_DEBUG "%s\n", buf);
- sprintf(buf, "%02x: ", reg);
+ printk(KERN_CONT "\n");
+ printk(KERN_DEBUG "%02x:", reg);
}
ret = zl10353_read_register(state, reg);
if (ret >= 0)
- sprintf(buf2, "%02x ", (u8)ret);
+ printk(KERN_CONT " %02x", (u8)ret);
else
- strcpy(buf2, "-- ");
- strcat(buf, buf2);
+ printk(KERN_CONT " --");
if (reg == 0xff)
break;
}
- printk(KERN_DEBUG "%s\n", buf);
+ printk(KERN_CONT "\n");
}
static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index a246903c3341..a36bb9970aeb 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1367,7 +1367,7 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
&msg, sizeof(msg));
}
-/* new GPIO managment implementation */
+/* new GPIO management implementation */
static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
u32 *pGroupNum, u32 *pGroupCfg) {
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index f1108c64e895..eec18aaf5512 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -657,12 +657,12 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
extern void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
-/* old GPIO managment */
+/* old GPIO management */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_config_gpio *pinconfig);
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
-/* new GPIO managment */
+/* new GPIO management */
extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
struct smscore_gpio_config *pGpioConfig);
extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index ce64c6214cc4..8986d967d2f4 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -490,7 +490,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
if (!av7110->analog_tuner_flags)
return 0;
- if (input < 0 || input >= 4)
+ if (input >= 4)
return -EINVAL;
av7110->current_input = input;
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index d30fc0ce82c0..8b1440136c45 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -359,7 +359,8 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(v->card, "ADS Cadet", sizeof(v->card));
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
v->version = CADET_VERSION;
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
return 0;
}
@@ -372,7 +373,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
switch (v->index) {
case 0:
strlcpy(v->name, "FM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_STEREO;
+ v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
v->rangelow = 1400; /* 87.5 MHz */
v->rangehigh = 1728; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev);
@@ -386,6 +387,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
default:
break;
}
+ v->rxsubchans |= V4L2_TUNER_SUB_RDS;
break;
case 1:
strlcpy(v->name, "AM", sizeof(v->name));
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 575bf9d89419..a1239083472d 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -46,7 +46,7 @@
* Version 0.11: Converted to v4l2_device.
*
* Many things to do:
- * - Correct power managment of device (suspend & resume)
+ * - Correct power management of device (suspend & resume)
* - Add code for scanning and smooth tuning
* - Add code for sensitivity value
* - Correct mistakes
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index e85f318b4d2b..8e6dd84ed208 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -106,20 +106,24 @@
* Tobias Lorenz <tobias.lorenz@gmx.net>
* - add LED status output
* - get HW/SW version from scratchpad
+ * 2009-06-16 Edouard Lafargue <edouard@lafargue.name>
+ * Version 1.0.10
+ * - add support for interrupt mode for RDS endpoint,
+ * instead of polling.
+ * Improves RDS reception significantly
*
* ToDo:
* - add firmware download/update support
- * - RDS support: interrupt mode, instead of polling
*/
/* driver definitions */
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
#define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10)
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.9"
+#define DRIVER_VERSION "1.0.10"
/* kernel includes */
@@ -218,16 +222,6 @@ static unsigned short max_rds_errors = 1;
module_param(max_rds_errors, ushort, 0644);
MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
-/* RDS poll frequency */
-static unsigned int rds_poll_time = 40;
-/* 40 is used by the original USBRadio.exe */
-/* 50 is used by radio-cadet */
-/* 75 should be okay */
-/* 80 is the usual RDS receive interval */
-module_param(rds_poll_time, uint, 0644);
-MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
-
-
/**************************************************************************
* Register Definitions
@@ -450,6 +444,12 @@ struct si470x_device {
struct usb_interface *intf;
struct video_device *videodev;
+ /* Interrupt endpoint handling */
+ char *int_in_buffer;
+ struct usb_endpoint_descriptor *int_in_endpoint;
+ struct urb *int_in_urb;
+ int int_in_running;
+
/* driver management */
unsigned int users;
unsigned char disconnected;
@@ -459,7 +459,6 @@ struct si470x_device {
unsigned short registers[RADIO_REGISTER_NUM];
/* RDS receive buffer */
- struct delayed_work work;
wait_queue_head_t read_queue;
struct mutex lock; /* buffer locking */
unsigned char *buffer; /* size is always multiple of three */
@@ -865,43 +864,6 @@ static int si470x_get_all_registers(struct si470x_device *radio)
/**************************************************************************
- * General Driver Functions - RDS_REPORT
- **************************************************************************/
-
-/*
- * si470x_get_rds_registers - read rds registers
- */
-static int si470x_get_rds_registers(struct si470x_device *radio)
-{
- unsigned char buf[RDS_REPORT_SIZE];
- int retval;
- int size;
- unsigned char regnr;
-
- buf[0] = RDS_REPORT;
-
- retval = usb_interrupt_msg(radio->usbdev,
- usb_rcvintpipe(radio->usbdev, 1),
- (void *) &buf, sizeof(buf), &size, usb_timeout);
- if (size != sizeof(buf))
- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
- "return size differs: %d != %zu\n", size, sizeof(buf));
- if (retval < 0)
- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
- "usb_interrupt_msg returned %d\n", retval);
-
- if (retval >= 0)
- for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
- radio->registers[STATUSRSSI + regnr] =
- get_unaligned_be16(
- &buf[regnr * RADIO_REGISTER_SIZE + 1]);
-
- return (retval < 0) ? -EINVAL : 0;
-}
-
-
-
-/**************************************************************************
* General Driver Functions - LED_REPORT
**************************************************************************/
@@ -959,102 +921,118 @@ static int si470x_get_scratch_page_versions(struct si470x_device *radio)
**************************************************************************/
/*
- * si470x_rds - rds processing function
+ * si470x_int_in_callback - rds callback and processing function
+ *
+ * TODO: do we need to use mutex locks in some sections?
*/
-static void si470x_rds(struct si470x_device *radio)
+static void si470x_int_in_callback(struct urb *urb)
{
+ struct si470x_device *radio = urb->context;
+ unsigned char buf[RDS_REPORT_SIZE];
+ int retval;
+ unsigned char regnr;
unsigned char blocknum;
unsigned short bler; /* rds block errors */
unsigned short rds;
unsigned char tmpbuf[3];
- /* get rds blocks */
- if (si470x_get_rds_registers(radio) < 0)
- return;
- if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
- /* No RDS group ready */
- return;
- }
- if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
- /* RDS decoder not synchronized */
- return;
- }
-
- /* copy all four RDS blocks to internal buffer */
- mutex_lock(&radio->lock);
- for (blocknum = 0; blocknum < 4; blocknum++) {
- switch (blocknum) {
- default:
- bler = (radio->registers[STATUSRSSI] &
- STATUSRSSI_BLERA) >> 9;
- rds = radio->registers[RDSA];
- break;
- case 1:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERB) >> 14;
- rds = radio->registers[RDSB];
- break;
- case 2:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERC) >> 12;
- rds = radio->registers[RDSC];
- break;
- case 3:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERD) >> 10;
- rds = radio->registers[RDSD];
- break;
- };
-
- /* Fill the V4L2 RDS buffer */
- put_unaligned_le16(rds, &tmpbuf);
- tmpbuf[2] = blocknum; /* offset name */
- tmpbuf[2] |= blocknum << 3; /* received offset */
- if (bler > max_rds_errors)
- tmpbuf[2] |= 0x80; /* uncorrectable errors */
- else if (bler > 0)
- tmpbuf[2] |= 0x40; /* corrected error(s) */
-
- /* copy RDS block to internal buffer */
- memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
- radio->wr_index += 3;
-
- /* wrap write pointer */
- if (radio->wr_index >= radio->buf_size)
- radio->wr_index = 0;
-
- /* check for overflow */
- if (radio->wr_index == radio->rd_index) {
- /* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
- radio->rd_index = 0;
+ if (urb->status) {
+ if (urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN) {
+ return;
+ } else {
+ printk(KERN_WARNING DRIVER_NAME
+ ": non-zero urb status (%d)\n", urb->status);
+ goto resubmit; /* Maybe we can recover. */
}
}
- mutex_unlock(&radio->lock);
-
- /* wake up read queue */
- if (radio->wr_index != radio->rd_index)
- wake_up_interruptible(&radio->read_queue);
-}
-
-
-/*
- * si470x_work - rds work function
- */
-static void si470x_work(struct work_struct *work)
-{
- struct si470x_device *radio = container_of(work, struct si470x_device,
- work.work);
/* safety checks */
if (radio->disconnected)
return;
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
- return;
+ goto resubmit;
+
+ if (urb->actual_length > 0) {
+ /* Update RDS registers with URB data */
+ buf[0] = RDS_REPORT;
+ for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+ radio->registers[STATUSRSSI + regnr] =
+ get_unaligned_be16(&radio->int_in_buffer[
+ regnr * RADIO_REGISTER_SIZE + 1]);
+ /* get rds blocks */
+ if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
+ /* No RDS group ready, better luck next time */
+ goto resubmit;
+ }
+ if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
+ /* RDS decoder not synchronized */
+ goto resubmit;
+ }
+ for (blocknum = 0; blocknum < 4; blocknum++) {
+ switch (blocknum) {
+ default:
+ bler = (radio->registers[STATUSRSSI] &
+ STATUSRSSI_BLERA) >> 9;
+ rds = radio->registers[RDSA];
+ break;
+ case 1:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERB) >> 14;
+ rds = radio->registers[RDSB];
+ break;
+ case 2:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERC) >> 12;
+ rds = radio->registers[RDSC];
+ break;
+ case 3:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERD) >> 10;
+ rds = radio->registers[RDSD];
+ break;
+ };
+
+ /* Fill the V4L2 RDS buffer */
+ put_unaligned_le16(rds, &tmpbuf);
+ tmpbuf[2] = blocknum; /* offset name */
+ tmpbuf[2] |= blocknum << 3; /* received offset */
+ if (bler > max_rds_errors)
+ tmpbuf[2] |= 0x80; /* uncorrectable errors */
+ else if (bler > 0)
+ tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+ /* copy RDS block to internal buffer */
+ memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
+ radio->wr_index += 3;
+
+ /* wrap write pointer */
+ if (radio->wr_index >= radio->buf_size)
+ radio->wr_index = 0;
+
+ /* check for overflow */
+ if (radio->wr_index == radio->rd_index) {
+ /* increment and wrap read pointer */
+ radio->rd_index += 3;
+ if (radio->rd_index >= radio->buf_size)
+ radio->rd_index = 0;
+ }
+ }
+ if (radio->wr_index != radio->rd_index)
+ wake_up_interruptible(&radio->read_queue);
+ }
- si470x_rds(radio);
- schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time));
+resubmit:
+ /* Resubmit if we're still running. */
+ if (radio->int_in_running && radio->usbdev) {
+ retval = usb_submit_urb(radio->int_in_urb, GFP_ATOMIC);
+ if (retval) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": resubmitting urb failed (%d)", retval);
+ radio->int_in_running = 0;
+ }
+ }
}
@@ -1076,8 +1054,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
/* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
si470x_rds_on(radio);
- schedule_delayed_work(&radio->work,
- msecs_to_jiffies(rds_poll_time));
}
/* block if no new data available */
@@ -1136,8 +1112,6 @@ static unsigned int si470x_fops_poll(struct file *file,
/* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
si470x_rds_on(radio);
- schedule_delayed_work(&radio->work,
- msecs_to_jiffies(rds_poll_time));
}
poll_wait(file, &radio->read_queue, pts);
@@ -1170,8 +1144,31 @@ static int si470x_fops_open(struct file *file)
if (radio->users == 1) {
/* start radio */
retval = si470x_start(radio);
- if (retval < 0)
+ if (retval < 0) {
+ usb_autopm_put_interface(radio->intf);
+ goto done;
+ }
+
+ /* initialize interrupt urb */
+ usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
+ usb_rcvintpipe(radio->usbdev,
+ radio->int_in_endpoint->bEndpointAddress),
+ radio->int_in_buffer,
+ le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
+ si470x_int_in_callback,
+ radio,
+ radio->int_in_endpoint->bInterval);
+
+ radio->int_in_running = 1;
+ mb();
+
+ retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_INFO DRIVER_NAME
+ ": submitting int urb failed (%d)\n", retval);
+ radio->int_in_running = 0;
usb_autopm_put_interface(radio->intf);
+ }
}
done:
@@ -1197,16 +1194,21 @@ static int si470x_fops_release(struct file *file)
mutex_lock(&radio->disconnect_lock);
radio->users--;
if (radio->users == 0) {
+ /* shutdown interrupt handler */
+ if (radio->int_in_running) {
+ radio->int_in_running = 0;
+ if (radio->int_in_urb)
+ usb_kill_urb(radio->int_in_urb);
+ }
+
if (radio->disconnected) {
video_unregister_device(radio->videodev);
+ kfree(radio->int_in_buffer);
kfree(radio->buffer);
kfree(radio);
goto unlock;
}
- /* stop rds reception */
- cancel_delayed_work_sync(&radio->work);
-
/* cancel read processes */
wake_up_interruptible(&radio->read_queue);
@@ -1240,31 +1242,6 @@ static const struct v4l2_file_operations si470x_fops = {
**************************************************************************/
/*
- * si470x_v4l2_queryctrl - query control
- */
-static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
- .default_value = 15,
- },
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
-};
-
-
-/*
* si470x_vidioc_querycap - query device capabilities
*/
static int si470x_vidioc_querycap(struct file *file, void *priv,
@@ -1277,7 +1254,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info));
capability->version = DRIVER_KERNEL_VERSION;
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
- V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
return 0;
}
@@ -1289,7 +1266,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
static int si470x_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
- unsigned char i = 0;
int retval = -EINVAL;
/* abort if qc->id is below V4L2_CID_BASE */
@@ -1297,12 +1273,11 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv,
goto done;
/* search video control */
- for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
- if (qc->id == si470x_v4l2_queryctrl[i].id) {
- memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
- retval = 0; /* found */
- break;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
}
/* disable unsupported base controls */
@@ -1438,7 +1413,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
/* driver constants */
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
- tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_RDS;
/* range limits */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
@@ -1464,6 +1440,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
else
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ /* If there is a reliable method of detecting an RDS channel,
+ then this code should check for that before setting this
+ RDS subchannel. */
+ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
/* mono/stereo selector */
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
@@ -1657,7 +1637,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct si470x_device *radio;
- int retval = 0;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i, int_end_size, retval = 0;
/* private data allocation and initialization */
radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
@@ -1672,11 +1654,45 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
+ iface_desc = intf->cur_altsetting;
+
+ /* Set up interrupt endpoint information. */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_IN) && ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
+ radio->int_in_endpoint = endpoint;
+ }
+ if (!radio->int_in_endpoint) {
+ printk(KERN_INFO DRIVER_NAME
+ ": could not find interrupt in endpoint\n");
+ retval = -EIO;
+ goto err_radio;
+ }
+
+ int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize);
+
+ radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL);
+ if (!radio->int_in_buffer) {
+ printk(KERN_INFO DRIVER_NAME
+ "could not allocate int_in_buffer");
+ retval = -ENOMEM;
+ goto err_radio;
+ }
+
+ radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!radio->int_in_urb) {
+ printk(KERN_INFO DRIVER_NAME "could not allocate int_in_urb");
+ retval = -ENOMEM;
+ goto err_intbuffer;
+ }
+
/* video device allocation and initialization */
radio->videodev = video_device_alloc();
if (!radio->videodev) {
retval = -ENOMEM;
- goto err_radio;
+ goto err_intbuffer;
}
memcpy(radio->videodev, &si470x_viddev_template,
sizeof(si470x_viddev_template));
@@ -1734,9 +1750,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->rd_index = 0;
init_waitqueue_head(&radio->read_queue);
- /* prepare rds work function */
- INIT_DELAYED_WORK(&radio->work, si470x_work);
-
/* register video device */
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (retval) {
@@ -1751,6 +1764,8 @@ err_all:
kfree(radio->buffer);
err_video:
video_device_release(radio->videodev);
+err_intbuffer:
+ kfree(radio->int_in_buffer);
err_radio:
kfree(radio);
err_initial:
@@ -1764,12 +1779,8 @@ err_initial:
static int si470x_usb_driver_suspend(struct usb_interface *intf,
pm_message_t message)
{
- struct si470x_device *radio = usb_get_intfdata(intf);
-
printk(KERN_INFO DRIVER_NAME ": suspending now...\n");
- cancel_delayed_work_sync(&radio->work);
-
return 0;
}
@@ -1779,16 +1790,8 @@ static int si470x_usb_driver_suspend(struct usb_interface *intf,
*/
static int si470x_usb_driver_resume(struct usb_interface *intf)
{
- struct si470x_device *radio = usb_get_intfdata(intf);
-
printk(KERN_INFO DRIVER_NAME ": resuming now...\n");
- mutex_lock(&radio->lock);
- if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS)
- schedule_delayed_work(&radio->work,
- msecs_to_jiffies(rds_poll_time));
- mutex_unlock(&radio->lock);
-
return 0;
}
@@ -1802,12 +1805,15 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
mutex_lock(&radio->disconnect_lock);
radio->disconnected = 1;
- cancel_delayed_work_sync(&radio->work);
usb_set_intfdata(intf, NULL);
if (radio->users == 0) {
/* set led to disconnect state */
si470x_set_led_state(radio, BLINK_ORANGE_LED);
+ /* Free data structures. */
+ usb_free_urb(radio->int_in_urb);
+
+ kfree(radio->int_in_buffer);
video_unregister_device(radio->videodev);
kfree(radio->buffer);
kfree(radio);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 84b6fc15519d..8460013a0020 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -493,6 +493,28 @@ config VIDEO_UPD64083
endmenu # encoder / decoder chips
+config DISPLAY_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Display"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ select VIDEO_ADV7343
+ select VIDEO_THS7303
+ help
+ Support for DaVinci based display device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called davincihd_display.
+
+config VIDEO_DAVINCI_VPIF
+ tristate "DaVinci VPIF Driver"
+ depends on DISPLAY_DAVINCI_DM646X_EVM
+ help
+ Support for DaVinci VPIF Driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif.
+
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -505,6 +527,55 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
+config VIDEO_VPSS_SYSTEM
+ tristate "VPSS System module driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for vpss system module for video driver
+ default y
+
+config VIDEO_VPFE_CAPTURE
+ tristate "VPFE Video Capture Driver"
+ depends on VIDEO_V4L2 && ARCH_DAVINCI
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for DMXXXX VPFE based frame grabber. This is the
+ common V4L2 module for following DMXXX SoCs from Texas
+ Instruments:- DM6446 & DM355.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+ tristate "DM6446 CCDC HW module"
+ depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from slave decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+ tristate "DM355 CCDC HW module"
+ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from a slave decoders
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_PMS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9f2e3214a482..00fb23e64374 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -154,12 +154,16 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 30f5caf5dda5..df26f2fe44eb 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
-#include <linux/version.h>
#include <media/adv7343.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 14baffc22192..b8a4b52e8d47 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -151,7 +151,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
dprintk(2, "%s()\n", __func__);
if (dev->urb_streaming) {
- dprintk(2, "%s: iso xfer already running!\n", __func__);
+ dprintk(2, "%s: bulk xfer already running!\n", __func__);
return 0;
}
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 13e494365e70..cbdb65c34f21 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -320,7 +320,6 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
static struct i2c_adapter au0828_i2c_adap_template = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
- .id = I2C_HW_B_AU0828,
.algo = &au0828_i2c_algo_template,
};
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index fdb4adff3d28..ca6558c394be 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3324,8 +3324,6 @@ void __devinit bttv_init_card1(struct bttv *btv)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
- int addr=ADDR_UNSET;
-
btv->tuner_type = UNSET;
if (BTTV_BOARD_UNKNOWN == btv->c.type) {
@@ -3470,9 +3468,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->pll.pll_current = -1;
/* tuner configuration (from card list / autodetect / insmod option) */
- if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
- addr = bttv_tvcards[btv->c.type].tuner_addr;
-
if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
if (UNSET == btv->tuner_type)
btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
@@ -3496,40 +3491,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (UNSET == btv->tuner_type)
btv->tuner_type = TUNER_ABSENT;
- if (btv->tuner_type != TUNER_ABSENT) {
- struct tuner_setup tun_setup;
-
- /* Load tuner module before issuing tuner config call! */
- if (bttv_tvcards[btv->c.type].has_radio)
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_RADIO));
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
- v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
- v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
-
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = btv->tuner_type;
- tun_setup.addr = addr;
-
- if (bttv_tvcards[btv->c.type].has_radio)
- tun_setup.mode_mask |= T_RADIO;
-
- bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
- }
-
- if (btv->tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &btv->tda9887_conf;
-
- bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
- }
-
btv->dig = bttv_tvcards[btv->c.type].has_dig_in ?
bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET;
btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ?
@@ -3540,15 +3501,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_remote = remote[btv->c.nr];
if (bttv_tvcards[btv->c.type].has_radio)
- btv->has_radio=1;
+ btv->has_radio = 1;
if (bttv_tvcards[btv->c.type].has_remote)
- btv->has_remote=1;
+ btv->has_remote = 1;
if (!bttv_tvcards[btv->c.type].no_gpioirq)
- btv->gpioirq=1;
+ btv->gpioirq = 1;
if (bttv_tvcards[btv->c.type].volume_gpio)
- btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
+ btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio;
if (bttv_tvcards[btv->c.type].audio_mode_gpio)
- btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
+ btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio;
if (btv->tuner_type == TUNER_ABSENT)
return; /* no tuner or related drivers to load */
@@ -3666,6 +3627,49 @@ no_audio:
}
+/* initialize the tuner */
+void __devinit bttv_init_tuner(struct bttv *btv)
+{
+ int addr = ADDR_UNSET;
+
+ if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+ addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+ if (btv->tuner_type != TUNER_ABSENT) {
+ struct tuner_setup tun_setup;
+
+ /* Load tuner module before issuing tuner config call! */
+ if (bttv_tvcards[btv->c.type].has_radio)
+ v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tuner", "tuner",
+ v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tuner", "tuner",
+ v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tuner", "tuner",
+ v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = addr;
+
+ if (bttv_tvcards[btv->c.type].has_radio)
+ tun_setup.mode_mask |= T_RADIO;
+
+ bttv_call_all(btv, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (btv->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &btv->tda9887_conf;
+
+ bttv_call_all(btv, tuner, s_config, &tda9887_cfg);
+ }
+}
+
/* ----------------------------------------------------------------------- */
static void modtec_eeprom(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index d147d29bb0d3..939d1e512974 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2652,6 +2652,8 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
+ if (btv->has_saa6588)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
@@ -4419,6 +4421,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* some card-specific stuff (needs working i2c) */
bttv_init_card2(btv);
+ bttv_init_tuner(btv);
init_irqreg(btv);
/* register video4linux + input */
@@ -4592,14 +4595,10 @@ static int bttv_resume(struct pci_dev *pci_dev)
#endif
static struct pci_device_id bttv_pci_tbl[] = {
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
+ {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
{0,}
};
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index ebd1ee9dc871..beda363418b0 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -352,7 +352,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
/* bt878 */
strlcpy(btv->c.i2c_adap.name, "bt878",
sizeof(btv->c.i2c_adap.name));
- btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
btv->c.i2c_adap.algo = &bttv_algo;
} else {
/* bt848 */
@@ -362,7 +361,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
strlcpy(btv->c.i2c_adap.name, "bttv",
sizeof(btv->c.i2c_adap.name));
- btv->c.i2c_adap.id = I2C_HW_B_BT848;
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
sizeof(bttv_i2c_algo_bit_template));
btv->i2c_algo.udelay = i2c_udelay;
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3d36daf206f3..3ec2402c6b4a 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -283,6 +283,7 @@ extern struct tvcard bttv_tvcards[];
extern void bttv_idcard(struct bttv *btv);
extern void bttv_init_card1(struct bttv *btv);
extern void bttv_init_card2(struct bttv *btv);
+extern void bttv_init_tuner(struct bttv *btv);
/* card-specific funtions */
extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c4d181dde1ca..9c149a781294 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -490,7 +490,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
int ret;
cafe_smbus_enable_irq(cam);
- adap->id = I2C_HW_SMBUS_CAFE;
adap->owner = THIS_MODULE;
adap->algo = &cafe_smbus_algo;
strcpy(adap->name, "cafe_ccic");
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 36f2d76006fd..f11e47a58286 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -56,7 +56,8 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_CS5345,
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
- CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+ CX18_HW_Z8F0811_IR_HAUP,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -102,7 +103,8 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_CS5345,
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
- CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+ CX18_HW_Z8F0811_IR_HAUP,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
@@ -204,7 +206,7 @@ static const struct cx18_card cx18_card_mpc718 = {
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_GPIO_MUX,
- .hw_all = CX18_HW_418_AV | CX18_HW_TUNER |
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 3c552b6b7c4d..444e3c7c563e 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -22,13 +22,17 @@
*/
/* hardware flags */
-#define CX18_HW_TUNER (1 << 0)
-#define CX18_HW_TVEEPROM (1 << 1)
-#define CX18_HW_CS5345 (1 << 2)
-#define CX18_HW_DVB (1 << 3)
-#define CX18_HW_418_AV (1 << 4)
-#define CX18_HW_GPIO_MUX (1 << 5)
-#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
+#define CX18_HW_TUNER (1 << 0)
+#define CX18_HW_TVEEPROM (1 << 1)
+#define CX18_HW_CS5345 (1 << 2)
+#define CX18_HW_DVB (1 << 3)
+#define CX18_HW_418_AV (1 << 4)
+#define CX18_HW_GPIO_MUX (1 << 5)
+#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
+#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7)
+#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8)
+#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \
+ CX18_HW_Z8F0811_IR_TX_HAUP)
/* video inputs */
#define CX18_CARD_INPUT_VID_TUNER 1
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 5136df198338..93f0dae01350 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
+#include <linux/kernel.h>
#include "cx18-driver.h"
#include "cx18-cards.h"
@@ -317,7 +318,7 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
idx = p.audio_properties & 0x03;
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
- if (idx < sizeof(freqs))
+ if (idx < ARRAY_SIZE(freqs))
cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
return err;
}
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 92026e82e10e..dd0224f328ad 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -268,6 +268,20 @@ static void cx18_iounmap(struct cx18 *cx)
}
}
+static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
+{
+ int i;
+
+ CX18_INFO("eeprom dump:\n");
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ CX18_INFO("eeprom %02x:", i);
+ printk(KERN_CONT " %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk(KERN_CONT "\n");
+ }
+}
+
/* Hauppauge card? get values from tveeprom */
void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
{
@@ -279,8 +293,26 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
c.adapter = &cx->i2c_adap[0];
c.addr = 0xA0 >> 1;
- tveeprom_read(&c, eedata, sizeof(eedata));
- tveeprom_hauppauge_analog(&c, tv, eedata);
+ memset(tv, 0, sizeof(*tv));
+ if (tveeprom_read(&c, eedata, sizeof(eedata)))
+ return;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ tveeprom_hauppauge_analog(&c, tv, eedata);
+ break;
+ case CX18_CARD_YUAN_MPC718:
+ tv->model = 0x718;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
+ eedata[2], eedata[1], eedata[4], eedata[3]);
+ break;
+ default:
+ tv->model = 0xffffffff;
+ cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+ break;
+ }
}
static void cx18_process_eeprom(struct cx18 *cx)
@@ -298,6 +330,11 @@ static void cx18_process_eeprom(struct cx18 *cx)
case 74000 ... 74999:
cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
break;
+ case 0x718:
+ return;
+ case 0xffffffff:
+ CX18_INFO("Unknown EEPROM encoding\n");
+ return;
case 0:
CX18_ERR("Invalid EEPROM\n");
return;
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 29969c18949c..04d9c2508b86 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -690,7 +690,7 @@ int cx18_v4l2_open(struct file *filp)
int res;
struct video_device *video_dev = video_devdata(filp);
struct cx18_stream *s = video_get_drvdata(video_dev);
- struct cx18 *cx = s->cx;;
+ struct cx18 *cx = s->cx;
mutex_lock(&cx->serialize_lock);
if (cx18_init_on_first_open(cx)) {
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 8591e4fc359f..ba754e8056fb 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -28,6 +28,7 @@
#include "cx18-gpio.h"
#include "cx18-i2c.h"
#include "cx18-irq.h"
+#include <media/ir-kbd-i2c.h>
#define CX18_REG_I2C_1_WR 0xf15000
#define CX18_REG_I2C_1_RD 0xf15008
@@ -40,16 +41,20 @@
#define GETSDL_BIT 0x0008
#define CX18_CS5345_I2C_ADDR 0x4c
+#define CX18_Z8F0811_IR_TX_I2C_ADDR 0x70
+#define CX18_Z8F0811_IR_RX_I2C_ADDR 0x71
/* This array should match the CX18_HW_ defines */
static const u8 hw_addrs[] = {
- 0, /* CX18_HW_TUNER */
- 0, /* CX18_HW_TVEEPROM */
- CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
- 0, /* CX18_HW_DVB */
- 0, /* CX18_HW_418_AV */
- 0, /* CX18_HW_GPIO_MUX */
- 0, /* CX18_HW_GPIO_RESET_CTRL */
+ 0, /* CX18_HW_TUNER */
+ 0, /* CX18_HW_TVEEPROM */
+ CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */
+ 0, /* CX18_HW_DVB */
+ 0, /* CX18_HW_418_AV */
+ 0, /* CX18_HW_GPIO_MUX */
+ 0, /* CX18_HW_GPIO_RESET_CTRL */
+ CX18_Z8F0811_IR_TX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -62,6 +67,8 @@ static const u8 hw_bus[] = {
0, /* CX18_HW_418_AV */
0, /* CX18_HW_GPIO_MUX */
0, /* CX18_HW_GPIO_RESET_CTRL */
+ 0, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -73,6 +80,8 @@ static const char * const hw_modules[] = {
NULL, /* CX18_HW_418_AV */
NULL, /* CX18_HW_GPIO_MUX */
NULL, /* CX18_HW_GPIO_RESET_CTRL */
+ NULL, /* CX18_HW_Z8F0811_IR_TX_HAUP */
+ NULL, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
/* This array should match the CX18_HW_ defines */
@@ -84,8 +93,37 @@ static const char * const hw_devicenames[] = {
"cx23418_AV",
"gpio_mux",
"gpio_reset_ctrl",
+ "ir_tx_z8f0811_haup",
+ "ir_rx_z8f0811_haup",
};
+static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
+ u8 addr)
+{
+ struct i2c_board_info info;
+ struct IR_i2c_init_data ir_init_data;
+ unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, type, I2C_NAME_SIZE);
+
+ /* Our default information for ir-kbd-i2c.c to use */
+ switch (hw) {
+ case CX18_HW_Z8F0811_IR_RX_HAUP:
+ memset(&ir_init_data, 0, sizeof(struct IR_i2c_init_data));
+ ir_init_data.ir_codes = ir_codes_hauppauge_new;
+ ir_init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ ir_init_data.type = IR_TYPE_RC5;
+ ir_init_data.name = "CX23418 Z8F0811 Hauppauge";
+ info.platform_data = &ir_init_data;
+ break;
+ default:
+ break;
+ }
+
+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+}
+
int cx18_i2c_register(struct cx18 *cx, unsigned idx)
{
struct v4l2_subdev *sd;
@@ -115,11 +153,14 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return sd != NULL ? 0 : -1;
}
+ if (hw & CX18_HW_Z8F0811_IR_HAUP)
+ return cx18_i2c_new_ir(adap, hw, type, hw_addrs[idx]);
+
/* Is it not an I2C device or one we do not wish to register? */
if (!hw_addrs[idx])
return -1;
- /* It's an I2C device other than an analog tuner */
+ /* It's an I2C device other than an analog tuner or IR chip */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
if (sd != NULL)
sd->grp_id = hw;
@@ -190,7 +231,6 @@ static int cx18_getsda(void *data)
/* template for i2c-bit-algo */
static struct i2c_adapter cx18_i2c_adap_template = {
.name = "cx18 i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = NULL, /* set by i2c-algo-bit */
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index d7b1921e6666..fc76e4d6ffa7 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -605,7 +605,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
if (ret)
return ret;
- if (inp < 0 || inp >= cx->nof_inputs)
+ if (inp >= cx->nof_inputs)
return -EINVAL;
if (inp == cx->active_input) {
diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c
index 33219dc4d649..58d9cc0867b9 100644
--- a/drivers/media/video/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/video/cx231xx/cx231xx-i2c.c
@@ -432,7 +432,6 @@ static struct i2c_algorithm cx231xx_algo = {
static struct i2c_adapter cx231xx_adap_template = {
.owner = THIS_MODULE,
.name = "cx231xx",
- .id = I2C_HW_B_CX231XX,
.algo = &cx231xx_algo,
};
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 609bae6098d3..36503725d973 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -923,8 +923,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;;
+ f->fmt.pix.pixelformat = dev->format->fourcc;
+ f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index 08582e58bdbf..0316257b7345 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -443,6 +443,7 @@ int netup_ci_init(struct cx23885_tsport *port)
goto err;
INIT_WORK(&state->work, netup_read_ci_status);
+ schedule_work(&state->work);
ci_dbg_print("%s: CI initialized!\n", __func__);
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 428f0c45e6b7..6c3b51ce3372 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -58,7 +58,8 @@ MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
#define dprintk(level, fmt, arg...)\
do { if (v4l_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\
+ printk(KERN_DEBUG "%s: " fmt, \
+ (dev) ? dev->name : "cx23885[?]", ## arg); \
} while (0)
static struct cx23885_tvnorm cx23885_tvnorms[] = {
@@ -629,6 +630,39 @@ int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
return retval;
}
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Set the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val |= (mask & 0x000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+ u32 val;
+
+ /* Clear the gpio value */
+ mc417_register_read(dev, 0x900C, &val);
+ val &= ~(mask & 0x0000ffff);
+ mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+ u32 val;
+
+ /* Enable GPIO direction bits */
+ mc417_register_read(dev, 0x9020, &val);
+ if (asoutput)
+ val |= (mask & 0x0000ffff);
+ else
+ val &= ~(mask & 0x0000ffff);
+
+ mc417_register_write(dev, 0x9020, val);
+}
/* ------------------------------------------------------------------ */
/* MPEG encoder API */
@@ -954,25 +988,8 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
IVTV_CMD_HW_BLOCKS_RST);
- /* Restore GPIO settings, make sure EIO14 is enabled as an output. */
- dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
- __func__, gpio_output);
- /* Power-up seems to have GPIOs AFU. This was causing digital side
- * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
- * power-up.
- * gpio_output |= (1<<14);
- */
- /* Note: GPIO14 is specific to the HVR1800 here */
- gpio_output = 0x10ff0411 | (1<<14);
- retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
- dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
- __func__, gpio_output);
-
- dprintk(1, "%s: GPIO value EIO 0-15 was = 0x%x\n",
- __func__, value);
- value |= (1<<14);
- dprintk(1, "%s: GPIO value EIO 0-15 now = 0x%x\n",
- __func__, value);
+ /* F/W power up disturbs the GPIOs, restore state */
+ retval |= mc417_register_write(dev, 0x9020, gpio_output);
retval |= mc417_register_write(dev, 0x900C, value);
retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
@@ -1677,6 +1694,7 @@ static struct v4l2_file_operations mpeg_fops = {
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
+ .ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1713,6 +1731,8 @@ static struct video_device cx23885_mpeg_template = {
.fops = &mpeg_fops,
.ioctl_ops = &mpeg_ioctl_ops,
.minor = -1,
+ .tvnorms = CX23885_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
void cx23885_417_unregister(struct cx23885_dev *dev)
@@ -1784,9 +1804,6 @@ int cx23885_417_register(struct cx23885_dev *dev)
return err;
}
- /* Initialize MC417 registers */
- cx23885_mc417_init(dev);
-
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
dev->name, dev->v4l_device->num);
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index ce29b5e34a11..3143d85ef31d 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -201,6 +201,15 @@ struct cx23885_board cx23885_boards[] = {
.name = "Mygica X8506 DMB-TH",
.portb = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
+ .name = "Magic-Pro ProHDTV Extreme 2",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1850] = {
+ .name = "Hauppauge WinTV-HVR1850",
+ .portb = CX23885_MPEG_ENCODER,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -324,6 +333,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x14f1,
.subdevice = 0x8651,
.card = CX23885_BOARD_MYGICA_X8506,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8657,
+ .card = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8541,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1850,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -483,8 +500,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
/* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
* DVB-T and MPEG2 HW Encoder */
break;
+ case 85021:
+ /* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM,
+ Dual channel ATSC and MPEG2 HW Encoder */
+ break;
default:
- printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n",
dev->name, tv.model);
break;
}
@@ -574,13 +596,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* CX23417 GPIO's */
/* EIO15 Zilog Reset */
/* EIO14 S5H1409/CX24227 Reset */
+ mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
+
+ /* Bring the demod and blaster out of reset */
+ mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+ mdelay(100);
/* Force the TDA8295A into reset and back */
- cx_set(GP0_IO, 0x00040004);
+ cx23885_gpio_enable(dev, GPIO_2, 1);
+ cx23885_gpio_set(dev, GPIO_2);
mdelay(20);
- cx_clear(GP0_IO, 0x00000004);
+ cx23885_gpio_clear(dev, GPIO_2);
mdelay(20);
- cx_set(GP0_IO, 0x00040004);
+ cx23885_gpio_set(dev, GPIO_2);
mdelay(20);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1200:
@@ -715,14 +747,45 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx23885_gpio_set(dev, GPIO_9);
break;
case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
/* GPIO-1 reset XC5000 */
- /* GPIO-2 reset LGS8GL5 */
+ /* GPIO-2 reset LGS8GL5 / LGS8G75 */
cx_set(GP0_IO, 0x00060000);
cx_clear(GP0_IO, 0x00000006);
mdelay(100);
cx_set(GP0_IO, 0x00060006);
mdelay(100);
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 Wake# */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 C_IR_TX */
+ /* GPIO-21 I2S DAT */
+ /* GPIO-22 I2S WCLK */
+ /* GPIO-23 I2S BCLK */
+ /* ALT GPIO: EXP GPIO LATCH */
+
+ /* CX23417 GPIO's */
+ /* GPIO-14 S5H1411/CX24228 Reset */
+ /* GPIO-13 EEPROM write protect */
+ mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+ /* Put the demod into reset and protect the eeprom */
+ mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+ mdelay(100);
+
+ /* Bring the demod out of reset */
+ mc417_gpio_set(dev, GPIO_14);
+ mdelay(100);
+
+ /* CX24228 GPIO */
+ /* Connected to IF / Mux */
+ break;
}
}
@@ -739,6 +802,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
/* FIXME: Implement me */
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
@@ -778,6 +842,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -827,6 +892,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_MYGICA_X8506:
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -844,6 +910,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index bf7bb1c412fb..40d438d7234d 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -713,12 +713,26 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
dev->hwrevision = 0xa1;
break;
case 0x02:
- /* CX23885-13Z */
+ /* CX23885-13Z/14Z */
dev->hwrevision = 0xb0;
break;
case 0x03:
- /* CX23888-22Z */
- dev->hwrevision = 0xc0;
+ if (dev->pci->device == 0x8880) {
+ /* CX23888-21Z/22Z */
+ dev->hwrevision = 0xc0;
+ } else {
+ /* CX23885-14Z */
+ dev->hwrevision = 0xa4;
+ }
+ break;
+ case 0x04:
+ if (dev->pci->device == 0x8880) {
+ /* CX23888-31Z */
+ dev->hwrevision = 0xd0;
+ } else {
+ /* CX23885-15Z, CX23888-31Z */
+ dev->hwrevision = 0xa5;
+ }
break;
case 0x0e:
/* CX23887-15Z */
@@ -756,6 +770,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
/* Configure the internal memory */
if (dev->pci->device == 0x8880) {
+ /* Could be 887 or 888, assume a default */
dev->bridge = CX23885_BRIDGE_887;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 25000000;
@@ -868,6 +883,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
__func__, dev->radio_type, dev->radio_addr);
+ /* The cx23417 encoder has GPIO's that need to be initialised
+ * before DVB, so that demodulators and tuners are out of
+ * reset before DVB uses them.
+ */
+ if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
+ (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+ cx23885_mc417_init(dev);
+
/* init hardware */
cx23885_reset(dev);
@@ -1250,6 +1273,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
switch (dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
+ case CX23885_BRIDGE_888:
/* enable irqs */
dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 86ac529e62be..022fad798fc2 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -396,7 +396,7 @@ static struct stv0900_reg stv0900_ts_regs[] = {
static struct stv0900_config netup_stv0900_config = {
.demod_address = 0x68,
- .xtal = 27000000,
+ .xtal = 8000000,
.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
.diseqc_mode = 2,/* 2/3 PWM */
.ts_config_regs = stv0900_ts_regs,
@@ -408,14 +408,14 @@ static struct stv0900_config netup_stv0900_config = {
static struct stv6110_config netup_stv6110_tunerconfig_a = {
.i2c_address = 0x60,
- .mclk = 27000000,
- .iq_wiring = 0,
+ .mclk = 16000000,
+ .clk_div = 1,
};
static struct stv6110_config netup_stv6110_tunerconfig_b = {
.i2c_address = 0x63,
- .mclk = 27000000,
- .iq_wiring = 1,
+ .mclk = 16000000,
+ .clk_div = 1,
};
static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -487,6 +487,26 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
port->set_frontend_save(fe, param) : -ENODEV;
}
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x19,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 1,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 6500, /* 6.50 MHz */
+ .if_neg_center = 1,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 2, /* 1.6 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6500,
+};
+
static int dvb_register(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
@@ -833,6 +853,30 @@ static int dvb_register(struct cx23885_tsport *port)
&mygica_x8506_xc5000_config);
}
break;
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &magicpro_prohdtve2_lgs8g75_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &magicpro_prohdtve2_xc5000_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &hcw_s5h1411_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL)
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_tda18271_config);
+ break;
+
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 384dec34134f..4172cb387420 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -283,7 +283,6 @@ static struct i2c_algorithm cx23885_i2c_algo_template = {
static struct i2c_adapter cx23885_i2c_adap_template = {
.name = "cx23885",
.owner = THIS_MODULE,
- .id = I2C_HW_B_CX23885,
.algo = &cx23885_i2c_algo_template,
};
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 214a55e943b7..86f26947bb78 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -76,6 +76,8 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1255 20
#define CX23885_BOARD_HAUPPAUGE_HVR1210 21
#define CX23885_BOARD_MYGICA_X8506 22
+#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23
+#define CX23885_BOARD_HAUPPAUGE_HVR1850 24
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -87,6 +89,12 @@
#define GPIO_7 0x00000080
#define GPIO_8 0x00000100
#define GPIO_9 0x00000200
+#define GPIO_10 0x00000400
+#define GPIO_11 0x00000800
+#define GPIO_12 0x00001000
+#define GPIO_13 0x00002000
+#define GPIO_14 0x00004000
+#define GPIO_15 0x00008000
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -331,6 +339,7 @@ struct cx23885_dev {
CX23885_BRIDGE_UNDEFINED = 0,
CX23885_BRIDGE_885 = 885,
CX23885_BRIDGE_887 = 887,
+ CX23885_BRIDGE_888 = 888,
} bridge;
/* Analog video */
@@ -395,7 +404,7 @@ struct sram_channel {
u32 cmds_start;
u32 ctrl_start;
u32 cdt;
- u32 fifo_start;;
+ u32 fifo_start;
u32 fifo_size;
u32 ptr1_reg;
u32 ptr2_reg;
@@ -504,6 +513,9 @@ extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
extern void cx23885_mc417_init(struct cx23885_dev *dev);
extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 0be51b65f098..1aeaf18a9bea 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -321,6 +321,15 @@ static void cx23885_initialize(struct i2c_client *client)
/* Select AFE clock pad output source */
cx25840_write(client, 0x144, 0x05);
+ /* Drive GPIO2 direction and values for HVR1700
+ * where an onboard mux selects the output of demodulator
+ * vs the 417. Failure to set this results in no DTV.
+ * It's safe to set this across all Hauppauge boards
+ * currently, regardless of the board type.
+ */
+ cx25840_write(client, 0x160, 0x1d);
+ cx25840_write(client, 0x164, 0x00);
+
/* Do the firmware load in a work handler to prevent.
Otherwise the kernel is blocked waiting for the
bit-banging i2c interface to finish uploading the
@@ -1578,12 +1587,6 @@ static int cx25840_probe(struct i2c_client *client,
state->id = id;
state->rev = device_id;
- if (state->is_cx23885) {
- /* Drive GPIO2 direction and values */
- cx25840_write(client, 0x160, 0x1d);
- cx25840_write(client, 0x164, 0x00);
- }
-
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 0df53b0d75d9..2a535d0403ed 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -98,9 +98,14 @@ int cx25840_loadfw(struct i2c_client *client)
const u8 *ptr;
int size, retval;
int MAX_BUF_SIZE = FWSEND;
+ u32 gpio_oe = 0, gpio_da = 0;
- if (state->is_cx23885)
+ if (state->is_cx23885) {
firmware = FWFILE_CX23885;
+ /* Preserve the GPIO OE and output bits */
+ gpio_oe = cx25840_read(client, 0x160);
+ gpio_da = cx25840_read(client, 0x164);
+ }
else if (state->is_cx231xx)
firmware = FWFILE_CX231XX;
@@ -142,5 +147,11 @@ int cx25840_loadfw(struct i2c_client *client)
size = fw->size;
release_firmware(fw);
+ if (state->is_cx23885) {
+ /* Restore GPIO configuration after f/w load */
+ cx25840_write(client, 0x160, gpio_oe);
+ cx25840_write(client, 0x164, gpio_da);
+ }
+
return check_fw_load(client, size);
}
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 356d6896da3f..fbdc1cde56a6 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1371,7 +1371,7 @@ static struct cx8802_driver cx8802_blackbird_driver = {
.advise_release = cx8802_blackbird_advise_release,
};
-static int blackbird_init(void)
+static int __init blackbird_init(void)
{
printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -1384,7 +1384,7 @@ static int blackbird_init(void)
return cx8802_register_driver(&cx8802_blackbird_driver);
}
-static void blackbird_fini(void)
+static void __exit blackbird_fini(void)
{
cx8802_unregister_driver(&cx8802_blackbird_driver);
}
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index c44e87600219..973aaa199a6a 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1349,7 +1349,7 @@ static struct cx8802_driver cx8802_dvb_driver = {
.advise_release = cx8802_dvb_advise_release,
};
-static int dvb_init(void)
+static int __init dvb_init(void)
{
printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -1362,7 +1362,7 @@ static int dvb_init(void)
return cx8802_register_driver(&cx8802_dvb_driver);
}
-static void dvb_fini(void)
+static void __exit dvb_fini(void)
{
cx8802_unregister_driver(&cx8802_dvb_driver);
}
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index da4e3912cd37..de9ff0fc741f 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -116,6 +116,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
break;
case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* Enable MPEG parallel IO and video signal pins */
+ cx_write(MO_PINMUX_IO, 0x88);
+ cx_write(TS_SOP_STAT, 0);
+ cx_write(TS_VALERR_CNTRL, 0);
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
/* Enable MPEG parallel IO and video signal pins */
@@ -866,7 +870,7 @@ static struct pci_driver cx8802_pci_driver = {
.remove = __devexit_p(cx8802_remove),
};
-static int cx8802_init(void)
+static int __init cx8802_init(void)
{
printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -879,7 +883,7 @@ static int cx8802_init(void)
return pci_register_driver(&cx8802_pci_driver);
}
-static void cx8802_fini(void)
+static void __exit cx8802_fini(void)
{
pci_unregister_driver(&cx8802_pci_driver);
}
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 2bb54c3ef5cd..bdd1d8acbbbd 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -2113,7 +2113,7 @@ static struct pci_driver cx8800_pci_driver = {
#endif
};
-static int cx8800_init(void)
+static int __init cx8800_init(void)
{
printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -2126,7 +2126,7 @@ static int cx8800_init(void)
return pci_register_driver(&cx8800_pci_driver);
}
-static void cx8800_fini(void)
+static void __exit cx8800_fini(void)
{
pci_unregister_driver(&cx8800_pci_driver);
}
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile
new file mode 100644
index 000000000000..f44cad2f5412
--- /dev/null
+++ b/drivers/media/video/davinci/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the davinci video device drivers.
+#
+
+# VPIF
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o
+
+#DM646x EVM Display driver
+obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o
+
+# Capture: DM6446 and DM355
+obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
+obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
+obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
+obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/video/davinci/ccdc_hw_device.h
new file mode 100644
index 000000000000..86b9b3518965
--- /dev/null
+++ b/drivers/media/video/davinci/ccdc_hw_device.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * ccdc device API
+ */
+#ifndef _CCDC_HW_DEVICE_H
+#define _CCDC_HW_DEVICE_H
+
+#ifdef __KERNEL__
+#include <linux/videodev2.h>
+#include <linux/device.h>
+#include <media/davinci/vpfe_types.h>
+#include <media/davinci/ccdc_types.h>
+
+/*
+ * ccdc hw operations
+ */
+struct ccdc_hw_ops {
+ /* Pointer to initialize function to initialize ccdc device */
+ int (*open) (struct device *dev);
+ /* Pointer to deinitialize function */
+ int (*close) (struct device *dev);
+ /* set ccdc base address */
+ void (*set_ccdc_base)(void *base, int size);
+ /* Pointer to function to enable or disable ccdc */
+ void (*enable) (int en);
+ /* reset sbl. only for 6446 */
+ void (*reset) (void);
+ /* enable output to sdram */
+ void (*enable_out_to_sdram) (int en);
+ /* Pointer to function to set hw parameters */
+ int (*set_hw_if_params) (struct vpfe_hw_if_param *param);
+ /* get interface parameters */
+ int (*get_hw_if_params) (struct vpfe_hw_if_param *param);
+ /*
+ * Pointer to function to set parameters. Used
+ * for implementing VPFE_S_CCDC_PARAMS
+ */
+ int (*set_params) (void *params);
+ /*
+ * Pointer to function to get parameter. Used
+ * for implementing VPFE_G_CCDC_PARAMS
+ */
+ int (*get_params) (void *params);
+ /* Pointer to function to configure ccdc */
+ int (*configure) (void);
+
+ /* Pointer to function to set buffer type */
+ int (*set_buftype) (enum ccdc_buftype buf_type);
+ /* Pointer to function to get buffer type */
+ enum ccdc_buftype (*get_buftype) (void);
+ /* Pointer to function to set frame format */
+ int (*set_frame_format) (enum ccdc_frmfmt frm_fmt);
+ /* Pointer to function to get frame format */
+ enum ccdc_frmfmt (*get_frame_format) (void);
+ /* enumerate hw pix formats */
+ int (*enum_pix)(u32 *hw_pix, int i);
+ /* Pointer to function to set buffer type */
+ u32 (*get_pixel_format) (void);
+ /* Pointer to function to get pixel format. */
+ int (*set_pixel_format) (u32 pixfmt);
+ /* Pointer to function to set image window */
+ int (*set_image_window) (struct v4l2_rect *win);
+ /* Pointer to function to set image window */
+ void (*get_image_window) (struct v4l2_rect *win);
+ /* Pointer to function to get line length */
+ unsigned int (*get_line_length) (void);
+
+ /* Query CCDC control IDs */
+ int (*queryctrl)(struct v4l2_queryctrl *qctrl);
+ /* Set CCDC control */
+ int (*set_control)(struct v4l2_control *ctrl);
+ /* Get CCDC control */
+ int (*get_control)(struct v4l2_control *ctrl);
+
+ /* Pointer to function to set frame buffer address */
+ void (*setfbaddr) (unsigned long addr);
+ /* Pointer to function to get field id */
+ int (*getfid) (void);
+};
+
+struct ccdc_hw_device {
+ /* ccdc device name */
+ char name[32];
+ /* module owner */
+ struct module *owner;
+ /* hw ops */
+ struct ccdc_hw_ops hw_ops;
+};
+
+/* Used by CCDC module to register & unregister with vpfe capture driver */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev);
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev);
+
+#endif
+#endif
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
new file mode 100644
index 000000000000..4629cabe3f28
--- /dev/null
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * CCDC hardware module for DM355
+ * ------------------------------
+ *
+ * This module is for configuring DM355 CCD controller of VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application include dm355_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters
+ *
+ * TODO: 1) Raw bayer parameter settings and bayer capture
+ * 2) Split module parameter structure to module specific ioctl structs
+ * 3) add support for lense shading correction
+ * 4) investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <media/davinci/dm355_ccdc.h>
+#include <media/davinci/vpss.h>
+#include "dm355_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM355");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct device *dev;
+
+/* Object for CCDC raw mode */
+static struct ccdc_params_raw ccdc_hw_params_raw = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .gain = {
+ .r_ye = 256,
+ .gb_g = 256,
+ .gr_cy = 256,
+ .b_mg = 256
+ },
+ .config_params = {
+ .datasft = 2,
+ .data_sz = CCDC_DATA_10BITS,
+ .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
+ .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
+ .alaw = {
+ .gama_wd = 2,
+ },
+ .blk_clamp = {
+ .sample_pixel = 1,
+ .dc_sub = 25
+ },
+ .col_pat_field0 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ .col_pat_field1 = {
+ .olop = CCDC_GREEN_BLUE,
+ .olep = CCDC_BLUE,
+ .elop = CCDC_RED,
+ .elep = CCDC_GREEN_RED
+ },
+ },
+};
+
+
+/* Object for CCDC ycbcr mode */
+static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
+ .win = CCDC_WIN_PAL,
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+};
+
+static enum vpfe_hw_if_type ccdc_if_type;
+static void *__iomem ccdc_base_addr;
+static int ccdc_addr_size;
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_base_addr + offset);
+}
+
+static void ccdc_set_ccdc_base(void *addr, int size)
+{
+ ccdc_base_addr = addr;
+ ccdc_addr_size = size;
+}
+
+static void ccdc_enable(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
+ temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_enable_output_to_sdram(int en)
+{
+ unsigned int temp;
+ temp = regr(SYNCEN);
+ temp &= (~(CCDC_SYNCEN_WEN_MASK));
+ temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
+ regw(temp, SYNCEN);
+}
+
+static void ccdc_config_gain_offset(void)
+{
+ /* configure gain */
+ regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
+ regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
+ regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
+ regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
+ /* configure offset */
+ regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function restore power on defaults in the ccdc registers
+ */
+static int ccdc_restore_defaults(void)
+{
+ int i;
+
+ dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
+ /* set all registers to zero */
+ for (i = 0; i <= CCDC_REG_LAST; i += 4)
+ regw(0, i);
+
+ /* now override the values with power on defaults in registers */
+ regw(MODESET_DEFAULT, MODESET);
+ /* no culling support */
+ regw(CULH_DEFAULT, CULH);
+ regw(CULV_DEFAULT, CULV);
+ /* Set default Gain and Offset */
+ ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
+ ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
+ ccdc_config_gain_offset();
+ regw(OUTCLIP_DEFAULT, OUTCLIP);
+ regw(LSCCFG2_DEFAULT, LSCCFG2);
+ /* select ccdc input */
+ if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
+ dev_dbg(dev, "\ncouldn't select ccdc input source");
+ return -EFAULT;
+ }
+ /* select ccdc clock */
+ if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
+ dev_dbg(dev, "\ncouldn't enable ccdc clock");
+ return -EFAULT;
+ }
+ dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
+ return 0;
+}
+
+static int ccdc_open(struct device *device)
+{
+ dev = device;
+ return ccdc_restore_defaults();
+}
+
+static int ccdc_close(struct device *device)
+{
+ /* disable clock */
+ vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
+ /* do nothing for now */
+ return 0;
+}
+/*
+ * ccdc_setwin()
+ * This function will configure the window size to
+ * be capture in CCDC reg.
+ */
+static void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt, int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int mid_img = 0;
+
+ dev_dbg(dev, "\nStarting ccdc_setwin...");
+
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
+
+ /* Writing the horizontal info into the registers */
+ regw(horz_start, SPH);
+ regw(horz_nr_pixels, NPH);
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 and VDINT1 */
+ regw(vert_start, VDINT0);
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /* configure VDINT0 and VDINT1 */
+ mid_img = vert_start + (image_win->height / 2);
+ regw(vert_start, VDINT0);
+ regw(mid_img, VDINT1);
+ }
+ regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
+ regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
+ regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
+ dev_dbg(dev, "\nEnd of ccdc_setwin...");
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
+ ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
+ dev_dbg(dev, "Invalid value of data shift\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
+ ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
+ dev_dbg(dev, "Invalid value of median filter1\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
+ ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
+ dev_dbg(dev, "Invalid value of median filter2\n");
+ return -EINVAL;
+ }
+
+ if ((ccdcparam->med_filt_thres < 0) ||
+ (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
+ dev_dbg(dev, "Invalid value of median filter thresold\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
+ ccdcparam->data_sz > CCDC_DATA_8BITS) {
+ dev_dbg(dev, "Invalid value of data size\n");
+ return -EINVAL;
+ }
+
+ if (ccdcparam->alaw.enable) {
+ if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
+ ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
+ dev_dbg(dev, "Invalid value of ALAW\n");
+ return -EINVAL;
+ }
+ }
+
+ if (ccdcparam->blk_clamp.b_clamp_enable) {
+ if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
+ ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
+ dev_dbg(dev, "Invalid value of sample pixel\n");
+ return -EINVAL;
+ }
+ if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
+ ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
+ dev_dbg(dev, "Invalid value of sample lines\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ /* only raw module parameters can be set through the IOCTL */
+ if (ccdc_if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
+ "params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ memcpy(&ccdc_hw_params_raw.config_params,
+ &ccdc_raw_params,
+ sizeof(ccdc_raw_params));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* This function will configure CCDC for YCbCr video capture */
+static void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ u32 temp;
+
+ /* first set the CCDC power on defaults values in all registers */
+ dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ ccdc_restore_defaults();
+
+ /* configure pixel format & video frame format */
+ temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
+ CCDC_INPUT_MODE_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
+ CCDC_FRM_FMT_SHIFT));
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, REC656IF);
+ /*
+ * configure the FID, VD, HD pin polarity fld,hd pol positive,
+ * vd negative, 8-bit pack mode
+ */
+ temp |= CCDC_VD_POL_NEGATIVE;
+ } else { /* y/c external sync mode */
+ temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+
+ /* pack the data to 8-bit */
+ temp |= CCDC_DATA_PACK_ENABLE;
+
+ regw(temp, MODESET);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /* configure the order of y cb cr in SD-RAM */
+ temp = (params->pix_order << CCDC_Y8POS_SHIFT);
+ temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
+ regw(temp, CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This is done by rounding up
+ * width to a multiple of 16 pixels and multiply by two to account for
+ * y:cb:cr 4:2:2 data
+ */
+ regw(((params->win.width * 2 + 31) >> 5), HSIZE);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
+ }
+
+ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+}
+
+/*
+ * ccdc_config_black_clamp()
+ * configure parameters for Optical Black Clamp
+ */
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->b_clamp_enable) {
+ /* configure DCSub */
+ regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
+ regw(0x0000, CLAMP);
+ return;
+ }
+ /* Enable the Black clamping, set sample lines and pixels */
+ val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
+ regw(val, CLAMP);
+
+ /* If Black clamping is enable then make dcsub 0 */
+ val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
+ << CCDC_NUM_LINE_CALC_SHIFT;
+ regw(val, DCSUB);
+}
+
+/*
+ * ccdc_config_black_compense()
+ * configure parameters for Black Compensation
+ */
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = (bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT);
+ regw(val, BLKCMP1);
+
+ val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT);
+ regw(val, BLKCMP0);
+}
+
+/*
+ * ccdc_write_dfc_entry()
+ * write an entry in the dfc table.
+ */
+int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+{
+/* TODO This is to be re-visited and adjusted */
+#define DFC_WRITE_WAIT_COUNT 1000
+ u32 val, count = DFC_WRITE_WAIT_COUNT;
+
+ regw(dfc->dft_corr_vert[index], DFCMEM0);
+ regw(dfc->dft_corr_horz[index], DFCMEM1);
+ regw(dfc->dft_corr_sub1[index], DFCMEM2);
+ regw(dfc->dft_corr_sub2[index], DFCMEM3);
+ regw(dfc->dft_corr_sub3[index], DFCMEM4);
+ /* set WR bit to write */
+ val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
+ regw(val, DFCMEMCTL);
+
+ /*
+ * Assume, it is very short. If we get an error, we need to
+ * adjust this value
+ */
+ while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
+ count--;
+ /*
+ * TODO We expect the count to be non-zero to be successful. Adjust
+ * the count if write requires more time
+ */
+
+ if (count) {
+ dev_err(dev, "defect table write timeout !!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * ccdc_config_vdfc()
+ * configure parameters for Vertical Defect Correction
+ */
+static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
+{
+ u32 val;
+ int i;
+
+ /* Configure General Defect Correction. The table used is from IPIPE */
+ val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
+
+ /* Configure Vertical Defect Correction if needed */
+ if (!dfc->ver_dft_en) {
+ /* Enable only General Defect Correction */
+ regw(val, DFCCTL);
+ return 0;
+ }
+
+ if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
+ return -EINVAL;
+
+ val |= CCDC_DFCCTL_VDFC_DISABLE;
+ val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
+ CCDC_DFCCTL_VDFCSL_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
+ CCDC_DFCCTL_VDFCUDA_SHIFT;
+ val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
+ CCDC_DFCCTL_VDFLSFT_SHIFT;
+ regw(val , DFCCTL);
+
+ /* clear address ptr to offset 0 */
+ val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
+
+ /* write defect table entries */
+ for (i = 0; i < dfc->table_size; i++) {
+ /* increment address for non zero index */
+ if (i != 0)
+ val = CCDC_DFCMEMCTL_INC_ADDR;
+ regw(val, DFCMEMCTL);
+ if (ccdc_write_dfc_entry(i, dfc) < 0)
+ return -EFAULT;
+ }
+
+ /* update saturation level and enable dfc */
+ regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
+ val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
+ CCDC_DFCCTL_VDFCEN_SHIFT);
+ regw(val, DFCCTL);
+ return 0;
+}
+
+/*
+ * ccdc_config_csc()
+ * configure parameters for color space conversion
+ * Each register CSCM0-7 has two values in S8Q5 format.
+ */
+static void ccdc_config_csc(struct ccdc_csc *csc)
+{
+ u32 val1, val2;
+ int i;
+
+ if (!csc->enable)
+ return;
+
+ /* Enable the CSC sub-module */
+ regw(CCDC_CSC_ENABLE, CSCCTL);
+
+ /* Converting the co-eff as per the format of the register */
+ for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
+ if ((i % 2) == 0) {
+ /* CSCM - LSB */
+ val1 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ /*
+ * convert decimal part to binary. Use 2 decimal
+ * precision, user values range from .00 - 0.99
+ */
+ val1 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ } else {
+
+ /* CSCM - MSB */
+ val2 = (csc->coeff[i].integer &
+ CCDC_CSC_COEF_INTEG_MASK)
+ << CCDC_CSC_COEF_INTEG_SHIFT;
+ val2 |= (((csc->coeff[i].decimal &
+ CCDC_CSC_COEF_DECIMAL_MASK) *
+ CCDC_CSC_DEC_MAX) / 100);
+ val2 <<= CCDC_CSCM_MSB_SHIFT;
+ val2 |= val1;
+ regw(val2, (CSCM0 + ((i - 1) << 1)));
+ }
+ }
+}
+
+/*
+ * ccdc_config_color_patterns()
+ * configure parameters for color patterns
+ */
+static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
+ struct ccdc_col_pat *pat1)
+{
+ u32 val;
+
+ val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
+ (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
+ (pat1->elop << 12) | (pat1->elep << 14));
+ regw(val, COLPTN);
+}
+
+/* This function will configure CCDC for Raw mode image capture */
+static int ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int val;
+
+ dev_dbg(dev, "\nStarting ccdc_config_raw...");
+
+ /* restore power on defaults to register */
+ ccdc_restore_defaults();
+
+ /* CCDCFG register:
+ * set CCD Not to swap input since input is RAW data
+ * set FID detection function to Latch at V-Sync
+ * set WENLOG - ccdc valid area to AND
+ * set TRGSEL to WENBIT
+ * set EXTRG to DISABLE
+ * disable latching function on VSYNC - shadowed registers
+ */
+ regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
+ CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
+ CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
+
+ /*
+ * Set VDHD direction to input, input type to raw input
+ * normal data polarity, do not use external WEN
+ */
+ val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
+ CCDC_EXWEN_DISABLE);
+
+ /*
+ * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
+ * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
+ * frame format(progressive or interlace), & pixel format (Input mode)
+ */
+ val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
+
+ /* set pack for alaw compression */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ val |= CCDC_DATA_PACK_ENABLE;
+
+ /* Configure for LPF */
+ if (config_params->lpf_enable)
+ val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
+ CCDC_LPF_SHIFT;
+
+ /* Configure the data shift */
+ val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
+ CCDC_DATASFT_SHIFT;
+ regw(val , MODESET);
+ dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
+
+ /* Configure the Median Filter threshold */
+ regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
+
+ /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
+ val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
+ CCDC_CFA_MOSAIC;
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val |= (CCDC_ALAW_ENABLE |
+ ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) <<
+ CCDC_GAMMAWD_INPUT_SHIFT));
+ }
+
+ /* Configure Median filter1 & filter2 */
+ val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
+ (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
+
+ regw(val, GAMMAWD);
+ dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 1);
+
+ /* Optical Clamp Averaging */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Vertical Defect Correction if needed */
+ if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
+ return -EFAULT;
+
+ /* color space conversion */
+ ccdc_config_csc(&config_params->csc);
+
+ /* color pattern */
+ ccdc_config_color_patterns(&config_params->col_pat_field0,
+ &config_params->col_pat_field1);
+
+ /* Configure the Gain & offset control */
+ ccdc_config_gain_offset();
+
+ dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
+
+ /* Configure DATAOFST register */
+ val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_H_SHIFT;
+ val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
+ CCDC_DATAOFST_V_SHIFT;
+ regw(val, DATAOFST);
+
+ /* configuring HSIZE register */
+ val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
+ CCDC_HSIZE_FLIP_SHIFT;
+
+ /* If pack 8 is enable then 1 pixel will take 1 byte */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable) {
+ val |= (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ /* adjust to multiple of 32 */
+ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ } else {
+ /* else one pixel will take 2 byte */
+ val |= (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK;
+
+ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
+ (((params->win.width * 2) + 31) >> 5) &
+ CCDC_HSIZE_VAL_MASK);
+ }
+ regw(val, HSIZE);
+
+ /* Configure SDOFST register */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For interlace inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_INVERSE);
+ } else {
+ /* For interlace non inverse mode */
+ regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_INTERLACE_NORMAL);
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ if (params->image_invert_enable) {
+ /* For progessive inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_INVERSE);
+ } else {
+ /* For progessive non inverse mode */
+ regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
+ dev_dbg(dev, "\nWriting %x to SDOFST...\n",
+ CCDC_SDOFST_PROGRESSIVE_NORMAL);
+ }
+ }
+ dev_dbg(dev, "\nend of ccdc_config_raw...");
+ return 0;
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.buf_type = buf_type;
+ else
+ ccdc_hw_params_ycbcr.buf_type = buf_type;
+ return 0;
+}
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.buf_type;
+ return ccdc_hw_params_ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ alaw->enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.win = *win;
+ else
+ ccdc_hw_params_ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ *win = ccdc_hw_params_raw.win;
+ else
+ *win = ccdc_hw_params_ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int len;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_hw_params_raw.win.width;
+ else
+ len = ccdc_hw_params_raw.win.width * 2;
+ } else
+ len = ccdc_hw_params_ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ else
+ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.frm_fmt;
+ else
+ return ccdc_hw_params_ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(MODESET) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw((addr >> 21) & 0x007f, STADRH);
+ regw((addr >> 5) & 0x0ffff, STADRL);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
+ ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM355 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .set_ccdc_base = ccdc_set_ccdc_base,
+ .enable = ccdc_enable,
+ .enable_out_to_sdram = ccdc_enable_output_to_sdram,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int dm355_ccdc_init(void)
+{
+ printk(KERN_NOTICE "dm355_ccdc_init\n");
+ if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
+ return -1;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ ccdc_hw_dev.name);
+ return 0;
+}
+
+static void dm355_ccdc_exit(void)
+{
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+}
+
+module_init(dm355_ccdc_init);
+module_exit(dm355_ccdc_exit);
diff --git a/drivers/media/video/davinci/dm355_ccdc_regs.h b/drivers/media/video/davinci/dm355_ccdc_regs.h
new file mode 100644
index 000000000000..d6d2ef0533b5
--- /dev/null
+++ b/drivers/media/video/davinci/dm355_ccdc_regs.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _DM355_CCDC_REGS_H
+#define _DM355_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define SYNCEN 0x00
+#define MODESET 0x04
+#define HDWIDTH 0x08
+#define VDWIDTH 0x0c
+#define PPLN 0x10
+#define LPFR 0x14
+#define SPH 0x18
+#define NPH 0x1c
+#define SLV0 0x20
+#define SLV1 0x24
+#define NLV 0x28
+#define CULH 0x2c
+#define CULV 0x30
+#define HSIZE 0x34
+#define SDOFST 0x38
+#define STADRH 0x3c
+#define STADRL 0x40
+#define CLAMP 0x44
+#define DCSUB 0x48
+#define COLPTN 0x4c
+#define BLKCMP0 0x50
+#define BLKCMP1 0x54
+#define MEDFILT 0x58
+#define RYEGAIN 0x5c
+#define GRCYGAIN 0x60
+#define GBGGAIN 0x64
+#define BMGGAIN 0x68
+#define OFFSET 0x6c
+#define OUTCLIP 0x70
+#define VDINT0 0x74
+#define VDINT1 0x78
+#define RSV0 0x7c
+#define GAMMAWD 0x80
+#define REC656IF 0x84
+#define CCDCFG 0x88
+#define FMTCFG 0x8c
+#define FMTPLEN 0x90
+#define FMTSPH 0x94
+#define FMTLNH 0x98
+#define FMTSLV 0x9c
+#define FMTLNV 0xa0
+#define FMTRLEN 0xa4
+#define FMTHCNT 0xa8
+#define FMT_ADDR_PTR_B 0xac
+#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4))
+#define FMTPGM_VF0 0xcc
+#define FMTPGM_VF1 0xd0
+#define FMTPGM_AP0 0xd4
+#define FMTPGM_AP1 0xd8
+#define FMTPGM_AP2 0xdc
+#define FMTPGM_AP3 0xe0
+#define FMTPGM_AP4 0xe4
+#define FMTPGM_AP5 0xe8
+#define FMTPGM_AP6 0xec
+#define FMTPGM_AP7 0xf0
+#define LSCCFG1 0xf4
+#define LSCCFG2 0xf8
+#define LSCH0 0xfc
+#define LSCV0 0x100
+#define LSCKH 0x104
+#define LSCKV 0x108
+#define LSCMEMCTL 0x10c
+#define LSCMEMD 0x110
+#define LSCMEMQ 0x114
+#define DFCCTL 0x118
+#define DFCVSAT 0x11c
+#define DFCMEMCTL 0x120
+#define DFCMEM0 0x124
+#define DFCMEM1 0x128
+#define DFCMEM2 0x12c
+#define DFCMEM3 0x130
+#define DFCMEM4 0x134
+#define CSCCTL 0x138
+#define CSCM0 0x13c
+#define CSCM1 0x140
+#define CSCM2 0x144
+#define CSCM3 0x148
+#define CSCM4 0x14c
+#define CSCM5 0x150
+#define CSCM6 0x154
+#define CSCM7 0x158
+#define DATAOFST 0x15c
+#define CCDC_REG_LAST DATAOFST
+/**************************************************************
+* Define for various register bit mask and shifts for CCDC
+*
+**************************************************************/
+#define CCDC_RAW_IP_MODE 0
+#define CCDC_VDHDOUT_INPUT 0
+#define CCDC_YCINSWP_RAW (0 << 4)
+#define CCDC_EXWEN_DISABLE 0
+#define CCDC_DATAPOL_NORMAL 0
+#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0
+#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6)
+#define CCDC_CCDCFG_WENLOG_AND 0
+#define CCDC_CCDCFG_TRGSEL_WEN 0
+#define CCDC_CCDCFG_EXTRG_DISABLE 0
+#define CCDC_CFA_MOSAIC 0
+#define CCDC_Y8POS_SHIFT 11
+
+#define CCDC_VDC_DFCVSAT_MASK 0x3fff
+#define CCDC_DATAOFST_MASK 0x0ff
+#define CCDC_DATAOFST_H_SHIFT 0
+#define CCDC_DATAOFST_V_SHIFT 8
+#define CCDC_GAMMAWD_CFA_MASK 1
+#define CCDC_GAMMAWD_CFA_SHIFT 5
+#define CCDC_GAMMAWD_INPUT_SHIFT 2
+#define CCDC_FID_POL_MASK 1
+#define CCDC_FID_POL_SHIFT 4
+#define CCDC_HD_POL_MASK 1
+#define CCDC_HD_POL_SHIFT 3
+#define CCDC_VD_POL_MASK 1
+#define CCDC_VD_POL_SHIFT 2
+#define CCDC_VD_POL_NEGATIVE (1 << 2)
+#define CCDC_FRM_FMT_MASK 1
+#define CCDC_FRM_FMT_SHIFT 7
+#define CCDC_DATA_SZ_MASK 7
+#define CCDC_DATA_SZ_SHIFT 8
+#define CCDC_VDHDOUT_MASK 1
+#define CCDC_VDHDOUT_SHIFT 0
+#define CCDC_EXWEN_MASK 1
+#define CCDC_EXWEN_SHIFT 5
+#define CCDC_INPUT_MODE_MASK 3
+#define CCDC_INPUT_MODE_SHIFT 12
+#define CCDC_PIX_FMT_MASK 3
+#define CCDC_PIX_FMT_SHIFT 12
+#define CCDC_DATAPOL_MASK 1
+#define CCDC_DATAPOL_SHIFT 6
+#define CCDC_WEN_ENABLE (1 << 1)
+#define CCDC_VDHDEN_ENABLE (1 << 16)
+#define CCDC_LPF_ENABLE (1 << 14)
+#define CCDC_ALAW_ENABLE 1
+#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_REC656IF_BT656_EN 3
+
+#define CCDC_FMTCFG_FMTMODE_MASK 3
+#define CCDC_FMTCFG_FMTMODE_SHIFT 1
+#define CCDC_FMTCFG_LNUM_MASK 3
+#define CCDC_FMTCFG_LNUM_SHIFT 4
+#define CCDC_FMTCFG_ADDRINC_MASK 7
+#define CCDC_FMTCFG_ADDRINC_SHIFT 8
+
+#define CCDC_CCDCFG_FIDMD_SHIFT 6
+#define CCDC_CCDCFG_WENLOG_SHIFT 8
+#define CCDC_CCDCFG_TRGSEL_SHIFT 9
+#define CCDC_CCDCFG_EXTRG_SHIFT 10
+#define CCDC_CCDCFG_MSBINVI_SHIFT 13
+
+#define CCDC_HSIZE_FLIP_SHIFT 12
+#define CCDC_HSIZE_FLIP_MASK 1
+#define CCDC_HSIZE_VAL_MASK 0xFFF
+#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
+#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D
+#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D
+#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000
+#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0
+#define CCDC_START_PX_HOR_MASK 0x7FFF
+#define CCDC_NUM_PX_HOR_MASK 0x7FFF
+#define CCDC_START_VER_ONE_MASK 0x7FFF
+#define CCDC_START_VER_TWO_MASK 0x7FFF
+#define CCDC_NUM_LINES_VER 0x7FFF
+
+#define CCDC_BLK_CLAMP_ENABLE (1 << 15)
+#define CCDC_BLK_SGAIN_MASK 0x1F
+#define CCDC_BLK_ST_PXL_MASK 0x1FFF
+#define CCDC_BLK_SAMPLE_LN_MASK 3
+#define CCDC_BLK_SAMPLE_LN_SHIFT 13
+
+#define CCDC_NUM_LINE_CALC_MASK 3
+#define CCDC_NUM_LINE_CALC_SHIFT 14
+
+#define CCDC_BLK_DC_SUB_MASK 0x3FFF
+#define CCDC_BLK_COMP_MASK 0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT 0
+#define CCDC_BLK_COMP_R_COMP_SHIFT 8
+#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
+#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15)
+#define CCDC_FPC_ENABLE (1 << 15)
+#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
+#define CCDC_DATA_PACK_ENABLE (1 << 11)
+#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
+#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
+#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
+#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
+#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
+
+#define CCDC_CSC_COEF_INTEG_MASK 7
+#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f
+#define CCDC_CSC_COEF_INTEG_SHIFT 5
+#define CCDC_CSCM_MSB_SHIFT 8
+#define CCDC_CSC_ENABLE 1
+#define CCDC_CSC_DEC_MAX 32
+
+#define CCDC_MFILT1_SHIFT 10
+#define CCDC_MFILT2_SHIFT 8
+#define CCDC_MED_FILT_THRESH 0x3FFF
+#define CCDC_LPF_MASK 1
+#define CCDC_LPF_SHIFT 14
+#define CCDC_OFFSET_MASK 0x3FF
+#define CCDC_DATASFT_MASK 7
+#define CCDC_DATASFT_SHIFT 8
+
+#define CCDC_DF_ENABLE 1
+
+#define CCDC_FMTPLEN_P0_MASK 0xF
+#define CCDC_FMTPLEN_P1_MASK 0xF
+#define CCDC_FMTPLEN_P2_MASK 7
+#define CCDC_FMTPLEN_P3_MASK 7
+#define CCDC_FMTPLEN_P0_SHIFT 0
+#define CCDC_FMTPLEN_P1_SHIFT 4
+#define CCDC_FMTPLEN_P2_SHIFT 8
+#define CCDC_FMTPLEN_P3_SHIFT 12
+
+#define CCDC_FMTSPH_MASK 0x1FFF
+#define CCDC_FMTLNH_MASK 0x1FFF
+#define CCDC_FMTSLV_MASK 0x1FFF
+#define CCDC_FMTLNV_MASK 0x7FFF
+#define CCDC_FMTRLEN_MASK 0x1FFF
+#define CCDC_FMTHCNT_MASK 0x1FFF
+
+#define CCDC_ADP_INIT_MASK 0x1FFF
+#define CCDC_ADP_LINE_SHIFT 13
+#define CCDC_ADP_LINE_MASK 3
+#define CCDC_FMTPGN_APTR_MASK 7
+
+#define CCDC_DFCCTL_GDFCEN_MASK 1
+#define CCDC_DFCCTL_VDFCEN_MASK 1
+#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4)
+#define CCDC_DFCCTL_VDFCEN_SHIFT 4
+#define CCDC_DFCCTL_VDFCSL_MASK 3
+#define CCDC_DFCCTL_VDFCSL_SHIFT 5
+#define CCDC_DFCCTL_VDFCUDA_MASK 1
+#define CCDC_DFCCTL_VDFCUDA_SHIFT 7
+#define CCDC_DFCCTL_VDFLSFT_MASK 3
+#define CCDC_DFCCTL_VDFLSFT_SHIFT 8
+#define CCDC_DFCMEMCTL_DFCMARST_MASK 1
+#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2
+#define CCDC_DFCMEMCTL_DFCMWR_MASK 1
+#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0
+#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2)
+
+#define CCDC_LSCCFG_GFTSF_MASK 7
+#define CCDC_LSCCFG_GFTSF_SHIFT 1
+#define CCDC_LSCCFG_GFTINV_MASK 0xf
+#define CCDC_LSCCFG_GFTINV_SHIFT 4
+#define CCDC_LSC_GFTABLE_SEL_MASK 3
+#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8
+#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10
+#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12
+#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14
+#define CCDC_LSC_GFMODE_MASK 3
+#define CCDC_LSC_GFMODE_SHIFT 4
+#define CCDC_LSC_DISABLE 0
+#define CCDC_LSC_ENABLE 1
+#define CCDC_LSC_TABLE1_SLC 0
+#define CCDC_LSC_TABLE2_SLC 1
+#define CCDC_LSC_TABLE3_SLC 2
+#define CCDC_LSC_MEMADDR_RESET (1 << 2)
+#define CCDC_LSC_MEMADDR_INCR (0 << 2)
+#define CCDC_LSC_FRAC_MASK_T1 0xFF
+#define CCDC_LSC_INT_MASK 3
+#define CCDC_LSC_FRAC_MASK 0x3FFF
+#define CCDC_LSC_CENTRE_MASK 0x3FFF
+#define CCDC_LSC_COEF_MASK 0xff
+#define CCDC_LSC_COEFL_SHIFT 0
+#define CCDC_LSC_COEFU_SHIFT 8
+#define CCDC_GAIN_MASK 0x7FF
+#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0)
+#define CCDC_SYNCEN_WEN_MASK (1 << 1)
+#define CCDC_SYNCEN_WEN_SHIFT 1
+
+/* Power on Defaults in hardware */
+#define MODESET_DEFAULT 0x200
+#define CULH_DEFAULT 0xFFFF
+#define CULV_DEFAULT 0xFF
+#define GAIN_DEFAULT 256
+#define OUTCLIP_DEFAULT 0x3FFF
+#define LSCCFG2_DEFAULT 0xE
+
+#endif
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
new file mode 100644
index 000000000000..2f19a919f477
--- /dev/null
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * CCDC hardware module for DM6446
+ * ------------------------------
+ *
+ * This module is for configuring CCD controller of DM6446 VPFE to capture
+ * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
+ * such as Defect Pixel Correction, Color Space Conversion etc to
+ * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
+ * module also allows application to configure individual
+ * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
+ * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
+ * files. The setparams() API is called by vpfe_capture driver
+ * to configure module parameters. This file is named DM644x so that other
+ * variants such DM6443 may be supported using the same module.
+ *
+ * TODO: Test Raw bayer parameter settings and bayer capture
+ * Split module parameter structure to module specific ioctl structs
+ * investigate if enum used for user space type definition
+ * to be replaced by #defines or integer
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+#include <media/davinci/dm644x_ccdc.h>
+#include <media/davinci/vpss.h>
+#include "dm644x_ccdc_regs.h"
+#include "ccdc_hw_device.h"
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CCDC Driver for DM6446");
+MODULE_AUTHOR("Texas Instruments");
+
+static struct device *dev;
+
+/* Object for CCDC raw mode */
+static struct ccdc_params_raw ccdc_hw_params_raw = {
+ .pix_fmt = CCDC_PIXFMT_RAW,
+ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
+ .win = CCDC_WIN_VGA,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .config_params = {
+ .data_sz = CCDC_DATA_10BITS,
+ },
+};
+
+/* Object for CCDC ycbcr mode */
+static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = CCDC_WIN_PAL,
+ .fid_pol = VPFE_PINPOL_POSITIVE,
+ .vd_pol = VPFE_PINPOL_POSITIVE,
+ .hd_pol = VPFE_PINPOL_POSITIVE,
+ .bt656_enable = 1,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+};
+
+#define CCDC_MAX_RAW_YUV_FORMATS 2
+
+/* Raw Bayer formats */
+static u32 ccdc_raw_bayer_pix_formats[] =
+ {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
+
+/* Raw YUV formats */
+static u32 ccdc_raw_yuv_pix_formats[] =
+ {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
+
+static void *__iomem ccdc_base_addr;
+static int ccdc_addr_size;
+static enum vpfe_hw_if_type ccdc_if_type;
+
+/* register access routines */
+static inline u32 regr(u32 offset)
+{
+ return __raw_readl(ccdc_base_addr + offset);
+}
+
+static inline void regw(u32 val, u32 offset)
+{
+ __raw_writel(val, ccdc_base_addr + offset);
+}
+
+static void ccdc_set_ccdc_base(void *addr, int size)
+{
+ ccdc_base_addr = addr;
+ ccdc_addr_size = size;
+}
+
+static void ccdc_enable(int flag)
+{
+ regw(flag, CCDC_PCR);
+}
+
+static void ccdc_enable_vport(int flag)
+{
+ if (flag)
+ /* enable video port */
+ regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
+ else
+ regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
+}
+
+/*
+ * ccdc_setwin()
+ * This function will configure the window size
+ * to be capture in CCDC reg
+ */
+void ccdc_setwin(struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt,
+ int ppc)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int val = 0, mid_img = 0;
+
+ dev_dbg(dev, "\nStarting ccdc_setwin...");
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left << (ppc - 1);
+ horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
+ regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
+ CCDC_HORZ_INFO);
+
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 */
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
+ regw(val, CCDC_VDINT);
+
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /*
+ * configure VDINT0 and VDINT1. VDINT1 will be at half
+ * of image height
+ */
+ mid_img = vert_start + (image_win->height / 2);
+ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
+ (mid_img & CCDC_VDINT_VDINT1_MASK);
+ regw(val, CCDC_VDINT);
+
+ }
+ regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
+ CCDC_VERT_START);
+ regw(vert_nr_lines, CCDC_VERT_LINES);
+ dev_dbg(dev, "\nEnd of ccdc_setwin...");
+}
+
+static void ccdc_readregs(void)
+{
+ unsigned int val = 0;
+
+ val = regr(CCDC_ALAW);
+ dev_notice(dev, "\nReading 0x%x to ALAW...\n", val);
+ val = regr(CCDC_CLAMP);
+ dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val);
+ val = regr(CCDC_DCSUB);
+ dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val);
+ val = regr(CCDC_BLKCMP);
+ dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val);
+ val = regr(CCDC_FPC_ADDR);
+ dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val);
+ val = regr(CCDC_FPC);
+ dev_notice(dev, "\nReading 0x%x to FPC...\n", val);
+ val = regr(CCDC_FMTCFG);
+ dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val);
+ val = regr(CCDC_COLPTN);
+ dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val);
+ val = regr(CCDC_FMT_HORZ);
+ dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val);
+ val = regr(CCDC_FMT_VERT);
+ dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val);
+ val = regr(CCDC_HSIZE_OFF);
+ dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
+ val = regr(CCDC_SDOFST);
+ dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val);
+ val = regr(CCDC_VP_OUT);
+ dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val);
+ val = regr(CCDC_SYN_MODE);
+ dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val);
+ val = regr(CCDC_HORZ_INFO);
+ dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val);
+ val = regr(CCDC_VERT_START);
+ dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val);
+ val = regr(CCDC_VERT_LINES);
+ dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val);
+}
+
+static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
+{
+ if (ccdcparam->alaw.enable) {
+ if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
+ (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
+ (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
+ dev_dbg(dev, "\nInvalid data line select");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int *fpc_virtaddr = NULL;
+ unsigned int *fpc_physaddr = NULL;
+
+ memcpy(config_params, raw_params, sizeof(*raw_params));
+ /*
+ * allocate memory for fault pixel table and copy the user
+ * values to the table
+ */
+ if (!config_params->fault_pxl.enable)
+ return 0;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+ fpc_virtaddr = (unsigned int *)phys_to_virt(
+ (unsigned long)fpc_physaddr);
+ /*
+ * Allocate memory for FPC table if current
+ * FPC table buffer is not big enough to
+ * accomodate FPC Number requested
+ */
+ if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
+ if (fpc_physaddr != NULL) {
+ free_pages((unsigned long)fpc_physaddr,
+ get_order
+ (config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+
+ /* Allocate memory for FPC table */
+ fpc_virtaddr =
+ (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
+ get_order(raw_params->
+ fault_pxl.fp_num *
+ FP_NUM_BYTES));
+
+ if (fpc_virtaddr == NULL) {
+ dev_dbg(dev,
+ "\nUnable to allocate memory for FPC");
+ return -EFAULT;
+ }
+ fpc_physaddr =
+ (unsigned int *)virt_to_phys((void *)fpc_virtaddr);
+ }
+
+ /* Copy number of fault pixels and FPC table */
+ config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
+ if (copy_from_user(fpc_virtaddr,
+ (void __user *)raw_params->fault_pxl.fpc_table_addr,
+ config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
+ dev_dbg(dev, "\n copy_from_user failed");
+ return -EFAULT;
+ }
+ config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+ return 0;
+}
+
+static int ccdc_close(struct device *dev)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
+
+ fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
+
+ if (fpc_physaddr != NULL) {
+ fpc_virtaddr = (unsigned int *)
+ phys_to_virt((unsigned long)fpc_physaddr);
+ free_pages((unsigned long)fpc_virtaddr,
+ get_order(config_params->fault_pxl.fp_num *
+ FP_NUM_BYTES));
+ }
+ return 0;
+}
+
+/*
+ * ccdc_restore_defaults()
+ * This function will write defaults to all CCDC registers
+ */
+static void ccdc_restore_defaults(void)
+{
+ int i;
+
+ /* disable CCDC */
+ ccdc_enable(0);
+ /* set all registers to default value */
+ for (i = 4; i <= 0x94; i += 4)
+ regw(0, i);
+ regw(CCDC_NO_CULLING, CCDC_CULLING);
+ regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
+}
+
+static int ccdc_open(struct device *device)
+{
+ dev = device;
+ ccdc_restore_defaults();
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_enable_vport(1);
+ return 0;
+}
+
+static void ccdc_sbl_reset(void)
+{
+ vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
+}
+
+/* Parameter operations */
+static int ccdc_set_params(void __user *params)
+{
+ struct ccdc_config_params_raw ccdc_raw_params;
+ int x;
+
+ if (ccdc_if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
+ if (x) {
+ dev_dbg(dev, "ccdc_set_params: error in copying"
+ "ccdc params, %d\n", x);
+ return -EFAULT;
+ }
+
+ if (!validate_ccdc_param(&ccdc_raw_params)) {
+ if (!ccdc_update_raw_params(&ccdc_raw_params))
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * ccdc_config_ycbcr()
+ * This function will configure CCDC for YCbCr video capture
+ */
+void ccdc_config_ycbcr(void)
+{
+ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
+ u32 syn_mode;
+
+ dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
+ /*
+ * first restore the CCDC registers to default values
+ * This is important since we assume default values to be set in
+ * a lot of registers that we didn't touch
+ */
+ ccdc_restore_defaults();
+
+ /*
+ * configure pixel format, frame format, configure video frame
+ * format, enable output to SDRAM, enable internal timing generator
+ * and 8bit pack mode
+ */
+ syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
+ CCDC_SYN_MODE_INPMOD_SHIFT) |
+ ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
+ CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
+ CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
+
+ /*
+ * configure the FID, VD, HD pin polarity,
+ * fld,hd pol positive, vd negative, 8-bit data
+ */
+ syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE | CCDC_SYN_MODE_8BITS;
+ } else {
+ /* y/c external sync mode */
+ syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
+ CCDC_FID_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) <<
+ CCDC_HD_POL_SHIFT) |
+ ((params->vd_pol & CCDC_VD_POL_MASK) <<
+ CCDC_VD_POL_SHIFT));
+ }
+ regw(syn_mode, CCDC_SYN_MODE);
+
+ /* configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, 2);
+
+ /*
+ * configure the order of y cb cr in SDRAM, and disable latch
+ * internal register on vsync
+ */
+ regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
+ CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This should be a
+ * on 32 byte bondary. So clear LSB 5 bits
+ */
+ regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ /* two fields are interleaved in memory */
+ regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
+
+ ccdc_sbl_reset();
+ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
+ ccdc_readregs();
+}
+
+static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->enable) {
+ /* configure DCSub */
+ val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
+ regw(val, CCDC_DCSUB);
+ dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val);
+ regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
+ dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n");
+ return;
+ }
+ /*
+ * Configure gain, Start pixel, No of line to be avg,
+ * No of pixel/line to be avg, & Enable the Black clamping
+ */
+ val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
+ ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
+ CCDC_BLK_ST_PXL_SHIFT) |
+ ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
+ CCDC_BLK_SAMPLE_LINE_SHIFT) |
+ ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
+ CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
+ regw(val, CCDC_CLAMP);
+ dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val);
+ /* If Black clamping is enable then make dcsub 0 */
+ regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
+ dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n");
+}
+
+static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
+ ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GB_COMP_SHIFT) |
+ ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & CCDC_BLK_COMP_MASK) <<
+ CCDC_BLK_COMP_R_COMP_SHIFT));
+ regw(val, CCDC_BLKCMP);
+}
+
+static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
+{
+ u32 val;
+
+ /* Initially disable FPC */
+ val = CCDC_FPC_DISABLE;
+ regw(val, CCDC_FPC);
+
+ if (!fpc->enable)
+ return;
+
+ /* Configure Fault pixel if needed */
+ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
+ dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n",
+ (fpc->fpc_table_addr));
+ /* Write the FPC params with FPC disable */
+ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
+ regw(val, CCDC_FPC);
+
+ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+ /* read the FPC register */
+ val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
+ regw(val, CCDC_FPC);
+ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val);
+}
+
+/*
+ * ccdc_config_raw()
+ * This function will configure CCDC for Raw capture mode
+ */
+void ccdc_config_raw(void)
+{
+ struct ccdc_params_raw *params = &ccdc_hw_params_raw;
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int syn_mode = 0;
+ unsigned int val;
+
+ dev_dbg(dev, "\nStarting ccdc_config_raw...");
+
+ /* Reset CCDC */
+ ccdc_restore_defaults();
+
+ /* Disable latching function registers on VSYNC */
+ regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(SYN_MODE.VDPOL),
+ * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
+ * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
+ * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
+ * SDRAM, enable internal timing generator
+ */
+ syn_mode =
+ (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
+ ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
+ ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
+ ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
+ ((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
+ CCDC_DATA_SZ_SHIFT) |
+ ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
+ CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val = ((config_params->alaw.gama_wd &
+ CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
+ regw(val, CCDC_ALAW);
+ dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val);
+ }
+
+ /* Configure video window */
+ ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
+
+ /* Configure Black Clamp */
+ ccdc_config_black_clamp(&config_params->blk_clamp);
+
+ /* Configure Black level compensation */
+ ccdc_config_black_compense(&config_params->blk_comp);
+
+ /* Configure Fault Pixel Correction */
+ ccdc_config_fpc(&config_params->fault_pxl);
+
+ /* If data size is 8 bit then pack the data */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ syn_mode |= CCDC_DATA_PACK_ENABLE;
+
+#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
+ /* enable video port */
+ val = CCDC_ENABLE_VIDEO_PORT;
+#else
+ /* disable video port */
+ val = CCDC_DISABLE_VIDEO_PORT;
+#endif
+
+ if (config_params->data_sz == CCDC_DATA_8BITS)
+ val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ else
+ val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
+ << CCDC_FMTCFG_VPIN_SHIFT;
+ /* Write value in FMTCFG */
+ regw(val, CCDC_FMTCFG);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val);
+ /* Configure the color pattern according to mt9t001 sensor */
+ regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
+
+ dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
+ /*
+ * Configure Data formatter(Video port) pixel selection
+ * (FMT_HORZ, FMT_VERT)
+ */
+ val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
+ CCDC_FMT_HORZ_FMTSPH_SHIFT) |
+ (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
+ regw(val, CCDC_FMT_HORZ);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
+ val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
+ << CCDC_FMT_VERT_FMTSLV_SHIFT;
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
+ else
+ val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
+
+ dev_dbg(dev, "\nparams->win.height 0x%x ...\n",
+ params->win.height);
+ regw(val, CCDC_FMT_VERT);
+
+ dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val);
+
+ dev_dbg(dev, "\nbelow regw(val, FMT_VERT)...");
+
+ /*
+ * Configure Horizontal offset register. If pack 8 is enabled then
+ * 1 pixel will take 1 byte
+ */
+ if ((config_params->data_sz == CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
+ CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
+ else
+ /* else one pixel will take 2 byte */
+ regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
+ CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
+ CCDC_HSIZE_OFF);
+
+ /* Set value for SDOFST */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For intelace inverse mode */
+ regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n");
+ }
+
+ else {
+ /* For intelace non inverse mode */
+ regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n");
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
+ dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n");
+ }
+
+ /*
+ * Configure video port pixel selection (VPOUT)
+ * Here -1 is to make the height value less than FMT_VERT.FMTLNV
+ */
+ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
+ << CCDC_VP_OUT_VERT_NUM_SHIFT;
+ else
+ val =
+ ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
+ 1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
+ CCDC_VP_OUT_VERT_NUM_SHIFT;
+
+ val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
+ << CCDC_VP_OUT_HORZ_NUM_SHIFT;
+ val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
+ regw(val, CCDC_VP_OUT);
+
+ dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val);
+ regw(syn_mode, CCDC_SYN_MODE);
+ dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
+
+ ccdc_sbl_reset();
+ dev_dbg(dev, "\nend of ccdc_config_raw...");
+ ccdc_readregs();
+}
+
+static int ccdc_configure(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_config_raw();
+ else
+ ccdc_config_ycbcr();
+ return 0;
+}
+
+static int ccdc_set_buftype(enum ccdc_buftype buf_type)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.buf_type = buf_type;
+ else
+ ccdc_hw_params_ycbcr.buf_type = buf_type;
+ return 0;
+}
+
+static enum ccdc_buftype ccdc_get_buftype(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.buf_type;
+ return ccdc_hw_params_ycbcr.buf_type;
+}
+
+static int ccdc_enum_pix(u32 *pix, int i)
+{
+ int ret = -EINVAL;
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
+ *pix = ccdc_raw_bayer_pix_formats[i];
+ ret = 0;
+ }
+ } else {
+ if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
+ *pix = ccdc_raw_yuv_pix_formats[i];
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int ccdc_set_pixel_format(u32 pixfmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
+ if (pixfmt == V4L2_PIX_FMT_SBGGR8)
+ ccdc_hw_params_raw.config_params.alaw.enable = 1;
+ else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
+ return -EINVAL;
+ } else {
+ if (pixfmt == V4L2_PIX_FMT_YUYV)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ else if (pixfmt == V4L2_PIX_FMT_UYVY)
+ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static u32 ccdc_get_pixel_format(void)
+{
+ struct ccdc_a_law *alaw =
+ &ccdc_hw_params_raw.config_params.alaw;
+ u32 pixfmt;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ if (alaw->enable)
+ pixfmt = V4L2_PIX_FMT_SBGGR8;
+ else
+ pixfmt = V4L2_PIX_FMT_SBGGR16;
+ else {
+ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+ return pixfmt;
+}
+
+static int ccdc_set_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.win = *win;
+ else
+ ccdc_hw_params_ycbcr.win = *win;
+ return 0;
+}
+
+static void ccdc_get_image_window(struct v4l2_rect *win)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ *win = ccdc_hw_params_raw.win;
+ else
+ *win = ccdc_hw_params_ycbcr.win;
+}
+
+static unsigned int ccdc_get_line_length(void)
+{
+ struct ccdc_config_params_raw *config_params =
+ &ccdc_hw_params_raw.config_params;
+ unsigned int len;
+
+ if (ccdc_if_type == VPFE_RAW_BAYER) {
+ if ((config_params->alaw.enable) ||
+ (config_params->data_sz == CCDC_DATA_8BITS))
+ len = ccdc_hw_params_raw.win.width;
+ else
+ len = ccdc_hw_params_raw.win.width * 2;
+ } else
+ len = ccdc_hw_params_ycbcr.win.width * 2;
+ return ALIGN(len, 32);
+}
+
+static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ ccdc_hw_params_raw.frm_fmt = frm_fmt;
+ else
+ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
+ return 0;
+}
+
+static enum ccdc_frmfmt ccdc_get_frame_format(void)
+{
+ if (ccdc_if_type == VPFE_RAW_BAYER)
+ return ccdc_hw_params_raw.frm_fmt;
+ else
+ return ccdc_hw_params_ycbcr.frm_fmt;
+}
+
+static int ccdc_getfid(void)
+{
+ return (regr(CCDC_SYN_MODE) >> 15) & 1;
+}
+
+/* misc operations */
+static inline void ccdc_setfbaddr(unsigned long addr)
+{
+ regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
+}
+
+static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
+{
+ ccdc_if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
+ ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
+ break;
+ default:
+ /* TODO add support for raw bayer here */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ccdc_hw_device ccdc_hw_dev = {
+ .name = "DM6446 CCDC",
+ .owner = THIS_MODULE,
+ .hw_ops = {
+ .open = ccdc_open,
+ .close = ccdc_close,
+ .set_ccdc_base = ccdc_set_ccdc_base,
+ .reset = ccdc_sbl_reset,
+ .enable = ccdc_enable,
+ .set_hw_if_params = ccdc_set_hw_if_params,
+ .set_params = ccdc_set_params,
+ .configure = ccdc_configure,
+ .set_buftype = ccdc_set_buftype,
+ .get_buftype = ccdc_get_buftype,
+ .enum_pix = ccdc_enum_pix,
+ .set_pixel_format = ccdc_set_pixel_format,
+ .get_pixel_format = ccdc_get_pixel_format,
+ .set_frame_format = ccdc_set_frame_format,
+ .get_frame_format = ccdc_get_frame_format,
+ .set_image_window = ccdc_set_image_window,
+ .get_image_window = ccdc_get_image_window,
+ .get_line_length = ccdc_get_line_length,
+ .setfbaddr = ccdc_setfbaddr,
+ .getfid = ccdc_getfid,
+ },
+};
+
+static int dm644x_ccdc_init(void)
+{
+ printk(KERN_NOTICE "dm644x_ccdc_init\n");
+ if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
+ return -1;
+ printk(KERN_NOTICE "%s is registered with vpfe.\n",
+ ccdc_hw_dev.name);
+ return 0;
+}
+
+static void dm644x_ccdc_exit(void)
+{
+ vpfe_unregister_ccdc_device(&ccdc_hw_dev);
+}
+
+module_init(dm644x_ccdc_init);
+module_exit(dm644x_ccdc_exit);
diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/video/davinci/dm644x_ccdc_regs.h
new file mode 100644
index 000000000000..6e5d05324466
--- /dev/null
+++ b/drivers/media/video/davinci/dm644x_ccdc_regs.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _DM644X_CCDC_REGS_H
+#define _DM644X_CCDC_REGS_H
+
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define CCDC_PID 0x0
+#define CCDC_PCR 0x4
+#define CCDC_SYN_MODE 0x8
+#define CCDC_HD_VD_WID 0xc
+#define CCDC_PIX_LINES 0x10
+#define CCDC_HORZ_INFO 0x14
+#define CCDC_VERT_START 0x18
+#define CCDC_VERT_LINES 0x1c
+#define CCDC_CULLING 0x20
+#define CCDC_HSIZE_OFF 0x24
+#define CCDC_SDOFST 0x28
+#define CCDC_SDR_ADDR 0x2c
+#define CCDC_CLAMP 0x30
+#define CCDC_DCSUB 0x34
+#define CCDC_COLPTN 0x38
+#define CCDC_BLKCMP 0x3c
+#define CCDC_FPC 0x40
+#define CCDC_FPC_ADDR 0x44
+#define CCDC_VDINT 0x48
+#define CCDC_ALAW 0x4c
+#define CCDC_REC656IF 0x50
+#define CCDC_CCDCFG 0x54
+#define CCDC_FMTCFG 0x58
+#define CCDC_FMT_HORZ 0x5c
+#define CCDC_FMT_VERT 0x60
+#define CCDC_FMT_ADDR0 0x64
+#define CCDC_FMT_ADDR1 0x68
+#define CCDC_FMT_ADDR2 0x6c
+#define CCDC_FMT_ADDR3 0x70
+#define CCDC_FMT_ADDR4 0x74
+#define CCDC_FMT_ADDR5 0x78
+#define CCDC_FMT_ADDR6 0x7c
+#define CCDC_FMT_ADDR7 0x80
+#define CCDC_PRGEVEN_0 0x84
+#define CCDC_PRGEVEN_1 0x88
+#define CCDC_PRGODD_0 0x8c
+#define CCDC_PRGODD_1 0x90
+#define CCDC_VP_OUT 0x94
+
+
+/***************************************************************
+* Define for various register bit mask and shifts for CCDC
+****************************************************************/
+#define CCDC_FID_POL_MASK 1
+#define CCDC_FID_POL_SHIFT 4
+#define CCDC_HD_POL_MASK 1
+#define CCDC_HD_POL_SHIFT 3
+#define CCDC_VD_POL_MASK 1
+#define CCDC_VD_POL_SHIFT 2
+#define CCDC_HSIZE_OFF_MASK 0xffffffe0
+#define CCDC_32BYTE_ALIGN_VAL 31
+#define CCDC_FRM_FMT_MASK 0x1
+#define CCDC_FRM_FMT_SHIFT 7
+#define CCDC_DATA_SZ_MASK 7
+#define CCDC_DATA_SZ_SHIFT 8
+#define CCDC_PIX_FMT_MASK 3
+#define CCDC_PIX_FMT_SHIFT 12
+#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF
+#define CCDC_WEN_ENABLE (1 << 17)
+#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF
+#define CCDC_VDHDEN_ENABLE (1 << 16)
+#define CCDC_LPF_ENABLE (1 << 14)
+#define CCDC_ALAW_ENABLE (1 << 3)
+#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_BLK_CLAMP_ENABLE (1 << 31)
+#define CCDC_BLK_SGAIN_MASK 0x1F
+#define CCDC_BLK_ST_PXL_MASK 0x7FFF
+#define CCDC_BLK_ST_PXL_SHIFT 10
+#define CCDC_BLK_SAMPLE_LN_MASK 7
+#define CCDC_BLK_SAMPLE_LN_SHIFT 28
+#define CCDC_BLK_SAMPLE_LINE_MASK 7
+#define CCDC_BLK_SAMPLE_LINE_SHIFT 25
+#define CCDC_BLK_DC_SUB_MASK 0x03FFF
+#define CCDC_BLK_COMP_MASK 0xFF
+#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
+#define CCDC_BLK_COMP_GR_COMP_SHIFT 16
+#define CCDC_BLK_COMP_R_COMP_SHIFT 24
+#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
+#define CCDC_FPC_ENABLE (1 << 15)
+#define CCDC_FPC_DISABLE 0
+#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
+#define CCDC_DATA_PACK_ENABLE (1 << 11)
+#define CCDC_FMTCFG_VPIN_MASK 7
+#define CCDC_FMTCFG_VPIN_SHIFT 12
+#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF
+#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16
+#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF
+#define CCDC_FMT_VERT_FMTSLV_SHIFT 16
+#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF
+#define CCDC_VP_OUT_VERT_NUM_SHIFT 17
+#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF
+#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4
+#define CCDC_VP_OUT_HORZ_ST_MASK 0xF
+#define CCDC_HORZ_INFO_SPH_SHIFT 16
+#define CCDC_VERT_START_SLV0_SHIFT 16
+#define CCDC_VDINT_VDINT0_SHIFT 16
+#define CCDC_VDINT_VDINT1_MASK 0xFFFF
+#define CCDC_PPC_RAW 1
+#define CCDC_DCSUB_DEFAULT_VAL 0
+#define CCDC_CLAMP_DEFAULT_VAL 0
+#define CCDC_ENABLE_VIDEO_PORT 0x8000
+#define CCDC_DISABLE_VIDEO_PORT 0
+#define CCDC_COLPTN_VAL 0xBB11BB11
+#define CCDC_TWO_BYTES_PER_PIXEL 2
+#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D
+#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249
+#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000
+#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0
+#define CCDC_INTERLACED_HEIGHT_SHIFT 1
+#define CCDC_SYN_MODE_INPMOD_SHIFT 12
+#define CCDC_SYN_MODE_INPMOD_MASK 3
+#define CCDC_SYN_MODE_8BITS (7 << 8)
+#define CCDC_SYN_FLDMODE_MASK 1
+#define CCDC_SYN_FLDMODE_SHIFT 7
+#define CCDC_REC656IF_BT656_EN 3
+#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
+#define CCDC_CCDCFG_Y8POS_SHIFT 11
+#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
+#define CCDC_NO_CULLING 0xffff00ff
+#endif
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
new file mode 100644
index 000000000000..402ce43ef38e
--- /dev/null
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Driver name : VPFE Capture driver
+ * VPFE Capture driver allows applications to capture and stream video
+ * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
+ * TVP5146 or Raw Bayer RGB image data from an image sensor
+ * such as Microns' MT9T001, MT9T031 etc.
+ *
+ * These SoCs have, in common, a Video Processing Subsystem (VPSS) that
+ * consists of a Video Processing Front End (VPFE) for capturing
+ * video/raw image data and Video Processing Back End (VPBE) for displaying
+ * YUV data through an in-built analog encoder or Digital LCD port. This
+ * driver is for capture through VPFE. A typical EVM using these SoCs have
+ * following high level configuration.
+ *
+ *
+ * decoder(TVP5146/ YUV/
+ * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF)
+ * data input | |
+ * V |
+ * SDRAM |
+ * V
+ * Image Processor
+ * |
+ * V
+ * SDRAM
+ * The data flow happens from a decoder connected to the VPFE over a
+ * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface
+ * and to the input of VPFE through an optional MUX (if more inputs are
+ * to be interfaced on the EVM). The input data is first passed through
+ * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC
+ * does very little or no processing on YUV data and does pre-process Raw
+ * Bayer RGB data through modules such as Defect Pixel Correction (DFC)
+ * Color Space Conversion (CSC), data gain/offset etc. After this, data
+ * can be written to SDRAM or can be connected to the image processing
+ * block such as IPIPE (on DM355 only).
+ *
+ * Features supported
+ * - MMAP IO
+ * - Capture using TVP5146 over BT.656
+ * - support for interfacing decoders using sub device model
+ * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV
+ * data capture to SDRAM.
+ * TODO list
+ * - Support multiple REQBUF after open
+ * - Support for de-allocating buffers through REQBUF
+ * - Support for Raw Bayer RGB capture
+ * - Support for chaining Image Processor
+ * - Support for static allocation of buffers
+ * - Support for USERPTR IO
+ * - Support for STREAMON before QBUF
+ * - Support for control ioctls
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <linux/io.h>
+#include <media/davinci/vpfe_capture.h>
+#include "ccdc_hw_device.h"
+
+static int debug;
+static u32 numbuffers = 3;
+static u32 bufsize = (720 * 576 * 2);
+
+module_param(numbuffers, uint, S_IRUGO);
+module_param(bufsize, uint, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
+MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/* standard information */
+struct vpfe_standard {
+ v4l2_std_id std_id;
+ unsigned int width;
+ unsigned int height;
+ struct v4l2_fract pixelaspect;
+ /* 0 - progressive, 1 - interlaced */
+ int frame_format;
+};
+
+/* ccdc configuration */
+struct ccdc_config {
+ /* This make sure vpfe is probed and ready to go */
+ int vpfe_probed;
+ /* name of ccdc device */
+ char name[32];
+ /* for storing mem maps for CCDC */
+ int ccdc_addr_size;
+ void *__iomem ccdc_addr;
+};
+
+/* data structures */
+static struct vpfe_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers = 3,
+ .min_bufsize = 720 * 480 * 2,
+ .device_bufsize = 720 * 576 * 2,
+};
+
+/* ccdc device registered */
+static struct ccdc_hw_device *ccdc_dev;
+/* lock for accessing ccdc information */
+static DEFINE_MUTEX(ccdc_lock);
+/* ccdc configuration */
+static struct ccdc_config *ccdc_cfg;
+
+const struct vpfe_standard vpfe_standards[] = {
+ {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
+ {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
+};
+
+/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
+static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
+ {
+ .fmtdesc = {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit A-Law compr.",
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb - 16bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer GrRBGb 8bit DPCM compr.",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
+ },
+ .bpp = 1,
+ },
+ {
+ .fmtdesc = {
+ .index = 3,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 4,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "YCbCr 4:2:2 Interleaved YUYV",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ .bpp = 2,
+ },
+ {
+ .fmtdesc = {
+ .index = 5,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Y/CbCr 4:2:0 - Semi planar",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+ .bpp = 1,
+ },
+};
+
+/*
+ * vpfe_lookup_pix_format()
+ * lookup an entry in the vpfe pix format table based on pix_format
+ */
+static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
+ if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
+ return &vpfe_pix_fmts[i];
+ }
+ return NULL;
+}
+
+/*
+ * vpfe_register_ccdc_device. CCDC module calls this to
+ * register with vpfe capture
+ */
+int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
+{
+ int ret = 0;
+ printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
+
+ BUG_ON(!dev->hw_ops.open);
+ BUG_ON(!dev->hw_ops.enable);
+ BUG_ON(!dev->hw_ops.set_hw_if_params);
+ BUG_ON(!dev->hw_ops.configure);
+ BUG_ON(!dev->hw_ops.set_buftype);
+ BUG_ON(!dev->hw_ops.get_buftype);
+ BUG_ON(!dev->hw_ops.enum_pix);
+ BUG_ON(!dev->hw_ops.set_frame_format);
+ BUG_ON(!dev->hw_ops.get_frame_format);
+ BUG_ON(!dev->hw_ops.get_pixel_format);
+ BUG_ON(!dev->hw_ops.set_pixel_format);
+ BUG_ON(!dev->hw_ops.set_params);
+ BUG_ON(!dev->hw_ops.set_image_window);
+ BUG_ON(!dev->hw_ops.get_image_window);
+ BUG_ON(!dev->hw_ops.get_line_length);
+ BUG_ON(!dev->hw_ops.setfbaddr);
+ BUG_ON(!dev->hw_ops.getfid);
+
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_cfg) {
+ /*
+ * TODO. Will this ever happen? if so, we need to fix it.
+ * Proabably we need to add the request to a linked list and
+ * walk through it during vpfe probe
+ */
+ printk(KERN_ERR "vpfe capture not initialized\n");
+ ret = -1;
+ goto unlock;
+ }
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ ret = -1;
+ goto unlock;
+ }
+
+ if (ccdc_dev) {
+ printk(KERN_ERR "ccdc already registered\n");
+ ret = -1;
+ goto unlock;
+ }
+
+ ccdc_dev = dev;
+ dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr,
+ ccdc_cfg->ccdc_addr_size);
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(vpfe_register_ccdc_device);
+
+/*
+ * vpfe_unregister_ccdc_device. CCDC module calls this to
+ * unregister with vpfe capture
+ */
+void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
+{
+ if (NULL == dev) {
+ printk(KERN_ERR "invalid ccdc device ptr\n");
+ return;
+ }
+
+ printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n",
+ dev->name);
+
+ if (strcmp(dev->name, ccdc_cfg->name)) {
+ /* ignore this ccdc */
+ return;
+ }
+
+ mutex_lock(&ccdc_lock);
+ ccdc_dev = NULL;
+ mutex_unlock(&ccdc_lock);
+ return;
+}
+EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
+
+/*
+ * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
+ */
+static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_format *f)
+{
+ struct v4l2_rect image_win;
+ enum ccdc_buftype buf_type;
+ enum ccdc_frmfmt frm_fmt;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ f->fmt.pix.width = image_win.width;
+ f->fmt.pix.height = image_win.height;
+ f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height;
+ buf_type = ccdc_dev->hw_ops.get_buftype();
+ f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format();
+ frm_fmt = ccdc_dev->hw_ops.get_frame_format();
+ if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED)
+ f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+ else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n");
+ return -EINVAL;
+ }
+ } else {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * vpfe_config_ccdc_image_format()
+ * For a pix format, configure ccdc to setup the capture
+ */
+static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+ int ret = 0;
+
+ if (ccdc_dev->hw_ops.set_pixel_format(
+ vpfe_dev->fmt.fmt.pix.pixelformat) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "couldn't set pix format in ccdc\n");
+ return -EINVAL;
+ }
+ /* configure the image window */
+ ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop);
+
+ switch (vpfe_dev->fmt.fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+ /* do nothing, since it is default */
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_INTERLEAVED);
+ break;
+ case V4L2_FIELD_NONE:
+ frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+ /* buffer type only applicable for interlaced scan */
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ ret = ccdc_dev->hw_ops.set_buftype(
+ CCDC_BUFTYPE_FLD_SEPARATED);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set the frame format */
+ if (!ret)
+ ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt);
+ return ret;
+}
+/*
+ * vpfe_config_image_format()
+ * For a given standard, this functions sets up the default
+ * pix format & crop values in the vpfe device and ccdc. It first
+ * starts with defaults based values from the standard table.
+ * It then checks if sub device support g_fmt and then override the
+ * values based on that.Sets crop values to match with scan resolution
+ * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
+ * values in ccdc
+ */
+static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
+ const v4l2_std_id *std_id)
+{
+ struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
+ if (vpfe_standards[i].std_id & *std_id) {
+ vpfe_dev->std_info.active_pixels =
+ vpfe_standards[i].width;
+ vpfe_dev->std_info.active_lines =
+ vpfe_standards[i].height;
+ vpfe_dev->std_info.frame_format =
+ vpfe_standards[i].frame_format;
+ vpfe_dev->std_index = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(vpfe_standards)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n");
+ return -EINVAL;
+ }
+
+ vpfe_dev->crop.top = 0;
+ vpfe_dev->crop.left = 0;
+ vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
+ vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
+ vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width;
+ vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height;
+
+ /* first field and frame format based on standard frame format */
+ if (vpfe_dev->std_info.frame_format) {
+ vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+ /* assume V4L2_PIX_FMT_UYVY as default */
+ vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ } else {
+ vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ /* assume V4L2_PIX_FMT_SBGGR8 */
+ vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ }
+
+ /* if sub device supports g_fmt, override the defaults */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
+
+ if (ret && ret != -ENOIOCTLCMD) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "error in getting g_fmt from sub device\n");
+ return ret;
+ }
+
+ /* Sets the values in CCDC */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ if (ret)
+ return ret;
+
+ /* Update the values of sizeimage and bytesperline */
+ if (!ret) {
+ vpfe_dev->fmt.fmt.pix.bytesperline =
+ ccdc_dev->hw_ops.get_line_length();
+ vpfe_dev->fmt.fmt.pix.sizeimage =
+ vpfe_dev->fmt.fmt.pix.bytesperline *
+ vpfe_dev->fmt.fmt.pix.height;
+ }
+ return ret;
+}
+
+static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
+{
+ int ret = 0;
+
+ /* set first input of current subdevice as the current input */
+ vpfe_dev->current_input = 0;
+
+ /* set default standard */
+ vpfe_dev->std_index = 0;
+
+ /* Configure the default format information */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+ if (ret)
+ return ret;
+
+ /* now open the ccdc device to initialize it */
+ mutex_lock(&ccdc_lock);
+ if (NULL == ccdc_dev) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (!try_module_get(ccdc_dev->owner)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n");
+ ret = -ENODEV;
+ goto unlock;
+ }
+ ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev);
+ if (!ret)
+ vpfe_dev->initialized = 1;
+unlock:
+ mutex_unlock(&ccdc_lock);
+ return ret;
+}
+
+/*
+ * vpfe_open : It creates object of file handle structure and
+ * stores it in private_data member of filepointer
+ */
+static int vpfe_open(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
+
+ if (!vpfe_dev->cfg->num_subdevs) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n");
+ return -ENODEV;
+ }
+
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL);
+ if (NULL == fh) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+ /* store pointer to fh in private_data member of file */
+ file->private_data = fh;
+ fh->vpfe_dev = vpfe_dev;
+ mutex_lock(&vpfe_dev->lock);
+ /* If decoder is not initialized. initialize it */
+ if (!vpfe_dev->initialized) {
+ if (vpfe_initialize_device(vpfe_dev)) {
+ mutex_unlock(&vpfe_dev->lock);
+ return -ENODEV;
+ }
+ }
+ /* Increment device usrs counter */
+ vpfe_dev->usrs++;
+ /* Set io_allowed member to false */
+ fh->io_allowed = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
+ mutex_unlock(&vpfe_dev->lock);
+ return 0;
+}
+
+static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
+{
+ unsigned long addr;
+
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vpfe_dev->next_frm->queue);
+ vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
+ addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+ ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
+{
+ struct timeval timevalue;
+
+ do_gettimeofday(&timevalue);
+ vpfe_dev->cur_frm->ts = timevalue;
+ vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
+ vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ wake_up_interruptible(&vpfe_dev->cur_frm->done);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+}
+
+/* ISR for VINT0*/
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+ enum v4l2_field field;
+ unsigned long addr;
+ int fid;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
+ field = vpfe_dev->fmt.fmt.pix.field;
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started)
+ return IRQ_HANDLED;
+
+ /* only for 6446 this will be applicable */
+ if (NULL != ccdc_dev->hw_ops.reset)
+ ccdc_dev->hw_ops.reset();
+
+ if (field == V4L2_FIELD_NONE) {
+ /* handle progressive frame capture */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "frame format is progressive...\n");
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ return IRQ_HANDLED;
+ }
+
+ /* interlaced or TB capture check which field we are in hardware */
+ fid = ccdc_dev->hw_ops.getfid();
+
+ /* switch the software maintained field id */
+ vpfe_dev->field_id ^= 1;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n",
+ fid, vpfe_dev->field_id);
+ if (fid == vpfe_dev->field_id) {
+ /* we are in-sync here,continue */
+ if (fid == 0) {
+ /*
+ * One frame is just being captured. If the next frame
+ * is available, release the current frame and move on
+ */
+ if (vpfe_dev->cur_frm != vpfe_dev->next_frm)
+ vpfe_process_buffer_complete(vpfe_dev);
+ /*
+ * based on whether the two fields are stored
+ * interleavely or separately in memory, reconfigure
+ * the CCDC memory address
+ */
+ if (field == V4L2_FIELD_SEQ_TB) {
+ addr =
+ videobuf_to_dma_contig(vpfe_dev->cur_frm);
+ addr += vpfe_dev->field_off;
+ ccdc_dev->hw_ops.setfbaddr(addr);
+ }
+ return IRQ_HANDLED;
+ }
+ /*
+ * if one field is just being captured configure
+ * the next frame get the next frame from the empty
+ * queue if no frame is available hold on to the
+ * current buffer
+ */
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if (!list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+ } else if (fid == 0) {
+ /*
+ * out of sync. Recover from any hardware out-of-sync.
+ * May loose one frame
+ */
+ vpfe_dev->field_id = fid;
+ }
+ return IRQ_HANDLED;
+}
+
+/* vdint1_isr - isr handler for VINT1 interrupt */
+static irqreturn_t vdint1_isr(int irq, void *dev_id)
+{
+ struct vpfe_device *vpfe_dev = dev_id;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n");
+
+ /* if streaming not started, don't do anything */
+ if (!vpfe_dev->started)
+ return IRQ_HANDLED;
+
+ spin_lock(&vpfe_dev->dma_queue_lock);
+ if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) &&
+ !list_empty(&vpfe_dev->dma_queue) &&
+ vpfe_dev->cur_frm == vpfe_dev->next_frm)
+ vpfe_schedule_next_buffer(vpfe_dev);
+ spin_unlock(&vpfe_dev->dma_queue_lock);
+ return IRQ_HANDLED;
+}
+
+static void vpfe_detach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+ free_irq(IRQ_VDINT1, vpfe_dev);
+}
+
+static int vpfe_attach_irq(struct vpfe_device *vpfe_dev)
+{
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = ccdc_dev->hw_ops.get_frame_format();
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE) {
+ return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr,
+ IRQF_DISABLED, "vpfe_capture1",
+ vpfe_dev);
+ }
+ return 0;
+}
+
+/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */
+static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ vpfe_dev->started = 0;
+ ccdc_dev->hw_ops.enable(0);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(0);
+}
+
+/*
+ * vpfe_release : This function deletes buffer queue, frees the
+ * buffers and the vpfe file handle
+ */
+static int vpfe_release(struct file *file)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n");
+
+ /* Get the device lock */
+ mutex_lock(&vpfe_dev->lock);
+ /* if this instance is doing IO */
+ if (fh->io_allowed) {
+ if (vpfe_dev->started) {
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+ sdinfo->grp_id,
+ video, s_stream, 0);
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "stream off failed in subdev\n");
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+ videobuf_streamoff(&vpfe_dev->buffer_queue);
+ }
+ vpfe_dev->io_usrs = 0;
+ vpfe_dev->numbuffers = config_params.numbuffers;
+ }
+
+ /* Decrement device usrs counter */
+ vpfe_dev->usrs--;
+ /* Close the priority */
+ v4l2_prio_close(&vpfe_dev->prio, &fh->prio);
+ /* If this is the last file handle */
+ if (!vpfe_dev->usrs) {
+ vpfe_dev->initialized = 0;
+ if (ccdc_dev->hw_ops.close)
+ ccdc_dev->hw_ops.close(vpfe_dev->pdev);
+ module_put(ccdc_dev->owner);
+ }
+ mutex_unlock(&vpfe_dev->lock);
+ file->private_data = NULL;
+ /* Free memory allocated to file handle object */
+ kfree(fh);
+ return 0;
+}
+
+/*
+ * vpfe_mmap : It is used to map kernel space buffers
+ * into user spaces
+ */
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* Get the device object and file handle object */
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n");
+
+ return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma);
+}
+
+/*
+ * vpfe_poll: It is used for select/poll system call
+ */
+static unsigned int vpfe_poll(struct file *file, poll_table *wait)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n");
+
+ if (vpfe_dev->started)
+ return videobuf_poll_stream(file,
+ &vpfe_dev->buffer_queue, wait);
+ return 0;
+}
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpfe_open,
+ .release = vpfe_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vpfe_mmap,
+ .poll = vpfe_poll
+};
+
+/*
+ * vpfe_check_format()
+ * This function adjust the input pixel format as per hardware
+ * capabilities and update the same in pixfmt.
+ * Following algorithm used :-
+ *
+ * If given pixformat is not in the vpfe list of pix formats or not
+ * supported by the hardware, current value of pixformat in the device
+ * is used
+ * If given field is not supported, then current field is used. If field
+ * is different from current, then it is matched with that from sub device.
+ * Minimum height is 2 lines for interlaced or tb field and 1 line for
+ * progressive. Maximum height is clamped to active active lines of scan
+ * Minimum width is 32 bytes in memory and width is clamped to active
+ * pixels of scan.
+ * bytesperline is a multiple of 32.
+ */
+static const struct vpfe_pixel_format *
+ vpfe_check_format(struct vpfe_device *vpfe_dev,
+ struct v4l2_pix_format *pixfmt)
+{
+ u32 min_height = 1, min_width = 32, max_width, max_height;
+ const struct vpfe_pixel_format *vpfe_pix_fmt;
+ u32 pix;
+ int temp, found;
+
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ if (NULL == vpfe_pix_fmt) {
+ /*
+ * use current pixel format in the vpfe device. We
+ * will find this pix format in the table
+ */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check if hw supports it */
+ temp = 0;
+ found = 0;
+ while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
+ if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
+ found = 1;
+ break;
+ }
+ temp++;
+ }
+
+ if (!found) {
+ /* use current pixel format */
+ pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat;
+ /*
+ * Since this is currently used in the vpfe device, we
+ * will find this pix format in the table
+ */
+ vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat);
+ }
+
+ /* check what field format is supported */
+ if (pixfmt->field == V4L2_FIELD_ANY) {
+ /* if field is any, use current value as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ }
+
+ /*
+ * if field is not same as current field in the vpfe device
+ * try matching the field with the sub device field
+ */
+ if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) {
+ /*
+ * If field value is not in the supported fields, use current
+ * field used in the device as default
+ */
+ switch (pixfmt->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ /* if sub device is supporting progressive, use that */
+ if (!vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_NONE;
+ break;
+ case V4L2_FIELD_NONE:
+ if (vpfe_dev->std_info.frame_format)
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ break;
+
+ default:
+ /* use current field as default */
+ pixfmt->field = vpfe_dev->fmt.fmt.pix.field;
+ break;
+ }
+ }
+
+ /* Now adjust image resolutions supported */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED ||
+ pixfmt->field == V4L2_FIELD_SEQ_TB)
+ min_height = 2;
+
+ max_width = vpfe_dev->std_info.active_pixels;
+ max_height = vpfe_dev->std_info.active_lines;
+ min_width /= vpfe_pix_fmt->bpp;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp);
+
+ pixfmt->width = clamp((pixfmt->width), min_width, max_width);
+ pixfmt->height = clamp((pixfmt->height), min_height, max_height);
+
+ /* If interlaced, adjust height to be a multiple of 2 */
+ if (pixfmt->field == V4L2_FIELD_INTERLACED)
+ pixfmt->height &= (~1);
+ /*
+ * recalculate bytesperline and sizeimage since width
+ * and height might have changed
+ */
+ pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31)
+ & ~31);
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+ pixfmt->sizeimage =
+ pixfmt->bytesperline * pixfmt->height +
+ ((pixfmt->bytesperline * pixfmt->height) >> 1);
+ else
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height ="
+ " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n",
+ pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp,
+ pixfmt->bytesperline, pixfmt->sizeimage);
+ return vpfe_pix_fmt;
+}
+
+static int vpfe_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
+
+ cap->version = VPFE_CAPTURE_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+ strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+ return 0;
+}
+
+static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
+ /* Fill in the information about format */
+ *fmt = vpfe_dev->fmt;
+ return ret;
+}
+
+static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmt;
+ int temp_index;
+ u32 pix;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
+
+ if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ pix_fmt = vpfe_lookup_pix_format(pix);
+ if (NULL != pix_fmt) {
+ temp_index = fmt->index;
+ *fmt = pix_fmt->fmtdesc;
+ fmt->index = temp_index;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
+
+ /* If streaming is started, return error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n");
+ return -EBUSY;
+ }
+
+ /* Check for valid frame format */
+ pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix);
+
+ if (NULL == pix_fmts)
+ return -EINVAL;
+
+ /* store the pixel format in the device object */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /* First detach any IRQ if currently attached */
+ vpfe_detach_irq(vpfe_dev);
+ vpfe_dev->fmt = *fmt;
+ /* set image capture parameters in the ccdc */
+ ret = vpfe_config_ccdc_image_format(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ const struct vpfe_pixel_format *pix_fmts;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n");
+
+ pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix);
+ if (NULL == pix_fmts)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
+ * given app input index
+ */
+static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev,
+ int *subdev_index,
+ int *subdev_input_index,
+ int app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (app_input_index < (j + sdinfo->num_inputs)) {
+ *subdev_index = i;
+ *subdev_input_index = app_input_index - j;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+/*
+ * vpfe_get_app_input - Get app input index for a given subdev input index
+ * driver stores the input index of the current sub device and translate it
+ * when application request the current input
+ */
+static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
+ int *app_input_index)
+{
+ struct vpfe_config *cfg = vpfe_dev->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < cfg->num_subdevs; i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
+ if (vpfe_dev->current_input >= sdinfo->num_inputs)
+ return -1;
+ *app_input_index = j + vpfe_dev->current_input;
+ return 0;
+ }
+ j += sdinfo->num_inputs;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev, index ;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev,
+ &index,
+ inp->index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "input information not found"
+ " for the subdev\n");
+ return -EINVAL;
+ }
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
+ memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
+ return 0;
+}
+
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n");
+
+ return vpfe_get_app_input_index(vpfe_dev, index);
+}
+
+
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev_index, inp_index;
+ struct vpfe_route *route;
+ u32 input = 0, output = 0;
+ int ret = -EINVAL;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ /*
+ * If streaming is started return device busy
+ * error
+ */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ if (vpfe_get_subdev_input_index(vpfe_dev,
+ &subdev_index,
+ &inp_index,
+ index) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
+ goto unlock_out;
+ }
+
+ sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
+ route = &sdinfo->routes[inp_index];
+ if (route && sdinfo->can_route) {
+ input = route->input;
+ output = route->output;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_routing, input, output, 0);
+
+ if (ret) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "vpfe_doioctl:error in setting input in decoder\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ vpfe_dev->current_subdev = sdinfo;
+ vpfe_dev->current_input = index;
+ vpfe_dev->std_index = 0;
+
+ /* set the bus/interface parameter for the sub device in ccdc */
+ ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
+ if (ret)
+ goto unlock_out;
+
+ /* set the default image parameters in the device */
+ ret = vpfe_config_image_format(vpfe_dev,
+ &vpfe_standards[vpfe_dev->std_index].std_id);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n");
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ sdinfo = vpfe_dev->current_subdev;
+ if (ret)
+ return ret;
+ /* Call querystd function of decoder device */
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, querystd, std_id);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n");
+
+ /* Call decoder driver function to set the standard */
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ sdinfo = vpfe_dev->current_subdev;
+ /* If streaming is started, return device busy error */
+ if (vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ core, s_std, *std_id);
+ if (ret < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
+ goto unlock_out;
+ }
+ ret = vpfe_config_image_format(vpfe_dev, std_id);
+
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
+
+ *std_id = vpfe_standards[vpfe_dev->std_index].std_id;
+ return 0;
+}
+/*
+ * Videobuf operations
+ */
+static int vpfe_videobuf_setup(struct videobuf_queue *vq,
+ unsigned int *count,
+ unsigned int *size)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
+ *size = config_params.device_bufsize;
+
+ if (*count < config_params.min_numbuffers)
+ *count = config_params.min_numbuffers;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "count=%d, size=%d\n", *count, *size);
+ return 0;
+}
+
+static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
+
+ /* If buffer is not initialized, initialize it */
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = vpfe_dev->fmt.fmt.pix.width;
+ vb->height = vpfe_dev->fmt.fmt.pix.height;
+ vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
+ vb->field = field;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+static void vpfe_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ /* Get the file handle object and device object */
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n");
+
+ /* add the buffer to the DMA queue */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ list_add_tail(&vb->queue, &vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+
+ /* Change state of the buffer */
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+static void vpfe_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct vpfe_fh *fh = vq->priv_data;
+ struct vpfe_device *vpfe_dev = fh->vpfe_dev;
+ unsigned long flags;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n");
+
+ /*
+ * We need to flush the buffer from the dma queue since
+ * they are de-allocated
+ */
+ spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags);
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags);
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vpfe_videobuf_qops = {
+ .buf_setup = vpfe_videobuf_setup,
+ .buf_prepare = vpfe_videobuf_prepare,
+ .buf_queue = vpfe_videobuf_queue,
+ .buf_release = vpfe_videobuf_release,
+};
+
+/*
+ * vpfe_reqbufs. currently support REQBUF only once opening
+ * the device.
+ */
+static int vpfe_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n");
+ return -EINVAL;
+ }
+
+ if (V4L2_MEMORY_USERPTR == req_buf->memory) {
+ /* we don't support user ptr IO */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:"
+ " USERPTR IO not supported\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (vpfe_dev->io_usrs != 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ vpfe_dev->memory = req_buf->memory;
+ videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue,
+ &vpfe_videobuf_qops,
+ NULL,
+ &vpfe_dev->irqlock,
+ req_buf->type,
+ vpfe_dev->fmt.fmt.pix.field,
+ sizeof(struct videobuf_buffer),
+ fh);
+
+ fh->io_allowed = 1;
+ vpfe_dev->io_usrs = 1;
+ INIT_LIST_HEAD(&vpfe_dev->dma_queue);
+ ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf);
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ if (vpfe_dev->memory != V4L2_MEMORY_MMAP) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n");
+ return -EINVAL;
+ }
+ /* Call videobuf_querybuf to get information */
+ return videobuf_querybuf(&vpfe_dev->buffer_queue, buf);
+}
+
+static int vpfe_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If this file handle is not allowed to do IO,
+ * return error
+ */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+ return videobuf_qbuf(&vpfe_dev->buffer_queue, p);
+}
+
+static int vpfe_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+ return videobuf_dqbuf(&vpfe_dev->buffer_queue,
+ buf, file->f_flags & O_NONBLOCK);
+}
+
+/*
+ * vpfe_calculate_offsets : This function calculates buffers offset
+ * for top and bottom field
+ */
+static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev)
+{
+ struct v4l2_rect image_win;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n");
+
+ ccdc_dev->hw_ops.get_image_window(&image_win);
+ vpfe_dev->field_off = image_win.height * image_win.width;
+}
+
+/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */
+static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev)
+{
+ ccdc_dev->hw_ops.enable(1);
+ if (ccdc_dev->hw_ops.enable_out_to_sdram)
+ ccdc_dev->hw_ops.enable_out_to_sdram(1);
+ vpfe_dev->started = 1;
+}
+
+/*
+ * vpfe_streamon. Assume the DMA queue is not empty.
+ * application is expected to call QBUF before calling
+ * this ioctl. If not, driver returns error
+ */
+static int vpfe_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ unsigned long addr;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If file handle is not allowed IO, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 1);
+
+ if (ret && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n");
+ return -EINVAL;
+ }
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&vpfe_dev->buffer_queue.stream)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n");
+ return -EIO;
+ }
+
+ /* Call videobuf_streamon to start streaming * in videobuf */
+ ret = videobuf_streamon(&vpfe_dev->buffer_queue);
+ if (ret)
+ return ret;
+
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ goto streamoff;
+ /* Get the next frame from the buffer queue */
+ vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next,
+ struct videobuf_buffer, queue);
+ vpfe_dev->cur_frm = vpfe_dev->next_frm;
+ /* Remove buffer from the buffer queue */
+ list_del(&vpfe_dev->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
+ /* Initialize field_id and started member */
+ vpfe_dev->field_id = 0;
+ addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+
+ /* Calculate field offset */
+ vpfe_calculate_offsets(vpfe_dev);
+
+ if (vpfe_attach_irq(vpfe_dev) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in attaching interrupt handle\n");
+ ret = -EFAULT;
+ goto unlock_out;
+ }
+ if (ccdc_dev->hw_ops.configure() < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in configuring ccdc\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr));
+ vpfe_start_ccdc_capture(vpfe_dev);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+streamoff:
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ return ret;
+}
+
+static int vpfe_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct vpfe_fh *fh = file->private_data;
+ struct vpfe_subdev_info *sdinfo;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n");
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n");
+ return -EINVAL;
+ }
+
+ /* If io is allowed for this file handle, return error */
+ if (!fh->io_allowed) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If streaming is not started, return error */
+ if (!vpfe_dev->started) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "device started\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ vpfe_stop_ccdc_capture(vpfe_dev);
+ vpfe_detach_irq(vpfe_dev);
+
+ sdinfo = vpfe_dev->current_subdev;
+ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
+ video, s_stream, 0);
+
+ if (ret && (ret != -ENOIOCTLCMD))
+ v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n");
+ ret = videobuf_streamoff(&vpfe_dev->buffer_queue);
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+static int vpfe_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
+
+ if (vpfe_dev->std_index > ARRAY_SIZE(vpfe_standards))
+ return -EINVAL;
+
+ memset(crop, 0, sizeof(struct v4l2_cropcap));
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop->bounds.width = crop->defrect.width =
+ vpfe_standards[vpfe_dev->std_index].width;
+ crop->bounds.height = crop->defrect.height =
+ vpfe_standards[vpfe_dev->std_index].height;
+ crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+ return 0;
+}
+
+static int vpfe_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n");
+
+ crop->c = vpfe_dev->crop;
+ return 0;
+}
+
+static int vpfe_s_crop(struct file *file, void *priv,
+ struct v4l2_crop *crop)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n");
+
+ if (vpfe_dev->started) {
+ /* make sure streaming is not started */
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Cannot change crop when streaming is ON\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ if (crop->c.top < 0 || crop->c.left < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "doesn't support negative values for top & left\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ /* adjust the width to 16 pixel boundry */
+ crop->c.width = ((crop->c.width + 15) & ~0xf);
+
+ /* make sure parameters are valid */
+ if ((crop->c.left + crop->c.width >
+ vpfe_dev->std_info.active_pixels) ||
+ (crop->c.top + crop->c.height >
+ vpfe_dev->std_info.active_lines)) {
+ v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n");
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ccdc_dev->hw_ops.set_image_window(&crop->c);
+ vpfe_dev->fmt.fmt.pix.width = crop->c.width;
+ vpfe_dev->fmt.fmt.pix.height = crop->c.height;
+ vpfe_dev->fmt.fmt.pix.bytesperline =
+ ccdc_dev->hw_ops.get_line_length();
+ vpfe_dev->fmt.fmt.pix.sizeimage =
+ vpfe_dev->fmt.fmt.pix.bytesperline *
+ vpfe_dev->fmt.fmt.pix.height;
+ vpfe_dev->crop = crop->c;
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+static long vpfe_param_handler(struct file *file, void *priv,
+ int cmd, void *param)
+{
+ struct vpfe_device *vpfe_dev = video_drvdata(file);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
+
+ if (vpfe_dev->started) {
+ /* only allowed if streaming is not started */
+ v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n");
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&vpfe_dev->lock);
+ if (ret)
+ return ret;
+
+ switch (cmd) {
+ case VPFE_CMD_S_CCDC_RAW_PARAMS:
+ v4l2_warn(&vpfe_dev->v4l2_dev,
+ "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
+ ret = ccdc_dev->hw_ops.set_params(param);
+ if (ret) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Error in setting parameters in CCDC\n");
+ goto unlock_out;
+ }
+ if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "Invalid image format at CCDC\n");
+ goto unlock_out;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+unlock_out:
+ mutex_unlock(&vpfe_dev->lock);
+ return ret;
+}
+
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+ .vidioc_querycap = vpfe_querycap,
+ .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap,
+ .vidioc_enum_input = vpfe_enum_input,
+ .vidioc_g_input = vpfe_g_input,
+ .vidioc_s_input = vpfe_s_input,
+ .vidioc_querystd = vpfe_querystd,
+ .vidioc_s_std = vpfe_s_std,
+ .vidioc_g_std = vpfe_g_std,
+ .vidioc_reqbufs = vpfe_reqbufs,
+ .vidioc_querybuf = vpfe_querybuf,
+ .vidioc_qbuf = vpfe_qbuf,
+ .vidioc_dqbuf = vpfe_dqbuf,
+ .vidioc_streamon = vpfe_streamon,
+ .vidioc_streamoff = vpfe_streamoff,
+ .vidioc_cropcap = vpfe_cropcap,
+ .vidioc_g_crop = vpfe_g_crop,
+ .vidioc_s_crop = vpfe_s_crop,
+ .vidioc_default = vpfe_param_handler,
+};
+
+static struct vpfe_device *vpfe_initialize(void)
+{
+ struct vpfe_device *vpfe_dev;
+
+ /* Default number of buffers should be 3 */
+ if ((numbuffers > 0) &&
+ (numbuffers < config_params.min_numbuffers))
+ numbuffers = config_params.min_numbuffers;
+
+ /*
+ * Set buffer size to min buffers size if invalid buffer size is
+ * given
+ */
+ if (bufsize < config_params.min_bufsize)
+ bufsize = config_params.min_bufsize;
+
+ config_params.numbuffers = numbuffers;
+
+ if (numbuffers)
+ config_params.device_bufsize = bufsize;
+
+ /* Allocate memory for device objects */
+ vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL);
+
+ return vpfe_dev;
+}
+
+static void vpfe_disable_clock(struct vpfe_device *vpfe_dev)
+{
+ struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+
+ clk_disable(vpfe_cfg->vpssclk);
+ clk_put(vpfe_cfg->vpssclk);
+ clk_disable(vpfe_cfg->slaveclk);
+ clk_put(vpfe_cfg->slaveclk);
+ v4l2_info(vpfe_dev->pdev->driver,
+ "vpfe vpss master & slave clocks disabled\n");
+}
+
+static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
+{
+ struct vpfe_config *vpfe_cfg = vpfe_dev->cfg;
+ int ret = -ENOENT;
+
+ vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master");
+ if (NULL == vpfe_cfg->vpssclk) {
+ v4l2_err(vpfe_dev->pdev->driver, "No clock defined for"
+ "vpss_master\n");
+ return ret;
+ }
+
+ if (clk_enable(vpfe_cfg->vpssclk)) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "vpfe vpss master clock not enabled\n");
+ goto out;
+ }
+ v4l2_info(vpfe_dev->pdev->driver,
+ "vpfe vpss master clock enabled\n");
+
+ vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave");
+ if (NULL == vpfe_cfg->slaveclk) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "No clock defined for vpss slave\n");
+ goto out;
+ }
+
+ if (clk_enable(vpfe_cfg->slaveclk)) {
+ v4l2_err(vpfe_dev->pdev->driver,
+ "vpfe vpss slave clock not enabled\n");
+ goto out;
+ }
+ v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n");
+ return 0;
+out:
+ if (vpfe_cfg->vpssclk)
+ clk_put(vpfe_cfg->vpssclk);
+ if (vpfe_cfg->slaveclk)
+ clk_put(vpfe_cfg->slaveclk);
+
+ return -1;
+}
+
+/*
+ * vpfe_probe : This function creates device entries by register
+ * itself to the V4L2 driver and initializes fields of each
+ * device objects
+ */
+static __init int vpfe_probe(struct platform_device *pdev)
+{
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_config *vpfe_cfg;
+ struct resource *res1;
+ struct vpfe_device *vpfe_dev;
+ struct i2c_adapter *i2c_adap;
+ struct video_device *vfd;
+ int ret = -ENOMEM, i, j;
+ int num_subdevs = 0;
+
+ /* Get the pointer to the device object */
+ vpfe_dev = vpfe_initialize();
+
+ if (!vpfe_dev) {
+ v4l2_err(pdev->dev.driver,
+ "Failed to allocate memory for vpfe_dev\n");
+ return ret;
+ }
+
+ vpfe_dev->pdev = &pdev->dev;
+
+ if (NULL == pdev->dev.platform_data) {
+ v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n");
+ ret = -ENOENT;
+ goto probe_free_dev_mem;
+ }
+
+ vpfe_cfg = pdev->dev.platform_data;
+ vpfe_dev->cfg = vpfe_cfg;
+ if (NULL == vpfe_cfg->ccdc ||
+ NULL == vpfe_cfg->card_name ||
+ NULL == vpfe_cfg->sub_devs) {
+ v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n");
+ ret = -ENOENT;
+ goto probe_free_dev_mem;
+ }
+
+ /* enable vpss clocks */
+ ret = vpfe_enable_clock(vpfe_dev);
+ if (ret)
+ goto probe_free_dev_mem;
+
+ mutex_lock(&ccdc_lock);
+ /* Allocate memory for ccdc configuration */
+ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL);
+ if (NULL == ccdc_cfg) {
+ v4l2_err(pdev->dev.driver,
+ "Memory allocation failed for ccdc_cfg\n");
+ goto probe_disable_clock;
+ }
+
+ strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
+ /* Get VINT0 irq resource */
+ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT0\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+ vpfe_dev->ccdc_irq0 = res1->start;
+
+ /* Get VINT1 irq resource */
+ res1 = platform_get_resource(pdev,
+ IORESOURCE_IRQ, 1);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get interrupt for VINT1\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+ vpfe_dev->ccdc_irq1 = res1->start;
+
+ /* Get address base of CCDC */
+ res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res1) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to get register address map\n");
+ ret = -ENOENT;
+ goto probe_disable_clock;
+ }
+
+ ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1;
+ if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size,
+ pdev->dev.driver->name)) {
+ v4l2_err(pdev->dev.driver,
+ "Failed request_mem_region for ccdc base\n");
+ ret = -ENXIO;
+ goto probe_disable_clock;
+ }
+ ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start,
+ ccdc_cfg->ccdc_addr_size);
+ if (!ccdc_cfg->ccdc_addr) {
+ v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n");
+ ret = -ENXIO;
+ goto probe_out_release_mem1;
+ }
+
+ ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED,
+ "vpfe_capture0", vpfe_dev);
+
+ if (0 != ret) {
+ v4l2_err(pdev->dev.driver, "Unable to request interrupt\n");
+ goto probe_out_unmap1;
+ }
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (NULL == vfd) {
+ ret = -ENOMEM;
+ v4l2_err(pdev->dev.driver,
+ "Unable to alloc video device\n");
+ goto probe_out_release_irq;
+ }
+
+ /* Initialize field of video device */
+ vfd->release = video_device_release;
+ vfd->fops = &vpfe_fops;
+ vfd->ioctl_ops = &vpfe_ioctl_ops;
+ vfd->minor = -1;
+ vfd->tvnorms = 0;
+ vfd->current_norm = V4L2_STD_PAL;
+ vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "%s_V%d.%d.%d",
+ CAPTURE_DRV_NAME,
+ (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff,
+ (VPFE_CAPTURE_VERSION_CODE) & 0xff);
+ /* Set video_dev to the video device */
+ vpfe_dev->video_dev = vfd;
+
+ ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register v4l2 device.\n");
+ goto probe_out_video_release;
+ }
+ v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n");
+ spin_lock_init(&vpfe_dev->irqlock);
+ spin_lock_init(&vpfe_dev->dma_queue_lock);
+ mutex_init(&vpfe_dev->lock);
+
+ /* Initialize field of the device objects */
+ vpfe_dev->numbuffers = config_params.numbuffers;
+
+ /* Initialize prio member of device object */
+ v4l2_prio_init(&vpfe_dev->prio);
+ /* register video device */
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "trying to register vpfe device.\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "video_dev=%x\n", (int)&vpfe_dev->video_dev);
+ vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ret = video_register_device(vpfe_dev->video_dev,
+ VFL_TYPE_GRABBER, -1);
+
+ if (ret) {
+ v4l2_err(pdev->dev.driver,
+ "Unable to register video device.\n");
+ goto probe_out_v4l2_unregister;
+ }
+
+ v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n");
+ /* set the driver data in platform device */
+ platform_set_drvdata(pdev, vpfe_dev);
+ /* set driver private data */
+ video_set_drvdata(vpfe_dev->video_dev, vpfe_dev);
+ i2c_adap = i2c_get_adapter(1);
+ vpfe_cfg = pdev->dev.platform_data;
+ num_subdevs = vpfe_cfg->num_subdevs;
+ vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs,
+ GFP_KERNEL);
+ if (NULL == vpfe_dev->sd) {
+ v4l2_err(&vpfe_dev->v4l2_dev,
+ "unable to allocate memory for subdevice pointers\n");
+ ret = -ENOMEM;
+ goto probe_out_video_unregister;
+ }
+
+ for (i = 0; i < num_subdevs; i++) {
+ struct v4l2_input *inps;
+
+ sdinfo = &vpfe_cfg->sub_devs[i];
+
+ /* Load up the subdevice */
+ vpfe_dev->sd[i] =
+ v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+ i2c_adap,
+ sdinfo->name,
+ &sdinfo->board_info,
+ NULL);
+ if (vpfe_dev->sd[i]) {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s registered\n",
+ sdinfo->name);
+ vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
+ /* update tvnorms from the sub devices */
+ for (j = 0; j < sdinfo->num_inputs; j++) {
+ inps = &sdinfo->inputs[j];
+ vfd->tvnorms |= inps->std;
+ }
+ } else {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s register fails\n",
+ sdinfo->name);
+ goto probe_sd_out;
+ }
+ }
+
+ /* set first sub device as current one */
+ vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
+
+ /* We have at least one sub device to work with */
+ mutex_unlock(&ccdc_lock);
+ return 0;
+
+probe_sd_out:
+ kfree(vpfe_dev->sd);
+probe_out_video_unregister:
+ video_unregister_device(vpfe_dev->video_dev);
+probe_out_v4l2_unregister:
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+probe_out_video_release:
+ if (vpfe_dev->video_dev->minor == -1)
+ video_device_release(vpfe_dev->video_dev);
+probe_out_release_irq:
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+probe_out_unmap1:
+ iounmap(ccdc_cfg->ccdc_addr);
+probe_out_release_mem1:
+ release_mem_region(res1->start, res1->end - res1->start + 1);
+probe_disable_clock:
+ vpfe_disable_clock(vpfe_dev);
+ mutex_unlock(&ccdc_lock);
+ kfree(ccdc_cfg);
+probe_free_dev_mem:
+ kfree(vpfe_dev);
+ return ret;
+}
+
+/*
+ * vpfe_remove : It un-register device from V4L2 driver
+ */
+static int vpfe_remove(struct platform_device *pdev)
+{
+ struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+
+ free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
+ kfree(vpfe_dev->sd);
+ v4l2_device_unregister(&vpfe_dev->v4l2_dev);
+ video_unregister_device(vpfe_dev->video_dev);
+ mutex_lock(&ccdc_lock);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+ iounmap(ccdc_cfg->ccdc_addr);
+ mutex_unlock(&ccdc_lock);
+ vpfe_disable_clock(vpfe_dev);
+ kfree(vpfe_dev);
+ kfree(ccdc_cfg);
+ return 0;
+}
+
+static int
+vpfe_suspend(struct device *dev)
+{
+ /* add suspend code here later */
+ return -1;
+}
+
+static int
+vpfe_resume(struct device *dev)
+{
+ /* add resume code here later */
+ return -1;
+}
+
+static struct dev_pm_ops vpfe_dev_pm_ops = {
+ .suspend = vpfe_suspend,
+ .resume = vpfe_resume,
+};
+
+static struct platform_driver vpfe_driver = {
+ .driver = {
+ .name = CAPTURE_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &vpfe_dev_pm_ops,
+ },
+ .probe = vpfe_probe,
+ .remove = __devexit_p(vpfe_remove),
+};
+
+static __init int vpfe_init(void)
+{
+ printk(KERN_NOTICE "vpfe_init\n");
+ /* Register driver to the kernel */
+ return platform_driver_register(&vpfe_driver);
+}
+
+/*
+ * vpfe_cleanup : This function un-registers device driver
+ */
+static void vpfe_cleanup(void)
+{
+ platform_driver_unregister(&vpfe_driver);
+}
+
+module_init(vpfe_init);
+module_exit(vpfe_cleanup);
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c
new file mode 100644
index 000000000000..aa771268a5a5
--- /dev/null
+++ b/drivers/media/video/davinci/vpif.c
@@ -0,0 +1,234 @@
+/*
+ * vpif - DM646x Video Port Interface driver
+ * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
+ * that receiveing video byte stream and two channels(2, 3) for video output.
+ * The hardware supports SDTV, HDTV formats, raw data capture.
+ * Currently, the driver supports NTSC and PAL standards.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
+MODULE_LICENSE("GPL");
+
+#define VPIF_CH0_MAX_MODES (22)
+#define VPIF_CH1_MAX_MODES (02)
+#define VPIF_CH2_MAX_MODES (15)
+#define VPIF_CH3_MAX_MODES (02)
+
+static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
+{
+ if (val)
+ vpif_set_bit(reg, bit);
+ else
+ vpif_clr_bit(reg, bit);
+}
+
+/* This structure is used to keep track of VPIF size register's offsets */
+struct vpif_registers {
+ u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
+ u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
+ u32 vanc1_size, width_mask, len_mask;
+ u8 max_modes;
+};
+
+static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
+ /* Channel0 */
+ {
+ VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
+ VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
+ VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH0_MAX_MODES,
+ },
+ /* Channel1 */
+ {
+ VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
+ VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
+ VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
+ VPIF_CH1_MAX_MODES,
+ },
+ /* Channel2 */
+ {
+ VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
+ VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
+ VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
+ VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH2_MAX_MODES
+ },
+ /* Channel3 */
+ {
+ VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
+ VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
+ VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
+ VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
+ VPIF_CH3_MAX_MODES
+ },
+};
+
+/* vpif_set_mode_info:
+ * This function is used to set horizontal and vertical config parameters
+ * As per the standard in the channel, configure the values of L1, L3,
+ * L5, L7 L9, L11 in VPIF Register , also write width and height
+ */
+static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
+ u8 channel_id, u8 config_channel_id)
+{
+ u32 value;
+
+ value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
+ regw(value, vpifregs[channel_id].h_cfg);
+
+ value = (config->l1 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l3 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_00);
+
+ value = (config->l5 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l7 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_01);
+
+ value = (config->l9 & vpifregs[config_channel_id].len_mask);
+ value <<= VPIF_CH_LEN_SHIFT;
+ value |= (config->l11 & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg_02);
+
+ value = (config->vsize & vpifregs[config_channel_id].len_mask);
+ regw(value, vpifregs[channel_id].v_cfg);
+}
+
+/* config_vpif_params
+ * Function to set the parameters of a channel
+ * Mainly modifies the channel ciontrol register
+ * It sets frame format, yc mux mode
+ */
+static void config_vpif_params(struct vpif_params *vpifparams,
+ u8 channel_id, u8 found)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ u32 value, ch_nip, reg;
+ u8 start, end;
+ int i;
+
+ start = channel_id;
+ end = channel_id + found;
+
+ for (i = start; i < end; i++) {
+ reg = vpifregs[i].ch_ctrl;
+ if (channel_id < 2)
+ ch_nip = VPIF_CAPTURE_CH_NIP;
+ else
+ ch_nip = VPIF_DISPLAY_CH_NIP;
+
+ vpif_wr_bit(reg, ch_nip, config->frm_fmt);
+ vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
+ vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
+ vpifparams->video_params.storage_mode);
+
+ /* Set raster scanning SDR Format */
+ vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
+ vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);
+
+ if (channel_id > 1) /* Set the Pixel enable bit */
+ vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
+ else if (config->capture_format) {
+ /* Set the polarity of various pins */
+ vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
+ vpifparams->params.raw_params.fid_pol);
+ vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
+ vpifparams->params.raw_params.vd_pol);
+ vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
+ vpifparams->params.raw_params.hd_pol);
+
+ value = regr(reg);
+ /* Set data width */
+ value &= ((~(unsigned int)(0x3)) <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ value |= ((vpifparams->params.raw_params.data_sz) <<
+ VPIF_CH_DATA_WIDTH_BIT);
+ regw(value, reg);
+ }
+
+ /* Write the pitch in the driver */
+ regw((vpifparams->video_params.hpitch),
+ vpifregs[i].line_offset);
+ }
+}
+
+/* vpif_set_video_params
+ * This function is used to set video parameters in VPIF register
+ */
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
+{
+ const struct vpif_channel_config_params *config = &vpifparams->std_info;
+ int found = 1;
+
+ vpif_set_mode_info(config, channel_id, channel_id);
+ if (!config->ycmux_mode) {
+ /* YC are on separate channels (HDTV formats) */
+ vpif_set_mode_info(config, channel_id + 1, channel_id);
+ found = 2;
+ }
+
+ config_vpif_params(vpifparams, channel_id, found);
+
+ regw(0x80, VPIF_REQ_SIZE);
+ regw(0x01, VPIF_EMULATION_CTRL);
+
+ return found;
+}
+EXPORT_SYMBOL(vpif_set_video_params);
+
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+ u8 channel_id)
+{
+ u32 value;
+
+ value = 0x3F8 & (vbiparams->hstart0);
+ value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_strt);
+
+ value = 0x3F8 & (vbiparams->hstart1);
+ value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_strt);
+
+ value = 0x3F8 & (vbiparams->hsize0);
+ value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
+ regw(value, vpifregs[channel_id].vanc0_size);
+
+ value = 0x3F8 & (vbiparams->hsize1);
+ value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
+ regw(value, vpifregs[channel_id].vanc1_size);
+
+}
+EXPORT_SYMBOL(vpif_set_vbi_display_params);
+
+int vpif_channel_getfid(u8 channel_id)
+{
+ return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
+ >> VPIF_CH_FID_SHIFT;
+}
+EXPORT_SYMBOL(vpif_channel_getfid);
+
+void vpif_base_addr_init(void __iomem *base)
+{
+ vpif_base = base;
+}
+EXPORT_SYMBOL(vpif_base_addr_init);
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
new file mode 100644
index 000000000000..fca26dcb54de
--- /dev/null
+++ b/drivers/media/video/davinci/vpif.h
@@ -0,0 +1,632 @@
+/*
+ * VPIF header file
+ *
+ * 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.
+ */
+
+#ifndef VPIF_H
+#define VPIF_H
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <mach/hardware.h>
+
+/* Maximum channel allowed */
+#define VPIF_NUM_CHANNELS (4)
+#define VPIF_CAPTURE_NUM_CHANNELS (2)
+#define VPIF_DISPLAY_NUM_CHANNELS (2)
+
+/* Macros to read/write registers */
+static void __iomem *vpif_base;
+#define regr(reg) readl((reg) + vpif_base)
+#define regw(value, reg) writel(value, (reg + vpif_base))
+
+/* Register Addresss Offsets */
+#define VPIF_PID (0x0000)
+#define VPIF_CH0_CTRL (0x0004)
+#define VPIF_CH1_CTRL (0x0008)
+#define VPIF_CH2_CTRL (0x000C)
+#define VPIF_CH3_CTRL (0x0010)
+
+#define VPIF_INTEN (0x0020)
+#define VPIF_INTEN_SET (0x0024)
+#define VPIF_INTEN_CLR (0x0028)
+#define VPIF_STATUS (0x002C)
+#define VPIF_STATUS_CLR (0x0030)
+#define VPIF_EMULATION_CTRL (0x0034)
+#define VPIF_REQ_SIZE (0x0038)
+
+#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040)
+#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044)
+#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048)
+#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c)
+#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050)
+#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054)
+#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058)
+#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c)
+#define VPIF_CH0_SP_CFG (0x0060)
+#define VPIF_CH0_IMG_ADD_OFST (0x0064)
+#define VPIF_CH0_HANC_ADD_OFST (0x0068)
+#define VPIF_CH0_H_CFG (0x006c)
+#define VPIF_CH0_V_CFG_00 (0x0070)
+#define VPIF_CH0_V_CFG_01 (0x0074)
+#define VPIF_CH0_V_CFG_02 (0x0078)
+#define VPIF_CH0_V_CFG_03 (0x007c)
+
+#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080)
+#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084)
+#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088)
+#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c)
+#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090)
+#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094)
+#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098)
+#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c)
+#define VPIF_CH1_SP_CFG (0x00a0)
+#define VPIF_CH1_IMG_ADD_OFST (0x00a4)
+#define VPIF_CH1_HANC_ADD_OFST (0x00a8)
+#define VPIF_CH1_H_CFG (0x00ac)
+#define VPIF_CH1_V_CFG_00 (0x00b0)
+#define VPIF_CH1_V_CFG_01 (0x00b4)
+#define VPIF_CH1_V_CFG_02 (0x00b8)
+#define VPIF_CH1_V_CFG_03 (0x00bc)
+
+#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0)
+#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4)
+#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8)
+#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc)
+#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0)
+#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4)
+#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8)
+#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc)
+#define VPIF_CH2_SP_CFG (0x00e0)
+#define VPIF_CH2_IMG_ADD_OFST (0x00e4)
+#define VPIF_CH2_HANC_ADD_OFST (0x00e8)
+#define VPIF_CH2_H_CFG (0x00ec)
+#define VPIF_CH2_V_CFG_00 (0x00f0)
+#define VPIF_CH2_V_CFG_01 (0x00f4)
+#define VPIF_CH2_V_CFG_02 (0x00f8)
+#define VPIF_CH2_V_CFG_03 (0x00fc)
+#define VPIF_CH2_HANC0_STRT (0x0100)
+#define VPIF_CH2_HANC0_SIZE (0x0104)
+#define VPIF_CH2_HANC1_STRT (0x0108)
+#define VPIF_CH2_HANC1_SIZE (0x010c)
+#define VPIF_CH2_VANC0_STRT (0x0110)
+#define VPIF_CH2_VANC0_SIZE (0x0114)
+#define VPIF_CH2_VANC1_STRT (0x0118)
+#define VPIF_CH2_VANC1_SIZE (0x011c)
+
+#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140)
+#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144)
+#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148)
+#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c)
+#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150)
+#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154)
+#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158)
+#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c)
+#define VPIF_CH3_SP_CFG (0x0160)
+#define VPIF_CH3_IMG_ADD_OFST (0x0164)
+#define VPIF_CH3_HANC_ADD_OFST (0x0168)
+#define VPIF_CH3_H_CFG (0x016c)
+#define VPIF_CH3_V_CFG_00 (0x0170)
+#define VPIF_CH3_V_CFG_01 (0x0174)
+#define VPIF_CH3_V_CFG_02 (0x0178)
+#define VPIF_CH3_V_CFG_03 (0x017c)
+#define VPIF_CH3_HANC0_STRT (0x0180)
+#define VPIF_CH3_HANC0_SIZE (0x0184)
+#define VPIF_CH3_HANC1_STRT (0x0188)
+#define VPIF_CH3_HANC1_SIZE (0x018c)
+#define VPIF_CH3_VANC0_STRT (0x0190)
+#define VPIF_CH3_VANC0_SIZE (0x0194)
+#define VPIF_CH3_VANC1_STRT (0x0198)
+#define VPIF_CH3_VANC1_SIZE (0x019c)
+
+#define VPIF_IODFT_CTRL (0x01c0)
+
+/* Functions for bit Manipulation */
+static inline void vpif_set_bit(u32 reg, u32 bit)
+{
+ regw((regr(reg)) | (0x01 << bit), reg);
+}
+
+static inline void vpif_clr_bit(u32 reg, u32 bit)
+{
+ regw(((regr(reg)) & ~(0x01 << bit)), reg);
+}
+
+/* Macro for Generating mask */
+#ifdef GENERATE_MASK
+#undef GENERATE_MASK
+#endif
+
+#define GENERATE_MASK(bits, pos) \
+ ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos)
+
+/* Bit positions in the channel control registers */
+#define VPIF_CH_DATA_MODE_BIT (2)
+#define VPIF_CH_YC_MUX_BIT (3)
+#define VPIF_CH_SDR_FMT_BIT (4)
+#define VPIF_CH_HANC_EN_BIT (8)
+#define VPIF_CH_VANC_EN_BIT (9)
+
+#define VPIF_CAPTURE_CH_NIP (10)
+#define VPIF_DISPLAY_CH_NIP (11)
+
+#define VPIF_DISPLAY_PIX_EN_BIT (10)
+
+#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12)
+
+#define VPIF_CH_FID_POLARITY_BIT (15)
+#define VPIF_CH_V_VALID_POLARITY_BIT (14)
+#define VPIF_CH_H_VALID_POLARITY_BIT (13)
+#define VPIF_CH_DATA_WIDTH_BIT (28)
+
+#define VPIF_CH_CLK_EDGE_CTRL_BIT (31)
+
+/* Mask various length */
+#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0)
+#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0)
+#define VPIF_CH_LEN_SHIFT (16)
+
+/* VPIF masks for registers */
+#define VPIF_REQ_SIZE_MASK (0x1ff)
+
+/* bit posotion of interrupt vpif_ch_intr register */
+#define VPIF_INTEN_FRAME_CH0 (0x00000001)
+#define VPIF_INTEN_FRAME_CH1 (0x00000002)
+#define VPIF_INTEN_FRAME_CH2 (0x00000004)
+#define VPIF_INTEN_FRAME_CH3 (0x00000008)
+
+/* bit position of clock and channel enable in vpif_chn_ctrl register */
+
+#define VPIF_CH0_CLK_EN (0x00000002)
+#define VPIF_CH0_EN (0x00000001)
+#define VPIF_CH1_CLK_EN (0x00000002)
+#define VPIF_CH1_EN (0x00000001)
+#define VPIF_CH2_CLK_EN (0x00000002)
+#define VPIF_CH2_EN (0x00000001)
+#define VPIF_CH3_CLK_EN (0x00000002)
+#define VPIF_CH3_EN (0x00000001)
+#define VPIF_CH_CLK_EN (0x00000002)
+#define VPIF_CH_EN (0x00000001)
+
+#define VPIF_INT_TOP (0x00)
+#define VPIF_INT_BOTTOM (0x01)
+#define VPIF_INT_BOTH (0x02)
+
+#define VPIF_CH0_INT_CTRL_SHIFT (6)
+#define VPIF_CH1_INT_CTRL_SHIFT (6)
+#define VPIF_CH2_INT_CTRL_SHIFT (6)
+#define VPIF_CH3_INT_CTRL_SHIFT (6)
+#define VPIF_CH_INT_CTRL_SHIFT (6)
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch0_ctrl register */
+#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL))
+
+/* enabled interrupt on both the fields on vpid_ch1_ctrl register */
+#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\
+ (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL))
+
+#define VPIF_CH_FID_MASK (0x20)
+#define VPIF_CH_FID_SHIFT (5)
+
+#define VPIF_NTSC_VBI_START_FIELD0 (1)
+#define VPIF_NTSC_VBI_START_FIELD1 (263)
+#define VPIF_PAL_VBI_START_FIELD0 (624)
+#define VPIF_PAL_VBI_START_FIELD1 (311)
+
+#define VPIF_NTSC_HBI_START_FIELD0 (1)
+#define VPIF_NTSC_HBI_START_FIELD1 (263)
+#define VPIF_PAL_HBI_START_FIELD0 (624)
+#define VPIF_PAL_HBI_START_FIELD1 (311)
+
+#define VPIF_NTSC_VBI_COUNT_FIELD0 (20)
+#define VPIF_NTSC_VBI_COUNT_FIELD1 (19)
+#define VPIF_PAL_VBI_COUNT_FIELD0 (24)
+#define VPIF_PAL_VBI_COUNT_FIELD1 (25)
+
+#define VPIF_NTSC_HBI_COUNT_FIELD0 (263)
+#define VPIF_NTSC_HBI_COUNT_FIELD1 (262)
+#define VPIF_PAL_HBI_COUNT_FIELD0 (312)
+#define VPIF_PAL_HBI_COUNT_FIELD1 (313)
+
+#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720)
+#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720)
+#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268)
+#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280)
+
+#define VPIF_CH_VANC_EN (0x20)
+#define VPIF_DMA_REQ_SIZE (0x080)
+#define VPIF_EMULATION_DISABLE (0x01)
+
+extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS];
+
+/* inline function to enable/disable channel0 */
+static inline void enable_channel0(int enable)
+{
+ if (enable)
+ regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL);
+ else
+ regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL);
+}
+
+/* inline function to enable/disable channel1 */
+static inline void enable_channel1(int enable)
+{
+ if (enable)
+ regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL);
+ else
+ regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL);
+}
+
+/* inline function to enable interrupt for channel0 */
+static inline void channel0_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable interrupt for channel1 */
+static inline void channel1_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+
+ regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch0_set_vbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC);
+ regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch0_set_hbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC);
+ regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC);
+}
+
+static inline void ch1_set_vbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC);
+ regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch1_set_hbi_addr(unsigned long top_vbi,
+ unsigned long btm_vbi, unsigned long a, unsigned long b)
+{
+ regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC);
+ regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC);
+}
+
+/* Inline function to enable raw vbi in the given channel */
+static inline void disable_raw_feature(u8 channel_id, u8 index)
+{
+ u32 ctrl_reg;
+ if (0 == channel_id)
+ ctrl_reg = VPIF_CH0_CTRL;
+ else
+ ctrl_reg = VPIF_CH1_CTRL;
+
+ if (1 == index)
+ vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+ else
+ vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+static inline void enable_raw_feature(u8 channel_id, u8 index)
+{
+ u32 ctrl_reg;
+ if (0 == channel_id)
+ ctrl_reg = VPIF_CH0_CTRL;
+ else
+ ctrl_reg = VPIF_CH1_CTRL;
+
+ if (1 == index)
+ vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT);
+ else
+ vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT);
+}
+
+/* inline function to enable/disable channel2 */
+static inline void enable_channel2(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+ regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL);
+ } else {
+ regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL);
+ regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL);
+ }
+}
+
+/* inline function to enable/disable channel3 */
+static inline void enable_channel3(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+ regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL);
+ } else {
+ regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL);
+ regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL);
+ }
+}
+
+/* inline function to enable interrupt for channel2 */
+static inline void channel2_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable interrupt for channel3 */
+static inline void channel3_intr_enable(int enable)
+{
+ if (enable) {
+ regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET);
+
+ regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+ VPIF_INTEN_SET);
+ } else {
+ regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN);
+ regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3),
+ VPIF_INTEN_SET);
+ }
+}
+
+/* inline function to enable raw vbi data for channel2 */
+static inline void channel2_raw_enable(int enable, u8 index)
+{
+ u32 mask;
+
+ if (1 == index)
+ mask = VPIF_CH_VANC_EN_BIT;
+ else
+ mask = VPIF_CH_HANC_EN_BIT;
+
+ if (enable)
+ vpif_set_bit(VPIF_CH2_CTRL, mask);
+ else
+ vpif_clr_bit(VPIF_CH2_CTRL, mask);
+}
+
+/* inline function to enable raw vbi data for channel3*/
+static inline void channel3_raw_enable(int enable, u8 index)
+{
+ u32 mask;
+
+ if (1 == index)
+ mask = VPIF_CH_VANC_EN_BIT;
+ else
+ mask = VPIF_CH_HANC_EN_BIT;
+
+ if (enable)
+ vpif_set_bit(VPIF_CH3_CTRL, mask);
+ else
+ vpif_clr_bit(VPIF_CH3_CTRL, mask);
+}
+
+/* inline function to set buffer addresses in case of Y/C non mux mode */
+static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for video data */
+static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA);
+}
+
+static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA);
+ regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA);
+ regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA);
+ regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA);
+}
+
+/* inline function to set buffer addresses in VPIF registers for vbi data */
+static inline void ch2_set_vbi_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC);
+ regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC);
+}
+
+static inline void ch3_set_vbi_addr(unsigned long top_strt_luma,
+ unsigned long btm_strt_luma,
+ unsigned long top_strt_chroma,
+ unsigned long btm_strt_chroma)
+{
+ regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC);
+ regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC);
+}
+
+#define VPIF_MAX_NAME (30)
+
+/* This structure will store size parameters as per the mode selected by user */
+struct vpif_channel_config_params {
+ char name[VPIF_MAX_NAME]; /* Name of the mode */
+ u16 width; /* Indicates width of the image */
+ u16 height; /* Indicates height of the image */
+ u8 fps;
+ u8 frm_fmt; /* Indicates whether this is interlaced
+ * or progressive format */
+ u8 ycmux_mode; /* Indicates whether this mode requires
+ * single or two channels */
+ u16 eav2sav; /* length of sav 2 eav */
+ u16 sav2eav; /* length of sav 2 eav */
+ u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */
+ u16 vsize; /* Vertical size of the image */
+ u8 capture_format; /* Indicates whether capture format
+ * is in BT or in CCD/CMOS */
+ u8 vbi_supported; /* Indicates whether this mode
+ * supports capturing vbi or not */
+ u8 hd_sd;
+ v4l2_std_id stdid;
+};
+
+struct vpif_interface;
+struct vpif_params;
+struct vpif_vbi_params;
+
+int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id);
+void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
+ u8 channel_id);
+int vpif_channel_getfid(u8 channel_id);
+void vpif_base_addr_init(void __iomem *base);
+
+/* Enumerated data types */
+enum vpif_capture_pinpol {
+ VPIF_CAPTURE_PINPOL_SAME = 0,
+ VPIF_CAPTURE_PINPOL_INVERT = 1
+};
+
+enum data_size {
+ _8BITS = 0,
+ _10BITS,
+ _12BITS,
+};
+
+struct vpif_capture_params_raw {
+ enum data_size data_sz;
+ enum vpif_capture_pinpol fid_pol;
+ enum vpif_capture_pinpol vd_pol;
+ enum vpif_capture_pinpol hd_pol;
+};
+
+/* Structure for vpif parameters for raw vbi data */
+struct vpif_vbi_params {
+ __u32 hstart0; /* Horizontal start of raw vbi data for first field */
+ __u32 vstart0; /* Vertical start of raw vbi data for first field */
+ __u32 hsize0; /* Horizontal size of raw vbi data for first field */
+ __u32 vsize0; /* Vertical size of raw vbi data for first field */
+ __u32 hstart1; /* Horizontal start of raw vbi data for second field */
+ __u32 vstart1; /* Vertical start of raw vbi data for second field */
+ __u32 hsize1; /* Horizontal size of raw vbi data for second field */
+ __u32 vsize1; /* Vertical size of raw vbi data for second field */
+};
+
+/* structure for vpif parameters */
+struct vpif_interface {
+ __u8 storage_mode; /* Indicates field or frame mode */
+ unsigned long hpitch;
+ v4l2_std_id stdid;
+};
+
+struct vpif_params {
+ struct vpif_interface video_params;
+ struct vpif_channel_config_params std_info;
+ union param {
+ struct vpif_vbi_params vbi_params;
+ struct vpif_capture_params_raw raw_params;
+ } params;
+};
+
+#endif /* End of #ifndef VPIF_H */
+
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
new file mode 100644
index 000000000000..969d4b3aa785
--- /dev/null
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -0,0 +1,1679 @@
+/*
+ * vpif-display - VPIF display driver
+ * Display driver for TI DaVinci VPIF
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/version.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include <mach/dm646x.h>
+
+#include "vpif_display.h"
+#include "vpif.h"
+
+MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
+MODULE_LICENSE("GPL");
+
+#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
+
+#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
+#define vpif_dbg(level, debug, fmt, arg...) \
+ v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
+
+static int debug = 1;
+static u32 ch2_numbuffers = 3;
+static u32 ch3_numbuffers = 3;
+static u32 ch2_bufsize = 1920 * 1080 * 2;
+static u32 ch3_bufsize = 720 * 576 * 2;
+
+module_param(debug, int, 0644);
+module_param(ch2_numbuffers, uint, S_IRUGO);
+module_param(ch3_numbuffers, uint, S_IRUGO);
+module_param(ch2_bufsize, uint, S_IRUGO);
+module_param(ch3_bufsize, uint, S_IRUGO);
+
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
+MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
+MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
+MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
+
+static struct vpif_config_params config_params = {
+ .min_numbuffers = 3,
+ .numbuffers[0] = 3,
+ .numbuffers[1] = 3,
+ .min_bufsize[0] = 720 * 480 * 2,
+ .min_bufsize[1] = 720 * 480 * 2,
+ .channel_bufsize[0] = 1920 * 1080 * 2,
+ .channel_bufsize[1] = 720 * 576 * 2,
+};
+
+static struct vpif_device vpif_obj = { {NULL} };
+static struct device *vpif_dev;
+
+static const struct vpif_channel_config_params ch_params[] = {
+ {
+ "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
+ 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
+ },
+ {
+ "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
+ 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
+ },
+};
+
+/*
+ * vpif_uservirt_to_phys: This function is used to convert user
+ * space virtual address to physical address.
+ */
+static u32 vpif_uservirt_to_phys(u32 virtp)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long physp = 0;
+ struct vm_area_struct *vma;
+
+ vma = find_vma(mm, virtp);
+
+ /* For kernel direct-mapped memory, take the easy way */
+ if (virtp >= PAGE_OFFSET) {
+ physp = virt_to_phys((void *)virtp);
+ } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
+ /* this will catch, kernel-allocated, mmaped-to-usermode addr */
+ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+ } else {
+ /* otherwise, use get_user_pages() for general userland pages */
+ int res, nr_pages = 1;
+ struct page *pages;
+ down_read(&current->mm->mmap_sem);
+
+ res = get_user_pages(current, current->mm,
+ virtp, nr_pages, 1, 0, &pages, NULL);
+ up_read(&current->mm->mmap_sem);
+
+ if (res == nr_pages) {
+ physp = __pa(page_address(&pages[0]) +
+ (virtp & ~PAGE_MASK));
+ } else {
+ vpif_err("get_user_pages failed\n");
+ return 0;
+ }
+ }
+
+ return physp;
+}
+
+/*
+ * buffer_prepare: This is the callback function called from videobuf_qbuf()
+ * function the buffer is prepared and user space virtual address is converted
+ * into physical address
+ */
+static int vpif_buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct common_obj *common;
+ unsigned long addr;
+
+ common = &fh->channel->common[VPIF_VIDEO_INDEX];
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = common->width;
+ vb->height = common->height;
+ vb->size = vb->width * vb->height;
+ vb->field = field;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ /* if user pointer memory mechanism is used, get the physical
+ * address of the buffer */
+ if (V4L2_MEMORY_USERPTR == common->memory) {
+ if (!vb->baddr) {
+ vpif_err("buffer_address is 0\n");
+ return -EINVAL;
+ }
+
+ vb->boff = vpif_uservirt_to_phys(vb->baddr);
+ if (!ISALIGNED(vb->boff))
+ goto buf_align_exit;
+ }
+
+ addr = vb->boff;
+ if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
+ if (!ISALIGNED(addr + common->ytop_off) ||
+ !ISALIGNED(addr + common->ybtm_off) ||
+ !ISALIGNED(addr + common->ctop_off) ||
+ !ISALIGNED(addr + common->cbtm_off))
+ goto buf_align_exit;
+ }
+ return 0;
+
+buf_align_exit:
+ vpif_err("buffer offset not aligned to 8 bytes\n");
+ return -EINVAL;
+}
+
+/*
+ * vpif_buffer_setup: This function allocates memory for the buffers
+ */
+static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (V4L2_MEMORY_MMAP != common->memory)
+ return 0;
+
+ *size = config_params.channel_bufsize[ch->channel_id];
+ if (*count < config_params.min_numbuffers)
+ *count = config_params.min_numbuffers;
+
+ return 0;
+}
+
+/*
+ * vpif_buffer_queue: This function adds the buffer to DMA queue
+ */
+static void vpif_buffer_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct common_obj *common;
+
+ common = &fh->channel->common[VPIF_VIDEO_INDEX];
+
+ /* add the buffer to the DMA queue */
+ list_add_tail(&vb->queue, &common->dma_queue);
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpif_buffer_release: This function is called from the videobuf layer to
+ * free memory allocated to the buffers
+ */
+static void vpif_buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct vpif_fh *fh = q->priv_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ unsigned int buf_size = 0;
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ videobuf_dma_contig_free(q, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+
+ if (V4L2_MEMORY_MMAP != common->memory)
+ return;
+
+ buf_size = config_params.channel_bufsize[ch->channel_id];
+}
+
+static struct videobuf_queue_ops video_qops = {
+ .buf_setup = vpif_buffer_setup,
+ .buf_prepare = vpif_buffer_prepare,
+ .buf_queue = vpif_buffer_queue,
+ .buf_release = vpif_buffer_release,
+};
+static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
+
+static void process_progressive_mode(struct common_obj *common)
+{
+ unsigned long addr = 0;
+
+ /* Get the next buffer from buffer queue */
+ common->next_frm = list_entry(common->dma_queue.next,
+ struct videobuf_buffer, queue);
+ /* Remove that buffer from the buffer queue */
+ list_del(&common->next_frm->queue);
+ /* Mark status of the buffer as active */
+ common->next_frm->state = VIDEOBUF_ACTIVE;
+
+ /* Set top and bottom field addrs in VPIF registers */
+ addr = videobuf_to_dma_contig(common->next_frm);
+ common->set_addr(addr + common->ytop_off,
+ addr + common->ybtm_off,
+ addr + common->ctop_off,
+ addr + common->cbtm_off);
+}
+
+static void process_interlaced_mode(int fid, struct common_obj *common)
+{
+ /* device field id and local field id are in sync */
+ /* If this is even field */
+ if (0 == fid) {
+ if (common->cur_frm == common->next_frm)
+ return;
+
+ /* one frame is displayed If next frame is
+ * available, release cur_frm and move on */
+ /* Copy frame display time */
+ do_gettimeofday(&common->cur_frm->ts);
+ /* Change status of the cur_frm */
+ common->cur_frm->state = VIDEOBUF_DONE;
+ /* unlock semaphore on cur_frm */
+ wake_up_interruptible(&common->cur_frm->done);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+
+ } else if (1 == fid) { /* odd field */
+ if (list_empty(&common->dma_queue)
+ || (common->cur_frm != common->next_frm)) {
+ return;
+ }
+ /* one field is displayed configure the next
+ * frame if it is available else hold on current
+ * frame */
+ /* Get next from the buffer queue */
+ process_progressive_mode(common);
+
+ }
+}
+
+/*
+ * vpif_channel_isr: It changes status of the displayed buffer, takes next
+ * buffer from the queue and sets its address in VPIF registers
+ */
+static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
+{
+ struct vpif_device *dev = &vpif_obj;
+ struct channel_obj *ch;
+ struct common_obj *common;
+ enum v4l2_field field;
+ int fid = -1, i;
+ int channel_id = 0;
+
+ channel_id = *(int *)(dev_id);
+ ch = dev->dev[channel_id];
+ field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
+ for (i = 0; i < VPIF_NUMOBJECTS; i++) {
+ common = &ch->common[i];
+ /* If streaming is started in this channel */
+ if (0 == common->started)
+ continue;
+
+ if (1 == ch->vpifparams.std_info.frm_fmt) {
+ if (list_empty(&common->dma_queue))
+ continue;
+
+ /* Progressive mode */
+ if (!channel_first_int[i][channel_id]) {
+ /* Mark status of the cur_frm to
+ * done and unlock semaphore on it */
+ do_gettimeofday(&common->cur_frm->ts);
+ common->cur_frm->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&common->cur_frm->done);
+ /* Make cur_frm pointing to next_frm */
+ common->cur_frm = common->next_frm;
+ }
+
+ channel_first_int[i][channel_id] = 0;
+ process_progressive_mode(common);
+ } else {
+ /* Interlaced mode */
+ /* If it is first interrupt, ignore it */
+
+ if (channel_first_int[i][channel_id]) {
+ channel_first_int[i][channel_id] = 0;
+ continue;
+ }
+
+ if (0 == i) {
+ ch->field_id ^= 1;
+ /* Get field id from VPIF registers */
+ fid = vpif_channel_getfid(ch->channel_id + 2);
+ /* If fid does not match with stored field id */
+ if (fid != ch->field_id) {
+ /* Make them in sync */
+ if (0 == fid)
+ ch->field_id = fid;
+
+ return IRQ_HANDLED;
+ }
+ }
+ process_interlaced_mode(fid, common);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int vpif_get_std_info(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ const struct vpif_channel_config_params *config;
+
+ int index;
+
+ std_info->stdid = vid_ch->stdid;
+ if (!std_info)
+ return -1;
+
+ for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
+ config = &ch_params[index];
+ if (config->stdid & std_info->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ }
+
+ if (index == ARRAY_SIZE(ch_params))
+ return -1;
+
+ common->fmt.fmt.pix.width = std_info->width;
+ common->fmt.fmt.pix.height = std_info->height;
+ vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
+ common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
+
+ /* Set height and width paramateres */
+ ch->common[VPIF_VIDEO_INDEX].height = std_info->height;
+ ch->common[VPIF_VIDEO_INDEX].width = std_info->width;
+
+ return 0;
+}
+
+/*
+ * vpif_calculate_offsets: This function calculates buffers offset for Y and C
+ * in the top and bottom field
+ */
+static void vpif_calculate_offsets(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ enum v4l2_field field = common->fmt.fmt.pix.field;
+ struct video_obj *vid_ch = &ch->video;
+ unsigned int hpitch, vpitch, sizeimage;
+
+ if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
+ if (ch->vpifparams.std_info.frm_fmt)
+ vid_ch->buf_field = V4L2_FIELD_NONE;
+ else
+ vid_ch->buf_field = V4L2_FIELD_INTERLACED;
+ } else {
+ vid_ch->buf_field = common->fmt.fmt.pix.field;
+ }
+
+ if (V4L2_MEMORY_USERPTR == common->memory)
+ sizeimage = common->fmt.fmt.pix.sizeimage;
+ else
+ sizeimage = config_params.channel_bufsize[ch->channel_id];
+
+ hpitch = common->fmt.fmt.pix.bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ common->ytop_off = 0;
+ common->ybtm_off = hpitch;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = sizeimage / 2 + hpitch;
+ } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {
+ common->ytop_off = 0;
+ common->ybtm_off = sizeimage / 4;
+ common->ctop_off = sizeimage / 2;
+ common->cbtm_off = common->ctop_off + sizeimage / 4;
+ } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {
+ common->ybtm_off = 0;
+ common->ytop_off = sizeimage / 4;
+ common->cbtm_off = sizeimage / 2;
+ common->ctop_off = common->cbtm_off + sizeimage / 4;
+ }
+
+ if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
+ (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
+ vpifparams->video_params.storage_mode = 1;
+ } else {
+ vpifparams->video_params.storage_mode = 0;
+ }
+
+ if (ch->vpifparams.std_info.frm_fmt == 1) {
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ } else {
+ if ((field == V4L2_FIELD_ANY) ||
+ (field == V4L2_FIELD_INTERLACED))
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline * 2;
+ else
+ vpifparams->video_params.hpitch =
+ common->fmt.fmt.pix.bytesperline;
+ }
+
+ ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
+}
+
+static void vpif_config_format(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
+ if (config_params.numbuffers[ch->channel_id] == 0)
+ common->memory = V4L2_MEMORY_USERPTR;
+ else
+ common->memory = V4L2_MEMORY_MMAP;
+
+ common->fmt.fmt.pix.sizeimage =
+ config_params.channel_bufsize[ch->channel_id];
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+ common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+}
+
+static int vpif_check_format(struct channel_obj *ch,
+ struct v4l2_pix_format *pixfmt)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ enum v4l2_field field = pixfmt->field;
+ u32 sizeimage, hpitch, vpitch;
+
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+ goto invalid_fmt_exit;
+
+ if (!(VPIF_VALID_FIELD(field)))
+ goto invalid_fmt_exit;
+
+ if (pixfmt->bytesperline <= 0)
+ goto invalid_pitch_exit;
+
+ if (V4L2_MEMORY_USERPTR == common->memory)
+ sizeimage = pixfmt->sizeimage;
+ else
+ sizeimage = config_params.channel_bufsize[ch->channel_id];
+
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ hpitch = pixfmt->bytesperline;
+ vpitch = sizeimage / (hpitch * 2);
+
+ /* Check for valid value of pitch */
+ if ((hpitch < ch->vpifparams.std_info.width) ||
+ (vpitch < ch->vpifparams.std_info.height))
+ goto invalid_pitch_exit;
+
+ /* Check for 8 byte alignment */
+ if (!ISALIGNED(hpitch)) {
+ vpif_err("invalid pitch alignment\n");
+ return -EINVAL;
+ }
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+
+ return 0;
+
+invalid_fmt_exit:
+ vpif_err("invalid field format\n");
+ return -EINVAL;
+
+invalid_pitch_exit:
+ vpif_err("invalid pitch\n");
+ return -EINVAL;
+}
+
+static void vpif_config_addr(struct channel_obj *ch, int muxmode)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {
+ common->set_addr = ch3_set_videobuf_addr;
+ } else {
+ if (2 == muxmode)
+ common->set_addr = ch2_set_videobuf_addr_yc_nmux;
+ else
+ common->set_addr = ch2_set_videobuf_addr;
+ }
+}
+
+/*
+ * vpif_mmap: It is used to map kernel space buffers into user spaces
+ */
+static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX];
+
+ return videobuf_mmap_mapper(&common->buffer_queue, vma);
+}
+
+/*
+ * vpif_poll: It is used for select/poll system call
+ */
+static unsigned int vpif_poll(struct file *filep, poll_table *wait)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (common->started)
+ return videobuf_poll_stream(filep, &common->buffer_queue, wait);
+
+ return 0;
+}
+
+/*
+ * vpif_open: It creates object of file handle structure and stores it in
+ * private_data member of filepointer
+ */
+static int vpif_open(struct file *filep)
+{
+ struct video_device *vdev = video_devdata(filep);
+ struct channel_obj *ch = NULL;
+ struct vpif_fh *fh = NULL;
+
+ ch = video_get_drvdata(vdev);
+ /* Allocate memory for the file handle object */
+ fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ if (fh == NULL) {
+ vpif_err("unable to allocate memory for file handle object\n");
+ return -ENOMEM;
+ }
+
+ /* store pointer to fh in private_data member of filep */
+ filep->private_data = fh;
+ fh->channel = ch;
+ fh->initialized = 0;
+ if (!ch->initialized) {
+ fh->initialized = 1;
+ ch->initialized = 1;
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+ }
+
+ /* Increment channel usrs counter */
+ atomic_inc(&ch->usrs);
+ /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
+ fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
+ /* Initialize priority of this instance to default priority */
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&ch->prio, &fh->prio);
+
+ return 0;
+}
+
+/*
+ * vpif_release: This function deletes buffer queue, frees the buffers and
+ * the vpif file handle
+ */
+static int vpif_release(struct file *filep)
+{
+ struct vpif_fh *fh = filep->private_data;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ /* if this instance is doing IO */
+ if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ /* Reset io_usrs member of channel object */
+ common->io_usrs = 0;
+ /* Disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ common->started = 0;
+ /* Free buffers allocated */
+ videobuf_queue_cancel(&common->buffer_queue);
+ videobuf_mmap_free(&common->buffer_queue);
+ common->numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ }
+
+ mutex_unlock(&common->lock);
+
+ /* Decrement channel usrs counter */
+ atomic_dec(&ch->usrs);
+ /* If this file handle has initialize encoder device, reset it */
+ if (fh->initialized)
+ ch->initialized = 0;
+
+ /* Close the priority */
+ v4l2_prio_close(&ch->prio, &fh->prio);
+ filep->private_data = NULL;
+ fh->initialized = 0;
+ kfree(fh);
+
+ return 0;
+}
+
+/* functions implementing ioctls */
+
+static int vpif_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpif_config *config = vpif_dev->platform_data;
+
+ cap->version = VPIF_DISPLAY_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
+ strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
+ strlcpy(cap->card, config->card_name, sizeof(cap->card));
+
+ return 0;
+}
+
+static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index != 0) {
+ vpif_err("Invalid format index\n");
+ return -EINVAL;
+ }
+
+ /* Fill in the information about format */
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+ fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+
+ return 0;
+}
+
+static int vpif_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ /* Check the validity of the buffer type */
+ if (common->fmt.type != fmt->type)
+ return -EINVAL;
+
+ /* Fill in the information about format */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ *fmt = common->fmt;
+ mutex_unlock(&common->lock);
+ return 0;
+}
+
+static int vpif_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct v4l2_pix_format *pixfmt;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+
+ /* Check for the priority */
+ ret = v4l2_prio_check(&ch->prio, &fh->prio);
+ if (0 != ret)
+ return ret;
+ fh->initialized = 1;
+ }
+
+ if (common->started) {
+ vpif_dbg(1, debug, "Streaming in progress\n");
+ return -EBUSY;
+ }
+
+ pixfmt = &fmt->fmt.pix;
+ /* Check for valid field format */
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret)
+ return ret;
+
+ /* store the pix format in the channel object */
+ common->fmt.fmt.pix = *pixfmt;
+ /* store the format in the channel object */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ common->fmt = *fmt;
+ mutex_unlock(&common->lock);
+
+ return 0;
+}
+
+static int vpif_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ int ret = 0;
+
+ ret = vpif_check_format(ch, pixfmt);
+ if (ret) {
+ *pixfmt = common->fmt.fmt.pix;
+ pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
+ }
+
+ return ret;
+}
+
+static int vpif_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common;
+ enum v4l2_field field;
+ u8 index = 0;
+ int ret = 0;
+
+ /* This file handle has not initialized the channel,
+ It is not allowed to do settings */
+ if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
+ || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_err("Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
+ return -EINVAL;
+
+ index = VPIF_VIDEO_INDEX;
+
+ common = &ch->common[index];
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (common->fmt.type != reqbuf->type) {
+ ret = -EINVAL;
+ goto reqbuf_exit;
+ }
+
+ if (0 != common->io_usrs) {
+ ret = -EBUSY;
+ goto reqbuf_exit;
+ }
+
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
+ field = V4L2_FIELD_INTERLACED;
+ else
+ field = common->fmt.fmt.pix.field;
+ } else {
+ field = V4L2_VBI_INTERLACED;
+ }
+
+ /* Initialize videobuf queue as per the buffer type */
+ videobuf_queue_dma_contig_init(&common->buffer_queue,
+ &video_qops, NULL,
+ &common->irqlock,
+ reqbuf->type, field,
+ sizeof(struct videobuf_buffer), fh);
+
+ /* Set io allowed member of file handle to TRUE */
+ fh->io_allowed[index] = 1;
+ /* Increment io usrs member of channel object to 1 */
+ common->io_usrs = 1;
+ /* Store type of memory requested in channel object */
+ common->memory = reqbuf->memory;
+ INIT_LIST_HEAD(&common->dma_queue);
+
+ /* Allocate buffers */
+ ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
+
+reqbuf_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *tbuf)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (common->fmt.type != tbuf->type)
+ return -EINVAL;
+
+ return videobuf_querybuf(&common->buffer_queue, tbuf);
+}
+
+static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct v4l2_buffer tbuf = *buf;
+ struct videobuf_buffer *buf1;
+ unsigned long addr = 0;
+ unsigned long flags;
+ int ret = 0;
+
+ if (common->fmt.type != tbuf.type)
+ return -EINVAL;
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ if (!(list_empty(&common->dma_queue)) ||
+ (common->cur_frm != common->next_frm) ||
+ !(common->started) ||
+ (common->started && (0 == ch->field_id)))
+ return videobuf_qbuf(&common->buffer_queue, buf);
+
+ /* bufferqueue is empty store buffer address in VPIF registers */
+ mutex_lock(&common->buffer_queue.vb_lock);
+ buf1 = common->buffer_queue.bufs[tbuf.index];
+ if (buf1->memory != tbuf.memory) {
+ vpif_err("invalid buffer type\n");
+ goto qbuf_exit;
+ }
+
+ if ((buf1->state == VIDEOBUF_QUEUED) ||
+ (buf1->state == VIDEOBUF_ACTIVE)) {
+ vpif_err("invalid state\n");
+ goto qbuf_exit;
+ }
+
+ switch (buf1->memory) {
+ case V4L2_MEMORY_MMAP:
+ if (buf1->baddr == 0)
+ goto qbuf_exit;
+ break;
+
+ case V4L2_MEMORY_USERPTR:
+ if (tbuf.length < buf1->bsize)
+ goto qbuf_exit;
+
+ if ((VIDEOBUF_NEEDS_INIT != buf1->state)
+ && (buf1->baddr != tbuf.m.userptr))
+ vpif_buffer_release(&common->buffer_queue, buf1);
+ buf1->baddr = tbuf.m.userptr;
+ break;
+
+ default:
+ goto qbuf_exit;
+ }
+
+ local_irq_save(flags);
+ ret = vpif_buffer_prepare(&common->buffer_queue, buf1,
+ common->buffer_queue.field);
+ if (ret < 0) {
+ local_irq_restore(flags);
+ goto qbuf_exit;
+ }
+
+ buf1->state = VIDEOBUF_ACTIVE;
+ addr = buf1->boff;
+ common->next_frm = buf1;
+ if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+ common->set_addr((addr + common->ytop_off),
+ (addr + common->ybtm_off),
+ (addr + common->ctop_off),
+ (addr + common->cbtm_off));
+ }
+
+ local_irq_restore(flags);
+ list_add_tail(&buf1->stream, &common->buffer_queue.stream);
+ mutex_unlock(&common->buffer_queue.vb_lock);
+ return 0;
+
+qbuf_exit:
+ mutex_unlock(&common->buffer_queue.vb_lock);
+ return -EINVAL;
+}
+
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (!(*std_id & DM646X_V4L2_STD))
+ return -EINVAL;
+
+ if (common->started) {
+ vpif_err("streaming in progress\n");
+ return -EBUSY;
+ }
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.stdid = *std_id;
+ /* Get the information about the standard */
+ if (vpif_get_std_info(ch)) {
+ vpif_err("Error getting the standard info\n");
+ return -EINVAL;
+ }
+
+ if ((ch->vpifparams.std_info.width *
+ ch->vpifparams.std_info.height * 2) >
+ config_params.channel_bufsize[ch->channel_id]) {
+ vpif_err("invalid std for this size\n");
+ ret = -EINVAL;
+ goto s_std_exit;
+ }
+
+ common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_std_output, *std_id);
+ if (ret < 0) {
+ vpif_err("Failed to set output standard\n");
+ goto s_std_exit;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
+ s_std, *std_id);
+ if (ret < 0)
+ vpif_err("Failed to set standard for sub devices\n");
+
+s_std_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *std = ch->video.stdid;
+ return 0;
+}
+
+static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ return videobuf_dqbuf(&common->buffer_queue, p,
+ (file->f_flags & O_NONBLOCK));
+}
+
+static int vpif_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
+ struct vpif_params *vpif = &ch->vpifparams;
+ struct vpif_config *vpif_config_data =
+ vpif_dev->platform_data;
+ unsigned long addr = 0;
+ int ret = 0;
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ /* If Streaming is already started, return error */
+ if (common->started) {
+ vpif_err("channel->started\n");
+ return -EBUSY;
+ }
+
+ if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
+ && oth_ch->common[VPIF_VIDEO_INDEX].started &&
+ ch->vpifparams.std_info.ycmux_mode == 0)
+ || ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
+ && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
+ vpif_err("other channel is using\n");
+ return -EBUSY;
+ }
+
+ ret = vpif_check_format(ch, &common->fmt.fmt.pix);
+ if (ret < 0)
+ return ret;
+
+ /* Call videobuf_streamon to start streaming in videobuf */
+ ret = videobuf_streamon(&common->buffer_queue);
+ if (ret < 0) {
+ vpif_err("videobuf_streamon\n");
+ return ret;
+ }
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ /* If buffer queue is empty, return error */
+ if (list_empty(&common->dma_queue)) {
+ vpif_err("buffer queue is empty\n");
+ ret = -EIO;
+ goto streamon_exit;
+ }
+
+ /* Get the next frame from the buffer queue */
+ common->next_frm = common->cur_frm =
+ list_entry(common->dma_queue.next,
+ struct videobuf_buffer, queue);
+
+ list_del(&common->cur_frm->queue);
+ /* Mark state of the current frame to active */
+ common->cur_frm->state = VIDEOBUF_ACTIVE;
+
+ /* Initialize field_id and started member */
+ ch->field_id = 0;
+ common->started = 1;
+ if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ addr = common->cur_frm->boff;
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
+ if ((ch->vpifparams.std_info.frm_fmt &&
+ ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
+ && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
+ || (!ch->vpifparams.std_info.frm_fmt
+ && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
+ vpif_err("conflict in field format and std format\n");
+ ret = -EINVAL;
+ goto streamon_exit;
+ }
+
+ /* clock settings */
+ ret =
+ vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
+ ch->vpifparams.std_info.hd_sd);
+ if (ret < 0) {
+ vpif_err("can't set clock\n");
+ goto streamon_exit;
+ }
+
+ /* set the parameters and addresses */
+ ret = vpif_set_video_params(vpif, ch->channel_id + 2);
+ if (ret < 0)
+ goto streamon_exit;
+
+ common->started = ret;
+ vpif_config_addr(ch, ret);
+ common->set_addr((addr + common->ytop_off),
+ (addr + common->ybtm_off),
+ (addr + common->ctop_off),
+ (addr + common->cbtm_off));
+
+ /* Set interrupt for both the fields in VPIF
+ Register enable channel in VPIF register */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ channel2_intr_assert();
+ channel2_intr_enable(1);
+ enable_channel2(1);
+ }
+
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
+ || (common->started == 2)) {
+ channel3_intr_assert();
+ channel3_intr_enable(1);
+ enable_channel3(1);
+ }
+ channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
+ }
+
+streamon_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buftype)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ vpif_err("buffer type not supported\n");
+ return -EINVAL;
+ }
+
+ if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
+ vpif_err("fh->io_allowed\n");
+ return -EACCES;
+ }
+
+ if (!common->started) {
+ vpif_err("channel->started\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ /* disable channel */
+ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
+ (2 == common->started)) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
+ }
+ }
+
+ common->started = 0;
+ mutex_unlock(&common->lock);
+
+ return videobuf_streamoff(&common->buffer_queue);
+}
+
+static int vpif_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
+ return -EINVAL;
+
+ crop->bounds.left = crop->bounds.top = 0;
+ crop->defrect.left = crop->defrect.top = 0;
+ crop->defrect.height = crop->bounds.height = common->height;
+ crop->defrect.width = crop->bounds.width = common->width;
+
+ return 0;
+}
+
+static int vpif_enum_output(struct file *file, void *fh,
+ struct v4l2_output *output)
+{
+
+ struct vpif_config *config = vpif_dev->platform_data;
+
+ if (output->index >= config->output_count) {
+ vpif_dbg(1, debug, "Invalid output index\n");
+ return -EINVAL;
+ }
+
+ strcpy(output->name, config->output[output->index]);
+ output->type = V4L2_OUTPUT_TYPE_ANALOG;
+ output->std = DM646X_V4L2_STD;
+
+ return 0;
+}
+
+static int vpif_s_output(struct file *file, void *priv, unsigned int i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ if (common->started) {
+ vpif_err("Streaming in progress\n");
+ ret = -EBUSY;
+ goto s_output_exit;
+ }
+
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
+ s_routing, 0, i, 0);
+
+ if (ret < 0)
+ vpif_err("Failed to set output standard\n");
+
+ vid_ch->output_id = i;
+
+s_output_exit:
+ mutex_unlock(&common->lock);
+ return ret;
+}
+
+static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ *i = vid_ch->output_id;
+
+ return 0;
+}
+
+static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ *p = v4l2_prio_max(&ch->prio);
+
+ return 0;
+}
+
+static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_prio_change(&ch->prio, &fh->prio, p);
+}
+
+/* vpif display ioctl operations */
+static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
+ .vidioc_querycap = vpif_querycap,
+ .vidioc_g_priority = vpif_g_priority,
+ .vidioc_s_priority = vpif_s_priority,
+ .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
+ .vidioc_reqbufs = vpif_reqbufs,
+ .vidioc_querybuf = vpif_querybuf,
+ .vidioc_qbuf = vpif_qbuf,
+ .vidioc_dqbuf = vpif_dqbuf,
+ .vidioc_streamon = vpif_streamon,
+ .vidioc_streamoff = vpif_streamoff,
+ .vidioc_s_std = vpif_s_std,
+ .vidioc_g_std = vpif_g_std,
+ .vidioc_enum_output = vpif_enum_output,
+ .vidioc_s_output = vpif_s_output,
+ .vidioc_g_output = vpif_g_output,
+ .vidioc_cropcap = vpif_cropcap,
+};
+
+static const struct v4l2_file_operations vpif_fops = {
+ .owner = THIS_MODULE,
+ .open = vpif_open,
+ .release = vpif_release,
+ .ioctl = video_ioctl2,
+ .mmap = vpif_mmap,
+ .poll = vpif_poll
+};
+
+static struct video_device vpif_video_template = {
+ .name = "vpif",
+ .fops = &vpif_fops,
+ .minor = -1,
+ .ioctl_ops = &vpif_ioctl_ops,
+ .tvnorms = DM646X_V4L2_STD,
+ .current_norm = V4L2_STD_625_50,
+
+};
+
+/*Configure the channels, buffer sizei, request irq */
+static int initialize_vpif(void)
+{
+ int free_channel_objects_index;
+ int free_buffer_channel_index;
+ int free_buffer_index;
+ int err = 0, i, j;
+
+ /* Default number of buffers should be 3 */
+ if ((ch2_numbuffers > 0) &&
+ (ch2_numbuffers < config_params.min_numbuffers))
+ ch2_numbuffers = config_params.min_numbuffers;
+ if ((ch3_numbuffers > 0) &&
+ (ch3_numbuffers < config_params.min_numbuffers))
+ ch3_numbuffers = config_params.min_numbuffers;
+
+ /* Set buffer size to min buffers size if invalid buffer size is
+ * given */
+ if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
+ ch2_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
+ if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
+ ch3_bufsize =
+ config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
+
+ config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
+
+ if (ch2_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
+ ch2_bufsize;
+ }
+ config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
+
+ if (ch3_numbuffers) {
+ config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
+ ch3_bufsize;
+ }
+
+ /* Allocate memory for six channel objects */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ vpif_obj.dev[i] =
+ kmalloc(sizeof(struct channel_obj), GFP_KERNEL);
+ /* If memory allocation fails, return error */
+ if (!vpif_obj.dev[i]) {
+ free_channel_objects_index = i;
+ err = -ENOMEM;
+ goto vpif_init_free_channel_objects;
+ }
+ }
+
+ free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
+ free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
+ free_buffer_index = config_params.numbuffers[i - 1];
+
+ return 0;
+
+vpif_init_free_channel_objects:
+ for (j = 0; j < free_channel_objects_index; j++)
+ kfree(vpif_obj.dev[j]);
+ return err;
+}
+
+/*
+ * vpif_probe: This function creates device entries by register itself to the
+ * V4L2 driver and initializes fields of each channel objects
+ */
+static __init int vpif_probe(struct platform_device *pdev)
+{
+ const struct subdev_info *subdevdata;
+ int i, j = 0, k, q, m, err = 0;
+ struct i2c_adapter *i2c_adap;
+ struct vpif_config *config;
+ struct common_obj *common;
+ struct channel_obj *ch;
+ struct video_device *vfd;
+ struct resource *res;
+ int subdev_count;
+
+ vpif_dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ v4l2_err(vpif_dev->driver,
+ "Error getting platform resource\n");
+ return -ENOENT;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ vpif_dev->driver->name)) {
+ v4l2_err(vpif_dev->driver, "VPIF: failed request_mem_region\n");
+ return -ENXIO;
+ }
+
+ vpif_base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (!vpif_base) {
+ v4l2_err(vpif_dev->driver, "Unable to ioremap VPIF reg\n");
+ err = -ENXIO;
+ goto resource_exit;
+ }
+
+ vpif_base_addr_init(vpif_base);
+
+ initialize_vpif();
+
+ err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+ if (err) {
+ v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+ return err;
+ }
+
+ k = 0;
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
+ for (i = res->start; i <= res->end; i++) {
+ if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
+ "DM646x_Display",
+ (void *)(&vpif_obj.dev[k]->channel_id))) {
+ err = -EBUSY;
+ goto vpif_int_err;
+ }
+ }
+ k++;
+ }
+
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+
+ /* Allocate memory for video device */
+ vfd = video_device_alloc();
+ if (vfd == NULL) {
+ for (j = 0; j < i; j++) {
+ ch = vpif_obj.dev[j];
+ video_device_release(ch->video_dev);
+ }
+ err = -ENOMEM;
+ goto video_dev_alloc_exit;
+ }
+
+ /* Initialize field of video device */
+ *vfd = vpif_video_template;
+ vfd->v4l2_dev = &vpif_obj.v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d",
+ (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff,
+ (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff,
+ (VPIF_DISPLAY_VERSION_CODE) & 0xff);
+
+ /* Set video_dev to the video device */
+ ch->video_dev = vfd;
+ }
+
+ for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+ ch = vpif_obj.dev[j];
+ /* Initialize field of the channel objects */
+ atomic_set(&ch->usrs, 0);
+ for (k = 0; k < VPIF_NUMOBJECTS; k++) {
+ ch->common[k].numbuffers = 0;
+ common = &ch->common[k];
+ common->io_usrs = 0;
+ common->started = 0;
+ spin_lock_init(&common->irqlock);
+ mutex_init(&common->lock);
+ common->numbuffers = 0;
+ common->set_addr = NULL;
+ common->ytop_off = common->ybtm_off = 0;
+ common->ctop_off = common->cbtm_off = 0;
+ common->cur_frm = common->next_frm = NULL;
+ memset(&common->fmt, 0, sizeof(common->fmt));
+ common->numbuffers = config_params.numbuffers[k];
+
+ }
+ ch->initialized = 0;
+ ch->channel_id = j;
+ if (j < 2)
+ ch->common[VPIF_VIDEO_INDEX].numbuffers =
+ config_params.numbuffers[ch->channel_id];
+ else
+ ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
+
+ memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+
+ /* Initialize prio member of channel object */
+ v4l2_prio_init(&ch->prio);
+ ch->common[VPIF_VIDEO_INDEX].fmt.type =
+ V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ /* register video device */
+ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
+ (int)ch, (int)&ch->video_dev);
+
+ err = video_register_device(ch->video_dev,
+ VFL_TYPE_GRABBER, (j ? 3 : 2));
+ if (err < 0)
+ goto probe_out;
+
+ video_set_drvdata(ch->video_dev, ch);
+ }
+
+ i2c_adap = i2c_get_adapter(1);
+ config = pdev->dev.platform_data;
+ subdev_count = config->subdev_count;
+ subdevdata = config->subdevinfo;
+ vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ GFP_KERNEL);
+ if (vpif_obj.sd == NULL) {
+ vpif_err("unable to allocate memory for subdevice pointers\n");
+ err = -ENOMEM;
+ goto probe_out;
+ }
+
+ for (i = 0; i < subdev_count; i++) {
+ vpif_obj.sd[i] = v4l2_i2c_new_probed_subdev(&vpif_obj.v4l2_dev,
+ i2c_adap, subdevdata[i].name,
+ subdevdata[i].name,
+ &subdevdata[i].addr);
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+ goto probe_subdev_out;
+ }
+
+ if (vpif_obj.sd[i])
+ vpif_obj.sd[i]->grp_id = 1 << i;
+ }
+
+ return 0;
+
+probe_subdev_out:
+ kfree(vpif_obj.sd);
+probe_out:
+ for (k = 0; k < j; k++) {
+ ch = vpif_obj.dev[k];
+ video_unregister_device(ch->video_dev);
+ video_device_release(ch->video_dev);
+ ch->video_dev = NULL;
+ }
+vpif_int_err:
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+ vpif_err("VPIF IRQ request failed\n");
+ for (q = k; k >= 0; k--) {
+ for (m = i; m >= res->start; m--)
+ free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
+ m = res->end;
+ }
+video_dev_alloc_exit:
+ iounmap(vpif_base);
+resource_exit:
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return err;
+}
+
+/*
+ * vpif_remove: It un-register channels from V4L2 driver
+ */
+static int vpif_remove(struct platform_device *device)
+{
+ struct channel_obj *ch;
+ int i;
+
+ v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+ /* un-register device */
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+ /* Get the pointer to the channel object */
+ ch = vpif_obj.dev[i];
+ /* Unregister video device */
+ video_unregister_device(ch->video_dev);
+
+ ch->video_dev = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver vpif_driver = {
+ .driver = {
+ .name = "vpif_display",
+ .owner = THIS_MODULE,
+ },
+ .probe = vpif_probe,
+ .remove = vpif_remove,
+};
+
+static __init int vpif_init(void)
+{
+ return platform_driver_register(&vpif_driver);
+}
+
+/*
+ * vpif_cleanup: This function un-registers device and driver to the kernel,
+ * frees requested irq handler and de-allocates memory allocated for channel
+ * objects.
+ */
+static void vpif_cleanup(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ int irq_num;
+ int i = 0;
+
+ pdev = container_of(vpif_dev, struct platform_device, dev);
+
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num,
+ (void *)(&vpif_obj.dev[i]->channel_id));
+ i++;
+ }
+
+ iounmap(vpif_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_driver_unregister(&vpif_driver);
+ kfree(vpif_obj.sd);
+ for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
+ kfree(vpif_obj.dev[i]);
+}
+
+module_init(vpif_init);
+module_exit(vpif_cleanup);
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h
new file mode 100644
index 000000000000..a2a7cd166bbf
--- /dev/null
+++ b/drivers/media/video/davinci/vpif_display.h
@@ -0,0 +1,175 @@
+/*
+ * DM646x display header file
+ *
+ * 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.
+ */
+
+#ifndef DAVINCIHD_DISPLAY_H
+#define DAVINCIHD_DISPLAY_H
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "vpif.h"
+
+/* Macros */
+#define VPIF_MAJOR_RELEASE (0)
+#define VPIF_MINOR_RELEASE (0)
+#define VPIF_BUILD (1)
+
+#define VPIF_DISPLAY_VERSION_CODE \
+ ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+
+#define VPIF_VALID_FIELD(field) \
+ (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
+ (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \
+ (V4L2_FIELD_SEQ_BT == field)))
+
+#define VPIF_DISPLAY_MAX_DEVICES (2)
+#define VPIF_SLICED_BUF_SIZE (256)
+#define VPIF_SLICED_MAX_SERVICES (3)
+#define VPIF_VIDEO_INDEX (0)
+#define VPIF_VBI_INDEX (1)
+#define VPIF_HBI_INDEX (2)
+
+/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/
+#define VPIF_NUMOBJECTS (1)
+
+/* Macros */
+#define ISALIGNED(a) (0 == ((a) & 7))
+
+/* enumerated data types */
+/* Enumerated data type to give id to each device per channel */
+enum vpif_channel_id {
+ VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */
+ VPIF_CHANNEL3_VIDEO, /* Channel3 Video */
+};
+
+/* structures */
+
+struct video_obj {
+ enum v4l2_field buf_field;
+ u32 latest_only; /* indicate whether to return
+ * most recent displayed frame only */
+ v4l2_std_id stdid; /* Currently selected or default
+ * standard */
+ u32 output_id; /* Current output id */
+};
+
+struct vbi_obj {
+ int num_services;
+ struct vpif_vbi_params vbiparams; /* vpif parameters for the raw
+ * vbi data */
+};
+
+struct common_obj {
+ /* Buffer specific parameters */
+ u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for
+ * storing frames */
+ u32 numbuffers; /* number of buffers */
+ struct videobuf_buffer *cur_frm; /* Pointer pointing to current
+ * videobuf_buffer */
+ struct videobuf_buffer *next_frm; /* Pointer pointing to next
+ * videobuf_buffer */
+ enum v4l2_memory memory; /* This field keeps track of
+ * type of buffer exchange
+ * method user has selected */
+ struct v4l2_format fmt; /* Used to store the format */
+ struct videobuf_queue buffer_queue; /* Buffer queue used in
+ * video-buf */
+ struct list_head dma_queue; /* Queue of filled frames */
+ spinlock_t irqlock; /* Used in video-buf */
+
+ /* channel specific parameters */
+ struct mutex lock; /* lock used to access this
+ * structure */
+ u32 io_usrs; /* number of users performing
+ * IO */
+ u8 started; /* Indicates whether streaming
+ * started */
+ u32 ytop_off; /* offset of Y top from the
+ * starting of the buffer */
+ u32 ybtm_off; /* offset of Y bottom from the
+ * starting of the buffer */
+ u32 ctop_off; /* offset of C top from the
+ * starting of the buffer */
+ u32 cbtm_off; /* offset of C bottom from the
+ * starting of the buffer */
+ /* Function pointer to set the addresses */
+ void (*set_addr) (unsigned long, unsigned long,
+ unsigned long, unsigned long);
+ u32 height;
+ u32 width;
+};
+
+struct channel_obj {
+ /* V4l2 specific parameters */
+ struct video_device *video_dev; /* Identifies video device for
+ * this channel */
+ struct v4l2_prio_state prio; /* Used to keep track of state of
+ * the priority */
+ atomic_t usrs; /* number of open instances of
+ * the channel */
+ u32 field_id; /* Indicates id of the field
+ * which is being displayed */
+ u8 initialized; /* flag to indicate whether
+ * encoder is initialized */
+
+ enum vpif_channel_id channel_id;/* Identifies channel */
+ struct vpif_params vpifparams;
+ struct common_obj common[VPIF_NUMOBJECTS];
+ struct video_obj video;
+ struct vbi_obj vbi;
+};
+
+/* File handle structure */
+struct vpif_fh {
+ struct channel_obj *channel; /* pointer to channel object for
+ * opened device */
+ u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle
+ * is doing IO */
+ enum v4l2_priority prio; /* Used to keep track priority of
+ * this instance */
+ u8 initialized; /* Used to keep track of whether this
+ * file handle has initialized
+ * channel or not */
+};
+
+/* vpif device structure */
+struct vpif_device {
+ struct v4l2_device v4l2_dev;
+ struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
+ struct v4l2_subdev **sd;
+
+};
+
+struct vpif_config_params {
+ u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+ u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
+ u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS];
+ u8 min_numbuffers;
+};
+
+/* Struct which keeps track of the line numbers for the sliced vbi service */
+struct vpif_service_line {
+ u16 service_id;
+ u16 service_line[2];
+ u16 enc_service_id;
+ u8 bytestowrite;
+};
+
+#endif /* DAVINCIHD_DISPLAY_H */
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
new file mode 100644
index 000000000000..6d709ca8cfb0
--- /dev/null
+++ b/drivers/media/video/davinci/vpss.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * common vpss driver for all video drivers.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <media/davinci/vpss.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPSS Driver");
+MODULE_AUTHOR("Texas Instruments");
+
+/* DM644x defines */
+#define DM644X_SBL_PCR_VPSS (4)
+
+/* vpss BL register offsets */
+#define DM355_VPSSBL_CCDCMUX 0x1c
+/* vpss CLK register offsets */
+#define DM355_VPSSCLK_CLKCTRL 0x04
+/* masks and shifts */
+#define VPSS_HSSISEL_SHIFT 4
+
+/*
+ * vpss operations. Depends on platform. Not all functions are available
+ * on all platforms. The api, first check if a functio is available before
+ * invoking it. In the probe, the function ptrs are intialized based on
+ * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
+ */
+struct vpss_hw_ops {
+ /* enable clock */
+ int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
+ /* select input to ccdc */
+ void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
+ /* clear wbl overlflow bit */
+ int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+};
+
+/* vpss configuration */
+struct vpss_oper_config {
+ __iomem void *vpss_bl_regs_base;
+ __iomem void *vpss_regs_base;
+ struct resource *r1;
+ resource_size_t len1;
+ struct resource *r2;
+ resource_size_t len2;
+ char vpss_name[32];
+ spinlock_t vpss_lock;
+ struct vpss_hw_ops hw_ops;
+};
+
+static struct vpss_oper_config oper_cfg;
+
+/* register access routines */
+static inline u32 bl_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_bl_regs_base + offset);
+}
+
+static inline void bl_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset);
+}
+
+static inline u32 vpss_regr(u32 offset)
+{
+ return __raw_readl(oper_cfg.vpss_regs_base + offset);
+}
+
+static inline void vpss_regw(u32 val, u32 offset)
+{
+ __raw_writel(val, oper_cfg.vpss_regs_base + offset);
+}
+
+static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
+}
+
+int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
+{
+ if (!oper_cfg.hw_ops.select_ccdc_source)
+ return -1;
+
+ dm355_select_ccdc_source(src_sel);
+ return 0;
+}
+EXPORT_SYMBOL(vpss_select_ccdc_source);
+
+static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ u32 mask = 1, val;
+
+ if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
+ wbl_sel > VPSS_PCR_CCDC_WBL_O)
+ return -1;
+
+ /* writing a 0 clear the overflow */
+ mask = ~(mask << wbl_sel);
+ val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
+ bl_regw(val, DM644X_SBL_PCR_VPSS);
+ return 0;
+}
+
+int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
+{
+ if (!oper_cfg.hw_ops.clear_wbl_overflow)
+ return -1;
+
+ return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
+}
+EXPORT_SYMBOL(vpss_clear_wbl_overflow);
+
+/*
+ * dm355_enable_clock - Enable VPSS Clock
+ * @clock_sel: CLock to be enabled/disabled
+ * @en: enable/disable flag
+ *
+ * This is called to enable or disable a vpss clock
+ */
+static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ unsigned long flags;
+ u32 utemp, mask = 0x1, shift = 0;
+
+ switch (clock_sel) {
+ case VPSS_VPBE_CLOCK:
+ /* nothing since lsb */
+ break;
+ case VPSS_VENC_CLOCK_SEL:
+ shift = 2;
+ break;
+ case VPSS_CFALD_CLOCK:
+ shift = 3;
+ break;
+ case VPSS_H3A_CLOCK:
+ shift = 4;
+ break;
+ case VPSS_IPIPE_CLOCK:
+ shift = 5;
+ break;
+ case VPSS_CCDC_CLOCK:
+ shift = 6;
+ break;
+ default:
+ printk(KERN_ERR "dm355_enable_clock:"
+ " Invalid selector: %d\n", clock_sel);
+ return -1;
+ }
+
+ spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
+ utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
+ if (!en)
+ utemp &= ~(mask << shift);
+ else
+ utemp |= (mask << shift);
+
+ vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
+ spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
+ return 0;
+}
+
+int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
+{
+ if (!oper_cfg.hw_ops.enable_clock)
+ return -1;
+
+ return oper_cfg.hw_ops.enable_clock(clock_sel, en);
+}
+EXPORT_SYMBOL(vpss_enable_clock);
+
+static int __init vpss_probe(struct platform_device *pdev)
+{
+ int status, dm355 = 0;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENOENT;
+ }
+ strcpy(oper_cfg.vpss_name, pdev->dev.platform_data);
+
+ if (!strcmp(oper_cfg.vpss_name, "dm355_vpss"))
+ dm355 = 1;
+ else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) {
+ dev_err(&pdev->dev, "vpss driver not supported on"
+ " this platform\n");
+ return -ENODEV;
+ }
+
+ dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name);
+ oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!oper_cfg.r1)
+ return -ENOENT;
+
+ oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1;
+
+ oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1,
+ oper_cfg.r1->name);
+ if (!oper_cfg.r1)
+ return -EBUSY;
+
+ oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1);
+ if (!oper_cfg.vpss_bl_regs_base) {
+ status = -EBUSY;
+ goto fail1;
+ }
+
+ if (dm355) {
+ oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!oper_cfg.r2) {
+ status = -ENOENT;
+ goto fail2;
+ }
+ oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1;
+ oper_cfg.r2 = request_mem_region(oper_cfg.r2->start,
+ oper_cfg.len2,
+ oper_cfg.r2->name);
+ if (!oper_cfg.r2) {
+ status = -EBUSY;
+ goto fail2;
+ }
+
+ oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start,
+ oper_cfg.len2);
+ if (!oper_cfg.vpss_regs_base) {
+ status = -EBUSY;
+ goto fail3;
+ }
+ }
+
+ if (dm355) {
+ oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
+ oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
+ } else
+ oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
+
+ spin_lock_init(&oper_cfg.vpss_lock);
+ dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name);
+ return 0;
+
+fail3:
+ release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+fail2:
+ iounmap(oper_cfg.vpss_bl_regs_base);
+fail1:
+ release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
+ return status;
+}
+
+static int vpss_remove(struct platform_device *pdev)
+{
+ iounmap(oper_cfg.vpss_bl_regs_base);
+ release_mem_region(oper_cfg.r1->start, oper_cfg.len1);
+ if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) {
+ iounmap(oper_cfg.vpss_regs_base);
+ release_mem_region(oper_cfg.r2->start, oper_cfg.len2);
+ }
+ return 0;
+}
+
+static struct platform_driver vpss_driver = {
+ .driver = {
+ .name = "vpss",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(vpss_remove),
+ .probe = vpss_probe,
+};
+
+static void vpss_exit(void)
+{
+ platform_driver_unregister(&vpss_driver);
+}
+
+static int __init vpss_init(void)
+{
+ return platform_driver_register(&vpss_driver);
+}
+subsys_initcall(vpss_init);
+module_exit(vpss_exit);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index ebd24a25fb85..525eb0f25a7f 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -58,8 +58,6 @@ static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
-#define MT9V011_VERSION 0x8243
-
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
static unsigned long em28xx_devused;
@@ -159,6 +157,20 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
{ -1, -1, -1, -1},
};
+/* Pinnacle Hybrid Pro eb1a:2881 */
+static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+ {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+ {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */
+ {EM2880_R04_GPO, 0x0c, 0xff, 1},
+ { -1, -1, -1, -1},
+};
+
+
/* Callback for the most boards */
static struct em28xx_reg_seq default_tuner_gpio[] = {
{EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
@@ -205,13 +217,15 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = {
*/
struct em28xx_board em28xx_boards[] = {
[EM2750_BOARD_UNKNOWN] = {
- .name = "Unknown EM2750/EM2751 webcam grabber",
+ .name = "EM2710/EM2750/EM2751 webcam grabber",
.xclk = EM28XX_XCLK_FREQUENCY_48MHZ,
- .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
.amux = EM28XX_AMUX_VIDEO,
+ .gpio = silvercrest_reg_seq,
} },
},
[EM2800_BOARD_UNKNOWN] = {
@@ -233,13 +247,15 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_UNKNOWN] = {
.name = "Unknown EM2750/28xx video grabber",
.tuner_type = TUNER_ABSENT,
+ .is_webcam = 1, /* To enable sensor probe */
},
[EM2750_BOARD_DLCW_130] = {
/* Beijing Huaqi Information Digital Technology Co., Ltd */
.name = "Huaqi DLCW-130",
.valid = EM28XX_BOARD_NOT_VALIDATED,
.xclk = EM28XX_XCLK_FREQUENCY_48MHZ,
- .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -440,7 +456,8 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
.name = "Videology 20K14XUSB USB2.0",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -450,8 +467,7 @@ struct em28xx_board em28xx_boards[] = {
[EM2820_BOARD_SILVERCREST_WEBCAM] = {
.name = "Silvercrest Webcam 1.3mpix",
.tuner_type = TUNER_ABSENT,
- .is_27xx = 1,
- .decoder = EM28XX_MT9V011,
+ .is_webcam = 1,
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -500,7 +516,8 @@ struct em28xx_board em28xx_boards[] = {
/* Beijing Huaqi Information Digital Technology Co., Ltd */
.name = "NetGMBH Cam",
.valid = EM28XX_BOARD_NOT_VALIDATED,
- .tuner_type = TUNER_ABSENT, /* This is a webcam */
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -605,22 +622,27 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2861_BOARD_PLEXTOR_PX_TV100U] = {
.name = "Plextor ConvertX PX-TV100U",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_TNF_5335MF,
+ .xclk = EM28XX_XCLK_I2S_MSB_TIMING |
+ EM28XX_XCLK_FREQUENCY_12MHZ,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
+ .has_msp34xx = 1,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = pinnacle_hybrid_pro_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = pinnacle_hybrid_pro_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
+ .gpio = pinnacle_hybrid_pro_analog,
} },
},
@@ -1250,25 +1272,26 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
.name = "Pinnacle Hybrid Pro",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
+ .has_dvb = 1,
+ .dvb_gpio = pinnacle_hybrid_pro_digital,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
- .gpio = default_analog,
+ .gpio = pinnacle_hybrid_pro_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
- .gpio = default_analog,
+ .gpio = pinnacle_hybrid_pro_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
- .gpio = default_analog,
+ .gpio = pinnacle_hybrid_pro_analog,
} },
},
[EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
@@ -1624,6 +1647,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
{ USB_DEVICE(0x04bb, 0x0515),
.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
+ { USB_DEVICE(0xeb1a, 0x50a6),
+ .driver_info = EM2860_BOARD_GADMEI_UTV330 },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1638,6 +1663,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
{0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
{0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
+ {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
};
/* I2C devicelist hash table for devices with generic USB IDs */
@@ -1704,6 +1730,32 @@ static inline void em28xx_set_model(struct em28xx *dev)
EM28XX_I2C_FREQ_100_KHZ;
}
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+ int i;
+ unsigned char regs[][3] = {
+ { 0x0d, 0x00, 0x01, },
+ { 0x0d, 0x00, 0x00, },
+ { 0x04, 0x05, 0x00, }, /* hres = 1280 */
+ { 0x03, 0x04, 0x00, }, /* vres = 1024 */
+ { 0x20, 0x11, 0x00, },
+ { 0x06, 0x00, 0x10, },
+ { 0x2b, 0x00, 0x24, },
+ { 0x2e, 0x00, 0x24, },
+ { 0x35, 0x00, 0x24, },
+ { 0x2d, 0x00, 0x20, },
+ { 0x2c, 0x00, 0x20, },
+ { 0x09, 0x0a, 0xd4, },
+ { 0x35, 0x00, 0x57, },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
+
+ return 0;
+}
+
/* HINT method: webcam I2C chips
*
* This method work for webcams with Micron sensors
@@ -1716,9 +1768,6 @@ static int em28xx_hint_sensor(struct em28xx *dev)
__be16 version_be;
u16 version;
- if (dev->model != EM2820_BOARD_UNKNOWN)
- return 0;
-
dev->i2c_client.addr = 0xba >> 1;
cmd = 0;
i2c_master_send(&dev->i2c_client, &cmd, 1);
@@ -1729,16 +1778,39 @@ static int em28xx_hint_sensor(struct em28xx *dev)
version = be16_to_cpu(version_be);
switch (version) {
- case MT9V011_VERSION:
+ case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */
+ case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */
dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
sensor_name = "mt9v011";
+ dev->em28xx_sensor = EM28XX_MT9V011;
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 480;
+ dev->sensor_xtal = 6300000;
+
+ /* probably means GRGB 16 bit bayer */
+ dev->vinmode = 0x0d;
+ dev->vinctl = 0x00;
+
+ break;
+ case 0x8431:
+ dev->model = EM2750_BOARD_UNKNOWN;
+ sensor_name = "mt9m001";
+ dev->em28xx_sensor = EM28XX_MT9M001;
+ em28xx_initialize_mt9m001(dev);
+ dev->sensor_xres = 1280;
+ dev->sensor_yres = 1024;
+
+ /* probably means BGGR 16 bit bayer */
+ dev->vinmode = 0x0c;
+ dev->vinctl = 0x00;
+
break;
default:
- printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version));
+ printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version));
return -EINVAL;
}
- em28xx_errdev("Sensor is %s, assuming that webcam is %s\n",
+ em28xx_errdev("Sensor is %s, using model %s entry.\n",
sensor_name, em28xx_boards[dev->model].name);
return 0;
@@ -1772,10 +1844,7 @@ void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_info("chip ID is em2750\n");
break;
case CHIP_ID_EM2820:
- if (dev->board.is_27xx)
- em28xx_info("chip is em2710\n");
- else
- em28xx_info("chip ID is em2820\n");
+ em28xx_info("chip ID is em2710 or em2820\n");
break;
case CHIP_ID_EM2840:
em28xx_info("chip ID is em2840\n");
@@ -1815,9 +1884,8 @@ void em28xx_pre_card_setup(struct em28xx *dev)
/* request some modules */
switch (dev->model) {
case EM2861_BOARD_PLEXTOR_PX_TV100U:
- /* FIXME guess */
- /* Turn on analog audio output */
- em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ /* Sets the msp34xx I2S speed */
+ dev->i2s_speed = 2048000;
break;
case EM2861_BOARD_KWORLD_PVRTV_300U:
case EM2880_BOARD_KWORLD_DVB_305U:
@@ -1929,6 +1997,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_ZARLINK456;
break;
case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2881_BOARD_PINNACLE_HYBRID_PRO:
ctl->demod = XC3028_FE_ZARLINK456;
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
@@ -2225,6 +2294,7 @@ void em28xx_card_setup(struct em28xx *dev)
em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
so make the call now so the analog GPIOs are set properly
before probing the i2c bus. */
+ em28xx_gpio_set(dev, dev->board.tuner_gpio);
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
case EM2820_BOARD_SILVERCREST_WEBCAM:
@@ -2262,9 +2332,14 @@ void em28xx_card_setup(struct em28xx *dev)
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"tvp5150", "tvp5150", tvp5150_addrs);
- if (dev->board.decoder == EM28XX_MT9V011)
- v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "mt9v011", "mt9v011", mt9v011_addrs);
+ if (dev->em28xx_sensor == EM28XX_MT9V011) {
+ struct v4l2_subdev *sd;
+
+ sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs);
+ v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+ }
+
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
@@ -2410,7 +2485,19 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
return errCode;
}
- em28xx_hint_sensor(dev);
+ /*
+ * Default format, used for tvp5150 or saa711x output formats
+ */
+ dev->vinmode = 0x10;
+ dev->vinctl = 0x11;
+
+ /*
+ * If the device can be a webcam, seek for a sensor.
+ * If sensor is not found, then it isn't a webcam.
+ */
+ if (dev->board.is_webcam)
+ if (em28xx_hint_sensor(dev) < 0)
+ dev->board.is_webcam = 0;
/* Do board specific init and eeprom reading */
em28xx_card_setup(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 079ab4d563a6..5b78e199abd1 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -648,28 +648,17 @@ int em28xx_capture_start(struct em28xx *dev, int start)
int em28xx_set_outfmt(struct em28xx *dev)
{
int ret;
- int vinmode, vinctl, outfmt;
-
- outfmt = dev->format->reg;
-
- if (dev->board.is_27xx) {
- vinmode = 0x0d;
- vinctl = 0x00;
- } else {
- vinmode = 0x10;
- vinctl = 0x11;
- }
ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
- outfmt | 0x20, 0xff);
+ dev->format->reg | 0x20, 0xff);
if (ret < 0)
return ret;
- ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode);
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
if (ret < 0)
return ret;
- return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl);
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl);
}
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -707,10 +696,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
- if (dev->board.is_27xx) {
- /* FIXME: Don't use the scaler yet */
- mode = 0;
- } else if (dev->board.is_em2800) {
+ if (dev->board.is_em2800) {
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
} else {
u8 buf[2];
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 3da97c32b8fa..cf0ac7f2a30d 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -31,6 +31,8 @@
#include "lgdt330x.h"
#include "zl10353.h"
#include "s5h1409.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -243,7 +245,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
};
-static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = {
+static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
.disable_i2c_gate_ctrl = 1,
@@ -258,6 +260,41 @@ static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
};
#endif
+static int mt352_terratec_xs_init(struct dvb_frontend *fe)
+{
+ /* Values extracted from a USB trace of the Terratec Windows driver */
+ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c };
+ static u8 reset[] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
+ static u8 rs_err_cfg[] = { RS_ERR_PER_1, 0x00, 0x4d };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+ static u8 trl_nom_cfg[] = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
+ static u8 tps_given_cfg[] = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
+ static u8 tuner_go[] = { TUNER_GO, 0x01};
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
+ mt352_write(fe, rs_err_cfg, sizeof(rs_err_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ mt352_write(fe, trl_nom_cfg, sizeof(trl_nom_cfg));
+ mt352_write(fe, tps_given_cfg, sizeof(tps_given_cfg));
+ mt352_write(fe, tuner_go, sizeof(tuner_go));
+ return 0;
+}
+
+static struct mt352_config terratec_xs_mt352_cfg = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .if2 = 45600,
+ .demod_init = mt352_terratec_xs_init,
+};
+
/* ------------------------------------------------------------------ */
static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -440,7 +477,6 @@ static int dvb_init(struct em28xx *dev)
goto out_free;
}
break;
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2880_BOARD_KWORLD_DVB_310U:
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->frontend = dvb_attach(zl10353_attach,
@@ -451,20 +487,28 @@ static int dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ dvb->frontend = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_xc3028_no_i2c_gate,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2881_BOARD_PINNACLE_HYBRID_PRO:
dvb->frontend = dvb_attach(zl10353_attach,
- &em28xx_terratec_xs_zl10353_xc3028,
+ &em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
if (dvb->frontend == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
-
- /* FIXME: make support for mt352 work */
- printk(KERN_ERR "version of this board with mt352 not "
- "currently supported\n");
- result = -EINVAL;
- goto out_free;
+ dvb->frontend = dvb_attach(mt352_attach,
+ &terratec_xs_mt352_cfg,
+ &dev->i2c_adap);
}
+
if (attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 27e33a287dfc..71474d31e155 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -459,7 +459,6 @@ static struct i2c_algorithm em28xx_algo = {
static struct i2c_adapter em28xx_adap_template = {
.owner = THIS_MODULE,
.name = "em28xx",
- .id = I2C_HW_B_EM28XX,
.algo = &em28xx_algo,
};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 14316c912179..2a1f0335d800 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -124,7 +124,7 @@ static struct em28xx_fmt format[] = {
/* supported controls */
/* Common to all boards */
-static struct v4l2_queryctrl em28xx_qctrl[] = {
+static struct v4l2_queryctrl ac97_qctrl[] = {
{
.id = V4L2_CID_AUDIO_VOLUME,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -133,7 +133,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.maximum = 0x1f,
.step = 0x1,
.default_value = 0x1f,
- .flags = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -600,10 +600,29 @@ static void res_free(struct em28xx_fh *fh)
}
/*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
+ * ac97_queryctrl()
+ * return the ac97 supported controls
*/
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+
+ /* Control is not ac97 related */
+ return 1;
+}
+
+/*
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
+ */
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -613,29 +632,41 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
ctrl->value = dev->volume;
return 0;
default:
- return -EINVAL;
+ /* Control is not ac97 related */
+ return 1;
}
}
/*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
*/
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+ if (ctrl->id == ac97_qctrl[i].id)
+ goto handle;
+
+ /* Announce that hasn't handle it */
+ return 1;
+
+handle:
+ if (ctrl->value < ac97_qctrl[i].minimum ||
+ ctrl->value > ac97_qctrl[i].maximum)
+ return -ERANGE;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value != dev->mute) {
- dev->mute = ctrl->value;
- return em28xx_audio_analog_set(dev);
- }
- return 0;
+ dev->mute = ctrl->value;
+ break;
case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->value;
- return em28xx_audio_analog_set(dev);
- default:
- return -EINVAL;
+ break;
}
+
+ return em28xx_audio_analog_set(dev);
}
static int check_dev(struct em28xx *dev)
@@ -657,8 +688,8 @@ static void get_scale(struct em28xx *dev,
unsigned int width, unsigned int height,
unsigned int *hscale, unsigned int *vscale)
{
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
if (*hscale >= 0x4000)
@@ -726,11 +757,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
}
- if (dev->board.is_27xx) {
- /* FIXME: This is the only supported fmt */
- width = 640;
- height = 480;
- } else if (dev->board.is_em2800) {
+ if (dev->board.is_em2800) {
/* the em2800 can only scale down to 50% */
height = height > (3 * maxh / 4) ? maxh : maxh / 2;
width = width > (3 * maxw / 4) ? maxw : maxw / 2;
@@ -767,12 +794,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
{
struct em28xx_fmt *fmt;
- /* FIXME: This is the only supported fmt */
- if (dev->board.is_27xx) {
- width = 640;
- height = 480;
- }
-
fmt = format_by_fourcc(fourcc);
if (!fmt)
return -EINVAL;
@@ -997,7 +1018,6 @@ static int vidioc_queryctrl(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int id = qc->id;
- int i;
int rc;
rc = check_dev(dev);
@@ -1008,15 +1028,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
qc->id = id;
- if (!dev->board.has_msp34xx) {
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
+ /* enumberate AC97 controls */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ rc = ac97_queryctrl(qc);
+ if (!rc)
+ return 0;
}
+ /* enumberate V4L2 device controls */
mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
mutex_unlock(&dev->lock);
@@ -1041,14 +1060,16 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
mutex_lock(&dev->lock);
- if (dev->board.has_msp34xx)
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_get_ctrl(dev, ctrl);
+ else
+ rc = 1;
+
+ /* It were not an AC97 control. Sends it to the v4l2 dev interface */
+ if (rc == 1) {
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- else {
- rc = em28xx_get_ctrl(dev, ctrl);
- if (rc < 0) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- rc = 0;
- }
+ rc = 0;
}
mutex_unlock(&dev->lock);
@@ -1060,7 +1081,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u8 i;
int rc;
rc = check_dev(dev);
@@ -1069,28 +1089,31 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
mutex_lock(&dev->lock);
- if (dev->board.has_msp34xx)
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
- else {
+ /* Set an AC97 control */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+ rc = ac97_set_ctrl(dev, ctrl);
+ else
rc = 1;
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (ctrl->id == em28xx_qctrl[i].id) {
- if (ctrl->value < em28xx_qctrl[i].minimum ||
- ctrl->value > em28xx_qctrl[i].maximum) {
- rc = -ERANGE;
- break;
- }
-
- rc = em28xx_set_ctrl(dev, ctrl);
- break;
- }
- }
- }
- /* Control not found - try to send it to the attached devices */
+ /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
if (rc == 1) {
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
- rc = 0;
+
+ /*
+ * In the case of non-AC97 volume controls, we still need
+ * to do some setups at em28xx, in order to mute/unmute
+ * and to adjust audio volume. However, the value ranges
+ * should be checked by the corresponding V4L subdriver.
+ */
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ dev->mute = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ rc = em28xx_audio_analog_set(dev);
+ }
}
mutex_unlock(&dev->lock);
@@ -1613,9 +1636,9 @@ static int radio_queryctrl(struct file *file, void *priv,
qc->id >= V4L2_CID_LASTP1)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+ for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+ if (qc->id && qc->id == ac97_qctrl[i].id) {
+ memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
return 0;
}
}
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index d90fef463764..45bd513f62dc 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -358,10 +358,15 @@ struct em28xx_input {
#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
enum em28xx_decoder {
- EM28XX_NODECODER,
+ EM28XX_NODECODER = 0,
EM28XX_TVP5150,
EM28XX_SAA711X,
+};
+
+enum em28xx_sensor {
+ EM28XX_NOSENSOR = 0,
EM28XX_MT9V011,
+ EM28XX_MT9M001,
};
enum em28xx_adecoder {
@@ -390,7 +395,7 @@ struct em28xx_board {
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
unsigned int has_snapshot_button:1;
- unsigned int is_27xx:1;
+ unsigned int is_webcam:1;
unsigned int valid:1;
unsigned char xclk, i2c_speed;
@@ -474,6 +479,14 @@ struct em28xx {
struct v4l2_device v4l2_dev;
struct em28xx_board board;
+ /* Webcam specific fields */
+ enum em28xx_sensor em28xx_sensor;
+ int sensor_xres, sensor_yres;
+ int sensor_xtal;
+
+ /* Vinmode/Vinctl used at the driver */
+ int vinmode, vinctl;
+
unsigned int stream_on:1; /* Locks streams */
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
@@ -754,17 +767,23 @@ static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
/*FIXME: maxw should be dependent of alt mode */
static inline unsigned int norm_maxw(struct em28xx *dev)
{
+ if (dev->board.is_webcam)
+ return dev->sensor_xres;
+
if (dev->board.max_range_640_480)
return 640;
- else
- return 720;
+
+ return 720;
}
static inline unsigned int norm_maxh(struct em28xx *dev)
{
+ if (dev->board.is_webcam)
+ return dev->sensor_yres;
+
if (dev->board.max_range_640_480)
return 480;
- else
- return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
+
+ return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
}
#endif
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 578dc4ffc965..34f46f2bc040 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -102,6 +102,22 @@ config USB_GSPCA_PAC7311
To compile this driver as a module, choose M here: the
module will be called gspca_pac7311.
+config USB_GSPCA_SN9C20X
+ tristate "SN9C20X USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the
+ sn9c20x chips (SN9C201 and SN9C202).
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sn9c20x.
+
+config USB_GSPCA_SN9C20X_EVDEV
+ bool "Enable evdev support"
+ depends on USB_GSPCA_SN9C20X
+ ---help---
+ Say Y here in order to enable evdev support for sn9c20x webcam button.
+
config USB_GSPCA_SONIXB
tristate "SONIX Bayer USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 8a6643e8eb96..f6d3b86e9ad5 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o
obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o
obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o
obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o
@@ -35,6 +36,7 @@ gspca_ov519-objs := ov519.o
gspca_ov534-objs := ov534.o
gspca_pac207-objs := pac207.o
gspca_pac7311-objs := pac7311.o
+gspca_sn9c20x-objs := sn9c20x.o
gspca_sonixb-objs := sonixb.o
gspca_sonixj-objs := sonixj.o
gspca_spca500-objs := spca500.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 219cfa6fb877..8d48ea1742c2 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -846,6 +846,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 1e89600986c8..016599def6b5 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 6, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 7, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -486,6 +486,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
}
PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
i, ep->desc.bEndpointAddress);
+ gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
@@ -493,7 +494,6 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
return NULL;
}
}
- gspca_dev->alt = i; /* memorize the current alt setting */
return ep;
}
@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
if (!gspca_dev->cam.bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (gspca_dev->pkt_size == 0)
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ else
+ psize = gspca_dev->pkt_size;
npkt = gspca_dev->cam.npkt;
if (npkt == 0)
npkt = 32; /* default value */
@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* set the higher alternate setting and
* loop until urb submit succeeds */
gspca_dev->alt = gspca_dev->nbalt;
+ if (gspca_dev->sd_desc->isoc_init) {
+ ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
+ if (ret < 0)
+ goto out;
+ }
+ ep = get_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
for (;;) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
- ep = get_ep(gspca_dev);
- if (ep == NULL) {
- ret = -EIO;
- goto out;
- }
ret = create_urbs(gspca_dev, ep);
if (ret < 0)
goto out;
@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* submit the URBs */
for (n = 0; n < gspca_dev->nurbs; n++) {
ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
- if (ret < 0) {
- PDEBUG(D_ERR|D_STREAM,
- "usb_submit_urb [%d] err %d", n, ret);
- gspca_dev->streaming = 0;
- destroy_urbs(gspca_dev);
- if (ret == -ENOSPC) {
- msleep(20); /* wait for kill
- * complete */
- break; /* try the previous alt */
- }
- goto out;
- }
+ if (ret < 0)
+ break;
}
if (ret >= 0)
break;
+ PDEBUG(D_ERR|D_STREAM,
+ "usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ if (ret != -ENOSPC)
+ goto out;
+
+ /* the bandwidth is not wide enough
+ * negociate or try a lower alternate setting */
+ msleep(20); /* wait for kill complete */
+ if (gspca_dev->sd_desc->isoc_nego) {
+ ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
+ if (ret < 0)
+ goto out;
+ } else {
+ ep = get_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ }
}
out:
mutex_unlock(&gspca_dev->usb_lock);
@@ -727,6 +746,74 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ int ret;
+ struct gspca_dev *gspca_dev = priv;
+
+ if (!gspca_dev->sd_desc->get_chip_ident)
+ return -EINVAL;
+
+ if (!gspca_dev->sd_desc->get_register)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (gspca_dev->present)
+ ret = gspca_dev->sd_desc->get_register(gspca_dev, reg);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ return ret;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ int ret;
+ struct gspca_dev *gspca_dev = priv;
+
+ if (!gspca_dev->sd_desc->get_chip_ident)
+ return -EINVAL;
+
+ if (!gspca_dev->sd_desc->set_register)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (gspca_dev->present)
+ ret = gspca_dev->sd_desc->set_register(gspca_dev, reg);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ return ret;
+}
+#endif
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ int ret;
+ struct gspca_dev *gspca_dev = priv;
+
+ if (!gspca_dev->sd_desc->get_chip_ident)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (gspca_dev->present)
+ ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ return ret;
+}
+
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmtdesc)
{
@@ -1883,6 +1970,11 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_s_parm = vidioc_s_parm,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index bd1faff88644..70b1fd830876 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -69,6 +69,10 @@ typedef void (*cam_v_op) (struct gspca_dev *);
typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
typedef int (*cam_jpg_op) (struct gspca_dev *,
struct v4l2_jpegcompression *);
+typedef int (*cam_reg_op) (struct gspca_dev *,
+ struct v4l2_dbg_register *);
+typedef int (*cam_ident_op) (struct gspca_dev *,
+ struct v4l2_dbg_chip_ident *);
typedef int (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
typedef int (*cam_qmnu_op) (struct gspca_dev *,
@@ -94,9 +98,11 @@ struct sd_desc {
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
- cam_op start; /* called on stream on */
+ cam_op start; /* called on stream on after URBs creation */
cam_pkt_op pkt_scan;
/* optional operations */
+ cam_op isoc_init; /* called on stream on before getting the EP */
+ cam_op isoc_nego; /* called when URB submit failed with NOSPC */
cam_v_op stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off & disconnect - alt 0 */
cam_v_op dq_callback; /* called when a frame has been dequeued */
@@ -105,6 +111,11 @@ struct sd_desc {
cam_qmnu_op querymenu;
cam_streamparm_op get_streamparm;
cam_streamparm_op set_streamparm;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ cam_reg_op set_register;
+ cam_reg_op get_register;
+#endif
+ cam_ident_op get_chip_ident;
};
/* packet types when moving from iso buf to frame buf */
@@ -169,6 +180,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
+ u16 pkt_size; /* ISOC packet size */
};
int gspca_dev_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 8a5bba16ff32..7f1e5415850b 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -56,7 +56,7 @@ int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
return (err < 0) ? err : 0;
}
-/* Writes a byte to to the m5602 */
+/* Writes a byte to the m5602 */
int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
{
int err;
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 191bcd718979..0163903d1c0f 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -476,9 +476,6 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
- err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
- if (err < 0)
- return err;
err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
@@ -524,9 +521,6 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
- err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
- if (err < 0)
- return err;
err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 75e8d14e4ac7..de769caf013d 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -201,6 +201,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index e1e3a3a50484..0caf3c075730 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -1068,6 +1068,7 @@ static __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
{}
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
new file mode 100644
index 000000000000..52a7f8edf7ac
--- /dev/null
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -0,0 +1,2436 @@
+/*
+ * Sonix sn9c201 sn9c202 library
+ * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
+ * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ */
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/usb/input.h>
+#include <linux/input.h>
+#endif
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#include <media/v4l2-chip-ident.h>
+
+MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
+ "microdia project <microdia@googlegroups.com>");
+MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define MODULE_NAME "sn9c20x"
+
+#define MODE_RAW 0x10
+#define MODE_JPEG 0x20
+#define MODE_SXGA 0x80
+
+#define SENSOR_OV9650 0
+#define SENSOR_OV9655 1
+#define SENSOR_SOI968 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_MT9V011 5
+#define SENSOR_MT9V111 6
+#define SENSOR_MT9V112 7
+#define SENSOR_MT9M001 8
+#define SENSOR_MT9M111 9
+#define SENSOR_HV7131R 10
+#define SENSOR_MT9VPRB 20
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev;
+
+#define MIN_AVG_LUM 80
+#define MAX_AVG_LUM 130
+ atomic_t avg_lum;
+ u8 old_step;
+ u8 older_step;
+ u8 exposure_step;
+
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ s16 hue;
+ u8 gamma;
+ u8 red;
+ u8 blue;
+
+ u8 hflip;
+ u8 vflip;
+ u8 gain;
+ u16 exposure;
+ u8 auto_exposure;
+
+ u8 i2c_addr;
+ u8 sensor;
+ u8 hstart;
+ u8 vstart;
+
+ u8 *jpeg_hdr;
+ u8 quality;
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+ struct input_dev *input_dev;
+ u8 input_gpio;
+ struct task_struct *input_task;
+#endif
+};
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
+static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
+static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+#define BRIGHTNESS_IDX 0
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+#define BRIGHTNESS_DEFAULT 0x7f
+ .default_value = BRIGHTNESS_DEFAULT,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+#define CONTRAST_IDX 1
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+#define CONTRAST_DEFAULT 0x7f
+ .default_value = CONTRAST_DEFAULT,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+#define SATURATION_IDX 2
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+#define SATURATION_DEFAULT 0x7f
+ .default_value = SATURATION_DEFAULT,
+ },
+ .set = sd_setsaturation,
+ .get = sd_getsaturation,
+ },
+ {
+#define HUE_IDX 3
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -180,
+ .maximum = 180,
+ .step = 1,
+#define HUE_DEFAULT 0
+ .default_value = HUE_DEFAULT,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+ {
+#define GAMMA_IDX 4
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+#define GAMMA_DEFAULT 0x10
+ .default_value = GAMMA_DEFAULT,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+ {
+#define BLUE_IDX 5
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 0x7f,
+ .step = 1,
+#define BLUE_DEFAULT 0x28
+ .default_value = BLUE_DEFAULT,
+ },
+ .set = sd_setbluebalance,
+ .get = sd_getbluebalance,
+ },
+ {
+#define RED_IDX 6
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 0x7f,
+ .step = 1,
+#define RED_DEFAULT 0x28
+ .default_value = RED_DEFAULT,
+ },
+ .set = sd_setredbalance,
+ .get = sd_getredbalance,
+ },
+ {
+#define HFLIP_IDX 7
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define HFLIP_DEFAULT 0
+ .default_value = HFLIP_DEFAULT,
+ },
+ .set = sd_sethflip,
+ .get = sd_gethflip,
+ },
+ {
+#define VFLIP_IDX 8
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define VFLIP_DEFAULT 0
+ .default_value = VFLIP_DEFAULT,
+ },
+ .set = sd_setvflip,
+ .get = sd_getvflip,
+ },
+ {
+#define EXPOSURE_IDX 9
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 0x1780,
+ .step = 1,
+#define EXPOSURE_DEFAULT 0x33
+ .default_value = EXPOSURE_DEFAULT,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+#define GAIN_IDX 10
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 28,
+ .step = 1,
+#define GAIN_DEFAULT 0x00
+ .default_value = GAIN_DEFAULT,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+ {
+#define AUTOGAIN_IDX 11
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTO_EXPOSURE_DEFAULT 1
+ .default_value = AUTO_EXPOSURE_DEFAULT,
+ },
+ .set = sd_setautoexposure,
+ .get = sd_getautoexposure,
+ },
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 240,
+ .sizeimage = 240 * 120,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0 | MODE_JPEG},
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0 | MODE_RAW},
+ {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 240,
+ .sizeimage = 240 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 480,
+ .sizeimage = 480 * 240 ,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1 | MODE_JPEG},
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1 | MODE_RAW},
+ {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 480,
+ .sizeimage = 480 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 960,
+ .sizeimage = 960 * 480,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2 | MODE_JPEG},
+ {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2 | MODE_RAW},
+ {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 960,
+ .sizeimage = 960 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+};
+
+static const struct v4l2_pix_format sxga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 240,
+ .sizeimage = 240 * 120,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0 | MODE_JPEG},
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0 | MODE_RAW},
+ {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 240,
+ .sizeimage = 240 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 480,
+ .sizeimage = 480 * 240 ,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1 | MODE_JPEG},
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1 | MODE_RAW},
+ {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 480,
+ .sizeimage = 480 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 960,
+ .sizeimage = 960 * 480,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2 | MODE_JPEG},
+ {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2 | MODE_RAW},
+ {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
+ .bytesperline = 960,
+ .sizeimage = 960 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = (1280 * 1024) + 64,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3 | MODE_RAW | MODE_SXGA},
+};
+
+static const int hsv_red_x[] = {
+ 41, 44, 46, 48, 50, 52, 54, 56,
+ 58, 60, 62, 64, 66, 68, 70, 72,
+ 74, 76, 78, 80, 81, 83, 85, 87,
+ 88, 90, 92, 93, 95, 97, 98, 100,
+ 101, 102, 104, 105, 107, 108, 109, 110,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 123, 124, 125, 125,
+ 126, 127, 127, 128, 128, 129, 129, 129,
+ 130, 130, 130, 130, 131, 131, 131, 131,
+ 131, 131, 131, 131, 130, 130, 130, 130,
+ 129, 129, 129, 128, 128, 127, 127, 126,
+ 125, 125, 124, 123, 122, 122, 121, 120,
+ 119, 118, 117, 116, 115, 114, 112, 111,
+ 110, 109, 107, 106, 105, 103, 102, 101,
+ 99, 98, 96, 94, 93, 91, 90, 88,
+ 86, 84, 83, 81, 79, 77, 75, 74,
+ 72, 70, 68, 66, 64, 62, 60, 58,
+ 56, 54, 52, 49, 47, 45, 43, 41,
+ 39, 36, 34, 32, 30, 28, 25, 23,
+ 21, 19, 16, 14, 12, 9, 7, 5,
+ 3, 0, -1, -3, -6, -8, -10, -12,
+ -15, -17, -19, -22, -24, -26, -28, -30,
+ -33, -35, -37, -39, -41, -44, -46, -48,
+ -50, -52, -54, -56, -58, -60, -62, -64,
+ -66, -68, -70, -72, -74, -76, -78, -80,
+ -81, -83, -85, -87, -88, -90, -92, -93,
+ -95, -97, -98, -100, -101, -102, -104, -105,
+ -107, -108, -109, -110, -112, -113, -114, -115,
+ -116, -117, -118, -119, -120, -121, -122, -123,
+ -123, -124, -125, -125, -126, -127, -127, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -127, -127, -126, -125, -125, -124, -123,
+ -122, -122, -121, -120, -119, -118, -117, -116,
+ -115, -114, -112, -111, -110, -109, -107, -106,
+ -105, -103, -102, -101, -99, -98, -96, -94,
+ -93, -91, -90, -88, -86, -84, -83, -81,
+ -79, -77, -75, -74, -72, -70, -68, -66,
+ -64, -62, -60, -58, -56, -54, -52, -49,
+ -47, -45, -43, -41, -39, -36, -34, -32,
+ -30, -28, -25, -23, -21, -19, -16, -14,
+ -12, -9, -7, -5, -3, 0, 1, 3,
+ 6, 8, 10, 12, 15, 17, 19, 22,
+ 24, 26, 28, 30, 33, 35, 37, 39, 41
+};
+
+static const int hsv_red_y[] = {
+ 82, 80, 78, 76, 74, 73, 71, 69,
+ 67, 65, 63, 61, 58, 56, 54, 52,
+ 50, 48, 46, 44, 41, 39, 37, 35,
+ 32, 30, 28, 26, 23, 21, 19, 16,
+ 14, 12, 10, 7, 5, 3, 0, -1,
+ -3, -6, -8, -10, -13, -15, -17, -19,
+ -22, -24, -26, -29, -31, -33, -35, -38,
+ -40, -42, -44, -46, -48, -51, -53, -55,
+ -57, -59, -61, -63, -65, -67, -69, -71,
+ -73, -75, -77, -79, -81, -82, -84, -86,
+ -88, -89, -91, -93, -94, -96, -98, -99,
+ -101, -102, -104, -105, -106, -108, -109, -110,
+ -112, -113, -114, -115, -116, -117, -119, -120,
+ -120, -121, -122, -123, -124, -125, -126, -126,
+ -127, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, -128, -128, -128, -128,
+ -127, -127, -126, -125, -125, -124, -123, -122,
+ -121, -120, -119, -118, -117, -116, -115, -114,
+ -113, -111, -110, -109, -107, -106, -105, -103,
+ -102, -100, -99, -97, -96, -94, -92, -91,
+ -89, -87, -85, -84, -82, -80, -78, -76,
+ -74, -73, -71, -69, -67, -65, -63, -61,
+ -58, -56, -54, -52, -50, -48, -46, -44,
+ -41, -39, -37, -35, -32, -30, -28, -26,
+ -23, -21, -19, -16, -14, -12, -10, -7,
+ -5, -3, 0, 1, 3, 6, 8, 10,
+ 13, 15, 17, 19, 22, 24, 26, 29,
+ 31, 33, 35, 38, 40, 42, 44, 46,
+ 48, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 82, 84, 86, 88, 89, 91, 93,
+ 94, 96, 98, 99, 101, 102, 104, 105,
+ 106, 108, 109, 110, 112, 113, 114, 115,
+ 116, 117, 119, 120, 120, 121, 122, 123,
+ 124, 125, 126, 126, 127, 128, 128, 129,
+ 129, 130, 130, 131, 131, 131, 131, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 131, 131, 131, 130, 130,
+ 130, 129, 129, 128, 127, 127, 126, 125,
+ 125, 124, 123, 122, 121, 120, 119, 118,
+ 117, 116, 115, 114, 113, 111, 110, 109,
+ 107, 106, 105, 103, 102, 100, 99, 97,
+ 96, 94, 92, 91, 89, 87, 85, 84, 82
+};
+
+static const int hsv_green_x[] = {
+ -124, -124, -125, -125, -125, -125, -125, -125,
+ -125, -126, -126, -125, -125, -125, -125, -125,
+ -125, -124, -124, -124, -123, -123, -122, -122,
+ -121, -121, -120, -120, -119, -118, -117, -117,
+ -116, -115, -114, -113, -112, -111, -110, -109,
+ -108, -107, -105, -104, -103, -102, -100, -99,
+ -98, -96, -95, -93, -92, -91, -89, -87,
+ -86, -84, -83, -81, -79, -77, -76, -74,
+ -72, -70, -69, -67, -65, -63, -61, -59,
+ -57, -55, -53, -51, -49, -47, -45, -43,
+ -41, -39, -37, -35, -33, -30, -28, -26,
+ -24, -22, -20, -18, -15, -13, -11, -9,
+ -7, -4, -2, 0, 1, 3, 6, 8,
+ 10, 12, 14, 17, 19, 21, 23, 25,
+ 27, 29, 32, 34, 36, 38, 40, 42,
+ 44, 46, 48, 50, 52, 54, 56, 58,
+ 60, 62, 64, 66, 68, 70, 71, 73,
+ 75, 77, 78, 80, 82, 83, 85, 87,
+ 88, 90, 91, 93, 94, 96, 97, 98,
+ 100, 101, 102, 104, 105, 106, 107, 108,
+ 109, 111, 112, 113, 113, 114, 115, 116,
+ 117, 118, 118, 119, 120, 120, 121, 122,
+ 122, 123, 123, 124, 124, 124, 125, 125,
+ 125, 125, 125, 125, 125, 126, 126, 125,
+ 125, 125, 125, 125, 125, 124, 124, 124,
+ 123, 123, 122, 122, 121, 121, 120, 120,
+ 119, 118, 117, 117, 116, 115, 114, 113,
+ 112, 111, 110, 109, 108, 107, 105, 104,
+ 103, 102, 100, 99, 98, 96, 95, 93,
+ 92, 91, 89, 87, 86, 84, 83, 81,
+ 79, 77, 76, 74, 72, 70, 69, 67,
+ 65, 63, 61, 59, 57, 55, 53, 51,
+ 49, 47, 45, 43, 41, 39, 37, 35,
+ 33, 30, 28, 26, 24, 22, 20, 18,
+ 15, 13, 11, 9, 7, 4, 2, 0,
+ -1, -3, -6, -8, -10, -12, -14, -17,
+ -19, -21, -23, -25, -27, -29, -32, -34,
+ -36, -38, -40, -42, -44, -46, -48, -50,
+ -52, -54, -56, -58, -60, -62, -64, -66,
+ -68, -70, -71, -73, -75, -77, -78, -80,
+ -82, -83, -85, -87, -88, -90, -91, -93,
+ -94, -96, -97, -98, -100, -101, -102, -104,
+ -105, -106, -107, -108, -109, -111, -112, -113,
+ -113, -114, -115, -116, -117, -118, -118, -119,
+ -120, -120, -121, -122, -122, -123, -123, -124, -124
+};
+
+static const int hsv_green_y[] = {
+ -100, -99, -98, -97, -95, -94, -93, -91,
+ -90, -89, -87, -86, -84, -83, -81, -80,
+ -78, -76, -75, -73, -71, -70, -68, -66,
+ -64, -63, -61, -59, -57, -55, -53, -51,
+ -49, -48, -46, -44, -42, -40, -38, -36,
+ -34, -32, -30, -27, -25, -23, -21, -19,
+ -17, -15, -13, -11, -9, -7, -4, -2,
+ 0, 1, 3, 5, 7, 9, 11, 14,
+ 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46,
+ 48, 50, 52, 54, 56, 58, 59, 61,
+ 63, 65, 67, 68, 70, 72, 74, 75,
+ 77, 78, 80, 82, 83, 85, 86, 88,
+ 89, 90, 92, 93, 95, 96, 97, 98,
+ 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 112, 113, 114,
+ 115, 115, 116, 116, 117, 117, 118, 118,
+ 119, 119, 119, 120, 120, 120, 120, 120,
+ 121, 121, 121, 121, 121, 121, 120, 120,
+ 120, 120, 120, 119, 119, 119, 118, 118,
+ 117, 117, 116, 116, 115, 114, 114, 113,
+ 112, 111, 111, 110, 109, 108, 107, 106,
+ 105, 104, 103, 102, 100, 99, 98, 97,
+ 95, 94, 93, 91, 90, 89, 87, 86,
+ 84, 83, 81, 80, 78, 76, 75, 73,
+ 71, 70, 68, 66, 64, 63, 61, 59,
+ 57, 55, 53, 51, 49, 48, 46, 44,
+ 42, 40, 38, 36, 34, 32, 30, 27,
+ 25, 23, 21, 19, 17, 15, 13, 11,
+ 9, 7, 4, 2, 0, -1, -3, -5,
+ -7, -9, -11, -14, -16, -18, -20, -22,
+ -24, -26, -28, -30, -32, -34, -36, -38,
+ -40, -42, -44, -46, -48, -50, -52, -54,
+ -56, -58, -59, -61, -63, -65, -67, -68,
+ -70, -72, -74, -75, -77, -78, -80, -82,
+ -83, -85, -86, -88, -89, -90, -92, -93,
+ -95, -96, -97, -98, -100, -101, -102, -103,
+ -104, -105, -106, -107, -108, -109, -110, -111,
+ -112, -112, -113, -114, -115, -115, -116, -116,
+ -117, -117, -118, -118, -119, -119, -119, -120,
+ -120, -120, -120, -120, -121, -121, -121, -121,
+ -121, -121, -120, -120, -120, -120, -120, -119,
+ -119, -119, -118, -118, -117, -117, -116, -116,
+ -115, -114, -114, -113, -112, -111, -111, -110,
+ -109, -108, -107, -106, -105, -104, -103, -102, -100
+};
+
+static const int hsv_blue_x[] = {
+ 112, 113, 114, 114, 115, 116, 117, 117,
+ 118, 118, 119, 119, 120, 120, 120, 121,
+ 121, 121, 122, 122, 122, 122, 122, 122,
+ 122, 122, 122, 122, 122, 122, 121, 121,
+ 121, 120, 120, 120, 119, 119, 118, 118,
+ 117, 116, 116, 115, 114, 113, 113, 112,
+ 111, 110, 109, 108, 107, 106, 105, 104,
+ 103, 102, 100, 99, 98, 97, 95, 94,
+ 93, 91, 90, 88, 87, 85, 84, 82,
+ 80, 79, 77, 76, 74, 72, 70, 69,
+ 67, 65, 63, 61, 60, 58, 56, 54,
+ 52, 50, 48, 46, 44, 42, 40, 38,
+ 36, 34, 32, 30, 28, 26, 24, 22,
+ 19, 17, 15, 13, 11, 9, 7, 5,
+ 2, 0, -1, -3, -5, -7, -9, -12,
+ -14, -16, -18, -20, -22, -24, -26, -28,
+ -31, -33, -35, -37, -39, -41, -43, -45,
+ -47, -49, -51, -53, -54, -56, -58, -60,
+ -62, -64, -66, -67, -69, -71, -73, -74,
+ -76, -78, -79, -81, -83, -84, -86, -87,
+ -89, -90, -92, -93, -94, -96, -97, -98,
+ -99, -101, -102, -103, -104, -105, -106, -107,
+ -108, -109, -110, -111, -112, -113, -114, -114,
+ -115, -116, -117, -117, -118, -118, -119, -119,
+ -120, -120, -120, -121, -121, -121, -122, -122,
+ -122, -122, -122, -122, -122, -122, -122, -122,
+ -122, -122, -121, -121, -121, -120, -120, -120,
+ -119, -119, -118, -118, -117, -116, -116, -115,
+ -114, -113, -113, -112, -111, -110, -109, -108,
+ -107, -106, -105, -104, -103, -102, -100, -99,
+ -98, -97, -95, -94, -93, -91, -90, -88,
+ -87, -85, -84, -82, -80, -79, -77, -76,
+ -74, -72, -70, -69, -67, -65, -63, -61,
+ -60, -58, -56, -54, -52, -50, -48, -46,
+ -44, -42, -40, -38, -36, -34, -32, -30,
+ -28, -26, -24, -22, -19, -17, -15, -13,
+ -11, -9, -7, -5, -2, 0, 1, 3,
+ 5, 7, 9, 12, 14, 16, 18, 20,
+ 22, 24, 26, 28, 31, 33, 35, 37,
+ 39, 41, 43, 45, 47, 49, 51, 53,
+ 54, 56, 58, 60, 62, 64, 66, 67,
+ 69, 71, 73, 74, 76, 78, 79, 81,
+ 83, 84, 86, 87, 89, 90, 92, 93,
+ 94, 96, 97, 98, 99, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111, 112
+};
+
+static const int hsv_blue_y[] = {
+ -11, -13, -15, -17, -19, -21, -23, -25,
+ -27, -29, -31, -33, -35, -37, -39, -41,
+ -43, -45, -46, -48, -50, -52, -54, -55,
+ -57, -59, -61, -62, -64, -66, -67, -69,
+ -71, -72, -74, -75, -77, -78, -80, -81,
+ -83, -84, -86, -87, -88, -90, -91, -92,
+ -93, -95, -96, -97, -98, -99, -100, -101,
+ -102, -103, -104, -105, -106, -106, -107, -108,
+ -109, -109, -110, -111, -111, -112, -112, -113,
+ -113, -114, -114, -114, -115, -115, -115, -115,
+ -116, -116, -116, -116, -116, -116, -116, -116,
+ -116, -115, -115, -115, -115, -114, -114, -114,
+ -113, -113, -112, -112, -111, -111, -110, -110,
+ -109, -108, -108, -107, -106, -105, -104, -103,
+ -102, -101, -100, -99, -98, -97, -96, -95,
+ -94, -93, -91, -90, -89, -88, -86, -85,
+ -84, -82, -81, -79, -78, -76, -75, -73,
+ -71, -70, -68, -67, -65, -63, -62, -60,
+ -58, -56, -55, -53, -51, -49, -47, -45,
+ -44, -42, -40, -38, -36, -34, -32, -30,
+ -28, -26, -24, -22, -20, -18, -16, -14,
+ -12, -10, -8, -6, -4, -2, 0, 1,
+ 3, 5, 7, 9, 11, 13, 15, 17,
+ 19, 21, 23, 25, 27, 29, 31, 33,
+ 35, 37, 39, 41, 43, 45, 46, 48,
+ 50, 52, 54, 55, 57, 59, 61, 62,
+ 64, 66, 67, 69, 71, 72, 74, 75,
+ 77, 78, 80, 81, 83, 84, 86, 87,
+ 88, 90, 91, 92, 93, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 106, 107, 108, 109, 109, 110, 111,
+ 111, 112, 112, 113, 113, 114, 114, 114,
+ 115, 115, 115, 115, 116, 116, 116, 116,
+ 116, 116, 116, 116, 116, 115, 115, 115,
+ 115, 114, 114, 114, 113, 113, 112, 112,
+ 111, 111, 110, 110, 109, 108, 108, 107,
+ 106, 105, 104, 103, 102, 101, 100, 99,
+ 98, 97, 96, 95, 94, 93, 91, 90,
+ 89, 88, 86, 85, 84, 82, 81, 79,
+ 78, 76, 75, 73, 71, 70, 68, 67,
+ 65, 63, 62, 60, 58, 56, 55, 53,
+ 51, 49, 47, 45, 44, 42, 40, 38,
+ 36, 34, 32, 30, 28, 26, 24, 22,
+ 20, 18, 16, 14, 12, 10, 8, 6,
+ 4, 2, 0, -1, -3, -5, -7, -9, -11
+};
+
+static u16 i2c_ident[] = {
+ V4L2_IDENT_OV9650,
+ V4L2_IDENT_OV9655,
+ V4L2_IDENT_SOI968,
+ V4L2_IDENT_OV7660,
+ V4L2_IDENT_OV7670,
+ V4L2_IDENT_MT9V011,
+ V4L2_IDENT_MT9V111,
+ V4L2_IDENT_MT9V112,
+ V4L2_IDENT_MT9M001C12ST,
+ V4L2_IDENT_MT9M111,
+ V4L2_IDENT_HV7131R,
+};
+
+static u16 bridge_init[][2] = {
+ {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
+ {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
+ {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
+ {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
+ {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
+ {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
+ {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
+ {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
+ {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
+ {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
+ {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
+ {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
+ {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
+ {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
+ {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
+ {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
+ {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
+ {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
+ {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80}
+};
+
+/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
+static u8 ov_gain[] = {
+ 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
+ 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
+ 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
+ 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
+ 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
+ 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
+ 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
+ 0x70 /* 8x */
+};
+
+/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
+static u16 micron1_gain[] = {
+ /* 1x 1.25x 1.5x 1.75x */
+ 0x0020, 0x0028, 0x0030, 0x0038,
+ /* 2x 2.25x 2.5x 2.75x */
+ 0x00a0, 0x00a4, 0x00a8, 0x00ac,
+ /* 3x 3.25x 3.5x 3.75x */
+ 0x00b0, 0x00b4, 0x00b8, 0x00bc,
+ /* 4x 4.25x 4.5x 4.75x */
+ 0x00c0, 0x00c4, 0x00c8, 0x00cc,
+ /* 5x 5.25x 5.5x 5.75x */
+ 0x00d0, 0x00d4, 0x00d8, 0x00dc,
+ /* 6x 6.25x 6.5x 6.75x */
+ 0x00e0, 0x00e4, 0x00e8, 0x00ec,
+ /* 7x 7.25x 7.5x 7.75x */
+ 0x00f0, 0x00f4, 0x00f8, 0x00fc,
+ /* 8x */
+ 0x01c0
+};
+
+/* mt9m001 sensor uses a different gain formula then other micron sensors */
+/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
+static u16 micron2_gain[] = {
+ /* 1x 1.25x 1.5x 1.75x */
+ 0x0008, 0x000a, 0x000c, 0x000e,
+ /* 2x 2.25x 2.5x 2.75x */
+ 0x0010, 0x0012, 0x0014, 0x0016,
+ /* 3x 3.25x 3.5x 3.75x */
+ 0x0018, 0x001a, 0x001c, 0x001e,
+ /* 4x 4.25x 4.5x 4.75x */
+ 0x0020, 0x0051, 0x0052, 0x0053,
+ /* 5x 5.25x 5.5x 5.75x */
+ 0x0054, 0x0055, 0x0056, 0x0057,
+ /* 6x 6.25x 6.5x 6.75x */
+ 0x0058, 0x0059, 0x005a, 0x005b,
+ /* 7x 7.25x 7.5x 7.75x */
+ 0x005c, 0x005d, 0x005e, 0x005f,
+ /* 8x */
+ 0x0060
+};
+
+/* Gain = .5 + bit[7:0] / 16 */
+static u8 hv7131r_gain[] = {
+ 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
+ 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
+ 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
+ 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
+ 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
+ 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
+ 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
+ 0x78 /* 8x */
+};
+
+static u8 soi968_init[][2] = {
+ {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+ {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
+ {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
+ {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
+ {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
+ {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
+ {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13},
+ {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
+ {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
+ {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
+ {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
+};
+
+static u8 ov7660_init[][2] = {
+ {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
+ {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
+ {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
+ {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
+ {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
+ {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
+};
+
+static u8 ov7670_init[][2] = {
+ {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+ {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
+ {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
+ {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
+ {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
+ {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
+ {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
+ {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
+ {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
+ {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
+ {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
+ {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
+ {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
+ {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
+ {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
+ {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
+ {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
+ {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
+ {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
+ {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
+ {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
+ {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
+ {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
+ {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
+ {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
+ {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
+ {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
+ {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
+ {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
+ {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
+ {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
+ {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
+ {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
+ {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
+ {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
+ {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
+ {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
+ {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
+ {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
+ {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
+ {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
+ {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
+ {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
+ {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
+ {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
+ {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
+ {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
+ {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
+ {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
+ {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
+ {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
+ {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
+ {0x93, 0x00},
+};
+
+static u8 ov9650_init[][2] = {
+ {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+ {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
+ {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
+ {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
+ {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
+ {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
+ {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
+ {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
+ {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
+ {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
+ {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
+ {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
+ {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
+ {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
+ {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
+ {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
+ {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
+ {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
+ {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
+ {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
+ {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
+ {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
+ {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
+ {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
+ {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
+ {0xaa, 0x92}, {0xab, 0x0a},
+};
+
+static u8 ov9655_init[][2] = {
+ {0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
+ {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
+ {0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
+ {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x32, 0xbf},
+ {0x34, 0x3d}, {0x35, 0x00}, {0x36, 0xf8}, {0x38, 0x12},
+ {0x39, 0x57}, {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c},
+ {0x3d, 0x19}, {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40},
+ {0x42, 0x80}, {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a},
+ {0x48, 0x3c}, {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc},
+ {0x4d, 0xdc}, {0x4e, 0xdc}, {0x69, 0x02}, {0x6c, 0x04},
+ {0x6f, 0x9e}, {0x70, 0x05}, {0x71, 0x78}, {0x77, 0x02},
+ {0x8a, 0x23}, {0x8c, 0x0d}, {0x90, 0x7e}, {0x91, 0x7c},
+ {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, {0xa6, 0x60},
+ {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, {0xab, 0x04},
+ {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80},
+ {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, {0xb6, 0xaf},
+ {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, {0xbe, 0x3b},
+ {0xbf, 0x3a}, {0xc0, 0xe2}, {0xc1, 0xc8}, {0xc2, 0x01},
+ {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
+ {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x12, 0x61},
+ {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
+ {0x03, 0x12}, {0x17, 0x14}, {0x18, 0x00}, {0x19, 0x01},
+ {0x1a, 0x3d}, {0x32, 0xbf}, {0x11, 0x80}, {0x2a, 0x10},
+ {0x2b, 0x0a}, {0x92, 0x00}, {0x93, 0x00}, {0x1e, 0x04},
+ {0x1e, 0x04}, {0x10, 0x7c}, {0x04, 0x03}, {0xa1, 0x00},
+ {0x2d, 0x00}, {0x2e, 0x00}, {0x00, 0x00}, {0x01, 0x80},
+ {0x02, 0x80}, {0x12, 0x61}, {0x36, 0xfa}, {0x8c, 0x8d},
+ {0xc0, 0xaa}, {0x69, 0x0a}, {0x03, 0x12}, {0x17, 0x14},
+ {0x18, 0x00}, {0x19, 0x01}, {0x1a, 0x3d}, {0x32, 0xbf},
+ {0x11, 0x80}, {0x2a, 0x10}, {0x2b, 0x0a}, {0x92, 0x00},
+ {0x93, 0x00}, {0x04, 0x01}, {0x10, 0x1f}, {0xa1, 0x00},
+ {0x00, 0x0a}, {0xa1, 0x00}, {0x10, 0x5d}, {0x04, 0x03},
+ {0x00, 0x01}, {0xa1, 0x00}, {0x10, 0x7c}, {0x04, 0x03},
+ {0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
+};
+
+static u16 mt9v112_init[][2] = {
+ {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
+ {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
+ {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
+ {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
+ {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
+ {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
+ {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
+ {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
+ {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
+ {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
+ {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
+ {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
+ {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
+ {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
+ {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
+ {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
+};
+
+static u16 mt9v111_init[][2] = {
+ {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
+ {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
+ {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
+ {0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03},
+ {0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c},
+ {0x2d, 0xf0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064},
+ {0x67, 0x4010}, {0x06, 0x301e}, {0x08, 0x0480},
+ {0x01, 0x0004}, {0x02, 0x0016}, {0x03, 0x01e6},
+ {0x04, 0x0286}, {0x05, 0x0004}, {0x06, 0x0000},
+ {0x07, 0x3002}, {0x08, 0x0008}, {0x0c, 0x0000},
+ {0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000},
+ {0x10, 0x0000}, {0x11, 0x0000}, {0x12, 0x00b0},
+ {0x13, 0x007c}, {0x14, 0x0000}, {0x15, 0x0000},
+ {0x16, 0x0000}, {0x17, 0x0000}, {0x18, 0x0000},
+ {0x19, 0x0000}, {0x1a, 0x0000}, {0x1b, 0x0000},
+ {0x1c, 0x0000}, {0x1d, 0x0000}, {0x30, 0x0000},
+ {0x30, 0x0005}, {0x31, 0x0000}, {0x02, 0x0016},
+ {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0004},
+ {0x06, 0x0000}, {0x07, 0x3002}, {0x06, 0x002d},
+ {0x05, 0x0004}, {0x09, 0x0064}, {0x2b, 0x00a0},
+ {0x2c, 0x00a0}, {0x2d, 0x00a0}, {0x2e, 0x00a0},
+ {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281},
+ {0x05, 0x0004}, {0x06, 0x002d}, {0x07, 0x3002},
+ {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
+};
+
+static u16 mt9v011_init[][2] = {
+ {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
+ {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
+ {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
+ {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
+ {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
+ {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
+ {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
+ {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
+ {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
+ {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
+ {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
+ {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
+ {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
+ {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
+ {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
+ {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
+ {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
+ {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
+ {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
+ {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
+ {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
+ {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
+ {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
+ {0x06, 0x0029}, {0x05, 0x0009},
+};
+
+static u16 mt9m001_init[][2] = {
+ {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
+ {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
+ {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
+ {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
+ {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
+ {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
+ {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
+ {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
+ {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
+ {0x2e, 0x0029}, {0x07, 0x0002},
+};
+
+static u16 mt9m111_init[][2] = {
+ {0xf0, 0x0000}, {0x0d, 0x0008}, {0x0d, 0x0009},
+ {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300},
+ {0x9b, 0x4300}, {0xa1, 0x0280}, {0xa4, 0x0200},
+ {0x06, 0x308e}, {0xf0, 0x0000},
+};
+
+static u8 hv7131r_init[][2] = {
+ {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
+ {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
+ {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
+ {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
+ {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
+ {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
+ {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
+ {0x23, 0x09}, {0x01, 0x08},
+};
+
+int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int result;
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ reg,
+ 0x00,
+ gspca_dev->usb_buf,
+ length,
+ 500);
+ if (unlikely(result < 0 || result != length)) {
+ err("Read register failed 0x%02X", reg);
+ return -EIO;
+ }
+ return 0;
+}
+
+int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int result;
+ memcpy(gspca_dev->usb_buf, buffer, length);
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ reg,
+ 0x00,
+ gspca_dev->usb_buf,
+ length,
+ 500);
+ if (unlikely(result < 0 || result != length)) {
+ err("Write register failed index 0x%02X", reg);
+ return -EIO;
+ }
+ return 0;
+}
+
+int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+{
+ u8 data[1] = {value};
+ return reg_w(gspca_dev, reg, data, 1);
+}
+
+int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+{
+ int i;
+ reg_w(gspca_dev, 0x10c0, buffer, 8);
+ for (i = 0; i < 5; i++) {
+ reg_r(gspca_dev, 0x10c0, 1);
+ if (gspca_dev->usb_buf[0] & 0x04) {
+ if (gspca_dev->usb_buf[0] & 0x08)
+ return -EIO;
+ return 0;
+ }
+ msleep(1);
+ }
+ return -EIO;
+}
+
+int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ u8 row[8];
+
+ /*
+ * from the point of view of the bridge, the length
+ * includes the address
+ */
+ row[0] = 0x81 | (2 << 4);
+ row[1] = sd->i2c_addr;
+ row[2] = reg;
+ row[3] = val;
+ row[4] = 0x00;
+ row[5] = 0x00;
+ row[6] = 0x00;
+ row[7] = 0x10;
+
+ return i2c_w(gspca_dev, row);
+}
+
+int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 row[8];
+
+ /*
+ * from the point of view of the bridge, the length
+ * includes the address
+ */
+ row[0] = 0x81 | (3 << 4);
+ row[1] = sd->i2c_addr;
+ row[2] = reg;
+ row[3] = (val >> 8) & 0xff;
+ row[4] = val & 0xff;
+ row[5] = 0x00;
+ row[6] = 0x00;
+ row[7] = 0x10;
+
+ return i2c_w(gspca_dev, row);
+}
+
+int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 row[8];
+
+ row[0] = 0x81 | (1 << 4);
+ row[1] = sd->i2c_addr;
+ row[2] = reg;
+ row[3] = 0;
+ row[4] = 0;
+ row[5] = 0;
+ row[6] = 0;
+ row[7] = 0x10;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ row[0] = 0x81 | (1 << 4) | 0x02;
+ row[2] = 0;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+ return -EIO;
+ *val = gspca_dev->usb_buf[4];
+ return 0;
+}
+
+int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 row[8];
+
+ row[0] = 0x81 | (1 << 4);
+ row[1] = sd->i2c_addr;
+ row[2] = reg;
+ row[3] = 0;
+ row[4] = 0;
+ row[5] = 0;
+ row[6] = 0;
+ row[7] = 0x10;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ row[0] = 0x81 | (2 << 4) | 0x02;
+ row[2] = 0;
+ if (i2c_w(gspca_dev, row) < 0)
+ return -EIO;
+ if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+ return -EIO;
+ *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
+ return 0;
+}
+
+static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
+ if (i2c_w1(gspca_dev, ov9650_init[i][0],
+ ov9650_init[i][1]) < 0) {
+ err("OV9650 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 1;
+ sd->vstart = 7;
+ return 0;
+}
+
+static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
+ if (i2c_w1(gspca_dev, ov9655_init[i][0],
+ ov9655_init[i][1]) < 0) {
+ err("OV9655 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ /* disable hflip and vflip */
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ sd->hstart = 0;
+ sd->vstart = 7;
+ return 0;
+}
+
+static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
+ if (i2c_w1(gspca_dev, soi968_init[i][0],
+ soi968_init[i][1]) < 0) {
+ err("SOI968 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ /* disable hflip and vflip */
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ sd->hstart = 60;
+ sd->vstart = 11;
+ return 0;
+}
+
+static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
+ if (i2c_w1(gspca_dev, ov7660_init[i][0],
+ ov7660_init[i][1]) < 0) {
+ err("OV7660 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ /* disable hflip and vflip */
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ sd->hstart = 1;
+ sd->vstart = 1;
+ return 0;
+}
+
+static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
+ if (i2c_w1(gspca_dev, ov7670_init[i][0],
+ ov7670_init[i][1]) < 0) {
+ err("OV7670 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ /* disable hflip and vflip */
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ sd->hstart = 0;
+ sd->vstart = 1;
+ return 0;
+}
+
+static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ u16 value;
+ int ret;
+
+ sd->i2c_addr = 0x5d;
+ ret = i2c_r2(gspca_dev, 0xff, &value);
+ if ((ret == 0) && (value == 0x8243)) {
+ for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
+ if (i2c_w2(gspca_dev, mt9v011_init[i][0],
+ mt9v011_init[i][1]) < 0) {
+ err("MT9V011 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 2;
+ sd->vstart = 2;
+ sd->sensor = SENSOR_MT9V011;
+ info("MT9V011 sensor detected");
+ return 0;
+ }
+
+ sd->i2c_addr = 0x5c;
+ i2c_w2(gspca_dev, 0x01, 0x0004);
+ ret = i2c_r2(gspca_dev, 0xff, &value);
+ if ((ret == 0) && (value == 0x823a)) {
+ for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
+ if (i2c_w2(gspca_dev, mt9v111_init[i][0],
+ mt9v111_init[i][1]) < 0) {
+ err("MT9V111 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 2;
+ sd->vstart = 2;
+ sd->sensor = SENSOR_MT9V111;
+ info("MT9V111 sensor detected");
+ return 0;
+ }
+
+ sd->i2c_addr = 0x5d;
+ ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
+ if (ret < 0) {
+ sd->i2c_addr = 0x48;
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ }
+ ret = i2c_r2(gspca_dev, 0x00, &value);
+ if ((ret == 0) && (value == 0x1229)) {
+ for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
+ if (i2c_w2(gspca_dev, mt9v112_init[i][0],
+ mt9v112_init[i][1]) < 0) {
+ err("MT9V112 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 6;
+ sd->vstart = 2;
+ sd->sensor = SENSOR_MT9V112;
+ info("MT9V112 sensor detected");
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
+ if (i2c_w2(gspca_dev, mt9m111_init[i][0],
+ mt9m111_init[i][1]) < 0) {
+ err("MT9M111 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 0;
+ sd->vstart = 2;
+ return 0;
+}
+
+static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
+ if (i2c_w2(gspca_dev, mt9m001_init[i][0],
+ mt9m001_init[i][1]) < 0) {
+ err("MT9M001 sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ /* disable hflip and vflip */
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ sd->hstart = 2;
+ sd->vstart = 2;
+ return 0;
+}
+
+static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+{
+ int i;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
+ if (i2c_w1(gspca_dev, hv7131r_init[i][0],
+ hv7131r_init[i][1]) < 0) {
+ err("HV7131R Sensor initialization failed");
+ return -ENODEV;
+ }
+ }
+ sd->hstart = 0;
+ sd->vstart = 1;
+ return 0;
+}
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+static int input_kthread(void *data)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)data;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ DECLARE_WAIT_QUEUE_HEAD(wait);
+ set_freezable();
+ for (;;) {
+ if (kthread_should_stop())
+ break;
+
+ if (reg_r(gspca_dev, 0x1005, 1) < 0)
+ continue;
+
+ input_report_key(sd->input_dev,
+ KEY_CAMERA,
+ gspca_dev->usb_buf[0] & sd->input_gpio);
+ input_sync(sd->input_dev);
+
+ wait_event_freezable_timeout(wait,
+ kthread_should_stop(),
+ msecs_to_jiffies(100));
+ }
+ return 0;
+}
+
+
+static int sn9c20x_input_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->input_gpio == 0)
+ return 0;
+
+ sd->input_dev = input_allocate_device();
+ if (!sd->input_dev)
+ return -ENOMEM;
+
+ sd->input_dev->name = "SN9C20X Webcam";
+
+ sd->input_dev->phys = kasprintf(GFP_KERNEL, "usb-%s-%s",
+ gspca_dev->dev->bus->bus_name,
+ gspca_dev->dev->devpath);
+
+ if (!sd->input_dev->phys)
+ return -ENOMEM;
+
+ usb_to_input_id(gspca_dev->dev, &sd->input_dev->id);
+ sd->input_dev->dev.parent = &gspca_dev->dev->dev;
+
+ set_bit(EV_KEY, sd->input_dev->evbit);
+ set_bit(KEY_CAMERA, sd->input_dev->keybit);
+
+ if (input_register_device(sd->input_dev))
+ return -EINVAL;
+
+ sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%d",
+ gspca_dev->vdev.minor);
+
+ if (IS_ERR(sd->input_task))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void sn9c20x_input_cleanup(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->input_task != NULL && !IS_ERR(sd->input_task))
+ kthread_stop(sd->input_task);
+
+ if (sd->input_dev != NULL) {
+ input_unregister_device(sd->input_dev);
+ kfree(sd->input_dev->phys);
+ input_free_device(sd->input_dev);
+ sd->input_dev = NULL;
+ }
+}
+#endif
+
+static int set_cmatrix(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 hue_coord, hue_index = 180 + sd->hue;
+ u8 cmatrix[21];
+ memset(cmatrix, 0, 21);
+
+ cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+ cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
+ cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
+ cmatrix[18] = sd->brightness - 0x80;
+
+ hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+ cmatrix[6] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[7] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+ cmatrix[8] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[9] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+ cmatrix[10] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[11] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+ cmatrix[12] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[13] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+ cmatrix[14] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[15] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+ cmatrix[16] = (unsigned char)(hue_coord & 0xff);
+ cmatrix[17] = (unsigned char)((hue_coord >> 8) & 0x0f);
+
+ return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+}
+
+static int set_gamma(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 gamma[17];
+ u8 gval = sd->gamma * 0xb8 / 0x100;
+
+
+ gamma[0] = 0x0a;
+ gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
+ gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
+ gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
+ gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
+ gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
+ gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
+ gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
+ gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
+ gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
+ gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
+ gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
+ gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
+ gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
+ gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
+ gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
+ gamma[16] = 0xf5;
+
+ return reg_w(gspca_dev, 0x1190, gamma, 17);
+}
+
+static int set_redblue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ reg_w1(gspca_dev, 0x118c, sd->red);
+ reg_w1(gspca_dev, 0x118f, sd->blue);
+ return 0;
+}
+
+static int set_hvflip(struct gspca_dev *gspca_dev)
+{
+ u8 value, tslb;
+ u16 value2;
+ struct sd *sd = (struct sd *) gspca_dev;
+ switch (sd->sensor) {
+ case SENSOR_OV9650:
+ i2c_r1(gspca_dev, 0x1e, &value);
+ value &= ~0x30;
+ tslb = 0x01;
+ if (sd->hflip)
+ value |= 0x20;
+ if (sd->vflip) {
+ value |= 0x10;
+ tslb = 0x49;
+ }
+ i2c_w1(gspca_dev, 0x1e, value);
+ i2c_w1(gspca_dev, 0x3a, tslb);
+ break;
+ case SENSOR_MT9V111:
+ case SENSOR_MT9V011:
+ i2c_r2(gspca_dev, 0x20, &value2);
+ value2 &= ~0xc0a0;
+ if (sd->hflip)
+ value2 |= 0x8080;
+ if (sd->vflip)
+ value2 |= 0x4020;
+ i2c_w2(gspca_dev, 0x20, value2);
+ break;
+ case SENSOR_MT9M111:
+ case SENSOR_MT9V112:
+ i2c_r2(gspca_dev, 0x20, &value2);
+ value2 &= ~0x0003;
+ if (sd->hflip)
+ value2 |= 0x0002;
+ if (sd->vflip)
+ value2 |= 0x0001;
+ i2c_w2(gspca_dev, 0x20, value2);
+ break;
+ case SENSOR_HV7131R:
+ i2c_r1(gspca_dev, 0x01, &value);
+ value &= ~0x03;
+ if (sd->vflip)
+ value |= 0x01;
+ if (sd->hflip)
+ value |= 0x02;
+ i2c_w1(gspca_dev, 0x01, value);
+ break;
+ }
+ return 0;
+}
+
+static int set_exposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV7670:
+ case SENSOR_SOI968:
+ case SENSOR_OV9655:
+ case SENSOR_OV9650:
+ exp[0] |= (3 << 4);
+ exp[2] = 0x2d;
+ exp[3] = sd->exposure & 0xff;
+ exp[4] = sd->exposure >> 8;
+ break;
+ case SENSOR_MT9M001:
+ case SENSOR_MT9M111:
+ case SENSOR_MT9V112:
+ case SENSOR_MT9V111:
+ case SENSOR_MT9V011:
+ exp[0] |= (3 << 4);
+ exp[2] = 0x09;
+ exp[3] = sd->exposure >> 8;
+ exp[4] = sd->exposure & 0xff;
+ break;
+ case SENSOR_HV7131R:
+ exp[0] |= (4 << 4);
+ exp[2] = 0x25;
+ exp[3] = ((sd->exposure * 0xffffff) / 0xffff) >> 16;
+ exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
+ exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
+ break;
+ }
+ i2c_w(gspca_dev, exp);
+ return 0;
+}
+
+static int set_gain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV7670:
+ case SENSOR_SOI968:
+ case SENSOR_OV9655:
+ case SENSOR_OV9650:
+ gain[0] |= (2 << 4);
+ gain[3] = ov_gain[sd->gain];
+ break;
+ case SENSOR_MT9V011:
+ case SENSOR_MT9V111:
+ gain[0] |= (3 << 4);
+ gain[2] = 0x35;
+ gain[3] = micron1_gain[sd->gain] >> 8;
+ gain[4] = micron1_gain[sd->gain] & 0xff;
+ break;
+ case SENSOR_MT9V112:
+ case SENSOR_MT9M111:
+ gain[0] |= (3 << 4);
+ gain[2] = 0x2f;
+ gain[3] = micron1_gain[sd->gain] >> 8;
+ gain[4] = micron1_gain[sd->gain] & 0xff;
+ break;
+ case SENSOR_MT9M001:
+ gain[0] |= (3 << 4);
+ gain[2] = 0x2f;
+ gain[3] = micron2_gain[sd->gain] >> 8;
+ gain[4] = micron2_gain[sd->gain] & 0xff;
+ break;
+ case SENSOR_HV7131R:
+ gain[0] |= (2 << 4);
+ gain[2] = 0x30;
+ gain[3] = hv7131r_gain[sd->gain];
+ break;
+ }
+ i2c_w(gspca_dev, gain);
+ return 0;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ return set_cmatrix(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->brightness;
+ return 0;
+}
+
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ return set_cmatrix(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->saturation = val;
+ if (gspca_dev->streaming)
+ return set_cmatrix(gspca_dev);
+ return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->saturation;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ return set_cmatrix(gspca_dev);
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->hue;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ return set_gamma(gspca_dev);
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->gamma;
+ return 0;
+}
+
+static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->red = val;
+ if (gspca_dev->streaming)
+ return set_redblue(gspca_dev);
+ return 0;
+}
+
+static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->red;
+ return 0;
+}
+
+static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->blue = val;
+ if (gspca_dev->streaming)
+ return set_redblue(gspca_dev);
+ return 0;
+}
+
+static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->blue;
+ return 0;
+}
+
+static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hflip = val;
+ if (gspca_dev->streaming)
+ return set_hvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->hflip;
+ return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->vflip = val;
+ if (gspca_dev->streaming)
+ return set_hvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->vflip;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ return set_exposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ return set_gain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ sd->auto_exposure = val;
+ return 0;
+}
+
+static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->auto_exposure;
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
+ struct v4l2_dbg_register *reg)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ if (reg->match.addr != 0)
+ return -EINVAL;
+ if (reg->reg < 0x1000 || reg->reg > 0x11ff)
+ return -EINVAL;
+ if (reg_r(gspca_dev, reg->reg, 1) < 0)
+ return -EINVAL;
+ reg->val = gspca_dev->usb_buf[0];
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ if (reg->match.addr != sd->i2c_addr)
+ return -EINVAL;
+ if (sd->sensor >= SENSOR_MT9V011 &&
+ sd->sensor <= SENSOR_MT9M111) {
+ if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
+ return -EINVAL;
+ } else {
+ if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
+ return -EINVAL;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
+ struct v4l2_dbg_register *reg)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ if (reg->match.addr != 0)
+ return -EINVAL;
+ if (reg->reg < 0x1000 || reg->reg > 0x11ff)
+ return -EINVAL;
+ if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ if (reg->match.addr != sd->i2c_addr)
+ return -EINVAL;
+ if (sd->sensor >= SENSOR_MT9V011 &&
+ sd->sensor <= SENSOR_MT9M111) {
+ if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
+ return -EINVAL;
+ } else {
+ if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
+ return -EINVAL;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+#endif
+
+static int sd_chip_ident(struct gspca_dev *gspca_dev,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (chip->match.type) {
+ case V4L2_CHIP_MATCH_HOST:
+ if (chip->match.addr != 0)
+ return -EINVAL;
+ chip->revision = 0;
+ chip->ident = V4L2_IDENT_SN9C20X;
+ return 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ if (chip->match.addr != sd->i2c_addr)
+ return -EINVAL;
+ chip->revision = 0;
+ chip->ident = i2c_ident[sd->sensor];
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+
+ sd->sensor = (id->driver_info >> 8) & 0xff;
+ sd->i2c_addr = id->driver_info & 0xff;
+
+ switch (sd->sensor) {
+ case SENSOR_OV9650:
+ cam->cam_mode = sxga_mode;
+ cam->nmodes = ARRAY_SIZE(sxga_mode);
+ break;
+ default:
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ }
+
+ sd->old_step = 0;
+ sd->older_step = 0;
+ sd->exposure_step = 16;
+
+ sd->brightness = BRIGHTNESS_DEFAULT;
+ sd->contrast = CONTRAST_DEFAULT;
+ sd->saturation = SATURATION_DEFAULT;
+ sd->hue = HUE_DEFAULT;
+ sd->gamma = GAMMA_DEFAULT;
+ sd->red = RED_DEFAULT;
+ sd->blue = BLUE_DEFAULT;
+
+ sd->hflip = HFLIP_DEFAULT;
+ sd->vflip = VFLIP_DEFAULT;
+ sd->exposure = EXPOSURE_DEFAULT;
+ sd->gain = GAIN_DEFAULT;
+ sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
+
+ sd->quality = 95;
+
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+ sd->input_gpio = (id->driver_info >> 16) & 0xff;
+ if (sn9c20x_input_init(gspca_dev) < 0)
+ return -ENODEV;
+#endif
+ return 0;
+}
+
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ u8 value;
+ u8 i2c_init[9] =
+ {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
+
+ for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
+ value = bridge_init[i][1];
+ if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+ err("Device initialization failed");
+ return -ENODEV;
+ }
+ }
+
+ if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+ err("Device initialization failed");
+ return -ENODEV;
+ }
+
+ switch (sd->sensor) {
+ case SENSOR_OV9650:
+ if (ov9650_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("OV9650 sensor detected");
+ break;
+ case SENSOR_OV9655:
+ if (ov9655_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("OV9655 sensor detected");
+ break;
+ case SENSOR_SOI968:
+ if (soi968_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("SOI968 sensor detected");
+ break;
+ case SENSOR_OV7660:
+ if (ov7660_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("OV7660 sensor detected");
+ break;
+ case SENSOR_OV7670:
+ if (ov7670_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("OV7670 sensor detected");
+ break;
+ case SENSOR_MT9VPRB:
+ if (mt9v_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ break;
+ case SENSOR_MT9M111:
+ if (mt9m111_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("MT9M111 sensor detected");
+ break;
+ case SENSOR_MT9M001:
+ if (mt9m001_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("MT9M001 sensor detected");
+ break;
+ case SENSOR_HV7131R:
+ if (hv7131r_init_sensor(gspca_dev) < 0)
+ return -ENODEV;
+ info("HV7131R sensor detected");
+ break;
+ default:
+ info("Unsupported Sensor");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 value;
+ switch (sd->sensor) {
+ case SENSOR_OV9650:
+ if (mode & MODE_SXGA) {
+ i2c_w1(gspca_dev, 0x17, 0x1b);
+ i2c_w1(gspca_dev, 0x18, 0xbc);
+ i2c_w1(gspca_dev, 0x19, 0x01);
+ i2c_w1(gspca_dev, 0x1a, 0x82);
+ i2c_r1(gspca_dev, 0x12, &value);
+ i2c_w1(gspca_dev, 0x12, value & 0x07);
+ } else {
+ i2c_w1(gspca_dev, 0x17, 0x24);
+ i2c_w1(gspca_dev, 0x18, 0xc5);
+ i2c_w1(gspca_dev, 0x19, 0x00);
+ i2c_w1(gspca_dev, 0x1a, 0x3c);
+ i2c_r1(gspca_dev, 0x12, &value);
+ i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
+ }
+ break;
+ }
+}
+
+#define HW_WIN(mode, hstart, vstart) \
+((const u8 []){hstart & 0xff, hstart >> 8, \
+vstart & 0xff, vstart >> 8, \
+(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
+(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
+
+#define CLR_WIN(width, height) \
+((const u8 [])\
+{0, width >> 2, 0, height >> 1,\
+((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ int width = gspca_dev->width;
+ int height = gspca_dev->height;
+ u8 fmt, scale = 0;
+
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (sd->jpeg_hdr == NULL)
+ return -ENOMEM;
+
+ jpeg_define(sd->jpeg_hdr, height, width,
+ 0x21);
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+ if (mode & MODE_RAW)
+ fmt = 0x2d;
+ else if (mode & MODE_JPEG)
+ fmt = 0x2c;
+ else
+ fmt = 0x2f;
+
+ switch (mode & 0x0f) {
+ case 3:
+ scale = 0xc0;
+ info("Set 1280x1024");
+ break;
+ case 2:
+ scale = 0x80;
+ info("Set 640x480");
+ break;
+ case 1:
+ scale = 0x90;
+ info("Set 320x240");
+ break;
+ case 0:
+ scale = 0xa0;
+ info("Set 160x120");
+ break;
+ }
+
+ configure_sensor_output(gspca_dev, mode);
+ reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
+ reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+ reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
+ reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
+ reg_w1(gspca_dev, 0x1189, scale);
+ reg_w1(gspca_dev, 0x10e0, fmt);
+
+ set_cmatrix(gspca_dev);
+ set_gamma(gspca_dev);
+ set_redblue(gspca_dev);
+ set_gain(gspca_dev);
+ set_exposure(gspca_dev);
+ set_hvflip(gspca_dev);
+
+ reg_r(gspca_dev, 0x1061, 1);
+ reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
+ return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_r(gspca_dev, 0x1061, 1);
+ reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ kfree(sd->jpeg_hdr);
+}
+
+static void do_autoexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum, new_exp;
+
+ if (!sd->auto_exposure)
+ return;
+
+ avg_lum = atomic_read(&sd->avg_lum);
+
+ /*
+ * some hardcoded values are present
+ * like those for maximal/minimal exposure
+ * and exposure steps
+ */
+ if (avg_lum < MIN_AVG_LUM) {
+ if (sd->exposure > 0x1770)
+ return;
+
+ new_exp = sd->exposure + sd->exposure_step;
+ if (new_exp > 0x1770)
+ new_exp = 0x1770;
+ if (new_exp < 0x10)
+ new_exp = 0x10;
+ sd->exposure = new_exp;
+ set_exposure(gspca_dev);
+
+ sd->older_step = sd->old_step;
+ sd->old_step = 1;
+
+ if (sd->old_step ^ sd->older_step)
+ sd->exposure_step /= 2;
+ else
+ sd->exposure_step += 2;
+ }
+ if (avg_lum > MAX_AVG_LUM) {
+ if (sd->exposure < 0x10)
+ return;
+ new_exp = sd->exposure - sd->exposure_step;
+ if (new_exp > 0x1700)
+ new_exp = 0x1770;
+ if (new_exp < 0x10)
+ new_exp = 0x10;
+ sd->exposure = new_exp;
+ set_exposure(gspca_dev);
+ sd->older_step = sd->old_step;
+ sd->old_step = 0;
+
+ if (sd->old_step ^ sd->older_step)
+ sd->exposure_step /= 2;
+ else
+ sd->exposure_step += 2;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum;
+ static unsigned char frame_header[] =
+ {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+ if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+ avg_lum = ((data[35] >> 2) & 3) |
+ (data[20] << 2) |
+ (data[19] << 10);
+ avg_lum += ((data[35] >> 4) & 3) |
+ (data[22] << 2) |
+ (data[21] << 10);
+ avg_lum += ((data[35] >> 6) & 3) |
+ (data[24] << 2) |
+ (data[23] << 10);
+ avg_lum += (data[36] & 3) |
+ (data[26] << 2) |
+ (data[25] << 10);
+ avg_lum += ((data[36] >> 2) & 3) |
+ (data[28] << 2) |
+ (data[27] << 10);
+ avg_lum += ((data[36] >> 4) & 3) |
+ (data[30] << 2) |
+ (data[29] << 10);
+ avg_lum += ((data[36] >> 6) & 3) |
+ (data[32] << 2) |
+ (data[31] << 10);
+ avg_lum += ((data[44] >> 4) & 3) |
+ (data[34] << 2) |
+ (data[33] << 10);
+ avg_lum >>= 9;
+ atomic_set(&sd->avg_lum, avg_lum);
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, len);
+ return;
+ }
+ if (gspca_dev->last_packet_type == LAST_PACKET) {
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
+ & MODE_JPEG) {
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, len);
+ } else {
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ }
+ } else {
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ }
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autoexposure,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .set_register = sd_dbg_s_register,
+ .get_register = sd_dbg_g_register,
+#endif
+ .get_chip_ident = sd_chip_ident,
+};
+
+#define SN9C20X(sensor, i2c_addr, button_mask) \
+ .driver_info = (button_mask << 16) \
+ | (SENSOR_ ## sensor << 8) \
+ | (i2c_addr)
+
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
+ {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
+ {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, 0x10)},
+ {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
+ {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
+ {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
+ {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
+ {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
+ {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
+ {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
+ {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
+ {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
+ {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
+ {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
+ {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
+ {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
+ {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static void sd_disconnect(struct usb_interface *intf)
+{
+#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ sn9c20x_input_cleanup(gspca_dev);
+#endif
+
+ gspca_disconnect(intf);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = sd_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+ .reset_resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ info("registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 0d02f41fa7d0..f0b762f770fb 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -727,13 +727,13 @@ static const u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
/* Outformat = rawRGB */
{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
- {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+ {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
/* GAIN BLUE RED VREF */
{0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
/* COM 1 BAVE GEAVE AECHH */
{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
- {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
+ {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
/* AECH CLKRC COM7 COM8 */
{0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
{0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
@@ -1634,17 +1634,22 @@ static void setfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
+ return;
if (sd->sensor == SENSOR_OV7660) {
+ u8 com8;
+
+ com8 = 0xf8; /* no auto gain/wb/expo */
switch (sd->freq) {
case 0: /* Banding filter disabled */
- i2c_w1(gspca_dev, 0x13, 0xdf);
+ i2c_w1(gspca_dev, 0x13, com8 & 0xdf);
break;
case 1: /* 50 hz */
- i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x13, com8);
i2c_w1(gspca_dev, 0x3b, 0x0a);
break;
case 2: /* 60 hz */
- i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x13, com8);
i2c_w1(gspca_dev, 0x3b, 0x02);
break;
}
@@ -1735,6 +1740,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -2332,7 +2339,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
{USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
-/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+/* {USB_DEVICE(0x0c45, 0x6102), BSI(SN9C120, PO2030N, ??)}, */
+/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6802, 0x21)}, */
{USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
@@ -2348,6 +2356,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
#endif
+/* {USB_DEVICE(0x0c45, 0x6132), BSI(SN9C120, OV7670, 0x21)}, */
{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
@@ -2355,7 +2364,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
{USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
- {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
+/* {USB_DEVICE(0x0c45, 0x6142), BSI(SN9C120, PO2030N, ??)}, *sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, /*sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x6148), BSI(SN9C120, OM6802, 0x21)}, /*sn9c120b*/
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 8806b2ff82be..fab7ef85a6c1 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -670,6 +670,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 2ed2669bac3e..9696c4caf5c9 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1304,19 +1304,70 @@ static int reg_read(struct gspca_dev *gspca_dev,
return gspca_dev->usb_buf[0];
}
+/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */
+static int ssi_w(struct gspca_dev *gspca_dev,
+ u16 reg, u16 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, retry;
+
+ ret = reg_write(dev, 0x8802, reg >> 8);
+ if (ret < 0)
+ goto out;
+ ret = reg_write(dev, 0x8801, reg & 0x00ff);
+ if (ret < 0)
+ goto out;
+ if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */
+ ret = reg_write(dev, 0x8805, val & 0x00ff);
+ if (ret < 0)
+ goto out;
+ val >>= 8;
+ }
+ ret = reg_write(dev, 0x8800, val);
+ if (ret < 0)
+ goto out;
+
+ /* poll until not busy */
+ retry = 10;
+ for (;;) {
+ ret = reg_read(gspca_dev, 0x8803);
+ if (ret < 0)
+ break;
+ if (gspca_dev->usb_buf[0] == 0)
+ break;
+ if (--retry <= 0) {
+ PDEBUG(D_ERR, "ssi_w busy %02x",
+ gspca_dev->usb_buf[0]);
+ ret = -1;
+ break;
+ }
+ msleep(8);
+ }
+
+out:
+ return ret;
+}
+
static int write_vector(struct gspca_dev *gspca_dev,
const u16 (*data)[2])
{
struct usb_device *dev = gspca_dev->dev;
- int ret;
+ int ret = 0;
while ((*data)[1] != 0) {
- ret = reg_write(dev, (*data)[1], (*data)[0]);
+ if ((*data)[1] & 0x8000) {
+ if ((*data)[1] == 0xdd00) /* delay */
+ msleep((*data)[0]);
+ else
+ ret = reg_write(dev, (*data)[1], (*data)[0]);
+ } else {
+ ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]);
+ }
if (ret < 0)
- return ret;
+ break;
data++;
}
- return 0;
+ return ret;
}
/* this function is called at probe time */
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index f25be20cf1a6..47628964801e 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -333,6 +333,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index 3039ec208f3a..e5024c8496ef 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -64,7 +64,7 @@ static struct v4l2_pix_format hdcs1x00_mode[] = {
{
HDCS_1X00_DEF_WIDTH,
HDCS_1X00_DEF_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
+ V4L2_PIX_FMT_SGRBG8,
V4L2_FIELD_NONE,
.sizeimage =
HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
@@ -80,7 +80,7 @@ static struct v4l2_pix_format hdcs1020_mode[] = {
{
HDCS_1020_DEF_WIDTH,
HDCS_1020_DEF_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
+ V4L2_PIX_FMT_SGRBG8,
V4L2_FIELD_NONE,
.sizeimage =
HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
@@ -131,9 +131,11 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
(reg + len > 0xff)))
return -EINVAL;
- for (i = 0; i < len; i++, reg++) {
- regs[2*i] = reg;
- regs[2*i+1] = vals[i];
+ for (i = 0; i < len; i++) {
+ regs[2 * i] = reg;
+ regs[2 * i + 1] = vals[i];
+ /* All addresses are shifted left one bit as bit 0 toggles r/w */
+ reg += 2;
}
return stv06xx_write_sensor_bytes(sd, regs, len);
@@ -174,7 +176,9 @@ static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
}
ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
- if (ret < 0)
+
+ /* Update the state if the write succeeded */
+ if (!ret)
hdcs->state = state;
return ret;
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 9623f294bdac..eabad47a3ca6 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -52,6 +52,7 @@ struct sd {
#define LogitechClickSmart420 2
#define LogitechClickSmart820 3
#define MegapixV4 4
+#define MegaImageVI 5
u8 *jpeg_hdr;
};
@@ -844,7 +845,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
case BRIDGE_SPCA533:
cam->cam_mode = custom_mode;
- cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+ if (sd->subtype == MegaImageVI) /* 320x240 only */
+ cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
+ else
+ cam->nmodes = ARRAY_SIZE(custom_mode);
break;
case BRIDGE_SPCA504C:
cam->cam_mode = vga_mode2;
@@ -973,6 +977,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -986,7 +992,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */
if (sd->subtype == MegapixV4 ||
- sd->subtype == LogitechClickSmart820) {
+ sd->subtype == LogitechClickSmart820 ||
+ sd->subtype == MegaImageVI) {
reg_w(gspca_dev, 0xf0, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
reg_r(gspca_dev, 0xf0, 4, 0);
@@ -1382,6 +1389,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
+ {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
{USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
{USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 404214b8cd2b..1d321c30d22f 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -264,6 +264,10 @@ static const struct v4l2_pix_format vga_mode_t16[] = {
/* sensor specific data */
struct additional_sensor_data {
+ const u8 n3[6];
+ const u8 *n4, n4sz;
+ const u8 reg80, reg8e;
+ const u8 nset8[6];
const u8 data1[10];
const u8 data2[9];
const u8 data3[9];
@@ -272,14 +276,55 @@ struct additional_sensor_data {
const u8 stream[4];
};
+static const u8 n4_om6802[] = {
+ 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+ 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+ 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+ 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+ 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+ 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+ 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+ 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+ 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
+};
+static const u8 n4_other[] = {
+ 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
+ 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
+ 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
+ 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
+ 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
+ 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
+ 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
+ 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
+};
+static const u8 n4_tas5130a[] = {
+ 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
+ 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
+ 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
+ 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
+ 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
+ 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
+ 0xc6, 0xda
+};
+
static const struct additional_sensor_data sensor_data[] = {
- { /* OM6802 */
+ { /* 0: OM6802 */
+ .n3 =
+ {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
+ .n4 = n4_om6802,
+ .n4sz = sizeof n4_om6802,
+ .reg80 = 0x3c,
+ .reg8e = 0x33,
+ .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
.data1 =
{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
0xb3, 0xfc},
.data2 =
{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
0xff},
+ .data3 =
+ {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
+ 0xff},
.data4 = /*Freq (50/60Hz). Splitted for test purpose */
{0x66, 0xca, 0xa8, 0xf0},
.data5 = /* this could be removed later */
@@ -287,13 +332,23 @@ static const struct additional_sensor_data sensor_data[] = {
.stream =
{0x0b, 0x04, 0x0a, 0x78},
},
- { /* OTHER */
+ { /* 1: OTHER */
+ .n3 =
+ {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
+ .n4 = n4_other,
+ .n4sz = sizeof n4_other,
+ .reg80 = 0xac,
+ .reg8e = 0xb8,
+ .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
.data1 =
{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
0xe8, 0xfc},
.data2 =
{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
0xd9},
+ .data3 =
+ {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
+ 0xd9},
.data4 =
{0x66, 0x00, 0xa8, 0xa8},
.data5 =
@@ -301,13 +356,23 @@ static const struct additional_sensor_data sensor_data[] = {
.stream =
{0x0b, 0x04, 0x0a, 0x00},
},
- { /* TAS5130A */
+ { /* 2: TAS5130A */
+ .n3 =
+ {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
+ .n4 = n4_tas5130a,
+ .n4sz = sizeof n4_tas5130a,
+ .reg80 = 0x3c,
+ .reg8e = 0xb4,
+ .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
.data1 =
{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
0xc8, 0xfc},
.data2 =
{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
0xe0},
+ .data3 =
+ {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
+ 0xe0},
.data4 = /* Freq (50/60Hz). Splitted for test purpose */
{0x66, 0x00, 0xa8, 0xe8},
.data5 =
@@ -364,7 +429,7 @@ static const u8 gamma_table[GAMMA_MAX][17] = {
{0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
0xff},
- {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8D, 0x9B, /* 11 */
+ {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b, /* 11 */
0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
0xff},
{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
@@ -385,8 +450,6 @@ static const u8 tas5130a_sensor_init[][8] = {
{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
- {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
- {},
};
static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
@@ -633,10 +696,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
* but wont hurt anyway, and can help someone with similar webcam
* to see the initial parameters.*/
struct sd *sd = (struct sd *) gspca_dev;
+ const struct additional_sensor_data *sensor;
int i;
u16 sensor_id;
u8 test_byte = 0;
- u16 reg80, reg8e;
static const u8 read_indexs[] =
{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
@@ -645,37 +708,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
static const u8 n2[] =
{0x08, 0x00};
- static const u8 n3[6] =
- {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
- static const u8 n3_other[6] =
- {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00};
- static const u8 n4[] =
- {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
- 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
- 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
- 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
- 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
- 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
- 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
- 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
- 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
- static const u8 n4_other[] =
- {0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
- 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
- 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
- 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
- 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
- 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
- 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
- 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00};
- static const u8 nset8[6] =
- { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
- static const u8 nset8_other[6] =
- { 0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00 };
- static const u8 nset9[4] =
- { 0x0b, 0x04, 0x0a, 0x78 };
- static const u8 nset9_other[4] =
- { 0x0b, 0x04, 0x0a, 0x00 };
sensor_id = (reg_r(gspca_dev, 0x06) << 8)
| reg_r(gspca_dev, 0x07);
@@ -709,8 +741,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
if (i < 0) {
err("Bad sensor reset %02x", test_byte);
-/* return -EIO; */
-/*fixme: test - continue */
+ return -EIO;
}
reg_w_buf(gspca_dev, n2, sizeof n2);
}
@@ -723,31 +754,17 @@ static int sd_init(struct gspca_dev *gspca_dev)
i++;
}
- if (sd->sensor != SENSOR_OTHER) {
- reg_w_buf(gspca_dev, n3, sizeof n3);
- reg_w_buf(gspca_dev, n4, sizeof n4);
- reg_r(gspca_dev, 0x0080);
- reg_w(gspca_dev, 0x2c80);
- reg80 = 0x3880;
- reg8e = 0x338e;
- } else {
- reg_w_buf(gspca_dev, n3_other, sizeof n3_other);
- reg_w_buf(gspca_dev, n4_other, sizeof n4_other);
- sd->gamma = 5;
- reg80 = 0xac80;
- reg8e = 0xb88e;
- }
+ sensor = &sensor_data[sd->sensor];
+ reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
+ reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
- reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
- sizeof sensor_data[sd->sensor].data1);
- reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
- reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
+ reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+ reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+ reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
- reg_w(gspca_dev, reg80);
- reg_w(gspca_dev, reg80);
- reg_w(gspca_dev, reg8e);
+ reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+ reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+ reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
setbrightness(gspca_dev);
setcontrast(gspca_dev);
@@ -760,25 +777,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x2088);
reg_w(gspca_dev, 0x2089);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
- sizeof sensor_data[sd->sensor].data4);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
- sizeof sensor_data[sd->sensor].data5);
- if (sd->sensor != SENSOR_OTHER) {
- reg_w_buf(gspca_dev, nset8, sizeof nset8);
- reg_w_buf(gspca_dev, nset9, sizeof nset9);
- reg_w(gspca_dev, 0x2880);
- } else {
- reg_w_buf(gspca_dev, nset8_other, sizeof nset8_other);
- reg_w_buf(gspca_dev, nset9_other, sizeof nset9_other);
- }
+ reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+ reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
+ reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
- reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
- sizeof sensor_data[sd->sensor].data1);
- reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
- reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
- sizeof sensor_data[sd->sensor].data2);
+ reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+ reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+ reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
return 0;
}
@@ -828,7 +834,6 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
* i added some module parameters for test with some users */
static void poll_sensor(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
static const u8 poll1[] =
{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
@@ -844,24 +849,23 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
0xc2, 0x80, 0xc3, 0x10};
- if (sd->sensor == SENSOR_OM6802) {
- PDEBUG(D_STREAM, "[Sensor requires polling]");
- reg_w_buf(gspca_dev, poll1, sizeof poll1);
- reg_w_buf(gspca_dev, poll2, sizeof poll2);
- reg_w_buf(gspca_dev, poll3, sizeof poll3);
- reg_w_buf(gspca_dev, poll4, sizeof poll4);
- }
+ PDEBUG(D_STREAM, "[Sensor requires polling]");
+ reg_w_buf(gspca_dev, poll1, sizeof poll1);
+ reg_w_buf(gspca_dev, poll2, sizeof poll2);
+ reg_w_buf(gspca_dev, poll3, sizeof poll3);
+ reg_w_buf(gspca_dev, poll4, sizeof poll4);
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ const struct additional_sensor_data *sensor;
int i, mode;
u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
static const u8 t3[] =
{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (mode) {
case 0: /* 640x480 (0x00) */
break;
@@ -889,34 +893,33 @@ static int sd_start(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_TAS5130A: */
i = 0;
- while (tas5130a_sensor_init[i][0] != 0) {
+ for (;;) {
reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
sizeof tas5130a_sensor_init[0]);
+ if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
+ break;
i++;
}
reg_w(gspca_dev, 0x3c80);
/* just in case and to keep sync with logs (for mine) */
- reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
+ reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
sizeof tas5130a_sensor_init[0]);
reg_w(gspca_dev, 0x3c80);
break;
}
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
- sizeof sensor_data[sd->sensor].data4);
+ sensor = &sensor_data[sd->sensor];
+ reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
reg_r(gspca_dev, 0x0012);
reg_w_buf(gspca_dev, t2, sizeof t2);
reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
reg_w(gspca_dev, 0x0013);
msleep(15);
- reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
- sizeof sensor_data[sd->sensor].stream);
- poll_sensor(gspca_dev);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+ reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+
+ if (sd->sensor == SENSOR_OM6802)
+ poll_sensor(gspca_dev);
- /* restart on each start, just in case, sometimes regs goes wrong
- * when using controls from app */
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
- setcolors(gspca_dev);
return 0;
}
@@ -926,10 +929,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
sizeof sensor_data[sd->sensor].stream);
- msleep(20);
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
sizeof sensor_data[sd->sensor].stream);
- if (sd->sensor != SENSOR_OTHER) {
+ if (sd->sensor == SENSOR_OM6802) {
msleep(20);
reg_w(gspca_dev, 0x0309);
}
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 9f243d7e3110..4b44dde9f8b8 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -426,7 +426,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, packet_type0,
frame, data + 2, gspca_dev->width);
gspca_frame_add(gspca_dev, packet_type1,
- frame, data + gspca_dev->width + 6, gspca_dev->width);
+ frame, data + gspca_dev->width + 5, gspca_dev->width);
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 26dd155efcc3..c4ef7811bf60 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -32,14 +32,14 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 hflip;
- __u8 vflip;
- __u8 lightfreq;
- __u8 sharpness;
+ u8 hflip;
+ u8 vflip;
+ u8 lightfreq;
+ u8 sharpness;
u8 image_offset;
- char bridge;
+ u8 bridge;
#define BRIDGE_VC0321 0
#define BRIDGE_VC0323 1
u8 sensor;
@@ -52,6 +52,10 @@ struct sd {
#define SENSOR_OV7670 6
#define SENSOR_PO1200 7
#define SENSOR_PO3130NC 8
+ u8 flags;
+#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
+#define FL_HFLIP 0x02 /* mirrored by default */
+#define FL_VFLIP 0x04 /* vertical flipped by default */
};
/* V4L2 controls supported by the driver */
@@ -65,7 +69,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
-/* next 2 controls work with ov7660 and ov7670 only */
+/* next 2 controls work with some sensors only */
#define HFLIP_IDX 0
{
{
@@ -152,9 +156,9 @@ static const struct v4l2_pix_format vc0323_mode[] = {
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
- {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
+ {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
.bytesperline = 1280,
- .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+ .sizeimage = 1280 * 960 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
};
@@ -188,11 +192,11 @@ static const struct v4l2_pix_format svga_mode[] = {
#define OV7660_MVFP_MIRROR 0x20
#define OV7660_MVFP_VFLIP 0x10
-static const __u8 mi0360_matrix[9] = {
+static const u8 mi0360_matrix[9] = {
0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
};
-static const __u8 mi0360_initVGA_JPG[][4] = {
+static const u8 mi0360_initVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -301,7 +305,7 @@ static const __u8 mi0360_initVGA_JPG[][4] = {
{0xb3, 0x5c, 0x01, 0xcc},
{}
};
-static const __u8 mi0360_initQVGA_JPG[][4] = {
+static const u8 mi0360_initQVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -421,211 +425,95 @@ static const __u8 mi0360_initQVGA_JPG[][4] = {
{}
};
-static const __u8 mi1310_socinitVGA_JPG[][4] = {
+static const u8 mi1310_socinitVGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
{0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x0d, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
{0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x0f, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc},
{0xb6, 0x00, 0x00, 0xcc},
{0xb6, 0x03, 0x02, 0xcc},
{0xb6, 0x02, 0x80, 0xcc},
{0xb6, 0x05, 0x01, 0xcc},
{0xb6, 0x04, 0xe0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x25, 0xcc},
{0xb6, 0x18, 0x02, 0xcc},
{0xb6, 0x17, 0x58, 0xcc},
{0xb6, 0x16, 0x00, 0xcc},
{0xb6, 0x22, 0x12, 0xcc},
{0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
- {0xbf, 0xc0, 0x39, 0xcc},
- {0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb3, 0x01, 0x41, 0xcc},
- {0x03, 0x03, 0xc0, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
- {},
-};
-static const __u8 mi1310_socinitQVGA_JPG[][4] = {
- {0xb0, 0x03, 0x19, 0xcc},
- {0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb3, 0x05, 0x01, 0xcc},
- {0xb3, 0x06, 0x03, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
- {0xb3, 0x08, 0x01, 0xcc},
- {0xb3, 0x09, 0x0c, 0xcc},
- {0xb3, 0x34, 0x02, 0xcc},
- {0xb3, 0x35, 0xdd, 0xcc},
- {0xb3, 0x03, 0x0a, 0xcc},
- {0xb3, 0x04, 0x0d, 0xcc},
- {0xb3, 0x20, 0x00, 0xcc},
- {0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x01, 0xcc},
- {0xb3, 0x23, 0xe0, 0xcc},
- {0xb3, 0x14, 0x00, 0xcc},
- {0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x02, 0xcc},
- {0xb3, 0x17, 0x7f, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x13, 0xcc},
- {0xbc, 0x00, 0xd1, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
- {0xb8, 0x35, 0x00, 0xcc},
- {0xb8, 0x36, 0x00, 0xcc},
- {0xb8, 0x37, 0x00, 0xcc},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
- {0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x0f, 0xbb},
- {0xb6, 0x00, 0x00, 0xcc},
- {0xb6, 0x03, 0x01, 0xcc},
- {0xb6, 0x02, 0x40, 0xcc},
- {0xb6, 0x05, 0x00, 0xcc},
- {0xb6, 0x04, 0xf0, 0xcc},
- {0xb6, 0x12, 0x78, 0xcc},
- {0xb6, 0x18, 0x00, 0xcc},
- {0xb6, 0x17, 0x96, 0xcc},
- {0xb6, 0x16, 0x00, 0xcc},
- {0xb6, 0x22, 0x12, 0xcc},
- {0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
{0xbf, 0xc0, 0x39, 0xcc},
{0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x0a, 0xcc},
- {0xb9, 0x14, 0x0a, 0xcc},
- {0xb9, 0x15, 0x0a, 0xcc},
- {0xb9, 0x16, 0x0a, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x0f, 0xcc},
- {0xb9, 0x1a, 0x0f, 0xcc},
- {0xb9, 0x1b, 0x0f, 0xcc},
- {0xb9, 0x1c, 0x0f, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
{0xbc, 0x02, 0x18, 0xcc},
{0xbc, 0x03, 0x50, 0xcc},
{0xbc, 0x04, 0x18, 0xcc},
@@ -636,133 +524,335 @@ static const __u8 mi1310_socinitQVGA_JPG[][4] = {
{0xbc, 0x0a, 0x10, 0xcc},
{0xbc, 0x0b, 0x00, 0xcc},
{0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
{0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const u8 mi1310_socinitQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
{0x03, 0x03, 0xc0, 0xbb},
- {0x06, 0x00, 0x10, 0xbb},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
{},
};
static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
{0xb0, 0x03, 0x19, 0xcc},
{0xb0, 0x04, 0x02, 0xcc},
- {0xb3, 0x00, 0x24, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
{0xb3, 0x05, 0x00, 0xcc},
- {0xb3, 0x06, 0x01, 0xcc},
- {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
{0xb3, 0x08, 0x01, 0xcc},
{0xb3, 0x09, 0x0c, 0xcc},
{0xb3, 0x34, 0x02, 0xcc},
{0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
{0xb3, 0x03, 0x0a, 0xcc},
{0xb3, 0x04, 0x0d, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc},
- {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
{0xb3, 0x16, 0x04, 0xcc},
{0xb3, 0x17, 0xff, 0xcc},
- {0xb8, 0x01, 0x7d, 0xcc},
- {0xb8, 0x81, 0x09, 0xcc},
- {0xb8, 0x27, 0x20, 0xcc},
- {0xb8, 0x26, 0x80, 0xcc},
- {0xb8, 0x06, 0x00, 0xcc},
- {0xb8, 0x07, 0x05, 0xcc},
- {0xb8, 0x08, 0x00, 0xcc},
- {0xb8, 0x09, 0x04, 0xcc},
- {0xb3, 0x00, 0x25, 0xcc},
- {0xb8, 0x00, 0x11, 0xcc},
- {0xbc, 0x00, 0x71, 0xcc},
- {0xb8, 0x81, 0x01, 0xcc},
- {0xb8, 0x2c, 0x5a, 0xcc},
- {0xb8, 0x2d, 0xff, 0xcc},
- {0xb8, 0x2e, 0xee, 0xcc},
- {0xb8, 0x2f, 0xfb, 0xcc},
- {0xb8, 0x30, 0x52, 0xcc},
- {0xb8, 0x31, 0xf8, 0xcc},
- {0xb8, 0x32, 0xf1, 0xcc},
- {0xb8, 0x33, 0xff, 0xcc},
- {0xb8, 0x34, 0x54, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x70, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x0d, 0x00, 0x09, 0xbb},
- {0x0d, 0x00, 0x08, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */
{0xf0, 0x00, 0x01, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x06, 0x00, 0x14, 0xbb},
- {0x3a, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
- {0x9b, 0x10, 0x00, 0xbb},
- {0x00, 0x00, 0x10, 0xdd},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x60, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x37, 0x01, 0x40, 0xbb},
{0xf0, 0x00, 0x00, 0xbb},
- {0x00, 0x01, 0x00, 0xdd},
- {0x2b, 0x00, 0x28, 0xbb},
- {0x2c, 0x00, 0x30, 0xbb},
- {0x2d, 0x00, 0x30, 0xbb},
- {0x2e, 0x00, 0x28, 0xbb},
- {0x41, 0x00, 0xd7, 0xbb},
- {0x09, 0x02, 0x3a, 0xbb},
- {0x0c, 0x00, 0x00, 0xbb},
- {0x20, 0x00, 0x00, 0xbb},
- {0x05, 0x00, 0x8c, 0xbb},
- {0x06, 0x00, 0x32, 0xbb},
- {0x07, 0x00, 0xc6, 0xbb},
- {0x08, 0x00, 0x19, 0xbb},
- {0x24, 0x80, 0x6f, 0xbb},
- {0xc8, 0x00, 0x0f, 0xbb},
- {0x20, 0x00, 0x03, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
{0xb6, 0x00, 0x00, 0xcc},
{0xb6, 0x03, 0x05, 0xcc},
{0xb6, 0x02, 0x00, 0xcc},
- {0xb6, 0x05, 0x04, 0xcc},
- {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x05, 0x03, 0xcc},
+ {0xb6, 0x04, 0xc0, 0xcc},
{0xb6, 0x12, 0xf8, 0xcc},
- {0xb6, 0x18, 0x0a, 0xcc},
- {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x09, 0xcc},
+ {0xb6, 0x17, 0x60, 0xcc},
{0xb6, 0x16, 0x00, 0xcc},
{0xb6, 0x22, 0x12, 0xcc},
{0xb6, 0x23, 0x0b, 0xcc},
- {0xb3, 0x02, 0x02, 0xcc},
{0xbf, 0xc0, 0x39, 0xcc},
{0xbf, 0xc1, 0x04, 0xcc},
- {0xbf, 0xcc, 0x10, 0xcc},
- {0xb9, 0x12, 0x00, 0xcc},
- {0xb9, 0x13, 0x14, 0xcc},
- {0xb9, 0x14, 0x14, 0xcc},
- {0xb9, 0x15, 0x14, 0xcc},
- {0xb9, 0x16, 0x14, 0xcc},
- {0xb9, 0x18, 0x00, 0xcc},
- {0xb9, 0x19, 0x1e, 0xcc},
- {0xb9, 0x1a, 0x1e, 0xcc},
- {0xb9, 0x1b, 0x1e, 0xcc},
- {0xb9, 0x1c, 0x1e, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
{0xb3, 0x01, 0x41, 0xcc},
- {0xb8, 0x8e, 0x00, 0xcc},
- {0xb8, 0x8f, 0xff, 0xcc},
- {0xb6, 0x12, 0xf8, 0xcc},
- {0xb8, 0x0c, 0x20, 0xcc},
- {0xb8, 0x0d, 0x70, 0xcc},
- {0xb6, 0x13, 0x13, 0xcc},
- {0x2f, 0x00, 0xC0, 0xbb},
- {0xb8, 0xa0, 0x12, 0xcc},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0x00, 0x00, 0x80, 0xdd},
+ {0x06, 0x70, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5e, 0x6a, 0x53, 0xbb},
+ {0x5f, 0x40, 0x2c, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x58, 0x00, 0x00, 0xbb},
+ {0x53, 0x09, 0x03, 0xbb},
+ {0x54, 0x31, 0x18, 0xbb},
+ {0x55, 0x8b, 0x5f, 0xbb},
+ {0x56, 0xc0, 0xa9, 0xbb},
+ {0x57, 0xe0, 0xd2, 0xbb},
+ {0xe1, 0x00, 0x00, 0xbb},
+ {0xdc, 0x09, 0x03, 0xbb},
+ {0xdd, 0x31, 0x18, 0xbb},
+ {0xde, 0x8b, 0x5f, 0xbb},
+ {0xdf, 0xc0, 0xa9, 0xbb},
+ {0xe0, 0xe0, 0xd2, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf0, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
{}
};
-static const __u8 mi1320_gamma[17] = {
+static const u8 mi1320_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 mi1320_matrix[9] = {
+static const u8 mi1320_matrix[9] = {
0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
};
-static const __u8 mi1320_initVGA_data[][4] = {
+static const u8 mi1320_initVGA_data[][4] = {
{0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
@@ -841,7 +931,7 @@ static const __u8 mi1320_initVGA_data[][4] = {
{0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
{}
};
-static const __u8 mi1320_initQVGA_data[][4] = {
+static const u8 mi1320_initQVGA_data[][4] = {
{0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
@@ -948,7 +1038,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
{0x07, 0x00, 0xe0, 0xbb},
{0x08, 0x00, 0x0b, 0xbb},
{0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
{0xbf, 0xcc, 0x04, 0xcc},
@@ -958,7 +1048,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1051,7 +1141,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
{0x07, 0x00, 0xe0, 0xbb},
{0x08, 0x00, 0x0b, 0xbb},
{0x21, 0x00, 0x0c, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
{0xbf, 0xcc, 0x04, 0xcc},
@@ -1071,7 +1161,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1161,7 +1251,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x00, 0x00, 0x20, 0xdd},
{0xf0, 0x00, 0x00, 0xbb},
{0x00, 0x00, 0x30, 0xdd},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x00, 0x00, 0x20, 0xdd},
{0xbf, 0xc0, 0x26, 0xcc},
{0xbf, 0xc1, 0x02, 0xcc},
@@ -1172,7 +1262,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x01, 0x42, 0xbb},
{0x08, 0x00, 0x11, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1230,7 +1320,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x06, 0x00, 0x11, 0xbb},
{0x07, 0x00, 0x85, 0xbb},
{0x08, 0x00, 0x27, 0xbb},
- {0x20, 0x01, 0x03, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */
{0x21, 0x80, 0x00, 0xbb},
{0x22, 0x0d, 0x0f, 0xbb},
{0x24, 0x80, 0x00, 0xbb},
@@ -1249,15 +1339,15 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
{0x64, 0x5e, 0x1c, 0xbb},
{}
};
-static const __u8 po3130_gamma[17] = {
+static const u8 po3130_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 po3130_matrix[9] = {
+static const u8 po3130_matrix[9] = {
0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
};
-static const __u8 po3130_initVGA_data[][4] = {
+static const u8 po3130_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
@@ -1340,7 +1430,7 @@ static const __u8 po3130_initVGA_data[][4] = {
{0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
{}
};
-static const __u8 po3130_rundata[][4] = {
+static const u8 po3130_rundata[][4] = {
{0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
{0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
{0x00, 0x44, 0x40, 0xaa},
@@ -1355,7 +1445,7 @@ static const __u8 po3130_rundata[][4] = {
{}
};
-static const __u8 po3130_initQVGA_data[][4] = {
+static const u8 po3130_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
{0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
@@ -1441,16 +1531,16 @@ static const __u8 po3130_initQVGA_data[][4] = {
{}
};
-static const __u8 hv7131r_gamma[17] = {
+static const u8 hv7131r_gamma[17] = {
/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
* 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
};
-static const __u8 hv7131r_matrix[9] = {
+static const u8 hv7131r_matrix[9] = {
0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
};
-static const __u8 hv7131r_initVGA_data[][4] = {
+static const u8 hv7131r_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -1493,7 +1583,7 @@ static const __u8 hv7131r_initVGA_data[][4] = {
{}
};
-static const __u8 hv7131r_initQVGA_data[][4] = {
+static const u8 hv7131r_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x24, 0xcc},
@@ -1548,14 +1638,14 @@ static const __u8 hv7131r_initQVGA_data[][4] = {
{}
};
-static const __u8 ov7660_gamma[17] = {
+static const u8 ov7660_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 ov7660_matrix[9] = {
+static const u8 ov7660_matrix[9] = {
0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
};
-static const __u8 ov7660_initVGA_data[][4] = {
+static const u8 ov7660_initVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd},
{0xb0, 0x03, 0x01, 0xcc},
@@ -1613,7 +1703,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
{0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
{}
};
-static const __u8 ov7660_initQVGA_data[][4] = {
+static const u8 ov7660_initQVGA_data[][4] = {
{0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
{0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
{0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
@@ -1682,26 +1772,26 @@ static const __u8 ov7660_initQVGA_data[][4] = {
{}
};
-static const __u8 ov7660_50HZ[][4] = {
+static const u8 ov7660_50HZ[][4] = {
{0x00, 0x3b, 0x08, 0xaa},
{0x00, 0x9d, 0x40, 0xaa},
{0x00, 0x13, 0xa7, 0xaa},
{}
};
-static const __u8 ov7660_60HZ[][4] = {
+static const u8 ov7660_60HZ[][4] = {
{0x00, 0x3b, 0x00, 0xaa},
{0x00, 0x9e, 0x40, 0xaa},
{0x00, 0x13, 0xa7, 0xaa},
{}
};
-static const __u8 ov7660_NoFliker[][4] = {
+static const u8 ov7660_NoFliker[][4] = {
{0x00, 0x13, 0x87, 0xaa},
{}
};
-static const __u8 ov7670_initVGA_JPG[][4] = {
+static const u8 ov7670_initVGA_JPG[][4] = {
{0xb3, 0x01, 0x05, 0xcc},
{0x00, 0x00, 0x30, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
{0x00, 0x00, 0x10, 0xdd},
@@ -1831,7 +1921,7 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
{},
};
-static const __u8 ov7670_initQVGA_JPG[][4] = {
+static const u8 ov7670_initQVGA_JPG[][4] = {
{0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x30, 0xdd},
{0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
{0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
@@ -1966,14 +2056,14 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
};
/* PO1200 - values from usbvm326.inf and ms-win trace */
-static const __u8 po1200_gamma[17] = {
+static const u8 po1200_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
};
-static const __u8 po1200_matrix[9] = {
+static const u8 po1200_matrix[9] = {
0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
};
-static const __u8 po1200_initVGA_data[][4] = {
+static const u8 po1200_initVGA_data[][4] = {
{0xb0, 0x03, 0x19, 0xcc}, /* reset? */
{0xb0, 0x03, 0x19, 0xcc},
/* {0x00, 0x00, 0x33, 0xdd}, */
@@ -2276,9 +2366,9 @@ static const struct sensor_info sensor_info_data[] = {
/* read 'len' bytes in gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
- __u16 req,
- __u16 index,
- __u16 len)
+ u16 req,
+ u16 index,
+ u16 len)
{
usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -2290,9 +2380,9 @@ static void reg_r(struct gspca_dev *gspca_dev,
}
static void reg_w(struct usb_device *dev,
- __u16 req,
- __u16 value,
- __u16 index)
+ u16 req,
+ u16 value,
+ u16 index)
{
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -2342,11 +2432,18 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int i;
u16 value;
const struct sensor_info *ptsensor_info;
+/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+ }
+
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
@@ -2406,17 +2503,17 @@ static void i2c_write(struct gspca_dev *gspca_dev,
}
static void put_tab_to_reg(struct gspca_dev *gspca_dev,
- const __u8 *tab, __u8 tabsize, __u16 addr)
+ const u8 *tab, u8 tabsize, u16 addr)
{
int j;
- __u16 ad = addr;
+ u16 ad = addr;
for (j = 0; j < tabsize; j++)
reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
}
static void usb_exchange(struct gspca_dev *gspca_dev,
- const __u8 data[][4])
+ const u8 data[][4])
{
struct usb_device *dev = gspca_dev->dev;
int i = 0;
@@ -2466,7 +2563,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
};
cam = &gspca_dev->cam;
- sd->bridge = id->driver_info;
+ sd->bridge = id->driver_info >> 8;
+ sd->flags = id->driver_info & 0xff;
sensor = vc032x_probe_sensor(gspca_dev);
switch (sensor) {
case -1:
@@ -2519,8 +2617,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_MI1320_SOC:
cam->cam_mode = bi_mode;
cam->nmodes = ARRAY_SIZE(bi_mode);
- cam->input_flags = V4L2_IN_ST_VFLIP |
- V4L2_IN_ST_HFLIP;
break;
default:
cam->cam_mode = vc0323_mode;
@@ -2532,14 +2628,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
- if (sd->sensor == SENSOR_OV7670) {
- sd->hflip = 1;
- sd->vflip = 1;
- }
+ if (sd->sensor == SENSOR_OV7670)
+ sd->flags |= FL_HFLIP | FL_VFLIP;
sd->lightfreq = FREQ_DEF;
if (sd->sensor != SENSOR_OV7670)
gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
switch (sd->sensor) {
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320_SOC:
case SENSOR_OV7660:
case SENSOR_OV7670:
case SENSOR_PO1200:
@@ -2568,39 +2664,50 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-/* for OV7660 and OV7670 only */
+/* some sensors only */
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
-
+ u8 data[2], hflip, vflip;
+
+ hflip = sd->hflip;
+ if (sd->flags & FL_HFLIP)
+ hflip != hflip;
+ vflip = sd->vflip;
+ if (sd->flags & FL_VFLIP)
+ vflip != vflip;
switch (sd->sensor) {
- case SENSOR_OV7660:
- data = 1;
+ case SENSOR_MI1310_SOC:
+ case SENSOR_MI1320_SOC:
+ data[0] = data[1] = 0; /* select page 0 */
+ i2c_write(gspca_dev, 0xf0, data, 2);
+ data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
+ data[1] = 0x02 * hflip
+ | 0x01 * vflip;
+ i2c_write(gspca_dev, 0x20, data, 2);
break;
+ case SENSOR_OV7660:
case SENSOR_OV7670:
- data = 7;
+ data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
+ data[0] |= OV7660_MVFP_MIRROR * hflip
+ | OV7660_MVFP_VFLIP * vflip;
+ i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
break;
case SENSOR_PO1200:
- data = 0;
- i2c_write(gspca_dev, 0x03, &data, 1);
- data = 0x80 * sd->hflip
- | 0x40 * sd->vflip
+ data[0] = 0;
+ i2c_write(gspca_dev, 0x03, data, 1);
+ data[0] = 0x80 * hflip
+ | 0x40 * vflip
| 0x06;
- i2c_write(gspca_dev, 0x1e, &data, 1);
- return;
- default:
- return;
+ i2c_write(gspca_dev, 0x1e, data, 1);
+ break;
}
- data |= OV7660_MVFP_MIRROR * sd->hflip
- | OV7660_MVFP_VFLIP * sd->vflip;
- i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
}
static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- static const __u8 (*ov7660_freq_tb[3])[4] =
+ static const u8 (*ov7660_freq_tb[3])[4] =
{ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
if (sd->sensor != SENSOR_OV7660)
@@ -2612,7 +2719,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
+ u8 data;
if (sd->sensor != SENSOR_PO1200)
return;
@@ -2625,9 +2732,9 @@ static void setsharpness(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- const __u8 (*init)[4];
- const __u8 *GammaT = NULL;
- const __u8 *MatrixT = NULL;
+ const u8 (*init)[4];
+ const u8 *GammaT = NULL;
+ const u8 *MatrixT = NULL;
int mode;
static const u8 (*mi1320_soc_init[])[4] = {
mi1320_soc_InitSXGA,
@@ -2635,6 +2742,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
mi1320_soc_InitQVGA,
};
+/*fixme: back sensor only*/
+ if (sd->flags & FL_SAMSUNG) {
+ reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
+ reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
+ reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+ }
+
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
@@ -2737,15 +2851,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
/* set the led on 0x0892 0x0896 */
- if (sd->sensor != SENSOR_PO1200) {
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ if (sd->sensor == SENSOR_PO1200) {
+ setsharpness(gspca_dev);
+ sethvflip(gspca_dev);
+ reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ } else if (sd->sensor == SENSOR_MI1310_SOC) {
+ reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
msleep(100);
sethvflip(gspca_dev);
setlightfreq(gspca_dev);
} else {
- setsharpness(gspca_dev);
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ msleep(100);
sethvflip(gspca_dev);
- reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ setlightfreq(gspca_dev);
}
}
return 0;
@@ -2754,8 +2873,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
+ struct sd *sd = (struct sd *) gspca_dev;
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ if (sd->sensor == SENSOR_MI1310_SOC)
+ reg_w(dev, 0x89, 0x058c, 0x00ff);
+ else
+ reg_w(dev, 0x89, 0xffff, 0xffff);
reg_w(dev, 0xa0, 0x01, 0xb301);
reg_w(dev, 0xa0, 0x09, 0xb003);
}
@@ -2764,15 +2887,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
+ struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
- reg_w(dev, 0x89, 0xffff, 0xffff);
+/*fixme: is this useful?*/
+ if (sd->sensor == SENSOR_MI1310_SOC)
+ reg_w(dev, 0x89, 0x058c, 0x00ff);
+ else
+ reg_w(dev, 0x89, 0xffff, 0xffff);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
- __u8 *data, /* isoc packet */
+ u8 *data, /* isoc packet */
int len) /* iso pkt length */
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2872,21 +3000,12 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- default:
-/* case 2: * V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
}
return -EINVAL;
}
@@ -2906,19 +3025,23 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
+#define BF(bridge, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 8) \
+ | (flags)
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x041e, 0x405b), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
- {USB_DEVICE(0x15b8, 0x6001), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
- {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
+ {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
+ {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
+ {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)},
+ {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
+ {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
+ {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
+ {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
+ {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 08422d315e68..3d2756f7874a 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -7243,6 +7243,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 188bd5aea258..1c9bc94c905c 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -126,7 +126,7 @@ static int device_authorization(struct hdpvr_device *dev)
char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
if (!print_buf) {
v4l2_err(&dev->v4l2_dev, "Out of memory\n");
- goto error;
+ return retval;
}
#endif
@@ -140,7 +140,7 @@ static int device_authorization(struct hdpvr_device *dev)
if (ret != 46) {
v4l2_err(&dev->v4l2_dev,
"unexpected answer of status request, len %d\n", ret);
- goto error;
+ goto unlock;
}
#ifdef HDPVR_DEBUG
else {
@@ -163,7 +163,7 @@ static int device_authorization(struct hdpvr_device *dev)
v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
dev->usbc_buf[1]);
ret = -EINVAL;
- goto error;
+ goto unlock;
}
response = dev->usbc_buf+38;
@@ -188,10 +188,10 @@ static int device_authorization(struct hdpvr_device *dev)
10000);
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"magic request returned %d\n", ret);
- mutex_unlock(&dev->usbc_mutex);
retval = ret != 8;
-error:
+unlock:
+ mutex_unlock(&dev->usbc_mutex);
return retval;
}
@@ -350,6 +350,7 @@ static int hdpvr_probe(struct usb_interface *interface,
mutex_lock(&dev->io_mutex);
if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+ mutex_unlock(&dev->io_mutex);
v4l2_err(&dev->v4l2_dev,
"allocating transfer buffers failed\n");
goto error;
@@ -381,7 +382,6 @@ static int hdpvr_probe(struct usb_interface *interface,
error:
if (dev) {
- mutex_unlock(&dev->io_mutex);
/* this frees allocated memory */
hdpvr_delete(dev);
}
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index c4b5d1515c10..296330a0e1e5 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -127,7 +127,6 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
sizeof(i2c_adap->name));
i2c_adap->algo = &hdpvr_algo;
i2c_adap->class = I2C_CLASS_TV_ANALOG;
- i2c_adap->id = I2C_HW_B_HDPVR;
i2c_adap->owner = THIS_MODULE;
i2c_adap->dev.parent = &dev->udev->dev;
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index ccd47f57f42c..5937de23c813 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -375,6 +375,7 @@ static int hdpvr_open(struct file *file)
* in resumption */
mutex_lock(&dev->io_mutex);
dev->open_count++;
+ mutex_unlock(&dev->io_mutex);
fh->dev = dev;
@@ -383,7 +384,6 @@ static int hdpvr_open(struct file *file)
retval = 0;
err:
- mutex_unlock(&dev->io_mutex);
return retval;
}
@@ -519,8 +519,10 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
mutex_lock(&dev->io_mutex);
- if (video_is_unregistered(dev->video_dev))
+ if (video_is_unregistered(dev->video_dev)) {
+ mutex_unlock(&dev->io_mutex);
return -EIO;
+ }
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 86f2fefe1edf..b92ddcabf0b6 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -122,12 +122,12 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
return 1;
}
-static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
}
-static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
}
@@ -357,9 +357,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x47:
case 0x71:
case 0x2d:
- if (adap->id == I2C_HW_B_CX2388x) {
+ if (adap->id == I2C_HW_B_CX2388x ||
+ adap->id == I2C_HW_B_CX2341X) {
/* Handled by cx88-input */
- name = "CX2388x remote";
+ name = adap->id == I2C_HW_B_CX2341X ? "CX2341x remote"
+ : "CX2388x remote";
ir_type = IR_TYPE_RC5;
ir->get_key = get_key_haup_xvr;
if (hauppauge == 1) {
@@ -392,7 +394,36 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir_codes = init_data->ir_codes;
name = init_data->name;
- ir->get_key = init_data->get_key;
+ if (init_data->type)
+ ir_type = init_data->type;
+
+ switch (init_data->internal_get_key_func) {
+ case IR_KBD_GET_KEY_CUSTOM:
+ /* The bridge driver provided us its own function */
+ ir->get_key = init_data->get_key;
+ break;
+ case IR_KBD_GET_KEY_PIXELVIEW:
+ ir->get_key = get_key_pixelview;
+ break;
+ case IR_KBD_GET_KEY_PV951:
+ ir->get_key = get_key_pv951;
+ break;
+ case IR_KBD_GET_KEY_HAUP:
+ ir->get_key = get_key_haup;
+ break;
+ case IR_KBD_GET_KEY_KNC1:
+ ir->get_key = get_key_knc1;
+ break;
+ case IR_KBD_GET_KEY_FUSIONHDTV:
+ ir->get_key = get_key_fusionhdtv;
+ break;
+ case IR_KBD_GET_KEY_HAUP_XVR:
+ ir->get_key = get_key_haup_xvr;
+ break;
+ case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS:
+ ir->get_key = get_key_avermedia_cardbus;
+ break;
+ }
}
/* Make sure we are all setup before going on */
@@ -454,7 +485,8 @@ static int ir_remove(struct i2c_client *client)
static const struct i2c_device_id ir_kbd_id[] = {
/* Generic entry for any IR receiver */
{ "ir_video", 0 },
- /* IR device specific entries could be added here */
+ /* IR device specific entries should be added here */
+ { "ir_rx_z8f0811_haup", 0 },
{ }
};
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 2883c8780760..4873b6ca5801 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -977,26 +977,27 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
/* ------------------------------------------------------------------------- */
-/* AVerMedia PVR-150 Plus (M113) card */
+/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */
static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
- { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */
{ 0, 0, 0 }
};
static const struct ivtv_card ivtv_card_aver_pvr150 = {
.type = IVTV_CARD_AVER_PVR150PLUS,
- .name = "AVerMedia PVR-150 Plus",
+ .name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
.hw_muxer = IVTV_HW_GPIO,
- .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+ IVTV_HW_WM8739 | IVTV_HW_GPIO,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
- { IVTV_CARD_INPUT_SVIDEO1, 1,
- CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
},
.audio_inputs = {
@@ -1004,18 +1005,66 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
- .gpio_init = { .direction = 0x0800, .initial_value = 0 },
- .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+ /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+ .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+ .gpio_audio_input = { .mask = 0xc000,
+ .tuner = 0x0000,
+ .linein = 0x4000,
+ .radio = 0x8000 },
.tuners = {
- /* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
+ /* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */
+ { .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 },
},
.pci_list = ivtv_pci_aver_pvr150,
+ /* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */
.i2c = &ivtv_i2c_radio,
};
/* ------------------------------------------------------------------------- */
+/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
+ .type = IVTV_CARD_AVER_ULTRA1500MCE,
+ .name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_muxer = IVTV_HW_GPIO,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+ IVTV_HW_WM8739 | IVTV_HW_GPIO,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 },
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+ /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+ .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+ .gpio_audio_input = { .mask = 0xc000,
+ .tuner = 0x0000,
+ .linein = 0x4000,
+ .radio = 0x8000 },
+ .tuners = {
+ /* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ },
+ .pci_list = ivtv_pci_aver_ultra1500mce,
+ .i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
/* AVerMedia EZMaker PCI Deluxe card */
static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
@@ -1180,6 +1229,7 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_aver_ezmaker,
&ivtv_card_aver_m104,
&ivtv_card_buffalo,
+ &ivtv_card_aver_ultra1500mce,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 0b8fe85fb697..e99a0a255578 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -50,7 +50,8 @@
#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */
#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */
-#define IVTV_CARD_LAST 25
+#define IVTV_CARD_AVER_ULTRA1500MCE 26 /* AVerMedia UltraTV 1500 MCE */
+#define IVTV_CARD_LAST 26
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index a3b77ed3f089..4a9c8ce0ecb3 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -17,6 +17,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 <linux/kernel.h>
#include "ivtv-driver.h"
#include "ivtv-cards.h"
@@ -281,7 +282,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
idx = p.audio_properties & 0x03;
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
- if (idx < sizeof(freqs))
+ if (idx < ARRAY_SIZE(freqs))
ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
return err;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 558f8a837ff4..63ea0fb66063 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -186,6 +186,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
"\t\t\t25 = AverMedia M104 (not yet working)\n"
"\t\t\t26 = Buffalo PC-MV5L/PCI\n"
+ "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -218,7 +219,7 @@ MODULE_PARM_DESC(ivtv_yuv_mode,
"\t\t\tDefault: 0 (interlaced)");
MODULE_PARM_DESC(ivtv_yuv_threshold,
"If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n"
- "\t\t\tDefault: 480");;
+ "\t\t\tDefault: 480");
MODULE_PARM_DESC(enc_mpg_buffers,
"Encoder MPG Buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS));
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 85ac707228e7..aede061cae5d 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -236,18 +236,6 @@ static int subdev_s_radio(struct v4l2_subdev *sd)
return 0;
}
-static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
-{
- struct ivtv *itv = sd_to_ivtv(sd);
- u16 mask, data;
-
- mask = itv->card->gpio_audio_input.mask;
- data = itv->card->gpio_audio_input.tuner;
- if (mask)
- write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
- return 0;
-}
-
static int subdev_s_audio_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -344,7 +332,6 @@ static const struct v4l2_subdev_core_ops subdev_core_ops = {
.g_ctrl = subdev_g_ctrl,
.s_ctrl = subdev_s_ctrl,
.queryctrl = subdev_queryctrl,
- .s_std = subdev_s_std,
};
static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index e52aa322b134..8f15a31d3f66 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -509,7 +509,6 @@ static struct i2c_algorithm ivtv_algo = {
/* template for our-bit banger */
static struct i2c_adapter ivtv_i2c_adap_hw_template = {
.name = "ivtv i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = &ivtv_algo,
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
@@ -560,7 +559,6 @@ static int ivtv_getsda_old(void *data)
/* template for i2c-bit-algo */
static struct i2c_adapter ivtv_i2c_adap_template = {
.name = "ivtv i2c driver",
- .id = I2C_HW_B_CX2341X,
.algo = NULL, /* set by i2c-algo-bit */
.algo_data = NULL, /* filled from template */
.owner = THIS_MODULE,
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 1d66855a379a..d0765bed79c9 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1915,8 +1915,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
}
static struct pci_device_id meye_pci_tbl[] = {
- { PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 },
{ }
};
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 1fe8fc9183a7..c14bf47d6928 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -8,6 +8,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
+#include <asm/div64.h>
#include <media/v4l2-device.h>
#include "mt9v011.h"
#include <media/v4l2-i2c-drv.h>
@@ -57,6 +58,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
struct mt9v011 {
struct v4l2_subdev sd;
unsigned width, height;
+ unsigned xtal;
u16 global_gain, red_bal, blue_bal;
};
@@ -131,7 +133,7 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
{ R1E_MT9V011_DIGITAL_ZOOM, 0x0000 },
{ R20_MT9V011_READ_MODE, 0x1000 },
- { R07_MT9V011_OUT_CTRL, 0x000a }, /* chip enable */
+ { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */
};
static void set_balance(struct v4l2_subdev *sd)
@@ -154,6 +156,31 @@ static void set_balance(struct v4l2_subdev *sd)
mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
}
+static void calc_fps(struct v4l2_subdev *sd)
+{
+ struct mt9v011 *core = to_mt9v011(sd);
+ unsigned height, width, hblank, vblank, speed;
+ unsigned row_time, t_time;
+ u64 frames_per_ms;
+ unsigned tmp;
+
+ height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
+ width = mt9v011_read(sd, R04_MT9V011_WIDTH);
+ hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
+ vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
+ speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED);
+
+ row_time = (width + 113 + hblank) * (speed + 2);
+ t_time = row_time * (height + vblank + 1);
+
+ frames_per_ms = core->xtal * 1000l;
+ do_div(frames_per_ms, t_time);
+ tmp = frames_per_ms;
+
+ v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n",
+ tmp / 1000, tmp % 1000, t_time);
+}
+
static void set_res(struct v4l2_subdev *sd)
{
struct mt9v011 *core = to_mt9v011(sd);
@@ -175,10 +202,12 @@ static void set_res(struct v4l2_subdev *sd)
mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
- vstart = 8 + (640 - core->height) / 2;
+ vstart = 8 + (480 - core->height) / 2;
mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
+
+ calc_fps(sd);
};
static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
@@ -215,6 +244,23 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return -EINVAL;
}
+static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ v4l2_dbg(1, debug, sd, "queryctrl called\n");
+
+ for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++)
+ if (qc->id && qc->id == mt9v011_qctrl[i].id) {
+ memcpy(qc, &(mt9v011_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+
static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct mt9v011 *core = to_mt9v011(sd);
@@ -294,6 +340,22 @@ static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
return 0;
}
+static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
+{
+ struct mt9v011 *core = to_mt9v011(sd);
+ unsigned *xtal = data;
+
+ v4l2_dbg(1, debug, sd, "s_config called\n");
+
+ if (xtal) {
+ core->xtal = *xtal;
+ v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+ *xtal / 1000000, (*xtal / 1000) % 1000);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9v011_g_register(struct v4l2_subdev *sd,
@@ -331,16 +393,21 @@ static int mt9v011_s_register(struct v4l2_subdev *sd,
static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
+ u16 version;
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
+
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011,
- MT9V011_VERSION);
+ version);
}
static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
+ .queryctrl = mt9v011_queryctrl,
.g_ctrl = mt9v011_g_ctrl,
.s_ctrl = mt9v011_s_ctrl,
.reset = mt9v011_reset,
+ .s_config = mt9v011_s_config,
.g_chip_ident = mt9v011_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v011_g_register,
@@ -385,8 +452,9 @@ static int mt9v011_probe(struct i2c_client *c,
/* Check if the sensor is really a MT9V011 */
version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
- if (version != MT9V011_VERSION) {
- v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n",
+ if ((version != MT9V011_VERSION) &&
+ (version != MT9V011_REV_B_VERSION)) {
+ v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
version);
kfree(core);
return -EINVAL;
@@ -395,9 +463,10 @@ static int mt9v011_probe(struct i2c_client *c,
core->global_gain = 0x0024;
core->width = 640;
core->height = 480;
+ core->xtal = 27000000; /* Hz */
- v4l_info(c, "chip found @ 0x%02x (%s)\n",
- c->addr << 1, c->adapter->name);
+ v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
+ c->addr << 1, c->adapter->name, version);
return 0;
}
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h
index 9e443ee30558..3350fd6083c3 100644
--- a/drivers/media/video/mt9v011.h
+++ b/drivers/media/video/mt9v011.h
@@ -30,6 +30,7 @@
#define R35_MT9V011_GLOBAL_GAIN 0x35
#define RF1_MT9V011_CHIP_ENABLE 0xf1
-#define MT9V011_VERSION 0x8243
+#define MT9V011_VERSION 0x8232
+#define MT9V011_REV_B_VERSION 0x8243
#endif
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 610bd848df24..a334b1a966a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -540,7 +540,6 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
static struct i2c_adapter pvr2_i2c_adap_template = {
.owner = THIS_MODULE,
.class = 0,
- .id = I2C_HW_B_BT848,
};
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 0b658dee05a4..844565bde53b 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -135,12 +135,6 @@
#define DEVICE_USE_CODEC3(x) ((x)>=700)
#define DEVICE_USE_CODEC23(x) ((x)>=675)
-
-#ifndef V4L2_PIX_FMT_PWC1
-#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1')
-#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2')
-#endif
-
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 46e0d8ad880f..e048d25798cc 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1579,6 +1579,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->mclk = 20000000;
}
+ pcdev->soc_host.dev = &pdev->dev;
pcdev->mclk_divisor = mclk_get_divisor(pcdev);
INIT_LIST_HEAD(&pcdev->capture);
@@ -1644,7 +1645,6 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev)
pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME;
pcdev->soc_host.ops = &pxa_soc_camera_host_ops;
pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
err = soc_camera_host_register(&pcdev->soc_host);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index c25e81af5ce0..c3e96f070973 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -40,7 +40,7 @@
/* insmod options */
static unsigned int debug;
static unsigned int xtal;
-static unsigned int rbds;
+static unsigned int mmbs;
static unsigned int plvl;
static unsigned int bufblocks = 100;
@@ -48,8 +48,8 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
module_param(xtal, int, 0);
MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
-module_param(rbds, int, 0);
-MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0");
+module_param(mmbs, int, 0);
+MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
module_param(plvl, int, 0);
MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
module_param(bufblocks, int, 0);
@@ -78,6 +78,7 @@ struct saa6588 {
unsigned char last_blocknum;
wait_queue_head_t read_queue;
int data_available_for_read;
+ u8 sync;
};
static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s)
unsigned char tmp;
/* Although we only need 3 bytes, we have to read at least 6.
- SAA6588 returns garbage otherwise */
+ SAA6588 returns garbage otherwise. */
if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1)
dprintk(PREFIX "read error!\n");
return;
}
+ s->sync = tmpbuf[0] & 0x10;
+ if (!s->sync)
+ return;
blocknum = tmpbuf[0] >> 5;
if (blocknum == s->last_blocknum) {
if (debug > 3)
@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s)
occurred during reception of this block.
Bit 6: Corrected bit. Indicates that an error was
corrected for this data block.
- Bits 5-3: Received Offset. Indicates the offset received
- by the sync system.
- Bits 2-0: Offset Name. Indicates the offset applied to this data.
+ Bits 5-3: Same as bits 0-2.
+ Bits 2-0: Block number.
SAA6588 byte order is Status-MSB-LSB, so we have to swap the
first and the last of the 3 bytes block.
@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s)
tmpbuf[2] = tmpbuf[0];
tmpbuf[0] = tmp;
+ /* Map 'Invalid block E' to 'Invalid Block' */
+ if (blocknum == 6)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
+ /* And if are not in mmbs mode, then 'Block E' is also mapped
+ to 'Invalid Block'. As far as I can tell MMBS is discontinued,
+ and if there is ever a need to support E blocks, then please
+ contact the linux-media mailinglist. */
+ else if (!mmbs && blocknum == 5)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
tmp = blocknum;
tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */
if ((tmpbuf[2] & 0x03) == 0x03)
- tmp |= 0x80; /* uncorrectable error */
+ tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */
else if ((tmpbuf[2] & 0x03) != 0x00)
- tmp |= 0x40; /* corrected error */
+ tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */
spin_lock_irqsave(&s->lock, flags);
@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work)
schedule_delayed_work(&s->work, msecs_to_jiffies(20));
}
-static int saa6588_configure(struct saa6588 *s)
+static void saa6588_configure(struct saa6588 *s)
{
struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned char buf[3];
int rc;
buf[0] = cSyncRestart;
- if (rbds)
+ if (mmbs)
buf[0] |= cProcessingModeRBDS;
buf[1] = cFlywheelDefault;
@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s)
rc = i2c_master_send(client, buf, 3);
if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
-
- return 0;
}
/* ---------------------------------------------------------------------- */
@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
+static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ vt->capability |= V4L2_TUNER_CAP_RDS;
+ if (s->sync)
+ vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+ return 0;
+}
+
+static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ saa6588_configure(s);
+ return 0;
+}
+
static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = {
.ioctl = saa6588_ioctl,
};
+static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
+ .g_tuner = saa6588_g_tuner,
+ .s_tuner = saa6588_s_tuner,
+};
+
static const struct v4l2_subdev_ops saa6588_ops = {
.core = &saa6588_core_ops,
+ .tuner = &saa6588_tuner_ops,
};
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 94a023a14bbc..cb78c956d810 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1012,8 +1012,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev,
&dev->i2c_adap, "saa6588", "saa6588",
saa7134_boards[dev->board].rds_addr);
- if (sd)
+ if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+ dev->has_rds = 1;
+ }
}
request_submodules(dev);
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index ba87128542e0..da26f476a302 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1444,7 +1444,6 @@ video_poll(struct file *file, struct poll_table_struct *wait)
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.vb_lock);
buf = fh->cap.read_buf;
}
@@ -1790,7 +1789,7 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
if (0 != err)
return err;
- if (i < 0 || i >= SAA7134_INPUT_MAX)
+ if (i >= SAA7134_INPUT_MAX)
return -EINVAL;
if (NULL == card_in(dev, i).name)
return -EINVAL;
@@ -1819,6 +1818,8 @@ static int saa7134_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (saa7134_no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 82268848f26a..f591c07b7254 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -539,6 +539,7 @@ struct saa7134_dev {
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
unsigned char eedata[256];
+ int has_rds;
/* video overlay */
struct v4l2_framebuffer ovbuf;
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 8b4e7dafce7b..6a91714125d2 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -734,10 +734,6 @@ static int stv680_start_stream (struct usb_stv *stv680)
return 0;
nomem_err:
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
for (i = 0; i < STV680_NUMSBUF; i++) {
usb_kill_urb(stv680->urb[i]);
usb_free_urb(stv680->urb[i]);
@@ -745,6 +741,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
kfree(stv680->sbuf[i].data);
stv680->sbuf[i].data = NULL;
}
+ /* used in irq, free only as all URBs are dead */
+ for (i = 0; i < STV680_NUMSCRATCH; i++) {
+ kfree(stv680->scratch[i].data);
+ stv680->scratch[i].data = NULL;
+ }
return -ENOMEM;
}
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index 3750f7fadb12..244372627df2 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -31,7 +31,10 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
-#include <media/v4l2-int-device.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
#include <media/tvp514x.h>
#include "tvp514x_regs.h"
@@ -49,15 +52,11 @@ static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-#define dump_reg(client, reg, val) \
- do { \
- val = tvp514x_read_reg(client, reg); \
- v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
- } while (0)
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
-/**
- * enum tvp514x_std - enum for supported standards
- */
+/* enum tvp514x_std - enum for supported standards */
enum tvp514x_std {
STD_NTSC_MJ = 0,
STD_PAL_BDGHIN,
@@ -65,14 +64,6 @@ enum tvp514x_std {
};
/**
- * enum tvp514x_state - enum for different decoder states
- */
-enum tvp514x_state {
- STATE_NOT_DETECTED,
- STATE_DETECTED
-};
-
-/**
* struct tvp514x_std_info - Structure to store standard informations
* @width: Line width in pixels
* @height:Number of active lines
@@ -89,33 +80,27 @@ struct tvp514x_std_info {
static struct tvp514x_reg tvp514x_reg_list_default[0x40];
/**
* struct tvp514x_decoder - TVP5146/47 decoder object
- * @v4l2_int_device: Slave handle
- * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
+ * @sd: Subdevice Slave handle
* @tvp514x_regs: copy of hw's regs with preset values.
* @pdata: Board specific
- * @client: I2C client data
- * @id: Entry from I2C table
* @ver: Chip version
- * @state: TVP5146/47 decoder state - detected or not-detected
+ * @streaming: TVP5146/47 decoder streaming - enabled or disabled.
* @pix: Current pixel format
* @num_fmts: Number of formats
* @fmt_list: Format list
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
- * @route: input and output routing at chip level
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
*/
struct tvp514x_decoder {
- struct v4l2_int_device v4l2_int_device;
- struct v4l2_int_slave tvp514x_slave;
+ struct v4l2_subdev sd;
struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
const struct tvp514x_platform_data *pdata;
- struct i2c_client *client;
-
- struct i2c_device_id *id;
int ver;
- enum tvp514x_state state;
+ int streaming;
struct v4l2_pix_format pix;
int num_fmts;
@@ -124,15 +109,18 @@ struct tvp514x_decoder {
enum tvp514x_std current_std;
int num_stds;
struct tvp514x_std_info *std_list;
-
- struct v4l2_routing route;
+ /* Input and Output Routing parameters */
+ u32 input;
+ u32 output;
};
/* TVP514x default register values */
static struct tvp514x_reg tvp514x_reg_list_default[] = {
- {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */
+ /* Composite selected */
+ {TOK_WRITE, REG_INPUT_SEL, 0x05},
{TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
- {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */
+ /* Auto mode */
+ {TOK_WRITE, REG_VIDEO_STD, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
{TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
{TOK_WRITE, REG_COLOR_KILLER, 0x10},
@@ -145,53 +133,74 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
{TOK_WRITE, REG_HUE, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
{TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
- {TOK_SKIP, 0x0F, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x0F, 0x00},
{TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
{TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
{TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
- {TOK_SKIP, 0x13, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x13, 0x00},
{TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
- {TOK_SKIP, 0x15, 0x00}, /* Reserved */
- {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, /* NTSC timing */
+ /* Reserved */
+ {TOK_SKIP, 0x15, 0x00},
+ /* NTSC timing */
+ {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},
{TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
{TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
{TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
- {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},
{TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
{TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
{TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
- {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},
{TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
{TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
- {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, /* NTSC timing */
+ /* NTSC timing */
+ {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},
{TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
{TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
{TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
- {TOK_SKIP, 0x26, 0x00}, /* Reserved */
- {TOK_SKIP, 0x27, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x26, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x27, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
- {TOK_SKIP, 0x29, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x29, 0x00},
{TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
- {TOK_SKIP, 0x2B, 0x00}, /* Reserved */
+ /* Reserved */
+ {TOK_SKIP, 0x2B, 0x00},
{TOK_SKIP, REG_SCART_DELAY, 0x00},
{TOK_SKIP, REG_CTI_DELAY, 0x00},
{TOK_SKIP, REG_CTI_CONTROL, 0x00},
- {TOK_SKIP, 0x2F, 0x00}, /* Reserved */
- {TOK_SKIP, 0x30, 0x00}, /* Reserved */
- {TOK_SKIP, 0x31, 0x00}, /* Reserved */
- {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, /* HS, VS active high */
- {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, /* 10-bit BT.656 */
- {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, /* Enable clk & data */
- {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, /* Enable AVID & FLD */
- {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, /* Enable VS & HS */
+ /* Reserved */
+ {TOK_SKIP, 0x2F, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x30, 0x00},
+ /* Reserved */
+ {TOK_SKIP, 0x31, 0x00},
+ /* HS, VS active high */
+ {TOK_WRITE, REG_SYNC_CONTROL, 0x00},
+ /* 10-bit BT.656 */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},
+ /* Enable clk & data */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},
+ /* Enable AVID & FLD */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},
+ /* Enable VS & HS */
+ {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},
{TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
{TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
- {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */
+ /* Clear status */
+ {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01},
{TOK_TERM, 0, 0},
};
-/* List of image formats supported by TVP5146/47 decoder
+/**
+ * List of image formats supported by TVP5146/47 decoder
* Currently we are using 8 bit mode only, but can be
* extended to 10/20 bit mode.
*/
@@ -205,7 +214,7 @@ static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
},
};
-/*
+/**
* Supported standards -
*
* Currently supports two standards only, need to add support for rest of the
@@ -240,35 +249,32 @@ static struct tvp514x_std_info tvp514x_std_list[] = {
},
/* Standard: need to add for additional standard */
};
-/*
- * Control structure for Auto Gain
- * This is temporary data, will get replaced once
- * v4l2_ctrl_query_fill supports it.
- */
-static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
- .id = V4L2_CID_AUTOGAIN,
- .name = "Gain, Automatic",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
-};
-/*
- * Read a value from a register in an TVP5146/47 decoder device.
+
+static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tvp514x_decoder, sd);
+}
+
+
+/**
+ * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ *
* Returns value read if successful, or non-zero (-1) otherwise.
*/
-static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
read_again:
err = i2c_smbus_read_byte_data(client, reg);
if (err == -1) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Read: retry ... %d\n", retry);
+ v4l2_warn(sd, "Read: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto read_again;
@@ -278,20 +284,39 @@ read_again:
return err;
}
-/*
+/**
+ * dump_reg() - dump the register content of TVP5146/47.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ */
+static void dump_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ u32 val;
+
+ val = tvp514x_read_reg(sd, reg);
+ v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
+}
+
+/**
+ * tvp514x_write_reg() - Write a value to a register in TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: TVP5146/47 register address
+ * @val: value to be written to the register
+ *
* Write a value to a register in an TVP5146/47 decoder device.
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{
- int err;
- int retry = 0;
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
write_again:
err = i2c_smbus_write_byte_data(client, reg, val);
if (err) {
if (retry <= I2C_RETRY_COUNT) {
- v4l_warn(client, "Write: retry ... %d\n", retry);
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto write_again;
@@ -301,17 +326,19 @@ write_again:
return err;
}
-/*
- * tvp514x_write_regs : Initializes a list of TVP5146/47 registers
+/**
+ * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @reglist: list of TVP5146/47 registers and values
+ *
+ * Initializes a list of TVP5146/47 registers:-
* if token is TOK_TERM, then entire write operation terminates
* if token is TOK_DELAY, then a delay of 'val' msec is introduced
* if token is TOK_SKIP, then the register write is skipped
* if token is TOK_WRITE, then the register write is performed
- *
- * reglist - list of registers to be written
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_write_regs(struct i2c_client *client,
+static int tvp514x_write_regs(struct v4l2_subdev *sd,
const struct tvp514x_reg reglist[])
{
int err;
@@ -326,31 +353,33 @@ static int tvp514x_write_regs(struct i2c_client *client,
if (next->token == TOK_SKIP)
continue;
- err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+ err = tvp514x_write_reg(sd, next->reg, (u8) next->val);
if (err) {
- v4l_err(client, "Write failed. Err[%d]\n", err);
+ v4l2_err(sd, "Write failed. Err[%d]\n", err);
return err;
}
}
return 0;
}
-/*
- * tvp514x_get_current_std:
- * Returns the current standard detected by TVP5146/47
+/**
+ * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Get current standard detected by TVP5146/47, STD_INVALID if there is no
+ * standard detected.
*/
-static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
- *decoder)
+static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
- std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
- if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+ std = tvp514x_read_reg(sd, REG_VIDEO_STD);
+ if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT)
/* use the standard status register */
- std_status = tvp514x_read_reg(decoder->client,
- REG_VIDEO_STD_STATUS);
- } else
- std_status = std; /* use the standard register itself */
+ std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS);
+ else
+ /* use the standard register itself */
+ std_status = std;
switch (std_status & VIDEO_STD_MASK) {
case VIDEO_STD_NTSC_MJ_BIT:
@@ -366,94 +395,99 @@ static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
return STD_INVALID;
}
-/*
- * TVP5146/47 register dump function
- */
-static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
+/* TVP5146/47 register dump function */
+static void tvp514x_reg_dump(struct v4l2_subdev *sd)
{
- u8 value;
-
- dump_reg(decoder->client, REG_INPUT_SEL, value);
- dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value);
- dump_reg(decoder->client, REG_VIDEO_STD, value);
- dump_reg(decoder->client, REG_OPERATION_MODE, value);
- dump_reg(decoder->client, REG_COLOR_KILLER, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL1, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL2, value);
- dump_reg(decoder->client, REG_LUMA_CONTROL3, value);
- dump_reg(decoder->client, REG_BRIGHTNESS, value);
- dump_reg(decoder->client, REG_CONTRAST, value);
- dump_reg(decoder->client, REG_SATURATION, value);
- dump_reg(decoder->client, REG_HUE, value);
- dump_reg(decoder->client, REG_CHROMA_CONTROL1, value);
- dump_reg(decoder->client, REG_CHROMA_CONTROL2, value);
- dump_reg(decoder->client, REG_COMP_PR_SATURATION, value);
- dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value);
- dump_reg(decoder->client, REG_COMP_PB_SATURATION, value);
- dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value);
- dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value);
- dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value);
- dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value);
- dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value);
- dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value);
- dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value);
- dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value);
- dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value);
- dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value);
- dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value);
- dump_reg(decoder->client, REG_SYNC_CONTROL, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value);
- dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value);
- dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value);
+ dump_reg(sd, REG_INPUT_SEL);
+ dump_reg(sd, REG_AFE_GAIN_CTRL);
+ dump_reg(sd, REG_VIDEO_STD);
+ dump_reg(sd, REG_OPERATION_MODE);
+ dump_reg(sd, REG_COLOR_KILLER);
+ dump_reg(sd, REG_LUMA_CONTROL1);
+ dump_reg(sd, REG_LUMA_CONTROL2);
+ dump_reg(sd, REG_LUMA_CONTROL3);
+ dump_reg(sd, REG_BRIGHTNESS);
+ dump_reg(sd, REG_CONTRAST);
+ dump_reg(sd, REG_SATURATION);
+ dump_reg(sd, REG_HUE);
+ dump_reg(sd, REG_CHROMA_CONTROL1);
+ dump_reg(sd, REG_CHROMA_CONTROL2);
+ dump_reg(sd, REG_COMP_PR_SATURATION);
+ dump_reg(sd, REG_COMP_Y_CONTRAST);
+ dump_reg(sd, REG_COMP_PB_SATURATION);
+ dump_reg(sd, REG_COMP_Y_BRIGHTNESS);
+ dump_reg(sd, REG_AVID_START_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_START_PIXEL_MSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_AVID_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_START_PIXEL_MSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB);
+ dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_START_LINE_MSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_LSB);
+ dump_reg(sd, REG_VSYNC_STOP_LINE_MSB);
+ dump_reg(sd, REG_VBLK_START_LINE_LSB);
+ dump_reg(sd, REG_VBLK_START_LINE_MSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_LSB);
+ dump_reg(sd, REG_VBLK_STOP_LINE_MSB);
+ dump_reg(sd, REG_SYNC_CONTROL);
+ dump_reg(sd, REG_OUTPUT_FORMATTER1);
+ dump_reg(sd, REG_OUTPUT_FORMATTER2);
+ dump_reg(sd, REG_OUTPUT_FORMATTER3);
+ dump_reg(sd, REG_OUTPUT_FORMATTER4);
+ dump_reg(sd, REG_OUTPUT_FORMATTER5);
+ dump_reg(sd, REG_OUTPUT_FORMATTER6);
+ dump_reg(sd, REG_CLEAR_LOST_LOCK);
}
-/*
- * Configure the TVP5146/47 with the current register settings
+/**
+ * tvp514x_configure() - Configure the TVP5146/47 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @decoder: ptr to tvp514x_decoder structure
+ *
* Returns zero if successful, or non-zero otherwise.
*/
-static int tvp514x_configure(struct tvp514x_decoder *decoder)
+static int tvp514x_configure(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
{
int err;
/* common register initialization */
err =
- tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
+ tvp514x_write_regs(sd, decoder->tvp514x_regs);
if (err)
return err;
if (debug)
- tvp514x_reg_dump(decoder);
+ tvp514x_reg_dump(sd);
return 0;
}
-/*
- * Detect if an tvp514x is present, and if so which revision.
+/**
+ * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision.
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @decoder: pointer to tvp514x_decoder structure
+ *
* A device is considered to be detected if the chip ID (LSB and MSB)
* registers match the expected values.
* Any value of the rom version register is accepted.
* Returns ENODEV error number if no device is detected, or zero
* if a device is detected.
*/
-static int tvp514x_detect(struct tvp514x_decoder *decoder)
+static int tvp514x_detect(struct v4l2_subdev *sd,
+ struct tvp514x_decoder *decoder)
{
u8 chip_id_msb, chip_id_lsb, rom_ver;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
- chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
- rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+ chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB);
+ chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB);
+ rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION);
- v4l_dbg(1, debug, decoder->client,
+ v4l2_dbg(1, debug, sd,
"chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
chip_id_msb, chip_id_lsb, rom_ver);
if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
@@ -462,38 +496,30 @@ static int tvp514x_detect(struct tvp514x_decoder *decoder)
/* We didn't read the values we expected, so this must not be
* an TVP5146/47.
*/
- v4l_err(decoder->client,
- "chip id mismatch msb:0x%x lsb:0x%x\n",
- chip_id_msb, chip_id_lsb);
+ v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
+ chip_id_msb, chip_id_lsb);
return -ENODEV;
}
decoder->ver = rom_ver;
- decoder->state = STATE_DETECTED;
- v4l_info(decoder->client,
- "%s found at 0x%x (%s)\n", decoder->client->name,
- decoder->client->addr << 1,
- decoder->client->adapter->name);
+ v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
+ client->name, decoder->ver,
+ client->addr << 1, client->adapter->name);
return 0;
}
-/*
- * Following are decoder interface functions implemented by
- * TVP5146/47 decoder driver.
- */
-
/**
- * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
* detected, returns -EINVAL
*/
-static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
enum tvp514x_input input_sel;
u8 sync_lock_status, lock_mask;
@@ -502,11 +528,11 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
- input_sel = decoder->route.input;
+ input_sel = decoder->input;
switch (input_sel) {
case INPUT_CVBS_VI1A:
@@ -544,42 +570,39 @@ static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
return -EINVAL;
}
/* check whether signal is locked */
- sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
if (lock_mask != (sync_lock_status & lock_mask))
return -EINVAL; /* No input detected */
decoder->current_std = current_std;
*std_id = decoder->std_list[current_std].standard.id;
- v4l_dbg(1, debug, decoder->client, "Current STD: %s",
+ v4l2_dbg(1, debug, sd, "Current STD: %s",
decoder->std_list[current_std].standard.name);
return 0;
}
/**
- * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_std() - V4L2 decoder interface handler for s_std
+ * @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 v4l2_std_id ioctl enum
*
* If std_id is supported, sets the requested standard. Otherwise, returns
* -EINVAL
*/
-static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err, i;
- if (std_id == NULL)
- return -EINVAL;
-
for (i = 0; i < decoder->num_stds; i++)
- if (*std_id & decoder->std_list[i].standard.id)
+ if (std_id & decoder->std_list[i].standard.id)
break;
if ((i == decoder->num_stds) || (i == STD_INVALID))
return -EINVAL;
- err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
+ err = tvp514x_write_reg(sd, REG_VIDEO_STD,
decoder->std_list[i].video_std);
if (err)
return err;
@@ -588,24 +611,26 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
- v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+ v4l2_dbg(1, debug, sd, "Standard set to: %s",
decoder->std_list[i].standard.name);
return 0;
}
/**
- * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
- * @s: pointer to standard V4L2 device structure
- * @index: number of the input
+ * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @input: input selector for routing the signal
+ * @output: output selector for routing the signal
+ * @config: config value. Not used
*
* If index is valid, selects the requested input. Otherwise, returns -EINVAL if
* the input is not supported or there is no active signal present in the
* selected input.
*/
-static int ioctl_s_routing(struct v4l2_int_device *s,
- struct v4l2_routing *route)
+static int tvp514x_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err;
enum tvp514x_input input_sel;
enum tvp514x_output output_sel;
@@ -613,20 +638,21 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
u8 sync_lock_status, lock_mask;
int try_count = LOCK_RETRY_COUNT;
- if ((!route) || (route->input >= INPUT_INVALID) ||
- (route->output >= OUTPUT_INVALID))
- return -EINVAL; /* Index out of bound */
+ if ((input >= INPUT_INVALID) ||
+ (output >= OUTPUT_INVALID))
+ /* Index out of bound */
+ return -EINVAL;
- input_sel = route->input;
- output_sel = route->output;
+ input_sel = input;
+ output_sel = output;
- err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
+ err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel);
if (err)
return err;
- output_sel |= tvp514x_read_reg(decoder->client,
+ output_sel |= tvp514x_read_reg(sd,
REG_OUTPUT_FORMATTER1) & 0x7;
- err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
+ err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1,
output_sel);
if (err)
return err;
@@ -637,7 +663,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
/* Clear status */
msleep(LOCK_RETRY_DELAY);
err =
- tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
+ tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01);
if (err)
return err;
@@ -672,7 +698,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT;
break;
- /*Need to add other interfaces*/
+ /* Need to add other interfaces*/
default:
return -EINVAL;
}
@@ -682,42 +708,41 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
msleep(LOCK_RETRY_DELAY);
/* get the current standard for future reference */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
continue;
- sync_lock_status = tvp514x_read_reg(decoder->client,
+ sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
- break; /* Input detected */
+ /* Input detected */
+ break;
}
if ((current_std == STD_INVALID) || (try_count < 0))
return -EINVAL;
decoder->current_std = current_std;
- decoder->route.input = route->input;
- decoder->route.output = route->output;
+ decoder->input = input;
+ decoder->output = output;
- v4l_dbg(1, debug, decoder->client,
- "Input set to: %d, std : %d",
+ v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
input_sel, current_std);
return 0;
}
/**
- * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @qctrl: standard V4L2 v4l2_queryctrl structure
*
* If the requested control is supported, returns the control information.
* Otherwise, returns -EINVAL if the control is not supported.
*/
static int
-ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = -EINVAL;
if (qctrl == NULL)
@@ -725,13 +750,13 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
switch (qctrl->id) {
case V4L2_CID_BRIGHTNESS:
- /* Brightness supported is (0-255),
- */
+ /* Brightness supported is (0-255), */
err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
break;
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
- /* Saturation and Contrast supported is -
+ /**
+ * Saturation and Contrast supported is -
* Contrast: 0 - 255 (Default - 128)
* Saturation: 0 - 255 (Default - 128)
*/
@@ -744,30 +769,27 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
break;
case V4L2_CID_AUTOGAIN:
- /* Autogain is either 0 or 1*/
- memcpy(qctrl, &tvp514x_autogain_ctrl,
- sizeof(struct v4l2_queryctrl));
- err = 0;
+ /**
+ * Auto Gain supported is -
+ * 0 - 1 (Default - 1)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", qctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", qctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Query Control: %s : Min - %d, Max - %d, Def - %d",
- qctrl->name,
- qctrl->minimum,
- qctrl->maximum,
+ v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+ qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
return err;
}
/**
- * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, returns the control's current
@@ -775,9 +797,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
* supported.
*/
static int
-ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (ctrl == NULL)
return -EINVAL;
@@ -811,74 +833,70 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return -EINVAL;
}
- v4l_dbg(1, debug, decoder->client,
- "Get Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
ctrl->id, ctrl->value);
return 0;
}
/**
- * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
* @ctrl: pointer to v4l2_control structure
*
* If the requested control is supported, sets the control's current
* value in HW. Otherwise, returns -EINVAL if the control is not supported.
*/
static int
-ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int err = -EINVAL, value;
if (ctrl == NULL)
return err;
- value = (__s32) ctrl->value;
+ value = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid brightness setting %d\n",
+ v4l2_err(sd, "invalid brightness setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
+ err = tvp514x_write_reg(sd, REG_BRIGHTNESS,
value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid contrast setting %d\n",
+ v4l2_err(sd, "invalid contrast setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
- value);
+ err = tvp514x_write_reg(sd, REG_CONTRAST, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_CONTRAST].val = value;
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(decoder->client,
- "invalid saturation setting %d\n",
+ v4l2_err(sd, "invalid saturation setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_SATURATION,
- value);
+ err = tvp514x_write_reg(sd, REG_SATURATION, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_SATURATION].val = value;
break;
case V4L2_CID_HUE:
@@ -889,15 +907,13 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0;
else {
- v4l_err(decoder->client,
- "invalid hue setting %d\n",
- ctrl->value);
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_HUE,
- value);
+ err = tvp514x_write_reg(sd, REG_HUE, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_HUE].val = value;
break;
case V4L2_CID_AUTOGAIN:
@@ -906,41 +922,38 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
else if (value == 0)
value = 0x0C;
else {
- v4l_err(decoder->client,
- "invalid auto gain setting %d\n",
+ v4l2_err(sd, "invalid auto gain setting %d\n",
ctrl->value);
return -ERANGE;
}
- err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
- value);
+ err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value);
if (err)
return err;
+
decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
break;
default:
- v4l_err(decoder->client,
- "invalid control id %d\n", ctrl->id);
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
return err;
}
- v4l_dbg(1, debug, decoder->client,
- "Set Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
ctrl->id, ctrl->value);
return err;
}
/**
- * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
*
* Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
*/
static int
-ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
+tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int index;
if (fmt == NULL)
@@ -948,24 +961,25 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
index = fmt->index;
if ((index >= decoder->num_fmts) || (index < 0))
- return -EINVAL; /* Index out of bound */
+ /* Index out of bound */
+ return -EINVAL;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
memcpy(fmt, &decoder->fmt_list[index],
sizeof(struct v4l2_fmtdesc));
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: index - %d (%s)",
+ v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)",
decoder->fmt_list[index].index,
decoder->fmt_list[index].description);
return 0;
}
/**
- * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
*
* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
@@ -973,9 +987,9 @@ ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
* without actually making it take effect.
*/
static int
-ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
int ifmt;
struct v4l2_pix_format *pix;
enum tvp514x_std current_std;
@@ -984,12 +998,13 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pix = &f->fmt.pix;
/* Calculate height and width based on current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1003,7 +1018,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
break;
}
if (ifmt == decoder->num_fmts)
- ifmt = 0; /* None of the format matched, select default */
+ /* None of the format matched, select default */
+ ifmt = 0;
pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
pix->field = V4L2_FIELD_INTERLACED;
@@ -1012,8 +1028,7 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->priv = 0;
- v4l_dbg(1, debug, decoder->client,
- "Try FMT: pixelformat - %s, bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
"Width - %d, Height - %d",
decoder->fmt_list[ifmt].description, pix->bytesperline,
pix->width, pix->height);
@@ -1021,8 +1036,8 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
*
* If the requested format is supported, configures the HW to use that
@@ -1030,9 +1045,9 @@ ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
* correctly configured.
*/
static int
-ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_pix_format *pix;
int rval;
@@ -1040,10 +1055,11 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
pix = &f->fmt.pix;
- rval = ioctl_try_fmt_cap(s, f);
+ rval = tvp514x_try_fmt_cap(sd, f);
if (rval)
return rval;
@@ -1053,28 +1069,28 @@ ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap
+ * @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 v4l2_format structure
*
* Returns the decoder's current pixel format in the v4l2_format
* parameter.
*/
static int
-ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
if (f == NULL)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
f->fmt.pix = decoder->pix;
- v4l_dbg(1, debug, decoder->client,
- "Current FMT: bytesperline - %d"
+ v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
"Width - %d, Height - %d",
decoder->pix.bytesperline,
decoder->pix.width, decoder->pix.height);
@@ -1082,16 +1098,16 @@ ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
}
/**
- * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
*
* Returns the decoder's video CAPTURE parameters.
*/
static int
-ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_captureparm *cparm;
enum tvp514x_std current_std;
@@ -1099,13 +1115,14 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
memset(a, 0, sizeof(*a));
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1120,17 +1137,17 @@ ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
}
/**
- * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
- * @s: pointer to standard V4L2 device structure
+ * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
*
* Configures the decoder to use the input parameters, if possible. If
* not possible, returns the appropriate error code.
*/
static int
-ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
- struct tvp514x_decoder *decoder = s->priv;
+ struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
@@ -1138,12 +1155,13 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL; /* only capture is supported */
+ /* only capture is supported */
+ return -EINVAL;
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
- current_std = tvp514x_get_current_std(decoder);
+ current_std = tvp514x_get_current_std(sd);
if (current_std == STD_INVALID)
return -EINVAL;
@@ -1156,111 +1174,58 @@ ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
}
/**
- * ioctl_g_ifparm - V4L2 decoder interface handler for vidioc_int_g_ifparm_num
- * @s: pointer to standard V4L2 device structure
- * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
- *
- * Gets slave interface parameters.
- * Calculates the required xclk value to support the requested
- * clock parameters in p. This value is returned in the p
- * parameter.
- */
-static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
-{
- struct tvp514x_decoder *decoder = s->priv;
- int rval;
-
- if (p == NULL)
- return -EINVAL;
-
- if (NULL == decoder->pdata->ifparm)
- return -EINVAL;
-
- rval = decoder->pdata->ifparm(p);
- if (rval) {
- v4l_err(decoder->client, "g_ifparm.Err[%d]\n", rval);
- return rval;
- }
-
- p->u.bt656.clock_curr = TVP514X_XCLK_BT656;
-
- return 0;
-}
-
-/**
- * ioctl_g_priv - V4L2 decoder interface handler for vidioc_int_g_priv_num
- * @s: pointer to standard V4L2 device structure
- * @p: void pointer to hold decoder's private data address
- *
- * Returns device's (decoder's) private data area address in p parameter
- */
-static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
-{
- struct tvp514x_decoder *decoder = s->priv;
-
- if (NULL == decoder->pdata->priv_data_set)
- return -EINVAL;
-
- return decoder->pdata->priv_data_set(p);
-}
-
-/**
- * ioctl_s_power - V4L2 decoder interface handler for vidioc_int_s_power_num
- * @s: pointer to standard V4L2 device structure
- * @on: power state to which device is to be set
+ * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
*
- * Sets devices power state to requrested state, if possible.
+ * Sets streaming to enable or disable, if possible.
*/
-static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
+static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct tvp514x_decoder *decoder = s->priv;
int err = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- switch (on) {
- case V4L2_POWER_OFF:
- /* Power Down Sequence */
- err =
- tvp514x_write_reg(decoder->client, REG_OPERATION_MODE,
- 0x01);
- /* Disable mux for TVP5146/47 decoder data path */
- if (decoder->pdata->power_set)
- err |= decoder->pdata->power_set(on);
- decoder->state = STATE_NOT_DETECTED;
- break;
+ if (decoder->streaming == enable)
+ return 0;
- case V4L2_POWER_STANDBY:
- if (decoder->pdata->power_set)
- err = decoder->pdata->power_set(on);
+ switch (enable) {
+ case 0:
+ {
+ /* Power Down Sequence */
+ err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01);
+ if (err) {
+ v4l2_err(sd, "Unable to turn off decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
break;
+ }
+ case 1:
+ {
+ struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
+ client->driver->id_table->driver_data;
- case V4L2_POWER_ON:
- /* Enable mux for TVP5146/47 decoder data path */
- if ((decoder->pdata->power_set) &&
- (decoder->state == STATE_NOT_DETECTED)) {
- int i;
- struct tvp514x_init_seq *int_seq =
- (struct tvp514x_init_seq *)
- decoder->id->driver_data;
-
- err = decoder->pdata->power_set(on);
-
- /* Power Up Sequence */
- for (i = 0; i < int_seq->no_regs; i++) {
- err |= tvp514x_write_reg(decoder->client,
- int_seq->init_reg_seq[i].reg,
- int_seq->init_reg_seq[i].val);
- }
- /* Detect the sensor is not already detected */
- err |= tvp514x_detect(decoder);
- if (err) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
+ /* Power Up Sequence */
+ err = tvp514x_write_regs(sd, int_seq);
+ if (err) {
+ v4l2_err(sd, "Unable to turn on decoder\n");
+ return err;
}
- err |= tvp514x_configure(decoder);
+ /* Detect if not already detected */
+ err = tvp514x_detect(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to detect decoder\n");
+ return err;
+ }
+ err = tvp514x_configure(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to configure decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
break;
-
+ }
default:
err = -ENODEV;
break;
@@ -1269,93 +1234,38 @@ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
return err;
}
-/**
- * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT
- * @s: pointer to standard V4L2 device structure
- *
- * Initialize the decoder device (calls tvp514x_configure())
- */
-static int ioctl_init(struct v4l2_int_device *s)
-{
- struct tvp514x_decoder *decoder = s->priv;
-
- /* Set default standard to auto */
- decoder->tvp514x_regs[REG_VIDEO_STD].val =
- VIDEO_STD_AUTO_SWITCH_BIT;
-
- return tvp514x_configure(decoder);
-}
-
-/**
- * ioctl_dev_exit - V4L2 decoder interface handler for vidioc_int_dev_exit_num
- * @s: pointer to standard V4L2 device structure
- *
- * Delinitialise the dev. at slave detach. The complement of ioctl_dev_init.
- */
-static int ioctl_dev_exit(struct v4l2_int_device *s)
-{
- return 0;
-}
-
-/**
- * ioctl_dev_init - V4L2 decoder interface handler for vidioc_int_dev_init_num
- * @s: pointer to standard V4L2 device structure
- *
- * Initialise the device when slave attaches to the master. Returns 0 if
- * TVP5146/47 device could be found, otherwise returns appropriate error.
- */
-static int ioctl_dev_init(struct v4l2_int_device *s)
-{
- struct tvp514x_decoder *decoder = s->priv;
- int err;
-
- err = tvp514x_detect(decoder);
- if (err < 0) {
- v4l_err(decoder->client,
- "Unable to detect decoder\n");
- return err;
- }
-
- v4l_info(decoder->client,
- "chip version 0x%.2x detected\n", decoder->ver);
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+ .queryctrl = tvp514x_queryctrl,
+ .g_ctrl = tvp514x_g_ctrl,
+ .s_ctrl = tvp514x_s_ctrl,
+ .s_std = tvp514x_s_std,
+};
- return 0;
-}
+static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+ .s_routing = tvp514x_s_routing,
+ .querystd = tvp514x_querystd,
+ .enum_fmt = tvp514x_enum_fmt_cap,
+ .g_fmt = tvp514x_g_fmt_cap,
+ .try_fmt = tvp514x_try_fmt_cap,
+ .s_fmt = tvp514x_s_fmt_cap,
+ .g_parm = tvp514x_g_parm,
+ .s_parm = tvp514x_s_parm,
+ .s_stream = tvp514x_s_stream,
+};
-static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
- {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*) ioctl_dev_init},
- {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func*) ioctl_dev_exit},
- {vidioc_int_s_power_num, (v4l2_int_ioctl_func*) ioctl_s_power},
- {vidioc_int_g_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv},
- {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*) ioctl_g_ifparm},
- {vidioc_int_init_num, (v4l2_int_ioctl_func*) ioctl_init},
- {vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
- {vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_try_fmt_cap},
- {vidioc_int_g_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
- {vidioc_int_s_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_s_fmt_cap},
- {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
- {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
- {vidioc_int_queryctrl_num,
- (v4l2_int_ioctl_func *) ioctl_queryctrl},
- {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl},
- {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
- {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd},
- {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std},
- {vidioc_int_s_video_routing_num,
- (v4l2_int_ioctl_func *) ioctl_s_routing},
+static const struct v4l2_subdev_ops tvp514x_ops = {
+ .core = &tvp514x_core_ops,
+ .video = &tvp514x_video_ops,
};
static struct tvp514x_decoder tvp514x_dev = {
- .state = STATE_NOT_DETECTED,
+ .streaming = 0,
.fmt_list = tvp514x_fmt_list,
.num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
- .pix = { /* Default to NTSC 8-bit YUV 422 */
+ .pix = {
+ /* Default to NTSC 8-bit YUV 422 */
.width = NTSC_NUM_ACTIVE_PIXELS,
.height = NTSC_NUM_ACTIVE_LINES,
.pixelformat = V4L2_PIX_FMT_UYVY,
@@ -1369,20 +1279,13 @@ static struct tvp514x_decoder tvp514x_dev = {
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
- .v4l2_int_device = {
- .module = THIS_MODULE,
- .name = TVP514X_MODULE_NAME,
- .type = v4l2_int_type_slave,
- },
- .tvp514x_slave = {
- .ioctls = tvp514x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
- },
+
};
/**
- * tvp514x_probe - decoder driver i2c probe handler
+ * tvp514x_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
+ * @id: i2c driver id table
*
* Register decoder as an i2c client device and V4L2
* device.
@@ -1391,88 +1294,71 @@ static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp514x_decoder *decoder;
- int err;
+ struct v4l2_subdev *sd;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+ if (!client->dev.platform_data) {
+ v4l2_err(client, "No platform data!!\n");
+ return -ENODEV;
+ }
+
decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
- if (!client->dev.platform_data) {
- v4l_err(client, "No platform data!!\n");
- err = -ENODEV;
- goto out_free;
- }
-
+ /* Initialize the tvp514x_decoder with default configuration */
*decoder = tvp514x_dev;
- decoder->v4l2_int_device.priv = decoder;
- decoder->pdata = client->dev.platform_data;
- decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
+ /* Copy default register configuration */
memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
sizeof(tvp514x_reg_list_default));
- /*
+
+ /* Copy board specific information here */
+ decoder->pdata = client->dev.platform_data;
+
+ /**
* Fetch platform specific data, and configure the
* tvp514x_reg_list[] accordingly. Since this is one
* time configuration, no need to preserve.
*/
decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
- (decoder->pdata->clk_polarity << 1);
+ (decoder->pdata->clk_polarity << 1);
decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
- ((decoder->pdata->hs_polarity << 2) |
- (decoder->pdata->vs_polarity << 3));
- /*
- * Save the id data, required for power up sequence
- */
- decoder->id = (struct i2c_device_id *)id;
- /* Attach to Master */
- strcpy(decoder->v4l2_int_device.u.slave->attach_to,
- decoder->pdata->master);
- decoder->client = client;
- i2c_set_clientdata(client, decoder);
+ ((decoder->pdata->hs_polarity << 2) |
+ (decoder->pdata->vs_polarity << 3));
+ /* Set default standard to auto */
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ VIDEO_STD_AUTO_SWITCH_BIT;
/* Register with V4L2 layer as slave device */
- err = v4l2_int_device_register(&decoder->v4l2_int_device);
- if (err) {
- i2c_set_clientdata(client, NULL);
- v4l_err(client,
- "Unable to register to v4l2. Err[%d]\n", err);
- goto out_free;
-
- } else
- v4l_info(client, "Registered to v4l2 master %s!!\n",
- decoder->pdata->master);
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
+
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
return 0;
-out_free:
- kfree(decoder);
- return err;
}
/**
- * tvp514x_remove - decoder driver i2c remove handler
+ * tvp514x_remove() - decoder driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister decoder as an i2c client device and V4L2
* device. Complement of tvp514x_probe().
*/
-static int __exit tvp514x_remove(struct i2c_client *client)
+static int tvp514x_remove(struct i2c_client *client)
{
- struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
-
- if (!client->adapter)
- return -ENODEV; /* our client isn't attached */
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tvp514x_decoder *decoder = to_decoder(sd);
- v4l2_int_device_unregister(&decoder->v4l2_int_device);
- i2c_set_clientdata(client, NULL);
+ v4l2_device_unregister_subdev(sd);
kfree(decoder);
return 0;
}
-/*
- * TVP5146 Init/Power on Sequence
- */
+/* TVP5146 Init/Power on Sequence */
static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
@@ -1485,14 +1371,10 @@ static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp5146_init = {
- .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
- .init_reg_seq = tvp5146_init_reg_seq,
-};
-/*
- * TVP5147 Init/Power on Sequence
- */
+
+/* TVP5147 Init/Power on Sequence */
static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
{TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
@@ -1512,71 +1394,51 @@ static const struct tvp514x_reg tvp5147_init_reg_seq[] = {
{TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp5147_init = {
- .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
- .init_reg_seq = tvp5147_init_reg_seq,
-};
-/*
- * TVP5146M2/TVP5147M1 Init/Power on Sequence
- */
+
+/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
{TOK_WRITE, REG_OPERATION_MODE, 0x01},
{TOK_WRITE, REG_OPERATION_MODE, 0x00},
+ {TOK_TERM, 0, 0},
};
-static const struct tvp514x_init_seq tvp514xm_init = {
- .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
- .init_reg_seq = tvp514xm_init_reg_seq,
-};
-/*
+
+/**
* I2C Device Table -
*
* name - Name of the actual device/chip.
* driver_data - Driver data
*/
static const struct i2c_device_id tvp514x_id[] = {
- {"tvp5146", (unsigned long)&tvp5146_init},
- {"tvp5146m2", (unsigned long)&tvp514xm_init},
- {"tvp5147", (unsigned long)&tvp5147_init},
- {"tvp5147m1", (unsigned long)&tvp514xm_init},
+ {"tvp5146", (unsigned long)tvp5146_init_reg_seq},
+ {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq},
+ {"tvp5147", (unsigned long)tvp5147_init_reg_seq},
+ {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq},
{},
};
MODULE_DEVICE_TABLE(i2c, tvp514x_id);
-static struct i2c_driver tvp514x_i2c_driver = {
+static struct i2c_driver tvp514x_driver = {
.driver = {
- .name = TVP514X_MODULE_NAME,
- .owner = THIS_MODULE,
- },
+ .owner = THIS_MODULE,
+ .name = TVP514X_MODULE_NAME,
+ },
.probe = tvp514x_probe,
- .remove = __exit_p(tvp514x_remove),
+ .remove = tvp514x_remove,
.id_table = tvp514x_id,
};
-/**
- * tvp514x_init
- *
- * Module init function
- */
static int __init tvp514x_init(void)
{
- return i2c_add_driver(&tvp514x_i2c_driver);
+ return i2c_add_driver(&tvp514x_driver);
}
-/**
- * tvp514x_cleanup
- *
- * Module exit function
- */
-static void __exit tvp514x_cleanup(void)
+static void __exit tvp514x_exit(void)
{
- i2c_del_driver(&tvp514x_i2c_driver);
+ i2c_del_driver(&tvp514x_driver);
}
module_init(tvp514x_init);
-module_exit(tvp514x_cleanup);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("TVP514X linux decoder driver");
-MODULE_LICENSE("GPL");
+module_exit(tvp514x_exit);
diff --git a/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
index 351620aeecc2..18f29ad0dfe2 100644
--- a/drivers/media/video/tvp514x_regs.h
+++ b/drivers/media/video/tvp514x_regs.h
@@ -284,14 +284,4 @@ struct tvp514x_reg {
u32 val;
};
-/**
- * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
- * Sequence.
- * @ no_regs - Number of registers to write for power up sequence.
- * @ init_reg_seq - Array of registers and respective value to write.
- */
-struct tvp514x_init_seq {
- unsigned int no_regs;
- const struct tvp514x_reg *init_reg_seq;
-};
#endif /* ifndef _TVP514X_REGS_H */
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 36a6ba92df27..70043b1704fb 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -34,7 +34,7 @@
static struct uvc_control_info uvc_ctrls[] = {
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BRIGHTNESS_CONTROL,
+ .selector = UVC_PU_BRIGHTNESS_CONTROL,
.index = 0,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -42,7 +42,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_CONTRAST_CONTROL,
+ .selector = UVC_PU_CONTRAST_CONTROL,
.index = 1,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -50,7 +50,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_CONTROL,
+ .selector = UVC_PU_HUE_CONTROL,
.index = 2,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -58,7 +58,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SATURATION_CONTROL,
+ .selector = UVC_PU_SATURATION_CONTROL,
.index = 3,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -66,7 +66,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SHARPNESS_CONTROL,
+ .selector = UVC_PU_SHARPNESS_CONTROL,
.index = 4,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -74,7 +74,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAMMA_CONTROL,
+ .selector = UVC_PU_GAMMA_CONTROL,
.index = 5,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -82,7 +82,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.index = 6,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -90,7 +90,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.index = 7,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -98,7 +98,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.index = 8,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -106,7 +106,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAIN_CONTROL,
+ .selector = UVC_PU_GAIN_CONTROL,
.index = 9,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -114,7 +114,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.index = 10,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -122,7 +122,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_AUTO_CONTROL,
+ .selector = UVC_PU_HUE_AUTO_CONTROL,
.index = 11,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -130,7 +130,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.index = 12,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -138,7 +138,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.index = 13,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -146,7 +146,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_DIGITAL_MULTIPLIER_CONTROL,
+ .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
.index = 14,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -154,7 +154,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
+ .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
.index = 15,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -162,21 +162,21 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_ANALOG_VIDEO_STANDARD_CONTROL,
+ .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
.index = 16,
.size = 1,
.flags = UVC_CONTROL_GET_CUR,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_ANALOG_LOCK_STATUS_CONTROL,
+ .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
.index = 17,
.size = 1,
.flags = UVC_CONTROL_GET_CUR,
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_SCANNING_MODE_CONTROL,
+ .selector = UVC_CT_SCANNING_MODE_CONTROL,
.index = 0,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -184,7 +184,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_MODE_CONTROL,
+ .selector = UVC_CT_AE_MODE_CONTROL,
.index = 1,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -193,7 +193,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_PRIORITY_CONTROL,
+ .selector = UVC_CT_AE_PRIORITY_CONTROL,
.index = 2,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -201,7 +201,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.index = 3,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -209,7 +209,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_RELATIVE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
.index = 4,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -217,7 +217,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.index = 5,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -225,7 +225,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_RELATIVE_CONTROL,
+ .selector = UVC_CT_FOCUS_RELATIVE_CONTROL,
.index = 6,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -233,7 +233,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_IRIS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
.index = 7,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -241,7 +241,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_IRIS_RELATIVE_CONTROL,
+ .selector = UVC_CT_IRIS_RELATIVE_CONTROL,
.index = 8,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -249,7 +249,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.index = 9,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -257,7 +257,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.index = 10,
.size = 3,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -265,7 +265,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PANTILT_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
.index = 11,
.size = 8,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -273,7 +273,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PANTILT_RELATIVE_CONTROL,
+ .selector = UVC_CT_PANTILT_RELATIVE_CONTROL,
.index = 12,
.size = 4,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -281,7 +281,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ROLL_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL,
.index = 13,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -289,7 +289,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ROLL_RELATIVE_CONTROL,
+ .selector = UVC_CT_ROLL_RELATIVE_CONTROL,
.index = 14,
.size = 2,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -297,7 +297,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_AUTO_CONTROL,
+ .selector = UVC_CT_FOCUS_AUTO_CONTROL,
.index = 17,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -305,7 +305,7 @@ static struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PRIVACY_CONTROL,
+ .selector = UVC_CT_PRIVACY_CONTROL,
.index = 18,
.size = 1,
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -332,13 +332,13 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
__s8 zoom = (__s8)data[0];
switch (query) {
- case GET_CUR:
+ case UVC_GET_CUR:
return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
- case GET_MIN:
- case GET_MAX:
- case GET_RES:
- case GET_DEF:
+ case UVC_GET_MIN:
+ case UVC_GET_MAX:
+ case UVC_GET_RES:
+ case UVC_GET_DEF:
default:
return data[2];
}
@@ -356,7 +356,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BRIGHTNESS,
.name = "Brightness",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BRIGHTNESS_CONTROL,
+ .selector = UVC_PU_BRIGHTNESS_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -366,7 +366,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_CONTRAST_CONTROL,
+ .selector = UVC_PU_CONTRAST_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -376,7 +376,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_HUE,
.name = "Hue",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_CONTROL,
+ .selector = UVC_PU_HUE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -386,7 +386,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_SATURATION,
.name = "Saturation",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SATURATION_CONTROL,
+ .selector = UVC_PU_SATURATION_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -396,7 +396,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_SHARPNESS,
.name = "Sharpness",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_SHARPNESS_CONTROL,
+ .selector = UVC_PU_SHARPNESS_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -406,7 +406,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_GAMMA,
.name = "Gamma",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAMMA_CONTROL,
+ .selector = UVC_PU_GAMMA_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -416,7 +416,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BACKLIGHT_COMPENSATION,
.name = "Backlight Compensation",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -426,7 +426,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_GAIN,
.name = "Gain",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_GAIN_CONTROL,
+ .selector = UVC_PU_GAIN_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -436,7 +436,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.name = "Power Line Frequency",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.size = 2,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
@@ -448,7 +448,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_HUE_AUTO,
.name = "Hue, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_HUE_AUTO_CONTROL,
+ .selector = UVC_PU_HUE_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -458,7 +458,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_AUTO,
.name = "Exposure, Auto",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_MODE_CONTROL,
+ .selector = UVC_CT_AE_MODE_CONTROL,
.size = 4,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
@@ -470,7 +470,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
.name = "Exposure, Auto Priority",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_AE_PRIORITY_CONTROL,
+ .selector = UVC_CT_AE_PRIORITY_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -480,7 +480,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_EXPOSURE_ABSOLUTE,
.name = "Exposure (Absolute)",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.size = 32,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -490,7 +490,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.name = "White Balance Temperature, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -500,7 +500,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
.name = "White Balance Temperature",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -510,7 +510,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.name = "White Balance Component, Auto",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -520,7 +520,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_BLUE_BALANCE,
.name = "White Balance Blue Component",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -530,7 +530,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_RED_BALANCE,
.name = "White Balance Red Component",
.entity = UVC_GUID_UVC_PROCESSING,
- .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.size = 16,
.offset = 16,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -540,7 +540,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_FOCUS_ABSOLUTE,
.name = "Focus (absolute)",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -550,7 +550,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_FOCUS_AUTO,
.name = "Focus, Auto",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_FOCUS_AUTO_CONTROL,
+ .selector = UVC_CT_FOCUS_AUTO_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -560,7 +560,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_ZOOM_ABSOLUTE,
.name = "Zoom, Absolute",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.size = 16,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -570,7 +570,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_ZOOM_CONTINUOUS,
.name = "Zoom, Continuous",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.size = 0,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
@@ -582,7 +582,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.id = V4L2_CID_PRIVACY,
.name = "Privacy",
.entity = UVC_GUID_UVC_CAMERA,
- .selector = CT_PRIVACY_CONTROL,
+ .selector = UVC_CT_PRIVACY_CONTROL,
.size = 1,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -675,16 +675,16 @@ static const __u8 uvc_media_transport_input_guid[16] =
static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
{
switch (UVC_ENTITY_TYPE(entity)) {
- case ITT_CAMERA:
+ case UVC_ITT_CAMERA:
return memcmp(uvc_camera_guid, guid, 16) == 0;
- case ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
return memcmp(uvc_processing_guid, guid, 16) == 0;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
return memcmp(entity->extension.guidExtensionCode,
guid, 16) == 0;
@@ -793,11 +793,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
- if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(video->dev, UVC_GET_DEF, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector, data,
+ ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
+ v4l2_ctrl->default_value =
+ mapping->get(mapping, UVC_GET_DEF, data);
}
switch (mapping->v4l2_type) {
@@ -829,25 +831,28 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
}
if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
- if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(video->dev, UVC_GET_MIN, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector, data,
+ ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
+ v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
- if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(video->dev, UVC_GET_MAX, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector, data,
+ ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
+ v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
- if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
- video->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size)) < 0)
+ ret = uvc_query_ctrl(video->dev, UVC_GET_RES, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector, data,
+ ctrl->info->size);
+ if (ret < 0)
goto out;
- v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
+ v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
}
ret = 0;
@@ -912,7 +917,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
continue;
if (!rollback)
- ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+ ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
dev->intfnum, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
@@ -974,7 +979,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
return -EINVAL;
if (!ctrl->loaded) {
- ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
+ ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
@@ -984,7 +989,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
ctrl->loaded = 1;
}
- xctrl->value = mapping->get(mapping, GET_CUR,
+ xctrl->value = mapping->get(mapping, UVC_GET_CUR,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
@@ -1023,7 +1028,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
0, ctrl->info->size);
} else {
- ret = uvc_query_ctrl(video->dev, GET_CUR,
+ ret = uvc_query_ctrl(video->dev, UVC_GET_CUR,
ctrl->entity->id, video->dev->intfnum,
ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1115,9 +1120,9 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
goto out;
}
- ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
- video->dev->intfnum, xctrl->selector, data,
- xctrl->size);
+ ret = uvc_query_ctrl(video->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
+ xctrl->unit, video->dev->intfnum, xctrl->selector,
+ data, xctrl->size);
if (ret < 0)
goto out;
@@ -1211,7 +1216,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
if (!found)
return;
- if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
/* Check if the device control information and length match
* the user supplied information.
*/
@@ -1219,8 +1224,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
__le16 size;
__u8 inf;
- if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
- dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+ ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
+ dev->intfnum, info->selector, (__u8 *)&size, 2);
+ if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
"control " UVC_GUID_FORMAT "/%u (%d).\n",
UVC_GUID_ARGS(info->entity), info->selector,
@@ -1236,8 +1242,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
return;
}
- if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
- dev->intfnum, info->selector, &inf, 1)) < 0) {
+ ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
+ dev->intfnum, info->selector, &inf, 1);
+ if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
"control " UVC_GUID_FORMAT "/%u (%d).\n",
UVC_GUID_ARGS(info->entity), info->selector,
@@ -1391,7 +1398,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
unsigned int size;
unsigned int i;
- if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+ if (UVC_ENTITY_TYPE(entity) != UVC_VC_PROCESSING_UNIT)
return;
controls = entity->processing.bmControls;
@@ -1427,13 +1434,13 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
unsigned int bControlSize = 0, ncontrols = 0;
__u8 *bmControls = NULL;
- if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
bmControls = entity->extension.bmControls;
bControlSize = entity->extension.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
bmControls = entity->processing.bmControls;
bControlSize = entity->processing.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
bmControls = entity->camera.bmControls;
bControlSize = entity->camera.bControlSize;
}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 89927b7aec28..b712365f8d1d 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -249,23 +249,23 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
list_for_each_entry_continue(entity, &dev->entities, list) {
switch (UVC_ENTITY_TYPE(entity)) {
- case TT_STREAMING:
+ case UVC_TT_STREAMING:
if (entity->output.bSourceID == id)
return entity;
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
if (entity->processing.bSourceID == id)
return entity;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
for (i = 0; i < entity->selector.bNrInPins; ++i)
if (entity->selector.baSourceID[i] == id)
return entity;
break;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
for (i = 0; i < entity->extension.bNrInPins; ++i)
if (entity->extension.baSourceID[i] == id)
return entity;
@@ -297,9 +297,9 @@ static int uvc_parse_format(struct uvc_device *dev,
format->index = buffer[3];
switch (buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_FRAME_BASED:
- n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_FRAME_BASED:
+ n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
if (buflen < n) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -325,16 +325,16 @@ static int uvc_parse_format(struct uvc_device *dev,
}
format->bpp = buffer[21];
- if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
- ftype = VS_FRAME_UNCOMPRESSED;
+ if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
+ ftype = UVC_VS_FRAME_UNCOMPRESSED;
} else {
- ftype = VS_FRAME_FRAME_BASED;
+ ftype = UVC_VS_FRAME_FRAME_BASED;
if (buffer[27])
format->flags = UVC_FMT_FLAG_COMPRESSED;
}
break;
- case VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_MJPEG:
if (buflen < 11) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -347,10 +347,10 @@ static int uvc_parse_format(struct uvc_device *dev,
format->fcc = V4L2_PIX_FMT_MJPEG;
format->flags = UVC_FMT_FLAG_COMPRESSED;
format->bpp = 0;
- ftype = VS_FRAME_MJPEG;
+ ftype = UVC_VS_FRAME_MJPEG;
break;
- case VS_FORMAT_DV:
+ case UVC_VS_FORMAT_DV:
if (buflen < 9) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
@@ -395,8 +395,8 @@ static int uvc_parse_format(struct uvc_device *dev,
format->nframes = 1;
break;
- case VS_FORMAT_MPEG2TS:
- case VS_FORMAT_STREAM_BASED:
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
/* Not supported yet. */
default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
@@ -416,7 +416,7 @@ static int uvc_parse_format(struct uvc_device *dev,
*/
while (buflen > 2 && buffer[2] == ftype) {
frame = &format->frame[format->nframes];
- if (ftype != VS_FRAME_FRAME_BASED)
+ if (ftype != UVC_VS_FRAME_FRAME_BASED)
n = buflen > 25 ? buffer[25] : 0;
else
n = buflen > 21 ? buffer[21] : 0;
@@ -436,7 +436,7 @@ static int uvc_parse_format(struct uvc_device *dev,
frame->wHeight = get_unaligned_le16(&buffer[7]);
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
- if (ftype != VS_FRAME_FRAME_BASED) {
+ if (ftype != UVC_VS_FRAME_FRAME_BASED) {
frame->dwMaxVideoFrameBufferSize =
get_unaligned_le32(&buffer[17]);
frame->dwDefaultFrameInterval =
@@ -491,12 +491,12 @@ static int uvc_parse_format(struct uvc_device *dev,
buffer += buffer[0];
}
- if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+ if (buflen > 2 && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
buflen -= buffer[0];
buffer += buffer[0];
}
- if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+ if (buflen > 2 && buffer[2] == UVC_VS_COLORFORMAT) {
if (buflen < 6) {
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d COLORFORMAT error\n",
@@ -530,7 +530,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
int ret = -EINVAL;
if (intf->cur_altsetting->desc.bInterfaceSubClass
- != SC_VIDEOSTREAMING) {
+ != UVC_SC_VIDEOSTREAMING) {
uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
"video streaming interface\n", dev->udev->devnum,
intf->altsetting[0].desc.bInterfaceNumber);
@@ -589,12 +589,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
/* Parse the header descriptor. */
switch (buffer[2]) {
- case VS_OUTPUT_HEADER:
+ case UVC_VS_OUTPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
size = 9;
break;
- case VS_INPUT_HEADER:
+ case UVC_VS_INPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
size = 13;
break;
@@ -618,7 +618,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->header.bNumFormats = p;
streaming->header.bEndpointAddress = buffer[6];
- if (buffer[2] == VS_INPUT_HEADER) {
+ if (buffer[2] == UVC_VS_INPUT_HEADER) {
streaming->header.bmInfo = buffer[7];
streaming->header.bTerminalLink = buffer[8];
streaming->header.bStillCaptureMethod = buffer[9];
@@ -644,15 +644,15 @@ static int uvc_parse_streaming(struct uvc_device *dev,
_buflen = buflen;
/* Count the format and frame descriptors. */
- while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
+ while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
switch (_buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_MJPEG:
- case VS_FORMAT_FRAME_BASED:
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_FRAME_BASED:
nformats++;
break;
- case VS_FORMAT_DV:
+ case UVC_VS_FORMAT_DV:
/* DV format has no frame descriptor. We will create a
* dummy frame descriptor with a dummy frame interval.
*/
@@ -661,22 +661,22 @@ static int uvc_parse_streaming(struct uvc_device *dev,
nintervals++;
break;
- case VS_FORMAT_MPEG2TS:
- case VS_FORMAT_STREAM_BASED:
+ case UVC_VS_FORMAT_MPEG2TS:
+ case UVC_VS_FORMAT_STREAM_BASED:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT %u is not supported.\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber, _buffer[2]);
break;
- case VS_FRAME_UNCOMPRESSED:
- case VS_FRAME_MJPEG:
+ case UVC_VS_FRAME_UNCOMPRESSED:
+ case UVC_VS_FRAME_MJPEG:
nframes++;
if (_buflen > 25)
nintervals += _buffer[25] ? _buffer[25] : 3;
break;
- case VS_FRAME_FRAME_BASED:
+ case UVC_VS_FRAME_FRAME_BASED:
nframes++;
if (_buflen > 21)
nintervals += _buffer[21] ? _buffer[21] : 3;
@@ -709,12 +709,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->nformats = nformats;
/* Parse the format descriptors. */
- while (buflen > 2 && buffer[1] == CS_INTERFACE) {
+ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
switch (buffer[2]) {
- case VS_FORMAT_UNCOMPRESSED:
- case VS_FORMAT_MJPEG:
- case VS_FORMAT_DV:
- case VS_FORMAT_FRAME_BASED:
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ case UVC_VS_FORMAT_MJPEG:
+ case UVC_VS_FORMAT_DV:
+ case UVC_VS_FORMAT_FRAME_BASED:
format->frame = frame;
ret = uvc_parse_format(dev, streaming, format,
&interval, buffer, buflen);
@@ -819,7 +819,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
return -ENOMEM;
unit->id = buffer[3];
- unit->type = VC_EXTENSION_UNIT;
+ unit->type = UVC_VC_EXTENSION_UNIT;
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
@@ -856,7 +856,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
__u16 type;
switch (buffer[2]) {
- case VC_HEADER:
+ case UVC_VC_HEADER:
n = buflen >= 12 ? buffer[11] : 0;
if (buflen < 12 || buflen < 12 + n) {
@@ -883,7 +883,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
}
break;
- case VC_INPUT_TERMINAL:
+ case UVC_VC_INPUT_TERMINAL:
if (buflen < 8) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL error\n",
@@ -908,11 +908,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
p = 0;
len = 8;
- if (type == ITT_CAMERA) {
+ if (type == UVC_ITT_CAMERA) {
n = buflen >= 15 ? buffer[14] : 0;
len = 15;
- } else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+ } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
n = buflen >= 9 ? buffer[8] : 0;
p = buflen >= 10 + n ? buffer[9+n] : 0;
len = 10;
@@ -932,7 +932,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
term->id = buffer[3];
term->type = type | UVC_TERM_INPUT;
- if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+ if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
term->camera.bControlSize = n;
term->camera.bmControls = (__u8 *)term + sizeof *term;
term->camera.wObjectiveFocalLengthMin =
@@ -942,7 +942,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
term->camera.wOcularFocalLength =
get_unaligned_le16(&buffer[12]);
memcpy(term->camera.bmControls, &buffer[15], n);
- } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+ } else if (UVC_ENTITY_TYPE(term) ==
+ UVC_ITT_MEDIA_TRANSPORT_INPUT) {
term->media.bControlSize = n;
term->media.bmControls = (__u8 *)term + sizeof *term;
term->media.bTransportModeSize = p;
@@ -955,9 +956,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (buffer[7] != 0)
usb_string(udev, buffer[7], term->name,
sizeof term->name);
- else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
sprintf(term->name, "Camera %u", buffer[3]);
- else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+ else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
sprintf(term->name, "Media %u", buffer[3]);
else
sprintf(term->name, "Input %u", buffer[3]);
@@ -965,7 +966,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&term->list, &dev->entities);
break;
- case VC_OUTPUT_TERMINAL:
+ case UVC_VC_OUTPUT_TERMINAL:
if (buflen < 9) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d OUTPUT_TERMINAL error\n",
@@ -1002,7 +1003,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&term->list, &dev->entities);
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
p = buflen >= 5 ? buffer[4] : 0;
if (buflen < 5 || buflen < 6 + p) {
@@ -1031,7 +1032,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&unit->list, &dev->entities);
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
n = buflen >= 8 ? buffer[7] : 0;
p = dev->uvc_version >= 0x0110 ? 10 : 9;
@@ -1066,7 +1067,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
list_add_tail(&unit->list, &dev->entities);
break;
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
p = buflen >= 22 ? buffer[21] : 0;
n = buflen >= 24 + p ? buffer[22+p] : 0;
@@ -1194,7 +1195,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
struct uvc_entity *entity)
{
switch (UVC_ENTITY_TYPE(entity)) {
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- XU %d", entity->id);
@@ -1207,7 +1208,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
list_add_tail(&entity->chain, &video->extensions);
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- PU %d", entity->id);
@@ -1220,7 +1221,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
video->processing = entity;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- SU %d", entity->id);
@@ -1237,16 +1238,16 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
video->selector = entity;
break;
- case ITT_VENDOR_SPECIFIC:
- case ITT_CAMERA:
- case ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_ITT_VENDOR_SPECIFIC:
+ case UVC_ITT_CAMERA:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
list_add_tail(&entity->chain, &video->iterms);
break;
- case TT_STREAMING:
+ case UVC_TT_STREAMING:
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
@@ -1291,7 +1292,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
if (forward == NULL)
break;
- if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
+ if (UVC_ENTITY_TYPE(forward) != UVC_VC_EXTENSION_UNIT ||
forward == prev)
continue;
@@ -1323,15 +1324,15 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
int id = -1, i;
switch (UVC_ENTITY_TYPE(entity)) {
- case VC_EXTENSION_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
id = entity->extension.baSourceID[0];
break;
- case VC_PROCESSING_UNIT:
+ case UVC_VC_PROCESSING_UNIT:
id = entity->processing.bSourceID;
break;
- case VC_SELECTOR_UNIT:
+ case UVC_VC_SELECTOR_UNIT:
/* Single-input selector units are ignored. */
if (entity->selector.bNrInPins == 1) {
id = entity->selector.baSourceID[0];
@@ -1377,7 +1378,7 @@ static int uvc_scan_chain(struct uvc_video_device *video)
entity = video->oterm;
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
- if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
+ if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
video->sterm = entity;
id = entity->output.bSourceID;
@@ -1664,7 +1665,8 @@ static void uvc_disconnect(struct usb_interface *intf)
*/
usb_set_intfdata(intf, NULL);
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOSTREAMING)
return;
/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
@@ -1692,7 +1694,8 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
intf->cur_altsetting->desc.bInterfaceNumber);
/* Controls are cached on the fly so they don't need to be saved. */
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL)
return uvc_status_suspend(dev);
if (dev->video.streaming->intf != intf) {
@@ -1711,7 +1714,8 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber);
- if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+ UVC_SC_VIDEOCONTROL) {
if (reset) {
int ret = uvc_ctrl_resume_device(dev);
@@ -1845,11 +1849,29 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* ViMicro */
+ /* ViMicro Vega */
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0ac8,
- .idProduct = 0x0000,
+ .idProduct = 0x332d,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* ViMicro - Minoru3D */
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x3410,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
+ /* ViMicro Venus - Minoru3D */
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x3420,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
@@ -1862,7 +1884,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_DEF },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1925,7 +1948,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_PROBE_EXTRAFIELDS },
/* Ecamm Pico iMage */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 5e77cad29690..87cb9cc75af2 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -648,7 +648,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(input, 0, sizeof *input);
input->index = index;
strlcpy(input->name, iterm->name, sizeof input->name);
- if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+ if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
input->type = V4L2_INPUT_TYPE_CAMERA;
break;
}
@@ -663,9 +663,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
- ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
- video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
- &input, 1);
+ ret = uvc_query_ctrl(video->dev, UVC_GET_CUR,
+ video->selector->id, video->dev->intfnum,
+ UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
if (ret < 0)
return ret;
@@ -690,9 +690,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (input == 0 || input > video->selector->selector.bNrInPins)
return -EINVAL;
- return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
- video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
- &input, 1);
+ return uvc_query_ctrl(video->dev, UVC_SET_CUR,
+ video->selector->id, video->dev->intfnum,
+ UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
}
/* Try, Get, Set & Enum format */
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 01b633c73480..68468309932d 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -128,11 +128,14 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
if (data == NULL)
return -ENOMEM;
+ if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF)
+ return -EIO;
+
ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
- probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
- UVC_CTRL_STREAMING_TIMEOUT);
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, UVC_CTRL_STREAMING_TIMEOUT);
- if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+ if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
/* Some cameras, mostly based on Bison Electronics chipsets,
* answer a GET_MIN or GET_MAX request with the wCompQuality
* field only.
@@ -144,7 +147,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
ret = 0;
goto out;
- } else if (query == GET_DEF && probe == 1 && ret != size) {
+ } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
/* Many cameras don't support the GET_DEF request on their
* video probe control. Warn once and return, the caller will
* fall back to GET_CUR.
@@ -232,10 +235,10 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
data[33] = ctrl->bMaxVersion;
}
- ret = __uvc_query_ctrl(video->dev, SET_CUR, 0,
+ ret = __uvc_query_ctrl(video->dev, UVC_SET_CUR, 0,
video->streaming->intfnum,
- probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
- UVC_CTRL_STREAMING_TIMEOUT);
+ probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+ size, UVC_CTRL_STREAMING_TIMEOUT);
if (ret != size) {
uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
"%d (exp. %u).\n", probe ? "probe" : "commit",
@@ -269,10 +272,10 @@ int uvc_probe_video(struct uvc_video_device *video,
/* Get the minimum and maximum values for compression settings. */
if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
- ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+ ret = uvc_get_video_ctrl(video, &probe_min, 1, UVC_GET_MIN);
if (ret < 0)
goto done;
- ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+ ret = uvc_get_video_ctrl(video, &probe_max, 1, UVC_GET_MAX);
if (ret < 0)
goto done;
@@ -280,8 +283,11 @@ int uvc_probe_video(struct uvc_video_device *video,
}
for (i = 0; i < 2; ++i) {
- if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
- (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ ret = uvc_set_video_ctrl(video, probe, 1);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
goto done;
if (video->streaming->intf->num_altsetting == 1)
@@ -1065,7 +1071,7 @@ int uvc_video_init(struct uvc_video_device *video)
* requests on the probe control will just keep their current streaming
* parameters.
*/
- if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
+ if (uvc_get_video_ctrl(video, probe, 1, UVC_GET_DEF) == 0)
uvc_set_video_ctrl(video, probe, 1);
/* Initialize the streaming parameters with the probe control current
@@ -1073,7 +1079,8 @@ int uvc_video_init(struct uvc_video_device *video)
* control will always use values retrieved from a successful GET_CUR
* request on the probe control, as required by the UVC specification.
*/
- if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR);
+ if (ret < 0)
return ret;
/* Check if the default format descriptor exists. Use the first
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 3c78d3c1e4c0..fcccf9c9b7ba 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -67,155 +67,12 @@ struct uvc_xu_control {
#ifdef __KERNEL__
#include <linux/poll.h>
+#include <linux/usb/video.h>
/* --------------------------------------------------------------------------
* UVC constants
*/
-#define SC_UNDEFINED 0x00
-#define SC_VIDEOCONTROL 0x01
-#define SC_VIDEOSTREAMING 0x02
-#define SC_VIDEO_INTERFACE_COLLECTION 0x03
-
-#define PC_PROTOCOL_UNDEFINED 0x00
-
-#define CS_UNDEFINED 0x20
-#define CS_DEVICE 0x21
-#define CS_CONFIGURATION 0x22
-#define CS_STRING 0x23
-#define CS_INTERFACE 0x24
-#define CS_ENDPOINT 0x25
-
-/* VideoControl class specific interface descriptor */
-#define VC_DESCRIPTOR_UNDEFINED 0x00
-#define VC_HEADER 0x01
-#define VC_INPUT_TERMINAL 0x02
-#define VC_OUTPUT_TERMINAL 0x03
-#define VC_SELECTOR_UNIT 0x04
-#define VC_PROCESSING_UNIT 0x05
-#define VC_EXTENSION_UNIT 0x06
-
-/* VideoStreaming class specific interface descriptor */
-#define VS_UNDEFINED 0x00
-#define VS_INPUT_HEADER 0x01
-#define VS_OUTPUT_HEADER 0x02
-#define VS_STILL_IMAGE_FRAME 0x03
-#define VS_FORMAT_UNCOMPRESSED 0x04
-#define VS_FRAME_UNCOMPRESSED 0x05
-#define VS_FORMAT_MJPEG 0x06
-#define VS_FRAME_MJPEG 0x07
-#define VS_FORMAT_MPEG2TS 0x0a
-#define VS_FORMAT_DV 0x0c
-#define VS_COLORFORMAT 0x0d
-#define VS_FORMAT_FRAME_BASED 0x10
-#define VS_FRAME_FRAME_BASED 0x11
-#define VS_FORMAT_STREAM_BASED 0x12
-
-/* Endpoint type */
-#define EP_UNDEFINED 0x00
-#define EP_GENERAL 0x01
-#define EP_ENDPOINT 0x02
-#define EP_INTERRUPT 0x03
-
-/* Request codes */
-#define RC_UNDEFINED 0x00
-#define SET_CUR 0x01
-#define GET_CUR 0x81
-#define GET_MIN 0x82
-#define GET_MAX 0x83
-#define GET_RES 0x84
-#define GET_LEN 0x85
-#define GET_INFO 0x86
-#define GET_DEF 0x87
-
-/* VideoControl interface controls */
-#define VC_CONTROL_UNDEFINED 0x00
-#define VC_VIDEO_POWER_MODE_CONTROL 0x01
-#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
-
-/* Terminal controls */
-#define TE_CONTROL_UNDEFINED 0x00
-
-/* Selector Unit controls */
-#define SU_CONTROL_UNDEFINED 0x00
-#define SU_INPUT_SELECT_CONTROL 0x01
-
-/* Camera Terminal controls */
-#define CT_CONTROL_UNDEFINED 0x00
-#define CT_SCANNING_MODE_CONTROL 0x01
-#define CT_AE_MODE_CONTROL 0x02
-#define CT_AE_PRIORITY_CONTROL 0x03
-#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
-#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
-#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
-#define CT_FOCUS_RELATIVE_CONTROL 0x07
-#define CT_FOCUS_AUTO_CONTROL 0x08
-#define CT_IRIS_ABSOLUTE_CONTROL 0x09
-#define CT_IRIS_RELATIVE_CONTROL 0x0a
-#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
-#define CT_ZOOM_RELATIVE_CONTROL 0x0c
-#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
-#define CT_PANTILT_RELATIVE_CONTROL 0x0e
-#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
-#define CT_ROLL_RELATIVE_CONTROL 0x10
-#define CT_PRIVACY_CONTROL 0x11
-
-/* Processing Unit controls */
-#define PU_CONTROL_UNDEFINED 0x00
-#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
-#define PU_BRIGHTNESS_CONTROL 0x02
-#define PU_CONTRAST_CONTROL 0x03
-#define PU_GAIN_CONTROL 0x04
-#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
-#define PU_HUE_CONTROL 0x06
-#define PU_SATURATION_CONTROL 0x07
-#define PU_SHARPNESS_CONTROL 0x08
-#define PU_GAMMA_CONTROL 0x09
-#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
-#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
-#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
-#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
-#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
-#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
-#define PU_HUE_AUTO_CONTROL 0x10
-#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
-#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
-
-#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01
-#define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02
-#define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03
-
-/* VideoStreaming interface controls */
-#define VS_CONTROL_UNDEFINED 0x00
-#define VS_PROBE_CONTROL 0x01
-#define VS_COMMIT_CONTROL 0x02
-#define VS_STILL_PROBE_CONTROL 0x03
-#define VS_STILL_COMMIT_CONTROL 0x04
-#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
-#define VS_STREAM_ERROR_CODE_CONTROL 0x06
-#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
-#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
-#define VS_SYNC_DELAY_CONTROL 0x09
-
-#define TT_VENDOR_SPECIFIC 0x0100
-#define TT_STREAMING 0x0101
-
-/* Input Terminal types */
-#define ITT_VENDOR_SPECIFIC 0x0200
-#define ITT_CAMERA 0x0201
-#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
-
-/* Output Terminal types */
-#define OTT_VENDOR_SPECIFIC 0x0300
-#define OTT_DISPLAY 0x0301
-#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
-
-/* External Terminal types */
-#define EXTERNAL_VENDOR_SPECIFIC 0x0400
-#define COMPOSITE_CONNECTOR 0x0401
-#define SVIDEO_CONNECTOR 0x0402
-#define COMPONENT_CONNECTOR 0x0403
-
#define UVC_TERM_INPUT 0x0000
#define UVC_TERM_OUTPUT 0x8000
@@ -227,8 +84,6 @@ struct uvc_xu_control {
#define UVC_ENTITY_IS_OTERM(entity) \
(((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
-#define UVC_STATUS_TYPE_CONTROL 1
-#define UVC_STATUS_TYPE_STREAMING 2
/* ------------------------------------------------------------------------
* GUIDs
@@ -249,19 +104,6 @@ struct uvc_xu_control {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-#define UVC_GUID_LOGITECH_DEV_INFO \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
-#define UVC_GUID_LOGITECH_USER_HW \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
-#define UVC_GUID_LOGITECH_VIDEO \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
-#define UVC_GUID_LOGITECH_MOTOR \
- {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
- 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
-
#define UVC_GUID_FORMAT_MJPEG \
{ 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -314,6 +156,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
+#define UVC_QUIRK_PROBE_DEF 0x00000100
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index be64a502ea27..48840e95f943 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -42,6 +42,12 @@
printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
} while (0)
+#define dbgarg3(fmt, arg...) \
+ do { \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\
+ } while (0)
+
/* Zero out the end of the struct pointed to by p. Everthing after, but
* not including, the specified field is cleared. */
#define CLEAR_AFTER_FIELD(p, field) \
@@ -1717,24 +1723,29 @@ static long __video_do_ioctl(struct file *file,
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
- "index=%d, pixelformat=%d, type=%d ",
- p->index, p->pixel_format, p->type);
+ "index=%d, pixelformat=%c%c%c%c, type=%d ",
+ p->index,
+ (p->pixel_format & 0xff),
+ (p->pixel_format >> 8) & 0xff,
+ (p->pixel_format >> 16) & 0xff,
+ (p->pixel_format >> 24) & 0xff,
+ p->type);
switch (p->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
- dbgarg2("width = %d, height=%d\n",
+ dbgarg3("width = %d, height=%d\n",
p->discrete.width, p->discrete.height);
break;
case V4L2_FRMSIZE_TYPE_STEPWISE:
- dbgarg2("min %dx%d, max %dx%d, step %dx%d\n",
+ dbgarg3("min %dx%d, max %dx%d, step %dx%d\n",
p->stepwise.min_width, p->stepwise.min_height,
p->stepwise.step_width, p->stepwise.step_height,
p->stepwise.max_width, p->stepwise.max_height);
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
- dbgarg2("continuous\n");
+ dbgarg3("continuous\n");
break;
default:
- dbgarg2("- Unknown type!\n");
+ dbgarg3("- Unknown type!\n");
}
break;
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 97b082fe4473..f3b6e15d91f2 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -1776,7 +1776,6 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
static struct i2c_adapter vino_i2c_adapter = {
.name = "VINO I2C bus",
- .id = I2C_HW_SGI_VINO,
.algo = &sgi_algo,
.algo_data = &i2c_sgi_vino_data,
.owner = THIS_MODULE,
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 6c3f23e31b5c..602484dd3da9 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -1497,7 +1497,6 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
};
static struct i2c_adapter adap = {
- .id = I2C_HW_SMBUS_W9968CF,
.owner = THIS_MODULE,
.algo = &algo,
};
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 03dc2f3cf84a..40d07faa4a24 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -732,7 +732,6 @@ zoran_register_i2c (struct zoran *zr)
memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
sizeof(struct i2c_algo_bit_data));
zr->i2c_algo.data = zr;
- zr->i2c_adapter.id = I2C_HW_B_ZR36067;
strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
sizeof(zr->i2c_adapter.name));
i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index fc976f42f432..645daf29614f 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -27,6 +29,7 @@
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
@@ -35,24 +38,40 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
-#define MAX_FRAME_SIZE 100000
+#define FRAMES 1
+#define MAX_FRAME_SIZE 200000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
+
+/*#define FULL_DEBUG 1*/
+#ifdef FULL_DEBUG
+#define _DBG DBG
+#else
+#define _DBG(fmt, args...)
+#endif
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
@@ -101,24 +120,93 @@ static struct usb_device_id device_table[] = {
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
+ ZR364XX_READ_FRAME */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 state;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt *fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -272,139 +360,116 @@ static unsigned char header2[] = {
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
-/********************/
-/* V4L2 integration */
-/********************/
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
+ return 0;
+}
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
+{
+ _DBG("%s\n", __func__);
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
+ if (in_interrupt())
+ BUG();
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
+ 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 zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+ cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
}
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
}
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+ 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 zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ _DBG("%s\n", __func__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
- return size;
+ _DBG("%s\n", __func__);
+ free_buffer(vq, buf);
}
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
- DBG("zr364xx_read: read %d bytes.", (int) count);
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ _DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -412,21 +477,276 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+ (int) *ppos);
+
+ /* NoMan Sux ! */
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
+
+ return 0;
+}
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+ struct zr364xx_buffer *buf,
+ int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ _DBG("buffer to user\n");
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16 *)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ _DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ _DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ } else {
+ if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
+ dev_info(&cam->udev->dev,
+ "%s: buffer (%d bytes) too small to hold "
+ "frame data. Discarding frame data.\n",
+ __func__, MAX_FRAME_SIZE);
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ }
+ /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ _DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
+
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ } else if (cam->b_acquire) {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ _DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
+}
- return count;
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
}
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ _DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ sizeof(cap->bus_info));
+ cap->version = ZR364XX_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
return 0;
}
@@ -458,12 +778,11 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv,
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -472,7 +791,7 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -484,36 +803,42 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -527,47 +852,63 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
if (f->index > 0)
return -EINVAL;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
- if (vdev == NULL)
+ if (cam == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
return -EINVAL;
+ }
+
+ if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
+ !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ }
+
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
return 0;
}
static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -581,38 +922,327 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+ int i;
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ if (ret < 0)
+ return ret;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (res_check(cam)) {
+ DBG("%s can't change format after started\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
+ dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+ cam->width, cam->height);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
- DBG("ok!");
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+
+ if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
+ mode = 1;
+ else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
+ mode = 2;
+ else
+ mode = 0;
+
+ m0d1[0] = mode;
+ m1[2].value = 0xf000 + mode;
+ m2[1].value = 0xf000 + mode;
+ header2[437] = cam->height / 256;
+ header2[438] = cam->height % 256;
+ header2[439] = cam->width / 256;
+ header2[440] = cam->width % 256;
+
+ for (i = 0; init[cam->method][i].size != -1; i++) {
+ ret =
+ send_control_msg(cam->udev, 1, init[cam->method][i].value,
+ 0, init[cam->method][i].bytes,
+ init[cam->method][i].size);
+ if (ret < 0) {
+ dev_err(&cam->udev->dev,
+ "error during resolution change sequence: %d\n", i);
+ goto out;
+ }
+ }
+
+ /* Added some delay here, since opening/closing the camera quickly,
+ * like Ekiga does during its startup, can crash the webcam
+ */
+ mdelay(100);
+ cam->skip = 2;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ _DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ _DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int pipe;
+
+ pipe_info = purb->context;
+ _DBG("%s %p, status %d\n", __func__, purb, purb->status);
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ /* if shutting down, do not resubmit, exit immediately */
+ if (purb->status == -ESHUTDOWN) {
+ DBG("%s, err shutdown\n", __func__);
+ pipe_info->err_count++;
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 ||
+ purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ if (purb->status == 0)
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+ else {
+ pipe_info->err_count++;
+ DBG("%s: failed URB %d\n", __func__, purb->status);
+ }
+
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ purb->status = usb_submit_urb(pipe_info->stream_urb,
+ GFP_ATOMIC);
+
+ if (purb->status)
+ dev_err(&cam->udev->dev,
+ "error submitting urb (error=%i)\n",
+ purb->status);
+ } else
+ DBG("read pipe complete state 0\n");
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->err_count = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0)
+ pipe_info->state = 0;
+
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ cam->b_acquire = 1;
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ } else {
+ res_free(cam);
+ }
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -621,28 +1251,19 @@ static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -658,6 +1279,14 @@ static int zr364xx_open(struct file *file)
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -666,28 +1295,70 @@ static int zr364xx_open(struct file *file)
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+ cam = NULL;
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -710,40 +1381,43 @@ static int zr364xx_release(struct file *file)
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_mmap: %ld\n", size);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- if (vdev == NULL)
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
- cam = video_get_drvdata(vdev);
-
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
}
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- return 0;
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ _DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -752,6 +1426,7 @@ static const struct v4l2_file_operations zr364xx_fops = {
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -768,6 +1443,10 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -783,15 +1462,76 @@ static struct video_device zr364xx_template = {
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+ "Using less frames\n");
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+ return -ENOMEM;
+ } else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -810,22 +1550,17 @@ static int zr364xx_probe(struct usb_interface *intf,
if (cam->vdev == NULL) {
dev_err(&udev->dev, "cam->vdev: out of memory !\n");
kfree(cam);
+ cam = NULL;
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -852,21 +1587,53 @@ static int zr364xx_probe(struct usb_interface *intf,
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
+ cam = NULL;
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ err = zr364xx_board_init(cam);
+ if (err) {
+ spin_lock_init(&cam->slock);
+ return err;
+ }
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -876,17 +1643,10 @@ static int zr364xx_probe(struct usb_interface *intf,
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
- if (cam->vdev)
- video_unregister_device(cam->vdev);
- cam->vdev = NULL;
- kfree(cam->buffer);
- cam->buffer = NULL;
- vfree(cam->framebuf);
- cam->framebuf = NULL;
- kfree(cam);
- cam = NULL;
+ zr364xx_destroy(cam);
}
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5d0ba4f5924c..aa60e8a15da3 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6852,7 +6852,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
*size = y;
}
/**
- * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
+ * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
* @ioc: Pointer to MPT_ADAPTER structure
*
* Returns 0 for SUCCESS or -1 if FAILED.
@@ -6885,7 +6885,7 @@ mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
/**
- * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
+ * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
* @ioc: Pointer to MPT_ADAPTER structure
*
**/
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index a9e48e28b1dc..bc2ec2182c00 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
IOC_AND_NETDEV_NAMES_s_s(dev),
le32_to_cpu(pSimple->FlagsLength)));
- return 0;
+ return NETDEV_TX_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 13e7d7bfe85f..8ff10cb77cac 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -465,14 +465,14 @@ static int ab3100_get_set_reg_open_file(struct inode *inode, struct file *file)
return 0;
}
-static int ab3100_get_set_reg(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+static ssize_t ab3100_get_set_reg(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct ab3100_get_set_reg_priv *priv = file->private_data;
struct ab3100 *ab3100 = priv->ab3100;
char buf[32];
- int buf_size;
+ ssize_t buf_size;
int regp;
unsigned long user_reg;
int err;
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index c1de4afa89a6..86d394894d81 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -17,6 +17,7 @@
#include <linux/irq.h>
#include <linux/mfd/ezx-pcap.h>
#include <linux/spi/spi.h>
+#include <linux/gpio.h>
#define PCAP_ADC_MAXQ 8
struct pcap_adc_request {
@@ -106,11 +107,35 @@ int ezx_pcap_read(struct pcap_chip *pcap, u8 reg_num, u32 *value)
}
EXPORT_SYMBOL_GPL(ezx_pcap_read);
+int ezx_pcap_set_bits(struct pcap_chip *pcap, u8 reg_num, u32 mask, u32 val)
+{
+ int ret;
+ u32 tmp = PCAP_REGISTER_READ_OP_BIT |
+ (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
+
+ mutex_lock(&pcap->io_mutex);
+ ret = ezx_pcap_putget(pcap, &tmp);
+ if (ret)
+ goto out_unlock;
+
+ tmp &= (PCAP_REGISTER_VALUE_MASK & ~mask);
+ tmp |= (val & mask) | PCAP_REGISTER_WRITE_OP_BIT |
+ (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
+
+ ret = ezx_pcap_putget(pcap, &tmp);
+out_unlock:
+ mutex_unlock(&pcap->io_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ezx_pcap_set_bits);
+
/* IRQ */
-static inline unsigned int irq2pcap(struct pcap_chip *pcap, int irq)
+int irq_to_pcap(struct pcap_chip *pcap, int irq)
{
- return 1 << (irq - pcap->irq_base);
+ return irq - pcap->irq_base;
}
+EXPORT_SYMBOL_GPL(irq_to_pcap);
int pcap_to_irq(struct pcap_chip *pcap, int irq)
{
@@ -122,7 +147,7 @@ static void pcap_mask_irq(unsigned int irq)
{
struct pcap_chip *pcap = get_irq_chip_data(irq);
- pcap->msr |= irq2pcap(pcap, irq);
+ pcap->msr |= 1 << irq_to_pcap(pcap, irq);
queue_work(pcap->workqueue, &pcap->msr_work);
}
@@ -130,7 +155,7 @@ static void pcap_unmask_irq(unsigned int irq)
{
struct pcap_chip *pcap = get_irq_chip_data(irq);
- pcap->msr &= ~irq2pcap(pcap, irq);
+ pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
queue_work(pcap->workqueue, &pcap->msr_work);
}
@@ -154,34 +179,38 @@ static void pcap_isr_work(struct work_struct *work)
u32 msr, isr, int_sel, service;
int irq;
- ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
- ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);
+ do {
+ ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
+ ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);
- /* We cant service/ack irqs that are assigned to port 2 */
- if (!(pdata->config & PCAP_SECOND_PORT)) {
- ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
- isr &= ~int_sel;
- }
- ezx_pcap_write(pcap, PCAP_REG_ISR, isr);
+ /* We cant service/ack irqs that are assigned to port 2 */
+ if (!(pdata->config & PCAP_SECOND_PORT)) {
+ ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
+ isr &= ~int_sel;
+ }
- local_irq_disable();
- service = isr & ~msr;
+ ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr);
+ ezx_pcap_write(pcap, PCAP_REG_ISR, isr);
- for (irq = pcap->irq_base; service; service >>= 1, irq++) {
- if (service & 1) {
- struct irq_desc *desc = irq_to_desc(irq);
+ local_irq_disable();
+ service = isr & ~msr;
+ for (irq = pcap->irq_base; service; service >>= 1, irq++) {
+ if (service & 1) {
+ struct irq_desc *desc = irq_to_desc(irq);
- if (WARN(!desc, KERN_WARNING
- "Invalid PCAP IRQ %d\n", irq))
- break;
+ if (WARN(!desc, KERN_WARNING
+ "Invalid PCAP IRQ %d\n", irq))
+ break;
- if (desc->status & IRQ_DISABLED)
- note_interrupt(irq, desc, IRQ_NONE);
- else
- desc->handle_irq(irq, desc);
+ if (desc->status & IRQ_DISABLED)
+ note_interrupt(irq, desc, IRQ_NONE);
+ else
+ desc->handle_irq(irq, desc);
+ }
}
- }
- local_irq_enable();
+ local_irq_enable();
+ ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
+ } while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
}
static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -194,6 +223,19 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
}
/* ADC */
+void pcap_set_ts_bits(struct pcap_chip *pcap, u32 bits)
+{
+ u32 tmp;
+
+ mutex_lock(&pcap->adc_mutex);
+ ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp);
+ tmp &= ~(PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR);
+ tmp |= bits & (PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR);
+ ezx_pcap_write(pcap, PCAP_REG_ADC, tmp);
+ mutex_unlock(&pcap->adc_mutex);
+}
+EXPORT_SYMBOL_GPL(pcap_set_ts_bits);
+
static void pcap_disable_adc(struct pcap_chip *pcap)
{
u32 tmp;
@@ -216,15 +258,16 @@ static void pcap_adc_trigger(struct pcap_chip *pcap)
mutex_unlock(&pcap->adc_mutex);
return;
}
- mutex_unlock(&pcap->adc_mutex);
-
- /* start conversion on requested bank */
- tmp = pcap->adc_queue[head]->flags | PCAP_ADC_ADEN;
+ /* start conversion on requested bank, save TS_M bits */
+ ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp);
+ tmp &= (PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR);
+ tmp |= pcap->adc_queue[head]->flags | PCAP_ADC_ADEN;
if (pcap->adc_queue[head]->bank == PCAP_ADC_BANK_1)
tmp |= PCAP_ADC_AD_SEL1;
ezx_pcap_write(pcap, PCAP_REG_ADC, tmp);
+ mutex_unlock(&pcap->adc_mutex);
ezx_pcap_write(pcap, PCAP_REG_ADR, PCAP_ADR_ASC);
}
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index bae61b22501c..e57f778f405a 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -441,7 +441,7 @@ static void twl4030_sih_do_edge(struct work_struct *work)
/* see what work we have */
spin_lock_irq(&sih_agent_lock);
edge_change = agent->edge_change;
- agent->edge_change = 0;;
+ agent->edge_change = 0;
sih = edge_change ? agent->sih : NULL;
spin_unlock_irq(&sih_agent_lock);
if (!sih)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 68ab39d7cb35..040765f73a82 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -76,6 +76,35 @@ config IBM_ASM
information on the specific driver level and support statement
for your IBM server.
+config HWLAT_DETECTOR
+ tristate "Testing module to detect hardware-induced latencies"
+ depends on DEBUG_FS
+ depends on RING_BUFFER
+ default m
+ ---help---
+ A simple hardware latency detector. Use this module to detect
+ large latencies introduced by the behavior of the underlying
+ system firmware external to Linux. We do this using periodic
+ use of stop_machine to grab all available CPUs and measure
+ for unexplainable gaps in the CPU timestamp counter(s). By
+ default, the module is not enabled until the "enable" file
+ within the "hwlat_detector" debugfs directory is toggled.
+
+ This module is often used to detect SMI (System Management
+ Interrupts) on x86 systems, though is not x86 specific. To
+ this end, we default to using a sample window of 1 second,
+ during which we will sample for 0.5 seconds. If an SMI or
+ similar event occurs during that time, it is recorded
+ into an 8K samples global ring buffer until retreived.
+
+ WARNING: This software should never be enabled (it can be built
+ but should not be turned on after it is loaded) in a production
+ environment where high latencies are a concern since the
+ sampling mechanism actually introduces latencies for
+ regular tasks while the CPU(s) are being held.
+
+ If unsure, say N
+
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCI
@@ -233,6 +262,19 @@ config ISL29003
This driver can also be built as a module. If so, the module
will be called isl29003.
+config EP93XX_PWM
+ tristate "EP93xx PWM support"
+ depends on ARCH_EP93XX
+ help
+ This option enables device driver support for the PWM channels
+ on the Cirrus EP93xx processors. The EP9307 chip only has one
+ PWM channel all the others have two, the second channel is an
+ alternate function of the EGPIO14 pin. A sysfs interface is
+ provided to control the PWM channels.
+
+ To compile this driver as a module, choose M here: the module will
+ be called ep93xx_pwm.
+
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 36f733cd60e6..37449c021471 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -19,6 +19,8 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/
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_C2PORT) += c2port/
+obj-$(CONFIG_HWLAT_DETECTOR) += hwlat_detector.o
obj-y += eeprom/
obj-y += cb710/
diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c
index d38a7acdb6ec..d019746551f3 100644
--- a/drivers/misc/cb710/sgbuf2.c
+++ b/drivers/misc/cb710/sgbuf2.c
@@ -114,7 +114,6 @@ static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
if (!left)
return;
addr += len;
- flush_kernel_dcache_page(miter->page);
} while (sg_dwiter_next(miter));
}
@@ -142,9 +141,6 @@ void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t da
return;
} else
sg_dwiter_write_slow(miter, data);
-
- if (miter->length == miter->consumed)
- flush_kernel_dcache_page(miter->page);
}
EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block);
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index b34cb5f79eea..2e535a0ccd5e 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -173,6 +173,7 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
unsigned segment;
unsigned offset = (unsigned) off;
u8 *cp = bounce + 1;
+ int sr;
*cp = AT25_WREN;
status = spi_write(at25->spi, cp, 1);
@@ -214,7 +215,6 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT);
retries = 0;
do {
- int sr;
sr = spi_w8r8(at25->spi, AT25_RDSR);
if (sr < 0 || (sr & AT25_SR_nRDY)) {
@@ -228,7 +228,7 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
break;
} while (retries++ < 3 || time_before_eq(jiffies, timeout));
- if (time_after(jiffies, timeout)) {
+ if ((sr < 0) || (sr & AT25_SR_nRDY)) {
dev_err(&at25->spi->dev,
"write %d bytes offset %d, "
"timeout after %u msecs\n",
diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c
new file mode 100644
index 000000000000..ba4694169d79
--- /dev/null
+++ b/drivers/misc/ep93xx_pwm.c
@@ -0,0 +1,384 @@
+/*
+ * Simple PWM driver for EP93XX
+ *
+ * (c) Copyright 2009 Matthieu Crapet <mcrapet@gmail.com>
+ * (c) Copyright 2009 H Hartley Sweeten <hsweeten@visionengravers.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.
+ *
+ * EP9307 has only one channel:
+ * - PWMOUT
+ *
+ * EP9301/02/12/15 have two channels:
+ * - PWMOUT
+ * - PWMOUT1 (alternate function for EGPIO14)
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/platform.h>
+
+#define EP93XX_PWMx_TERM_COUNT 0x00
+#define EP93XX_PWMx_DUTY_CYCLE 0x04
+#define EP93XX_PWMx_ENABLE 0x08
+#define EP93XX_PWMx_INVERT 0x0C
+
+#define EP93XX_PWM_MAX_COUNT 0xFFFF
+
+struct ep93xx_pwm {
+ void __iomem *mmio_base;
+ struct clk *clk;
+ u32 duty_percent;
+};
+
+static inline void ep93xx_pwm_writel(struct ep93xx_pwm *pwm,
+ unsigned int val, unsigned int off)
+{
+ __raw_writel(val, pwm->mmio_base + off);
+}
+
+static inline unsigned int ep93xx_pwm_readl(struct ep93xx_pwm *pwm,
+ unsigned int off)
+{
+ return __raw_readl(pwm->mmio_base + off);
+}
+
+static inline void ep93xx_pwm_write_tc(struct ep93xx_pwm *pwm, u16 value)
+{
+ ep93xx_pwm_writel(pwm, value, EP93XX_PWMx_TERM_COUNT);
+}
+
+static inline u16 ep93xx_pwm_read_tc(struct ep93xx_pwm *pwm)
+{
+ return ep93xx_pwm_readl(pwm, EP93XX_PWMx_TERM_COUNT);
+}
+
+static inline void ep93xx_pwm_write_dc(struct ep93xx_pwm *pwm, u16 value)
+{
+ ep93xx_pwm_writel(pwm, value, EP93XX_PWMx_DUTY_CYCLE);
+}
+
+static inline void ep93xx_pwm_enable(struct ep93xx_pwm *pwm)
+{
+ ep93xx_pwm_writel(pwm, 0x1, EP93XX_PWMx_ENABLE);
+}
+
+static inline void ep93xx_pwm_disable(struct ep93xx_pwm *pwm)
+{
+ ep93xx_pwm_writel(pwm, 0x0, EP93XX_PWMx_ENABLE);
+}
+
+static inline int ep93xx_pwm_is_enabled(struct ep93xx_pwm *pwm)
+{
+ return ep93xx_pwm_readl(pwm, EP93XX_PWMx_ENABLE) & 0x1;
+}
+
+static inline void ep93xx_pwm_invert(struct ep93xx_pwm *pwm)
+{
+ ep93xx_pwm_writel(pwm, 0x1, EP93XX_PWMx_INVERT);
+}
+
+static inline void ep93xx_pwm_normal(struct ep93xx_pwm *pwm)
+{
+ ep93xx_pwm_writel(pwm, 0x0, EP93XX_PWMx_INVERT);
+}
+
+static inline int ep93xx_pwm_is_inverted(struct ep93xx_pwm *pwm)
+{
+ return ep93xx_pwm_readl(pwm, EP93XX_PWMx_INVERT) & 0x1;
+}
+
+/*
+ * /sys/devices/platform/ep93xx-pwm.N
+ * /min_freq read-only minimum pwm output frequency
+ * /max_req read-only maximum pwm output frequency
+ * /freq read-write pwm output frequency (0 = disable output)
+ * /duty_percent read-write pwm duty cycle percent (1..99)
+ * /invert read-write invert pwm output
+ */
+
+static ssize_t ep93xx_pwm_get_min_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ unsigned long rate = clk_get_rate(pwm->clk);
+
+ return sprintf(buf, "%ld\n", rate / (EP93XX_PWM_MAX_COUNT + 1));
+}
+
+static ssize_t ep93xx_pwm_get_max_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ unsigned long rate = clk_get_rate(pwm->clk);
+
+ return sprintf(buf, "%ld\n", rate / 2);
+}
+
+static ssize_t ep93xx_pwm_get_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+
+ if (ep93xx_pwm_is_enabled(pwm)) {
+ unsigned long rate = clk_get_rate(pwm->clk);
+ u16 term = ep93xx_pwm_read_tc(pwm);
+
+ return sprintf(buf, "%ld\n", rate / (term + 1));
+ } else {
+ return sprintf(buf, "disabled\n");
+ }
+}
+
+static ssize_t ep93xx_pwm_set_freq(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ long val;
+ int err;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return -EINVAL;
+
+ if (val == 0) {
+ ep93xx_pwm_disable(pwm);
+ } else if (val <= (clk_get_rate(pwm->clk) / 2)) {
+ u32 term, duty;
+
+ val = (clk_get_rate(pwm->clk) / val) - 1;
+ if (val > EP93XX_PWM_MAX_COUNT)
+ val = EP93XX_PWM_MAX_COUNT;
+ if (val < 1)
+ val = 1;
+
+ term = ep93xx_pwm_read_tc(pwm);
+ duty = ((val + 1) * pwm->duty_percent / 100) - 1;
+
+ /* If pwm is running, order is important */
+ if (val > term) {
+ ep93xx_pwm_write_tc(pwm, val);
+ ep93xx_pwm_write_dc(pwm, duty);
+ } else {
+ ep93xx_pwm_write_dc(pwm, duty);
+ ep93xx_pwm_write_tc(pwm, val);
+ }
+
+ if (!ep93xx_pwm_is_enabled(pwm))
+ ep93xx_pwm_enable(pwm);
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t ep93xx_pwm_get_duty_percent(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+
+ return sprintf(buf, "%d\n", pwm->duty_percent);
+}
+
+static ssize_t ep93xx_pwm_set_duty_percent(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ long val;
+ int err;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return -EINVAL;
+
+ if (val > 0 && val < 100) {
+ u32 term = ep93xx_pwm_read_tc(pwm);
+ ep93xx_pwm_write_dc(pwm, ((term + 1) * val / 100) - 1);
+ pwm->duty_percent = val;
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t ep93xx_pwm_get_invert(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+
+ return sprintf(buf, "%d\n", ep93xx_pwm_is_inverted(pwm));
+}
+
+static ssize_t ep93xx_pwm_set_invert(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ long val;
+ int err;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return -EINVAL;
+
+ if (val == 0)
+ ep93xx_pwm_normal(pwm);
+ else if (val == 1)
+ ep93xx_pwm_invert(pwm);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL);
+static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL);
+static DEVICE_ATTR(freq, S_IWUGO | S_IRUGO,
+ ep93xx_pwm_get_freq, ep93xx_pwm_set_freq);
+static DEVICE_ATTR(duty_percent, S_IWUGO | S_IRUGO,
+ ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent);
+static DEVICE_ATTR(invert, S_IWUGO | S_IRUGO,
+ ep93xx_pwm_get_invert, ep93xx_pwm_set_invert);
+
+static struct attribute *ep93xx_pwm_attrs[] = {
+ &dev_attr_min_freq.attr,
+ &dev_attr_max_freq.attr,
+ &dev_attr_freq.attr,
+ &dev_attr_duty_percent.attr,
+ &dev_attr_invert.attr,
+ NULL
+};
+
+static const struct attribute_group ep93xx_pwm_sysfs_files = {
+ .attrs = ep93xx_pwm_attrs,
+};
+
+static int __init ep93xx_pwm_probe(struct platform_device *pdev)
+{
+ struct ep93xx_pwm *pwm;
+ struct resource *res;
+ int err;
+
+ err = ep93xx_pwm_acquire_gpio(pdev);
+ if (err)
+ return err;
+
+ pwm = kzalloc(sizeof(struct ep93xx_pwm), GFP_KERNEL);
+ if (!pwm) {
+ err = -ENOMEM;
+ goto fail_no_mem;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ err = -ENXIO;
+ goto fail_no_mem_resource;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ err = -EBUSY;
+ goto fail_no_mem_resource;
+ }
+
+ pwm->mmio_base = ioremap(res->start, resource_size(res));
+ if (pwm->mmio_base == NULL) {
+ err = -ENXIO;
+ goto fail_no_ioremap;
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files);
+ if (err)
+ goto fail_no_sysfs;
+
+ pwm->clk = clk_get(&pdev->dev, "pwm_clk");
+ if (IS_ERR(pwm->clk)) {
+ err = PTR_ERR(pwm->clk);
+ goto fail_no_clk;
+ }
+
+ pwm->duty_percent = 50;
+
+ platform_set_drvdata(pdev, pwm);
+
+ /* disable pwm at startup. Avoids zero value. */
+ ep93xx_pwm_disable(pwm);
+ ep93xx_pwm_write_tc(pwm, EP93XX_PWM_MAX_COUNT);
+ ep93xx_pwm_write_dc(pwm, EP93XX_PWM_MAX_COUNT / 2);
+
+ clk_enable(pwm->clk);
+
+ return 0;
+
+fail_no_clk:
+ sysfs_remove_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files);
+fail_no_sysfs:
+ iounmap(pwm->mmio_base);
+fail_no_ioremap:
+ release_mem_region(res->start, resource_size(res));
+fail_no_mem_resource:
+ kfree(pwm);
+fail_no_mem:
+ ep93xx_pwm_release_gpio(pdev);
+ return err;
+}
+
+static int __exit ep93xx_pwm_remove(struct platform_device *pdev)
+{
+ struct ep93xx_pwm *pwm = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ep93xx_pwm_disable(pwm);
+ clk_disable(pwm->clk);
+ clk_put(pwm->clk);
+ platform_set_drvdata(pdev, NULL);
+ sysfs_remove_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files);
+ iounmap(pwm->mmio_base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(pwm);
+ ep93xx_pwm_release_gpio(pdev);
+
+ return 0;
+}
+
+static struct platform_driver ep93xx_pwm_driver = {
+ .driver = {
+ .name = "ep93xx-pwm",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(ep93xx_pwm_remove),
+};
+
+static int __init ep93xx_pwm_init(void)
+{
+ return platform_driver_probe(&ep93xx_pwm_driver, ep93xx_pwm_probe);
+}
+
+static void __exit ep93xx_pwm_exit(void)
+{
+ platform_driver_unregister(&ep93xx_pwm_driver);
+}
+
+module_init(ep93xx_pwm_init);
+module_exit(ep93xx_pwm_exit);
+
+MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, "
+ "H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("EP93xx PWM driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-pwm");
diff --git a/drivers/misc/hwlat_detector.c b/drivers/misc/hwlat_detector.c
new file mode 100644
index 000000000000..e02d8e17b484
--- /dev/null
+++ b/drivers/misc/hwlat_detector.c
@@ -0,0 +1,1208 @@
+/*
+ * hwlat_detector.c - A simple Hardware Latency detector.
+ *
+ * Use this module to detect large system latencies induced by the behavior of
+ * certain underlying system hardware or firmware, independent of Linux itself.
+ * The code was developed originally to detect the presence of SMIs on Intel
+ * and AMD systems, although there is no dependency upon x86 herein.
+ *
+ * The classical example usage of this module is in detecting the presence of
+ * SMIs or System Management Interrupts on Intel and AMD systems. An SMI is a
+ * somewhat special form of hardware interrupt spawned from earlier CPU debug
+ * modes in which the (BIOS/EFI/etc.) firmware arranges for the South Bridge
+ * LPC (or other device) to generate a special interrupt under certain
+ * circumstances, for example, upon expiration of a special SMI timer device,
+ * due to certain external thermal readings, on certain I/O address accesses,
+ * and other situations. An SMI hits a special CPU pin, triggers a special
+ * SMI mode (complete with special memory map), and the OS is unaware.
+ *
+ * Although certain hardware-inducing latencies are necessary (for example,
+ * a modern system often requires an SMI handler for correct thermal control
+ * and remote management) they can wreak havoc upon any OS-level performance
+ * guarantees toward low-latency, especially when the OS is not even made
+ * aware of the presence of these interrupts. For this reason, we need a
+ * somewhat brute force mechanism to detect these interrupts. In this case,
+ * we do it by hogging all of the CPU(s) for configurable timer intervals,
+ * sampling the built-in CPU timer, looking for discontiguous readings.
+ *
+ * WARNING: This implementation necessarily introduces latencies. Therefore,
+ * you should NEVER use this module in a production environment
+ * requiring any kind of low-latency performance guarantee(s).
+ *
+ * Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <jcm@redhat.com>
+ *
+ * Includes useful feedback from Clark Williams <clark@redhat.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ring_buffer.h>
+#include <linux/stop_machine.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+
+#define BUF_SIZE_DEFAULT 262144UL /* 8K*(sizeof(entry)) */
+#define BUF_FLAGS (RB_FL_OVERWRITE) /* no block on full */
+#define U64STR_SIZE 22 /* 20 digits max */
+
+#define VERSION "1.0.0"
+#define BANNER "hwlat_detector: "
+#define DRVNAME "hwlat_detector"
+#define DEFAULT_SAMPLE_WINDOW 1000000 /* 1s */
+#define DEFAULT_SAMPLE_WIDTH 500000 /* 0.5s */
+#define DEFAULT_LAT_THRESHOLD 10 /* 10us */
+
+/* Module metadata */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jon Masters <jcm@redhat.com>");
+MODULE_DESCRIPTION("A simple hardware latency detector");
+MODULE_VERSION(VERSION);
+
+/* Module parameters */
+
+static int debug;
+static int enabled;
+static int threshold;
+
+module_param(debug, int, 0); /* enable debug */
+module_param(enabled, int, 0); /* enable detector */
+module_param(threshold, int, 0); /* latency threshold */
+
+/* Buffering and sampling */
+
+static struct ring_buffer *ring_buffer; /* sample buffer */
+static DEFINE_MUTEX(ring_buffer_mutex); /* lock changes */
+static unsigned long buf_size = BUF_SIZE_DEFAULT;
+static struct task_struct *kthread; /* sampling thread */
+
+/* DebugFS filesystem entries */
+
+static struct dentry *debug_dir; /* debugfs directory */
+static struct dentry *debug_max; /* maximum TSC delta */
+static struct dentry *debug_count; /* total detect count */
+static struct dentry *debug_sample_width; /* sample width us */
+static struct dentry *debug_sample_window; /* sample window us */
+static struct dentry *debug_sample; /* raw samples us */
+static struct dentry *debug_threshold; /* threshold us */
+static struct dentry *debug_enable; /* enable/disable */
+
+/* Individual samples and global state */
+
+struct sample; /* latency sample */
+struct data; /* Global state */
+
+/* Sampling functions */
+static int __buffer_add_sample(struct sample *sample);
+static struct sample *buffer_get_sample(struct sample *sample);
+static int get_sample(void *unused);
+
+/* Threading and state */
+static int kthread_fn(void *unused);
+static int start_kthread(void);
+static int stop_kthread(void);
+static void __reset_stats(void);
+static int init_stats(void);
+
+/* Debugfs interface */
+static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos, const u64 *entry);
+static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos, u64 *entry);
+static int debug_sample_fopen(struct inode *inode, struct file *filp);
+static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos);
+static int debug_sample_release(struct inode *inode, struct file *filp);
+static int debug_enable_fopen(struct inode *inode, struct file *filp);
+static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos);
+static ssize_t debug_enable_fwrite(struct file *file,
+ const char __user *user_buffer,
+ size_t user_size, loff_t *offset);
+
+/* Initialization functions */
+static int init_debugfs(void);
+static void free_debugfs(void);
+static int detector_init(void);
+static void detector_exit(void);
+
+/* Individual latency samples are stored here when detected and packed into
+ * the ring_buffer circular buffer, where they are overwritten when
+ * more than buf_size/sizeof(sample) samples are received. */
+struct sample {
+ u64 seqnum; /* unique sequence */
+ u64 duration; /* ktime delta */
+ struct timespec timestamp; /* wall time */
+};
+
+/* keep the global state somewhere. Mostly used under stop_machine. */
+static struct data {
+
+ struct mutex lock; /* protect changes */
+
+ u64 count; /* total since reset */
+ u64 max_sample; /* max hardware latency */
+ u64 threshold; /* sample threshold level */
+
+ u64 sample_window; /* total sampling window (on+off) */
+ u64 sample_width; /* active sampling portion of window */
+
+ atomic_t sample_open; /* whether the sample file is open */
+
+ wait_queue_head_t wq; /* waitqeue for new sample values */
+
+} data;
+
+/**
+ * __buffer_add_sample - add a new latency sample recording to the ring buffer
+ * @sample: The new latency sample value
+ *
+ * This receives a new latency sample and records it in a global ring buffer.
+ * No additional locking is used in this case - suited for stop_machine use.
+ */
+static int __buffer_add_sample(struct sample *sample)
+{
+ return ring_buffer_write(ring_buffer,
+ sizeof(struct sample), sample);
+}
+
+/**
+ * buffer_get_sample - remove a hardware latency sample from the ring buffer
+ * @sample: Pre-allocated storage for the sample
+ *
+ * This retrieves a hardware latency sample from the global circular buffer
+ */
+static struct sample *buffer_get_sample(struct sample *sample)
+{
+ struct ring_buffer_event *e = NULL;
+ struct sample *s = NULL;
+ unsigned int cpu = 0;
+
+ if (!sample)
+ return NULL;
+
+ /* ring_buffers are per-cpu but we just want any value */
+ /* so we'll start with this cpu and try others if not */
+ /* Steven is planning to add a generic mechanism */
+ mutex_lock(&ring_buffer_mutex);
+ e = ring_buffer_consume(ring_buffer, smp_processor_id(), NULL);
+ if (!e) {
+ for_each_online_cpu(cpu) {
+ e = ring_buffer_consume(ring_buffer, cpu, NULL);
+ if (e)
+ break;
+ }
+ }
+
+ if (e) {
+ s = ring_buffer_event_data(e);
+ memcpy(sample, s, sizeof(struct sample));
+ } else
+ sample = NULL;
+ mutex_unlock(&ring_buffer_mutex);
+
+ return sample;
+}
+
+/**
+ * get_sample - sample the CPU TSC and look for likely hardware latencies
+ * @unused: This is not used but is a part of the stop_machine API
+ *
+ * Used to repeatedly capture the CPU TSC (or similar), looking for potential
+ * hardware-induced latency. Called under stop_machine, with data.lock held.
+ */
+static int get_sample(void *unused)
+{
+ ktime_t start, t1, t2;
+ s64 diff, total = 0;
+ u64 sample = 0;
+ int ret = 1;
+
+ start = ktime_get(); /* start timestamp */
+
+ do {
+
+ t1 = ktime_get(); /* we'll look for a discontinuity */
+ t2 = ktime_get();
+
+ total = ktime_to_us(ktime_sub(t2, start)); /* sample width */
+ diff = ktime_to_us(ktime_sub(t2, t1)); /* current diff */
+
+ /* This shouldn't happen */
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff; /* only want highest value */
+
+ } while (total <= data.sample_width);
+
+ /* If we exceed the threshold value, we have found a hardware latency */
+ if (sample > data.threshold) {
+ struct sample s;
+
+ data.count++;
+ s.seqnum = data.count;
+ s.duration = sample;
+ s.timestamp = CURRENT_TIME;
+ __buffer_add_sample(&s);
+
+ /* Keep a running maximum ever recorded hardware latency */
+ if (sample > data.max_sample)
+ data.max_sample = sample;
+
+ wake_up(&data.wq); /* wake up reader(s) */
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * kthread_fn - The CPU time sampling/hardware latency detection kernel thread
+ * @unused: A required part of the kthread API.
+ *
+ * Used to periodically sample the CPU TSC via a call to get_sample. We
+ * use stop_machine, whith does (intentionally) introduce latency since we
+ * need to ensure nothing else might be running (and thus pre-empting).
+ * Obviously this should never be used in production environments.
+ *
+ * stop_machine will schedule us typically only on CPU0 which is fine for
+ * almost every real-world hardware latency situation - but we might later
+ * generalize this if we find there are any actualy systems with alternate
+ * SMI delivery or other non CPU0 hardware latencies.
+ */
+static int kthread_fn(void *unused)
+{
+ int err = 0;
+ u64 interval = 0;
+
+ while (!kthread_should_stop()) {
+
+ mutex_lock(&data.lock);
+
+ err = stop_machine(get_sample, unused, 0);
+ if (err) {
+ /* Houston, we have a problem */
+ mutex_unlock(&data.lock);
+ goto err_out;
+ }
+
+ interval = data.sample_window - data.sample_width;
+ do_div(interval, USEC_PER_MSEC); /* modifies interval value */
+
+ mutex_unlock(&data.lock);
+
+ if (msleep_interruptible(interval))
+ goto out;
+ }
+ goto out;
+err_out:
+ printk(KERN_ERR BANNER "could not call stop_machine, disabling\n");
+ enabled = 0;
+out:
+ return err;
+
+}
+
+/**
+ * start_kthread - Kick off the hardware latency sampling/detector kthread
+ *
+ * This starts a kernel thread that will sit and sample the CPU timestamp
+ * counter (TSC or similar) and look for potential hardware latencies.
+ */
+static int start_kthread(void)
+{
+ kthread = kthread_run(kthread_fn, NULL,
+ DRVNAME);
+ if (IS_ERR(kthread)) {
+ printk(KERN_ERR BANNER "could not start sampling thread\n");
+ enabled = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * stop_kthread - Inform the hardware latency samping/detector kthread to stop
+ *
+ * This kicks the running hardware latency sampling/detector kernel thread and
+ * tells it to stop sampling now. Use this on unload and at system shutdown.
+ */
+static int stop_kthread(void)
+{
+ int ret;
+
+ ret = kthread_stop(kthread);
+
+ return ret;
+}
+
+/**
+ * __reset_stats - Reset statistics for the hardware latency detector
+ *
+ * We use data to store various statistics and global state. We call this
+ * function in order to reset those when "enable" is toggled on or off, and
+ * also at initialization. Should be called with data.lock held.
+ */
+static void __reset_stats(void)
+{
+ data.count = 0;
+ data.max_sample = 0;
+ ring_buffer_reset(ring_buffer); /* flush out old sample entries */
+}
+
+/**
+ * init_stats - Setup global state statistics for the hardware latency detector
+ *
+ * We use data to store various statistics and global state. We also use
+ * a global ring buffer (ring_buffer) to keep raw samples of detected hardware
+ * induced system latencies. This function initializes these structures and
+ * allocates the global ring buffer also.
+ */
+static int init_stats(void)
+{
+ int ret = -ENOMEM;
+
+ mutex_init(&data.lock);
+ init_waitqueue_head(&data.wq);
+ atomic_set(&data.sample_open, 0);
+
+ ring_buffer = ring_buffer_alloc(buf_size, BUF_FLAGS);
+
+ if (WARN(!ring_buffer, KERN_ERR BANNER
+ "failed to allocate ring buffer!\n"))
+ goto out;
+
+ __reset_stats();
+ data.threshold = DEFAULT_LAT_THRESHOLD; /* threshold us */
+ data.sample_window = DEFAULT_SAMPLE_WINDOW; /* window us */
+ data.sample_width = DEFAULT_SAMPLE_WIDTH; /* width us */
+
+ ret = 0;
+
+out:
+ return ret;
+
+}
+
+/*
+ * simple_data_read - Wrapper read function for global state debugfs entries
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ * @entry: The entry to read from
+ *
+ * This function provides a generic read implementation for the global state
+ * "data" structure debugfs filesystem entries. It would be nice to use
+ * simple_attr_read directly, but we need to make sure that the data.lock
+ * spinlock is held during the actual read (even though we likely won't ever
+ * actually race here as the updater runs under a stop_machine context).
+ */
+static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos, const u64 *entry)
+{
+ char buf[U64STR_SIZE];
+ u64 val = 0;
+ int len = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (!entry)
+ return -EFAULT;
+
+ mutex_lock(&data.lock);
+ val = *entry;
+ mutex_unlock(&data.lock);
+
+ len = snprintf(buf, sizeof(buf), "%llu\n", (unsigned long long)val);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+
+}
+
+/*
+ * simple_data_write - Wrapper write function for global state debugfs entries
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to write value from
+ * @cnt: The maximum number of bytes to write
+ * @ppos: The current "file" position
+ * @entry: The entry to write to
+ *
+ * This function provides a generic write implementation for the global state
+ * "data" structure debugfs filesystem entries. It would be nice to use
+ * simple_attr_write directly, but we need to make sure that the data.lock
+ * spinlock is held during the actual write (even though we likely won't ever
+ * actually race here as the updater runs under a stop_machine context).
+ */
+static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos, u64 *entry)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ *entry = val;
+ mutex_unlock(&data.lock);
+
+ return csize;
+}
+
+/**
+ * debug_count_fopen - Open function for "count" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "count" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_count_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_count_fread - Read function for "count" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "count" debugfs
+ * interface to the hardware latency detector. Can be used to read the
+ * number of latency readings exceeding the configured threshold since
+ * the detector was last reset (e.g. by writing a zero into "count").
+ */
+static ssize_t debug_count_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.count);
+}
+
+/**
+ * debug_count_fwrite - Write function for "count" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "count" debugfs
+ * interface to the hardware latency detector. Can be used to write a
+ * desired value, especially to zero the total count.
+ */
+static ssize_t debug_count_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.count);
+}
+
+/**
+ * debug_enable_fopen - Dummy open function for "enable" debugfs interface
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "enable" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_enable_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_enable_fread - Read function for "enable" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "enable" debugfs
+ * interface to the hardware latency detector. Can be used to determine
+ * whether the detector is currently enabled ("0\n" or "1\n" returned).
+ */
+static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char buf[4];
+
+ if ((cnt < sizeof(buf)) || (*ppos))
+ return 0;
+
+ buf[0] = enabled ? '1' : '0';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ if (copy_to_user(ubuf, buf, strlen(buf)))
+ return -EFAULT;
+ return *ppos = strlen(buf);
+}
+
+/**
+ * debug_enable_fwrite - Write function for "enable" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "enable" debugfs
+ * interface to the hardware latency detector. Can be used to enable or
+ * disable the detector, which will have the side-effect of possibly
+ * also resetting the global stats and kicking off the measuring
+ * kthread (on an enable) or the converse (upon a disable).
+ */
+static ssize_t debug_enable_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[4];
+ int csize = min(cnt, sizeof(buf));
+ long val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[sizeof(buf)-1] = '\0'; /* just in case */
+ err = strict_strtoul(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ if (val) {
+ if (enabled)
+ goto unlock;
+ enabled = 1;
+ __reset_stats();
+ if (start_kthread())
+ return -EFAULT;
+ } else {
+ if (!enabled)
+ goto unlock;
+ enabled = 0;
+ stop_kthread();
+ wake_up(&data.wq); /* reader(s) should return */
+ }
+unlock:
+ return csize;
+}
+
+/**
+ * debug_max_fopen - Open function for "max" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "max" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_max_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_max_fread - Read function for "max" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "max" debugfs
+ * interface to the hardware latency detector. Can be used to determine
+ * the maximum latency value observed since it was last reset.
+ */
+static ssize_t debug_max_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.max_sample);
+}
+
+/**
+ * debug_max_fwrite - Write function for "max" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "max" debugfs
+ * interface to the hardware latency detector. Can be used to reset the
+ * maximum or set it to some other desired value - if, then, subsequent
+ * measurements exceed this value, the maximum will be updated.
+ */
+static ssize_t debug_max_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.max_sample);
+}
+
+
+/**
+ * debug_sample_fopen - An open function for "sample" debugfs interface
+ * @inode: The in-kernel inode representation of this debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function handles opening the "sample" file within the hardware
+ * latency detector debugfs directory interface. This file is used to read
+ * raw samples from the global ring_buffer and allows the user to see a
+ * running latency history. Can be opened blocking or non-blocking,
+ * affecting whether it behaves as a buffer read pipe, or does not.
+ * Implements simple locking to prevent multiple simultaneous use.
+ */
+static int debug_sample_fopen(struct inode *inode, struct file *filp)
+{
+ if (!atomic_add_unless(&data.sample_open, 1, 1))
+ return -EBUSY;
+ else
+ return 0;
+}
+
+/**
+ * debug_sample_fread - A read function for "sample" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that will contain the samples read
+ * @cnt: The maximum bytes to read from the debugfs "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function handles reading from the "sample" file within the hardware
+ * latency detector debugfs directory interface. This file is used to read
+ * raw samples from the global ring_buffer and allows the user to see a
+ * running latency history. By default this will block pending a new
+ * value written into the sample buffer, unless there are already a
+ * number of value(s) waiting in the buffer, or the sample file was
+ * previously opened in a non-blocking mode of operation.
+ */
+static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ int len = 0;
+ char buf[64];
+ struct sample *sample = NULL;
+
+ if (!enabled)
+ return 0;
+
+ sample = kzalloc(sizeof(struct sample), GFP_KERNEL);
+ if (!sample)
+ return -ENOMEM;
+
+ while (!buffer_get_sample(sample)) {
+
+ DEFINE_WAIT(wait);
+
+ if (filp->f_flags & O_NONBLOCK) {
+ len = -EAGAIN;
+ goto out;
+ }
+
+ prepare_to_wait(&data.wq, &wait, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&data.wq, &wait);
+
+ if (signal_pending(current)) {
+ len = -EINTR;
+ goto out;
+ }
+
+ if (!enabled) { /* enable was toggled */
+ len = 0;
+ goto out;
+ }
+ }
+
+ len = snprintf(buf, sizeof(buf), "%010lu.%010lu\t%llu\n",
+ sample->timestamp.tv_sec,
+ sample->timestamp.tv_nsec,
+ sample->duration);
+
+
+ /* handling partial reads is more trouble than it's worth */
+ if (len > cnt)
+ goto out;
+
+ if (copy_to_user(ubuf, buf, len))
+ len = -EFAULT;
+
+out:
+ kfree(sample);
+ return len;
+}
+
+/**
+ * debug_sample_release - Release function for "sample" debugfs interface
+ * @inode: The in-kernel inode represenation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function completes the close of the debugfs interface "sample" file.
+ * Frees the sample_open "lock" so that other users may open the interface.
+ */
+static int debug_sample_release(struct inode *inode, struct file *filp)
+{
+ atomic_dec(&data.sample_open);
+
+ return 0;
+}
+
+/**
+ * debug_threshold_fopen - Open function for "threshold" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "threshold" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_threshold_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_threshold_fread - Read function for "threshold" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "threshold" debugfs
+ * interface to the hardware latency detector. It can be used to determine
+ * the current threshold level at which a latency will be recorded in the
+ * global ring buffer, typically on the order of 10us.
+ */
+static ssize_t debug_threshold_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.threshold);
+}
+
+/**
+ * debug_threshold_fwrite - Write function for "threshold" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "threshold" debugfs
+ * interface to the hardware latency detector. It can be used to configure
+ * the threshold level at which any subsequently detected latencies will
+ * be recorded into the global ring buffer.
+ */
+static ssize_t debug_threshold_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ int ret;
+
+ ret = simple_data_write(filp, ubuf, cnt, ppos, &data.threshold);
+
+ if (enabled)
+ wake_up_process(kthread);
+
+ return ret;
+}
+
+/**
+ * debug_width_fopen - Open function for "width" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "width" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_width_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_width_fread - Read function for "width" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "width" debugfs
+ * interface to the hardware latency detector. It can be used to determine
+ * for how many us of the total window us we will actively sample for any
+ * hardware-induced latecy periods. Obviously, it is not possible to
+ * sample constantly and have the system respond to a sample reader, or,
+ * worse, without having the system appear to have gone out to lunch.
+ */
+static ssize_t debug_width_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_width);
+}
+
+/**
+ * debug_width_fwrite - Write function for "width" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "width" debugfs
+ * interface to the hardware latency detector. It can be used to configure
+ * for how many us of the total window us we will actively sample for any
+ * hardware-induced latency periods. Obviously, it is not possible to
+ * sample constantly and have the system respond to a sample reader, or,
+ * worse, without having the system appear to have gone out to lunch. It
+ * is enforced that width is less that the total window size.
+ */
+static ssize_t debug_width_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ if (val < data.sample_window)
+ data.sample_width = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+
+ if (enabled)
+ wake_up_process(kthread);
+
+ return csize;
+}
+
+/**
+ * debug_window_fopen - Open function for "window" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "window" debugfs
+ * interface to the hardware latency detector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs.
+ */
+static int debug_window_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_window_fread - Read function for "window" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "window" debugfs
+ * interface to the hardware latency detector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs. Can be used to read the total window size.
+ */
+static ssize_t debug_window_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_window);
+}
+
+/**
+ * debug_window_fwrite - Write function for "window" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "window" debufds
+ * interface to the hardware latency detetector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs. Can be used to write a new total window size. It
+ * is enfoced that any value written must be greater than the sample width
+ * size, or an error results.
+ */
+static ssize_t debug_window_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ if (data.sample_width < val)
+ data.sample_window = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+
+ return csize;
+}
+
+/*
+ * Function pointers for the "count" debugfs file operations
+ */
+static const struct file_operations count_fops = {
+ .open = debug_count_fopen,
+ .read = debug_count_fread,
+ .write = debug_count_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "enable" debugfs file operations
+ */
+static const struct file_operations enable_fops = {
+ .open = debug_enable_fopen,
+ .read = debug_enable_fread,
+ .write = debug_enable_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "max" debugfs file operations
+ */
+static const struct file_operations max_fops = {
+ .open = debug_max_fopen,
+ .read = debug_max_fread,
+ .write = debug_max_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "sample" debugfs file operations
+ */
+static const struct file_operations sample_fops = {
+ .open = debug_sample_fopen,
+ .read = debug_sample_fread,
+ .release = debug_sample_release,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "threshold" debugfs file operations
+ */
+static const struct file_operations threshold_fops = {
+ .open = debug_threshold_fopen,
+ .read = debug_threshold_fread,
+ .write = debug_threshold_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "width" debugfs file operations
+ */
+static const struct file_operations width_fops = {
+ .open = debug_width_fopen,
+ .read = debug_width_fread,
+ .write = debug_width_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "window" debugfs file operations
+ */
+static const struct file_operations window_fops = {
+ .open = debug_window_fopen,
+ .read = debug_window_fread,
+ .write = debug_window_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * init_debugfs - A function to initialize the debugfs interface files
+ *
+ * This function creates entries in debugfs for "hwlat_detector", including
+ * files to read values from the detector, current samples, and the
+ * maximum sample that has been captured since the hardware latency
+ * dectector was started.
+ */
+static int init_debugfs(void)
+{
+ int ret = -ENOMEM;
+
+ debug_dir = debugfs_create_dir(DRVNAME, NULL);
+ if (!debug_dir)
+ goto err_debug_dir;
+
+ debug_sample = debugfs_create_file("sample", 0444,
+ debug_dir, NULL,
+ &sample_fops);
+ if (!debug_sample)
+ goto err_sample;
+
+ debug_count = debugfs_create_file("count", 0444,
+ debug_dir, NULL,
+ &count_fops);
+ if (!debug_count)
+ goto err_count;
+
+ debug_max = debugfs_create_file("max", 0444,
+ debug_dir, NULL,
+ &max_fops);
+ if (!debug_max)
+ goto err_max;
+
+ debug_sample_window = debugfs_create_file("window", 0644,
+ debug_dir, NULL,
+ &window_fops);
+ if (!debug_sample_window)
+ goto err_window;
+
+ debug_sample_width = debugfs_create_file("width", 0644,
+ debug_dir, NULL,
+ &width_fops);
+ if (!debug_sample_width)
+ goto err_width;
+
+ debug_threshold = debugfs_create_file("threshold", 0644,
+ debug_dir, NULL,
+ &threshold_fops);
+ if (!debug_threshold)
+ goto err_threshold;
+
+ debug_enable = debugfs_create_file("enable", 0644,
+ debug_dir, &enabled,
+ &enable_fops);
+ if (!debug_enable)
+ goto err_enable;
+
+ else {
+ ret = 0;
+ goto out;
+ }
+
+err_enable:
+ debugfs_remove(debug_threshold);
+err_threshold:
+ debugfs_remove(debug_sample_width);
+err_width:
+ debugfs_remove(debug_sample_window);
+err_window:
+ debugfs_remove(debug_max);
+err_max:
+ debugfs_remove(debug_count);
+err_count:
+ debugfs_remove(debug_sample);
+err_sample:
+ debugfs_remove(debug_dir);
+err_debug_dir:
+out:
+ return ret;
+}
+
+/**
+ * free_debugfs - A function to cleanup the debugfs file interface
+ */
+static void free_debugfs(void)
+{
+ /* could also use a debugfs_remove_recursive */
+ debugfs_remove(debug_enable);
+ debugfs_remove(debug_threshold);
+ debugfs_remove(debug_sample_width);
+ debugfs_remove(debug_sample_window);
+ debugfs_remove(debug_max);
+ debugfs_remove(debug_count);
+ debugfs_remove(debug_sample);
+ debugfs_remove(debug_dir);
+}
+
+/**
+ * detector_init - Standard module initialization code
+ */
+static int detector_init(void)
+{
+ int ret = -ENOMEM;
+
+ printk(KERN_INFO BANNER "version %s\n", VERSION);
+
+ ret = init_stats();
+ if (0 != ret)
+ goto out;
+
+ ret = init_debugfs();
+ if (0 != ret)
+ goto err_stats;
+
+ if (enabled)
+ ret = start_kthread();
+
+ goto out;
+
+err_stats:
+ ring_buffer_free(ring_buffer);
+out:
+ return ret;
+
+}
+
+/**
+ * detector_exit - Standard module cleanup code
+ */
+static void detector_exit(void)
+{
+ if (enabled) {
+ enabled = 0;
+ stop_kthread();
+ }
+
+ free_debugfs();
+ ring_buffer_free(ring_buffer); /* free up the ring buffer */
+
+}
+
+module_init(detector_init);
+module_exit(detector_exit);
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 5d778ec8cdb2..212da9af1ce7 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] == 0x33) {
dev_kfree_skb(skb);
- return 0; /* nothing needed to be done */
+ return NETDEV_TX_OK; /* nothing needed to be done */
}
/*
@@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
index 11efefb1af51..4e72964a7b43 100644
--- a/drivers/mmc/host/cb710-mmc.c
+++ b/drivers/mmc/host/cb710-mmc.c
@@ -278,7 +278,7 @@ static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)))
return -EINVAL;
- sg_miter_start(&miter, data->sg, data->sg_len, 0);
+ sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
15, CB710_MMC_C2_READ_PIO_SIZE_MASK);
@@ -307,7 +307,7 @@ static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
goto out;
}
out:
- cb710_sg_miter_stop_writing(&miter);
+ sg_miter_stop(&miter);
return err;
}
@@ -322,7 +322,7 @@ static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data)
if (unlikely(data->blocks > 1 && data->blksz & 15))
return -EINVAL;
- sg_miter_start(&miter, data->sg, data->sg_len, 0);
+ sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
0, CB710_MMC_C2_READ_PIO_SIZE_MASK);
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index e0be21a4a696..bf98d7cc928a 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -652,7 +652,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid)
set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
tasklet_schedule(&host->tasklet);
- return IRQ_RETVAL(handled);;
+ return IRQ_RETVAL(handled);
}
static void imxmci_tasklet_fnc(unsigned long data)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index e1aa8471ab1c..5eb86a8c943b 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -21,6 +21,7 @@
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
+#include <linux/gpio.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
@@ -472,17 +473,41 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static int mmci_get_ro(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+
+ if (host->gpio_wp == -ENOSYS)
+ return -ENOSYS;
+
+ return gpio_get_value(host->gpio_wp);
+}
+
+static int mmci_get_cd(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ unsigned int status;
+
+ if (host->gpio_cd == -ENOSYS)
+ status = host->plat->status(mmc_dev(host->mmc));
+ else
+ status = gpio_get_value(host->gpio_cd);
+
+ return !status;
+}
+
static const struct mmc_host_ops mmci_ops = {
.request = mmci_request,
.set_ios = mmci_set_ios,
+ .get_ro = mmci_get_ro,
+ .get_cd = mmci_get_cd,
};
static void mmci_check_status(unsigned long data)
{
struct mmci_host *host = (struct mmci_host *)data;
- unsigned int status;
+ unsigned int status = mmci_get_cd(host->mmc);
- status = host->plat->status(mmc_dev(host->mmc));
if (status ^ host->oldstat)
mmc_detect_change(host->mmc, 0);
@@ -515,12 +540,15 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host = mmc_priv(mmc);
host->mmc = mmc;
- /* Bits 12 thru 19 is the designer */
- host->hw_designer = (dev->periphid >> 12) & 0xff;
- /* Bits 20 thru 23 is the revison */
- host->hw_revision = (dev->periphid >> 20) & 0xf;
+
+ host->gpio_wp = -ENOSYS;
+ host->gpio_cd = -ENOSYS;
+
+ host->hw_designer = amba_manf(dev);
+ host->hw_revision = amba_rev(dev);
DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
DBG(host, "revision = 0x%01x\n", host->hw_revision);
+
host->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
@@ -591,6 +619,25 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
writel(0, host->base + MMCIMASK1);
writel(0xfff, host->base + MMCICLEAR);
+ if (gpio_is_valid(plat->gpio_cd)) {
+ ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
+ if (ret == 0)
+ ret = gpio_direction_input(plat->gpio_cd);
+ if (ret == 0)
+ host->gpio_cd = plat->gpio_cd;
+ else if (ret != -ENOSYS)
+ goto err_gpio_cd;
+ }
+ if (gpio_is_valid(plat->gpio_wp)) {
+ ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
+ if (ret == 0)
+ ret = gpio_direction_input(plat->gpio_wp);
+ if (ret == 0)
+ host->gpio_wp = plat->gpio_wp;
+ else if (ret != -ENOSYS)
+ goto err_gpio_wp;
+ }
+
ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
if (ret)
goto unmap;
@@ -602,6 +649,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
writel(MCI_IRQENABLE, host->base + MMCIMASK0);
amba_set_drvdata(dev, mmc);
+ host->oldstat = mmci_get_cd(host->mmc);
mmc_add_host(mmc);
@@ -620,6 +668,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
irq0_free:
free_irq(dev->irq[0], host);
unmap:
+ if (host->gpio_wp != -ENOSYS)
+ gpio_free(host->gpio_wp);
+ err_gpio_wp:
+ if (host->gpio_cd != -ENOSYS)
+ gpio_free(host->gpio_cd);
+ err_gpio_cd:
iounmap(host->base);
clk_disable:
clk_disable(host->clk);
@@ -655,6 +709,11 @@ static int __devexit mmci_remove(struct amba_device *dev)
free_irq(dev->irq[0], host);
free_irq(dev->irq[1], host);
+ if (host->gpio_wp != -ENOSYS)
+ gpio_free(host->gpio_wp);
+ if (host->gpio_cd != -ENOSYS)
+ gpio_free(host->gpio_cd);
+
iounmap(host->base);
clk_disable(host->clk);
clk_put(host->clk);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 0441bac1c0ec..839f264c9725 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -151,6 +151,8 @@ struct mmci_host {
struct mmc_data *data;
struct mmc_host *mmc;
struct clk *clk;
+ int gpio_cd;
+ int gpio_wp;
unsigned int data_xfered;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index bc14bb1b0579..88671529c45d 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -512,7 +512,7 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
}
/* For the DMA case the DMA engine handles the data transfer
- * automatically. For non DMA we have to to it ourselves.
+ * automatically. For non DMA we have to do it ourselves.
* Don't do it in interrupt context though.
*/
if (!mxcmci_use_dma(host) && host->data)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index e55ac792d68c..5e0b1529964d 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -28,6 +28,7 @@
#include <linux/mmc/host.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
#include <asm/sizes.h>
@@ -96,10 +97,18 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
{
+ int on;
+
#ifdef CONFIG_REGULATOR
if (host->vcc)
mmc_regulator_set_ocr(host->vcc, vdd);
#endif
+ if (!host->vcc && host->pdata &&
+ gpio_is_valid(host->pdata->gpio_power)) {
+ on = ((1 << vdd) & host->pdata->ocr_mask);
+ gpio_set_value(host->pdata->gpio_power,
+ !!on ^ host->pdata->gpio_power_invert);
+ }
if (!host->vcc && host->pdata && host->pdata->setpower)
host->pdata->setpower(mmc_dev(host->mmc), vdd);
}
@@ -421,6 +430,12 @@ static int pxamci_get_ro(struct mmc_host *mmc)
{
struct pxamci_host *host = mmc_priv(mmc);
+ if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) {
+ if (host->pdata->gpio_card_ro_invert)
+ return !gpio_get_value(host->pdata->gpio_card_ro);
+ else
+ return gpio_get_value(host->pdata->gpio_card_ro);
+ }
if (host->pdata && host->pdata->get_ro)
return !!host->pdata->get_ro(mmc_dev(mmc));
/*
@@ -534,7 +549,7 @@ static int pxamci_probe(struct platform_device *pdev)
struct mmc_host *mmc;
struct pxamci_host *host = NULL;
struct resource *r, *dmarx, *dmatx;
- int ret, irq;
+ int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -661,13 +676,63 @@ static int pxamci_probe(struct platform_device *pdev)
}
host->dma_drcmrtx = dmatx->start;
+ if (host->pdata) {
+ gpio_cd = host->pdata->gpio_card_detect;
+ gpio_ro = host->pdata->gpio_card_ro;
+ gpio_power = host->pdata->gpio_power;
+ }
+ if (gpio_is_valid(gpio_power)) {
+ ret = gpio_request(gpio_power, "mmc card power");
+ if (ret) {
+ dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power);
+ goto out;
+ }
+ gpio_direction_output(gpio_power,
+ host->pdata->gpio_power_invert);
+ }
+ 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);
+ goto err_gpio_ro;
+ }
+ gpio_direction_input(gpio_ro);
+ }
+ 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);
+ goto err_gpio_cd;
+ }
+ gpio_direction_input(gpio_cd);
+
+ ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "mmc card detect", mmc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request card detect IRQ\n");
+ goto err_request_irq;
+ }
+ }
+
if (host->pdata && host->pdata->init)
host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
+ if (gpio_is_valid(gpio_power) && host->pdata->setpower)
+ dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
+ if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
+ dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
+
mmc_add_host(mmc);
return 0;
+err_request_irq:
+ gpio_free(gpio_cd);
+err_gpio_cd:
+ gpio_free(gpio_ro);
+err_gpio_ro:
+ gpio_free(gpio_power);
out:
if (host) {
if (host->dma >= 0)
@@ -688,12 +753,26 @@ static int pxamci_probe(struct platform_device *pdev)
static int pxamci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+ int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
platform_set_drvdata(pdev, NULL);
if (mmc) {
struct pxamci_host *host = mmc_priv(mmc);
+ if (host->pdata) {
+ gpio_cd = host->pdata->gpio_card_detect;
+ gpio_ro = host->pdata->gpio_card_ro;
+ gpio_power = host->pdata->gpio_power;
+ }
+ if (gpio_is_valid(gpio_cd)) {
+ free_irq(gpio_to_irq(gpio_cd), mmc);
+ gpio_free(gpio_cd);
+ }
+ if (gpio_is_valid(gpio_ro))
+ gpio_free(gpio_ro);
+ if (gpio_is_valid(gpio_power))
+ gpio_free(gpio_power);
if (host->vcc)
regulator_put(host->vcc);
@@ -725,20 +804,20 @@ static int pxamci_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
+static int pxamci_suspend(struct device *dev)
{
- struct mmc_host *mmc = platform_get_drvdata(dev);
+ struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
if (mmc)
- ret = mmc_suspend_host(mmc, state);
+ ret = mmc_suspend_host(mmc, PMSG_SUSPEND);
return ret;
}
-static int pxamci_resume(struct platform_device *dev)
+static int pxamci_resume(struct device *dev)
{
- struct mmc_host *mmc = platform_get_drvdata(dev);
+ struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
if (mmc)
@@ -746,19 +825,22 @@ static int pxamci_resume(struct platform_device *dev)
return ret;
}
-#else
-#define pxamci_suspend NULL
-#define pxamci_resume NULL
+
+static struct dev_pm_ops pxamci_pm_ops = {
+ .suspend = pxamci_suspend,
+ .resume = pxamci_resume,
+};
#endif
static struct platform_driver pxamci_driver = {
.probe = pxamci_probe,
.remove = pxamci_remove,
- .suspend = pxamci_suspend,
- .resume = pxamci_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pxamci_pm_ops,
+#endif
},
};
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c
index d79fa55c3b89..908844327db0 100644
--- a/drivers/mmc/host/sdhci-of.c
+++ b/drivers/mmc/host/sdhci-of.c
@@ -158,6 +158,13 @@ static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
return of_host->clock;
}
+static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_of_host *of_host = sdhci_priv(host);
+
+ return of_host->clock / 256 / 16;
+}
+
static unsigned int esdhc_get_timeout_clock(struct sdhci_host *host)
{
struct sdhci_of_host *of_host = sdhci_priv(host);
@@ -184,6 +191,7 @@ static struct sdhci_of_data sdhci_esdhc = {
.set_clock = esdhc_set_clock,
.enable_dma = esdhc_enable_dma,
.get_max_clock = esdhc_get_max_clock,
+ .get_min_clock = esdhc_get_min_clock,
.get_timeout_clock = esdhc_get_timeout_clock,
},
};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6779b4ecab18..fc96f8cb9c0b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -773,8 +773,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
}
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
- sg_miter_start(&host->sg_miter,
- data->sg, data->sg_len, SG_MITER_ATOMIC);
+ int flags;
+
+ flags = SG_MITER_ATOMIC;
+ if (host->data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
host->blocks = data->blocks;
}
@@ -1766,7 +1772,10 @@ int sdhci_add_host(struct sdhci_host *host)
* Set host parameters.
*/
mmc->ops = &sdhci_ops;
- mmc->f_min = host->max_clk / 256;
+ if (host->ops->get_min_clock)
+ mmc->f_min = host->ops->get_min_clock(host);
+ else
+ mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_SDIO_IRQ;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 831ddf7dcb49..c77e9ff30223 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -302,6 +302,7 @@ struct sdhci_ops {
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
+ unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
};
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index ae5fe91867e1..3f7985311e35 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -776,13 +776,13 @@ static struct spi_driver m25p80_driver = {
};
-static int m25p80_init(void)
+static int __init m25p80_init(void)
{
return spi_register_driver(&m25p80_driver);
}
-static void m25p80_exit(void)
+static void __exit m25p80_exit(void)
{
spi_unregister_driver(&m25p80_driver);
}
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 00248e81ecd5..7d846e9173da 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -303,7 +303,7 @@ __setup("slram=", mtd_slram_setup);
#endif
-static int init_slram(void)
+static int __init init_slram(void)
{
char *devname;
int i;
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index a790c062af1f..e56d6b42f020 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1099,7 +1099,7 @@ static struct mtd_blktrans_ops ftl_tr = {
.owner = THIS_MODULE,
};
-static int init_ftl(void)
+static int __init init_ftl(void)
{
return register_mtd_blktrans(&ftl_tr);
}
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index d4fb9a3ab4df..1bdf0ee6d0b6 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -184,7 +184,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)
info->map.bankwidth = 1;
/*
- * map_priv_2 is used to store a ptr to to the bank_setup routine
+ * map_priv_2 is used to store a ptr to the bank_setup routine
*/
info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup;
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 29acd06b1c39..1b4690bdfdb3 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -903,12 +903,12 @@ static struct pci_driver cafe_nand_pci_driver = {
.resume = cafe_nand_resume,
};
-static int cafe_nand_init(void)
+static int __init cafe_nand_init(void)
{
return pci_register_driver(&cafe_nand_pci_driver);
}
-static void cafe_nand_exit(void)
+static void __exit cafe_nand_exit(void)
{
pci_unregister_driver(&cafe_nand_pci_driver);
}
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 10081e656a6f..826cacffcefc 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -147,7 +147,7 @@ static int cmx270_device_ready(struct mtd_info *mtd)
/*
* Main initialization routine
*/
-static int cmx270_init(void)
+static int __init cmx270_init(void)
{
struct nand_chip *this;
const char *part_type;
@@ -261,7 +261,7 @@ module_init(cmx270_init);
/*
* Clean up routine
*/
-static void cmx270_cleanup(void)
+static void __exit cmx270_cleanup(void)
{
/* Release resources, unregister device */
nand_release(cmx270_nand_mtd);
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c
index 2c410a011317..0f5562aeedc1 100644
--- a/drivers/mtd/nand/ts7250.c
+++ b/drivers/mtd/nand/ts7250.c
@@ -24,8 +24,11 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
-#include <asm/io.h>
+#include <linux/io.h>
+
#include <mach/hardware.h>
+#include <mach/ts72xx.h>
+
#include <asm/sizes.h>
#include <asm/mach-types.h>
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 0f2034c3ed2f..9f87c99189a9 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1065,7 +1065,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
}
/*
- * Now we have got to calculate how much data we have to to copy. In
+ * Now we have got to calculate how much data we have to copy. In
* case of a static volume it is fairly easy - the VID header contains
* the data size. In case of a dynamic volume it is more difficult - we
* have to read the contents, cut 0xFF bytes from the end and copy only
@@ -1254,6 +1254,7 @@ out_free:
if (!ubi->volumes[i])
continue;
kfree(ubi->volumes[i]->eba_tbl);
+ ubi->volumes[i]->eba_tbl = NULL;
}
return err;
}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4cb69925d8d9..4e7bcb215075 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -480,20 +480,20 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
loff_t addr;
uint32_t data = 0;
- addr = (loff_t)pnum * ubi->peb_size;
+ addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
if (err) {
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
- "%zd bytes", err, pnum, 0, written);
+ "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
ubi_dbg_dump_stack();
return err;
}
- addr += ubi->vid_hdr_aloffset;
+ addr -= ubi->vid_hdr_aloffset;
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
if (err) {
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
- "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
+ "%zd bytes", err, pnum, 0, written);
ubi_dbg_dump_stack();
return err;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index a423131b6171..e7161adc419d 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -75,9 +75,10 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
else if (list == &si->erase)
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- else if (list == &si->corr)
+ else if (list == &si->corr) {
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- else if (list == &si->alien)
+ si->corr_count += 1;
+ } else if (list == &si->alien)
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
else
BUG();
@@ -781,11 +782,22 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return -EINVAL;
}
+ /*
+ * Make sure that all PEBs have the same image sequence number.
+ * This allows us to detect situations when users flash UBI
+ * images incorrectly, so that the flash has the new UBI image
+ * and leftovers from the old one. This feature was added
+ * relatively recently, and the sequence number was always
+ * zero, because old UBI implementations always set it to zero.
+ * For this reasons, we do not panic if some PEBs have zero
+ * sequence number, while other PEBs have non-zero sequence
+ * number.
+ */
image_seq = be32_to_cpu(ech->image_seq);
if (!si->image_seq_set) {
ubi->image_seq = image_seq;
si->image_seq_set = 1;
- } else if (ubi->image_seq != image_seq) {
+ } else if (ubi->image_seq && ubi->image_seq != image_seq) {
ubi_err("bad image sequence number %d in PEB %d, "
"expected %d", image_seq, pnum, ubi->image_seq);
ubi_dbg_dump_ec_hdr(ech);
@@ -853,7 +865,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
}
}
- /* Both UBI headers seem to be fine */
+ if (ec_corr)
+ ubi_warn("valid VID header but corrupted EC header at PEB %d",
+ pnum);
err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
if (err)
return err;
@@ -925,6 +939,19 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
ubi_msg("empty MTD device detected");
/*
+ * Few corrupted PEBs are not a problem and may be just a result of
+ * unclean reboots. However, many of them may indicate some problems
+ * with the flash HW or driver. Print a warning in this case.
+ */
+ if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
+ ubi_warn("%d PEBs are corrupted", si->corr_count);
+ printk(KERN_WARNING "corrupted PEBs are:");
+ list_for_each_entry(seb, &si->corr, u.list)
+ printk(KERN_CONT " %d", seb->pnum);
+ printk(KERN_CONT "\n");
+ }
+
+ /*
* In case of unknown erase counter we use the mean erase counter
* value.
*/
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 1017cf12def5..bab31695dace 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -102,6 +102,7 @@ struct ubi_scan_volume {
* @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
+ * @corr_count: count of corrupted PEBs
* @image_seq_set: indicates @ubi->image_seq is known
*
* This data structure contains the result of scanning and may be used by other
@@ -125,6 +126,7 @@ struct ubi_scan_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ int corr_count;
int image_seq_set;
};
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 6a5fe9633783..1af08178defd 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -570,7 +570,7 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
/*
* ubi_rb_for_each_entry - walk an RB-tree.
- * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
+ * @rb: a pointer to type 'struct rb_node' to use as a loop counter
* @pos: a pointer to RB-tree entry type to use as a loop counter
* @root: RB-tree's root
* @member: the name of the 'struct rb_node' within the RB-tree entry
@@ -579,7 +579,8 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
for (rb = rb_first(root), \
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
rb; \
- rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
+ rb = rb_next(rb), \
+ pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 367bec63620c..e29fb1a4a611 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (el_debug > 2)
pr_debug(" queued xmit.\n");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* A receive upset our load, despite our best efforts */
if (el_debug > 2)
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index f71b35402755..7bba480d7220 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
prime_rx(dev);
spin_unlock_irqrestore(&adapter->lock, flags);
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/******************************************************
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 96b86659381a..9e93a0b39b6e 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index d2137efbd455..d2515d840c00 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 3e00fa8ea65f..3116410b3499 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -832,7 +832,9 @@ static int corkscrew_open(struct net_device *dev)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
}
- vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+ if (i != 0)
+ vp->rx_ring[i - 1].next =
+ isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
}
if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
@@ -1054,7 +1056,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
netif_wake_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
@@ -1117,7 +1119,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index cdd955c4014c..70c701b80d99 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index aaa8a9f405d4..72b9ed7f4641 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
atomic_dec(&lp->tx_count);
@@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
p->control &= ~CONTROL_EOL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c34aee91250b..202048450eed 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
static int
@@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
iowrite16(DownUnstall, ioaddr + EL3_CMD);
spin_unlock_irqrestore(&vp->lock, flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 69f5b7d298a6..b1e5764628c6 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
EXPORT_SYMBOL_GPL(lance_start_xmit);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 50efde11ea6c..07919d0877ee 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
cpw8(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 0e2ba21d4441..b39ec98345ea 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1707,7 +1707,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
} else {
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&tp->lock, flags);
@@ -1732,7 +1732,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
dev->name, len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 77547545509b..996cc9102215 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b5a7513df4eb..3ed49f1337c7 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -209,7 +209,7 @@ config MII
config MACB
tristate "Atmel MACB support"
- depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9
+ depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45 || ARCH_AT91CAP9
select PHYLIB
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -1732,6 +1732,7 @@ config KS8842
config KS8851
tristate "Micrel KS8851 SPI"
depends on SPI
+ select MII
help
SPI driver for Micrel KS8851 SPI attached network chip.
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 08787f5a22a3..174a81187a95 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
volatile struct lance_regs *ll = lp->ll;
volatile struct lance_init_block *ib = lp->init_block;
int entry, skblen;
- int status = 0;
+ int status = NETDEV_TX_OK;
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
skblen = max_t(unsigned, skb->len, ETH_ZLEN);
local_irq_save(flags);
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 19831bd64016..61ac671f97bf 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
This function returns all the memory mapped registers of the device.
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 7f8325419803..29b279f88efb 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 78cea5e80b1d..6cfd961bb8de 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
}
if(rt == NULL) {
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
our_addr = atalk_find_dev_addr(rt->dev);
@@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index b642647170be..c80fb9cf8ffa 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* initialization stuff */
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 58e8d522e5bc..47d976cc3d7d 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 627bc75da17d..164b37e85eea 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 2e7419a61191..c8bc60a7040c 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
we free and return(0) or don't free and return 1 */
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1228,7 +1228,6 @@ static int at91ether_resume(struct platform_device *pdev)
#endif
static struct platform_driver at91ether_driver = {
- .probe = at91ether_probe,
.remove = __devexit_p(at91ether_remove),
.suspend = at91ether_suspend,
.resume = at91ether_resume,
@@ -1240,7 +1239,7 @@ static struct platform_driver at91ether_driver = {
static int __init at91ether_init(void)
{
- return platform_driver_register(&at91ether_driver);
+ return platform_driver_probe(&at91ether_driver, at91ether_probe);
}
static void __exit at91ether_exit(void)
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index edf770f639fa..e47c0d962857 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 455037134aa3..1f7a69c929a6 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
priv(dev)->stats.tx_dropped ++;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = (length + 1) & ~1;
@@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static irqreturn_t
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 18b566ad4fd1..5349c58d1fae 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -318,7 +318,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
pos3 = mca_read_stored_pos( slot, 3 );
pos4 = mca_read_stored_pos( slot, 4 );
- for (l_i = 0; l_i < 0x09; l_i++)
+ for (l_i = 0; l_i < 8; l_i++)
if (( pos3 & 0x07) == at1700_ioaddr_pattern[l_i])
break;
ioaddr = at1700_mca_probe_list[l_i];
@@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
netif_start_queue (dev);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 5425ab0c38c0..0c0deceb6938 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
if (len > skb->len) {
if (skb_padto(skb, len))
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue (dev);
@@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index a383122679de..1d601ce7d5b2 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -2678,6 +2678,9 @@ static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev,
netif_device_detach(netdev);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev))
atl1c_down(adapter);
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 9fc6d6d9060e..4570749e3d3b 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -2497,6 +2497,9 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
netif_device_detach(netdev);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev))
atl1e_down(adapter);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 4317b3edb3d7..4beacc9c909f 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d3c734f4d679..2aab1ebc6cd1 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 36d4d377ec2f..1f7f015442df 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf
struct b44 *bp = netdev_priv(dev);
struct ssb_bus *bus = bp->sdev->bus;
- strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
- strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
switch (bus->bustype) {
case SSB_BUSTYPE_PCI:
- strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+ strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
break;
case SSB_BUSTYPE_PCMCIA:
case SSB_BUSTYPE_SSB:
- strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+ strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
break;
}
}
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
index c6934f179c09..fdb6e81a4374 100644
--- a/drivers/net/benet/Kconfig
+++ b/drivers/net/benet/Kconfig
@@ -1,7 +1,6 @@
config BE2NET
tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
depends on PCI && INET
- select INET_LRO
help
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine 2.
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 5b4bf3d2cdc2..beb131399231 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -28,11 +28,10 @@
#include <linux/if_vlan.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-#include <linux/inet_lro.h>
#include "be_hw.h"
-#define DRV_VER "2.0.348"
+#define DRV_VER "2.0.400"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
@@ -72,8 +71,7 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
-#define BE_MAX_LRO_DESCRIPTORS 16
-#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS))
+#define FW_VER_LEN 32
struct be_dma_mem {
void *va;
@@ -127,7 +125,6 @@ static inline void queue_tail_inc(struct be_queue_info *q)
index_inc(&q->tail, q->len);
}
-
struct be_eq_obj {
struct be_queue_info q;
char desc[32];
@@ -146,31 +143,6 @@ struct be_mcc_obj {
struct be_queue_info cq;
};
-struct be_ctrl_info {
- u8 __iomem *csr;
- u8 __iomem *db; /* Door Bell */
- u8 __iomem *pcicfg; /* PCI config space */
- int pci_func;
-
- /* 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"
-
struct be_drvr_stats {
u32 be_tx_reqs; /* number of TX requests initiated */
u32 be_tx_stops; /* number of times TX Q was stopped */
@@ -189,8 +161,6 @@ struct be_drvr_stats {
u32 be_polls; /* number of times NAPI called poll function */
u32 be_rx_events; /* number of ucast rx completion events */
u32 be_rx_compl; /* number of rx completion entries processed */
- u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */
- u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */
ulong be_rx_jiffies;
u64 be_rx_bytes;
u64 be_rx_bytes_prev;
@@ -233,8 +203,6 @@ struct be_rx_obj {
struct be_queue_info q;
struct be_queue_info cq;
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
};
#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
@@ -242,8 +210,19 @@ struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
- /* Mbox, pci config, csr address information */
- struct be_ctrl_info ctrl;
+ u8 __iomem *csr;
+ u8 __iomem *db; /* Door Bell */
+ u8 __iomem *pcicfg; /* PCI config space */
+
+ 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;
+
+ struct be_mcc_obj mcc_obj;
+ spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
+ spinlock_t mcc_cq_lock;
struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS];
bool msix_enabled;
@@ -271,7 +250,6 @@ struct be_adapter {
/* Ethtool knobs and info */
bool rx_csum; /* BE card must perform rx-checksumming */
- u32 max_rx_coal;
char fw_ver[FW_VER_LEN];
u32 if_handle; /* Used to configure filtering */
u32 pmac_id; /* MAC addr handle used by BE card */
@@ -285,6 +263,11 @@ extern struct ethtool_ops be_ethtool_ops;
#define drvr_stats(adapter) (&adapter->stats.drvr_stats)
+static inline unsigned int be_pci_func(struct be_adapter *adapter)
+{
+ return PCI_FUNC(adapter->pdev->devfn);
+}
+
#define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops)
#define PAGE_SHIFT_4K 12
@@ -375,6 +358,7 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
return val;
}
-extern void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
+extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
#endif /* BE_H */
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 583517ed56f0..de107732dcdc 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -16,21 +16,22 @@
*/
#include "be.h"
+#include "be_cmds.h"
-static void be_mcc_notify(struct be_ctrl_info *ctrl)
+static void be_mcc_notify(struct be_adapter *adapter)
{
- struct be_queue_info *mccq = &ctrl->mcc_obj.q;
+ struct be_queue_info *mccq = &adapter->mcc_obj.q;
u32 val = 0;
val |= mccq->id & DB_MCCQ_RING_ID_MASK;
val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
- iowrite32(val, ctrl->db + DB_MCCQ_OFFSET);
+ iowrite32(val, adapter->db + DB_MCCQ_OFFSET);
}
/* To check if valid bit is set, check the entire word as we don't know
* the endianness of the data (old entry is host endian while a new entry is
* little endian) */
-static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl)
+static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
if (compl->flags != 0) {
compl->flags = le32_to_cpu(compl->flags);
@@ -42,13 +43,13 @@ static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl)
}
/* Need to reset the entire word that houses the valid bit */
-static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl)
+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_cq_entry *compl)
+static int be_mcc_compl_process(struct be_adapter *adapter,
+ struct be_mcc_compl *compl)
{
u16 compl_status, extd_status;
@@ -61,8 +62,8 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
if (compl_status != MCC_STATUS_SUCCESS) {
extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
CQE_STATUS_EXTD_MASK;
- printk(KERN_WARNING DRV_NAME
- " error in cmd completion: status(compl/extd)=%d/%d\n",
+ dev_warn(&adapter->pdev->dev,
+ "Error in cmd completion: status(compl/extd)=%d/%d\n",
compl_status, extd_status);
return -1;
}
@@ -70,11 +71,11 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
}
/* Link state evt is a string of bytes; no need for endian swapping */
-static void be_async_link_state_process(struct be_ctrl_info *ctrl,
+static void be_async_link_state_process(struct be_adapter *adapter,
struct be_async_event_link_state *evt)
{
- ctrl->async_cb(ctrl->adapter_ctxt,
- evt->port_link_status == ASYNC_EVENT_LINK_UP ? true : false);
+ be_link_status_update(adapter,
+ evt->port_link_status == ASYNC_EVENT_LINK_UP);
}
static inline bool is_link_state_evt(u32 trailer)
@@ -84,10 +85,10 @@ static inline bool is_link_state_evt(u32 trailer)
ASYNC_EVENT_CODE_LINK_STATE);
}
-static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl)
+static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
{
- struct be_queue_info *mcc_cq = &ctrl->mcc_obj.cq;
- struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq);
+ struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq;
+ struct be_mcc_compl *compl = queue_tail_node(mcc_cq);
if (be_mcc_compl_is_new(compl)) {
queue_tail_inc(mcc_cq);
@@ -96,55 +97,55 @@ static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl)
return NULL;
}
-void be_process_mcc(struct be_ctrl_info *ctrl)
+void be_process_mcc(struct be_adapter *adapter)
{
- struct be_mcc_cq_entry *compl;
+ struct be_mcc_compl *compl;
int num = 0;
- spin_lock_bh(&ctrl->mcc_cq_lock);
- while ((compl = be_mcc_compl_get(ctrl))) {
+ spin_lock_bh(&adapter->mcc_cq_lock);
+ while ((compl = be_mcc_compl_get(adapter))) {
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
/* Interpret flags as an async trailer */
BUG_ON(!is_link_state_evt(compl->flags));
/* Interpret compl as a async link evt */
- be_async_link_state_process(ctrl,
+ be_async_link_state_process(adapter,
(struct be_async_event_link_state *) compl);
} else {
- be_mcc_compl_process(ctrl, compl);
- atomic_dec(&ctrl->mcc_obj.q.used);
+ be_mcc_compl_process(adapter, compl);
+ atomic_dec(&adapter->mcc_obj.q.used);
}
be_mcc_compl_use(compl);
num++;
}
if (num)
- be_cq_notify(ctrl, ctrl->mcc_obj.cq.id, true, num);
- spin_unlock_bh(&ctrl->mcc_cq_lock);
+ be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num);
+ spin_unlock_bh(&adapter->mcc_cq_lock);
}
/* Wait till no more pending mcc requests are present */
-static void be_mcc_wait_compl(struct be_ctrl_info *ctrl)
+static void be_mcc_wait_compl(struct be_adapter *adapter)
{
#define mcc_timeout 50000 /* 5s timeout */
int i;
for (i = 0; i < mcc_timeout; i++) {
- be_process_mcc(ctrl);
- if (atomic_read(&ctrl->mcc_obj.q.used) == 0)
+ be_process_mcc(adapter);
+ if (atomic_read(&adapter->mcc_obj.q.used) == 0)
break;
udelay(100);
}
if (i == mcc_timeout)
- printk(KERN_WARNING DRV_NAME "mcc poll timed out\n");
+ dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
}
/* Notify MCC requests and wait for completion */
-static void be_mcc_notify_wait(struct be_ctrl_info *ctrl)
+static void be_mcc_notify_wait(struct be_adapter *adapter)
{
- be_mcc_notify(ctrl);
- be_mcc_wait_compl(ctrl);
+ be_mcc_notify(adapter);
+ be_mcc_wait_compl(adapter);
}
-static int be_mbox_db_ready_wait(void __iomem *db)
+static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
{
int cnt = 0, wait = 5;
u32 ready;
@@ -155,8 +156,7 @@ static int be_mbox_db_ready_wait(void __iomem *db)
break;
if (cnt > 200000) {
- printk(KERN_WARNING DRV_NAME
- ": mbox_db poll timed out\n");
+ dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
return -1;
}
@@ -173,55 +173,52 @@ static int be_mbox_db_ready_wait(void __iomem *db)
* Insert the mailbox address into the doorbell in two steps
* Polls on the mbox doorbell till a command completion (or a timeout) occurs
*/
-static int be_mbox_db_ring(struct be_ctrl_info *ctrl)
+static int be_mbox_notify(struct be_adapter *adapter)
{
int status;
u32 val = 0;
- void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
- struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
+ void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET;
+ struct be_dma_mem *mbox_mem = &adapter->mbox_mem;
struct be_mcc_mailbox *mbox = mbox_mem->va;
- struct be_mcc_cq_entry *cqe = &mbox->cqe;
+ struct be_mcc_compl *compl = &mbox->compl;
- memset(cqe, 0, sizeof(*cqe));
+ memset(compl, 0, sizeof(*compl));
- val &= ~MPU_MAILBOX_DB_RDY_MASK;
val |= MPU_MAILBOX_DB_HI_MASK;
/* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
iowrite32(val, db);
/* wait for ready to be set */
- status = be_mbox_db_ready_wait(db);
+ status = be_mbox_db_ready_wait(adapter, db);
if (status != 0)
return status;
val = 0;
- val &= ~MPU_MAILBOX_DB_RDY_MASK;
- val &= ~MPU_MAILBOX_DB_HI_MASK;
/* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
val |= (u32)(mbox_mem->dma >> 4) << 2;
iowrite32(val, db);
- status = be_mbox_db_ready_wait(db);
+ status = be_mbox_db_ready_wait(adapter, db);
if (status != 0)
return status;
/* A cq entry has been made now */
- if (be_mcc_compl_is_new(cqe)) {
- status = be_mcc_compl_process(ctrl, &mbox->cqe);
- be_mcc_compl_use(cqe);
+ if (be_mcc_compl_is_new(compl)) {
+ status = be_mcc_compl_process(adapter, &mbox->compl);
+ be_mcc_compl_use(compl);
if (status)
return status;
} else {
- printk(KERN_WARNING DRV_NAME "invalid mailbox completion\n");
+ dev_err(&adapter->pdev->dev, "invalid mailbox completion\n");
return -1;
}
return 0;
}
-static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage)
+static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage)
{
- u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
+ u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET);
*stage = sem & EP_SEMAPHORE_POST_STAGE_MASK;
if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK)
@@ -230,54 +227,17 @@ static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage)
return 0;
}
-static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage)
-{
- u16 stage, cnt, error;
- for (cnt = 0; cnt < 5000; cnt++) {
- error = be_POST_stage_get(ctrl, &stage);
- if (error)
- return -1;
-
- if (stage == poll_stage)
- break;
- udelay(1000);
- }
- if (stage != poll_stage)
- return -1;
- return 0;
-}
-
-
-int be_cmd_POST(struct be_ctrl_info *ctrl)
+int be_cmd_POST(struct be_adapter *adapter)
{
u16 stage, error;
- error = be_POST_stage_get(ctrl, &stage);
- if (error)
- goto err;
-
- if (stage == POST_STAGE_ARMFW_RDY)
- return 0;
-
- if (stage != POST_STAGE_AWAITING_HOST_RDY)
- goto err;
-
- /* On awaiting host rdy, reset and again poll on awaiting host rdy */
- iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
- error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY);
- if (error)
- goto err;
-
- /* Now kickoff POST and poll on armfw ready */
- iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
- error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY);
- if (error)
- goto err;
+ error = be_POST_stage_get(adapter, &stage);
+ if (error || stage != POST_STAGE_ARMFW_RDY) {
+ dev_err(&adapter->pdev->dev, "POST failed.\n");
+ return -1;
+ }
return 0;
-err:
- printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage);
- return -1;
}
static inline void *embedded_payload(struct be_mcc_wrb *wrb)
@@ -367,16 +327,16 @@ static inline struct be_mcc_wrb *wrb_from_mcc(struct be_queue_info *mccq)
return wrb;
}
-int be_cmd_eq_create(struct be_ctrl_info *ctrl,
+int be_cmd_eq_create(struct be_adapter *adapter,
struct be_queue_info *eq, int eq_delay)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->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);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -387,7 +347,7 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl,
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,
- ctrl->pci_func);
+ be_pci_func(adapter));
AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
/* 4byte eqe*/
AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
@@ -399,24 +359,24 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
eq->id = le16_to_cpu(resp->eq_id);
eq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr,
+int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
u8 type, bool permanent, u32 if_handle)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_mac_query *req = embedded_payload(wrb);
struct be_cmd_resp_mac_query *resp = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -432,22 +392,22 @@ int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr,
req->permanent = 0;
}
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status)
memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr,
+int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
u32 if_id, u32 *pmac_id)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_pmac_add *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -458,23 +418,23 @@ int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr,
req->if_id = cpu_to_le32(if_id);
memcpy(req->mac_address, mac_addr, ETH_ALEN);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb);
*pmac_id = le32_to_cpu(resp->pmac_id);
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id)
+int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_pmac_del *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -485,24 +445,24 @@ int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id)
req->if_id = cpu_to_le32(if_id);
req->pmac_id = cpu_to_le32(pmac_id);
- status = be_mbox_db_ring(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ status = be_mbox_notify(adapter);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_cq_create(struct be_ctrl_info *ctrl,
+int be_cmd_cq_create(struct be_adapter *adapter,
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_mcc_wrb *wrb = wrb_from_mbox(&adapter->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);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -521,17 +481,17 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl,
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, ctrl->pci_func);
+ AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter));
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_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
cq->id = le16_to_cpu(resp->cq_id);
cq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
@@ -544,17 +504,17 @@ static u32 be_encoded_q_len(int q_len)
return len_encoded;
}
-int be_cmd_mccq_create(struct be_ctrl_info *ctrl,
+int be_cmd_mccq_create(struct be_adapter *adapter,
struct be_queue_info *mccq,
struct be_queue_info *cq)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_mcc_create *req = embedded_payload(wrb);
struct be_dma_mem *q_mem = &mccq->dma_mem;
void *ctxt = &req->context;
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -564,7 +524,7 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl,
req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
- AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, ctrl->pci_func);
+ AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter));
AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
be_encoded_q_len(mccq->len));
@@ -574,29 +534,29 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
mccq->id = le16_to_cpu(resp->id);
mccq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_txq_create(struct be_ctrl_info *ctrl,
+int be_cmd_txq_create(struct be_adapter *adapter,
struct be_queue_info *txq,
struct be_queue_info *cq)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_eth_tx_create *req = embedded_payload(wrb);
struct be_dma_mem *q_mem = &txq->dma_mem;
void *ctxt = &req->context;
int status;
u32 len_encoded;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -613,7 +573,7 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl,
len_encoded = 0;
AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded);
AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt,
- ctrl->pci_func);
+ be_pci_func(adapter));
AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id);
@@ -621,27 +581,27 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
txq->id = le16_to_cpu(resp->cid);
txq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_rxq_create(struct be_ctrl_info *ctrl,
+int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_queue_info *rxq, u16 cq_id, u16 frag_size,
u16 max_frame_size, u32 if_id, u32 rss)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_eth_rx_create *req = embedded_payload(wrb);
struct be_dma_mem *q_mem = &rxq->dma_mem;
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -657,27 +617,27 @@ int be_cmd_rxq_create(struct be_ctrl_info *ctrl,
req->max_frame_size = cpu_to_le16(max_frame_size);
req->rss_queue = cpu_to_le32(rss);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb);
rxq->id = le16_to_cpu(resp->id);
rxq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
/* Generic destroyer function for all types of queues */
-int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
int queue_type)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_q_destroy *req = embedded_payload(wrb);
u8 subsys = 0, opcode = 0;
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -704,29 +664,27 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
opcode = OPCODE_COMMON_MCC_DESTROY;
break;
default:
- printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n");
- status = -1;
- goto err;
+ BUG();
}
be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
req->id = cpu_to_le16(q->id);
- status = be_mbox_db_ring(ctrl);
-err:
- spin_unlock(&ctrl->mbox_lock);
+ status = be_mbox_notify(adapter);
+
+ spin_unlock(&adapter->mbox_lock);
return status;
}
/* Create an rx filtering policy configuration on an i/f */
-int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac,
+int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac,
bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_if_create *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -739,7 +697,7 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac,
if (!pmac_invalid)
memcpy(req->mac_addr, mac, ETH_ALEN);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_if_create *resp = embedded_payload(wrb);
*if_handle = le32_to_cpu(resp->interface_id);
@@ -747,17 +705,17 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac,
*pmac_id = le32_to_cpu(resp->pmac_id);
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id)
+int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_if_destroy *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -766,9 +724,9 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id)
OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req));
req->interface_id = cpu_to_le32(interface_id);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
@@ -776,14 +734,14 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id)
/* Get stats is a non embedded command: the request is not embedded inside
* WRB but is a separate dma memory block
*/
-int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd)
+int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_get_stats *req = nonemb_cmd->va;
struct be_sge *sge = nonembedded_sgl(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
memset(req, 0, sizeof(*req));
@@ -796,24 +754,24 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd)
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_get_stats *resp = nonemb_cmd->va;
be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats));
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_link_status_query(struct be_ctrl_info *ctrl,
+int be_cmd_link_status_query(struct be_adapter *adapter,
bool *link_up)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_link_status *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
*link_up = false;
memset(wrb, 0, sizeof(*wrb));
@@ -823,24 +781,24 @@ int be_cmd_link_status_query(struct be_ctrl_info *ctrl,
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req));
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_link_status *resp = embedded_payload(wrb);
if (resp->mac_speed != PHY_LINK_SPEED_ZERO)
*link_up = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver)
+int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_get_fw_version *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -848,24 +806,24 @@ int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
/* set the EQ delay interval of an EQ to specified value */
-int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd)
+int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -878,20 +836,20 @@ int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd)
req->delay[0].phase = 0;
req->delay[0].delay_multiplier = cpu_to_le32(eqd);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array,
+int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
u32 num, bool untagged, bool promiscuous)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_vlan_config *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -908,21 +866,21 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array,
req->num_vlan * sizeof(vtag_array[0]));
}
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
/* Use MCC for this command as it may be called in BH context */
-int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en)
+int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_promiscuous_config *req;
- spin_lock_bh(&ctrl->mcc_lock);
+ spin_lock_bh(&adapter->mcc_lock);
- wrb = wrb_from_mcc(&ctrl->mcc_obj.q);
+ wrb = wrb_from_mcc(&adapter->mcc_obj.q);
BUG_ON(!wrb);
req = embedded_payload(wrb);
@@ -937,9 +895,9 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en)
else
req->port0_promiscuous = en;
- be_mcc_notify_wait(ctrl);
+ be_mcc_notify_wait(adapter);
- spin_unlock_bh(&ctrl->mcc_lock);
+ spin_unlock_bh(&adapter->mcc_lock);
return 0;
}
@@ -947,16 +905,16 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en)
* Use MCC for this command as it may be called in BH context
* (mc == NULL) => multicast promiscous
*/
-int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id,
+int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
struct dev_mc_list *mc_list, u32 mc_count)
{
#define BE_MAX_MC 32 /* set mcast promisc if > 32 */
struct be_mcc_wrb *wrb;
struct be_cmd_req_mcast_mac_config *req;
- spin_lock_bh(&ctrl->mcc_lock);
+ spin_lock_bh(&adapter->mcc_lock);
- wrb = wrb_from_mcc(&ctrl->mcc_obj.q);
+ wrb = wrb_from_mcc(&adapter->mcc_obj.q);
BUG_ON(!wrb);
req = embedded_payload(wrb);
@@ -979,20 +937,20 @@ int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id,
req->promiscuous = 1;
}
- be_mcc_notify_wait(ctrl);
+ be_mcc_notify_wait(adapter);
- spin_unlock_bh(&ctrl->mcc_lock);
+ spin_unlock_bh(&adapter->mcc_lock);
return 0;
}
-int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc)
+int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_set_flow_control *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -1004,19 +962,19 @@ int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc)
req->tx_flow_control = cpu_to_le16((u16)tx_fc);
req->rx_flow_control = cpu_to_le16((u16)rx_fc);
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc)
+int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_get_flow_control *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -1025,7 +983,7 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req));
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_get_flow_control *resp =
embedded_payload(wrb);
@@ -1033,17 +991,17 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc)
*rx_fc = le16_to_cpu(resp->rx_flow_control);
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
-int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num)
+int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num)
{
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem);
struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ spin_lock(&adapter->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -1052,12 +1010,12 @@ int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
- status = be_mbox_db_ring(ctrl);
+ status = be_mbox_notify(adapter);
if (!status) {
struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
*port_num = le32_to_cpu(resp->phys_port);
}
- spin_unlock(&ctrl->mbox_lock);
+ spin_unlock(&adapter->mbox_lock);
return status;
}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 747626da7b4e..5c5de3540d20 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -69,7 +69,7 @@ enum {
#define CQE_STATUS_EXTD_MASK 0xFFFF
#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */
-struct be_mcc_cq_entry {
+struct be_mcc_compl {
u32 status; /* dword 0 */
u32 tag0; /* dword 1 */
u32 tag1; /* dword 2 */
@@ -106,7 +106,7 @@ struct be_async_event_link_state {
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
- struct be_mcc_cq_entry cqe;
+ struct be_mcc_compl compl;
};
#define CMD_SUBSYSTEM_COMMON 0x1
@@ -634,7 +634,6 @@ struct be_cmd_resp_link_status {
} __packed;
/******************** Get FW Version *******************/
-#define FW_VER_LEN 32
struct be_cmd_req_get_fw_version {
struct be_cmd_req_hdr hdr;
u8 rsvd0[FW_VER_LEN];
@@ -697,52 +696,52 @@ struct be_cmd_resp_query_fw_cfg {
u32 rsvd[26];
};
-extern int be_pci_fnum_get(struct be_ctrl_info *ctrl);
-extern int be_cmd_POST(struct be_ctrl_info *ctrl);
-extern int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr,
+extern int be_pci_fnum_get(struct be_adapter *adapter);
+extern int be_cmd_POST(struct be_adapter *adapter);
+extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
u8 type, bool permanent, u32 if_handle);
-extern int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr,
+extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
u32 if_id, u32 *pmac_id);
-extern int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id);
-extern int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 if_flags, u8 *mac,
+extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id);
+extern int be_cmd_if_create(struct be_adapter *adapter, u32 if_flags, u8 *mac,
bool pmac_invalid, u32 *if_handle, u32 *pmac_id);
-extern int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 if_handle);
-extern int be_cmd_eq_create(struct be_ctrl_info *ctrl,
+extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle);
+extern int be_cmd_eq_create(struct be_adapter *adapter,
struct be_queue_info *eq, int eq_delay);
-extern int be_cmd_cq_create(struct be_ctrl_info *ctrl,
+extern int be_cmd_cq_create(struct be_adapter *adapter,
struct be_queue_info *cq, struct be_queue_info *eq,
bool sol_evts, bool no_delay,
int num_cqe_dma_coalesce);
-extern int be_cmd_mccq_create(struct be_ctrl_info *ctrl,
+extern int be_cmd_mccq_create(struct be_adapter *adapter,
struct be_queue_info *mccq,
struct be_queue_info *cq);
-extern int be_cmd_txq_create(struct be_ctrl_info *ctrl,
+extern int be_cmd_txq_create(struct be_adapter *adapter,
struct be_queue_info *txq,
struct be_queue_info *cq);
-extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl,
+extern int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_queue_info *rxq, u16 cq_id,
u16 frag_size, u16 max_frame_size, u32 if_id,
u32 rss);
-extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
int type);
-extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl,
+extern int be_cmd_link_status_query(struct be_adapter *adapter,
bool *link_up);
-extern int be_cmd_reset(struct be_ctrl_info *ctrl);
-extern int be_cmd_get_stats(struct be_ctrl_info *ctrl,
+extern int be_cmd_reset(struct be_adapter *adapter);
+extern int be_cmd_get_stats(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
-extern int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver);
+extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver);
-extern int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd);
-extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id,
+extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd);
+extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id,
u16 *vtag_array, u32 num, bool untagged,
bool promiscuous);
-extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl,
+extern int be_cmd_promiscuous_config(struct be_adapter *adapter,
u8 port_num, bool en);
-extern int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id,
+extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
struct dev_mc_list *mc_list, u32 mc_count);
-extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl,
+extern int be_cmd_set_flow_control(struct be_adapter *adapter,
u32 tx_fc, u32 rx_fc);
-extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl,
+extern int be_cmd_get_flow_control(struct be_adapter *adapter,
u32 *tx_fc, u32 *rx_fc);
-extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num);
-extern void be_process_mcc(struct be_ctrl_info *ctrl);
+extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num);
+extern void be_process_mcc(struct be_adapter *adapter);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index cccc5419ad72..c480c19200d7 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -16,6 +16,7 @@
*/
#include "be.h"
+#include "be_cmds.h"
#include <linux/ethtool.h>
struct be_ethtool_stat {
@@ -127,8 +128,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
-
coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
@@ -144,14 +143,12 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
}
/*
- * This routine is used to set interrup coalescing delay *as well as*
- * the number of pkts to coalesce for LRO.
+ * This routine is used to set interrup coalescing delay
*/
static int
be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_ctrl_info *ctrl = &adapter->ctrl;
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
u32 tx_max, tx_min, tx_cur;
@@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
- adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
- if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
-
/* if AIC is being turned on now, start with an EQD of 0 */
if (rx_eq->enable_aic == 0 &&
coalesce->use_adaptive_rx_coalesce == 1) {
@@ -183,7 +176,7 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
if (tx_cur > BE_MAX_EQD)
tx_cur = BE_MAX_EQD;
if (tx_eq->cur_eqd != tx_cur) {
- status = be_cmd_modify_eqd(ctrl, tx_eq->q.id, tx_cur);
+ status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur);
if (!status)
tx_eq->cur_eqd = tx_cur;
}
@@ -203,7 +196,8 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
if (rx_cur > BE_MAX_EQD)
rx_cur = BE_MAX_EQD;
if (rx_eq->cur_eqd != rx_cur) {
- status = be_cmd_modify_eqd(ctrl, rx_eq->q.id, rx_cur);
+ status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
+ rx_cur);
if (!status)
rx_eq->cur_eqd = rx_cur;
}
@@ -317,8 +311,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
- be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause,
- &ecmd->rx_pause);
+ be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
ecmd->autoneg = 0;
}
@@ -331,7 +324,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
if (ecmd->autoneg != 0)
return -EINVAL;
- status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause,
+ status = be_cmd_set_flow_control(adapter, ecmd->tx_pause,
ecmd->rx_pause);
if (!status)
dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index 29c33c709c6d..d28f0c679bc8 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -51,9 +51,6 @@
* with the OS.
*/
#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
-/* PCI physical function number */
-#define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK 0x7 /* bits 26 - 28 */
-#define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT 26
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index c43f6a119295..ef82a52f3934 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -16,6 +16,7 @@
*/
#include "be.h"
+#include "be_cmds.h"
#include <asm/div64.h>
MODULE_VERSION(DRV_VER);
@@ -60,40 +61,39 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
return 0;
}
-static void be_intr_set(struct be_ctrl_info *ctrl, bool enable)
+static void be_intr_set(struct be_adapter *adapter, bool enable)
{
- u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
+ u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
u32 reg = ioread32(addr);
u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
- if (!enabled && enable) {
+
+ if (!enabled && enable)
reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
- } else if (enabled && !enable) {
+ else if (enabled && !enable)
reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
- } else {
- printk(KERN_WARNING DRV_NAME
- ": bad value in membar_int_ctrl reg=0x%x\n", reg);
+ else
return;
- }
+
iowrite32(reg, addr);
}
-static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted)
+static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
val |= qid & DB_RQ_RING_ID_MASK;
val |= posted << DB_RQ_NUM_POSTED_SHIFT;
- iowrite32(val, ctrl->db + DB_RQ_OFFSET);
+ iowrite32(val, adapter->db + DB_RQ_OFFSET);
}
-static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted)
+static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
val |= qid & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
- iowrite32(val, ctrl->db + DB_TXULP1_OFFSET);
+ iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
}
-static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid,
+static void be_eq_notify(struct be_adapter *adapter, u16 qid,
bool arm, bool clear_int, u16 num_popped)
{
u32 val = 0;
@@ -104,18 +104,17 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid,
val |= 1 << DB_EQ_CLR_SHIFT;
val |= 1 << DB_EQ_EVNT_SHIFT;
val |= num_popped << DB_EQ_NUM_POPPED_SHIFT;
- iowrite32(val, ctrl->db + DB_EQ_OFFSET);
+ iowrite32(val, adapter->db + DB_EQ_OFFSET);
}
-void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
- bool arm, u16 num_popped)
+void be_cq_notify(struct be_adapter *adapter, 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);
+ iowrite32(val, adapter->db + DB_CQ_OFFSET);
}
@@ -126,12 +125,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
int status = 0;
if (netif_running(netdev)) {
- status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle,
+ status = be_cmd_pmac_del(adapter, adapter->if_handle,
adapter->pmac_id);
if (status)
return status;
- status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data,
+ status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
adapter->if_handle, &adapter->pmac_id);
}
@@ -214,9 +213,8 @@ static void netdev_stats_update(struct be_adapter *adapter)
dev_stats->tx_window_errors = 0;
}
-void be_link_status_update(void *ctxt, bool link_up)
+void be_link_status_update(struct be_adapter *adapter, bool link_up)
{
- struct be_adapter *adapter = ctxt;
struct net_device *netdev = adapter->netdev;
/* If link came up or went down */
@@ -237,7 +235,6 @@ void be_link_status_update(void *ctxt, bool link_up)
/* Update the EQ delay n BE based on the RX frags consumed / sec */
static void be_rx_eqd_update(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
ulong now = jiffies;
@@ -270,7 +267,7 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
if (eqd < 10)
eqd = 0;
if (eqd != rx_eq->cur_eqd)
- be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd);
+ be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
rx_eq->cur_eqd = eqd;
}
@@ -412,8 +409,8 @@ static int make_tx_wrbs(struct be_adapter *adapter,
struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[i];
busaddr = pci_map_page(pdev, frag->page,
- frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, frag->size);
be_dws_cpu_to_le(wrb, sizeof(*wrb));
@@ -461,7 +458,7 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev)
stopped = true;
}
- be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt);
+ be_txq_notify(adapter, txq->id, wrb_cnt);
be_tx_stats_update(adapter, wrb_cnt, copied, stopped);
return NETDEV_TX_OK;
@@ -502,10 +499,10 @@ static void be_vid_config(struct net_device *netdev)
ntags++;
}
}
- be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle,
+ be_cmd_vlan_config(adapter, adapter->if_handle,
vtag, ntags, 1, 0);
} else {
- be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle,
+ be_cmd_vlan_config(adapter, adapter->if_handle,
NULL, 0, 1, 1);
}
}
@@ -515,13 +512,12 @@ static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp)
struct be_adapter *adapter = netdev_priv(netdev);
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- struct be_ctrl_info *ctrl = &adapter->ctrl;
- be_eq_notify(ctrl, rx_eq->q.id, false, false, 0);
- be_eq_notify(ctrl, tx_eq->q.id, false, false, 0);
+ be_eq_notify(adapter, rx_eq->q.id, false, false, 0);
+ be_eq_notify(adapter, tx_eq->q.id, false, false, 0);
adapter->vlan_grp = grp;
- be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
- be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
+ be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
+ be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
}
static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
@@ -548,10 +544,9 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
static void be_set_multicast_list(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_ctrl_info *ctrl = &adapter->ctrl;
if (netdev->flags & IFF_PROMISC) {
- be_cmd_promiscuous_config(ctrl, adapter->port_num, 1);
+ be_cmd_promiscuous_config(adapter, adapter->port_num, 1);
adapter->promiscuous = true;
goto done;
}
@@ -559,15 +554,15 @@ static void be_set_multicast_list(struct net_device *netdev)
/* BE was previously in promiscous mode; disable it */
if (adapter->promiscuous) {
adapter->promiscuous = false;
- be_cmd_promiscuous_config(ctrl, adapter->port_num, 0);
+ be_cmd_promiscuous_config(adapter, adapter->port_num, 0);
}
if (netdev->flags & IFF_ALLMULTI) {
- be_cmd_multicast_set(ctrl, adapter->if_handle, NULL, 0);
+ be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0);
goto done;
}
- be_cmd_multicast_set(ctrl, adapter->if_handle, netdev->mc_list,
+ be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list,
netdev->mc_count);
done:
return;
@@ -667,7 +662,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
struct be_queue_info *rxq = &adapter->rx_obj.q;
struct be_rx_page_info *page_info;
u16 rxq_idx, i, num_rcvd, j;
- u32 pktsize, hdr_len, curr_frag_len;
+ u32 pktsize, hdr_len, curr_frag_len, size;
u8 *start;
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -708,12 +703,13 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
}
/* More frags present for this completion */
- pktsize -= curr_frag_len; /* account for above copied frag */
+ size = pktsize;
for (i = 1, j = 0; i < num_rcvd; i++) {
+ size -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
page_info = get_rx_page_info(adapter, rxq_idx);
- curr_frag_len = min(pktsize, rx_frag_size);
+ curr_frag_len = min(size, rx_frag_size);
/* Coalesce all frags from the same physical page in one slot */
if (page_info->page_offset == 0) {
@@ -731,7 +727,6 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
skb_shinfo(skb)->frags[j].size += curr_frag_len;
skb->len += curr_frag_len;
skb->data_len += curr_frag_len;
- pktsize -= curr_frag_len;
memset(page_info, 0, sizeof(*page_info));
}
@@ -742,7 +737,7 @@ done:
return;
}
-/* Process the RX completion indicated by rxcp when LRO is disabled */
+/* Process the RX completion indicated by rxcp when GRO is disabled */
static void be_rx_compl_process(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
@@ -789,13 +784,14 @@ static void be_rx_compl_process(struct be_adapter *adapter,
return;
}
-/* Process the RX completion indicated by rxcp when LRO is enabled */
-static void be_rx_compl_process_lro(struct be_adapter *adapter,
+/* Process the RX completion indicated by rxcp when GRO is enabled */
+static void be_rx_compl_process_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
struct be_rx_page_info *page_info;
- struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+ struct sk_buff *skb = NULL;
struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_eq_obj *eq_obj = &adapter->rx_eq;
u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
u16 i, rxq_idx = 0, vid, j;
@@ -804,6 +800,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+ skb = napi_get_frags(&eq_obj->napi);
+ if (!skb) {
+ be_rx_compl_discard(adapter, rxcp);
+ return;
+ }
+
remaining = pkt_size;
for (i = 0, j = -1; i < num_rcvd; i++) {
page_info = get_rx_page_info(adapter, rxq_idx);
@@ -814,13 +816,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (i == 0 || page_info->page_offset == 0) {
/* First frag or Fresh page */
j++;
- rx_frags[j].page = page_info->page;
- rx_frags[j].page_offset = page_info->page_offset;
- rx_frags[j].size = 0;
+ skb_shinfo(skb)->frags[j].page = page_info->page;
+ skb_shinfo(skb)->frags[j].page_offset =
+ page_info->page_offset;
+ skb_shinfo(skb)->frags[j].size = 0;
} else {
put_page(page_info->page);
}
- rx_frags[j].size += curr_frag_len;
+ skb_shinfo(skb)->frags[j].size += curr_frag_len;
remaining -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
@@ -828,9 +831,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
}
BUG_ON(j > MAX_SKB_FRAGS);
+ skb_shinfo(skb)->nr_frags = j + 1;
+ skb->len = pkt_size;
+ skb->data_len = pkt_size;
+ skb->truesize += pkt_size;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
if (likely(!vlanf)) {
- lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
- pkt_size, NULL, 0);
+ napi_gro_frags(&eq_obj->napi);
} else {
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
vid = be16_to_cpu(vid);
@@ -838,9 +846,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (!adapter->vlan_grp || adapter->num_vlans == 0)
return;
- lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr,
- rx_frags, pkt_size, pkt_size, adapter->vlan_grp,
- vid, NULL, 0);
+ vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
}
be_rx_stats_update(adapter, pkt_size, num_rcvd);
@@ -931,7 +937,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
if (posted) {
atomic_add(posted, &rxq->used);
- be_rxq_notify(&adapter->ctrl, rxq->id, posted);
+ be_rxq_notify(adapter, rxq->id, posted);
} else if (atomic_read(&rxq->used) == 0) {
/* Let be_worker replenish when memory is available */
adapter->rx_post_starved = true;
@@ -999,7 +1005,7 @@ static void be_rx_q_clean(struct be_adapter *adapter)
while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
be_rx_compl_discard(adapter, rxcp);
be_rx_compl_reset(rxcp);
- be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1);
+ be_cq_notify(adapter, rx_cq->id, true, 1);
}
/* Then free posted rx buffer that were not used */
@@ -1032,16 +1038,15 @@ static void be_tx_q_clean(struct be_adapter *adapter)
static void be_mcc_queues_destroy(struct be_adapter *adapter)
{
struct be_queue_info *q;
- struct be_ctrl_info *ctrl = &adapter->ctrl;
- q = &ctrl->mcc_obj.q;
+ q = &adapter->mcc_obj.q;
if (q->created)
- be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_MCCQ);
be_queue_free(adapter, q);
- q = &ctrl->mcc_obj.cq;
+ q = &adapter->mcc_obj.cq;
if (q->created)
- be_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
be_queue_free(adapter, q);
}
@@ -1049,25 +1054,24 @@ static void be_mcc_queues_destroy(struct be_adapter *adapter)
static int be_mcc_queues_create(struct be_adapter *adapter)
{
struct be_queue_info *q, *cq;
- struct be_ctrl_info *ctrl = &adapter->ctrl;
/* Alloc MCC compl queue */
- cq = &ctrl->mcc_obj.cq;
+ cq = &adapter->mcc_obj.cq;
if (be_queue_alloc(adapter, cq, MCC_CQ_LEN,
- sizeof(struct be_mcc_cq_entry)))
+ sizeof(struct be_mcc_compl)))
goto err;
/* Ask BE to create MCC compl queue; share TX's eq */
- if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0))
+ if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0))
goto mcc_cq_free;
/* Alloc MCC queue */
- q = &ctrl->mcc_obj.q;
+ q = &adapter->mcc_obj.q;
if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb)))
goto mcc_cq_destroy;
/* Ask BE to create MCC queue */
- if (be_cmd_mccq_create(ctrl, q, cq))
+ if (be_cmd_mccq_create(adapter, q, cq))
goto mcc_q_free;
return 0;
@@ -1075,7 +1079,7 @@ static int be_mcc_queues_create(struct be_adapter *adapter)
mcc_q_free:
be_queue_free(adapter, q);
mcc_cq_destroy:
- be_cmd_q_destroy(ctrl, cq, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
mcc_cq_free:
be_queue_free(adapter, cq);
err:
@@ -1088,7 +1092,7 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
q = &adapter->tx_obj.q;
if (q->created) {
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_TXQ);
/* No more tx completions can be rcvd now; clean up if there
* are any pending completions or pending tx requests */
@@ -1098,12 +1102,12 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
q = &adapter->tx_obj.cq;
if (q->created)
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
be_queue_free(adapter, q);
q = &adapter->tx_eq.q;
if (q->created)
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_EQ);
be_queue_free(adapter, q);
}
@@ -1121,7 +1125,7 @@ static int be_tx_queues_create(struct be_adapter *adapter)
return -1;
/* Ask BE to create Tx Event queue */
- if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd))
+ if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
goto tx_eq_free;
/* Alloc TX eth compl queue */
cq = &adapter->tx_obj.cq;
@@ -1130,7 +1134,7 @@ static int be_tx_queues_create(struct be_adapter *adapter)
goto tx_eq_destroy;
/* Ask BE to create Tx eth compl queue */
- if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3))
+ if (be_cmd_cq_create(adapter, cq, eq, false, false, 3))
goto tx_cq_free;
/* Alloc TX eth queue */
@@ -1139,18 +1143,18 @@ static int be_tx_queues_create(struct be_adapter *adapter)
goto tx_cq_destroy;
/* Ask BE to create Tx eth queue */
- if (be_cmd_txq_create(&adapter->ctrl, q, cq))
+ if (be_cmd_txq_create(adapter, q, cq))
goto tx_q_free;
return 0;
tx_q_free:
be_queue_free(adapter, q);
tx_cq_destroy:
- be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
tx_cq_free:
be_queue_free(adapter, cq);
tx_eq_destroy:
- be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ);
+ be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
tx_eq_free:
be_queue_free(adapter, eq);
return -1;
@@ -1162,19 +1166,19 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
q = &adapter->rx_obj.q;
if (q->created) {
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
be_rx_q_clean(adapter);
}
be_queue_free(adapter, q);
q = &adapter->rx_obj.cq;
if (q->created)
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
be_queue_free(adapter, q);
q = &adapter->rx_eq.q;
if (q->created)
- be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ);
+ be_cmd_q_destroy(adapter, q, QTYPE_EQ);
be_queue_free(adapter, q);
}
@@ -1183,7 +1187,6 @@ static int be_rx_queues_create(struct be_adapter *adapter)
struct be_queue_info *eq, *q, *cq;
int rc;
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
adapter->rx_eq.max_eqd = BE_MAX_EQD;
adapter->rx_eq.min_eqd = 0;
@@ -1198,7 +1201,7 @@ static int be_rx_queues_create(struct be_adapter *adapter)
return rc;
/* Ask BE to create Rx Event queue */
- rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd);
+ rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd);
if (rc)
goto rx_eq_free;
@@ -1210,7 +1213,7 @@ static int be_rx_queues_create(struct be_adapter *adapter)
goto rx_eq_destroy;
/* Ask BE to create Rx eth compl queue */
- rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3);
+ rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
if (rc)
goto rx_cq_free;
@@ -1221,7 +1224,7 @@ static int be_rx_queues_create(struct be_adapter *adapter)
goto rx_cq_destroy;
/* Ask BE to create Rx eth queue */
- rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size,
+ rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false);
if (rc)
goto rx_q_free;
@@ -1230,11 +1233,11 @@ static int be_rx_queues_create(struct be_adapter *adapter)
rx_q_free:
be_queue_free(adapter, q);
rx_cq_destroy:
- be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ);
+ be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
rx_cq_free:
be_queue_free(adapter, cq);
rx_eq_destroy:
- be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ);
+ be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
rx_eq_free:
be_queue_free(adapter, eq);
return rc;
@@ -1254,8 +1257,7 @@ static bool event_get(struct be_eq_obj *eq_obj, u16 *rid)
return true;
}
-static int event_handle(struct be_ctrl_info *ctrl,
- struct be_eq_obj *eq_obj)
+static int event_handle(struct be_adapter *adapter, struct be_eq_obj *eq_obj)
{
u16 rid = 0, num = 0;
@@ -1263,7 +1265,7 @@ static int event_handle(struct be_ctrl_info *ctrl,
num++;
/* We can see an interrupt and no event */
- be_eq_notify(ctrl, eq_obj->q.id, true, true, num);
+ be_eq_notify(adapter, eq_obj->q.id, true, true, num);
if (num)
napi_schedule(&eq_obj->napi);
@@ -1273,25 +1275,24 @@ static int event_handle(struct be_ctrl_info *ctrl,
static irqreturn_t be_intx(int irq, void *dev)
{
struct be_adapter *adapter = dev;
- struct be_ctrl_info *ctrl = &adapter->ctrl;
- int isr;
+ int isr;
- isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
- ctrl->pci_func * CEV_ISR_SIZE);
+ isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
+ be_pci_func(adapter) * CEV_ISR_SIZE);
if (!isr)
- return IRQ_NONE;
+ return IRQ_NONE;
- event_handle(ctrl, &adapter->tx_eq);
- event_handle(ctrl, &adapter->rx_eq);
+ event_handle(adapter, &adapter->tx_eq);
+ event_handle(adapter, &adapter->rx_eq);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
static irqreturn_t be_msix_rx(int irq, void *dev)
{
struct be_adapter *adapter = dev;
- event_handle(&adapter->ctrl, &adapter->rx_eq);
+ event_handle(adapter, &adapter->rx_eq);
return IRQ_HANDLED;
}
@@ -1300,12 +1301,12 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
{
struct be_adapter *adapter = dev;
- event_handle(&adapter->ctrl, &adapter->tx_eq);
+ event_handle(adapter, &adapter->tx_eq);
return IRQ_HANDLED;
}
-static inline bool do_lro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
@@ -1314,8 +1315,7 @@ static inline bool do_lro(struct be_adapter *adapter,
if (err)
drvr_stats(adapter)->be_rxcp_err++;
- return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
- false : true;
+ return (tcp_frame && !err) ? true : false;
}
int be_poll_rx(struct napi_struct *napi, int budget)
@@ -1332,16 +1332,14 @@ int be_poll_rx(struct napi_struct *napi, int budget)
if (!rxcp)
break;
- if (do_lro(adapter, rxcp))
- be_rx_compl_process_lro(adapter, rxcp);
+ if (do_gro(adapter, rxcp))
+ be_rx_compl_process_gro(adapter, rxcp);
else
be_rx_compl_process(adapter, rxcp);
be_rx_compl_reset(rxcp);
}
- lro_flush_all(&adapter->rx_obj.lro_mgr);
-
/* Refill the queue */
if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
be_post_rx_frags(adapter);
@@ -1349,10 +1347,10 @@ int be_poll_rx(struct napi_struct *napi, int budget)
/* All consumed */
if (work_done < budget) {
napi_complete(napi);
- be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done);
+ be_cq_notify(adapter, rx_cq->id, true, work_done);
} else {
/* More to be consumed; continue with interrupts disabled */
- be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done);
+ be_cq_notify(adapter, rx_cq->id, false, work_done);
}
return work_done;
}
@@ -1373,7 +1371,7 @@ void be_process_tx(struct be_adapter *adapter)
}
if (num_cmpl) {
- be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
+ be_cq_notify(adapter, tx_cq->id, true, num_cmpl);
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs.
@@ -1401,7 +1399,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
be_process_tx(adapter);
- be_process_mcc(&adapter->ctrl);
+ be_process_mcc(adapter);
return 1;
}
@@ -1413,7 +1411,7 @@ static void be_worker(struct work_struct *work)
int status;
/* Get Stats */
- status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd);
+ status = be_cmd_get_stats(adapter, &adapter->stats.cmd);
if (!status)
netdev_stats_update(adapter);
@@ -1447,8 +1445,7 @@ static void be_msix_enable(struct be_adapter *adapter)
static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
{
- return adapter->msix_entries[eq_id -
- 8 * adapter->ctrl.pci_func].vector;
+ return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector;
}
static int be_msix_register(struct be_adapter *adapter)
@@ -1533,7 +1530,6 @@ done:
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_ctrl_info *ctrl = &adapter->ctrl;
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
bool link_up;
@@ -1547,16 +1543,16 @@ static int be_open(struct net_device *netdev)
be_irq_register(adapter);
- be_intr_set(ctrl, true);
+ be_intr_set(adapter, true);
/* The evt queues are created in unarmed state; arm them */
- be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
- be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
+ be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
+ be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
/* Rx compl queue may be in unarmed state; rearm it */
- be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
+ be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0);
- status = be_cmd_link_status_query(ctrl, &link_up);
+ status = be_cmd_link_status_query(adapter, &link_up);
if (status)
return status;
be_link_status_update(adapter, link_up);
@@ -1567,7 +1563,6 @@ static int be_open(struct net_device *netdev)
static int be_setup(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
struct net_device *netdev = adapter->netdev;
u32 if_flags;
int status;
@@ -1575,7 +1570,7 @@ static int be_setup(struct be_adapter *adapter)
if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS |
BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED |
BE_IF_FLAGS_PASS_L3L4_ERRORS;
- status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr,
+ status = be_cmd_if_create(adapter, if_flags, netdev->dev_addr,
false/* pmac_invalid */, &adapter->if_handle,
&adapter->pmac_id);
if (status != 0)
@@ -1583,7 +1578,7 @@ static int be_setup(struct be_adapter *adapter)
be_vid_config(netdev);
- status = be_cmd_set_flow_control(ctrl, true, true);
+ status = be_cmd_set_flow_control(adapter, true, true);
if (status != 0)
goto if_destroy;
@@ -1606,19 +1601,17 @@ rx_qs_destroy:
tx_qs_destroy:
be_tx_queues_destroy(adapter);
if_destroy:
- be_cmd_if_destroy(ctrl, adapter->if_handle);
+ be_cmd_if_destroy(adapter, adapter->if_handle);
do_none:
return status;
}
static int be_clear(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
-
be_rx_queues_destroy(adapter);
be_tx_queues_destroy(adapter);
- be_cmd_if_destroy(ctrl, adapter->if_handle);
+ be_cmd_if_destroy(adapter, adapter->if_handle);
be_mcc_queues_destroy(adapter);
return 0;
@@ -1627,7 +1620,6 @@ static int be_clear(struct be_adapter *adapter)
static int be_close(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_ctrl_info *ctrl = &adapter->ctrl;
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
int vec;
@@ -1638,7 +1630,7 @@ static int be_close(struct net_device *netdev)
netif_carrier_off(netdev);
adapter->link_up = false;
- be_intr_set(ctrl, false);
+ be_intr_set(adapter, false);
if (adapter->msix_enabled) {
vec = be_msix_vec_get(adapter, tx_eq->q.id);
@@ -1656,57 +1648,6 @@ static int be_close(struct net_device *netdev)
return 0;
}
-static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
- void **ip_hdr, void **tcpudp_hdr,
- u64 *hdr_flags, void *priv)
-{
- struct ethhdr *eh;
- struct vlan_ethhdr *veh;
- struct iphdr *iph;
- u8 *va = page_address(frag->page) + frag->page_offset;
- unsigned long ll_hlen;
-
- prefetch(va);
- eh = (struct ethhdr *)va;
- *mac_hdr = eh;
- ll_hlen = ETH_HLEN;
- if (eh->h_proto != htons(ETH_P_IP)) {
- if (eh->h_proto == htons(ETH_P_8021Q)) {
- veh = (struct vlan_ethhdr *)va;
- if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
- return -1;
-
- ll_hlen += VLAN_HLEN;
- } else {
- return -1;
- }
- }
- *hdr_flags = LRO_IPV4;
- iph = (struct iphdr *)(va + ll_hlen);
- *ip_hdr = iph;
- if (iph->protocol != IPPROTO_TCP)
- return -1;
- *hdr_flags |= LRO_TCP;
- *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
-
- return 0;
-}
-
-static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
-{
- struct net_lro_mgr *lro_mgr;
-
- lro_mgr = &adapter->rx_obj.lro_mgr;
- lro_mgr->dev = netdev;
- lro_mgr->features = LRO_F_NAPI;
- lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
- lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
- lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
- lro_mgr->lro_arr = adapter->rx_obj.lro_desc;
- lro_mgr->get_frag_header = be_get_frag_header;
- lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
-}
-
static struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
@@ -1727,7 +1668,7 @@ static void be_netdev_init(struct net_device *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_IPV6_CSUM | NETIF_F_GRO;
netdev->flags |= IFF_MULTICAST;
@@ -1737,8 +1678,6 @@ static void be_netdev_init(struct net_device *netdev)
SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
- be_lro_init(adapter, netdev);
-
netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
BE_NAPI_WEIGHT);
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
@@ -1750,13 +1689,12 @@ static void be_netdev_init(struct net_device *netdev)
static void be_unmap_pci_bars(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
- if (ctrl->csr)
- iounmap(ctrl->csr);
- if (ctrl->db)
- iounmap(ctrl->db);
- if (ctrl->pcicfg)
- iounmap(ctrl->pcicfg);
+ if (adapter->csr)
+ iounmap(adapter->csr);
+ if (adapter->db)
+ iounmap(adapter->db);
+ if (adapter->pcicfg)
+ iounmap(adapter->pcicfg);
}
static int be_map_pci_bars(struct be_adapter *adapter)
@@ -1767,19 +1705,19 @@ static int be_map_pci_bars(struct be_adapter *adapter)
pci_resource_len(adapter->pdev, 2));
if (addr == NULL)
return -ENOMEM;
- adapter->ctrl.csr = addr;
+ adapter->csr = addr;
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4),
128 * 1024);
if (addr == NULL)
goto pci_map_err;
- adapter->ctrl.db = addr;
+ adapter->db = addr;
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1),
pci_resource_len(adapter->pdev, 1));
if (addr == NULL)
goto pci_map_err;
- adapter->ctrl.pcicfg = addr;
+ adapter->pcicfg = addr;
return 0;
pci_map_err:
@@ -1790,7 +1728,7 @@ pci_map_err:
static void be_ctrl_cleanup(struct be_adapter *adapter)
{
- struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced;
+ struct be_dma_mem *mem = &adapter->mbox_mem_alloced;
be_unmap_pci_bars(adapter);
@@ -1799,14 +1737,11 @@ static void be_ctrl_cleanup(struct be_adapter *adapter)
mem->va, mem->dma);
}
-/* Initialize the mbox required to send cmds to BE */
static int be_ctrl_init(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
- struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced;
- struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem;
+ struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced;
+ struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem;
int status;
- u32 val;
status = be_map_pci_bars(adapter);
if (status)
@@ -1823,16 +1758,10 @@ static int be_ctrl_init(struct be_adapter *adapter)
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);
- spin_lock_init(&ctrl->mcc_lock);
- spin_lock_init(&ctrl->mcc_cq_lock);
-
- ctrl->async_cb = be_link_status_update;
- ctrl->adapter_ctxt = adapter;
+ spin_lock_init(&adapter->mbox_lock);
+ spin_lock_init(&adapter->mcc_lock);
+ spin_lock_init(&adapter->mcc_cq_lock);
- val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
- ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) &
- MEMBAR_CTRL_INT_CTRL_PFUNC_MASK;
return 0;
}
@@ -1886,18 +1815,17 @@ static void __devexit be_remove(struct pci_dev *pdev)
static int be_hw_up(struct be_adapter *adapter)
{
- struct be_ctrl_info *ctrl = &adapter->ctrl;
int status;
- status = be_cmd_POST(ctrl);
+ status = be_cmd_POST(adapter);
if (status)
return status;
- status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver);
+ status = be_cmd_get_fw_ver(adapter, adapter->fw_ver);
if (status)
return status;
- status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num);
+ status = be_cmd_query_fw_cfg(adapter, &adapter->port_num);
return status;
}
@@ -1907,7 +1835,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
int status = 0;
struct be_adapter *adapter;
struct net_device *netdev;
- struct be_ctrl_info *ctrl;
u8 mac[ETH_ALEN];
status = pci_enable_device(pdev);
@@ -1942,7 +1869,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
}
}
- ctrl = &adapter->ctrl;
status = be_ctrl_init(adapter);
if (status)
goto free_netdev;
@@ -1955,7 +1881,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status)
goto stats_clean;
- status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK,
+ status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK,
true /* permanent */, 0);
if (status)
goto stats_clean;
@@ -2054,12 +1980,6 @@ static int __init be_init_module(void)
" Using 2048\n");
rx_frag_size = 2048;
}
- /* Ensure rx_frag_size is aligned to chache line */
- if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) {
- printk(KERN_WARNING DRV_NAME
- " : Bad module param rx_frag_size. Using 2048\n");
- rx_frag_size = 2048;
- }
return pci_register_driver(&be_driver);
}
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index c15fc281f79f..f580b21eabd1 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -656,7 +656,7 @@ out:
dev->trans_start = jiffies;
dev->stats.tx_packets++;
dev->stats.tx_bytes += (skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
static void bfin_mac_rx(struct net_device *dev)
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 206144f2470f..406f06424251 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1489,7 +1489,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev)
struct bmac_data *bp = netdev_priv(dev);
skb_queue_tail(bp->queue, skb);
bmac_start(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void bmac_tx_timeout(unsigned long data)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b70cc99962fc..756d4b4f0a9f 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -8023,6 +8023,13 @@ static const struct net_device_ops bnx2_netdev_ops = {
#endif
};
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#ifdef BCM_VLAN
+ dev->vlan_features |= flags;
+#endif
+}
+
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -8064,16 +8071,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(dev->perm_addr, bp->mac_addr, 6);
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_IPV6_CSUM;
-
+ vlan_features_add(dev, NETIF_F_IPV6_CSUM);
+ }
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_TSO6;
-
+ vlan_features_add(dev, NETIF_F_TSO6);
+ }
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
goto error;
@@ -8188,6 +8199,11 @@ static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
rtnl_lock();
netif_device_detach(dev);
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
if (netif_running(dev)) {
bnx2_netif_stop(bp);
del_timer_sync(&bp->timer);
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 85a737c5c23f..8bd80fca9788 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -160,7 +160,7 @@ struct sw_rx_page {
#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT)
#define SGE_PAGE_SIZE PAGE_SIZE
#define SGE_PAGE_SHIFT PAGE_SHIFT
-#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr)
+#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
@@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 03c62421d999..7de83c4a557a 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -91,6 +91,21 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_HIDE_PORT1 0x00002000
+ /* The fan failure mechanism is usually related to the PHY type
+ since the power consumption of the board is determined by the PHY.
+ Currently, fan is required for most designs with SFX7101, BCM8727
+ and BCM8481. If a fan is not required for a board which uses one
+ of those PHYs, this field should be set to "Disabled". If a fan is
+ required for a different PHY type, this option should be set to
+ "Enabled".
+ The fan failure indication is expected on
+ SPIO5 */
+#define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000
+#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19
+#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000
+#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000
+#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000
+
u32 power_dissipated; /* 0x11c */
#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000
#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24
@@ -233,6 +248,8 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00
@@ -343,10 +360,16 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEATURE_MBA_ENABLED 0x02000000
#define PORT_FEATURE_MFW_ENABLED 0x04000000
- /* Check the optic vendor via i2c before allowing it to be used by
- SW */
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000
+ /* Reserved bits: 28-29 */
+ /* Check the optic vendor via i2c against a list of approved modules
+ in a separate nvram image */
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xE0000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT 0x00000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER 0x20000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000
+
u32 wol_config;
/* Default is used when driver sets to "auto" mode */
@@ -642,6 +665,12 @@ struct drv_func_mb {
#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
+ /*
+ * The optic module verification commands requris bootcode
+ * v5.0.6 or later
+ */
+#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000
+#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006
#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000
#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000
@@ -676,6 +705,9 @@ struct drv_func_mb {
#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000
#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000
#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000
+#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000
+#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000
+#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000
#define FW_MSG_CODE_LIC_CHALLENGE 0xff010000
#define FW_MSG_CODE_LIC_RESPONSE 0xff020000
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index 2ee581a2cdec..1f17334c8f02 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -139,21 +139,26 @@
#define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
#define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
+
+#define SFP_EEPROM_COMP_CODE_ADDR 0x3
+ #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
+ #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
+ #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
+
#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
-#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
-#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+
#define SFP_EEPROM_OPTIONS_ADDR 0x40
#define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
#define SFP_EEPROM_OPTIONS_SIZE 2
-#define SFP_MODULE_TYPE_UNKNOWN 0x0
-#define SFP_MODULE_TYPE_LC 0x1
-#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
-#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
+#define EDC_MODE_LINEAR 0x0022
+#define EDC_MODE_LIMITING 0x0044
+#define EDC_MODE_PASSIVE_DAC 0x0055
+
+
-#define SFP_LIMITING_MODE_VALUE 0x0044
/**********************************************************/
/* INTERFACE */
/**********************************************************/
@@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* All MDC/MDIO is directed through single EMAC */
if (REG_RD(bp, NIG_REG_PORT_SWAP))
emac_base = GRCBASE_EMAC0;
@@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0xa040);
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* Restore normal power mode*/
@@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
}
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 ext_phy_type,
+ u32 shmem_base)
{
/* Boot port from external ROM */
/* EDC grst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* ucode reboot and rst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
0x008c);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0001);
/* Reset internal microprocessor */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Release srst bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Clear ser_boot_ctl bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0000);
bnx2x_save_bcm_spirom_ver(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
shmem_base);
}
+static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ shmem_base);
+}
+
+static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ shmem_base);
+
+}
+
static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
{
struct bnx2x *bp = params->bp;
@@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+ /* Set PLL register value to be same like in P13 ver */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL2,
+ MDIO_PMA_REG_PLL_CTRL,
0x73A0);
/* Clear soft reset.
@@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
params->shmem_base);
}
-static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u8 tx_en)
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
+ u32 ext_phy_type, u8 ext_phy_addr,
+ u8 tx_en)
{
u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
tx_en, port);
/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
@@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
val |= (1<<15);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
val);
}
-
-static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf) {
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
struct bnx2x *bp = params->bp;
- u16 val, i;
+ u16 val = 0;
+ u16 i;
u8 port = params->port;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
@@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
(byte_cnt | 0xa000));
/* Set the read command address */
@@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr);
/* Activate read command */
@@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
0x2c0f);
/* Wait up to 500us for command complete status */
@@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
break;
udelay(5);
}
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK,
"Got bad status 0x%x when reading from SFP+ EEPROM\n",
- (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
return -EINVAL;
}
@@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
return 0;;
msleep(1);
}
return -EINVAL;
}
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
+ struct bnx2x *bp = params->bp;
+ u16 val, i;
+ u8 port = params->port;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (byte_cnt > 16) {
+ DP(NETIF_MSG_LINK, "Reading from eeprom is"
+ " is limited to 0xf\n");
+ return -EINVAL;
+ }
+
+ /* Need to read from 1.8000 to clear it */
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ &val);
-static u8 bnx2x_get_sfp_module_type(struct link_params *params,
- u8 *module_type)
+ /* Set the read command byte count */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+ ((byte_cnt < 2) ? 2 : byte_cnt));
+
+ /* Set the read command address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+ addr);
+ /* Set the destination address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ 0x8004,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
+
+ /* Activate read command */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ 0x8002);
+ /* Wait appropriate time for two-wire command to finish before
+ polling the status register */
+ msleep(1);
+
+ /* Wait up to 500us for command complete status */
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
+ break;
+ udelay(5);
+ }
+
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
+ DP(NETIF_MSG_LINK,
+ "Got bad status 0x%x when reading from SFP+ EEPROM\n",
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
+ return -EINVAL;
+ }
+
+ /* Read the buffer */
+ for (i = 0; i < byte_cnt; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
+ o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
+ }
+
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
+ return 0;;
+ msleep(1);
+ }
+
+ return -EINVAL;
+}
+
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf)
+{
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ return -EINVAL;
+}
+
+static u8 bnx2x_get_edc_mode(struct link_params *params,
+ u16 *edc_mode)
{
struct bnx2x *bp = params->bp;
- u8 val;
- *module_type = SFP_MODULE_TYPE_UNKNOWN;
+ u8 val, check_limiting_mode = 0;
+ *edc_mode = EDC_MODE_LIMITING;
/* First check for copper cable */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_CON_TYPE_ADDR,
1,
&val) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
+ DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
return -EINVAL;
}
@@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
- *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
+ check_limiting_mode = 1;
} else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
DP(NETIF_MSG_LINK, "Passive Copper"
" cable detected\n");
- *module_type =
- SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
+ *edc_mode =
+ EDC_MODE_PASSIVE_DAC;
} else {
DP(NETIF_MSG_LINK, "Unknown copper-cable-"
"type 0x%x !!!\n", copper_module_type);
@@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
}
case SFP_EEPROM_CON_TYPE_VAL_LC:
DP(NETIF_MSG_LINK, "Optic module detected\n");
- *module_type = SFP_MODULE_TYPE_LC;
+ check_limiting_mode = 1;
break;
default:
@@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
val);
return -EINVAL;
}
+
+ if (check_limiting_mode) {
+ u8 options[SFP_EEPROM_OPTIONS_SIZE];
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_OPTIONS_ADDR,
+ SFP_EEPROM_OPTIONS_SIZE,
+ options) != 0) {
+ DP(NETIF_MSG_LINK, "Failed to read Option"
+ " field from module EEPROM\n");
+ return -EINVAL;
+ }
+ if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
+ *edc_mode = EDC_MODE_LINEAR;
+ else
+ *edc_mode = EDC_MODE_LIMITING;
+ }
+ DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
return 0;
}
-
/* This function read the relevant field from the module ( SFP+ ),
and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params,
- u8 module_type)
+static u8 bnx2x_verify_sfp_module(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 *str_p, *tmp_buf;
- u16 i;
-
-#define COMPLIANCE_STR_CNT 6
- u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
- "FINISAR CORP. ", "Amphenol"};
- u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
- /* Passive Copper cables are allowed to participate,
- since the module is hardwired to the copper cable */
-
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
+ u32 val;
+ u32 fw_resp;
+ char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
+ char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
+
+ val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
return 0;
}
- if (module_type != SFP_MODULE_TYPE_LC) {
- DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
+ /* Ask the FW to validate the module */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+ DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+ "verification\n");
+ return -EINVAL;
+ }
+
+ fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+ if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
+ DP(NETIF_MSG_LINK, "Approved module\n");
return 0;
}
- /* In case of non copper cable or Active copper cable,
- verify that the SFP+ module is compliant with this board*/
+ /* format the warning message */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
- buf) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
- " module EEPROM\n");
- return -EINVAL;
- }
- for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
- str_p = compliance_str[i];
- tmp_buf = buf;
- while (*str_p) {
- if ((u8)(*tmp_buf) != (u8)(*str_p))
- break;
- str_p++;
- tmp_buf++;
- }
+ (u8 *)vendor_name))
+ vendor_name[0] = '\0';
+ else
+ vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_PART_NO_ADDR,
+ SFP_EEPROM_PART_NO_SIZE,
+ (u8 *)vendor_pn))
+ vendor_pn[0] = '\0';
+ else
+ vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
- if (!(*str_p)) {
- DP(NETIF_MSG_LINK, "SFP+ Module verified, "
- "index=%x\n", i);
- return 0;
- }
- }
- DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
+ printk(KERN_INFO PFX "Warning: "
+ "Unqualified SFP+ module "
+ "detected on %s, Port %d from %s part number %s\n"
+ , bp->dev->name, params->port,
+ vendor_name, vendor_pn);
return -EINVAL;
}
-
static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
- u8 module_type)
+ u16 edc_mode)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
- u8 options[SFP_EEPROM_OPTIONS_SIZE];
- u8 limiting_mode;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u16 cur_limiting_mode;
- if (bnx2x_read_sfp_module_eeprom(params,
- SFP_EEPROM_OPTIONS_ADDR,
- SFP_EEPROM_OPTIONS_SIZE,
- options) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Option field from"
- " module EEPROM\n");
- return -EINVAL;
- }
- limiting_mode = !(options[0] &
- SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
bnx2x_cl45_read(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
@@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
cur_limiting_mode);
- if (limiting_mode &&
- (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
+ if (edc_mode == EDC_MODE_LIMITING) {
DP(NETIF_MSG_LINK,
- "Module options = 0x%x.Setting LIMITING MODE\n",
- options[0]);
+ "Setting LIMITING MODE\n");
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
- SFP_LIMITING_MODE_VALUE);
+ EDC_MODE_LIMITING);
} else { /* LRM mode ( default )*/
- DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
- options[0]);
+ DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
/* Changing to LRM mode takes quite few seconds.
So do it only if current mode is limiting
( default is LRM )*/
- if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
+ if (cur_limiting_mode != EDC_MODE_LIMITING)
return 0;
bnx2x_cl45_write(bp, port,
@@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
return 0;
}
+static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+ u16 edc_mode)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u16 phy_identifier;
+ u16 rom_ver2_val;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &phy_identifier);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier & ~(1<<9)));
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ &rom_ver2_val);
+ /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier | (1<<9)));
+
+ return 0;
+}
+
+
static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
{
u8 val;
@@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
return -EINVAL;
}
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+ struct link_params *params,
+ u8 ext_phy_addr, u8 is_power_up) {
+ /* Make sure GPIOs are not using for LED mode */
+ u16 val;
+ u8 port = params->port;
+ /*
+ * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+ * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+ * output
+ * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+ * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+ * where the 1st bit is the over-current(only input), and 2nd bit is
+ * for power( only output )
+ */
+
+ /*
+ * In case of NOC feature is disabled and power is up, set GPIO control
+ * as input to enable listening of over-current indication
+ */
+
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
+ val = (1<<4);
+ else
+ /*
+ * Set GPIO control to OUTPUT, and set the power bit
+ * to according to the is_power_up
+ */
+ val = ((!(is_power_up)) << 1);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ val);
+}
+
static u8 bnx2x_sfp_module_detection(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 module_type;
+ u16 edc_mode;
+ u8 rc = 0;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
- DP(NETIF_MSG_LINK, "Module detection is not required "
- "for this phy\n");
- return 0;
- }
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port);
- if (bnx2x_get_sfp_module_type(params,
- &module_type) != 0) {
+ if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
- /* In case module detection is disabled, it trys to
- link up. The issue that can happen here is LRM /
- LIMITING mode which set according to the module-type*/
- DP(NETIF_MSG_LINK, "Unable to read module-type."
- "Probably due to Bit Stretching."
- " Proceeding...\n");
- } else {
- return -EINVAL;
- }
- } else if (bnx2x_verify_sfp_module(params, module_type) !=
+ return -EINVAL;
+ } else if (bnx2x_verify_sfp_module(params) !=
0) {
/* check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
+ rc = -EINVAL;
/* Turn on fault module-detected led */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
- return -EINVAL;
+ if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+ ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
+ /* Shutdown SFP+ module */
+ DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
+ bnx2x_8727_power_module(bp, params,
+ ext_phy_addr, 0);
+ return rc;
+ }
+ } else {
+ /* Turn off fault module-detected led */
+ DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_LOW,
+ params->port);
}
- /* Turn off fault module-detected led */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_LOW,
- params->port);
+ /* power up the SFP module */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
- /* Check and set limiting mode / LRM mode */
- bnx2x_bcm8726_set_limiting_mode(params, module_type);
+ /* Check and set limiting mode / LRM mode on 8726.
+ On 8727 it is done automatically */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+ else
+ bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+ /*
+ * Enable transmit for this module if the module is approved, or
+ * if unapproved modules should also enable the Tx laser
+ */
+ if (rc == 0 ||
+ (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 1);
+ else
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
- /* Enable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 1);
- return 0;
+ return rc;
}
void bnx2x_handle_module_detect_int(struct link_params *params)
@@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
port);
- if (bnx2x_wait_for_sfp_module_initialized(params)
- == 0)
+ if (bnx2x_wait_for_sfp_module_initialized(params) ==
+ 0)
bnx2x_sfp_module_detection(params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
@@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type =
+ XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
port);
/* Module was plugged out. */
/* Disable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 0);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
}
}
@@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
driver is loaded, it reset all registers, including the
transmitter */
bnx2x_sfp_module_detection(params);
+
+ /* Set Flow control */
+ bnx2x_ext_phy_set_pause(params, vars);
if (params->req_line_speed == SPEED_1000) {
DP(NETIF_MSG_LINK, "Setting 1G force\n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
@@ -3450,6 +3717,187 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
((val & (1<<7)) > 0));
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 tmp1;
+ u16 rx_alarm_ctrl_val;
+ u16 lasi_ctrl_val;
+
+ /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+ u16 mod_abs;
+ rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+ lasi_ctrl_val = 0x0004;
+
+ DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+ /* enable LASI */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ rx_alarm_ctrl_val);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_CTRL,
+ lasi_ctrl_val);
+
+ /* Initially configure MOD_ABS to interrupt when
+ module is presence( bit 8) */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ /* Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8) | (1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Make MOD_ABS give interrupt on change */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val |= (1<<12);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ /* Set 8727 GPIOs to input to allow reading from the
+ 8727 GPIO0 status which reflect SFP+ module
+ over-current */
+
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val &= 0xff8f; /* Reset bits 4-6 */
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+ bnx2x_bcm8073_set_xaui_low_power_mode(params);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &tmp1);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+ /* Set option 1G speed */
+ if (params->req_line_speed == SPEED_1000) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G force\n");
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x40);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0xD);
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, &tmp1);
+ DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+
+ } else if ((params->req_line_speed ==
+ SPEED_AUTO_NEG) &&
+ ((params->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_PMA_REG_8727_MISC_CTRL, 0);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_AN, 0x1300);
+ } else {
+ /* Since the 8727 has only single reset pin,
+ need to set the 10G registers although it is
+ default */
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CTRL, 0x0020);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ 0x7, 0x0100);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x2040);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0x0008);
+ }
+
+ /* Set 2-wire transfer rate to 400Khz since 100Khz
+ is not operational */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+ 0xa101);
+
+ /* Set TX PreEmphasis if needed */
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+ DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+ "TX_CTRL2 0x%x\n",
+ params->xgxs_config_tx[0],
+ params->xgxs_config_tx[1]);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL1,
+ params->xgxs_config_tx[0]);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL2,
+ params->xgxs_config_tx[1]);
+ }
+
+ break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
{
u16 fw_ver1, fw_ver2;
@@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
return rc;
}
+static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u16 mod_abs, rx_alarm_status;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ if (mod_abs & (1<<8)) {
+
+ /* Module is absent */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is absent\n");
+
+ /* 1. Set mod_abs to detect next module
+ presence event
+ 2. Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ } else {
+ /* Module is present */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is present\n");
+ /* First thing, disable transmitter,
+ and if the module is ok, the
+ module_detection will enable it*/
+
+ /* 1. Set mod_abs to detect next module
+ absent event ( bit 8)
+ 2. Restore the default polarity of the OPRXLOS signal and
+ this signal will then correctly indicate the presence or
+ absence of the Rx signal. (bit 9) */
+ mod_abs |= ((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed. This is need to be done
+ before calling the module detection, otherwise it will clear
+ the link update alarm */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+
+ if (bnx2x_wait_for_sfp_module_initialized(params)
+ == 0)
+ bnx2x_sfp_module_detection(params);
+ else
+ DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+ }
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+ /* No need to check link status in case of
+ module plugged in/out */
+}
+
static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
struct link_vars *vars)
@@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_SD, &rx_sd);
- DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
- ext_phy_link_up = (rx_sd & 0x1);
+
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+
+ DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+ ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
+ && ((val1 & (1<<8)) == 0));
if (ext_phy_link_up)
vars->line_speed = SPEED_10000;
break;
@@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
else
vars->line_speed = SPEED_10000;
}
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 link_status = 0;
+ u16 rx_alarm_status;
+ /* Check the LASI */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_STATUS, &val1);
+
+ DP(NETIF_MSG_LINK,
+ "8727 LASI status 0x%x\n",
+ val1);
+
+ /* Clear MSG-OUT */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &val1);
+
+ /*
+ * If a module is present and there is need to check
+ * for over current
+ */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) &&
+ !(rx_alarm_status & (1<<5))) {
+ /* Check over-current using 8727 GPIO0 input*/
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ &val1);
+
+ if ((val1 & (1<<8)) == 0) {
+ DP(NETIF_MSG_LINK, "8727 Power fault"
+ " has been detected on port"
+ " %d\n", params->port);
+ printk(KERN_ERR PFX "Error: Power"
+ " fault on %s Port %d has"
+ " been detected and the"
+ " power to that SFP+ module"
+ " has been removed to prevent"
+ " failure of the card. Please"
+ " remove the SFP+ module and"
+ " restart the system to clear"
+ " this error.\n"
+ , bp->dev->name, params->port);
+ /*
+ * Disable all RX_ALARMs except for
+ * mod_abs
+ */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ (1<<5));
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ /* Wait for module_absent_event */
+ val1 |= (1<<8);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ val1);
+ /* Clear RX alarm */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM,
+ &rx_alarm_status);
+ break;
+ }
+ } /* Over current check */
+
+ /* When module absent bit is set, check module */
+ if (rx_alarm_status & (1<<5)) {
+ bnx2x_8727_handle_mod_abs(params);
+ /* Enable all mod_abs and link detection bits */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ ((1<<5) | (1<<2)));
+ }
+
+ /* If transmitter is disabled,
+ ignore false link up indication */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ if (val1 & (1<<15)) {
+ DP(NETIF_MSG_LINK, "Tx is disabled\n");
+ ext_phy_link_up = 0;
+ break;
+ }
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+ &link_status);
+ /* Bits 0..2 --> speed detected,
+ bits 13..15--> link is down */
+ if ((link_status & (1<<2)) &&
+ (!(link_status & (1<<15)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_10000;
+ } else if ((link_status & (1<<0)) &&
+ (!(link_status & (1<<13)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_1000;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " up in 1G\n", params->port);
+ } else {
+ ext_phy_link_up = 0;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " is down\n", params->port);
+ }
break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
{
@@ -4242,6 +4946,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
@@ -4790,6 +5495,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
}
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0);
+
+ bnx2x_set_led(bp, params->port, LED_MODE_OPER,
+ vars->line_speed, params->hw_led_mode,
+ params->chip_id);
+
} else
/* No loopback */
{
@@ -4843,10 +5553,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL, 0x0001);
-
- /* Disable Transmitter */
- bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
-
}
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
@@ -4859,6 +5565,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u32 chip_id = params->chip_id;
u8 port = params->port;
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
/* disable attentions */
vars->link_status = 0;
@@ -4893,6 +5604,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+
+ /* Disable Transmitter */
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+ break;
+ }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
"low power mode\n",
@@ -5217,6 +5943,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
}
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+{
+ u8 ext_phy_addr[PORT_MAX];
+ s8 port;
+ u32 swap_val, swap_override;
+ DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+
+ bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override));
+ msleep(5);
+
+ /* PART1 - Reset both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ /* Extract the ext phy address for the port */
+ u32 ext_phy_config = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].external_phy_config));
+
+ /* disable attentions */
+ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ (NIG_MASK_XGXS0_LINK_STATUS |
+ NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_SERDES0_LINK_STATUS |
+ NIG_MASK_MI_INT));
+
+ ext_phy_addr[port] = ((ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ /* Reset the phy */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL,
+ 1<<15);
+ }
+
+ /* Add delay of 150ms after reset */
+ msleep(150);
+
+ /* PART2 - Download firmware to both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ u16 fw_ver1;
+
+ bnx2x_bcm8727_external_rom_boot(bp, port,
+ ext_phy_addr[port], shmem_base);
+
+ bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+ if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
+ DP(NETIF_MSG_LINK,
+ "bnx2x_8073_common_init_phy port %x:"
+ "Download failed. fw version = 0x%x\n",
+ port, fw_ver1);
+ return -EINVAL;
+ }
+
+ }
+
+
+
+ return 0;
+}
+
static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{
@@ -5275,6 +6069,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
rc = bnx2x_8073_common_init_phy(bp, shmem_base);
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+ rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* GPIO1 affects both ports, so there's need to pull
it for single port alone */
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h
index 19a866dc10eb..d25ef45d793f 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x_link.h
@@ -39,7 +39,13 @@
#define SPEED_15000 15000
#define SPEED_16000 16000
-
+#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
+#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25
+#define SFP_EEPROM_VENDOR_OUI_SIZE 3
+#define SFP_EEPROM_PART_NO_ADDR 0x28
+#define SFP_EEPROM_PART_NO_SIZE 16
+#define PWR_FLT_ERR_MSG_LEN 250
/***********************************************************/
/* Structs */
/***********************************************************/
@@ -91,7 +97,8 @@ struct link_params {
u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
-#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0)
+#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
+#define FEATURE_CONFIG_BCM8727_NOC (1<<3)
/* Device pointer passed to all callback functions */
struct bnx2x *bp;
};
@@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf);
+
#endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index c36a5f33739f..665ed36a0d48 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.48.105-1"
-#define DRV_MODULE_RELDATE "2009/04/22"
+#define DRV_MODULE_VERSION "1.48.114-1"
+#define DRV_MODULE_RELDATE "2009/07/29"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
@@ -653,6 +653,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
REG_WR(bp, addr, val);
+ /*
+ * Ensure that HC_CONFIG is written before leading/trailing edge config
+ */
+ mmiowb();
+ barrier();
if (CHIP_IS_E1H(bp)) {
/* init leading/trailing edge */
@@ -667,6 +672,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
}
+
+ /* Make sure that interrupts are indeed enabled from here on */
+ mmiowb();
}
static void bnx2x_int_disable(struct bnx2x *bp)
@@ -699,6 +707,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
/* disable interrupt handling */
atomic_inc(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
if (disable_hw)
/* prevent the HW from sending interrupts */
bnx2x_int_disable(bp);
@@ -740,6 +750,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
(*(u32 *)&igu_ack), hc_addr);
REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+ /* Make sure that ACK is written */
+ mmiowb();
+ barrier();
}
static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2430,9 +2444,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
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();
+
spin_unlock_bh(&bp->spq_lock);
return 0;
}
@@ -2599,11 +2618,27 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
}
}
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+
+ /* mark the failure */
+ bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+ SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+ bp->link_params.ext_phy_config);
+
+ /* log the failure */
+ printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+ " the driver to shutdown the card to prevent permanent"
+ " damage. Please contact Dell Support for assistance\n",
+ bp->dev->name);
+}
static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{
int port = BP_PORT(bp);
int reg_offset;
- u32 val;
+ u32 val, swap_val, swap_override;
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -2616,36 +2651,32 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
BNX2X_ERR("SPIO5 hw attention\n");
+ /* Fan failure attention */
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure attention */
-
+ /* Low power mode is controlled by GPIO 2 */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
/* The PHY reset is controlled by GPIO 1 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* Low power mode is controlled by GPIO 2 */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ /* The PHY reset is controlled by GPIO 1 */
+ /* fake the port number to cancel the swap done in
+ set_gpio() */
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+ port = (swap_val && swap_override) ^ 1;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* mark the failure */
- bp->link_params.ext_phy_config &=
- ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
- bp->link_params.ext_phy_config |=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
- SHMEM_WR(bp,
- dev_info.port_hw_config[port].
- external_phy_config,
- bp->link_params.ext_phy_config);
- /* log the failure */
- printk(KERN_ERR PFX "Fan Failure on Network"
- " Controller %s has caused the driver to"
- " shutdown the card to prevent permanent"
- " damage. Please contact Dell Support for"
- " assistance\n", bp->dev->name);
break;
default:
break;
}
+ bnx2x_fan_failure(bp);
}
if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
@@ -4801,7 +4832,14 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
int mode = bp->rx_mode;
int mask = (1 << BP_L_ID(bp));
int func = BP_FUNC(bp);
+ int port = BP_PORT(bp);
int i;
+ /* All but management unicast packets should pass to the host as well */
+ u32 llh_mask =
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask);
@@ -4825,6 +4863,8 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
tstorm_mac_filter.ucast_accept_all = mask;
tstorm_mac_filter.mcast_accept_all = mask;
tstorm_mac_filter.bcast_accept_all = mask;
+ /* pass management unicast packets as well */
+ llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
break;
default:
@@ -4832,6 +4872,10 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
break;
}
+ REG_WR(bp,
+ (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
+ llh_mask);
+
for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
@@ -5185,6 +5229,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
mmiowb();
bnx2x_int_enable(bp);
+
+ /* Check for SPIO5 */
+ bnx2x_attn_int_deasserted0(bp,
+ REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+ AEU_INPUTS_ATTN_BITS_SPIO5);
}
/* end of nic init */
@@ -5510,6 +5559,60 @@ static void bnx2x_reset_common(struct bnx2x *bp)
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
}
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+ u32 val;
+ u8 port;
+ u8 is_required = 0;
+
+ val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+ SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+ if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+ is_required = 1;
+
+ /*
+ * The fan failure mechanism is usually related to the PHY type since
+ * the power consumption of the board is affected by the PHY. Currently,
+ * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+ */
+ else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+ for (port = PORT_0; port < PORT_MAX; port++) {
+ u32 phy_type =
+ SHMEM_RD(bp, dev_info.port_hw_config[port].
+ external_phy_config) &
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ is_required |=
+ ((phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+ }
+
+ DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+ if (is_required == 0)
+ return;
+
+ /* Fan failure is indicated by SPIO 5 */
+ bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+ MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+ /* set to active low mode */
+ val = REG_RD(bp, MISC_REG_SPIO_INT);
+ val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+ MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+ REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+ /* enable interrupt to signal the IGU */
+ val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+ val |= (1 << MISC_REGISTERS_SPIO_5);
+ REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
@@ -5736,30 +5839,16 @@ static int bnx2x_init_common(struct bnx2x *bp)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
bp->port.need_hw_lock = 1;
break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure is indicated by SPIO 5 */
- bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
- MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
- /* set to active low mode */
- val = REG_RD(bp, MISC_REG_SPIO_INT);
- val |= ((1 << MISC_REGISTERS_SPIO_5) <<
- MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
- REG_WR(bp, MISC_REG_SPIO_INT, val);
-
- /* enable interrupt to signal the IGU */
- val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
- val |= (1 << MISC_REGISTERS_SPIO_5);
- REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
- break;
-
default:
break;
}
+ bnx2x_setup_fan_failure_detection(bp);
+
/* clear PXP2 attentions */
REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
@@ -5989,10 +6078,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* add SPIO 5 to group 0 */
- val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ {
+ u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ val = REG_RD(bp, reg_addr);
val |= AEU_INPUTS_ATTN_BITS_SPIO5;
- REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+ REG_WR(bp, reg_addr, val);
+ }
break;
default:
@@ -6142,7 +6236,7 @@ init_hw_err:
}
/* send the MCP a request, block until there is a reply */
-static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
{
int func = BP_FUNC(bp);
u32 seq = ++bp->fw_seq;
@@ -6583,7 +6677,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
static void bnx2x_netif_start(struct bnx2x *bp)
{
- if (atomic_dec_and_test(&bp->intr_sem)) {
+ int intr_sem;
+
+ intr_sem = atomic_dec_and_test(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+ if (intr_sem) {
if (netif_running(bp->dev)) {
bnx2x_napi_enable(bp);
bnx2x_int_enable(bp);
@@ -7256,17 +7355,17 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
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);
}
if (unload_mode == UNLOAD_NORMAL)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
- else if (bp->flags & NO_WOL_FLAG) {
+ else if (bp->flags & NO_WOL_FLAG)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
- if (CHIP_IS_E1H(bp))
- REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
- } else if (bp->wol) {
+ else if (bp->wol) {
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u8 *mac_addr = bp->dev->dev_addr;
u32 val;
@@ -7610,6 +7709,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
BNX2X_ERR("This driver needs bc_ver %X but found %X,"
" please upgrade BC\n", BNX2X_BC_VER, val);
}
+ bp->link_params.feature_config_flags |=
+ (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
if (BP_E1HVN(bp) == 0) {
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -7770,6 +7872,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
SUPPORTED_Asym_Pause);
break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+ ext_phy_type);
+
+ bp->port.supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
ext_phy_type);
@@ -8033,6 +8147,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config =
SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
+ /* BCM8727_NOC => BCM8727 no over current */
+ if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+ bp->link_params.ext_phy_config &=
+ ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+ bp->link_params.feature_config_flags |=
+ FEATURE_CONFIG_BCM8727_NOC;
+ }
+
bp->link_params.speed_cap_mask =
SHMEM_RD(bp,
dev_info.port_hw_config[port].speed_capability_mask);
@@ -8053,17 +8178,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
}
- config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
- if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
- bp->link_params.feature_config_flags |=
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
- else
- bp->link_params.feature_config_flags &=
- ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-
/* If the device is capable of WoL, set the default state according
* to the HW
*/
+ config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED));
@@ -8073,8 +8191,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config,
bp->link_params.speed_cap_mask, bp->port.link_config);
- bp->link_params.switch_cfg = (bp->port.link_config &
- PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ bp->link_params.switch_cfg |= (bp->port.link_config &
+ PORT_FEATURE_CONNECTED_SWITCH_MASK);
bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
bnx2x_link_settings_requested(bp);
@@ -8170,6 +8288,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
/* Disable interrupt handling until HW is initialized */
atomic_set(&bp->intr_sem, 1);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
mutex_init(&bp->port.phy_mutex);
@@ -8269,6 +8388,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
cmd->port = PORT_FIBRE;
break;
@@ -9296,10 +9416,9 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
{ XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 },
{ XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff },
- { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff },
{ NIG_REG_LLH0_T_BIT, 4, 0x00000001 },
-/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
- { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
+ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
+/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
{ NIG_REG_XCM0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_BRB0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 },
@@ -9308,8 +9427,8 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff },
{ NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff },
{ NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 },
-/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
- { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
+ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
+/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
{ NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff },
{ NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 },
{ NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
@@ -9692,8 +9811,15 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags &= ~ETH_TEST_FL_OFFLINE;
if (etest->flags & ETH_TEST_FL_OFFLINE) {
+ int port = BP_PORT(bp);
+ u32 val;
u8 link_up;
+ /* save current value of input enable for TX port IF */
+ val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+ /* 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;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
bnx2x_nic_load(bp, LOAD_DIAG);
@@ -9713,6 +9839,10 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+ /* restore input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
bnx2x_nic_load(bp, LOAD_NORMAL);
/* wait until link state is restored */
bnx2x_wait_for_link(bp, link_up);
@@ -11065,12 +11195,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= NETIF_F_HW_CSUM;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->features |= NETIF_F_TSO6;
#ifdef BCM_VLAN
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+ dev->vlan_features |= NETIF_F_SG;
+ dev->vlan_features |= NETIF_F_HW_CSUM;
+ if (bp->flags & USING_DAC_FLAG)
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+ dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->vlan_features |= NETIF_F_TSO6;
#endif
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features |= NETIF_F_TSO6;
return 0;
@@ -11554,6 +11691,11 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
netif_device_detach(dev);
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
if (netif_running(dev))
bnx2x_eeh_nic_unload(bp);
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index b8ce6fc927a0..cab40152399f 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -1616,6 +1616,11 @@
/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
loaded; 0-prepare; -unprepare */
#define MISC_REG_UNPREPARED 0xa424
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15)
@@ -1660,6 +1665,8 @@
#define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc
/* [RW 1] Input enable for TX PBF user packet port1 IF */
#define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0
+/* [RW 1] Input enable for TX UMP management packet port0 IF */
+#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4
/* [RW 1] Input enable for RX_EMAC0 IF */
#define NIG_REG_EMAC0_IN_EN 0x100a4
/* [RW 1] output enable for TX EMAC pause port 0 IF */
@@ -3788,7 +3795,7 @@
The fields are:[4:0] - tail pointer; [10:5] - Link List size; 15:11] -
header pointer. */
#define TCM_REG_XX_TABLE 0x50240
-/* [RW 4] Load value for for cfc ac credit cnt. */
+/* [RW 4] Load value for cfc ac credit cnt. */
#define TM_REG_CFC_AC_CRDCNT_VAL 0x164208
/* [RW 4] Load value for cfc cld credit cnt. */
#define TM_REG_CFC_CLD_CRDCNT_VAL 0x164210
@@ -5843,25 +5850,33 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_ROM_VER2 0xca1a
#define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b
#define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d
-#define MDIO_PMA_REG_GEN_CTRL2 0xca1e
+#define MDIO_PMA_REG_PLL_CTRL 0xca1e
#define MDIO_PMA_REG_MISC_CTRL0 0xca23
#define MDIO_PMA_REG_LRM_MODE 0xca3f
#define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46
#define MDIO_PMA_REG_MISC_CTRL1 0xca85
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002
-#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL 0x8000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE 0x0000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE 0x0004
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT 0x8002
+#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR 0x8003
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
#define MDIO_PMA_REG_8726_TX_CTRL1 0xca01
#define MDIO_PMA_REG_8726_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
+#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309
+#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02
+#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808
+#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e
#define MDIO_PMA_REG_8073_CHIP_REV 0xc801
#define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index d4b570886c6e..68a227275def 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
//mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
port->sm_vars &= ~AD_PORT_MATCHED;
- port->partner_oper.port_state |= AD_SHORT_TIMEOUT;
+ port->partner_oper.port_state |=
+ AD_STATE_LACP_ACTIVITY;
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
port->actor_oper_port_state |= AD_STATE_EXPIRED;
break;
@@ -1982,7 +1983,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
// find new aggregator for the related port(s)
new_aggregator = __get_first_agg(port);
for (; new_aggregator; new_aggregator = __get_next_agg(new_aggregator)) {
- // if the new aggregator is empty, or it connected to to our port only
+ // if the new aggregator is empty, or it is connected to our port only
if (!new_aggregator->lag_ports || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator)) {
break;
}
@@ -2431,7 +2432,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 46d312bedfb8..bf45d2002924 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1413,7 +1413,7 @@ out:
}
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
void bond_alb_monitor(struct work_struct *work)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index aa1be1feceed..3bf0cc61e92c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4285,7 +4285,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -4316,7 +4316,7 @@ out:
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4362,7 +4362,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4422,7 +4422,7 @@ out:
/* frame sent to all suitable interfaces */
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*------------------------- Device initialization ---------------------------*/
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 33821a81cbf8..30ae55d71678 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM
you may want to enable this option.
config CAN_EMS_PCI
- tristate "EMS CPC-PCI and CPC-PCIe Card"
+ tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
depends on PCI && CAN_SJA1000
---help---
- This driver is for the one or two channel CPC-PCI and CPC-PCIe
- cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+ This driver is for the one, two or four channel CPC-PCI,
+ CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+ (http://www.ems-wuensche.de).
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 121b64101d72..7d84b8ac9c1c 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -32,13 +32,16 @@
#define DRV_NAME "ems_pci"
MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
MODULE_LICENSE("GPL v2");
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN
struct ems_pci_card {
+ int version;
int channels;
struct pci_dev *pci_dev;
@@ -63,12 +66,22 @@ struct ems_pci_card {
#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */
/*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR 0x4c /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+ PLX_ICSR_LINTI1_CLR)
+
+/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
- * This means normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
*/
#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
@@ -79,17 +92,21 @@ struct ems_pci_card {
* is driven by the first one CLKOUT output.
*/
#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR 1
+#define EMS_PCI_V1_MEM_SIZE 4096
+#define EMS_PCI_V2_BASE_BAR 2
+#define EMS_PCI_V2_MEM_SIZE 128
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
-#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID 0x2104
-
static struct pci_device_id ems_pci_tbl[] = {
- {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v1 */
+ {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+ /* CPC-104P v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
{0,}
};
MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
/*
* Helper to read internal registers from card logic (not CAN)
*/
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
{
- return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
+ return readb(card->base_addr + (port * 4));
}
-static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
{
- return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ return readb(priv->reg_base + (port * 4));
}
-static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
{
- writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ writeb(val, priv->reg_base + (port * 4));
}
-static void ems_pci_post_irq(const struct sja1000_priv *priv)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
{
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
/* reset int flag of pita */
- writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
- + PITA2_ICR);
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
+{
+ writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+ struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+ writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
}
/*
@@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- ems_pci_write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, REG_MOD, 1);
- ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
- res = ems_pci_read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, REG_CDR);
if (res == CDR_PELICAN)
return 1;
@@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
struct sja1000_priv *priv;
struct net_device *dev;
struct ems_pci_card *card;
+ int max_chan, mem_size, base_bar;
int err, i;
/* Enabling PCI device */
@@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
card->channels = 0;
- /* Remap PITA configuration space, and controller memory area */
- card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+ if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+ card->version = 2; /* CPC-PCI v2 */
+ max_chan = EMS_PCI_V2_MAX_CHAN;
+ base_bar = EMS_PCI_V2_BASE_BAR;
+ mem_size = EMS_PCI_V2_MEM_SIZE;
+ } else {
+ card->version = 1; /* CPC-PCI v1 */
+ max_chan = EMS_PCI_V1_MAX_CHAN;
+ base_bar = EMS_PCI_V1_BASE_BAR;
+ mem_size = EMS_PCI_V1_MEM_SIZE;
+ }
+
+ /* Remap configuration space and controller memory area */
+ card->conf_addr = pci_iomap(pdev, 0, mem_size);
if (card->conf_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+ card->base_addr = pci_iomap(pdev, base_bar, mem_size);
if (card->base_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- /* Configure PITA-2 parallel interface (enable MUX) */
- writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
- /* Check for unique EMS CAN signature */
- if (ems_pci_readb(card, 0) != 0x55 ||
- ems_pci_readb(card, 1) != 0xAA ||
- ems_pci_readb(card, 2) != 0x01 ||
- ems_pci_readb(card, 3) != 0xCB ||
- ems_pci_readb(card, 4) != 0x11) {
- dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
- err = -ENODEV;
- goto failure_cleanup;
+ if (card->version == 1) {
+ /* Configure PITA-2 parallel interface (enable MUX) */
+ writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+ /* Check for unique EMS CAN signature */
+ if (ems_pci_v1_readb(card, 0) != 0x55 ||
+ ems_pci_v1_readb(card, 1) != 0xAA ||
+ ems_pci_v1_readb(card, 2) != 0x01 ||
+ ems_pci_v1_readb(card, 3) != 0xCB ||
+ ems_pci_v1_readb(card, 4) != 0x11) {
+ dev_err(&pdev->dev,
+ "Not EMS Dr. Thomas Wuensche interface\n");
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
}
ems_pci_card_reset(card);
/* Detect available channels */
- for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+ for (i = 0; i < max_chan; i++) {
dev = alloc_sja1000dev(0);
if (dev == NULL) {
err = -ENOMEM;
@@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
dev->irq = pdev->irq;
priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+ (i * EMS_PCI_CAN_CTRL_SIZE);
+ if (card->version == 1) {
+ priv->read_reg = ems_pci_v1_read_reg;
+ priv->write_reg = ems_pci_v1_write_reg;
+ priv->post_irq = ems_pci_v1_post_irq;
+ } else {
+ priv->read_reg = ems_pci_v2_read_reg;
+ priv->write_reg = ems_pci_v2_write_reg;
+ priv->post_irq = ems_pci_v2_post_irq;
+ }
/* Check if channel is present */
if (ems_pci_check_chan(priv)) {
- priv->read_reg = ems_pci_read_reg;
- priv->write_reg = ems_pci_write_reg;
- priv->post_irq = ems_pci_post_irq;
priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
priv->ocr = EMS_PCI_OCR;
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
- /* Enable interrupts from card */
- writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+ if (card->version == 1)
+ /* reset int flag of pita */
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+ else
+ /* enable IRQ in PLX 9030 */
+ writel(PLX_ICSR_ENA_CLR,
+ card->conf_addr + PLX_ICSR);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 08ebee79d8a6..b3004de1e5e4 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -282,7 +282,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv->write_reg(priv, REG_CMR, CMD_TR);
- return 0;
+ return NETDEV_TX_OK;
}
static void sja1000_rx(struct net_device *dev)
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index eb066673c2a0..299a33b914f8 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ring;
if (skb_padto(skb, cp->min_frame_size))
- return 0;
+ return NETDEV_TX_OK;
/* XXX: we need some higher-level QoS hooks to steer packets to
* individual queues.
@@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
return NETDEV_TX_BUSY;
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void cas_init_tx_dma(struct cas *cp)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 4d1515f45ba2..4869d77cbe91 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -227,7 +227,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
}
rcu_read_lock();
- ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
+ ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
if (ulp_ops)
ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len);
rcu_read_unlock();
@@ -319,6 +319,20 @@ static int cnic_abort_prep(struct cnic_sock *csk)
return 0;
}
+static void cnic_uio_stop(void)
+{
+ struct cnic_dev *dev;
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(dev, &cnic_dev_list, list) {
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (cp->cnic_uinfo)
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+ }
+ read_unlock(&cnic_dev_lock);
+}
+
int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
{
struct cnic_dev *dev;
@@ -390,6 +404,9 @@ int cnic_unregister_driver(int ulp_type)
}
read_unlock(&cnic_dev_lock);
+ if (ulp_type == CNIC_ULP_ISCSI)
+ cnic_uio_stop();
+
rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
mutex_unlock(&cnic_lock);
@@ -632,7 +649,6 @@ static void cnic_free_resc(struct cnic_dev *dev)
int i = 0;
if (cp->cnic_uinfo) {
- cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
while (cp->uio_dev != -1 && i < 15) {
msleep(100);
i++;
@@ -1057,6 +1073,9 @@ static void cnic_ulp_stop(struct cnic_dev *dev)
struct cnic_local *cp = dev->cnic_priv;
int if_type;
+ if (cp->cnic_uinfo)
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+
rcu_read_lock();
for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
struct cnic_ulp_ops *ulp_ops;
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7a18dc7e5c7f..15c0195ebd31 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 55445f980f9c..ecf88abbf99e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1367,7 +1367,7 @@ net_open(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+ set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
set_dma_count(dev->dma, lp->dmasize*1024);
enable_dma(dev->dma);
@@ -1572,7 +1572,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
* to restart the netdevice layer
*/
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 1694fad38720..74723f2e7431 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
return netdev_priv(adap->port[idx]);
}
+static inline int phy2portid(struct cphy *phy)
+{
+ struct adapter *adap = phy->adapter;
+ struct port_info *port0 = adap2pinfo(adap, 0);
+
+ return &port0->phy == phy ? 0 : 1;
+}
+
#define OFFLOAD_DEVMAP_BIT 15
#define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -312,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
+
#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 9fe008ec9ba5..5248f9e0b2f4 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait)
return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
}
-static int ael1006_power_down(struct cphy *phy, int enable)
-{
- return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD,
- MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable);
-}
-
static struct cphy_ops ael1006_ops = {
.reset = ael1006_reset,
.intr_enable = t3_phy_lasi_intr_enable,
@@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_r,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
@@ -304,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
{ 0, 0, 0, 0 }
};
- static u16 sr_edc[] = {
- 0xcc00, 0x2ff4,
- 0xcc01, 0x3cd4,
- 0xcc02, 0x2015,
- 0xcc03, 0x3105,
- 0xcc04, 0x6524,
- 0xcc05, 0x27ff,
- 0xcc06, 0x300f,
- 0xcc07, 0x2c8b,
- 0xcc08, 0x300b,
- 0xcc09, 0x4009,
- 0xcc0a, 0x400e,
- 0xcc0b, 0x2f72,
- 0xcc0c, 0x3002,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x2172,
- 0xcc0f, 0x3012,
- 0xcc10, 0x1002,
- 0xcc11, 0x25d2,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0xd01e,
- 0xcc15, 0x27d2,
- 0xcc16, 0x3012,
- 0xcc17, 0x1002,
- 0xcc18, 0x2004,
- 0xcc19, 0x3c84,
- 0xcc1a, 0x6436,
- 0xcc1b, 0x2007,
- 0xcc1c, 0x3f87,
- 0xcc1d, 0x8676,
- 0xcc1e, 0x40b7,
- 0xcc1f, 0xa746,
- 0xcc20, 0x4047,
- 0xcc21, 0x5673,
- 0xcc22, 0x2982,
- 0xcc23, 0x3002,
- 0xcc24, 0x13d2,
- 0xcc25, 0x8bbd,
- 0xcc26, 0x2862,
- 0xcc27, 0x3012,
- 0xcc28, 0x1002,
- 0xcc29, 0x2092,
- 0xcc2a, 0x3012,
- 0xcc2b, 0x1002,
- 0xcc2c, 0x5cc3,
- 0xcc2d, 0x314,
- 0xcc2e, 0x2942,
- 0xcc2f, 0x3002,
- 0xcc30, 0x1002,
- 0xcc31, 0xd019,
- 0xcc32, 0x2032,
- 0xcc33, 0x3012,
- 0xcc34, 0x1002,
- 0xcc35, 0x2a04,
- 0xcc36, 0x3c74,
- 0xcc37, 0x6435,
- 0xcc38, 0x2fa4,
- 0xcc39, 0x3cd4,
- 0xcc3a, 0x6624,
- 0xcc3b, 0x5563,
- 0xcc3c, 0x2d42,
- 0xcc3d, 0x3002,
- 0xcc3e, 0x13d2,
- 0xcc3f, 0x464d,
- 0xcc40, 0x2862,
- 0xcc41, 0x3012,
- 0xcc42, 0x1002,
- 0xcc43, 0x2032,
- 0xcc44, 0x3012,
- 0xcc45, 0x1002,
- 0xcc46, 0x2fb4,
- 0xcc47, 0x3cd4,
- 0xcc48, 0x6624,
- 0xcc49, 0x5563,
- 0xcc4a, 0x2d42,
- 0xcc4b, 0x3002,
- 0xcc4c, 0x13d2,
- 0xcc4d, 0x2ed2,
- 0xcc4e, 0x3002,
- 0xcc4f, 0x1002,
- 0xcc50, 0x2fd2,
- 0xcc51, 0x3002,
- 0xcc52, 0x1002,
- 0xcc53, 0x004,
- 0xcc54, 0x2942,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x2092,
- 0xcc58, 0x3012,
- 0xcc59, 0x1002,
- 0xcc5a, 0x5cc3,
- 0xcc5b, 0x317,
- 0xcc5c, 0x2f72,
- 0xcc5d, 0x3002,
- 0xcc5e, 0x1002,
- 0xcc5f, 0x2942,
- 0xcc60, 0x3002,
- 0xcc61, 0x1002,
- 0xcc62, 0x22cd,
- 0xcc63, 0x301d,
- 0xcc64, 0x2862,
- 0xcc65, 0x3012,
- 0xcc66, 0x1002,
- 0xcc67, 0x2ed2,
- 0xcc68, 0x3002,
- 0xcc69, 0x1002,
- 0xcc6a, 0x2d72,
- 0xcc6b, 0x3002,
- 0xcc6c, 0x1002,
- 0xcc6d, 0x628f,
- 0xcc6e, 0x2112,
- 0xcc6f, 0x3012,
- 0xcc70, 0x1002,
- 0xcc71, 0x5aa3,
- 0xcc72, 0x2dc2,
- 0xcc73, 0x3002,
- 0xcc74, 0x1312,
- 0xcc75, 0x6f72,
- 0xcc76, 0x1002,
- 0xcc77, 0x2807,
- 0xcc78, 0x31a7,
- 0xcc79, 0x20c4,
- 0xcc7a, 0x3c24,
- 0xcc7b, 0x6724,
- 0xcc7c, 0x1002,
- 0xcc7d, 0x2807,
- 0xcc7e, 0x3187,
- 0xcc7f, 0x20c4,
- 0xcc80, 0x3c24,
- 0xcc81, 0x6724,
- 0xcc82, 0x1002,
- 0xcc83, 0x2514,
- 0xcc84, 0x3c64,
- 0xcc85, 0x6436,
- 0xcc86, 0xdff4,
- 0xcc87, 0x6436,
- 0xcc88, 0x1002,
- 0xcc89, 0x40a4,
- 0xcc8a, 0x643c,
- 0xcc8b, 0x4016,
- 0xcc8c, 0x8c6c,
- 0xcc8d, 0x2b24,
- 0xcc8e, 0x3c24,
- 0xcc8f, 0x6435,
- 0xcc90, 0x1002,
- 0xcc91, 0x2b24,
- 0xcc92, 0x3c24,
- 0xcc93, 0x643a,
- 0xcc94, 0x4025,
- 0xcc95, 0x8a5a,
- 0xcc96, 0x1002,
- 0xcc97, 0x2731,
- 0xcc98, 0x3011,
- 0xcc99, 0x1001,
- 0xcc9a, 0xc7a0,
- 0xcc9b, 0x100,
- 0xcc9c, 0xc502,
- 0xcc9d, 0x53ac,
- 0xcc9e, 0xc503,
- 0xcc9f, 0xd5d5,
- 0xcca0, 0xc600,
- 0xcca1, 0x2a6d,
- 0xcca2, 0xc601,
- 0xcca3, 0x2a4c,
- 0xcca4, 0xc602,
- 0xcca5, 0x111,
- 0xcca6, 0xc60c,
- 0xcca7, 0x5900,
- 0xcca8, 0xc710,
- 0xcca9, 0x700,
- 0xccaa, 0xc718,
- 0xccab, 0x700,
- 0xccac, 0xc720,
- 0xccad, 0x4700,
- 0xccae, 0xc801,
- 0xccaf, 0x7f50,
- 0xccb0, 0xc802,
- 0xccb1, 0x7760,
- 0xccb2, 0xc803,
- 0xccb3, 0x7fce,
- 0xccb4, 0xc804,
- 0xccb5, 0x5700,
- 0xccb6, 0xc805,
- 0xccb7, 0x5f11,
- 0xccb8, 0xc806,
- 0xccb9, 0x4751,
- 0xccba, 0xc807,
- 0xccbb, 0x57e1,
- 0xccbc, 0xc808,
- 0xccbd, 0x2700,
- 0xccbe, 0xc809,
- 0xccbf, 0x000,
- 0xccc0, 0xc821,
- 0xccc1, 0x002,
- 0xccc2, 0xc822,
- 0xccc3, 0x014,
- 0xccc4, 0xc832,
- 0xccc5, 0x1186,
- 0xccc6, 0xc847,
- 0xccc7, 0x1e02,
- 0xccc8, 0xc013,
- 0xccc9, 0xf341,
- 0xccca, 0xc01a,
- 0xcccb, 0x446,
- 0xcccc, 0xc024,
- 0xcccd, 0x1000,
- 0xccce, 0xc025,
- 0xcccf, 0xa00,
- 0xccd0, 0xc026,
- 0xccd1, 0xc0c,
- 0xccd2, 0xc027,
- 0xccd3, 0xc0c,
- 0xccd4, 0xc029,
- 0xccd5, 0x0a0,
- 0xccd6, 0xc030,
- 0xccd7, 0xa00,
- 0xccd8, 0xc03c,
- 0xccd9, 0x01c,
- 0xccda, 0xc005,
- 0xccdb, 0x7a06,
- 0xccdc, 0x000,
- 0xccdd, 0x2731,
- 0xccde, 0x3011,
- 0xccdf, 0x1001,
- 0xcce0, 0xc620,
- 0xcce1, 0x000,
- 0xcce2, 0xc621,
- 0xcce3, 0x03f,
- 0xcce4, 0xc622,
- 0xcce5, 0x000,
- 0xcce6, 0xc623,
- 0xcce7, 0x000,
- 0xcce8, 0xc624,
- 0xcce9, 0x000,
- 0xccea, 0xc625,
- 0xcceb, 0x000,
- 0xccec, 0xc627,
- 0xcced, 0x000,
- 0xccee, 0xc628,
- 0xccef, 0x000,
- 0xccf0, 0xc62c,
- 0xccf1, 0x000,
- 0xccf2, 0x000,
- 0xccf3, 0x2806,
- 0xccf4, 0x3cb6,
- 0xccf5, 0xc161,
- 0xccf6, 0x6134,
- 0xccf7, 0x6135,
- 0xccf8, 0x5443,
- 0xccf9, 0x303,
- 0xccfa, 0x6524,
- 0xccfb, 0x00b,
- 0xccfc, 0x1002,
- 0xccfd, 0x2104,
- 0xccfe, 0x3c24,
- 0xccff, 0x2105,
- 0xcd00, 0x3805,
- 0xcd01, 0x6524,
- 0xcd02, 0xdff4,
- 0xcd03, 0x4005,
- 0xcd04, 0x6524,
- 0xcd05, 0x1002,
- 0xcd06, 0x5dd3,
- 0xcd07, 0x306,
- 0xcd08, 0x2ff7,
- 0xcd09, 0x38f7,
- 0xcd0a, 0x60b7,
- 0xcd0b, 0xdffd,
- 0xcd0c, 0x00a,
- 0xcd0d, 0x1002,
- 0xcd0e, 0
- };
+
int i, err;
err = set_phy_regs(phy, regs);
@@ -585,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i],
- sr_edc[i + 1]);
+ if (phy->priv != edc_sr)
+ err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
+ EDC_OPT_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_sr;
return err;
@@ -604,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
{ 0, 0, 0, 0 }
};
- static u16 twinax_edc[] = {
- 0xcc00, 0x4009,
- 0xcc01, 0x27ff,
- 0xcc02, 0x300f,
- 0xcc03, 0x40aa,
- 0xcc04, 0x401c,
- 0xcc05, 0x401e,
- 0xcc06, 0x2ff4,
- 0xcc07, 0x3cd4,
- 0xcc08, 0x2035,
- 0xcc09, 0x3145,
- 0xcc0a, 0x6524,
- 0xcc0b, 0x26a2,
- 0xcc0c, 0x3012,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x29c2,
- 0xcc0f, 0x3002,
- 0xcc10, 0x1002,
- 0xcc11, 0x2072,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0x22cd,
- 0xcc15, 0x301d,
- 0xcc16, 0x2e52,
- 0xcc17, 0x3012,
- 0xcc18, 0x1002,
- 0xcc19, 0x28e2,
- 0xcc1a, 0x3002,
- 0xcc1b, 0x1002,
- 0xcc1c, 0x628f,
- 0xcc1d, 0x2ac2,
- 0xcc1e, 0x3012,
- 0xcc1f, 0x1002,
- 0xcc20, 0x5553,
- 0xcc21, 0x2ae2,
- 0xcc22, 0x3002,
- 0xcc23, 0x1302,
- 0xcc24, 0x401e,
- 0xcc25, 0x2be2,
- 0xcc26, 0x3012,
- 0xcc27, 0x1002,
- 0xcc28, 0x2da2,
- 0xcc29, 0x3012,
- 0xcc2a, 0x1002,
- 0xcc2b, 0x2ba2,
- 0xcc2c, 0x3002,
- 0xcc2d, 0x1002,
- 0xcc2e, 0x5ee3,
- 0xcc2f, 0x305,
- 0xcc30, 0x400e,
- 0xcc31, 0x2bc2,
- 0xcc32, 0x3002,
- 0xcc33, 0x1002,
- 0xcc34, 0x2b82,
- 0xcc35, 0x3012,
- 0xcc36, 0x1002,
- 0xcc37, 0x5663,
- 0xcc38, 0x302,
- 0xcc39, 0x401e,
- 0xcc3a, 0x6f72,
- 0xcc3b, 0x1002,
- 0xcc3c, 0x628f,
- 0xcc3d, 0x2be2,
- 0xcc3e, 0x3012,
- 0xcc3f, 0x1002,
- 0xcc40, 0x22cd,
- 0xcc41, 0x301d,
- 0xcc42, 0x2e52,
- 0xcc43, 0x3012,
- 0xcc44, 0x1002,
- 0xcc45, 0x2522,
- 0xcc46, 0x3012,
- 0xcc47, 0x1002,
- 0xcc48, 0x2da2,
- 0xcc49, 0x3012,
- 0xcc4a, 0x1002,
- 0xcc4b, 0x2ca2,
- 0xcc4c, 0x3012,
- 0xcc4d, 0x1002,
- 0xcc4e, 0x2fa4,
- 0xcc4f, 0x3cd4,
- 0xcc50, 0x6624,
- 0xcc51, 0x410b,
- 0xcc52, 0x56b3,
- 0xcc53, 0x3c4,
- 0xcc54, 0x2fb2,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x220b,
- 0xcc58, 0x303b,
- 0xcc59, 0x56b3,
- 0xcc5a, 0x3c3,
- 0xcc5b, 0x866b,
- 0xcc5c, 0x400c,
- 0xcc5d, 0x23a2,
- 0xcc5e, 0x3012,
- 0xcc5f, 0x1002,
- 0xcc60, 0x2da2,
- 0xcc61, 0x3012,
- 0xcc62, 0x1002,
- 0xcc63, 0x2ca2,
- 0xcc64, 0x3012,
- 0xcc65, 0x1002,
- 0xcc66, 0x2fb4,
- 0xcc67, 0x3cd4,
- 0xcc68, 0x6624,
- 0xcc69, 0x56b3,
- 0xcc6a, 0x3c3,
- 0xcc6b, 0x866b,
- 0xcc6c, 0x401c,
- 0xcc6d, 0x2205,
- 0xcc6e, 0x3035,
- 0xcc6f, 0x5b53,
- 0xcc70, 0x2c52,
- 0xcc71, 0x3002,
- 0xcc72, 0x13c2,
- 0xcc73, 0x5cc3,
- 0xcc74, 0x317,
- 0xcc75, 0x2522,
- 0xcc76, 0x3012,
- 0xcc77, 0x1002,
- 0xcc78, 0x2da2,
- 0xcc79, 0x3012,
- 0xcc7a, 0x1002,
- 0xcc7b, 0x2b82,
- 0xcc7c, 0x3012,
- 0xcc7d, 0x1002,
- 0xcc7e, 0x5663,
- 0xcc7f, 0x303,
- 0xcc80, 0x401e,
- 0xcc81, 0x004,
- 0xcc82, 0x2c42,
- 0xcc83, 0x3012,
- 0xcc84, 0x1002,
- 0xcc85, 0x6f72,
- 0xcc86, 0x1002,
- 0xcc87, 0x628f,
- 0xcc88, 0x2304,
- 0xcc89, 0x3c84,
- 0xcc8a, 0x6436,
- 0xcc8b, 0xdff4,
- 0xcc8c, 0x6436,
- 0xcc8d, 0x2ff5,
- 0xcc8e, 0x3005,
- 0xcc8f, 0x8656,
- 0xcc90, 0xdfba,
- 0xcc91, 0x56a3,
- 0xcc92, 0xd05a,
- 0xcc93, 0x21c2,
- 0xcc94, 0x3012,
- 0xcc95, 0x1392,
- 0xcc96, 0xd05a,
- 0xcc97, 0x56a3,
- 0xcc98, 0xdfba,
- 0xcc99, 0x383,
- 0xcc9a, 0x6f72,
- 0xcc9b, 0x1002,
- 0xcc9c, 0x28c5,
- 0xcc9d, 0x3005,
- 0xcc9e, 0x4178,
- 0xcc9f, 0x5653,
- 0xcca0, 0x384,
- 0xcca1, 0x22b2,
- 0xcca2, 0x3012,
- 0xcca3, 0x1002,
- 0xcca4, 0x2be5,
- 0xcca5, 0x3005,
- 0xcca6, 0x41e8,
- 0xcca7, 0x5653,
- 0xcca8, 0x382,
- 0xcca9, 0x002,
- 0xccaa, 0x4258,
- 0xccab, 0x2474,
- 0xccac, 0x3c84,
- 0xccad, 0x6437,
- 0xccae, 0xdff4,
- 0xccaf, 0x6437,
- 0xccb0, 0x2ff5,
- 0xccb1, 0x3c05,
- 0xccb2, 0x8757,
- 0xccb3, 0xb888,
- 0xccb4, 0x9787,
- 0xccb5, 0xdff4,
- 0xccb6, 0x6724,
- 0xccb7, 0x866a,
- 0xccb8, 0x6f72,
- 0xccb9, 0x1002,
- 0xccba, 0x2d01,
- 0xccbb, 0x3011,
- 0xccbc, 0x1001,
- 0xccbd, 0xc620,
- 0xccbe, 0x14e5,
- 0xccbf, 0xc621,
- 0xccc0, 0xc53d,
- 0xccc1, 0xc622,
- 0xccc2, 0x3cbe,
- 0xccc3, 0xc623,
- 0xccc4, 0x4452,
- 0xccc5, 0xc624,
- 0xccc6, 0xc5c5,
- 0xccc7, 0xc625,
- 0xccc8, 0xe01e,
- 0xccc9, 0xc627,
- 0xccca, 0x000,
- 0xcccb, 0xc628,
- 0xcccc, 0x000,
- 0xcccd, 0xc62b,
- 0xccce, 0x000,
- 0xcccf, 0xc62c,
- 0xccd0, 0x000,
- 0xccd1, 0x000,
- 0xccd2, 0x2d01,
- 0xccd3, 0x3011,
- 0xccd4, 0x1001,
- 0xccd5, 0xc620,
- 0xccd6, 0x000,
- 0xccd7, 0xc621,
- 0xccd8, 0x000,
- 0xccd9, 0xc622,
- 0xccda, 0x0ce,
- 0xccdb, 0xc623,
- 0xccdc, 0x07f,
- 0xccdd, 0xc624,
- 0xccde, 0x032,
- 0xccdf, 0xc625,
- 0xcce0, 0x000,
- 0xcce1, 0xc627,
- 0xcce2, 0x000,
- 0xcce3, 0xc628,
- 0xcce4, 0x000,
- 0xcce5, 0xc62b,
- 0xcce6, 0x000,
- 0xcce7, 0xc62c,
- 0xcce8, 0x000,
- 0xcce9, 0x000,
- 0xccea, 0x2d01,
- 0xcceb, 0x3011,
- 0xccec, 0x1001,
- 0xcced, 0xc502,
- 0xccee, 0x609f,
- 0xccef, 0xc600,
- 0xccf0, 0x2a6e,
- 0xccf1, 0xc601,
- 0xccf2, 0x2a2c,
- 0xccf3, 0xc60c,
- 0xccf4, 0x5400,
- 0xccf5, 0xc710,
- 0xccf6, 0x700,
- 0xccf7, 0xc718,
- 0xccf8, 0x700,
- 0xccf9, 0xc720,
- 0xccfa, 0x4700,
- 0xccfb, 0xc728,
- 0xccfc, 0x700,
- 0xccfd, 0xc729,
- 0xccfe, 0x1207,
- 0xccff, 0xc801,
- 0xcd00, 0x7f50,
- 0xcd01, 0xc802,
- 0xcd02, 0x7760,
- 0xcd03, 0xc803,
- 0xcd04, 0x7fce,
- 0xcd05, 0xc804,
- 0xcd06, 0x520e,
- 0xcd07, 0xc805,
- 0xcd08, 0x5c11,
- 0xcd09, 0xc806,
- 0xcd0a, 0x3c51,
- 0xcd0b, 0xc807,
- 0xcd0c, 0x4061,
- 0xcd0d, 0xc808,
- 0xcd0e, 0x49c1,
- 0xcd0f, 0xc809,
- 0xcd10, 0x3840,
- 0xcd11, 0xc80a,
- 0xcd12, 0x000,
- 0xcd13, 0xc821,
- 0xcd14, 0x002,
- 0xcd15, 0xc822,
- 0xcd16, 0x046,
- 0xcd17, 0xc844,
- 0xcd18, 0x182f,
- 0xcd19, 0xc013,
- 0xcd1a, 0xf341,
- 0xcd1b, 0xc01a,
- 0xcd1c, 0x446,
- 0xcd1d, 0xc024,
- 0xcd1e, 0x1000,
- 0xcd1f, 0xc025,
- 0xcd20, 0xa00,
- 0xcd21, 0xc026,
- 0xcd22, 0xc0c,
- 0xcd23, 0xc027,
- 0xcd24, 0xc0c,
- 0xcd25, 0xc029,
- 0xcd26, 0x0a0,
- 0xcd27, 0xc030,
- 0xcd28, 0xa00,
- 0xcd29, 0xc03c,
- 0xcd2a, 0x01c,
- 0xcd2b, 0x000,
- 0xcd2c, 0x2b84,
- 0xcd2d, 0x3c74,
- 0xcd2e, 0x6435,
- 0xcd2f, 0xdff4,
- 0xcd30, 0x6435,
- 0xcd31, 0x2806,
- 0xcd32, 0x3006,
- 0xcd33, 0x8565,
- 0xcd34, 0x2b24,
- 0xcd35, 0x3c24,
- 0xcd36, 0x6436,
- 0xcd37, 0x1002,
- 0xcd38, 0x2b24,
- 0xcd39, 0x3c24,
- 0xcd3a, 0x6436,
- 0xcd3b, 0x4045,
- 0xcd3c, 0x8656,
- 0xcd3d, 0x1002,
- 0xcd3e, 0x2807,
- 0xcd3f, 0x31a7,
- 0xcd40, 0x20c4,
- 0xcd41, 0x3c24,
- 0xcd42, 0x6724,
- 0xcd43, 0x1002,
- 0xcd44, 0x2807,
- 0xcd45, 0x3187,
- 0xcd46, 0x20c4,
- 0xcd47, 0x3c24,
- 0xcd48, 0x6724,
- 0xcd49, 0x1002,
- 0xcd4a, 0x2514,
- 0xcd4b, 0x3c64,
- 0xcd4c, 0x6436,
- 0xcd4d, 0xdff4,
- 0xcd4e, 0x6436,
- 0xcd4f, 0x1002,
- 0xcd50, 0x2806,
- 0xcd51, 0x3cb6,
- 0xcd52, 0xc161,
- 0xcd53, 0x6134,
- 0xcd54, 0x6135,
- 0xcd55, 0x5443,
- 0xcd56, 0x303,
- 0xcd57, 0x6524,
- 0xcd58, 0x00b,
- 0xcd59, 0x1002,
- 0xcd5a, 0xd019,
- 0xcd5b, 0x2104,
- 0xcd5c, 0x3c24,
- 0xcd5d, 0x2105,
- 0xcd5e, 0x3805,
- 0xcd5f, 0x6524,
- 0xcd60, 0xdff4,
- 0xcd61, 0x4005,
- 0xcd62, 0x6524,
- 0xcd63, 0x2e8d,
- 0xcd64, 0x303d,
- 0xcd65, 0x5dd3,
- 0xcd66, 0x306,
- 0xcd67, 0x2ff7,
- 0xcd68, 0x38f7,
- 0xcd69, 0x60b7,
- 0xcd6a, 0xdffd,
- 0xcd6b, 0x00a,
- 0xcd6c, 0x1002,
- 0xcd6d, 0
- };
int i, err;
err = set_phy_regs(phy, regs);
@@ -982,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
+ EDC_TWX_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_twinax;
return err;
@@ -1201,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
{ 0, 0, 0, 0 }
};
-
- /* TWINAX EDC firmware */
- static u16 twinax_edc[] = {
- 0xd800, 0x4009,
- 0xd801, 0x2fff,
- 0xd802, 0x300f,
- 0xd803, 0x40aa,
- 0xd804, 0x401c,
- 0xd805, 0x401e,
- 0xd806, 0x2ff4,
- 0xd807, 0x3dc4,
- 0xd808, 0x2035,
- 0xd809, 0x3035,
- 0xd80a, 0x6524,
- 0xd80b, 0x2cb2,
- 0xd80c, 0x3012,
- 0xd80d, 0x1002,
- 0xd80e, 0x26e2,
- 0xd80f, 0x3022,
- 0xd810, 0x1002,
- 0xd811, 0x27d2,
- 0xd812, 0x3022,
- 0xd813, 0x1002,
- 0xd814, 0x2822,
- 0xd815, 0x3012,
- 0xd816, 0x1002,
- 0xd817, 0x2492,
- 0xd818, 0x3022,
- 0xd819, 0x1002,
- 0xd81a, 0x2772,
- 0xd81b, 0x3012,
- 0xd81c, 0x1002,
- 0xd81d, 0x23d2,
- 0xd81e, 0x3022,
- 0xd81f, 0x1002,
- 0xd820, 0x22cd,
- 0xd821, 0x301d,
- 0xd822, 0x27f2,
- 0xd823, 0x3022,
- 0xd824, 0x1002,
- 0xd825, 0x5553,
- 0xd826, 0x0307,
- 0xd827, 0x2522,
- 0xd828, 0x3022,
- 0xd829, 0x1002,
- 0xd82a, 0x2142,
- 0xd82b, 0x3012,
- 0xd82c, 0x1002,
- 0xd82d, 0x4016,
- 0xd82e, 0x5e63,
- 0xd82f, 0x0344,
- 0xd830, 0x2142,
- 0xd831, 0x3012,
- 0xd832, 0x1002,
- 0xd833, 0x400e,
- 0xd834, 0x2522,
- 0xd835, 0x3022,
- 0xd836, 0x1002,
- 0xd837, 0x2b52,
- 0xd838, 0x3012,
- 0xd839, 0x1002,
- 0xd83a, 0x2742,
- 0xd83b, 0x3022,
- 0xd83c, 0x1002,
- 0xd83d, 0x25e2,
- 0xd83e, 0x3022,
- 0xd83f, 0x1002,
- 0xd840, 0x2fa4,
- 0xd841, 0x3dc4,
- 0xd842, 0x6624,
- 0xd843, 0x414b,
- 0xd844, 0x56b3,
- 0xd845, 0x03c6,
- 0xd846, 0x866b,
- 0xd847, 0x400c,
- 0xd848, 0x2712,
- 0xd849, 0x3012,
- 0xd84a, 0x1002,
- 0xd84b, 0x2c4b,
- 0xd84c, 0x309b,
- 0xd84d, 0x56b3,
- 0xd84e, 0x03c3,
- 0xd84f, 0x866b,
- 0xd850, 0x400c,
- 0xd851, 0x2272,
- 0xd852, 0x3022,
- 0xd853, 0x1002,
- 0xd854, 0x2742,
- 0xd855, 0x3022,
- 0xd856, 0x1002,
- 0xd857, 0x25e2,
- 0xd858, 0x3022,
- 0xd859, 0x1002,
- 0xd85a, 0x2fb4,
- 0xd85b, 0x3dc4,
- 0xd85c, 0x6624,
- 0xd85d, 0x56b3,
- 0xd85e, 0x03c3,
- 0xd85f, 0x866b,
- 0xd860, 0x401c,
- 0xd861, 0x2c45,
- 0xd862, 0x3095,
- 0xd863, 0x5b53,
- 0xd864, 0x2372,
- 0xd865, 0x3012,
- 0xd866, 0x13c2,
- 0xd867, 0x5cc3,
- 0xd868, 0x2712,
- 0xd869, 0x3012,
- 0xd86a, 0x1312,
- 0xd86b, 0x2b52,
- 0xd86c, 0x3012,
- 0xd86d, 0x1002,
- 0xd86e, 0x2742,
- 0xd86f, 0x3022,
- 0xd870, 0x1002,
- 0xd871, 0x2582,
- 0xd872, 0x3022,
- 0xd873, 0x1002,
- 0xd874, 0x2142,
- 0xd875, 0x3012,
- 0xd876, 0x1002,
- 0xd877, 0x628f,
- 0xd878, 0x2985,
- 0xd879, 0x33a5,
- 0xd87a, 0x25e2,
- 0xd87b, 0x3022,
- 0xd87c, 0x1002,
- 0xd87d, 0x5653,
- 0xd87e, 0x03d2,
- 0xd87f, 0x401e,
- 0xd880, 0x6f72,
- 0xd881, 0x1002,
- 0xd882, 0x628f,
- 0xd883, 0x2304,
- 0xd884, 0x3c84,
- 0xd885, 0x6436,
- 0xd886, 0xdff4,
- 0xd887, 0x6436,
- 0xd888, 0x2ff5,
- 0xd889, 0x3005,
- 0xd88a, 0x8656,
- 0xd88b, 0xdfba,
- 0xd88c, 0x56a3,
- 0xd88d, 0xd05a,
- 0xd88e, 0x2972,
- 0xd88f, 0x3012,
- 0xd890, 0x1392,
- 0xd891, 0xd05a,
- 0xd892, 0x56a3,
- 0xd893, 0xdfba,
- 0xd894, 0x0383,
- 0xd895, 0x6f72,
- 0xd896, 0x1002,
- 0xd897, 0x2b45,
- 0xd898, 0x3005,
- 0xd899, 0x4178,
- 0xd89a, 0x5653,
- 0xd89b, 0x0384,
- 0xd89c, 0x2a62,
- 0xd89d, 0x3012,
- 0xd89e, 0x1002,
- 0xd89f, 0x2f05,
- 0xd8a0, 0x3005,
- 0xd8a1, 0x41c8,
- 0xd8a2, 0x5653,
- 0xd8a3, 0x0382,
- 0xd8a4, 0x0002,
- 0xd8a5, 0x4218,
- 0xd8a6, 0x2474,
- 0xd8a7, 0x3c84,
- 0xd8a8, 0x6437,
- 0xd8a9, 0xdff4,
- 0xd8aa, 0x6437,
- 0xd8ab, 0x2ff5,
- 0xd8ac, 0x3c05,
- 0xd8ad, 0x8757,
- 0xd8ae, 0xb888,
- 0xd8af, 0x9787,
- 0xd8b0, 0xdff4,
- 0xd8b1, 0x6724,
- 0xd8b2, 0x866a,
- 0xd8b3, 0x6f72,
- 0xd8b4, 0x1002,
- 0xd8b5, 0x2641,
- 0xd8b6, 0x3021,
- 0xd8b7, 0x1001,
- 0xd8b8, 0xc620,
- 0xd8b9, 0x0000,
- 0xd8ba, 0xc621,
- 0xd8bb, 0x0000,
- 0xd8bc, 0xc622,
- 0xd8bd, 0x00ce,
- 0xd8be, 0xc623,
- 0xd8bf, 0x007f,
- 0xd8c0, 0xc624,
- 0xd8c1, 0x0032,
- 0xd8c2, 0xc625,
- 0xd8c3, 0x0000,
- 0xd8c4, 0xc627,
- 0xd8c5, 0x0000,
- 0xd8c6, 0xc628,
- 0xd8c7, 0x0000,
- 0xd8c8, 0xc62c,
- 0xd8c9, 0x0000,
- 0xd8ca, 0x0000,
- 0xd8cb, 0x2641,
- 0xd8cc, 0x3021,
- 0xd8cd, 0x1001,
- 0xd8ce, 0xc502,
- 0xd8cf, 0x53ac,
- 0xd8d0, 0xc503,
- 0xd8d1, 0x2cd3,
- 0xd8d2, 0xc600,
- 0xd8d3, 0x2a6e,
- 0xd8d4, 0xc601,
- 0xd8d5, 0x2a2c,
- 0xd8d6, 0xc605,
- 0xd8d7, 0x5557,
- 0xd8d8, 0xc60c,
- 0xd8d9, 0x5400,
- 0xd8da, 0xc710,
- 0xd8db, 0x0700,
- 0xd8dc, 0xc711,
- 0xd8dd, 0x0f06,
- 0xd8de, 0xc718,
- 0xd8df, 0x0700,
- 0xd8e0, 0xc719,
- 0xd8e1, 0x0f06,
- 0xd8e2, 0xc720,
- 0xd8e3, 0x4700,
- 0xd8e4, 0xc721,
- 0xd8e5, 0x0f06,
- 0xd8e6, 0xc728,
- 0xd8e7, 0x0700,
- 0xd8e8, 0xc729,
- 0xd8e9, 0x1207,
- 0xd8ea, 0xc801,
- 0xd8eb, 0x7f50,
- 0xd8ec, 0xc802,
- 0xd8ed, 0x7760,
- 0xd8ee, 0xc803,
- 0xd8ef, 0x7fce,
- 0xd8f0, 0xc804,
- 0xd8f1, 0x520e,
- 0xd8f2, 0xc805,
- 0xd8f3, 0x5c11,
- 0xd8f4, 0xc806,
- 0xd8f5, 0x3c51,
- 0xd8f6, 0xc807,
- 0xd8f7, 0x4061,
- 0xd8f8, 0xc808,
- 0xd8f9, 0x49c1,
- 0xd8fa, 0xc809,
- 0xd8fb, 0x3840,
- 0xd8fc, 0xc80a,
- 0xd8fd, 0x0000,
- 0xd8fe, 0xc821,
- 0xd8ff, 0x0002,
- 0xd900, 0xc822,
- 0xd901, 0x0046,
- 0xd902, 0xc844,
- 0xd903, 0x182f,
- 0xd904, 0xc013,
- 0xd905, 0xf341,
- 0xd906, 0xc084,
- 0xd907, 0x0030,
- 0xd908, 0xc904,
- 0xd909, 0x1401,
- 0xd90a, 0xcb0c,
- 0xd90b, 0x0004,
- 0xd90c, 0xcb0e,
- 0xd90d, 0xa00a,
- 0xd90e, 0xcb0f,
- 0xd90f, 0xc0c0,
- 0xd910, 0xcb10,
- 0xd911, 0xc0c0,
- 0xd912, 0xcb11,
- 0xd913, 0x00a0,
- 0xd914, 0xcb12,
- 0xd915, 0x0007,
- 0xd916, 0xc241,
- 0xd917, 0xa000,
- 0xd918, 0xc243,
- 0xd919, 0x7fe0,
- 0xd91a, 0xc604,
- 0xd91b, 0x000e,
- 0xd91c, 0xc609,
- 0xd91d, 0x00f5,
- 0xd91e, 0xc611,
- 0xd91f, 0x000e,
- 0xd920, 0xc660,
- 0xd921, 0x9600,
- 0xd922, 0xc687,
- 0xd923, 0x0004,
- 0xd924, 0xc60a,
- 0xd925, 0x04f5,
- 0xd926, 0x0000,
- 0xd927, 0x2641,
- 0xd928, 0x3021,
- 0xd929, 0x1001,
- 0xd92a, 0xc620,
- 0xd92b, 0x14e5,
- 0xd92c, 0xc621,
- 0xd92d, 0xc53d,
- 0xd92e, 0xc622,
- 0xd92f, 0x3cbe,
- 0xd930, 0xc623,
- 0xd931, 0x4452,
- 0xd932, 0xc624,
- 0xd933, 0xc5c5,
- 0xd934, 0xc625,
- 0xd935, 0xe01e,
- 0xd936, 0xc627,
- 0xd937, 0x0000,
- 0xd938, 0xc628,
- 0xd939, 0x0000,
- 0xd93a, 0xc62c,
- 0xd93b, 0x0000,
- 0xd93c, 0x0000,
- 0xd93d, 0x2b84,
- 0xd93e, 0x3c74,
- 0xd93f, 0x6435,
- 0xd940, 0xdff4,
- 0xd941, 0x6435,
- 0xd942, 0x2806,
- 0xd943, 0x3006,
- 0xd944, 0x8565,
- 0xd945, 0x2b24,
- 0xd946, 0x3c24,
- 0xd947, 0x6436,
- 0xd948, 0x1002,
- 0xd949, 0x2b24,
- 0xd94a, 0x3c24,
- 0xd94b, 0x6436,
- 0xd94c, 0x4045,
- 0xd94d, 0x8656,
- 0xd94e, 0x5663,
- 0xd94f, 0x0302,
- 0xd950, 0x401e,
- 0xd951, 0x1002,
- 0xd952, 0x2807,
- 0xd953, 0x31a7,
- 0xd954, 0x20c4,
- 0xd955, 0x3c24,
- 0xd956, 0x6724,
- 0xd957, 0x1002,
- 0xd958, 0x2807,
- 0xd959, 0x3187,
- 0xd95a, 0x20c4,
- 0xd95b, 0x3c24,
- 0xd95c, 0x6724,
- 0xd95d, 0x1002,
- 0xd95e, 0x24f4,
- 0xd95f, 0x3c64,
- 0xd960, 0x6436,
- 0xd961, 0xdff4,
- 0xd962, 0x6436,
- 0xd963, 0x1002,
- 0xd964, 0x2006,
- 0xd965, 0x3d76,
- 0xd966, 0xc161,
- 0xd967, 0x6134,
- 0xd968, 0x6135,
- 0xd969, 0x5443,
- 0xd96a, 0x0303,
- 0xd96b, 0x6524,
- 0xd96c, 0x00fb,
- 0xd96d, 0x1002,
- 0xd96e, 0x20d4,
- 0xd96f, 0x3c24,
- 0xd970, 0x2025,
- 0xd971, 0x3005,
- 0xd972, 0x6524,
- 0xd973, 0x1002,
- 0xd974, 0xd019,
- 0xd975, 0x2104,
- 0xd976, 0x3c24,
- 0xd977, 0x2105,
- 0xd978, 0x3805,
- 0xd979, 0x6524,
- 0xd97a, 0xdff4,
- 0xd97b, 0x4005,
- 0xd97c, 0x6524,
- 0xd97d, 0x2e8d,
- 0xd97e, 0x303d,
- 0xd97f, 0x2408,
- 0xd980, 0x35d8,
- 0xd981, 0x5dd3,
- 0xd982, 0x0307,
- 0xd983, 0x8887,
- 0xd984, 0x63a7,
- 0xd985, 0x8887,
- 0xd986, 0x63a7,
- 0xd987, 0xdffd,
- 0xd988, 0x00f9,
- 0xd989, 0x1002,
- 0xd98a, 0x0000,
- };
int i, err;
/* set uC clock and activate it */
@@ -1612,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
if (err)
return err;
- /* write TWINAX EDC firmware into PHY */
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
+ EDC_TWX_AEL2020_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
/* activate uC */
err = set_phy_regs(phy, uCactivate);
if (!err)
@@ -1649,9 +624,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
*/
static int ael2020_intr_enable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x2 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_enable(phy);
+ struct reg_val regs[] = {
+ /* output Module's Loss Of Signal (LOS) to LED */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
+ 0xffff, 0x4 },
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
+
+ /* enable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err, link_ok = 0;
+
+ /* set up "link status" LED and enable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
+ if (err)
+ return err;
+ if (link_ok)
+ t3_link_changed(phy->adapter,
+ phy2portid(phy));
+
+ err = t3_phy_lasi_intr_enable(phy);
+ if (err)
+ return err;
+
+ return 0;
}
/*
@@ -1659,9 +664,26 @@ static int ael2020_intr_enable(struct cphy *phy)
*/
static int ael2020_intr_disable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x1 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_disable(phy);
+ struct reg_val regs[] = {
+ /* reset "link status" LED to "off" */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
+
+ /* disable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err;
+
+ /* turn off "link status" LED and disable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ return t3_phy_lasi_intr_disable(phy);
}
/*
@@ -1679,31 +701,26 @@ static int ael2020_intr_clear(struct cphy *phy)
return err ? err : t3_phy_lasi_intr_clear(phy);
}
+static struct reg_val ael2020_reset_regs[] = {
+ /* Erratum #2: CDRLOL asserted, causing PMA link down status */
+ { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
+
+ /* force XAUI to send LF when RX_LOS is asserted */
+ { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
+
+ /* allow writes to transceiver module EEPROM on i2c bus */
+ { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
+ { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
+ { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
+
+ /* end */
+ { 0, 0, 0, 0 }
+};
/*
* Reset the PHY and put it into a canonical operating state.
*/
static int ael2020_reset(struct cphy *phy, int wait)
{
- static struct reg_val regs0[] = {
- /* Erratum #2: CDRLOL asserted, causing PMA link down status */
- { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
-
- /* force XAUI to send LF when RX_LOS is asserted */
- { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
-
- /* RX_LOS pin is active high */
- { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS,
- 0x0020, 0x0020 },
-
- /* output Module's Loss Of Signal (LOS) to LED */
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
- 0xffff, 0x0004 },
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
-
- /* end */
- { 0, 0, 0, 0 }
- };
int err;
unsigned int lasi_ctrl;
@@ -1720,7 +737,7 @@ static int ael2020_reset(struct cphy *phy, int wait)
/* basic initialization for all module types */
phy->priv = edc_none;
- err = set_phy_regs(phy, regs0);
+ err = set_phy_regs(phy, ael2020_reset_regs);
if (err)
return err;
@@ -1798,10 +815,16 @@ static struct cphy_ops ael2020_ops = {
int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
+ int err;
+
cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_IRQ, "10GBASE-R");
msleep(125);
+
+ err = set_phy_regs(phy, ael2020_reset_regs);
+ if (err)
+ return err;
return 0;
}
@@ -1840,7 +863,7 @@ static struct cphy_ops qt2045_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_x,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c
index b1fd5bf836e4..341b7ef1508f 100644
--- a/drivers/net/cxgb3/aq100x.c
+++ b/drivers/net/cxgb3/aq100x.c
@@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
- SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T");
+ SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
+ "1000/10GBASE-T");
/*
* The PHY has been out of reset ever since the system powered up. So
@@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
/* Firmware version check. */
t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
- if (v != 30) {
+ if (v != 101)
CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
phy_addr, v);
- return 0; /* allow t3_prep_adapter to succeed */
- }
/*
* The PHY should start in really-low-power mode. Prepare it for normal
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index d21b705501a9..1b2c305fb82b 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -566,6 +566,15 @@ struct cphy_ops {
u32 mmds;
};
+enum {
+ EDC_OPT_AEL2005 = 0,
+ EDC_OPT_AEL2005_SIZE = 1084,
+ EDC_TWX_AEL2005 = 1,
+ EDC_TWX_AEL2005_SIZE = 1464,
+ EDC_TWX_AEL2020 = 2,
+ EDC_TWX_AEL2020_SIZE = 1628,
+ EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */
+};
/* A PHY instance */
struct cphy {
@@ -577,6 +586,7 @@ struct cphy {
unsigned long fifo_errors; /* FIFO over/under-flows */
const struct cphy_ops *ops; /* PHY operations */
struct mdio_if_info mdio;
+ u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */
};
/* Convenience MDIO read/write wrappers */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index fb5df5c6203e..8b3e76c1cf52 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -172,6 +172,23 @@ static void link_report(struct net_device *dev)
}
}
+static void enable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
+ F_ENDROPPKT);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
+ t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
+}
+
+static void disable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
+ F_ENDROPPKT, 0);
+}
+
void t3_os_link_fault(struct adapter *adap, int port_id, int state)
{
struct net_device *dev = adap->port[port_id];
@@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
netif_carrier_on(dev);
+ disable_tx_fifo_drain(adap, pi);
+
/* Clear local faults */
t3_xgm_intr_disable(adap, pi->port_id);
t3_read_reg(adap, A_XGM_INT_STATUS +
@@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
t3_xgm_intr_enable(adap, pi->port_id);
t3_mac_enable(mac, MAC_DIRECTION_TX);
- } else
+ } else {
netif_carrier_off(dev);
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adap, pi);
+ }
link_report(dev);
}
@@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
if (link_stat != netif_carrier_ok(dev)) {
if (link_stat) {
+ disable_tx_fifo_drain(adapter, pi);
+
t3_mac_enable(mac, MAC_DIRECTION_RX);
/* Clear local faults */
@@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
+
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adapter, pi);
}
link_report(dev);
@@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap)
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+ req->mtu_idx = NMTUS - 1;
req->iff = i;
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
@@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap)
#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
+
+static inline const char *get_edc_fw_name(int edc_idx)
+{
+ const char *fw_name = NULL;
+
+ switch (edc_idx) {
+ case EDC_OPT_AEL2005:
+ fw_name = AEL2005_OPT_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2005:
+ fw_name = AEL2005_TWX_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2020:
+ fw_name = AEL2020_TWX_EDC_NAME;
+ break;
+ }
+ return fw_name;
+}
+
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
+{
+ struct adapter *adapter = phy->adapter;
+ const struct firmware *fw;
+ char buf[64];
+ u32 csum;
+ const __be32 *p;
+ u16 *cache = phy->phy_cache;
+ int i, ret;
+
+ snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+
+ ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+ if (ret < 0) {
+ dev_err(&adapter->pdev->dev,
+ "could not upgrade firmware: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ /* check size, take checksum in account */
+ if (fw->size > size + 4) {
+ CH_ERR(adapter, "firmware image too large %u, expected %d\n",
+ (unsigned int)fw->size, size + 4);
+ ret = -EINVAL;
+ }
+
+ /* compute checksum */
+ p = (const __be32 *)fw->data;
+ for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < size / 4 ; i++) {
+ *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
+ *cache++ = be32_to_cpu(p[i]) & 0xffff;
+ }
+
+ release_firmware(fw);
+
+ return ret;
+}
static int upgrade_fw(struct adapter *adap)
{
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 870d44992c70..526e144b8b74 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -3465,7 +3465,7 @@ static void config_pcie(struct adapter *adap)
{201, 321, 258, 450, 834, 1602}
};
- u16 val;
+ u16 val, devid;
unsigned int log2_width, pldsize;
unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
@@ -3473,6 +3473,17 @@ static void config_pcie(struct adapter *adap)
adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
&val);
pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+
+ pci_read_config_word(adap->pdev, 0x2, &devid);
+ if (devid == 0x37) {
+ pci_write_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr +
+ PCI_EXP_DEVCTL,
+ val & ~PCI_EXP_DEVCTL_READRQ &
+ ~PCI_EXP_DEVCTL_PAYLOAD);
+ pldsize = 0;
+ }
+
pci_read_config_word(adap->pdev,
adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
&val);
@@ -3682,6 +3693,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
{
mac->adapter = adapter;
+ if (!adapter->params.vpd.xauicfg[1])
+ index = 0;
mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
mac->nucast = 1;
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index f87f9435049f..0109ee4f2f91 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
- if (fc & PAUSE_TX)
- val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
- t3_read_reg(adap,
- A_XGM_RX_MAX_PKT_SIZE
- + oft)) / 8);
+ if (fc & PAUSE_TX) {
+ u32 rx_max_pkt_size =
+ G_RXMAXPKTSIZE(t3_read_reg(adap,
+ A_XGM_RX_MAX_PKT_SIZE + oft));
+ val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
+ }
t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index e1af089064bc..6b13f4fd2e96 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock_irqrestore(&de600_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 55d2bb67cffa..45794f6cb0f6 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
spin_unlock_irqrestore(&de620_lock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 2b22e580c4de..a31696a3928e 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void lance_load_multicast(struct net_device *dev)
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 102b8d439714..b2e0a8fc21d7 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_length_errors++; /* bump error counter */
netif_wake_queue(dev);
dev_kfree_skb(skb);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
/*
* See if adapter link is available, if not, free buffer
@@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_discards++; /* bump error counter */
dev_kfree_skb(skb); /* free sk_buff now */
netif_wake_queue(dev);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
}
@@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt(
dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
spin_unlock_irqrestore(&bp->lock, flags);
netif_wake_queue(dev);
- return(0); /* packet queued to adapter */
+ return NETDEV_TX_OK; /* packet queued to adapter */
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 97ea2d6d3fe1..adb997c5bb5d 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev)
static int load_packet(struct net_device *dev, struct sk_buff *skb)
{
struct depca_private *lp = netdev_priv(dev);
- int i, entry, end, len, status = 0;
+ int i, entry, end, len, status = NETDEV_TX_OK;
entry = lp->tx_new; /* Ring around buffer number. */
end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index dd771dea6ae6..a2bc4158259a 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -92,6 +92,7 @@ typedef struct board_info {
u16 tx_pkt_cnt;
u16 queue_pkt_len;
u16 queue_start_addr;
+ u16 queue_ip_summed;
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
@@ -124,6 +125,10 @@ typedef struct board_info {
struct mii_if_info mii;
u32 msg_enable;
+
+ int rx_csum;
+ int can_csum;
+ int ip_summed;
} board_info_t;
/* debug code */
@@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev)
return mii_nway_restart(&dm->mii);
}
+static uint32_t dm9000_get_rx_csum(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ return dm->rx_csum;
+}
+
+static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ unsigned long flags;
+
+ if (dm->can_csum) {
+ dm->rx_csum = data;
+
+ spin_lock_irqsave(&dm->lock, flags);
+ iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
+ spin_unlock_irqrestore(&dm->lock, flags);
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ int ret = -EOPNOTSUPP;
+
+ if (dm->can_csum)
+ ret = ethtool_op_set_tx_csum(dev, data);
+ return ret;
+}
+
static u32 dm9000_get_link(struct net_device *dev)
{
board_info_t *dm = to_dm9000_board(dev);
@@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
+ .get_rx_csum = dm9000_get_rx_csum,
+ .set_rx_csum = dm9000_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = dm9000_set_tx_csum,
};
static void dm9000_show_carrier(board_info_t *db,
@@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev)
/* I/O mode */
db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
+ /* Checksum mode */
+ dm9000_set_rx_csum(dev, db->rx_csum);
+
/* GPIO0 on pre-activate PHY */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
@@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev)
spin_unlock_irqrestore(&db->lock, flags);
}
+static void dm9000_send_packet(struct net_device *dev,
+ int ip_summed,
+ u16 pkt_len)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ /* The DM9000 is not smart enough to leave fragmented packets alone. */
+ if (dm->ip_summed != ip_summed) {
+ if (ip_summed == CHECKSUM_NONE)
+ iow(dm, DM9000_TCCR, 0);
+ else
+ iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
+ dm->ip_summed = ip_summed;
+ }
+
+ /* Set TX length to DM9000 */
+ iow(dm, DM9000_TXPLL, pkt_len);
+ iow(dm, DM9000_TXPLH, pkt_len >> 8);
+
+ /* Issue TX polling command */
+ iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+}
+
/*
* Hardware start transmission.
* Send a packet to media from the upper layer.
@@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
- /* Set TX length to DM9000 */
- iow(db, DM9000_TXPLL, skb->len);
- iow(db, DM9000_TXPLH, skb->len >> 8);
-
- /* Issue TX polling command */
- iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
-
- dev->trans_start = jiffies; /* save the time stamp */
+ dm9000_send_packet(dev, skb->ip_summed, skb->len);
} else {
/* Second packet */
db->queue_pkt_len = skb->len;
+ db->queue_ip_summed = skb->ip_summed;
netif_stop_queue(dev);
}
@@ -788,7 +851,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
/* Queue packet check & send */
- if (db->tx_pkt_cnt > 0) {
- iow(db, DM9000_TXPLL, db->queue_pkt_len);
- iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
- iow(db, DM9000_TCR, TCR_TXREQ);
- dev->trans_start = jiffies;
- }
+ if (db->tx_pkt_cnt > 0)
+ dm9000_send_packet(dev, db->queue_ip_summed,
+ db->queue_pkt_len);
netif_wake_queue(dev);
}
}
@@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev)
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
- if (rxbyte > DM9000_PKT_RDY) {
+ if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %d\n", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
return;
}
- if (rxbyte != DM9000_PKT_RDY)
+ if (!(rxbyte & DM9000_PKT_RDY))
return;
/* A packet ready now & Get status/length */
@@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev)
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
+ if (db->rx_csum) {
+ if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
netif_rx(skb);
dev->stats.rx_packets++;
@@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev)
(db->dumpblk)(db->io_data, RxLen);
}
- } while (rxbyte == DM9000_PKT_RDY);
+ } while (rxbyte & DM9000_PKT_RDY);
}
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
@@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev)
db->type = TYPE_DM9000E;
}
+ /* dm9000a/b are capable of hardware checksum offload */
+ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
+ db->can_csum = 1;
+ db->rx_csum = 1;
+ ndev->features |= NETIF_F_IP_CSUM;
+ }
+
/* from this point we assume that we have found a DM9000 */
/* driver system function */
@@ -1410,9 +1483,10 @@ out:
}
static int
-dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
+dm9000_drv_suspend(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db;
if (ndev) {
@@ -1428,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
}
static int
-dm9000_drv_resume(struct platform_device *dev)
+dm9000_drv_resume(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db = netdev_priv(ndev);
if (ndev) {
@@ -1447,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev)
return 0;
}
+static struct dev_pm_ops dm9000_drv_pm_ops = {
+ .suspend = dm9000_drv_suspend,
+ .resume = dm9000_drv_resume,
+};
+
static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
@@ -1466,11 +1546,10 @@ static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
+ .pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
- .suspend = dm9000_drv_suspend,
- .resume = dm9000_drv_resume,
};
static int __init
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index ba25cf541420..80817c2edfb3 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -45,6 +45,10 @@
#define DM9000_CHIPR 0x2C
#define DM9000_SMCR 0x2F
+#define DM9000_ETXCSR 0x30
+#define DM9000_TCCR 0x31
+#define DM9000_RCSR 0x32
+
#define CHIPR_DM9000A 0x19
#define CHIPR_DM9000B 0x1B
@@ -131,7 +135,21 @@
#define GPCR_GEP_CNTL (1<<0)
+#define TCCR_IP (1<<0)
+#define TCCR_TCP (1<<1)
+#define TCCR_UDP (1<<2)
+
+#define RCSR_UDP_BAD (1<<7)
+#define RCSR_TCP_BAD (1<<6)
+#define RCSR_IP_BAD (1<<5)
+#define RCSR_UDP (1<<4)
+#define RCSR_TCP (1<<3)
+#define RCSR_IP (1<<2)
+#define RCSR_CSUM (1<<1)
+#define RCSR_DISCARD (1<<0)
+
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
+#define DM9000_PKT_ERR 0x02
#define DM9000_PKT_MAX 1536 /* Received packet max size */
/* DM9000A / DM9000B definitions */
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 33fa9eee4cac..2818d5de3940 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void dnet_reset_hw(struct dnet *bp)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 8ebd7d789405..713ce6c532c5 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 41b648a67fec..569df19f0df5 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
netdev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int e100_tx_clean(struct nic *nic)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index e9a416f40162..1a4f89c66a26 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -111,6 +111,9 @@ do { \
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
+#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
+
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
@@ -137,7 +140,7 @@ do { \
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
-#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
@@ -161,6 +164,7 @@ do { \
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
+ struct page *page;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
@@ -202,6 +206,7 @@ struct e1000_rx_ring {
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
+ struct sk_buff *rx_skb_top;
/* cpu for rx queue */
int cpu;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c854c96f5ab3..27f996a2010f 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
return 0;
}
+static int e1000_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->hw.mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if (adapter->itr_setting <= 3)
+ ec->rx_coalesce_usecs = adapter->itr_setting;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+ return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (hw->mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 3) &&
+ (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+ (ec->rx_coalesce_usecs == 2))
+ return -EINVAL;
+
+ if (ec->rx_coalesce_usecs <= 3) {
+ adapter->itr = 20000;
+ adapter->itr_setting = ec->rx_coalesce_usecs;
+ } else {
+ adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+ adapter->itr_setting = adapter->itr & ~3;
+ }
+
+ if (adapter->itr_setting != 0)
+ ew32(ITR, 1000000000 / (adapter->itr * 256));
+ else
+ ew32(ITR, 0);
+
+ return 0;
+}
+
static int e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_strings = e1000_get_strings,
.phys_id = e1000_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
- .get_sset_count = e1000_get_sset_count,
+ .get_sset_count = e1000_get_sset_count,
+ .get_coalesce = e1000_get_coalesce,
+ .set_coalesce = e1000_set_coalesce,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index e1a3fc1303ee..26df87f1dfd8 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
s32 ret_val;
u16 i;
u16 phy_data;
- u16 reg_data;
+ u16 reg_data = 0;
DEBUGFUNC("e1000_setup_copper_link");
@@ -3035,7 +3035,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
/* If TBI compatibility is was previously off, turn it on. For
* compatibility with a TBI link partner, we will store bad
* packets. Some frames have an additional byte on the end and
- * will look like CRC errors to to the hardware.
+ * will look like CRC errors to the hardware.
*/
if (!hw->tbi_compatibility_on) {
hw->tbi_compatibility_on = true;
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 99fce2c5dd26..a8866bdbb671 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw);
/* The sizes (in bytes) of a ethernet packet */
#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
#define ETHERNET_FCS_SIZE 4
-#define MAXIMUM_ETHERNET_PACKET_SIZE \
- (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define MINIMUM_ETHERNET_PACKET_SIZE \
(MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define CRC_LENGTH ETHERNET_FCS_SIZE
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 5b8cbdb4b520..d7df00c2dbd6 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget);
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do);
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rx_ring,
+ struct e1000_rx_ring *rx_ring,
int cleaned_count);
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int cleaned_count);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
@@ -635,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 pba = 0, tx_space, min_tx_space, min_rx_space;
- u16 fc_high_water_mark = E1000_FC_HIGH_DIFF;
bool legacy_pba_adjust = false;
+ u16 hwm;
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
@@ -680,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter)
}
if (legacy_pba_adjust) {
- if (adapter->netdev->mtu > E1000_RXBUFFER_8192)
+ if (hw->max_frame_size > E1000_RXBUFFER_8192)
pba -= 8; /* allocate more FIFO for Tx */
if (hw->mac_type == e1000_82547) {
@@ -690,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter)
(E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
atomic_set(&adapter->tx_fifo_stall, 0);
}
- } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
/* adjust PBA for jumbo frames */
ew32(PBA, pba);
/* To maintain wire speed transmits, the Tx FIFO should be
- * large enough to accomodate two full transmit packets,
+ * large enough to accommodate two full transmit packets,
* rounded up to the next 1KB and expressed in KB. Likewise,
- * the Rx FIFO should be large enough to accomodate at least
+ * the Rx FIFO should be large enough to accommodate at least
* one full receive packet and is similarly rounded up and
* expressed in KB. */
pba = er32(PBA);
@@ -705,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter)
tx_space = pba >> 16;
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
- /* don't include ethernet FCS because hardware appends/strips */
- min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE +
- VLAN_TAG_SIZE;
- min_tx_space = min_rx_space;
- min_tx_space *= 2;
+ /*
+ * the tx fifo also stores 16 bytes of information about the tx
+ * but don't include ethernet FCS because hardware appends it
+ */
+ min_tx_space = (hw->max_frame_size +
+ sizeof(struct e1000_tx_desc) -
+ ETH_FCS_LEN) * 2;
min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
+ /* software strips receive CRC, so leave room for it */
+ min_rx_space = hw->max_frame_size;
min_rx_space = ALIGN(min_rx_space, 1024);
min_rx_space >>= 10;
@@ -748,23 +758,22 @@ void e1000_reset(struct e1000_adapter *adapter)
ew32(PBA, pba);
- /* flow control settings */
- /* Set the FC high water mark to 90% of the FIFO size.
- * Required to clear last 3 LSB */
- fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
- /* We can't use 90% on small FIFOs because the remainder
- * would be less than 1 full frame. In this case, we size
- * it to allow at least a full frame above the high water
- * mark. */
- if (pba < E1000_PBA_16K)
- fc_high_water_mark = (pba * 1024) - 1600;
-
- hw->fc_high_water = fc_high_water_mark;
- hw->fc_low_water = fc_high_water_mark - 8;
- if (hw->mac_type == e1000_80003es2lan)
- hw->fc_pause_time = 0xFFFF;
- else
- hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+ /*
+ * flow control settings:
+ * The high water mark must be low enough to fit one full frame
+ * (or the size used for early receive) above it in the Rx FIFO.
+ * Set it to the lower of:
+ * - 90% of the Rx FIFO size, and
+ * - the full Rx FIFO size minus the early receive size (for parts
+ * with ERT support assuming ERT set to E1000_ERT_2048), or
+ * - the full Rx FIFO size minus one full frame
+ */
+ hwm = min(((pba << 10) * 9 / 10),
+ ((pba << 10) - hw->max_frame_size));
+
+ hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+ hw->fc_low_water = hw->fc_high_water - 8;
+ hw->fc_pause_time = E1000_FC_PAUSE_TIME;
hw->fc_send_xon = 1;
hw->fc = hw->original_fc;
@@ -1862,6 +1871,7 @@ setup_rx_desc_die:
rxdr->next_to_clean = 0;
rxdr->next_to_use = 0;
+ rxdr->rx_skb_top = NULL;
return 0;
}
@@ -1968,10 +1978,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 rdlen, rctl, rxcsum, ctrl_ext;
- rdlen = adapter->rx_ring[0].count *
- sizeof(struct e1000_rx_desc);
- adapter->clean_rx = e1000_clean_rx_irq;
- adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
+ } else {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ }
/* disable receives while setting up the descriptors */
rctl = er32(RCTL);
@@ -2185,26 +2202,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
- if (buffer_info->dma) {
- pci_unmap_single(pdev,
- buffer_info->dma,
- buffer_info->length,
- PCI_DMA_FROMDEVICE);
+ if (buffer_info->dma &&
+ adapter->clean_rx == e1000_clean_rx_irq) {
+ pci_unmap_single(pdev, buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ } else if (buffer_info->dma &&
+ adapter->clean_rx == e1000_clean_jumbo_rx_irq) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
}
buffer_info->dma = 0;
-
+ if (buffer_info->page) {
+ put_page(buffer_info->page);
+ buffer_info->page = NULL;
+ }
if (buffer_info->skb) {
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
}
}
+ /* there also may be some cached data from a chained receive */
+ if (rx_ring->rx_skb_top) {
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ }
+
size = sizeof(struct e1000_buffer) * rx_ring->count;
memset(rx_ring->buffer_info, 0, size);
/* Zero out the descriptor ring */
-
memset(rx_ring->desc, 0, rx_ring->size);
rx_ring->next_to_clean = 0;
@@ -3450,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
switch (hw->mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
case e1000_ich8lan:
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
}
@@ -3463,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
&eeprom_data);
if ((hw->device_id != E1000_DEV_ID_82573L) ||
(eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR,
"Jumbo Frames not supported.\n");
return -EINVAL;
@@ -3489,8 +3519,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
- * larger slab size
- * i.e. RXBUFFER_2048 --> size-4096 slab */
+ * larger slab size.
+ * i.e. RXBUFFER_2048 --> size-4096 slab
+ * however with the new *_jumbo_rx* routines, jumbo receives will use
+ * fragmented skbs */
if (max_frame <= E1000_RXBUFFER_256)
adapter->rx_buffer_len = E1000_RXBUFFER_256;
@@ -3500,16 +3532,16 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = E1000_RXBUFFER_1024;
else if (max_frame <= E1000_RXBUFFER_2048)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- else if (max_frame <= E1000_RXBUFFER_4096)
- adapter->rx_buffer_len = E1000_RXBUFFER_4096;
- else if (max_frame <= E1000_RXBUFFER_8192)
- adapter->rx_buffer_len = E1000_RXBUFFER_8192;
- else if (max_frame <= E1000_RXBUFFER_16384)
+ else
+#if (PAGE_SIZE >= E1000_RXBUFFER_16384)
adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+#elif (PAGE_SIZE >= E1000_RXBUFFER_4096)
+ adapter->rx_buffer_len = PAGE_SIZE;
+#endif
/* adjust allocation if LPE protects us, and we aren't using SBP */
if (!hw->tbi_compatibility_on &&
- ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
+ ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) ||
(max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -3987,9 +4019,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
}
/**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+ u16 length)
+{
+ bi->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ */
+static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
+ __le16 vlan, struct sk_buff *skb)
+{
+ if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) {
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ le16_to_cpu(vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
+ } else {
+ netif_receive_skb(skb);
+ }
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ */
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc, *next_rxd;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ unsigned long irq_flags;
+ u32 length;
+ unsigned int i;
+ int cleaned_count = 0;
+ bool cleaned = false;
+ unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (rx_desc->status & E1000_RXD_STAT_DD) {
+ struct sk_buff *skb;
+ u8 status;
+
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ status = rx_desc->status;
+ skb = buffer_info->skb;
+ buffer_info->skb = NULL;
+
+ if (++i == rx_ring->count) i = 0;
+ next_rxd = E1000_RX_DESC(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = true;
+ cleaned_count++;
+ pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* errors is only valid for DD + EOP descriptors */
+ if (unlikely((status & E1000_RXD_STAT_EOP) &&
+ (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+ u8 last_byte = *(skb->data + length - 1);
+ if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
+ last_byte)) {
+ spin_lock_irqsave(&adapter->stats_lock,
+ irq_flags);
+ e1000_tbi_adjust_stats(hw, &adapter->stats,
+ length, skb->data);
+ spin_unlock_irqrestore(&adapter->stats_lock,
+ irq_flags);
+ length--;
+ } else {
+ /* recycle both page and skb */
+ buffer_info->skb = skb;
+ /* an error means any chain goes out the window
+ * too */
+ if (rx_ring->rx_skb_top)
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ goto next_desc;
+ }
+ }
+
+#define rxtop rx_ring->rx_skb_top
+ if (!(status & E1000_RXD_STAT_EOP)) {
+ /* this descriptor is only the beginning (or middle) */
+ if (!rxtop) {
+ /* this is the beginning of a chain */
+ rxtop = skb;
+ skb_fill_page_desc(rxtop, 0, buffer_info->page,
+ 0, length);
+ } else {
+ /* this is the middle of a chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the skb, only consumed the page */
+ buffer_info->skb = skb;
+ }
+ e1000_consume_page(buffer_info, rxtop, length);
+ goto next_desc;
+ } else {
+ if (rxtop) {
+ /* end of the chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the current skb, we only consumed the
+ * page */
+ buffer_info->skb = skb;
+ skb = rxtop;
+ rxtop = NULL;
+ e1000_consume_page(buffer_info, skb, length);
+ } else {
+ /* no chain, got EOP, this buf is the packet
+ * copybreak to save the put_page/alloc_page */
+ if (length <= copybreak &&
+ skb_tailroom(skb) >= length) {
+ u8 *vaddr;
+ vaddr = kmap_atomic(buffer_info->page,
+ KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr, length);
+ kunmap_atomic(vaddr,
+ KM_SKB_DATA_SOFTIRQ);
+ /* re-use the page, so don't erase
+ * buffer_info->page */
+ skb_put(skb, length);
+ } else {
+ skb_fill_page_desc(skb, 0,
+ buffer_info->page, 0,
+ length);
+ e1000_consume_page(buffer_info, skb,
+ length);
+ }
+ }
+ }
+
+ /* Receive Checksum Offload XXX recompute due to CRC strip? */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ pskb_trim(skb, skb->len - 4);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ /* eth type trans needs skb->data to point to something */
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
+ DPRINTK(DRV, ERR, "pskb_may_pull failed.\n");
+ dev_kfree_skb(skb);
+ goto next_desc;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
+
+next_desc:
+ rx_desc->status = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = E1000_DESC_UNUSED(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+
+ 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;
+ return cleaned;
+}
+
+/**
* e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure
- **/
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ */
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do)
@@ -4001,7 +4251,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info, *next_buffer;
unsigned long flags;
u32 length;
- u8 last_byte;
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
@@ -4033,9 +4282,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
cleaned = true;
cleaned_count++;
- pci_unmap_single(pdev,
- buffer_info->dma,
- buffer_info->length,
+ pci_unmap_single(pdev, buffer_info->dma, buffer_info->length,
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
@@ -4052,7 +4299,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
}
if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
- last_byte = *(skb->data + length - 1);
+ u8 last_byte = *(skb->data + length - 1);
if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -4107,13 +4354,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
- if (unlikely(adapter->vlgrp &&
- (status & E1000_RXD_STAT_VP))) {
- vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->special));
- } else {
- netif_receive_skb(skb);
- }
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
next_desc:
rx_desc->status = 0;
@@ -4142,6 +4383,114 @@ next_desc:
}
/**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void
+e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring, int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = 256 -
+ 16 /*for skb_reserve */ -
+ NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ skb = buffer_info->skb;
+ if (skb) {
+ skb_trim(skb, 0);
+ goto check_page;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ /* Fix for errata 23, can't cross 64kB boundary */
+ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+ struct sk_buff *oldskb = skb;
+ 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);
+ /* Failed allocation, critical failure */
+ if (!skb) {
+ dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+ /* give up */
+ dev_kfree_skb(skb);
+ dev_kfree_skb(oldskb);
+ break; /* while (cleaned_count--) */
+ }
+
+ /* 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:
+ /* allocate a new page if necessary */
+ if (!buffer_info->page) {
+ buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!buffer_info->page)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+ }
+
+ if (!buffer_info->dma)
+ buffer_info->dma = pci_map_page(pdev,
+ buffer_info->page, 0,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ if (unlikely(++i == rx_ring->count))
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(i-- == 0))
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+ writel(i, adapter->hw.hw_addr + rx_ring->rdt);
+ }
+}
+
+/**
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
* @adapter: address of board private structure
**/
@@ -4186,6 +4535,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break;
}
@@ -4193,6 +4543,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* give up */
dev_kfree_skb(skb);
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
@@ -4210,9 +4561,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
map_skb:
buffer_info->dma = pci_map_single(pdev,
skb->data,
- adapter->rx_buffer_len,
+ buffer_info->length,
PCI_DMA_FROMDEVICE);
+ /*
+ * XXX if it was allocated cleanly it will never map to a
+ * boundary crossing
+ */
+
/* Fix for errata 23, can't cross 64kB boundary */
if (!e1000_check_64k_bound(adapter,
(void *)(unsigned long)buffer_info->dma,
@@ -4229,6 +4585,7 @@ map_skb:
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
rx_desc = E1000_RX_DESC(*rx_ring, i);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index cc2ab6412c73..53317a83857a 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue (dev);
@@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
eepro_en_int(ioaddr);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -1784,7 +1784,7 @@ int __init init_module(void)
printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
}
- for (i = 0; io[i] != -1 && i < MAX_EEPRO; i++) {
+ for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
dev = alloc_etherdev(sizeof(struct eepro_local));
if (!dev)
break;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 1686dca28748..d1b6368faacd 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
if (buf->len < ETH_ZLEN) {
if (skb_padto(buf, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
#endif
enable_irq(dev->irq);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1474,13 +1474,13 @@ static void eexp_hw_init586(struct net_device *dev)
outw(0x0000, ioaddr + 0x800c);
outw(0x0000, ioaddr + 0x800e);
- for (i = 0; i < (sizeof(start_code)); i+=32) {
+ for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
int j;
outw(i, ioaddr + SM_PTR);
- for (j = 0; j < 16; j+=2)
+ for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
outw(start_code[(i+j)/2],
ioaddr+0x4000+j);
- for (j = 0; j < 16; j+=2)
+ for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
outw(start_code[(i+j+16)/2],
ioaddr+0x8000+j);
}
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index fc6cc038c7b8..372d6c6a4e7f 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
priv->tx_skb = skb;
schedule_work(&priv->tx_work);
- return 0;
+ return NETDEV_TX_OK;
}
static void enc28j60_tx_work_handler(struct work_struct *work)
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 88d7ebf31220..d668ff2af6e3 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -969,7 +969,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Caution: the write order is important here, set the field with the
"ownership" bit last. */
@@ -1013,7 +1013,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, (int)skb->len, entry, ctrl_word,
(int)inl(dev->base_addr + TxSTAT));
- return 0;
+ return NETDEV_TX_OK;
}
static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 19b7dd983944..c0e69c5cae84 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&eql->queue.lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 0d8b6da046f2..97d5205edc8f 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
status = 0;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void eth16i_rx(struct net_device *dev)
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index ceb6a9c357ad..4dbe5f173273 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -894,7 +894,7 @@ static int ethoc_probe(struct platform_device *pdev)
mmio = devm_request_mem_region(&pdev->dev, res->start,
res->end - res->start + 1, res->name);
- if (!res) {
+ if (!mmio) {
dev_err(&pdev->dev, "cannot request I/O memory space\n");
ret = -ENXIO;
goto free;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 1e9723281405..9c51bc813ad3 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
if (inb (EWRK3_FMQC) == 0)
netif_stop_queue (dev);
- return 0;
+ return NETDEV_TX_OK;
err_out:
ENABLE_IRQs;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 48385c42ab57..f66da84a9398 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -584,7 +584,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (np->flags == HAS_MII_XCVR) {
int phy, phy_idx = 0;
- for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
+ for (phy = 1; phy < 32 && phy_idx < ARRAY_SIZE(np->phys);
+ phy++) {
int mii_status = mdio_read(dev, phy, 1);
if (mii_status != 0xffff && mii_status != 0x0000) {
@@ -1377,7 +1378,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d4b98074b1b7..6ec0cfc8a77f 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&fep->hw_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
@@ -1141,19 +1141,9 @@ static void __inline__ fec_request_mii_intr(struct net_device *dev)
printk("FEC: Could not allocate fec(MII) IRQ(66)!\n");
}
-static void __inline__ fec_disable_phy_intr(void)
+static void __inline__ fec_disable_phy_intr(struct net_device *dev)
{
- volatile unsigned long *icrp;
- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = 0x08000000;
-}
-
-static void __inline__ fec_phy_ack_intr(void)
-{
- volatile unsigned long *icrp;
- /* Acknowledge the interrupt */
- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = 0x0d000000;
+ free_irq(66, dev);
}
#endif
@@ -1385,7 +1375,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
writel(0, fep->hwp + FEC_MII_SPEED);
fep->phy_speed = 0;
#ifdef HAVE_mii_link_interrupt
- fec_disable_phy_intr();
+ fec_disable_phy_intr(dev);
#endif
}
}
@@ -1398,8 +1388,6 @@ mii_link_interrupt(int irq, void * dev_id)
struct net_device *dev = dev_id;
struct fec_enet_private *fep = netdev_priv(dev);
- fec_phy_ack_intr();
-
mii_do_cmd(dev, fep->phy->ack_int);
mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index b892c3ad9a74..2bc2d2b20644 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -754,17 +754,16 @@ static int fs_init_phy(struct net_device *dev)
fep->oldlink = 0;
fep->oldspeed = 0;
fep->oldduplex = -1;
- if(fep->fpi->phy_node)
- phydev = of_phy_connect(dev, fep->fpi->phy_node,
- &fs_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
- else {
- printk("No phy bus ID specified in BSP code\n");
- return -EINVAL;
+
+ phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (!phydev) {
+ phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link,
+ PHY_INTERFACE_MODE_MII);
}
- if (IS_ERR(phydev)) {
- printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phydev);
+ if (!phydev) {
+ dev_err(&dev->dev, "Could not attach to PHY\n");
+ return -ENODEV;
}
fep->phydev = phydev;
@@ -1005,6 +1004,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
goto out_free_fpi;
}
+ SET_NETDEV_DEV(ndev, &ofdev->dev);
dev_set_drvdata(&ofdev->dev, ndev);
fep = netdev_priv(ndev);
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 75a09994d665..a2d69c1cd07e 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,7 @@
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <asm/mpc5xxx.h>
#include "fs_enet.h"
#include "fec.h"
@@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = NULL;
struct resource res;
struct mii_bus *new_bus;
struct fec_info *fec;
- int ret = -ENOMEM, i;
+ int (*get_bus_freq)(struct device_node *) = match->data;
+ int ret = -ENOMEM, clock, speed;
new_bus = mdiobus_alloc();
if (!new_bus)
@@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
if (!fec->fecp)
goto out_fec;
- fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+ if (get_bus_freq) {
+ clock = get_bus_freq(ofdev->node);
+ if (!clock) {
+ /* Use maximum divider if clock is unknown */
+ dev_warn(&ofdev->dev, "could not determine IPS clock\n");
+ clock = 0x3F * 5000000;
+ }
+ } else
+ clock = ppc_proc_freq;
+
+ /*
+ * Scale for a MII clock <= 2.5 MHz
+ * Note that only 6 bits (25:30) are available for MII speed.
+ */
+ speed = (clock + 4999999) / 5000000;
+ if (speed > 0x3F) {
+ speed = 0x3F;
+ dev_err(&ofdev->dev,
+ "MII clock (%d Hz) exceeds max (2.5 MHz)\n",
+ clock / speed);
+ }
+
+ fec->mii_speed = speed << 1;
setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
FEC_ECNTRL_ETHER_EN);
out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
- out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+ clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed);
new_bus->phy_mask = ~0;
new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
{
.compatible = "fsl,pq1-fec-mdio",
},
+#if defined(CONFIG_PPC_MPC512x)
+ {
+ .compatible = "fsl,mpc5121-fec-mdio",
+ .data = mpc5xxx_get_bus_frequency,
+ },
+#endif
{},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 43d813ed9f45..056ba4625780 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -264,15 +264,6 @@ static int gfar_of_init(struct net_device *dev)
priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
- if (!priv->phy_node) {
- u32 *fixed_link;
-
- fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
- if (!fixed_link) {
- err = -ENODEV;
- goto err_out;
- }
- }
/* Find the TBI PHY. If it's not there, we don't support SGMII */
priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -306,7 +297,6 @@ static int gfar_probe(struct of_device *ofdev,
u32 tempval;
struct net_device *dev = NULL;
struct gfar_private *priv = NULL;
- DECLARE_MAC_BUF(mac);
int err = 0;
int len_devname;
@@ -659,13 +649,14 @@ static int init_phy(struct net_device *dev)
interface = gfar_get_interface(dev);
- if (priv->phy_node) {
- priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link,
- 0, interface);
- if (!priv->phydev) {
- dev_err(&dev->dev, "error: Could not attach to PHY\n");
- return -ENODEV;
- }
+ priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, 0,
+ interface);
+ if (!priv->phydev)
+ priv->phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+ interface);
+ if (!priv->phydev) {
+ dev_err(&dev->dev, "could not attach to PHY\n");
+ return -ENODEV;
}
if (interface == PHY_INTERFACE_MODE_SGMII)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index dbf06e9313cc..2234118eedbb 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -366,9 +366,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
return -EINVAL;
}
- priv->rxic = mk_ic_value(
- gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs),
- cvals->rx_max_coalesced_frames);
+ priv->rxic = mk_ic_value(cvals->rx_max_coalesced_frames,
+ gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs));
/* Set up tx coalescing */
if ((cvals->tx_coalesce_usecs == 0) ||
@@ -390,9 +389,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
return -EINVAL;
}
- priv->txic = mk_ic_value(
- gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs),
- cvals->tx_max_coalesced_frames);
+ priv->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
+ gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
gfar_write(&priv->regs->rxic, 0);
if (priv->rxcoalescing)
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index d62378cbc149..635341d6a028 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1372,7 +1372,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",
dev->name, hmp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 981ab530e9ac..6cb2bdfd7b19 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int sp_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 352703255bba..7bcaf7c66243 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(bc, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (bc->skb)
return NETDEV_TX_LOCKED;
/* strip KISS byte */
if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
bc->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index abcd19a8bff9..4c5f4dfbe05e 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
dev_queue_xmit(skb);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 7459b3ac77a9..950f3bb21f9d 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->ring_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index d034f8ca63cb..16b060b92117 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(sm, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sm->skb)
return NETDEV_TX_LOCKED;
netif_stop_queue(dev);
sm->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index fda2fc83e9a1..ac191ef2119b 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
static int ax_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index d712e7af780c..c5406525c1ad 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (skb->len > scc->stat.bufsize || skb->len < 2) {
scc->dev_stat.tx_dropped++; /* bogus frame */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
scc->dev_stat.tx_packets++;
@@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (kisscmd) {
scc_set_param(scc, kisscmd, *skb->data);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&scc->lock, flags);
@@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
__scc_start_tx_timer(scc, t_dwait, 0);
}
spin_unlock_irqrestore(&scc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* ----> ioctl functions <---- */
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index b06691937ce9..b85aa162314e 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&yp->send_queue, skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 1d3429a415e6..d1b63387e9bc 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
goto drop;
if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Get Tx ring tail pointer */
if (lp->txrtail->next == lp->txrhead) {
@@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
lp->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
@@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("hp100: %s: start_xmit: end\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index beb84213b671..5443558c439d 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len)
++dev->stats.tx_packets;
dev->stats.tx_bytes += len;
- return 0;
+ return NETDEV_TX_OK;
}
/* Tx lock BH */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0995c438f286..76b295a18185 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags);
spin_unlock_irqrestore(&adapter->stats_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int ibmveth_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 96713ef06298..0a79b4517804 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
u32 from = G_TC_FROM(skb->tc_verd);
stats->rx_packets++;
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index ac28dd5a4fd1..6158c0f3b205 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -53,7 +53,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *);
+static void igb_configure_pcs_link_82575(struct e1000_hw *);
static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
u16 *);
static s32 igb_get_phy_id_82575(struct e1000_hw *);
@@ -61,6 +61,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *, u16);
static bool igb_sgmii_active_82575(struct e1000_hw *);
static s32 igb_reset_init_script_82575(struct e1000_hw *);
static s32 igb_read_mac_addr_82575(struct e1000_hw *);
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
{
@@ -84,6 +85,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
mac->type = e1000_82576;
break;
default:
@@ -170,6 +172,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
size = 14;
nvm->word_size = 1 << size;
+ /* if 82576 then initialize mailbox parameters */
+ if (mac->type == e1000_82576)
+ igb_init_mbx_params_pf(hw);
+
/* setup PHY parameters */
if (phy->media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
@@ -219,10 +225,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
- /* if 82576 then initialize mailbox parameters */
- if (mac->type == e1000_82576)
- igb_init_mbx_params_pf(hw);
-
return 0;
}
@@ -764,98 +766,6 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
}
/**
- * igb_init_rx_addrs_82575 - Initialize receive address's
- * @hw: pointer to the HW structure
- * @rar_count: receive address registers
- *
- * Setups the receive address registers by setting the base receive address
- * register to the devices MAC address and clearing all the other receive
- * address registers to 0.
- **/
-static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count)
-{
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * e1000_init_rx_addrs_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- hw_dbg("e1000_init_rx_addrs_82575");
-
- /* Setup the receive address */
- hw_dbg("Programming MAC Address into RAR[0]\n");
- hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
- /* Zero out the other (rar_entry_count - 1) receive addresses */
- hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
- for (i = 1; i < rar_count; i++)
- hw->mac.ops.rar_set(hw, addr, i);
-}
-
-/**
- * igb_update_mc_addr_list - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
- *
- * Updates the Receive Address Registers and Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
- **/
-void igb_update_mc_addr_list(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count,
- u32 rar_used_count, u32 rar_count)
-{
- u32 hash_value;
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * igb_update_mc_addr_list_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- /*
- * Load the first set of multicast addresses into the exact
- * filters (RAR). If there are not enough to fill the RAR
- * array, clear the filters.
- */
- for (i = rar_used_count; i < rar_count; i++) {
- if (mc_addr_count) {
- igb_rar_set(hw, mc_addr_list, i);
- mc_addr_count--;
- mc_addr_list += ETH_ALEN;
- } else {
- igb_rar_set(hw, addr, i);
- }
- }
-
- /* Clear the old settings from the MTA */
- hw_dbg("Clearing MTA\n");
- for (i = 0; i < hw->mac.mta_reg_count; i++) {
- array_wr32(E1000_MTA, i, 0);
- wrfl();
- }
-
- /* Load any remaining multicast addresses into the hash table. */
- for (; mc_addr_count > 0; mc_addr_count--) {
- hash_value = igb_hash_mc_addr(hw, mc_addr_list);
- hw_dbg("Hash value = 0x%03X\n", hash_value);
- igb_mta_set(hw, hash_value);
- mc_addr_list += ETH_ALEN;
- }
-}
-
-/**
* igb_shutdown_fiber_serdes_link_82575 - Remove link during power down
* @hw: pointer to the HW structure
*
@@ -866,9 +776,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
- if (hw->mac.type != e1000_82576 ||
- (hw->phy.media_type != e1000_media_type_fiber &&
- hw->phy.media_type != e1000_media_type_internal_serdes))
+ if (hw->phy.media_type != e1000_media_type_internal_serdes)
return;
/* if the management interface is not enabled, then power down */
@@ -911,6 +819,12 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
if (ret_val)
hw_dbg("PCI-E Master disable polling has failed.\n");
+ /* set the completion timeout for interface */
+ ret_val = igb_set_pcie_completion_timeout(hw);
+ if (ret_val) {
+ hw_dbg("PCI-E Set completion timeout has failed.\n");
+ }
+
hw_dbg("Masking off all interrupts\n");
wr32(E1000_IMC, 0xffffffff);
@@ -943,7 +857,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
wr32(E1000_IMC, 0xffffffff);
icr = rd32(E1000_ICR);
- igb_check_alt_mac_addr(hw);
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = igb_check_alt_mac_addr(hw);
return ret_val;
}
@@ -972,7 +887,8 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
igb_clear_vfta(hw);
/* Setup the receive address */
- igb_init_rx_addrs_82575(hw, rar_count);
+ igb_init_rx_addrs(hw, rar_count);
+
/* Zero out the Multicast HASH table */
hw_dbg("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++)
@@ -1002,7 +918,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
**/
static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
{
- u32 ctrl, led_ctrl;
+ u32 ctrl;
s32 ret_val;
bool link;
@@ -1017,11 +933,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
break;
case e1000_phy_igp_3:
ret_val = igb_copper_link_setup_igp(hw);
- /* Setup activity LED */
- led_ctrl = rd32(E1000_LEDCTL);
- led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
- wr32(E1000_LEDCTL, led_ctrl);
break;
default:
ret_val = -E1000_ERR_PHY;
@@ -1052,9 +963,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
}
- ret_val = igb_configure_pcs_link_82575(hw);
- if (ret_val)
- goto out;
+ igb_configure_pcs_link_82575(hw);
/*
* Check link status. Wait up to 100 microseconds for link to become
@@ -1163,14 +1072,14 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
* independent interface (sgmii) is being used. Configures the link
* for auto-negotiation or forces speed/duplex.
**/
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
+static void igb_configure_pcs_link_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 reg = 0;
if (hw->phy.media_type != e1000_media_type_copper ||
!(igb_sgmii_active_82575(hw)))
- goto out;
+ return;
/* For SGMII, we need to issue a PCS autoneg restart */
reg = rd32(E1000_PCS_LCTL);
@@ -1213,9 +1122,6 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
reg);
}
wr32(E1000_PCS_LCTL, reg);
-
-out:
- return 0;
}
/**
@@ -1229,10 +1135,6 @@ out:
static bool igb_sgmii_active_82575(struct e1000_hw *hw)
{
struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
-
- if (hw->mac.type != e1000_82575 && hw->mac.type != e1000_82576)
- return false;
-
return dev_spec->sgmii_active;
}
@@ -1424,6 +1326,57 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
}
/**
+ * igb_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 200ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+ u32 gcr = rd32(E1000_GCR);
+ s32 ret_val = 0;
+ u16 pcie_devctl2;
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & E1000_GCR_CAP_VER2)) {
+ gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+out:
+ /* disable completion timeout resend */
+ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+ wr32(E1000_GCR, gcr);
+ return ret_val;
+}
+
+/**
* igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
* @hw: pointer to the hardware struct
* @enable: state to enter, either enabled or disabled
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index 0f16abab2565..8a1e6597061f 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -28,10 +28,14 @@
#ifndef _E1000_82575_H_
#define _E1000_82575_H_
-void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32);
extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_ON2))
+
#define E1000_RAR_ENTRIES_82575 16
#define E1000_RAR_ENTRIES_82576 24
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 3bda3db73f1f..c85829355d50 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -435,6 +435,12 @@
/* Flow Control */
#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+/* PCI Express Control */
+#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define E1000_GCR_CAP_VER2 0x00040000
+
/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
@@ -569,9 +575,11 @@
/* PCI/PCI-X/PCI-EX Config space */
#define PCIE_LINK_STATUS 0x12
+#define PCIE_DEVICE_CONTROL2 0x28
#define PCIE_LINK_WIDTH_MASK 0x3F0
#define PCIE_LINK_WIDTH_SHIFT 4
+#define PCIE_DEVICE_CONTROL2_16ms 0x0005
#define PHY_REVISION_MASK 0xFFFFFFF0
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 68aac20c31ca..119869b1124d 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_SERDES_QUAD 0x150D
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
@@ -61,8 +62,7 @@ enum e1000_mac_type {
enum e1000_media_type {
e1000_media_type_unknown = 0,
e1000_media_type_copper = 1,
- e1000_media_type_fiber = 2,
- e1000_media_type_internal_serdes = 3,
+ e1000_media_type_internal_serdes = 2,
e1000_num_media_types
};
@@ -137,7 +137,7 @@ enum e1000_rev_polarity {
e1000_rev_polarity_undefined = 0xFF
};
-enum e1000_fc_type {
+enum e1000_fc_mode {
e1000_fc_none = 0,
e1000_fc_rx_pause,
e1000_fc_tx_pause,
@@ -339,6 +339,10 @@ struct e1000_mac_info {
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
u8 forced_speed_duplex;
@@ -425,8 +429,8 @@ struct e1000_fc_info {
u16 pause_time; /* Flow control pause timer */
bool send_xon; /* Flow control send XON */
bool strict_ieee; /* Strict IEEE mode */
- enum e1000_fc_type type; /* Type of flow control */
- enum e1000_fc_type original_type;
+ enum e1000_fc_mode current_mode; /* Type of flow control */
+ enum e1000_fc_mode requested_mode;
};
struct e1000_mbx_operations {
@@ -495,5 +499,7 @@ extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
#else
#define hw_dbg(format, arg...)
#endif
-
#endif
+/* These functions must be implemented by drivers */
+s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 472f3f124840..a0231cd079f1 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -37,20 +37,6 @@
static s32 igb_set_default_fc(struct e1000_hw *hw);
static s32 igb_set_fc_watermarks(struct e1000_hw *hw);
-static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
- struct igb_adapter *adapter = hw->back;
- u16 cap_offset;
-
- cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
- if (!cap_offset)
- return -E1000_ERR_CONFIG;
-
- pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
- return 0;
-}
-
/**
* igb_get_bus_info_pcie - Get PCIe bus information
* @hw: pointer to the HW structure
@@ -118,6 +104,31 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
}
/**
+ * igb_init_rx_addrs - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+ u32 i;
+ u8 mac_addr[ETH_ALEN] = {0};
+
+ /* Setup the receive address */
+ hw_dbg("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
* igb_vfta_set - enable or disable vlan in VLAN filter table
* @hw: pointer to the HW structure
* @vid: VLAN id to add or remove
@@ -275,6 +286,41 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
}
/**
+ * igb_update_mc_addr_list - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count)
+{
+ u32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ /* clear mta_shadow */
+ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (u32) i < mc_addr_count; i++) {
+ hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ALEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]);
+ wrfl();
+}
+
+/**
* igb_hash_mc_addr - Generate a multicast hash value
* @hw: pointer to the HW structure
* @mc_addr: pointer to a multicast address
@@ -490,18 +536,24 @@ s32 igb_setup_link(struct e1000_hw *hw)
if (igb_check_reset_block(hw))
goto out;
- ret_val = igb_set_default_fc(hw);
- if (ret_val)
- goto out;
+ /*
+ * If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = igb_set_default_fc(hw);
+ if (ret_val)
+ goto out;
+ }
/*
* We want to save off the original Flow Control configuration just
* in case we get disconnected and then reconnected into a different
* hub or switch with different Flow Control capabilities.
*/
- hw->fc.original_type = hw->fc.type;
+ hw->fc.current_mode = hw->fc.requested_mode;
- hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type);
+ hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
/* Call the necessary media_type subroutine to configure the link. */
ret_val = hw->mac.ops.setup_physical_interface(hw);
@@ -568,7 +620,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
* ability to transmit pause frames is not enabled, then these
* registers will be set to 0.
*/
- if (hw->fc.type & e1000_fc_tx_pause) {
+ if (hw->fc.current_mode & e1000_fc_tx_pause) {
/*
* We need to set up the Receive Threshold high and low water
* marks as well as (optionally) enabling the transmission of
@@ -615,12 +667,12 @@ static s32 igb_set_default_fc(struct e1000_hw *hw)
}
if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
- hw->fc.type = e1000_fc_none;
+ hw->fc.requested_mode = e1000_fc_none;
else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
NVM_WORD0F_ASM_DIR)
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.requested_mode = e1000_fc_tx_pause;
else
- hw->fc.type = e1000_fc_full;
+ hw->fc.requested_mode = e1000_fc_full;
out:
return ret_val;
@@ -650,7 +702,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* receive flow control.
*
* The "Case" statement below enables/disable flow control
- * according to the "hw->fc.type" parameter.
+ * according to the "hw->fc.current_mode" parameter.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
@@ -661,9 +713,9 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* 3: Both Rx and TX flow control (symmetric) is enabled.
* other: No other values should be possible at this point.
*/
- hw_dbg("hw->fc.type = %u\n", hw->fc.type);
+ hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
@@ -713,8 +765,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* configuration of the MAC to match the "fc" parameter.
*/
if (mac->autoneg_failed) {
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes)
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
ret_val = igb_force_mac_fc(hw);
} else {
if (hw->phy.media_type == e1000_media_type_copper)
@@ -812,11 +863,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
- if (hw->fc.original_type == e1000_fc_full) {
- hw->fc.type = e1000_fc_full;
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
hw_dbg("Flow Control = FULL.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = "
"RX PAUSE frames only.\r\n");
}
@@ -833,7 +884,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.current_mode = e1000_fc_tx_pause;
hw_dbg("Flow Control = TX PAUSE frames only.\r\n");
}
/*
@@ -848,7 +899,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
/*
@@ -872,13 +923,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if ((hw->fc.original_type == e1000_fc_none ||
- hw->fc.original_type == e1000_fc_tx_pause) ||
+ else if ((hw->fc.requested_mode == e1000_fc_none ||
+ hw->fc.requested_mode == e1000_fc_tx_pause) ||
hw->fc.strict_ieee) {
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
hw_dbg("Flow Control = NONE.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
@@ -894,7 +945,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
}
if (duplex == HALF_DUPLEX)
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/*
* Now we call a subroutine to actually force the MAC
@@ -1065,9 +1116,17 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
goto out;
}
- if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
- *data = ID_LED_DEFAULT;
-
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch(hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_82575_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+ }
out:
return ret_val;
}
@@ -1161,22 +1220,16 @@ s32 igb_blink_led(struct e1000_hw *hw)
u32 ledctl_blink = 0;
u32 i;
- if (hw->phy.media_type == e1000_media_type_fiber) {
- /* always blink LED0 for PCI-E fiber */
- ledctl_blink = E1000_LEDCTL_LED0_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
- } else {
- /*
- * set the blink bit for each LED that's "on" (0x0E)
- * in ledctl_mode2
- */
- ledctl_blink = hw->mac.ledctl_mode2;
- for (i = 0; i < 4; i++)
- if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
- E1000_LEDCTL_MODE_LED_ON)
- ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
- (i * 8));
- }
+ /*
+ * set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2
+ */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
wr32(E1000_LEDCTL, ledctl_blink);
@@ -1191,15 +1244,7 @@ s32 igb_blink_led(struct e1000_hw *hw)
**/
s32 igb_led_off(struct e1000_hw *hw)
{
- u32 ctrl;
-
switch (hw->phy.media_type) {
- case e1000_media_type_fiber:
- ctrl = rd32(E1000_CTRL);
- ctrl |= E1000_CTRL_SWDPIN0;
- ctrl |= E1000_CTRL_SWDPIO0;
- wr32(E1000_CTRL, ctrl);
- break;
case e1000_media_type_copper:
wr32(E1000_LEDCTL, hw->mac.ledctl_mode1);
break;
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
index 1d690b4c9ae4..7518af8cbbf5 100644
--- a/drivers/net/igb/e1000_mac.h
+++ b/drivers/net/igb/e1000_mac.h
@@ -51,6 +51,8 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
s32 igb_id_led_init(struct e1000_hw *hw);
s32 igb_led_off(struct e1000_hw *hw);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count);
s32 igb_setup_link(struct e1000_hw *hw);
s32 igb_validate_mdi_setting(struct e1000_hw *hw);
s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
@@ -60,6 +62,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
void igb_clear_vfta(struct e1000_hw *hw);
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
void igb_put_hw_semaphore(struct e1000_hw *hw);
void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index f50fac25be40..c1f4da630420 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -735,7 +735,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
* other: No software override. The flow control configuration
* in the EEPROM is used.
*/
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
/*
* Flow control (RX & TX) is completely disabled by a
@@ -992,7 +992,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
u32 ctrl;
/* Turn off flow control when forcing speed/duplex */
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/* Force speed/duplex on the mac */
ctrl = rd32(E1000_CTRL);
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 6e5924511e40..345d1442d6d6 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -305,6 +305,7 @@ enum {
#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
#define E1000_SWSM 0x05B50 /* SW Semaphore */
#define E1000_FWSM 0x05B54 /* FW Semaphore */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 9598ac09f4b8..114ccab1f2be 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -168,8 +168,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->duplex = -1;
}
- ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
- hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
return 0;
}
@@ -191,23 +190,20 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->mac.autoneg = 1;
- if (hw->phy.media_type == e1000_media_type_fiber)
- hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
- ADVERTISED_FIBRE |
- ADVERTISED_Autoneg;
- else
- hw->phy.autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
ecmd->advertising = hw->phy.autoneg_advertised;
- } else
+ if (adapter->fc_autoneg)
+ hw->fc.requested_mode = e1000_fc_default;
+ } else {
if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
clear_bit(__IGB_RESETTING, &adapter->state);
return -EINVAL;
}
+ }
/* reset the link */
-
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
@@ -227,11 +223,11 @@ static void igb_get_pauseparam(struct net_device *netdev,
pause->autoneg =
(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
- if (hw->fc.type == e1000_fc_rx_pause)
+ if (hw->fc.current_mode == e1000_fc_rx_pause)
pause->rx_pause = 1;
- else if (hw->fc.type == e1000_fc_tx_pause)
+ else if (hw->fc.current_mode == e1000_fc_tx_pause)
pause->tx_pause = 1;
- else if (hw->fc.type == e1000_fc_full) {
+ else if (hw->fc.current_mode == e1000_fc_full) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
@@ -249,26 +245,28 @@ static int igb_set_pauseparam(struct net_device *netdev,
while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
msleep(1);
- if (pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_full;
- else if (pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_rx_pause;
- else if (!pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_tx_pause;
- else if (!pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_none;
-
- hw->fc.original_type = hw->fc.type;
-
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+ hw->fc.requested_mode = e1000_fc_default;
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
} else
igb_reset(adapter);
- } else
- retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
- igb_setup_link(hw) : igb_force_mac_fc(hw));
+ } else {
+ if (pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_none;
+
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ retval = ((hw->phy.media_type == e1000_media_type_copper) ?
+ igb_force_mac_fc(hw) : igb_setup_link(hw));
+ }
clear_bit(__IGB_RESETTING, &adapter->state);
return retval;
@@ -1483,8 +1481,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 reg;
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes) {
+ if (hw->phy.media_type == e1000_media_type_internal_serdes) {
reg = rd32(E1000_RCTL);
reg |= E1000_RCTL_LBM_TCVR;
wr32(E1000_RCTL, reg);
@@ -1843,7 +1840,6 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
@@ -1852,11 +1848,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
!device_can_wakeup(&adapter->pdev->dev))
return wol->wolopts ? -EOPNOTSUPP : 0;
- switch (hw->device_id) {
- default:
- break;
- }
-
/* these settings will always override what we currently have */
adapter->wol = 0;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index adb09d32625d..fb3273517587 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -65,6 +65,7 @@ static struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), 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 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
@@ -127,7 +128,7 @@ static void igb_restore_vlan(struct igb_adapter *);
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 void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
+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);
@@ -1129,7 +1130,7 @@ void igb_reset(struct igb_adapter *adapter)
}
fc->pause_time = 0xFFFF;
fc->send_xon = 1;
- fc->type = fc->original_type;
+ fc->current_mode = fc->requested_mode;
/* disable receive for all VFs and wait one second */
if (adapter->vfs_allocated_count) {
@@ -1426,8 +1427,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
hw->mac.autoneg = true;
hw->phy.autoneg_advertised = 0x2f;
- hw->fc.original_type = e1000_fc_default;
- hw->fc.type = e1000_fc_default;
+ hw->fc.requested_mode = e1000_fc_default;
+ hw->fc.current_mode = e1000_fc_default;
adapter->itr_setting = IGB_DEFAULT_ITR;
adapter->itr = IGB_START_ITR;
@@ -2535,7 +2536,6 @@ static void igb_set_multi(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct e1000_mac_info *mac = &hw->mac;
struct dev_mc_list *mc_ptr;
u8 *mta_list = NULL;
u32 rctl;
@@ -2558,13 +2558,18 @@ static void igb_set_multi(struct net_device *netdev)
}
wr32(E1000_RCTL, rctl);
- if (netdev->mc_count) {
- mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
- if (!mta_list) {
- dev_err(&adapter->pdev->dev,
- "failed to allocate multicast filter list\n");
- return;
- }
+ 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;
+ }
+
+ mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list) {
+ dev_err(&adapter->pdev->dev,
+ "failed to allocate multicast filter list\n");
+ return;
}
/* The shared function expects a packed array of only addresses. */
@@ -2576,14 +2581,9 @@ static void igb_set_multi(struct net_device *netdev)
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,
- adapter->vfs_allocated_count + 1,
- mac->rar_entry_count);
-
- igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
- igb_restore_vf_multicasts(adapter);
-
+ igb_update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
+ igb_restore_vf_multicasts(adapter);
}
/* Need to wait a few seconds after link up to get diagnostic information from
@@ -2618,10 +2618,6 @@ static bool igb_has_link(struct igb_adapter *adapter)
link_active = true;
}
break;
- case e1000_media_type_fiber:
- ret_val = hw->mac.ops.check_for_link(hw);
- link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU);
- break;
case e1000_media_type_internal_serdes:
ret_val = hw->mac.ops.check_for_link(hw);
link_active = hw->mac.serdes_has_link;
@@ -4542,6 +4538,20 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
adapter->hw_csum_good++;
}
+static inline u16 igb_get_hlen(struct igb_adapter *adapter,
+ union e1000_adv_rx_desc *rx_desc)
+{
+ /* HW will not DMA in data larger than the given buffer, even if it
+ * parses the (NFS, of course) header to be larger. In that case, it
+ * fills the header buffer and spills the rest into the page.
+ */
+ u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
+ E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
+ if (hlen > adapter->rx_ps_hdr_size)
+ hlen = adapter->rx_ps_hdr_size;
+ return hlen;
+}
+
static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int *work_done, int budget)
{
@@ -4556,7 +4566,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int cleaned_count = 0;
unsigned int total_bytes = 0, total_packets = 0;
unsigned int i;
- u32 length, hlen, staterr;
+ u32 staterr;
+ u16 length;
i = rx_ring->next_to_clean;
buffer_info = &rx_ring->buffer_info[i];
@@ -4593,17 +4604,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
goto send_up;
}
- /* HW will not DMA in data larger than the given buffer, even
- * if it parses the (NFS, of course) header to be larger. In
- * that case, it fills the header buffer and spills the rest
- * into the page.
- */
- hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
- E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
- if (hlen > adapter->rx_ps_hdr_size)
- hlen = adapter->rx_ps_hdr_size;
-
- if (!skb_shinfo(skb)->nr_frags) {
+ if (buffer_info->dma) {
+ u16 hlen = igb_get_hlen(adapter, rx_desc);
pci_unmap_single(pdev, buffer_info->dma,
adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
@@ -5033,6 +5035,34 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
}
+s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+ return 0;
+}
+
+s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+
+ return 0;
+}
+
static void igb_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp)
{
@@ -5136,14 +5166,6 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
mac->autoneg = 0;
- /* Fiber NICs only allow 1000 gbps Full duplex */
- if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- dev_err(&adapter->pdev->dev,
- "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
- }
-
switch (spddplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
@@ -5452,19 +5474,6 @@ static void igb_io_resume(struct pci_dev *pdev)
igb_get_hw_control(adapter);
}
-static void igb_set_mc_list_pools(struct igb_adapter *adapter,
- int entry_count, u16 total_rar_filters)
-{
- struct e1000_hw *hw = &adapter->hw;
- int i = adapter->vfs_allocated_count + 1;
-
- if ((i + entry_count) < total_rar_filters)
- total_rar_filters = i + entry_count;
-
- for (; i < total_rar_filters; i++)
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
-}
-
static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr)
{
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 2bc9d63027db..3f03c42ece97 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -149,7 +149,6 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
bufsz = adapter->rx_ps_hdr_size;
else
bufsz = adapter->rx_buffer_len;
- bufsz += NET_IP_ALIGN;
while (cleaned_count--) {
rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i);
@@ -173,7 +172,7 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
}
if (!buffer_info->skb) {
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
@@ -286,7 +285,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
if (!skb_shinfo(skb)->nr_frags) {
pci_unmap_single(pdev, buffer_info->dma,
- adapter->rx_ps_hdr_size + NET_IP_ALIGN,
+ adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
skb_put(skb, hlen);
}
@@ -2512,6 +2511,9 @@ static pci_ers_result_t igbvf_io_error_detected(struct pci_dev *pdev,
netif_device_detach(netdev);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev))
igbvf_down(adapter);
pci_disable_device(pdev);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e3cfefab670c..8ec15ab8c8c2 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&ip->ioc3_lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void ioc3_timeout(struct net_device *dev)
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index ad1795580028..f0d0cea6e329 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
@@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.sir_base;
@@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index c4361d466597..22baf65e1563 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
aup->newspeed = 0;
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
ptxd = aup->tx_ring[aup->tx_head];
@@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 9a0346e751ac..e4e905698dc7 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT (self != NULL, return 0; );
+ IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__
,skb->len,self->txpending,INB (OBOE_ENABLEH));
@@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
{
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* True packet, go on, but */
/* do not accept anything before change speed execution */
@@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
toshoboe_setbaud (self);
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>');
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*interrupt handler */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 0c0831c03f64..6a1aa7a40fe2 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
}
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop:
/* Drop silently the skb and exit */
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 45fd9c1eb343..51ca89c9a0ba 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
@@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
@@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else {
/* Change speed after current frame */
self->new_speed = speed;
@@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 3376a4f39e0a..e76a083f901a 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
pxa_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 2aeb2e6aec1b..70e6acc597b0 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
sa1100_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!IS_FIR(si)) {
@@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index fd0796c3db3c..71dce20e62be 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
int err;
s32 speed;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
netif_stop_queue(ndev);
@@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
dev->new_speed = speed;
}
@@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* called from network layer with rtnl hold */
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index d0797adb5f8e..15f8a7f81600 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(1, "%s\n", __func__);
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
}
@@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
s32 speed;
int mtt;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
@@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 8e5e45caf2f1..c475b23091bc 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 864798502ff9..36a60748447b 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
__u32 speed;
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
netif_stop_queue(dev);
@@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
@@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
iobase = self->io.fir_base;
if (self->st_fifo.len)
- return 0;
+ return NETDEV_TX_OK;
if (self->chip_id == 0x3076)
iodelay(1500);
else
@@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
dev->trans_start = jiffies;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index ac0e4b6b6b66..08e26f1297b4 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
spin_unlock_irqrestore(&idev->lock, flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* sanity checks - simply drop the packet */
@@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&idev->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_unlock:
spin_unlock_irqrestore(&idev->lock, flags);
@@ -1058,7 +1058,7 @@ drop:
* packet for later retry of transmission - which isn't exactly
* what we want after we've just called dev_kfree_skb_any ;-)
*/
- return 0;
+ return NETDEV_TX_OK;
}
static void vlsi_tx_interrupt(struct net_device *ndev)
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index d0883835b0c6..49ef76320f51 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
w83977af_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore set register */
outb(set, iobase+SSR);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index d12377b84358..9706e64e367b 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -468,7 +468,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
#if TX_RING
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index e44215cb1882..e36e951cbc65 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ( ! ((1 << rlp) & port->lpar_map) ) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
lpmask = 1 << rlp;
@@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* You must hold the connection's lock when you call this function. */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 9c897cf86b9f..fad08ce8a6c3 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (skb->len <= 0) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring,
@@ -2227,6 +2227,11 @@ static pci_ers_result_t ixgb_io_error_detected(struct pci_dev *pdev,
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgb_adapter *adapter = netdev_priv(netdev);
+ netif_device_detach(netdev);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev))
ixgb_down(adapter, true);
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index cd22323cfd22..62b6c028ae81 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -96,6 +96,8 @@
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
+#define IXGBE_MAX_RSC_INT_RATE 162760
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
@@ -229,10 +231,6 @@ struct ixgbe_q_vector {
#define IXGBE_TX_CTXTDESC_ADV(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
-#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
-#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc)
-#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc)
-
#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
#ifdef IXGBE_FCOE
/* Use 3K as the baby jumbo frame size for FCoE */
@@ -327,6 +325,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25)
#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26)
#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27)
+#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 28)
#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29)
u32 flags2;
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index b9923047ce11..ed0bb3b20255 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82598AT:
+ case IXGBE_DEV_ID_82598AT2:
media_type = ixgbe_media_type_copper;
break;
default:
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index da2c8514b8d0..1c7265732900 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -139,6 +139,18 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
}
adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
+#ifdef IXGBE_FCOE
+ /* Turn on FCoE offload */
+ if ((adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) &&
+ (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))) {
+ adapter->flags |= IXGBE_FLAG_FCOE_ENABLED;
+ adapter->ring_feature[RING_F_FCOE].indices =
+ IXGBE_FCRETA_SIZE;
+ netdev->features |= NETIF_F_FCOE_CRC;
+ netdev->features |= NETIF_F_FSO;
+ netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
+ }
+#endif /* IXGBE_FCOE */
ixgbe_init_interrupt_scheme(adapter);
if (netif_running(netdev))
netdev->netdev_ops->ndo_open(netdev);
@@ -156,6 +168,18 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
if (adapter->hw.mac.type == ixgbe_mac_82599EB)
adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+#ifdef IXGBE_FCOE
+ /* Turn off FCoE offload */
+ if (adapter->flags & (IXGBE_FLAG_FCOE_CAPABLE |
+ IXGBE_FLAG_FCOE_ENABLED)) {
+ adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+ adapter->ring_feature[RING_F_FCOE].indices = 0;
+ netdev->features &= ~NETIF_F_FCOE_CRC;
+ netdev->features &= ~NETIF_F_FSO;
+ netdev->fcoe_ddp_xid = 0;
+ }
+#endif /* IXGBE_FCOE */
ixgbe_init_interrupt_scheme(adapter);
if (netif_running(netdev))
netdev->netdev_ops->ndo_open(netdev);
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 2a978008fd6e..c6db9a04187d 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
+ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
&tx_ring->dma))) {
@@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
((u64) tx_ring->dma >> 32));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
- tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
+ tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
@@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
for (i = 0; i < tx_ring->count; i++) {
- struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
+ union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
struct sk_buff *skb;
unsigned int size = 1024;
@@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
tx_ring->tx_buffer_info[i].length = skb->len;
tx_ring->tx_buffer_info[i].dma =
pci_map_single(pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
- desc->lower.data = cpu_to_le32(skb->len);
- desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
- IXGBE_TXD_CMD_IFCS |
- IXGBE_TXD_CMD_RS);
- desc->upper.data = 0;
+ PCI_DMA_TODEVICE);
+ desc->read.buffer_addr =
+ cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
+ desc->read.cmd_type_len = cpu_to_le32(skb->len);
+ desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
+ IXGBE_TXD_CMD_IFCS |
+ IXGBE_TXD_CMD_RS);
+ desc->read.olinfo_status = 0;
+ if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ desc->read.olinfo_status |=
+ (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
}
/* Setup Rx Descriptor ring and Rx buffers */
@@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
+ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
rx_ring->size = ALIGN(rx_ring->size, 4096);
if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
&rx_ring->dma))) {
@@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
for (i = 0; i < rx_ring->count; i++) {
- struct ixgbe_legacy_rx_desc *rx_desc =
- IXGBE_RX_DESC(*rx_ring, i);
+ union ixgbe_adv_rx_desc *rx_desc =
+ IXGBE_RX_DESC_ADV(*rx_ring, i);
struct sk_buff *skb;
skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
@@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
rx_ring->rx_buffer_info[i].dma =
pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
PCI_DMA_FROMDEVICE);
- rx_desc->buffer_addr =
+ rx_desc->read.pkt_addr =
cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
@@ -1975,7 +1980,10 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
* any other value means disable eitr, which is best
* served by setting the interrupt rate very high
*/
- adapter->eitr_param = IXGBE_MAX_INT_RATE;
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
+ adapter->eitr_param = IXGBE_MAX_RSC_INT_RATE;
+ else
+ adapter->eitr_param = IXGBE_MAX_INT_RATE;
adapter->itr_setting = 0;
}
@@ -1999,13 +2007,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
ethtool_op_set_flags(netdev, data);
- if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE))
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
return 0;
/* if state changes we need to update adapter->flags and reset */
if ((!!(data & ETH_FLAG_LRO)) !=
- (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) {
- adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED;
+ (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
+ adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
else
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index e3442f47f932..44adc9862826 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -34,6 +34,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
+#include <linux/pkt_sched.h>
#include <linux/ipv6.h>
#include <net/checksum.h>
#include <net/ip6_checksum.h>
@@ -48,7 +49,7 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.34-k2"
+#define DRV_VERSION "2.0.37-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
@@ -74,6 +75,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2),
+ board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
@@ -510,8 +513,11 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
* @skb: skb currently being received and modified
**/
static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
- u32 status_err, struct sk_buff *skb)
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
{
+ u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error);
+
skb->ip_summed = CHECKSUM_NONE;
/* Rx csum disabled */
@@ -529,6 +535,16 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
return;
if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+ u16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+
+ /*
+ * 82599 errata, UDP frames with a 0 checksum can be marked as
+ * checksum errors.
+ */
+ if ((pkt_info & IXGBE_RXDADV_PKTTYPE_UDP) &&
+ (adapter->hw.mac.type == ixgbe_mac_82599EB))
+ return;
+
adapter->hw_csum_rx_error++;
return;
}
@@ -766,7 +782,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
prefetch(next_rxd);
cleaned_count++;
- if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
rsc_count = ixgbe_get_rsc_count(rx_desc);
if (rsc_count) {
@@ -802,7 +818,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
goto next_desc;
}
- ixgbe_rx_checksum(adapter, staterr, skb);
+ ixgbe_rx_checksum(adapter, rx_desc, skb);
/* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len;
@@ -2022,7 +2038,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
}
} else {
- if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) &&
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
(netdev->mtu <= ETH_DATA_LEN))
rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
else
@@ -2151,7 +2167,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
}
- if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) {
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
/* Enable 82599 HW-RSC */
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i].reg_idx;
@@ -3798,16 +3814,17 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
} else if (hw->mac.type == ixgbe_mac_82599EB) {
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
- adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE;
- adapter->flags |= IXGBE_FLAG2_RSC_ENABLED;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
adapter->ring_feature[RING_F_FDIR].indices =
IXGBE_MAX_FDIR_INDICES;
adapter->atr_sample_rate = 20;
adapter->fdir_pballoc = 0;
#ifdef IXGBE_FCOE
- adapter->flags |= IXGBE_FLAG_FCOE_ENABLED;
- adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE;
+ adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
+ adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+ adapter->ring_feature[RING_F_FCOE].indices = 0;
#endif /* IXGBE_FCOE */
}
@@ -4643,13 +4660,13 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (hw->mac.type == ixgbe_mac_82599EB) {
u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- flow_rx = (mflcn & IXGBE_MFLCN_RFCE);
- flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X);
+ flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
} else {
u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
- flow_rx = (frctl & IXGBE_FCTRL_RFCE);
- flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X);
+ flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+ flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
@@ -5125,9 +5142,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
int count = 0;
unsigned int f;
- r_idx = skb->queue_mapping;
- tx_ring = &adapter->tx_ring[r_idx];
-
if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
tx_flags |= vlan_tx_tag_get(skb);
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
@@ -5137,11 +5151,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_VLAN;
} else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- tx_flags |= (skb->queue_mapping << 13);
- tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= IXGBE_TX_FLAGS_VLAN;
+ if (skb->priority != TC_PRIO_CONTROL) {
+ tx_flags |= (skb->queue_mapping << 13);
+ tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IXGBE_TX_FLAGS_VLAN;
+ } else {
+ skb->queue_mapping =
+ adapter->ring_feature[RING_F_DCB].indices-1;
+ }
}
+ r_idx = skb->queue_mapping;
+ tx_ring = &adapter->tx_ring[r_idx];
+
if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
(skb->protocol == htons(ETH_P_FCOE)))
tx_flags |= IXGBE_TX_FLAGS_FCOE;
@@ -5340,12 +5362,19 @@ static int ixgbe_del_sanmac_netdev(struct net_device *dev)
static void ixgbe_netpoll(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int i;
- disable_irq(adapter->pdev->irq);
adapter->flags |= IXGBE_FLAG_IN_NETPOLL;
- ixgbe_intr(adapter->pdev->irq, netdev);
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ for (i = 0; i < num_q_vectors; i++) {
+ struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
+ ixgbe_msix_clean_many(0, q_vector);
+ }
+ } else {
+ ixgbe_intr(adapter->pdev->irq, netdev);
+ }
adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL;
- enable_irq(adapter->pdev->irq);
}
#endif
@@ -5580,23 +5609,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
#endif
#ifdef IXGBE_FCOE
- if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
+ if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
if (hw->mac.ops.get_device_caps) {
hw->mac.ops.get_device_caps(hw, &device_caps);
- if (!(device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)) {
- netdev->features |= NETIF_F_FCOE_CRC;
- netdev->features |= NETIF_F_FSO;
- netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
- } else {
- adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
- }
+ if (device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)
+ adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
}
}
#endif /* IXGBE_FCOE */
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED)
+ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
netdev->features |= NETIF_F_LRO;
/* make sure the EEPROM is good */
@@ -5638,7 +5662,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
adapter->wol = 0;
break;
}
- device_init_wakeup(&adapter->pdev->dev, true);
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
/* pick up the PCI bus settings for reporting later */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fa87309dc087..17ee3890a0a1 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -42,6 +42,7 @@
#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB
#define IXGBE_DEV_ID_82598AT 0x10C8
+#define IXGBE_DEV_ID_82598AT2 0x150B
#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1
@@ -1893,27 +1894,6 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIR_INIT_DONE_POLL 10
#define IXGBE_FDIRCMD_CMD_POLL 10
-/* Transmit Descriptor - Legacy */
-struct ixgbe_legacy_tx_desc {
- u64 buffer_addr; /* Address of the descriptor's data buffer */
- union {
- __le32 data;
- struct {
- __le16 length; /* Data buffer length */
- u8 cso; /* Checksum offset */
- u8 cmd; /* Descriptor control */
- } flags;
- } lower;
- union {
- __le32 data;
- struct {
- u8 status; /* Descriptor status */
- u8 css; /* Checksum start */
- __le16 vlan;
- } fields;
- } upper;
-};
-
/* Transmit Descriptor - Advanced */
union ixgbe_adv_tx_desc {
struct {
@@ -1928,16 +1908,6 @@ union ixgbe_adv_tx_desc {
} wb;
};
-/* Receive Descriptor - Legacy */
-struct ixgbe_legacy_rx_desc {
- __le64 buffer_addr; /* Address of the descriptor's data buffer */
- __le16 length; /* Length of data DMAed into data buffer */
- __le16 csum; /* Packet checksum */
- u8 status; /* Descriptor status */
- u8 errors; /* Descriptor Errors */
- __le16 vlan;
-};
-
/* Receive Descriptor - Advanced */
union ixgbe_adv_rx_desc {
struct {
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 2a0174b62e96..588b44d944ce 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
entry = tx_pointer;
@@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
local_irq_enable();
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 2f286091394d..ec337b502fd9 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
-static int __init sonic_probe1(struct net_device *dev)
+static int __devinit sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
unsigned int silicon_revision;
@@ -211,7 +211,7 @@ out:
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
-static int __init jazz_sonic_probe(struct platform_device *pdev)
+static int __devinit jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 1e3c63d67b91..e7068c7cd627 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme)
jwrite32f(jme, JME_IENC, INTR_ENABLE);
}
-static inline void
-jme_enable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme,
- JME_SHBA_LO,
- ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN);
-}
-
-static inline void
-jme_disable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme, JME_SHBA_LO, 0x0);
-}
-
static u32
jme_linkstat_from_phy(struct jme_adapter *jme)
{
@@ -522,12 +508,8 @@ jme_setup_tx_resources(struct jme_adapter *jme)
&(txring->dmaalloc),
GFP_ATOMIC);
- if (!txring->alloc) {
- txring->desc = NULL;
- txring->dmaalloc = 0;
- txring->dma = 0;
- return -ENOMEM;
- }
+ if (!txring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -539,6 +521,11 @@ jme_setup_tx_resources(struct jme_adapter *jme)
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, jme->tx_ring_size);
+ txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->tx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(txring->bufinf)))
+ goto err_free_txring;
+
/*
* Initialize Transmit Descriptors
*/
@@ -547,6 +534,20 @@ jme_setup_tx_resources(struct jme_adapter *jme)
sizeof(struct jme_buffer_info) * jme->tx_ring_size);
return 0;
+
+err_free_txring:
+ dma_free_coherent(&(jme->pdev->dev),
+ TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+ txring->alloc,
+ txring->dmaalloc);
+
+err_set_null:
+ txring->desc = NULL;
+ txring->dmaalloc = 0;
+ txring->dma = 0;
+ txring->bufinf = NULL;
+
+ return -ENOMEM;
}
static void
@@ -554,19 +555,22 @@ jme_free_tx_resources(struct jme_adapter *jme)
{
int i;
struct jme_ring *txring = &(jme->txring[0]);
- struct jme_buffer_info *txbi = txring->bufinf;
+ struct jme_buffer_info *txbi;
if (txring->alloc) {
- for (i = 0 ; i < jme->tx_ring_size ; ++i) {
- txbi = txring->bufinf + i;
- if (txbi->skb) {
- dev_kfree_skb(txbi->skb);
- txbi->skb = NULL;
+ if (txring->bufinf) {
+ for (i = 0 ; i < jme->tx_ring_size ; ++i) {
+ txbi = txring->bufinf + i;
+ if (txbi->skb) {
+ dev_kfree_skb(txbi->skb);
+ txbi->skb = NULL;
+ }
+ txbi->mapping = 0;
+ txbi->len = 0;
+ txbi->nr_desc = 0;
+ txbi->start_xmit = 0;
}
- txbi->mapping = 0;
- txbi->len = 0;
- txbi->nr_desc = 0;
- txbi->start_xmit = 0;
+ kfree(txring->bufinf);
}
dma_free_coherent(&(jme->pdev->dev),
@@ -578,11 +582,11 @@ jme_free_tx_resources(struct jme_adapter *jme)
txring->desc = NULL;
txring->dmaalloc = 0;
txring->dma = 0;
+ txring->bufinf = NULL;
}
txring->next_to_use = 0;
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, 0);
-
}
static inline void
@@ -653,7 +657,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
static void
jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
{
- struct jme_ring *rxring = jme->rxring;
+ struct jme_ring *rxring = &(jme->rxring[0]);
register struct rxdesc *rxdesc = rxring->desc;
struct jme_buffer_info *rxbi = rxring->bufinf;
rxdesc += i;
@@ -720,8 +724,11 @@ jme_free_rx_resources(struct jme_adapter *jme)
struct jme_ring *rxring = &(jme->rxring[0]);
if (rxring->alloc) {
- for (i = 0 ; i < jme->rx_ring_size ; ++i)
- jme_free_rx_buf(jme, i);
+ if (rxring->bufinf) {
+ for (i = 0 ; i < jme->rx_ring_size ; ++i)
+ jme_free_rx_buf(jme, i);
+ kfree(rxring->bufinf);
+ }
dma_free_coherent(&(jme->pdev->dev),
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
@@ -731,6 +738,7 @@ jme_free_rx_resources(struct jme_adapter *jme)
rxring->desc = NULL;
rxring->dmaalloc = 0;
rxring->dma = 0;
+ rxring->bufinf = NULL;
}
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
@@ -746,12 +754,8 @@ jme_setup_rx_resources(struct jme_adapter *jme)
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
&(rxring->dmaalloc),
GFP_ATOMIC);
- if (!rxring->alloc) {
- rxring->desc = NULL;
- rxring->dmaalloc = 0;
- rxring->dma = 0;
- return -ENOMEM;
- }
+ if (!rxring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -762,9 +766,16 @@ jme_setup_rx_resources(struct jme_adapter *jme)
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
+ rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->rx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(rxring->bufinf)))
+ goto err_free_rxring;
+
/*
* Initiallize Receive Descriptors
*/
+ memset(rxring->bufinf, 0,
+ sizeof(struct jme_buffer_info) * jme->rx_ring_size);
for (i = 0 ; i < jme->rx_ring_size ; ++i) {
if (unlikely(jme_make_new_rx_buf(jme, i))) {
jme_free_rx_resources(jme);
@@ -775,6 +786,19 @@ jme_setup_rx_resources(struct jme_adapter *jme)
}
return 0;
+
+err_free_rxring:
+ dma_free_coherent(&(jme->pdev->dev),
+ RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+ rxring->alloc,
+ rxring->dmaalloc);
+err_set_null:
+ rxring->desc = NULL;
+ rxring->dmaalloc = 0;
+ rxring->dma = 0;
+ rxring->bufinf = NULL;
+
+ return -ENOMEM;
}
static inline void
@@ -790,9 +814,9 @@ jme_enable_rx_engine(struct jme_adapter *jme)
/*
* Setup RX DMA Bass Address
*/
- jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
- jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
/*
* Setup RX Descriptor Count
@@ -856,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
return false;
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) {
- msg_rx_err(jme, "TCP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
+ == RXWBFLAG_TCPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "TCP Checksum error\n");
+ return false;
}
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) {
- msg_rx_err(jme, "UDP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
+ == RXWBFLAG_UDPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "UDP Checksum error.\n");
+ return false;
}
- if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) {
+ if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
+ == RXWBFLAG_IPV4)) {
msg_rx_err(jme, "IPv4 Checksum error.\n");
- goto out_sumerr;
+ return false;
}
return true;
-
-out_sumerr:
- return false;
}
static void
@@ -1296,7 +1320,7 @@ jme_rx_empty_tasklet(unsigned long arg)
static void
jme_wake_queue_if_stopped(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
smp_wmb();
if (unlikely(netif_queue_stopped(jme->dev) &&
@@ -1483,12 +1507,7 @@ jme_msi(int irq, void *dev_id)
struct jme_adapter *jme = netdev_priv(netdev);
u32 intrstat;
- pci_dma_sync_single_for_cpu(jme->pdev,
- jme->shadow_dma,
- sizeof(u32) * SHADOW_REG_NR,
- PCI_DMA_FROMDEVICE);
- intrstat = jme->shadow_regs[SHADOW_IEVE];
- jme->shadow_regs[SHADOW_IEVE] = 0;
+ intrstat = jread32(jme, JME_IEVE);
jme_intr_msi(jme, intrstat);
@@ -1566,6 +1585,7 @@ jme_open(struct net_device *netdev)
jme_clear_pm(jme);
JME_NAPI_ENABLE(jme);
+ tasklet_enable(&jme->linkch_task);
tasklet_enable(&jme->txclean_task);
tasklet_hi_enable(&jme->rxclean_task);
tasklet_hi_enable(&jme->rxempty_task);
@@ -1574,7 +1594,6 @@ jme_open(struct net_device *netdev)
if (rc)
goto err_out;
- jme_enable_shadow(jme);
jme_start_irq(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
@@ -1642,15 +1661,14 @@ jme_close(struct net_device *netdev)
netif_carrier_off(netdev);
jme_stop_irq(jme);
- jme_disable_shadow(jme);
jme_free_irq(jme);
JME_NAPI_DISABLE(jme);
- tasklet_kill(&jme->linkch_task);
- tasklet_kill(&jme->txclean_task);
- tasklet_kill(&jme->rxclean_task);
- tasklet_kill(&jme->rxempty_task);
+ tasklet_disable(&jme->linkch_task);
+ tasklet_disable(&jme->txclean_task);
+ tasklet_disable(&jme->rxclean_task);
+ tasklet_disable(&jme->rxempty_task);
jme_reset_ghc_speed(jme);
jme_disable_rx_engine(jme);
@@ -1668,7 +1686,7 @@ static int
jme_alloc_txdesc(struct jme_adapter *jme,
struct sk_buff *skb)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
int idx, nr_alloc, mask = jme->tx_ring_mask;
idx = txring->next_to_use;
@@ -1722,7 +1740,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
static void
jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc = txring->desc, *ctxdesc;
struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
@@ -1835,7 +1853,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
static int
jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc;
struct jme_buffer_info *txbi;
u8 flags;
@@ -1883,7 +1901,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
static void
jme_stop_queue_if_full(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct jme_buffer_info *txbi = txring->bufinf;
int idx = atomic_read(&txring->next_to_clean);
@@ -2725,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev,
rc = -ENOMEM;
goto err_out_free_netdev;
}
- jme->shadow_regs = pci_alloc_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- &(jme->shadow_dma));
- if (!(jme->shadow_regs)) {
- jeprintk(pdev, "Allocating shadow register mapping error.\n");
- rc = -ENOMEM;
- goto err_out_unmap;
- }
if (no_pseudohp) {
apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
@@ -2768,6 +2778,7 @@ jme_init_one(struct pci_dev *pdev,
tasklet_init(&jme->rxempty_task,
&jme_rx_empty_tasklet,
(unsigned long) jme);
+ tasklet_disable_nosync(&jme->linkch_task);
tasklet_disable_nosync(&jme->txclean_task);
tasklet_disable_nosync(&jme->rxclean_task);
tasklet_disable_nosync(&jme->rxempty_task);
@@ -2817,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev,
if (!jme->mii_if.phy_id) {
rc = -EIO;
jeprintk(pdev, "Can not find phy_id.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme->reg_ghc |= GHC_LINK_POLL;
@@ -2846,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev,
if (rc) {
jeprintk(pdev,
"Reload eeprom for reading MAC Address error.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme_load_macaddr(netdev);
@@ -2862,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev,
rc = register_netdev(netdev);
if (rc) {
jeprintk(pdev, "Cannot register net device.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
@@ -2876,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev,
return 0;
-err_out_free_shadow:
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
err_out_unmap:
iounmap(jme->regs);
err_out_free_netdev:
@@ -2901,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev)
struct jme_adapter *jme = netdev_priv(netdev);
unregister_netdev(netdev);
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
iounmap(jme->regs);
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
@@ -2930,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
- jme_disable_shadow(jme);
-
if (netif_carrier_ok(netdev)) {
if (test_bit(JME_FLAG_POLL, &jme->flags))
jme_polling_mode(jme);
@@ -2983,7 +2983,6 @@ jme_resume(struct pci_dev *pdev)
else
jme_reset_phy_processor(jme);
- jme_enable_shadow(jme);
jme_start_irq(jme);
netif_device_attach(netdev);
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 0996a069ac7b..251abed3817e 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
#define __JME_H_INCLUDED__
#define DRV_NAME "jme"
-#define DRV_VERSION "1.0.4"
+#define DRV_VERSION "1.0.5"
#define PFX DRV_NAME ": "
#define PCI_DEVICE_ID_JMICRON_JMC250 0x0250
@@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits {
};
#define TXDESC_MSS_SHIFT 2
-enum jme_rxdescwb_flags_bits {
+enum jme_txwbdesc_flags_bits {
TXWBFLAG_OWN = 0x80,
TXWBFLAG_INT = 0x40,
TXWBFLAG_TMOUT = 0x20,
@@ -372,7 +372,6 @@ struct jme_buffer_info {
/*
* The structure holding buffer information and ring descriptors all together.
*/
-#define MAX_RING_DESC_NR 1024
struct jme_ring {
void *alloc; /* pointer to allocated memory */
void *desc; /* pointer to ring memory */
@@ -380,7 +379,7 @@ struct jme_ring {
dma_addr_t dma; /* phys address for ring dma */
/* Buffer information corresponding to each descriptor */
- struct jme_buffer_info bufinf[MAX_RING_DESC_NR];
+ struct jme_buffer_info *bufinf;
int next_to_use;
atomic_t next_to_clean;
@@ -411,13 +410,10 @@ struct jme_ring {
/*
* Jmac Adapter Private data
*/
-#define SHADOW_REG_NR 8
struct jme_adapter {
struct pci_dev *pdev;
struct net_device *dev;
void __iomem *regs;
- dma_addr_t shadow_dma;
- u32 *shadow_regs;
struct mii_if_info mii_if;
struct jme_ring rxring[RX_RING_NR];
struct jme_ring txring[TX_RING_NR];
@@ -464,10 +460,6 @@ struct jme_adapter {
DECLARE_NET_DEVICE_STATS
};
-enum shadow_reg_val {
- SHADOW_IEVE = 0,
-};
-
enum jme_flags_bits {
JME_FLAG_MSI = 1,
JME_FLAG_SSET = 2,
@@ -1104,13 +1096,6 @@ enum jme_chipmode_shifts {
};
/*
- * Shadow base address register bits
- */
-enum jme_shadow_base_address_bits {
- SHBA_POSTEN = 0x1,
-};
-
-/*
* Aggressive Power Mode Control
*/
enum jme_apmc_bits {
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 633808d447be..30fd4f5f1d5a 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
out:
spin_unlock_irqrestore(&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 070fa4500871..51e11c3e53e1 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index f28c23343009..d6be36000c5c 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 96e7248876c1..da8d0a0ca94f 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Kick off the transfer */
temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index da472c687481..51bbce72bede 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
} else
lb_stats->drops++;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index d44bddbee373..c292bad411ee 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
dev->stats.tx_packets++;
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index dab45339d3a8..149e0ed4a055 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 5b5c25368d1e..429c4c82b839 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -241,7 +241,7 @@ static int macb_mii_init(struct macb *bp)
struct eth_platform_data *pdata;
int err = -ENXIO, i;
- /* Enable managment port */
+ /* Enable management port */
macb_writel(bp, NCR, MACB_BIT(MPE));
bp->mii_bus = mdiobus_alloc();
@@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void macb_free_consistent(struct macb *bp)
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 1427755c224d..7d7577b598ea 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&mp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void mace_set_multicast(struct net_device *dev)
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 5d04d94f2a21..92ceb689b4d4 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->meth_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = {
/*
* The init function.
*/
-static int __init meth_probe(struct platform_device *pdev)
+static int __devinit meth_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct meth_private *priv;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index b3b9a147d09a..8ea98bd89ff1 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
mipsnet_put_todevice(dev, skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index ac57b6a42c6e..ccfe276943f0 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -34,7 +34,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/hardirq.h>
#include <linux/mlx4/cmd.h>
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 08c43f2ae72b..d5c18c674255 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
/* Poll CQ here */
mlx4_en_xmit_poll(priv, tx_ind);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
dev_kfree_skb_any(skb);
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index b9ceddde46c0..c11a0525c40e 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -31,7 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
index baf4bf66062c..04b382fcb8c8 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/mlx4/icm.c
@@ -31,7 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index dac621b1e9fc..5c1afe0d73e8 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1070,18 +1070,12 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_disable_pdev;
}
- err = pci_request_region(pdev, 0, DRV_NAME);
+ err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- dev_err(&pdev->dev, "Cannot request control region, aborting.\n");
+ dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n");
goto err_disable_pdev;
}
- err = pci_request_region(pdev, 2, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "Cannot request UAR region, aborting.\n");
- goto err_release_bar0;
- }
-
pci_set_master(pdev);
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -1090,7 +1084,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");
- goto err_release_bar2;
+ goto err_release_regions;
}
}
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -1101,7 +1095,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (err) {
dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, "
"aborting.\n");
- goto err_release_bar2;
+ goto err_release_regions;
}
}
@@ -1110,7 +1104,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(&pdev->dev, "Device struct alloc failed, "
"aborting.\n");
err = -ENOMEM;
- goto err_release_bar2;
+ goto err_release_regions;
}
dev = &priv->dev;
@@ -1205,11 +1199,8 @@ err_cmd:
err_free_dev:
kfree(priv);
-err_release_bar2:
- pci_release_region(pdev, 2);
-
-err_release_bar0:
- pci_release_region(pdev, 0);
+err_release_regions:
+ pci_release_regions(pdev);
err_disable_pdev:
pci_disable_device(pdev);
@@ -1265,8 +1256,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
pci_disable_msix(pdev);
kfree(priv);
- pci_release_region(pdev, 2);
- pci_release_region(pdev, 0);
+ pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 6053c357a470..5ccbce9866fe 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -31,7 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index f96948be0a44..ca7ab8e7b4cc 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -32,7 +32,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mlx4/cmd.h>
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index 26d1a7a9e375..c4988d6bd5b2 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -31,7 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/errno.h>
#include <asm/page.h>
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
index bd22df95adf9..ca25b9dc8378 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/mlx4/profile.c
@@ -32,8 +32,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
-
#include "mlx4.h"
#include "fw.h"
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 1c565ef8d179..42ab9fc01d3e 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -33,8 +33,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
-
#include <linux/mlx4/cmd.h>
#include <linux/mlx4/qp.h>
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c
index 3951b884c0fb..e5741dab3825 100644
--- a/drivers/net/mlx4/reset.c
+++ b/drivers/net/mlx4/reset.c
@@ -31,7 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index fe9f218691f5..1377d0dc8f1f 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -31,8 +31,6 @@
* SOFTWARE.
*/
-#include <linux/init.h>
-
#include <linux/mlx4/cmd.h>
#include "mlx4.h"
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1f6e36ea669e..1a34f7e11d98 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2748,7 +2748,7 @@ again:
/* The packet is gone, so we must
* return 0 */
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
/* adjust the len to account for the zero pad
* so that the nic can know how long it is */
@@ -2892,7 +2892,7 @@ again:
tx->stop_queue++;
netif_tx_stop_queue(netdev_queue);
}
- return 0;
+ return NETDEV_TX_OK;
abort_linearize:
/* Free any DMA resources we've alloced and clear out the skb
@@ -2936,7 +2936,7 @@ abort_linearize:
drop:
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
}
}
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
drop:
ss = &mgp->ss[skb_get_queue_mapping(skb)];
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 5f0758bda6b3..29ebebc6a95b 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
DTX(("tbusy=0, returning 0\n"));
netif_start_queue(dev);
spin_unlock_irqrestore(&mp->irq_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* Create the MyriNet MAC header for an arbitrary protocol layer
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 78c088331f57..32db12a27342 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 946366dcc992..9f4235466d59 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irq(&priv->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void netx_eth_receive(struct net_device *ndev)
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index f86e05047d19..e22d08615893 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -57,8 +57,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 30
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.30"
+#define _NETXEN_NIC_LINUX_SUBVERSION 41
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.41"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -143,18 +143,13 @@
#define NX_ETHERMTU 1500
#define NX_MAX_ETHERHDR 32 /* This contains some padding */
-#define NX_RX_NORMAL_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
+#define NX_P2_RX_BUF_MAX_LEN 1760
+#define NX_P3_RX_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
#define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU)
#define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU)
#define NX_CT_DEFAULT_RX_BUF_LEN 2048
-#define MAX_RX_BUFFER_LENGTH 1760
-#define MAX_RX_JUMBO_BUFFER_LENGTH 8062
-#define MAX_RX_LRO_BUFFER_LENGTH (8062)
-#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2)
-#define RX_JUMBO_DMA_MAP_LEN \
- (MAX_RX_JUMBO_BUFFER_LENGTH - 2)
-#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2)
+#define NX_RX_LRO_BUFFER_LENGTH (8060)
/*
* Maximum number of ring contexts
@@ -200,13 +195,20 @@
#define RCV_RING_JUMBO 1
#define RCV_RING_LRO 2
-#define MAX_CMD_DESCRIPTORS 4096
-#define MAX_RCV_DESCRIPTORS 16384
-#define MAX_CMD_DESCRIPTORS_HOST 1024
-#define MAX_RCV_DESCRIPTORS_1G 2048
-#define MAX_RCV_DESCRIPTORS_10G 4096
-#define MAX_JUMBO_RCV_DESCRIPTORS 1024
+#define MIN_CMD_DESCRIPTORS 64
+#define MIN_RCV_DESCRIPTORS 64
+#define MIN_JUMBO_DESCRIPTORS 32
+
+#define MAX_CMD_DESCRIPTORS 1024
+#define MAX_RCV_DESCRIPTORS_1G 4096
+#define MAX_RCV_DESCRIPTORS_10G 8192
+#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512
+#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
#define MAX_LRO_RCV_DESCRIPTORS 8
+
+#define DEFAULT_RCV_DESCRIPTORS_1G 2048
+#define DEFAULT_RCV_DESCRIPTORS_10G 4096
+
#define NETXEN_CTX_SIGNATURE 0xdee0
#define NETXEN_CTX_SIGNATURE_V2 0x0002dee0
#define NETXEN_CTX_RESET 0xbad0
@@ -302,6 +304,10 @@ struct netxen_ring_ctx {
#define FLAGS_IPSEC_SA_ADD 0x04
#define FLAGS_IPSEC_SA_DELETE 0x08
#define FLAGS_VLAN_TAGGED 0x10
+#define FLAGS_VLAN_OOB 0x40
+
+#define netxen_set_tx_vlan_tci(cmd_desc, v) \
+ (cmd_desc)->vlan_TCI = cpu_to_le16(v);
#define netxen_set_cmd_desc_port(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
@@ -316,58 +322,33 @@ struct netxen_ring_ctx {
cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
#define netxen_set_tx_frags_len(_desc, _frags, _len) \
- (_desc)->num_of_buffers_total_length = \
+ (_desc)->nfrags__length = \
cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
u8 ip_hdr_offset; /* For LSO only */
- /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */
- __le16 flags_opcode;
- /* Bit pattern: 0-7 total number of segments,
- 8-31 Total size of the packet */
- __le32 num_of_buffers_total_length;
- union {
- struct {
- __le32 addr_low_part2;
- __le32 addr_high_part2;
- };
- __le64 addr_buffer2;
- };
+ __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */
+ __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */
+
+ __le64 addr_buffer2;
- __le16 reference_handle; /* changed to u16 to add mss */
- __le16 mss; /* passed by NDIS_PACKET for LSO */
- /* Bit pattern 0-3 port, 0-3 ctx id */
- u8 port_ctxid;
+ __le16 reference_handle;
+ __le16 mss;
+ u8 port_ctxid; /* 7:4 ctxid 3:0 port */
u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
__le16 conn_id; /* IPSec offoad only */
- union {
- struct {
- __le32 addr_low_part3;
- __le32 addr_high_part3;
- };
- __le64 addr_buffer3;
- };
- union {
- struct {
- __le32 addr_low_part1;
- __le32 addr_high_part1;
- };
- __le64 addr_buffer1;
- };
+ __le64 addr_buffer3;
+ __le64 addr_buffer1;
__le16 buffer_length[4];
- union {
- struct {
- __le32 addr_low_part4;
- __le32 addr_high_part4;
- };
- __le64 addr_buffer4;
- };
+ __le64 addr_buffer4;
- __le64 unused;
+ __le16 vlan_TCI;
+ __le16 reserved;
+ __le32 reserved2;
} __attribute__ ((aligned(64)));
@@ -380,6 +361,7 @@ struct rcv_desc {
};
/* opcode field in status_desc */
+#define NETXEN_NIC_SYN_OFFLOAD 0x03
#define NETXEN_NIC_RXPKT_DESC 0x04
#define NETXEN_OLD_RXPKT_DESC 0x3f
#define NETXEN_NIC_RESPONSE_DESC 0x05
@@ -1078,6 +1060,9 @@ typedef struct {
#define NX_MAC_EVENT 0x1
+#define NX_IP_UP 2
+#define NX_IP_DOWN 3
+
/*
* Driver --> Firmware
*/
@@ -1132,6 +1117,9 @@ typedef struct {
#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5)
#define NX_FW_CAPABILITY_SWITCHING (1 << 6)
+#define NX_FW_CAPABILITY_PEXQ (1 << 7)
+#define NX_FW_CAPABILITY_BDG (1 << 8)
+#define NX_FW_CAPABILITY_FVLANTX (1 << 9)
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -1315,29 +1303,11 @@ struct netxen_adapter {
nx_nic_intr_coalesce_t coal;
- u32 fw_major;
+ u32 resv5;
u32 fw_version;
const struct firmware *fw;
};
-/*
- * NetXen dma watchdog control structure
- *
- * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
- * Bit 1 : disable_request => 1 req disable dma watchdog
- * Bit 2 : enable_request => 1 req enable dma watchdog
- * Bit 3-31 : unused
- */
-
-#define netxen_set_dma_watchdog_disable_req(config_word) \
- _netxen_set_bits(config_word, 1, 1, 1)
-#define netxen_set_dma_watchdog_enable_req(config_word) \
- _netxen_set_bits(config_word, 2, 1, 1)
-#define netxen_get_dma_watchdog_enabled(config_word) \
- ((config_word) & 0x1)
-#define netxen_get_dma_watchdog_disabled(config_word) \
- (((config_word) >> 1) & 0x1)
-
int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
@@ -1398,8 +1368,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
unsigned long long addr);
/* Functions from netxen_nic_init.c */
-void netxen_free_adapter_offload(struct netxen_adapter *adapter);
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
+int netxen_init_dummy_dma(struct netxen_adapter *adapter);
+void netxen_free_dummy_dma(struct netxen_adapter *adapter);
+
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
int netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_need_fw_reset(struct netxen_adapter *adapter);
@@ -1443,6 +1414,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
int netxen_config_rss(struct netxen_adapter *adapter, int enable);
+int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
@@ -1455,6 +1427,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring);
+/* Functions from netxen_nic_main.c */
+int netxen_nic_reset_context(struct netxen_adapter *);
+
/*
* NetXen Board information
*/
@@ -1505,56 +1480,6 @@ static inline void get_brd_name_by_type(u32 type, char *name)
name = "Unknown";
}
-static inline int
-dma_watchdog_shutdown_request(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- /* check if already inactive */
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl) == 0)
- return 1;
-
- /* Send the disable request */
- netxen_set_dma_watchdog_disable_req(ctrl);
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-static inline int
-dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
-}
-
-static inline int
-dma_watchdog_wakeup(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl))
- return 1;
-
- /* send the wakeup request */
- netxen_set_dma_watchdog_enable_req(ctrl);
-
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-
static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
{
smp_mb();
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 9f8ae4719e2f..9e0469643d34 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -647,7 +647,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
rds_ring->desc_head = (struct rcv_desc *)addr;
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
rds_ring->crb_rcv_producer =
recv_crb_registers[port].crb_rcv_producer[ring];
}
@@ -675,7 +675,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
err = nx_fw_cmd_create_rx_ctx(adapter);
if (err)
goto err_out_free;
@@ -705,7 +705,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
int port = adapter->portnum;
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
nx_fw_cmd_destroy_rx_ctx(adapter);
nx_fw_cmd_destroy_tx_ctx(adapter);
} else {
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index e16ea46c24b8..39a308c363c7 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -490,28 +490,86 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
}
static void
-netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+netxen_nic_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
{
struct netxen_adapter *adapter = netdev_priv(dev);
- ring->rx_pending = 0;
- ring->rx_jumbo_pending = 0;
- ring->rx_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_NORMAL].num_desc;
- ring->rx_jumbo_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_JUMBO].num_desc;
+ ring->rx_pending = adapter->num_rxd;
+ ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
+ ring->rx_jumbo_pending += adapter->num_lro_rxd;
ring->tx_pending = adapter->num_txd;
- if (adapter->ahw.port_type == NETXEN_NIC_GBE)
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
- else
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ } else {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
- ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
- ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
+
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
}
+static u32
+netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
+{
+ u32 num_desc;
+ num_desc = max(val, min);
+ num_desc = min(num_desc, max);
+ num_desc = roundup_pow_of_two(num_desc);
+
+ if (val != num_desc) {
+ printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
+ netxen_nic_driver_name, r_name, num_desc, val);
+ }
+
+ return num_desc;
+}
+
+static int
+netxen_nic_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
+ u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ u16 num_rxd, num_jumbo_rxd, num_txd;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return -EOPNOTSUPP;
+
+ if (ring->rx_mini_pending)
+ return -EOPNOTSUPP;
+
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
+ max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ num_rxd = netxen_validate_ringparam(ring->rx_pending,
+ MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+
+ num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending,
+ MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+
+ num_txd = netxen_validate_ringparam(ring->tx_pending,
+ MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
+
+ if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
+ num_jumbo_rxd == adapter->num_jumbo_rxd)
+ return 0;
+
+ adapter->num_rxd = num_rxd;
+ adapter->num_jumbo_rxd = num_jumbo_rxd;
+ adapter->num_txd = num_txd;
+
+ return netxen_nic_reset_context(adapter);
+}
+
static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
@@ -893,6 +951,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
+ .set_ringparam = netxen_nic_set_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
.set_tx_csum = ethtool_op_set_tx_csum,
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 824103675648..a7328584a21a 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -852,7 +852,7 @@ enum {
#define NX_PEG_TUNE_MN_PRESENT 0x1
#define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c))
-#define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14)
+#define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14))
#define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0))
#define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index b9123d445c96..ddb9deb12b33 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
return rv;
}
+int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd)
+{
+ nx_nic_req_t req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(nx_nic_req_t));
+ req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
+
+ word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(cmd);
+ req.words[1] = cpu_to_le64(ip);
+
+ rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0) {
+ printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n",
+ adapter->netdev->name,
+ (cmd == NX_IP_UP) ? "Add" : "Remove", ip);
+ }
+ return rv;
+}
+
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable)
{
nx_nic_req_t req;
@@ -2021,7 +2045,6 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
- adapter->fw_major = fw_major;
adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
if (adapter->portnum == 0) {
@@ -2047,6 +2070,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
dev_info(&pdev->dev, "firmware running in %s mode\n",
adapter->ahw.cut_through ? "cut-through" : "legacy");
}
+
+ if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222))
+ adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
}
int
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 5d3343ef3d86..81253abbfa34 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -184,6 +184,13 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter)
kfree(recv_ctx->rds_rings);
skip_rds:
+ if (recv_ctx->sds_rings == NULL)
+ goto skip_sds;
+
+ for(ring = 0; ring < adapter->max_sds_rings; ring++)
+ recv_ctx->sds_rings[ring].consumer = 0;
+
+skip_sds:
if (adapter->tx_ring == NULL)
return;
@@ -247,9 +254,14 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
rds_ring->skb_size =
NX_CT_DEFAULT_RX_BUF_LEN;
} else {
- rds_ring->dma_size = RX_DMA_MAP_LEN;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ rds_ring->dma_size =
+ NX_P3_RX_BUF_MAX_LEN;
+ else
+ rds_ring->dma_size =
+ NX_P2_RX_BUF_MAX_LEN;
rds_ring->skb_size =
- MAX_RX_BUFFER_LENGTH;
+ rds_ring->dma_size + NET_IP_ALIGN;
}
break;
@@ -267,8 +279,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
case RCV_RING_LRO:
rds_ring->num_desc = adapter->num_lro_rxd;
- rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
- rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
break;
}
@@ -880,22 +892,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
return 0;
}
-void netxen_request_firmware(struct netxen_adapter *adapter)
+static int
+netxen_p3_has_mn(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
- u8 fw_type;
- struct pci_dev *pdev = adapter->pdev;
- int rc = 0;
-
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- fw_type = NX_P2_MN_ROMIMAGE;
- goto request_fw;
- } else {
- fw_type = NX_P3_CT_ROMIMAGE;
- goto request_fw;
- }
-
-request_mn:
capability = 0;
netxen_rom_fast_read(adapter,
@@ -903,23 +903,35 @@ request_mn:
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
+
capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
- if (capability & NX_PEG_TUNE_MN_PRESENT) {
- fw_type = NX_P3_MN_ROMIMAGE;
- goto request_fw;
- }
+ if (capability & NX_PEG_TUNE_MN_PRESENT)
+ return 1;
}
+ return 0;
+}
- fw_type = NX_FLASH_ROMIMAGE;
- adapter->fw = NULL;
- goto done;
+void netxen_request_firmware(struct netxen_adapter *adapter)
+{
+ u8 fw_type;
+ struct pci_dev *pdev = adapter->pdev;
+ int rc = 0;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ fw_type = NX_P2_MN_ROMIMAGE;
+ goto request_fw;
+ }
+
+ fw_type = netxen_p3_has_mn(adapter) ?
+ NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
request_fw:
rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
if (rc != 0) {
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -931,9 +943,10 @@ request_fw:
if (rc != 0) {
release_firmware(adapter->fw);
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -953,19 +966,20 @@ netxen_release_firmware(struct netxen_adapter *adapter)
release_firmware(adapter->fw);
}
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
+int netxen_init_dummy_dma(struct netxen_adapter *adapter)
{
- uint64_t addr;
- uint32_t hi;
- uint32_t lo;
+ u64 addr;
+ u32 hi, lo;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
- adapter->dummy_dma.addr =
- pci_alloc_consistent(adapter->pdev,
+ adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
&adapter->dummy_dma.phys_addr);
if (adapter->dummy_dma.addr == NULL) {
- printk("%s: ERROR: Could not allocate dummy DMA memory\n",
- __func__);
+ dev_err(&adapter->pdev->dev,
+ "ERROR: Could not allocate dummy DMA memory\n");
return -ENOMEM;
}
@@ -976,29 +990,41 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
- uint32_t temp = 0;
- NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp);
- }
-
return 0;
}
-void netxen_free_adapter_offload(struct netxen_adapter *adapter)
+/*
+ * NetXen DMA watchdog control:
+ *
+ * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
+ * Bit 1 : disable_request => 1 req disable dma watchdog
+ * Bit 2 : enable_request => 1 req enable dma watchdog
+ * Bit 3-31 : unused
+ */
+void netxen_free_dummy_dma(struct netxen_adapter *adapter)
{
int i = 100;
+ u32 ctrl;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return;
if (!adapter->dummy_dma.addr)
return;
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- do {
- if (dma_watchdog_shutdown_request(adapter) == 1)
- break;
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+ if ((ctrl & 0x1) != 0) {
+ NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2));
+
+ while ((ctrl & 0x1) != 0) {
+
msleep(50);
- if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+
+ if (--i == 0)
break;
- } while (--i);
+ };
}
if (i) {
@@ -1007,10 +1033,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter)
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
adapter->dummy_dma.addr = NULL;
- } else {
- printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
- adapter->netdev->name);
- }
+ } else
+ dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n");
}
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
@@ -1083,10 +1107,6 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
- if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) {
- adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
- }
-
return err;
}
@@ -1296,6 +1316,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
switch (opcode) {
case NETXEN_NIC_RXPKT_DESC:
case NETXEN_OLD_RXPKT_DESC:
+ case NETXEN_NIC_SYN_OFFLOAD:
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
@@ -1468,7 +1489,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
NXWR32(adapter, rds_ring->crb_rcv_producer,
(producer-1) & (rds_ring->num_desc-1));
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 637ac8b89bac..305a99055f64 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,6 +39,7 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
@@ -65,7 +66,7 @@ static int netxen_nic_open(struct net_device *netdev);
static int netxen_nic_close(struct net_device *netdev);
static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);
static void netxen_tx_timeout(struct net_device *netdev);
-static void netxen_tx_timeout_task(struct work_struct *work);
+static void netxen_reset_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_nic_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -181,7 +182,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
- return 1;
+ return -ENOMEM;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
@@ -221,7 +222,7 @@ netxen_napi_disable(struct netxen_adapter *adapter)
}
}
-static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
+static int nx_set_dma_mask(struct netxen_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
uint64_t mask, cmask;
@@ -229,19 +230,17 @@ static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
adapter->pci_using_dac = 0;
mask = DMA_BIT_MASK(32);
- /*
- * Consistent DMA mask is set to 32 bit because it cannot be set to
- * 35 bits. For P3 also leave it at 32 bits for now. Only the rings
- * come off this pool.
- */
cmask = DMA_BIT_MASK(32);
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
#ifndef CONFIG_IA64
- if (revision_id >= NX_P3_B0)
- mask = DMA_BIT_MASK(39);
- else if (revision_id == NX_P2_C1)
mask = DMA_BIT_MASK(35);
#endif
+ } else {
+ mask = DMA_BIT_MASK(39);
+ cmask = mask;
+ }
+
if (pci_set_dma_mask(pdev, mask) == 0 &&
pci_set_consistent_dma_mask(pdev, cmask) == 0) {
adapter->pci_using_dac = 1;
@@ -256,7 +255,7 @@ static int
nx_update_dma_mask(struct netxen_adapter *adapter)
{
int change, shift, err;
- uint64_t mask, old_mask;
+ uint64_t mask, old_mask, old_cmask;
struct pci_dev *pdev = adapter->pdev;
change = 0;
@@ -272,22 +271,41 @@ nx_update_dma_mask(struct netxen_adapter *adapter)
if (change) {
old_mask = pdev->dma_mask;
+ old_cmask = pdev->dev.coherent_dma_mask;
+
mask = (1ULL<<(32+shift)) - 1;
err = pci_set_dma_mask(pdev, mask);
if (err)
- return pci_set_dma_mask(pdev, old_mask);
+ goto err_out;
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+
+ err = pci_set_consistent_dma_mask(pdev, mask);
+ if (err)
+ goto err_out;
+ }
+ dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift);
}
return 0;
+
+err_out:
+ pci_set_dma_mask(pdev, old_mask);
+ pci_set_consistent_dma_mask(pdev, old_cmask);
+ return err;
}
-static void netxen_check_options(struct netxen_adapter *adapter)
+static void
+netxen_check_options(struct netxen_adapter *adapter)
{
- if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
- else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
+ if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ }
adapter->msix_supported = 0;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
@@ -305,11 +323,15 @@ static void netxen_check_options(struct netxen_adapter *adapter)
}
}
- adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
- adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
- adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
- return;
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->max_rds_rings = 3;
+ } else {
+ adapter->num_lro_rxd = 0;
+ adapter->max_rds_rings = 2;
+ }
}
static int
@@ -744,7 +766,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
}
- err = netxen_initialize_adapter_offload(adapter);
+ err = netxen_init_dummy_dma(adapter);
if (err)
return err;
@@ -760,10 +782,14 @@ wait_init:
/* Handshake with the card before we register the devices. */
err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
if (err) {
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
return err;
}
+ nx_update_dma_mask(adapter);
+
+ netxen_nic_get_firmware_info(adapter);
+
return 0;
}
@@ -814,6 +840,20 @@ netxen_nic_free_irq(struct netxen_adapter *adapter)
}
}
+static void
+netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter)
+{
+ adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT;
+ adapter->coal.normal.data.rx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->coal.normal.data.rx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ adapter->coal.normal.data.tx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US;
+ adapter->coal.normal.data.tx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS;
+}
+
static int
netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
{
@@ -836,6 +876,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
if (adapter->max_sds_rings > 1)
netxen_config_rss(adapter, 1);
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_config_intr_coalesce(adapter);
+
netxen_napi_enable(adapter);
if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION)
@@ -880,17 +923,15 @@ netxen_nic_attach(struct netxen_adapter *adapter)
struct nx_host_rds_ring *rds_ring;
struct nx_host_tx_ring *tx_ring;
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+ return 0;
+
err = netxen_init_firmware(adapter);
if (err != 0) {
printk(KERN_ERR "Failed to init firmware\n");
return -EIO;
}
- if (adapter->fw_major < 4)
- adapter->max_rds_rings = 3;
- else
- adapter->max_rds_rings = 2;
-
err = netxen_alloc_sw_resources(adapter);
if (err) {
printk(KERN_ERR "%s: Error in setting sw resources\n",
@@ -907,7 +948,7 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_sw;
}
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
tx_ring = adapter->tx_ring;
tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum];
tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum];
@@ -931,6 +972,9 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_rxbuf;
}
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_nic_init_coalesce_defaults(adapter);
+
adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
return 0;
@@ -945,6 +989,9 @@ err_out_free_sw:
static void
netxen_nic_detach(struct netxen_adapter *adapter)
{
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ return;
+
netxen_free_hw_resources(adapter);
netxen_release_rx_buffers(adapter);
netxen_nic_free_irq(adapter);
@@ -953,6 +1000,95 @@ netxen_nic_detach(struct netxen_adapter *adapter)
adapter->is_up = 0;
}
+int
+netxen_nic_reset_context(struct netxen_adapter *adapter)
+{
+ int err = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
+
+ if (netif_running(netdev))
+ netxen_nic_down(adapter, netdev);
+
+ netxen_nic_detach(adapter);
+
+ err = netxen_nic_attach(adapter);
+ if (err)
+ goto done;
+
+ if (netif_running(netdev))
+ err = netxen_nic_up(adapter, netdev);
+ }
+done:
+ return err;
+}
+
+static int
+netxen_setup_netdev(struct netxen_adapter *adapter,
+ struct net_device *netdev)
+{
+ int err = 0;
+ struct pci_dev *pdev = adapter->pdev;
+
+ adapter->rx_csum = 1;
+ adapter->mc_enabled = 0;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ adapter->max_mc_count = 38;
+ else
+ adapter->max_mc_count = 16;
+
+ netdev->netdev_ops = &netxen_netdev_ops;
+ netdev->watchdog_timeo = 2*HZ;
+
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_GRO);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ }
+
+ if (adapter->pci_using_dac) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
+
+ if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
+ netdev->features |= (NETIF_F_HW_VLAN_TX);
+
+ netdev->irq = adapter->msix_entries[0].vector;
+
+ err = netxen_napi_add(adapter, netdev);
+ if (err)
+ return err;
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &netxen_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+ INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
+ INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task);
+
+ if (netxen_read_mac_addr(adapter))
+ dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register net device\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int __devinit
netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -990,9 +1126,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev = alloc_etherdev(sizeof(struct netxen_adapter));
if(!netdev) {
- printk(KERN_ERR"%s: Failed to allocate memory for the "
- "device block.Check system memory resource"
- " usage.\n", netxen_nic_driver_name);
+ dev_err(&pdev->dev, "failed to allocate net_device\n");
+ err = -ENOMEM;
goto err_out_free_res;
}
@@ -1006,7 +1141,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
revision_id = pdev->revision;
adapter->ahw.revision_id = revision_id;
- err = nx_set_dma_mask(adapter, revision_id);
+ err = nx_set_dma_mask(adapter);
if (err)
goto err_out_free_netdev;
@@ -1020,38 +1155,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* This will be reset for mezz cards */
adapter->portnum = pci_func_id;
- adapter->rx_csum = 1;
- adapter->mc_enabled = 0;
- if (NX_IS_REVISION_P3(revision_id))
- adapter->max_mc_count = 38;
- else
- adapter->max_mc_count = 16;
-
- netdev->netdev_ops = &netxen_netdev_ops;
- netdev->watchdog_timeo = 2*HZ;
-
- netxen_nic_change_mtu(netdev, netdev->mtu);
-
- SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
- netdev->features |= (NETIF_F_GRO);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-
- if (NX_IS_REVISION_P3(revision_id)) {
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- }
- if (adapter->pci_using_dac) {
- netdev->features |= NETIF_F_HIGHDMA;
- netdev->vlan_features |= NETIF_F_HIGHDMA;
- }
-
- if (netxen_nic_get_board_info(adapter) != 0) {
- printk("%s: Error getting board config info.\n",
- netxen_nic_driver_name);
- err = -EIO;
+ err = netxen_nic_get_board_info(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error getting board config info.\n");
goto err_out_iounmap;
}
@@ -1072,15 +1179,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_iounmap;
- nx_update_dma_mask(adapter);
-
- netxen_nic_get_firmware_info(adapter);
-
/*
* See if the firmware gave us a virtual-physical port mapping.
*/
adapter->physical_port = adapter->portnum;
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
i = NXRD32(adapter, CRB_V2P(adapter->portnum));
if (i != 0x55555555)
adapter->physical_port = i;
@@ -1090,31 +1193,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_setup_intr(adapter);
- netdev->irq = adapter->msix_entries[0].vector;
-
- if (netxen_napi_add(adapter, netdev))
- goto err_out_disable_msi;
-
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &netxen_watchdog;
- adapter->watchdog_timer.data = (unsigned long)adapter;
- INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
- INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
-
- err = netxen_read_mac_addr(adapter);
+ err = netxen_setup_netdev(adapter, netdev);
if (err)
- dev_warn(&pdev->dev, "failed to read mac addr\n");
-
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
-
- if ((err = register_netdev(netdev))) {
- printk(KERN_ERR "%s: register_netdev failed port #%d"
- " aborting\n", netxen_nic_driver_name,
- adapter->portnum);
- err = -EIO;
goto err_out_disable_msi;
- }
pci_set_drvdata(pdev, adapter);
@@ -1134,7 +1215,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_disable_msi:
netxen_teardown_intr(adapter);
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
err_out_iounmap:
netxen_cleanup_pci_map(adapter);
@@ -1164,12 +1245,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
- netxen_nic_detach(adapter);
- }
+ netxen_nic_detach(adapter);
if (adapter->portnum == 0)
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
netxen_teardown_intr(adapter);
netxen_free_sds_rings(&adapter->recv_ctx);
@@ -1198,8 +1277,7 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
if (netif_running(netdev))
netxen_nic_down(adapter, netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
- netxen_nic_detach(adapter);
+ netxen_nic_detach(adapter);
pci_save_state(pdev);
@@ -1260,11 +1338,9 @@ static int netxen_nic_open(struct net_device *netdev)
if (adapter->driver_mismatch)
return -EIO;
- if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
- err = netxen_nic_attach(adapter);
- if (err)
- return err;
- }
+ err = netxen_nic_attach(adapter);
+ if (err)
+ return err;
err = netxen_nic_up(adapter, netdev);
if (err)
@@ -1290,30 +1366,52 @@ static int netxen_nic_close(struct net_device *netdev)
return 0;
}
-static bool netxen_tso_check(struct net_device *netdev,
- struct cmd_desc_type0 *desc, struct sk_buff *skb)
+static void
+netxen_tso_check(struct net_device *netdev,
+ struct nx_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
{
- bool tso = false;
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
- u16 flags = 0;
+ u16 flags = 0, vid = 0;
+ u32 producer;
+ int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+ struct cmd_desc_type0 *hwdesc;
+ struct vlan_ethhdr *vh;
if (protocol == cpu_to_be16(ETH_P_8021Q)) {
- struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data;
+
+ vh = (struct vlan_ethhdr *)skb->data;
protocol = vh->h_vlan_encapsulated_proto;
flags = FLAGS_VLAN_TAGGED;
+
+ } else if (vlan_tx_tag_present(skb)) {
+
+ flags = FLAGS_VLAN_OOB;
+ vid = vlan_tx_tag_get(skb);
+ netxen_set_tx_vlan_tci(first_desc, vid);
+ vlan_oob = 1;
}
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
- desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- desc->total_hdr_length =
- skb_transport_offset(skb) + tcp_hdrlen(skb);
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->total_hdr_length = hdr_len;
+ if (vlan_oob) {
+ first_desc->total_hdr_length += VLAN_HLEN;
+ first_desc->tcp_hdr_offset = VLAN_HLEN;
+ first_desc->ip_hdr_offset = VLAN_HLEN;
+ /* Only in case of TSO on vlan device */
+ flags |= FLAGS_VLAN_TAGGED;
+ }
opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
TX_TCP_LSO6 : TX_TCP_LSO;
- tso = true;
+ tso = 1;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4proto;
@@ -1334,10 +1432,62 @@ static bool netxen_tso_check(struct net_device *netdev,
opcode = TX_UDPV6_PKT;
}
}
- desc->tcp_hdr_offset = skb_transport_offset(skb);
- desc->ip_hdr_offset = skb_network_offset(skb);
- netxen_set_tx_flags_opcode(desc, flags, opcode);
- return tso;
+
+ first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+ first_desc->ip_hdr_offset += skb_network_offset(skb);
+ netxen_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ if (!tso)
+ return;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ producer = tx_ring->producer;
+ copied = 0;
+ offset = 2;
+
+ if (vlan_oob) {
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vid);
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *)hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ barrier();
}
static void
@@ -1361,9 +1511,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev,
static inline void
netxen_clear_cmddesc(u64 *desc)
{
- int i;
- for (i = 0; i < 8; i++)
- desc[i] = 0ULL;
+ desc[0] = 0ULL;
+ desc[2] = 0ULL;
}
static int
@@ -1371,18 +1520,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
- unsigned int first_seg_len = skb->len - skb->data_len;
+ struct skb_frag_struct *frag;
struct netxen_cmd_buffer *pbuf;
struct netxen_skb_frag *buffrag;
- struct cmd_desc_type0 *hwdesc;
- struct pci_dev *pdev = adapter->pdev;
+ struct cmd_desc_type0 *hwdesc, *first_desc;
+ struct pci_dev *pdev;
dma_addr_t temp_dma;
int i, k;
+ unsigned long offset;
u32 producer;
- int frag_count, no_of_desc;
+ int len, frag_count, no_of_desc;
u32 num_txd = tx_ring->num_desc;
- bool is_tso = false;
frag_count = skb_shinfo(skb)->nr_frags + 1;
@@ -1396,32 +1545,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = tx_ring->producer;
- hwdesc = &tx_ring->desc_head[producer];
- netxen_clear_cmddesc((u64 *)hwdesc);
- pbuf = &tx_ring->cmd_buf_arr[producer];
+ pdev = adapter->pdev;
+ len = skb->len - skb->data_len;
- is_tso = netxen_tso_check(netdev, hwdesc, skb);
+ temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, temp_dma))
+ goto drop_packet;
+ pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = skb;
pbuf->frag_count = frag_count;
- buffrag = &pbuf->frag_array[0];
- temp_dma = pci_map_single(pdev, skb->data, first_seg_len,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, temp_dma))
- goto drop_packet;
+ buffrag = &pbuf->frag_array[0];
buffrag->dma = temp_dma;
- buffrag->length = first_seg_len;
+ buffrag->length = len;
+
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ netxen_clear_cmddesc((u64 *)hwdesc);
netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
netxen_set_tx_port(hwdesc, adapter->portnum);
- hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
- hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+ hwdesc->buffer_length[0] = cpu_to_le16(len);
+ hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
for (i = 1, k = 1; i < frag_count; i++, k++) {
- struct skb_frag_struct *frag;
- int len, temp_len;
- unsigned long offset;
/* move to next desc. if there is a need */
if ((i & 0x3) == 0) {
@@ -1432,11 +1579,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = NULL;
}
+ buffrag = &pbuf->frag_array[i];
frag = &skb_shinfo(skb)->frags[i - 1];
len = frag->size;
offset = frag->page_offset;
- temp_len = len;
temp_dma = pci_map_page(pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, temp_dma)) {
@@ -1444,11 +1591,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
goto drop_packet;
}
- buffrag++;
buffrag->dma = temp_dma;
- buffrag->length = temp_len;
+ buffrag->length = len;
- hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
+ hwdesc->buffer_length[k] = cpu_to_le16(len);
switch (k) {
case 0:
hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
@@ -1463,53 +1609,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
break;
}
- frag++;
- }
- producer = get_next_index(producer, num_txd);
-
- /* For LSO, we need to copy the MAC/IP/TCP headers into
- * the descriptor ring
- */
- if (is_tso) {
- int hdr_len, first_hdr_len, more_hdr;
- hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
- first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
- more_hdr = 1;
- } else {
- first_hdr_len = hdr_len;
- more_hdr = 0;
- }
- /* copy the MAC/IP/TCP headers to the cmd descriptor list */
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
-
- /* copy the first 64 bytes */
- memcpy(((void *)hwdesc) + 2,
- (void *)(skb->data), first_hdr_len);
- producer = get_next_index(producer, num_txd);
-
- if (more_hdr) {
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
- /* copy the next 64 bytes - should be enough except
- * for pathological case
- */
- skb_copy_from_linear_data_offset(skb, first_hdr_len,
- hwdesc,
- (hdr_len -
- first_hdr_len));
- producer = get_next_index(producer, num_txd);
- }
}
+ tx_ring->producer = get_next_index(producer, num_txd);
- tx_ring->producer = producer;
- adapter->stats.txbytes += skb->len;
+ netxen_tso_check(netdev, tx_ring, first_desc, skb);
netxen_nic_update_cmd_producer(adapter, tx_ring);
+ adapter->stats.txbytes += skb->len;
adapter->stats.xmitcalled++;
return NETDEV_TX_OK;
@@ -1641,10 +1748,13 @@ static void netxen_tx_timeout(struct net_device *netdev)
{
struct netxen_adapter *adapter = (struct netxen_adapter *)
netdev_priv(netdev);
+
+ dev_err(&netdev->dev, "transmit timeout, resetting.\n");
+
SCHEDULE_WORK(&adapter->tx_timeout_task);
}
-static void netxen_tx_timeout_task(struct work_struct *work)
+static void netxen_reset_task(struct work_struct *work)
{
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, tx_timeout_task);
@@ -1652,9 +1762,6 @@ static void netxen_tx_timeout_task(struct work_struct *work)
if (!netif_running(adapter->netdev))
return;
- printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
- netxen_nic_driver_name, adapter->netdev->name);
-
netxen_napi_disable(adapter);
adapter->netdev->trans_start = jiffies;
@@ -1712,7 +1819,7 @@ static irqreturn_t netxen_intr(int irq, void *data)
}
/* clear interrupt */
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
netxen_nic_disable_int(sds_ring);
adapter->pci_write_immediate(adapter,
@@ -1781,6 +1888,128 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
}
#endif
+#ifdef CONFIG_INET
+
+#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
+
+static int
+netxen_destip_supported(struct netxen_adapter *adapter)
+{
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
+
+ if (adapter->ahw.cut_through)
+ return 0;
+
+ return 1;
+}
+
+static int netxen_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netxen_adapter *adapter;
+ struct net_device *dev = (struct net_device *)ptr;
+ struct in_device *indev;
+
+recheck:
+ if (dev == NULL)
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ indev = in_dev_get(dev);
+ if (!indev)
+ goto done;
+
+ for_ifa(indev) {
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+ } endfor_ifa(indev);
+
+ in_dev_put(indev);
+done:
+ return NOTIFY_DONE;
+}
+
+static int
+netxen_inetaddr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netxen_adapter *adapter;
+ struct net_device *dev;
+
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+ dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+ if (dev == NULL || !netif_running(dev))
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netxen_netdev_cb = {
+ .notifier_call = netxen_netdev_event,
+};
+
+static struct notifier_block netxen_inetaddr_cb = {
+ .notifier_call = netxen_inetaddr_event,
+};
+#endif
+
static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
.id_table = netxen_pci_tbl,
@@ -1792,8 +2021,6 @@ static struct pci_driver netxen_driver = {
#endif
};
-/* Driver Registration on NetXen card */
-
static int __init netxen_init_module(void)
{
printk(KERN_INFO "%s\n", netxen_nic_driver_string);
@@ -1801,6 +2028,11 @@ static int __init netxen_init_module(void)
if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
return -ENOMEM;
+#ifdef CONFIG_INET
+ register_netdevice_notifier(&netxen_netdev_cb);
+ register_inetaddr_notifier(&netxen_inetaddr_cb);
+#endif
+
return pci_register_driver(&netxen_driver);
}
@@ -1809,6 +2041,11 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
pci_unregister_driver(&netxen_driver);
+
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&netxen_inetaddr_cb);
+ unregister_netdevice_notifier(&netxen_netdev_cb);
+#endif
destroy_workqueue(netxen_workq);
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 2a8da476ab3d..462d20f26436 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 77d44a061703..a0ac5d4f27d3 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->len > XMIT_BUFF_SIZE) {
printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 1f10ed603e20..81a061785898 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&p->ring_lock, flags);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 89f7b2ad5231..c47ba3610c58 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
dev->name, skb->data, skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index f35c609ba020..a23aa8724042 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pop_tx_status(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 690b9c76d34e..d2156ab3da2b 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 0e38d80fd255..b5cfac7c5179 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 479d5b494371..434d9407bfb3 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
} /* fjn_start_xmit */
/*====================================================================*/
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 36de91baf238..dd6059076705 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* mace_start_xmit */
/* ----------------------------------------------------------------------------
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 37e05d3ab893..2f39244c17f2 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
smc->saved_skb = NULL;
dev->stats.tx_dropped++;
- return 0; /* Do not re-queue this packet. */
+ return NETDEV_TX_OK; /* Do not re-queue this packet. */
}
/* A packet is now waiting. */
smc->packets_waiting++;
@@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
smc_hardware_send_packet(dev); /* Send the packet now.. */
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*======================================================================
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index ef37d22c7e1d..eda7bf6047cd 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pktlen < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
pktlen = ETH_ZLEN;
}
@@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev->stats.tx_bytes += pktlen;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/****************
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 28368157dac4..7650c791cada 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1611,8 +1611,11 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (pcnet32_dwio_read_csr(ioaddr, 0) == 4
&& pcnet32_dwio_check(ioaddr)) {
a = &pcnet32_dwio;
- } else
+ } else {
+ if (pcnet32_debug & NETIF_MSG_PROBE)
+ printk(KERN_ERR PFX "No access methods\n");
goto err_release_region;
+ }
}
chip_version =
@@ -1719,7 +1722,9 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
ret = -ENOMEM;
goto err_release_region;
}
- SET_NETDEV_DEV(dev, &pdev->dev);
+
+ if (pdev)
+ SET_NETDEV_DEV(dev, &pdev->dev);
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
@@ -1818,7 +1823,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
spin_lock_init(&lp->lock);
- SET_NETDEV_DEV(dev, &pdev->dev);
lp->name = chipname;
lp->shared_irq = shared;
lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */
@@ -1852,12 +1856,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
- if (!a) {
- if (pcnet32_debug & NETIF_MSG_PROBE)
- printk(KERN_ERR PFX "No access methods\n");
- ret = -ENODEV;
- goto err_free_consistent;
- }
lp->a = *a;
/* prior to register_netdev, dev->name is not yet correct */
@@ -1973,14 +1971,13 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
return 0;
- err_free_ring:
+err_free_ring:
pcnet32_free_ring(dev);
- err_free_consistent:
pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
lp->init_block, lp->init_dma_addr);
- err_free_netdev:
+err_free_netdev:
free_netdev(dev);
- err_release_region:
+err_release_region:
release_region(ioaddr, PCNET32_TOTAL_SIZE);
return ret;
}
@@ -2089,6 +2086,7 @@ static void pcnet32_free_ring(struct net_device *dev)
static int pcnet32_open(struct net_device *dev)
{
struct pcnet32_private *lp = netdev_priv(dev);
+ struct pci_dev *pdev = lp->pci_dev;
unsigned long ioaddr = dev->base_addr;
u16 val;
int i;
@@ -2149,9 +2147,9 @@ static int pcnet32_open(struct net_device *dev)
lp->a.write_csr(ioaddr, 124, val);
/* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */
- if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT &&
- (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX ||
- lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
+ if (pdev && pdev->subsystem_vendor == PCI_VENDOR_ID_AT &&
+ (pdev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX ||
+ pdev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) {
if (lp->options & PCNET32_PORT_ASEL) {
lp->options = PCNET32_PORT_FD | PCNET32_PORT_100;
if (netif_msg_link(lp))
@@ -2536,7 +2534,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The PCNET32 interrupt handler. */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index de9cf5136fdc..d5d8e1c5bc91 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,6 +56,12 @@ config BROADCOM_PHY
Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
and BCM5482 PHYs.
+config BCM63XX_PHY
+ tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+ depends on BCM63XX
+ ---help---
+ Currently supports the 6348 and 6358 PHYs.
+
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3a1bfefefbc3..edfaac48cbd5 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
+obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
new file mode 100644
index 000000000000..4fed95e8350e
--- /dev/null
+++ b/drivers/net/phy/bcm63xx.c
@@ -0,0 +1,132 @@
+/*
+ * Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/phy.h>
+
+#define MII_BCM63XX_IR 0x1a /* interrupt register */
+#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */
+#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */
+#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */
+#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ /* Mask interrupts globally. */
+ reg |= MII_BCM63XX_IR_GMASK;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+
+ /* Unmask events we are interested in */
+ reg = ~(MII_BCM63XX_IR_DUPLEX |
+ MII_BCM63XX_IR_SPEED |
+ MII_BCM63XX_IR_LINK) |
+ MII_BCM63XX_IR_EN;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+ int reg;
+
+ /* Clear pending interrupts. */
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ reg &= ~MII_BCM63XX_IR_GMASK;
+ else
+ reg |= MII_BCM63XX_IR_GMASK;
+
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+ .phy_id = 0x00406000,
+ .phy_id_mask = 0xfffffc00,
+ .name = "Broadcom BCM63XX (1)",
+ /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+ .phy_id = 0x002bdc00,
+ .phy_id_mask = 0xfffffc00,
+ .name = "Broadcom BCM63XX (2)",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&bcm63xx_1_driver);
+ if (ret)
+ goto out_63xx_1;
+ ret = phy_driver_register(&bcm63xx_2_driver);
+ if (ret)
+ goto out_63xx_2;
+ return ret;
+
+out_63xx_2:
+ phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+ return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+ phy_driver_unregister(&bcm63xx_1_driver);
+ phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 33984b737233..22cdd451fb82 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -30,6 +30,7 @@
#ifdef CONFIG_OF_GPIO
#include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#endif
@@ -81,13 +82,12 @@ static struct mdiobb_ops mdio_gpio_ops = {
.get_mdio_data = mdio_get,
};
-static int __devinit mdio_gpio_bus_init(struct device *dev,
+static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
struct mdio_gpio_platform_data *pdata,
int bus_id)
{
struct mii_bus *new_bus;
struct mdio_gpio_info *bitbang;
- int ret = -ENOMEM;
int i;
bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
@@ -104,8 +104,6 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
new_bus->name = "GPIO Bitbanged MDIO",
- ret = -ENODEV;
-
new_bus->phy_mask = pdata->phy_mask;
new_bus->irq = pdata->irqs;
new_bus->parent = dev;
@@ -129,15 +127,8 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
dev_set_drvdata(dev, new_bus);
- ret = mdiobus_register(new_bus);
- if (ret)
- goto out_free_all;
-
- return 0;
+ return new_bus;
-out_free_all:
- dev_set_drvdata(dev, NULL);
- gpio_free(bitbang->mdio);
out_free_mdc:
gpio_free(bitbang->mdc);
out_free_bus:
@@ -145,30 +136,47 @@ out_free_bus:
out_free_bitbang:
kfree(bitbang);
out:
- return ret;
+ return NULL;
}
-static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+static void __devinit mdio_gpio_bus_deinit(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
struct mdio_gpio_info *bitbang = bus->priv;
- mdiobus_unregister(bus);
- free_mdio_bitbang(bus);
dev_set_drvdata(dev, NULL);
- gpio_free(bitbang->mdc);
gpio_free(bitbang->mdio);
+ gpio_free(bitbang->mdc);
+ free_mdio_bitbang(bus);
kfree(bitbang);
}
+static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+ mdio_gpio_bus_deinit(dev);
+}
+
static int __devinit mdio_gpio_probe(struct platform_device *pdev)
{
struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct mii_bus *new_bus;
+ int ret;
if (!pdata)
return -ENODEV;
- return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+ new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+ if (!new_bus)
+ return -ENODEV;
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ mdio_gpio_bus_deinit(&pdev->dev);
+
+ return ret;
}
static int __devexit mdio_gpio_remove(struct platform_device *pdev)
@@ -179,29 +187,12 @@ static int __devexit mdio_gpio_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF_GPIO
-static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
- struct device_node *np)
-{
- const u32 *data;
- int len, id, irq;
-
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
- return;
-
- id = *data;
- pdata->phy_mask &= ~(1 << id);
-
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq)
- pdata->irqs[id] = irq;
-}
static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = NULL;
struct mdio_gpio_platform_data *pdata;
+ struct mii_bus *new_bus;
int ret;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
@@ -215,14 +206,18 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
ret = of_get_gpio(ofdev->node, 1);
if (ret < 0)
- goto out_free;
+ goto out_free;
pdata->mdio = ret;
- while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(pdata, np);
+ new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+ if (!new_bus)
+ return -ENODEV;
- return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+ ret = of_mdiobus_register(new_bus, ofdev->node);
+ if (ret)
+ mdio_gpio_bus_deinit(&ofdev->dev);
+
+ return ret;
out_free:
kfree(pdata);
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 2ca8b0d84ee2..00487f569cfd 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -990,7 +990,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
schedule_work(&nl->immediate);
spin_unlock_irq(&nl->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 639d11bc444e..7dd0868f983a 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
skb_queue_tail(&ppp->file.xq, skb);
ppp_xmit_process(ppp);
- return 0;
+ return NETDEV_TX_OK;
outf:
kfree_skb(skb);
++dev->stats.tx_dropped;
- return 0;
+ return NETDEV_TX_OK;
}
static int
@@ -1384,7 +1384,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* create a fragment for each channel */
bits = B;
- while (nfree > 0 && len > 0) {
+ while (len > 0) {
list = list->next;
if (list == &ppp->channels) {
i = 0;
@@ -1431,29 +1431,31 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
*otherwise divide it according to the speed
*of the channel we are going to transmit on
*/
- if (pch->speed == 0) {
- flen = totlen/nfree ;
- if (nbigger > 0) {
- flen++;
- nbigger--;
- }
- } else {
- flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) /
- ((totspeed*totfree)/pch->speed)) - hdrlen;
- if (nbigger > 0) {
- flen += ((totfree - nzero)*pch->speed)/totspeed;
- nbigger -= ((totfree - nzero)*pch->speed)/
+ if (nfree > 0) {
+ if (pch->speed == 0) {
+ flen = totlen/nfree ;
+ if (nbigger > 0) {
+ flen++;
+ nbigger--;
+ }
+ } else {
+ flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) /
+ ((totspeed*totfree)/pch->speed)) - hdrlen;
+ if (nbigger > 0) {
+ flen += ((totfree - nzero)*pch->speed)/totspeed;
+ nbigger -= ((totfree - nzero)*pch->speed)/
totspeed;
+ }
}
+ nfree--;
}
- nfree--;
/*
*check if we are on the last channel or
*we exceded the lenght of the data to
*fragment
*/
- if ((nfree == 0) || (flen > len))
+ if ((nfree <= 0) || (flen > len))
flen = len;
/*
*it is not worth to tx on slow channels:
@@ -1467,7 +1469,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
continue;
}
- mtu = pch->chan->mtu + 2 - hdrlen;
+ mtu = pch->chan->mtu - hdrlen;
if (mtu < 4)
mtu = 4;
if (flen > mtu)
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index f0031f1f97e5..5f2090233d7b 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1063,6 +1063,7 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
else {
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+ po = NULL;
while (++hash < PPPOE_HASH_SIZE) {
po = pn->hash_table[hash];
if (po)
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index e7935d09c896..e0f9219a0aea 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -2680,6 +2680,7 @@ out_unregister_pppol2tp_proto:
static void __exit pppol2tp_exit(void)
{
unregister_pppox_proto(PX_PROTO_OL2TP);
+ unregister_pernet_gen_device(pppol2tp_net_id, &pppol2tp_net_ops);
proto_unregister(&pppol2tp_sk_proto);
}
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 5768af17f168..3a271afdd8f5 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4076,6 +4076,11 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
struct net_device *ndev = pci_get_drvdata(pdev);
struct ql_adapter *qdev = netdev_priv(ndev);
+ netif_device_detach(ndev);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(ndev))
ql_adapter_down(qdev);
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 961b5397a531..840677f5ee82 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -1115,13 +1115,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
}
/* IO Size check */
- if (pci_resource_len(pdev, 0) < io_size) {
+ if (pci_resource_len(pdev, bar) < io_size) {
printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
err = -EIO;
goto err_out;
}
- pioaddr = pci_resource_start(pdev, 0); /* IO map base address */
+ pioaddr = pci_resource_start(pdev, bar); /* IO map base address */
pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct r6040_private));
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 4b53b58d75fc..b82780d805f5 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2060,8 +2060,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- pci_set_master(pdev);
-
/* ioremap MMIO region */
ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
if (!ioaddr) {
@@ -2089,6 +2087,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
RTL_W16(IntrStatus, 0xffff);
+ pci_set_master(pdev);
+
/* Identify chip attached to board */
rtl8169_get_mac_version(tp, ioaddr);
@@ -3874,6 +3874,15 @@ static void rtl_shutdown(struct pci_dev *pdev)
spin_unlock_irq(&tp->lock);
if (system_state == SYSTEM_POWER_OFF) {
+ /* WoL fails with some 8168 when the receiver is disabled. */
+ if (tp->features & RTL_FEATURE_WOL) {
+ pci_clear_master(pdev);
+
+ RTL_W8(ChipCmd, CmdRxEnb);
+ /* PCI commit */
+ RTL_R8(ChipCmd);
+ }
+
pci_wake_from_d3(pdev, true);
pci_set_power_state(pdev, PCI_D3hot);
}
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 8702e7acdee6..ede937ee50c7 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -72,7 +72,7 @@ static int rionet_check = 0;
static int rionet_capable = 1;
/*
- * This is a fast lookup table for for translating TX
+ * This is a fast lookup table for translating TX
* Ethernet packets into a destination RIO device. It
* could be made into a hash table to save memory depending
* on system trade-offs.
@@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev)
if (error == NET_RX_DROP) {
ndev->stats.rx_dropped++;
- } else if (error == NET_RX_BAD) {
- if (netif_msg_rx_err(rnet))
- printk(KERN_WARNING "%s: bad rx packet\n",
- DRV_NAME);
- ndev->stats.rx_errors++;
} else {
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
@@ -208,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&rnet->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 81dbcbb910f4..d95534655911 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&rrpriv->lock, flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 458daa06ed41..bd6d713c861a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len <= 0)) {
DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
queue = 0;
@@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
s2io_stop_tx_queue(sp, fifo->fifo_no);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
offload_type = s2io_offload_type(skb);
@@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (sp->config.intr_type == MSI_X)
tx_intr_handler(fifo);
- return 0;
+ return NETDEV_TX_OK;
pci_map_failed:
stats->pci_map_fail_cnt++;
s2io_stop_tx_queue(sp, fifo->fifo_no);
stats->mem_freed += skb->truesize;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
@@ -8636,6 +8636,9 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
netif_device_detach(netdev);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev)) {
/* Bring down the card, while avoiding PCI I/O */
do_s2io_card_down(sp, 0);
diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c
index 5345e47b35ac..4525cbe8dd69 100644
--- a/drivers/net/s6gmac.c
+++ b/drivers/net/s6gmac.c
@@ -793,7 +793,7 @@ static inline int s6gmac_phy_start(struct net_device *dev)
struct s6gmac *pd = netdev_priv(dev);
int i = 0;
struct phy_device *p = NULL;
- while ((!(p = pd->mii.bus->phy_map[i])) && (i < PHY_MAX_ADDR))
+ while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
i++;
p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
PHY_INTERFACE_MODE_RGMII);
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index fc0e38bddeeb..6a81aec645d9 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name);
/* sb1000 can't xmit datagrams */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* SB1000 interrupt handler. */
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index d8c9cf1b901d..508551f1b3fc 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&sc->sbm_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**********************************************************************
@@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget)
}
-static int __init sbmac_probe(struct platform_device *pldev)
+static int __devinit sbmac_probe(struct platform_device *pldev)
{
struct net_device *dev;
struct sbmac_softc *sc;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index ebbbe09725fe..7cc8bb814137 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 343e8da1fa30..1f1757118a5c 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -884,13 +884,12 @@ static int efx_wanted_rx_queues(void)
int count;
int cpu;
- if (unlikely(!alloc_cpumask_var(&core_mask, GFP_KERNEL))) {
+ if (unlikely(!zalloc_cpumask_var(&core_mask, GFP_KERNEL))) {
printk(KERN_WARNING
"sfc: RSS disabled due to allocation failure\n");
return 1;
}
- cpumask_clear(core_mask);
count = 0;
for_each_online_cpu(cpu) {
if (!cpumask_test_cpu(cpu, core_mask)) {
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 5fb88ca6dd7f..ecf3279fbef5 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&sp->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void timeout(struct net_device *dev)
@@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
-static int __init sgiseeq_probe(struct platform_device *pdev)
+static int __devinit sgiseeq_probe(struct platform_device *pdev)
{
struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
struct hpc3_regs *hpcregs = pd->hpc;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index a2d82ddb3b4d..4c4dcbf19026 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ndev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* device close function */
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index a9a897bb42d5..61ceeaaf104d 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
"to slot %d.\n",
net_dev->name, skb->data, (int)skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 088fe26484e7..888a14a045ef 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
// dequeue packets from xmt queue and send them
netif_start_queue(dev);
dev_kfree_skb(skb);
- return (0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
if (bp->QueueSkb == 0) { // return with tbusy set: queue full
@@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} // skfp_send_pkt
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 60d502eef4fc..543af2044f40 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3854,8 +3854,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
- if (device_may_wakeup(&hw->pdev->dev))
+ if (device_can_wakeup(&hw->pdev->dev)) {
skge->wol = wol_supported(hw) & WAKE_MAGIC;
+ device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+ }
hw->dev[port] = dev;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3550c5dcd93c..661abd0492ae 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4117,7 +4117,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n",
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)),
- last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
+ sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
sky2_read32(hw, B0_Y2_SP_LISR);
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5c61d5fad908..899c4a2112c9 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sl->tty == NULL) {
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
sl_lock(sl);
@@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index bc4976ac8712..2a6b6de95339 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_dropped++;
spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#ifdef SMC_USE_DMA
@@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->pending_tx_skb = skb;
netif_stop_queue(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
lp->txdma_active = 1;
@@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc911x_hardware_send_pkt(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index e02471b2f2b5..0a1b6f401087 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = ETH_ZLEN;
}
@@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/* either way, a packet is waiting now */
lp->packets_waiting++;
@@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
SMC_ENABLE_INT( IM_ALLOC_INT );
PRINTK2((CARDNAME": memory allocation deferred. \n"));
/* it's deferred, but I'll handle it later */
- return 0;
+ return NETDEV_TX_OK;
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 1c70e999cc50..0f2c52c2e044 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
smc_special_lock(&lp->lock);
@@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc_hardware_send_pkt((unsigned long)dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index f1f773b17fe1..57a159fac99f 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -186,7 +186,8 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l))
#define SMC_IRQ_FLAGS (-1) /* from resource */
-#elif defined(CONFIG_MACH_LOGICPD_PXA270)
+#elif defined(CONFIG_MACH_LOGICPD_PXA270) \
+ || defined(CONFIG_MACH_NOMADIK_8815NHK)
#define SMC_CAN_USE_8BIT 0
#define SMC_CAN_USE_16BIT 1
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 753a1fba4609..9599ce77ef85 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
length = skb->len;
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 669253c7bd41..5e7645ee8ab0 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 7bb27426dbd6..2f1eaaf7a727 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
if(skb->len > XMIT_BUFF_SIZE)
{
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
#endif
}
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 534dfe3eef6f..0ca4241b4f63 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
netif_start_queue(dev);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 5017d7fcb40c..536cf7e06bfd 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index d1521c3875b2..d09be481bcc4 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
"%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* Reset hardware tx and free all of tx buffers */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 4ef729198e10..008bd59fc64b 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index afc7b351e5ec..9d6fd4760eab 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* taken from the depca driver */
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c6ec61e0accf..dcefb608a9f4 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void qe_set_multicast(struct net_device *dev)
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d737f6b8f876..1ce2da172ca9 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
*/
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
#define FATAL_ERROR_INT \
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 384cb5e28397..70c9ec45d8fb 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n",
dev->name );
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
- return 0;
+ return NETDEV_TX_OK;
txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE);
tail_list = priv->txList + priv->txTail;
@@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} /* TLan_StartTx */
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index b40b6de2d086..1787d52941bc 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 9d896116cf76..96d00c8f8d3e 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
spin_unlock_irqrestore(&(ti->lock), flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************************************/
@@ -1912,7 +1912,7 @@ static int __init ibmtr_init(void)
find_turbo_adapters(io);
- for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) {
+ for (i = 0; i < IBMTR_MAX_ADAPTERS && io[i]; i++) {
struct net_device *dev;
irq[i] = 0;
mem[i] = 0;
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index b3715efdce56..d07e61a9499e 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
netif_stop_queue(dev);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 451b54136ede..f73f4e684f33 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
netif_wake_queue(dev);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 54ad4ed03374..6515894c83f5 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
if(tp->QueueSkb > 0)
netif_wake_queue(dev);
- return (0);
+ return NETDEV_TX_OK;
}
static int smctr_send_lobe_media_test(struct net_device *dev)
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index a2eab72b507a..07f6dfd3ba0c 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
tms380tr_exec_sifcmd(dev, CMD_TX_VALID);
spin_unlock_irqrestore(&tp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index ef49744a5085..bc8a6b263b40 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
dw32(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index eb72d2e9ab3d..acfdccd44567 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -5059,7 +5059,7 @@ mii_get_phy(struct net_device *dev)
if ((id == 0) || (id == 65535)) continue; /* Valid ID? */
for (j=0; j<limit; j++) { /* Search PHY table */
if (id != phy_info[j].id) continue; /* ID match? */
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++);
if (k < DE4X5_MAX_PHY) {
memcpy((char *)&lp->phy[k],
(char *)&phy_info[j], sizeof(struct phy_table));
@@ -5072,7 +5072,7 @@ mii_get_phy(struct net_device *dev)
break;
}
if ((j == limit) && (i < DE4X5_MAX_MII)) {
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++);
lp->phy[k].addr = i;
lp->phy[k].id = id;
lp->phy[k].spd.reg = GENERIC_REG; /* ANLPA register */
@@ -5091,7 +5091,7 @@ mii_get_phy(struct net_device *dev)
purgatory:
lp->active = 0;
if (lp->phy[0].id) { /* Reset the PHY devices */
- for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
+ for (k=0; k < DE4X5_MAX_PHY && lp->phy[k].id; k++) { /*For each PHY*/
mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 8e78f003f08f..5e15fab58c17 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 99a63649f4fc..019050f273a2 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -692,7 +692,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void tulip_clean_tx_ring(struct tulip_private *tp)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 9277ce8febe4..9074a34eb814 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 0f15773dae52..1853530a32a2 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index c2ca9f40e40e..22b6a239fb33 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->transmit_used = nextdescriptor;
leave("xircom-start_xmit - sent");
spin_unlock_irqrestore(&card->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 027f7aba26af..a998b6a9c245 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
if (tun->flags & TUN_FASYNC)
kill_fasync(&tun->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&tun->socket.wait);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void tun_net_mclist(struct net_device *dev)
@@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
case VIRTIO_NET_HDR_GSO_TCPV6:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
+ case VIRTIO_NET_HDR_GSO_UDP:
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+ break;
default:
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
@@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
@@ -997,7 +1002,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
goto err_free_sk;
}
- err = -EINVAL;
err = register_netdevice(tun->dev);
if (err < 0)
goto err_free_sk;
@@ -1074,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
old_features = dev->features;
/* Unset features, set them as we chew on the arg. */
features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
- |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6));
+ |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
+ |NETIF_F_UFO));
if (arg & TUN_F_CSUM) {
features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
@@ -1091,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg)
features |= NETIF_F_TSO6;
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
}
+
+ if (arg & TUN_F_UFO) {
+ features |= NETIF_F_UFO;
+ arg &= ~TUN_F_UFO;
+ }
}
/* This gives the user a way to test for new features in future by
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index cf25eb41b1ce..2c26b4577e8a 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 40c6eba775ce..52a6750b8201 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
{
struct sk_buff *skb = NULL;
- skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+ skb = __skb_dequeue(&ugeth->rx_recycle);
+ if (!skb)
+ skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if (skb == NULL)
return NULL;
@@ -1590,13 +1591,13 @@ static int init_phy(struct net_device *dev)
priv->oldspeed = 0;
priv->oldduplex = -1;
- if (!ug_info->phy_node)
- return 0;
-
phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
priv->phy_interface);
+ if (!phydev)
+ phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+ priv->phy_interface);
if (!phydev) {
- printk("%s: Could not attach to PHY\n", dev->name);
+ dev_err(&dev->dev, "Could not attach to PHY\n");
return -ENODEV;
}
@@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
iounmap(ugeth->ug_regs);
ugeth->ug_regs = NULL;
}
+
+ skb_queue_purge(&ugeth->rx_recycle);
}
static void ucc_geth_set_multi(struct net_device *dev)
@@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
+ skb_queue_head_init(&ugeth->rx_recycle);
+
return 0;
}
@@ -3173,7 +3178,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
spin_unlock_irq(&ugeth->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (netif_msg_rx_err(ugeth))
ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
__func__, __LINE__, (u32) skb);
- if (skb)
- dev_kfree_skb_any(skb);
+ if (skb) {
+ skb->data = skb->head + NET_SKB_PAD;
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ }
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
dev->stats.rx_dropped++;
@@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Normal processing. */
while ((bd_status & T_R) == 0) {
+ struct sk_buff *skb;
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
@@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
dev->stats.tx_packets++;
- /* Free the sk buffer associated with this TxBD */
- dev_kfree_skb(ugeth->
- tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+ skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+
+ if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+ skb_recycle_check(skb,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ else
+ dev_kfree_skb(skb);
+
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
(ugeth->skb_dirtytx[txQ] +
@@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
ug_info = ugeth->ug_info;
- howmany = 0;
- for (i = 0; i < ug_info->numQueuesRx; i++)
- howmany += ucc_geth_rx(ugeth, i, budget - howmany);
-
/* Tx event processing */
spin_lock(&ugeth->lock);
for (i = 0; i < ug_info->numQueuesTx; i++)
ucc_geth_tx(ugeth->ndev, i);
spin_unlock(&ugeth->lock);
+ howmany = 0;
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ howmany += ucc_geth_rx(ugeth, i, budget - howmany);
+
if (howmany < budget) {
napi_complete(napi);
setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
@@ -3608,9 +3624,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
struct ucc_geth_private *ugeth = NULL;
struct ucc_geth_info *ug_info;
struct resource res;
- struct device_node *phy;
int err, ucc_num, max_speed = 0;
- const u32 *fixed_link;
const unsigned int *prop;
const char *sprop;
const void *mac_addr;
@@ -3708,15 +3722,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ug_info->uf_info.regs = res.start;
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
- fixed_link = of_get_property(np, "fixed-link", NULL);
- if (fixed_link) {
- phy = NULL;
- } else {
- phy = of_parse_phandle(np, "phy-handle", 0);
- if (phy == NULL)
- return -ENODEV;
- }
- ug_info->phy_node = phy;
+
+ ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
/* Find the TBI PHY node. If it's not there, we don't support SGMII */
ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -3725,7 +3732,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
prop = of_get_property(np, "phy-connection-type", NULL);
if (!prop) {
/* handle interface property present in old trees */
- prop = of_get_property(phy, "interface", NULL);
+ prop = of_get_property(ug_info->phy_node, "interface", NULL);
if (prop != NULL) {
phy_interface = enet_to_phy_interface[*prop];
max_speed = enet_to_speed[*prop];
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 195ab267ead7..cfb31afc08a9 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1212,6 +1212,8 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
+ struct sk_buff_head rx_recycle;
+
struct ugeth_mii_info *mii_info;
struct phy_device *phydev;
phy_interface_t phy_interface;
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index b9dd42574288..7abdc4abbe07 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void catc_tx_timeout(struct net_device *netdev)
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index f8c6d7ea7264..ffe410635735 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
netif_stop_queue(net);
if (hso_get_activity(odev->parent) == -EAGAIN) {
odev->skb_tx_buf = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* log if asked */
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 1f9ec29fce50..200fe3d525ca 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth->stats.tx_errors++;
netif_start_queue(net);
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -864,7 +864,7 @@ skip:
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/****************************************************************
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 631d269ac980..69d2df95ac86 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fcc6fa0905d1..bac8b77fb25e 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index edfd9e10ceba..25e435c49040 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
+ struct driver_info *info = dev->driver_info;
int temp;
+ int retval;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
DECLARE_WAITQUEUE (wait, current);
@@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_errors, net->stats.tx_errors
);
+ /* allow minidriver to stop correctly (wireless devices to turn off
+ * radio etc) */
+ if (info->stop) {
+ retval = info->stop(dev);
+ if (retval < 0 && netif_msg_ifdown(dev))
+ devinfo(dev,
+ "stop fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ }
+
// ensure there are no more active urbs
add_wait_queue (&unlink_wakeup, &wait);
dev->wait = &unlink_wakeup;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1097c72e44d5..190f784c9cfe 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > (rcv->mtu + MTU_PAD))
goto rx_drop;
+ skb->tstamp.tv64 = 0;
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, rcv);
if (dev->features & NETIF_F_NO_CSUM)
@@ -189,17 +190,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
rcv_stats->rx_packets++;
netif_rx(skb);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
kfree_skb(skb);
stats->tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
rx_drop:
kfree_skb(skb);
rcv_stats->rx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 88c30a58b4bd..46eb618bbc90 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1226,7 +1226,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
entry = rp->cur_tx % TX_RING_SIZE;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
rp->tx_skbuff[entry] = skb;
@@ -1238,7 +1238,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
rp->tx_skbuff[entry] = NULL;
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/* Padding is not copied and so must be redone. */
@@ -1286,7 +1286,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, rp->cur_tx-1, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 3ba35956327a..47be41a39d35 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,9 +61,9 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/if.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/inetdevice.h>
#include <linux/reboot.h>
@@ -81,7 +81,7 @@
#include "via-velocity.h"
-static int velocity_nics = 0;
+static int velocity_nics;
static int msglevel = MSG_LEVEL_INFO;
/**
@@ -92,8 +92,7 @@ static int msglevel = MSG_LEVEL_INFO;
* Fetch the mask bits of the selected CAM and store them into the
* provided mask buffer.
*/
-
-static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
@@ -111,7 +110,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
/* Select mar */
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
}
@@ -122,8 +120,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Store a new mask into a CAM
*/
-
-static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -131,9 +128,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -141,7 +138,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -149,9 +146,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -167,8 +164,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Load an address or vlan tag into a CAM
*/
-
-static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
{
int i;
@@ -179,9 +175,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(*addr++, &(regs->MARCAM[i]));
- }
+
BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
udelay(10);
@@ -192,7 +188,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
const u8 *addr)
{
@@ -223,8 +219,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
* reset the Wake on lan features. This function doesn't restore
* the rest of the logic from the result of sleep/wakeup
*/
-
-static void mac_wol_reset(struct mac_regs __iomem * regs)
+static void mac_wol_reset(struct mac_regs __iomem *regs)
{
/* Turn off SWPTAG right after leaving power mode */
@@ -242,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem * regs)
writew(0xFFFF, &regs->WOLSRClr);
}
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static const struct ethtool_ops velocity_ethtool_ops;
/*
@@ -253,10 +247,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
-#define VELOCITY_PARAM(N,D) \
- static int N[MAX_UNITS]=OPTION_DEFAULT;\
+#define VELOCITY_PARAM(N, D) \
+ static int N[MAX_UNITS] = OPTION_DEFAULT;\
module_param_array(N, int, NULL, 0); \
- MODULE_PARM_DESC(N, D);
+ MODULE_PARM_DESC(N, D);
#define RX_DESC_MIN 64
#define RX_DESC_MAX 255
@@ -336,8 +330,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
4: indicate 10Mbps full duplex mode
Note:
- if EEPROM have been set to the force mode, this option is ignored
- by driver.
+ if EEPROM have been set to the force mode, this option is ignored
+ by driver.
*/
VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
@@ -370,76 +364,14 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
- const struct velocity_info_tbl *info);
-static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
-static void velocity_print_info(struct velocity_info *vptr);
-static int velocity_open(struct net_device *dev);
-static int velocity_change_mtu(struct net_device *dev, int mtu);
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t velocity_intr(int irq, void *dev_instance);
-static void velocity_set_multi(struct net_device *dev);
-static struct net_device_stats *velocity_get_stats(struct net_device *dev);
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int velocity_close(struct net_device *dev);
-static int velocity_receive_frame(struct velocity_info *, int idx);
-static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_free_rd_ring(struct velocity_info *vptr);
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
-static int velocity_soft_reset(struct velocity_info *vptr);
-static void mii_init(struct velocity_info *vptr, u32 mii_status);
-static u32 velocity_get_link(struct net_device *dev);
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
-static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
-static void velocity_shutdown(struct velocity_info *vptr);
-static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem * regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
-static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
-static u32 check_connection_type(struct mac_regs __iomem * regs);
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
-
#ifdef CONFIG_PM
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
-static int velocity_resume(struct pci_dev *pdev);
-
static DEFINE_SPINLOCK(velocity_dev_list_lock);
static LIST_HEAD(velocity_dev_list);
-
-#endif
-
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
-
-static struct notifier_block velocity_inetaddr_notifier = {
- .notifier_call = velocity_netdev_event,
-};
-
-static void velocity_register_notifier(void)
-{
- register_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-static void velocity_unregister_notifier(void)
-{
- unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-#else
-
-#define velocity_register_notifier() do {} while (0)
-#define velocity_unregister_notifier() do {} while (0)
-
#endif
/*
* Internal board variants. At the moment we have only one
*/
-
static struct velocity_info_tbl chip_info_table[] = {
{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
{ }
@@ -449,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = {
* Describe the PCI device identifiers that we support in this
* device driver. Used for hotplug autoloading.
*/
-
static const struct pci_device_id velocity_id_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ }
@@ -464,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
* Given a chip identifier return a suitable description. Returns
* a pointer a static string valid while the driver is loaded.
*/
-
static const char __devinit *get_chip_name(enum chip_type chip_id)
{
int i;
@@ -482,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id)
* unload for each active device that is present. Disconnects
* the device from the network layer and frees all the resources
*/
-
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -520,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname)
{
if (val == -1)
@@ -549,8 +477,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname)
+static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
{
(*opt) &= (~flag);
if (val == -1)
@@ -575,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla
* Turn the module and command options into a single structure
* for the current device
*/
-
static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname)
{
@@ -601,10 +527,9 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
* Initialize the content addressable memory used for filters. Load
* appropriately according to the presence of VLAN
*/
-
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -647,19 +572,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
vlan_group_set_device(vptr->vlgrp, vid, NULL);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
@@ -674,11 +599,10 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
* Reset the ownership and status for the receive ring side.
* Hand all the receive queue to the NIC.
*/
-
static void velocity_rx_reset(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i;
velocity_init_rx_ring_indexes(vptr);
@@ -696,6 +620,647 @@ static void velocity_rx_reset(struct velocity_info *vptr)
}
/**
+ * velocity_get_opt_media_mode - get media selection
+ * @vptr: velocity adapter
+ *
+ * Get the media mode stored in EEPROM or module options and load
+ * mii_status accordingly. The requested link state information
+ * is also returned.
+ */
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+ u32 status = 0;
+
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_AUTO:
+ status = VELOCITY_AUTONEG_ENABLE;
+ break;
+ case SPD_DPX_100_FULL:
+ status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_10_FULL:
+ status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_100_HALF:
+ status = VELOCITY_SPEED_100;
+ break;
+ case SPD_DPX_10_HALF:
+ status = VELOCITY_SPEED_10;
+ break;
+ }
+ vptr->mii_status = status;
+ return status;
+}
+
+/**
+ * safe_disable_mii_autopoll - autopoll off
+ * @regs: velocity registers
+ *
+ * Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ u16 ww;
+
+ /* turn off MAUTO */
+ writeb(0, &regs->MIICR);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+}
+
+/**
+ * enable_mii_autopoll - turn on autopolling
+ * @regs: velocity registers
+ *
+ * Enable the MII link status autopoll feature on the Velocity
+ * hardware. Wait for it to enable.
+ */
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ int ii;
+
+ writeb(0, &(regs->MIICR));
+ writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+ writeb(MIICR_MAUTO, &regs->MIICR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+}
+
+/**
+ * velocity_mii_read - read MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: buffer for received data
+ *
+ * Perform a single read of an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ writeb(index, &regs->MIIADR);
+
+ BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ if (!(readb(&regs->MIICR) & MIICR_RCMD))
+ break;
+ }
+
+ *data = readw(&regs->MIIDATA);
+
+ enable_mii_autopoll(regs);
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+
+/**
+ * mii_check_media_mode - check media state
+ * @regs: velocity registers
+ *
+ * Check the current MII status and determine the link status
+ * accordingly
+ */
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
+{
+ u32 status = 0;
+ u16 ANAR;
+
+ if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+ status |= VELOCITY_LINK_FAIL;
+
+ if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+ else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+ status |= (VELOCITY_SPEED_1000);
+ else {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if (ANAR & ANAR_TXFD)
+ status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+ else if (ANAR & ANAR_TX)
+ status |= VELOCITY_SPEED_100;
+ else if (ANAR & ANAR_10FD)
+ status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+ else
+ status |= (VELOCITY_SPEED_10);
+ }
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * velocity_mii_write - write MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: 16bit data for the MII register
+ *
+ * Perform a single write to an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ /* MII reg offset */
+ writeb(mii_addr, &regs->MIIADR);
+ /* set MII data */
+ writew(data, &regs->MIIDATA);
+
+ /* turn on MIICR_WCMD */
+ BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(5);
+ if (!(readb(&regs->MIICR) & MIICR_WCMD))
+ break;
+ }
+ enable_mii_autopoll(regs);
+
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+/**
+ * set_mii_flow_control - flow control setup
+ * @vptr: velocity interface
+ *
+ * Set up the flow control on this interface according to
+ * the supplied user/eeprom options.
+ */
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+ /*Enable or Disable PAUSE in ANAR */
+ switch (vptr->options.flow_cntl) {
+ case FLOW_CNTL_TX:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * mii_set_auto_on - autonegotiate on
+ * @vptr: velocity
+ *
+ * Enable autonegotation on this interface
+ */
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+ else
+ MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+static u32 check_connection_type(struct mac_regs __iomem *regs)
+{
+ u32 status = 0;
+ u8 PHYSR0;
+ u16 ANAR;
+ PHYSR0 = readb(&regs->PHYSR0);
+
+ /*
+ if (!(PHYSR0 & PHYSR0_LINKGD))
+ status|=VELOCITY_LINK_FAIL;
+ */
+
+ if (PHYSR0 & PHYSR0_FDPX)
+ status |= VELOCITY_DUPLEX_FULL;
+
+ if (PHYSR0 & PHYSR0_SPDG)
+ status |= VELOCITY_SPEED_1000;
+ else if (PHYSR0 & PHYSR0_SPD10)
+ status |= VELOCITY_SPEED_10;
+ else
+ status |= VELOCITY_SPEED_100;
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+
+
+/**
+ * velocity_set_media_mode - set media mode
+ * @mii_status: old MII link state
+ *
+ * Check the media link state and configure the flow control
+ * PHY and also velocity hardware setup accordingly. In particular
+ * we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+ u32 curr_status;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+ curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+ /* Set mii link status */
+ set_mii_flow_control(vptr);
+
+ /*
+ Check if new status is consisent with current status
+ if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+ || (mii_status==curr_status)) {
+ vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+ vptr->mii_status=check_connection_type(vptr->mac_regs);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+ return 0;
+ }
+ */
+
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+ /*
+ * If connection type is AUTO
+ */
+ if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+ /* clear force MAC mode bit */
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* set duplex mode of MAC according to duplex mode of MII */
+ MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+ MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ } else {
+ u16 ANAR;
+ u8 CHIPGCR;
+
+ /*
+ * 1. if it's 3119, disable frame bursting in halfduplex mode
+ * and enable it in fullduplex mode
+ * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+ * 3. only enable CD heart beat counter in 10HD mode
+ */
+
+ /* set force MAC mode bit */
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ CHIPGCR = readb(&regs->CHIPGCR);
+ CHIPGCR &= ~CHIPGCR_FCGMII;
+
+ if (mii_status & VELOCITY_DUPLEX_FULL) {
+ CHIPGCR |= CHIPGCR_FCFDX;
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ } else {
+ CHIPGCR &= ~CHIPGCR_FCFDX;
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ }
+
+ MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+ if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ else
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+
+ /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+ velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+ ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+ if (mii_status & VELOCITY_SPEED_100) {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_TXFD;
+ else
+ ANAR |= ANAR_TX;
+ } else {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_10FD;
+ else
+ ANAR |= ANAR_10;
+ }
+ velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ }
+ /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+ /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+ return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ * velocity_print_link_status - link status reporting
+ * @vptr: velocity to report on
+ *
+ * Turn the link status of the velocity card into a kernel log
+ * description of the new link state, detailing speed and duplex
+ * status
+ */
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+ if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+ } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+ else if (vptr->mii_status & VELOCITY_SPEED_100)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+ } else {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_100_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+ break;
+ case SPD_DPX_100_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+ break;
+ case SPD_DPX_10_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+ break;
+ case SPD_DPX_10_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * enable_flow_control_ability - flow control
+ * @vptr: veloity to configure
+ *
+ * Set up flow control according to the flow control options
+ * determined by the eeprom/configuration.
+ */
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ switch (vptr->options.flow_cntl) {
+
+ case FLOW_CNTL_DEFAULT:
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_RX:
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+/**
+ * velocity_soft_reset - soft reset
+ * @vptr: velocity to reset
+ *
+ * Kick off a soft reset of the velocity adapter and then poll
+ * until the reset sequence has completed before returning.
+ */
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i = 0;
+
+ writel(CR0_SFRST, &regs->CR0Set);
+
+ for (i = 0; i < W_MAX_TIMEOUT; i++) {
+ udelay(5);
+ if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+ break;
+ }
+
+ if (i == W_MAX_TIMEOUT) {
+ writel(CR0_FORSRST, &regs->CR0Set);
+ /* FIXME: PCI POSTING */
+ /* delay 2ms */
+ mdelay(2);
+ }
+ return 0;
+}
+
+/**
+ * velocity_set_multi - filter list change callback
+ * @dev: network device
+ *
+ * Called by the network layer when the filter lists need to change
+ * for a velocity adapter. Reload the CAMs with the new address
+ * filter ruleset.
+ */
+static void velocity_set_multi(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u8 rx_mode;
+ int i;
+ struct dev_mc_list *mclist;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+ } else if ((dev->mc_count > vptr->multicast_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB);
+ } else {
+ int offset = MCAM_SIZE - vptr->multicast_limit;
+ mac_get_cam_mask(regs, vptr->mCAMmask);
+
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ mac_set_cam(regs, i + offset, mclist->dmi_addr);
+ vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+ }
+
+ mac_set_cam_mask(regs, vptr->mCAMmask);
+ rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ }
+ if (dev->mtu > 1500)
+ rx_mode |= RCR_AL;
+
+ BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+/**
+ * mii_init - set up MII
+ * @vptr: velocity adapter
+ * @mii_status: links tatus
+ *
+ * Set up the PHY for the current link state.
+ */
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+ u16 BMCR;
+
+ switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+ case PHYID_CICADA_CS8201:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue.
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ /*
+ * Turn on Link/Activity LED enable bit for CIS8201
+ */
+ MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+ break;
+ case PHYID_VT3216_32BIT:
+ case PHYID_VT3216_64BIT:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ break;
+
+ case PHYID_MARVELL_1000:
+ case PHYID_MARVELL_1000S:
+ /*
+ * Assert CRS on Transmit
+ */
+ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ break;
+ default:
+ ;
+ }
+ velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+ if (BMCR & BMCR_ISO) {
+ BMCR &= ~BMCR_ISO;
+ velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+ }
+}
+
+
+/**
* velocity_init_registers - initialise MAC registers
* @vptr: velocity to init
* @type: type of initialisation (hot or cold)
@@ -703,11 +1268,10 @@ static void velocity_rx_reset(struct velocity_info *vptr)
* Initialise the MAC on a reset or on first set up on the
* hardware.
*/
-
static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i, mii_status;
mac_wol_reset(regs);
@@ -750,9 +1314,9 @@ static void velocity_init_registers(struct velocity_info *vptr,
mdelay(5);
mac_eeprom_reload(regs);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
- }
+
/*
* clear Pre_ACPI bit.
*/
@@ -819,291 +1383,29 @@ static void velocity_init_registers(struct velocity_info *vptr,
}
}
-/**
- * velocity_soft_reset - soft reset
- * @vptr: velocity to reset
- *
- * Kick off a soft reset of the velocity adapter and then poll
- * until the reset sequence has completed before returning.
- */
-
-static int velocity_soft_reset(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i = 0;
-
- writel(CR0_SFRST, &regs->CR0Set);
-
- for (i = 0; i < W_MAX_TIMEOUT; i++) {
- udelay(5);
- if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
- break;
- }
-
- if (i == W_MAX_TIMEOUT) {
- writel(CR0_FORSRST, &regs->CR0Set);
- /* FIXME: PCI POSTING */
- /* delay 2ms */
- mdelay(2);
- }
- return 0;
-}
-
-static const struct net_device_ops velocity_netdev_ops = {
- .ndo_open = velocity_open,
- .ndo_stop = velocity_close,
- .ndo_start_xmit = velocity_xmit,
- .ndo_get_stats = velocity_get_stats,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_set_multicast_list = velocity_set_multi,
- .ndo_change_mtu = velocity_change_mtu,
- .ndo_do_ioctl = velocity_ioctl,
- .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
- .ndo_vlan_rx_register = velocity_vlan_rx_register,
-};
-
-/**
- * velocity_found1 - set up discovered velocity card
- * @pdev: PCI device
- * @ent: PCI device table entry that matched
- *
- * Configure a discovered adapter from scratch. Return a negative
- * errno error code on failure paths.
- */
-
-static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void velocity_give_many_rx_descs(struct velocity_info *vptr)
{
- static int first = 1;
- struct net_device *dev;
- int i;
- const char *drv_string;
- const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
- struct velocity_info *vptr;
- struct mac_regs __iomem * regs;
- int ret = -ENOMEM;
-
- /* FIXME: this driver, like almost all other ethernet drivers,
- * can support more than MAX_UNITS.
- */
- if (velocity_nics >= MAX_UNITS) {
- dev_notice(&pdev->dev, "already found %d NICs.\n",
- velocity_nics);
- return -ENODEV;
- }
-
- dev = alloc_etherdev(sizeof(struct velocity_info));
- if (!dev) {
- dev_err(&pdev->dev, "allocate net device failed.\n");
- goto out;
- }
-
- /* Chain it all together */
-
- SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = netdev_priv(dev);
-
-
- if (first) {
- printk(KERN_INFO "%s Ver. %s\n",
- VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
- printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
- printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
- first = 0;
- }
-
- velocity_init_info(pdev, vptr, info);
-
- vptr->dev = dev;
-
- dev->irq = pdev->irq;
-
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_free_dev;
-
- ret = velocity_get_pci_info(vptr, pdev);
- if (ret < 0) {
- /* error message already printed */
- goto err_disable;
- }
-
- ret = pci_request_regions(pdev, VELOCITY_NAME);
- if (ret < 0) {
- dev_err(&pdev->dev, "No PCI resources.\n");
- goto err_disable;
- }
-
- regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
- if (regs == NULL) {
- ret = -EIO;
- goto err_release_res;
- }
-
- vptr->mac_regs = regs;
-
- mac_wol_reset(regs);
-
- dev->base_addr = vptr->ioaddr;
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(&regs->PAR[i]);
-
-
- drv_string = dev_driver_string(&pdev->dev);
-
- velocity_get_options(&vptr->options, velocity_nics, drv_string);
-
- /*
- * Mask out the options cannot be set to the chip
- */
-
- vptr->options.flags &= info->flags;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int avail, dirty, unusable;
/*
- * Enable the chip specified capbilities
+ * RD number must be equal to 4X per hardware spec
+ * (programming guide rev 1.20, p.13)
*/
+ if (vptr->rx.filled < 4)
+ return;
- vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
-
- vptr->wol_opts = vptr->options.wol_opts;
- vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-
- vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-
- dev->irq = pdev->irq;
- dev->netdev_ops = &velocity_netdev_ops;
- dev->ethtool_ops = &velocity_ethtool_ops;
-
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- dev->features |= NETIF_F_SG;
-#endif
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX;
-
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
- dev->features |= NETIF_F_IP_CSUM;
-
- ret = register_netdev(dev);
- if (ret < 0)
- goto err_iounmap;
-
- if (!velocity_get_link(dev)) {
- netif_carrier_off(dev);
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- }
-
- velocity_print_info(vptr);
- pci_set_drvdata(pdev, dev);
-
- /* and leave the chip powered down */
-
- pci_set_power_state(pdev, PCI_D3hot);
-#ifdef CONFIG_PM
- {
- unsigned long flags;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_add(&vptr->list, &velocity_dev_list);
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
- }
-#endif
- velocity_nics++;
-out:
- return ret;
-
-err_iounmap:
- iounmap(regs);
-err_release_res:
- pci_release_regions(pdev);
-err_disable:
- pci_disable_device(pdev);
-err_free_dev:
- free_netdev(dev);
- goto out;
-}
-
-/**
- * velocity_print_info - per driver data
- * @vptr: velocity
- *
- * Print per driver data as the kernel driver finds Velocity
- * hardware
- */
-
-static void __devinit velocity_print_info(struct velocity_info *vptr)
-{
- struct net_device *dev = vptr->dev;
-
- printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-}
-
-/**
- * velocity_init_info - init private data
- * @pdev: PCI device
- * @vptr: Velocity info
- * @info: Board type
- *
- * Set up the initial velocity_info struct for the device that has been
- * discovered.
- */
-
-static void __devinit velocity_init_info(struct pci_dev *pdev,
- struct velocity_info *vptr,
- const struct velocity_info_tbl *info)
-{
- memset(vptr, 0, sizeof(struct velocity_info));
-
- vptr->pdev = pdev;
- vptr->chip_id = info->chip_id;
- vptr->tx.numq = info->txqueue;
- vptr->multicast_limit = MCAM_SIZE;
- spin_lock_init(&vptr->lock);
- INIT_LIST_HEAD(&vptr->list);
-}
-
-/**
- * velocity_get_pci_info - retrieve PCI info for device
- * @vptr: velocity device
- * @pdev: PCI device it matches
- *
- * Retrieve the PCI configuration space data that interests us from
- * the kernel PCI layer
- */
-
-static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
-{
- vptr->rev_id = pdev->revision;
-
- pci_set_master(pdev);
-
- vptr->ioaddr = pci_resource_start(pdev, 0);
- vptr->memaddr = pci_resource_start(pdev, 1);
-
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #0 is not an I/O resource, aborting.\n");
- return -EINVAL;
- }
-
- if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #1 is an I/O resource, aborting.\n");
- return -EINVAL;
- }
+ wmb();
- if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
- dev_err(&pdev->dev, "region #1 is too small.\n");
- return -EINVAL;
+ unusable = vptr->rx.filled & 0x0003;
+ dirty = vptr->rx.dirty - unusable;
+ for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
+ dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+ vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
}
- vptr->pdev = pdev;
- return 0;
+ writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
+ vptr->rx.filled = unusable;
}
/**
@@ -1113,7 +1415,6 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
* Allocate PCI mapped DMA rings for the receive and transmit layer
* to use.
*/
-
static int velocity_init_dma_rings(struct velocity_info *vptr)
{
struct velocity_opt *opt = &vptr->options;
@@ -1154,46 +1455,50 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
return 0;
}
+static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
+{
+ vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
+}
+
/**
- * velocity_free_dma_rings - free PCI ring pointers
- * @vptr: Velocity to free from
+ * velocity_alloc_rx_buf - allocate aligned receive buffer
+ * @vptr: velocity
+ * @idx: ring index
*
- * Clean up the PCI ring buffers allocated to this velocity.
+ * Allocate a new full sized buffer for the reception of a frame and
+ * map it into PCI space for the hardware to use. The hardware
+ * requires *64* byte alignment of the buffer which makes life
+ * less fun than would be ideal.
*/
-
-static void velocity_free_dma_rings(struct velocity_info *vptr)
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
{
- const int size = vptr->options.numrx * sizeof(struct rx_desc) +
- vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
-
- pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
-}
+ struct rx_desc *rd = &(vptr->rx.ring[idx]);
+ struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-static void velocity_give_many_rx_descs(struct velocity_info *vptr)
-{
- struct mac_regs __iomem *regs = vptr->mac_regs;
- int avail, dirty, unusable;
+ rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
+ if (rd_info->skb == NULL)
+ return -ENOMEM;
/*
- * RD number must be equal to 4X per hardware spec
- * (programming guide rev 1.20, p.13)
+ * Do the gymnastics to get the buffer head for data at
+ * 64byte alignment.
*/
- if (vptr->rx.filled < 4)
- return;
-
- wmb();
+ skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
+ rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
+ vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
- unusable = vptr->rx.filled & 0x0003;
- dirty = vptr->rx.dirty - unusable;
- for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
- dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
- vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
- }
+ /*
+ * Fill in the descriptor to match
+ */
- writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
- vptr->rx.filled = unusable;
+ *((u32 *) & (rd->rdesc0)) = 0;
+ rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
+ rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+ rd->pa_high = 0;
+ return 0;
}
+
static int velocity_rx_refill(struct velocity_info *vptr)
{
int dirty = vptr->rx.dirty, done = 0;
@@ -1221,42 +1526,6 @@ static int velocity_rx_refill(struct velocity_info *vptr)
return done;
}
-static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
-{
- vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
-}
-
-/**
- * velocity_init_rd_ring - set up receive ring
- * @vptr: velocity to configure
- *
- * Allocate and set up the receive buffers for each ring slot and
- * assign them to the network adapter.
- */
-
-static int velocity_init_rd_ring(struct velocity_info *vptr)
-{
- int ret = -ENOMEM;
-
- vptr->rx.info = kcalloc(vptr->options.numrx,
- sizeof(struct velocity_rd_info), GFP_KERNEL);
- if (!vptr->rx.info)
- goto out;
-
- velocity_init_rx_ring_indexes(vptr);
-
- if (velocity_rx_refill(vptr) != vptr->options.numrx) {
- VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
- "%s: failed to allocate RX buffer.\n", vptr->dev->name);
- velocity_free_rd_ring(vptr);
- goto out;
- }
-
- ret = 0;
-out:
- return ret;
-}
-
/**
* velocity_free_rd_ring - free receive ring
* @vptr: velocity to clean up
@@ -1264,7 +1533,6 @@ out:
* Free the receive buffers for each ring slot and any
* attached socket buffers that need to go away.
*/
-
static void velocity_free_rd_ring(struct velocity_info *vptr)
{
int i;
@@ -1292,6 +1560,38 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
vptr->rx.info = NULL;
}
+
+
+/**
+ * velocity_init_rd_ring - set up receive ring
+ * @vptr: velocity to configure
+ *
+ * Allocate and set up the receive buffers for each ring slot and
+ * assign them to the network adapter.
+ */
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+ int ret = -ENOMEM;
+
+ vptr->rx.info = kcalloc(vptr->options.numrx,
+ sizeof(struct velocity_rd_info), GFP_KERNEL);
+ if (!vptr->rx.info)
+ goto out;
+
+ velocity_init_rx_ring_indexes(vptr);
+
+ if (velocity_rx_refill(vptr) != vptr->options.numrx) {
+ VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s: failed to allocate RX buffer.\n", vptr->dev->name);
+ velocity_free_rd_ring(vptr);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
/**
* velocity_init_td_ring - set up transmit ring
* @vptr: velocity
@@ -1300,7 +1600,6 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
* Returns zero on success or a negative posix errno code for
* failure.
*/
-
static int velocity_init_td_ring(struct velocity_info *vptr)
{
dma_addr_t curr;
@@ -1314,7 +1613,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
sizeof(struct velocity_td_info),
GFP_KERNEL);
if (!vptr->tx.infos[j]) {
- while(--j >= 0)
+ while (--j >= 0)
kfree(vptr->tx.infos[j]);
return -ENOMEM;
}
@@ -1324,22 +1623,92 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
return 0;
}
+/**
+ * velocity_free_dma_rings - free PCI ring pointers
+ * @vptr: Velocity to free from
+ *
+ * Clean up the PCI ring buffers allocated to this velocity.
+ */
+static void velocity_free_dma_rings(struct velocity_info *vptr)
+{
+ const int size = vptr->options.numrx * sizeof(struct rx_desc) +
+ vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
+
+ pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
+}
+
+
+static int velocity_init_rings(struct velocity_info *vptr, int mtu)
+{
+ int ret;
+
+ velocity_set_rxbufsize(vptr, mtu);
+
+ ret = velocity_init_dma_rings(vptr);
+ if (ret < 0)
+ goto out;
+
+ ret = velocity_init_rd_ring(vptr);
+ if (ret < 0)
+ goto err_free_dma_rings_0;
+
+ ret = velocity_init_td_ring(vptr);
+ if (ret < 0)
+ goto err_free_rd_ring_1;
+out:
+ return ret;
+
+err_free_rd_ring_1:
+ velocity_free_rd_ring(vptr);
+err_free_dma_rings_0:
+ velocity_free_dma_rings(vptr);
+ goto out;
+}
+
+/**
+ * velocity_free_tx_buf - free transmit buffer
+ * @vptr: velocity
+ * @tdinfo: buffer
+ *
+ * Release an transmit buffer. If the buffer was preallocated then
+ * recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+ struct sk_buff *skb = tdinfo->skb;
+ int i;
+ int pktlen;
+
+ /*
+ * Don't unmap the pre-allocated tx_bufs
+ */
+ if (tdinfo->skb_dma) {
+
+ pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
+ for (i = 0; i < tdinfo->nskb_dma; i++) {
+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[i] = 0;
+ }
+ }
+ dev_kfree_skb_irq(skb);
+ tdinfo->skb = NULL;
+}
+
+
/*
* FIXME: could we merge this with velocity_free_tx_buf ?
*/
-
static void velocity_free_td_ring_entry(struct velocity_info *vptr,
int q, int n)
{
- struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]);
+ struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]);
int i;
if (td_info == NULL)
return;
if (td_info->skb) {
- for (i = 0; i < td_info->nskb_dma; i++)
- {
+ for (i = 0; i < td_info->nskb_dma; i++) {
if (td_info->skb_dma[i]) {
pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
td_info->skb->len, PCI_DMA_TODEVICE);
@@ -1358,7 +1727,6 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
* Free up the transmit ring for this particular velocity adapter.
* We free the ring contents but not the ring itself.
*/
-
static void velocity_free_td_ring(struct velocity_info *vptr)
{
int i, j;
@@ -1366,70 +1734,175 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
for (j = 0; j < vptr->tx.numq; j++) {
if (vptr->tx.infos[j] == NULL)
continue;
- for (i = 0; i < vptr->options.numtx; i++) {
+ for (i = 0; i < vptr->options.numtx; i++)
velocity_free_td_ring_entry(vptr, j, i);
- }
kfree(vptr->tx.infos[j]);
vptr->tx.infos[j] = NULL;
}
}
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+ velocity_free_td_ring(vptr);
+ velocity_free_rd_ring(vptr);
+ velocity_free_dma_rings(vptr);
+}
+
/**
- * velocity_rx_srv - service RX interrupt
+ * velocity_error - handle error from controller
* @vptr: velocity
- * @status: adapter status (unused)
+ * @status: card status
+ *
+ * Process an error report from the hardware and attempt to recover
+ * the card itself. At the moment we cannot recover from some
+ * theoretically impossible errors but this could be fixed using
+ * the pci_device_failed logic to bounce the hardware
*
- * Walk the receive ring of the velocity adapter and remove
- * any received packets from the receive queue. Hand the ring
- * slots back to the adapter for reuse.
*/
-
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
+static void velocity_error(struct velocity_info *vptr, int status)
{
- struct net_device_stats *stats = &vptr->dev->stats;
- int rd_curr = vptr->rx.curr;
- int works = 0;
- do {
- struct rx_desc *rd = vptr->rx.ring + rd_curr;
+ if (status & ISR_TXSTLI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
- if (!vptr->rx.info[rd_curr].skb)
- break;
+ printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
+ BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
+ writew(TRDCSR_RUN, &regs->TDCSRClr);
+ netif_stop_queue(vptr->dev);
- if (rd->rdesc0.len & OWNED_BY_NIC)
- break;
+ /* FIXME: port over the pci_device_failed code and use it
+ here */
+ }
- rmb();
+ if (status & ISR_SRCI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int linked;
+
+ if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ vptr->mii_status = check_connection_type(regs);
+ /*
+ * If it is a 3119, disable frame bursting in
+ * halfduplex mode and enable it in fullduplex
+ * mode
+ */
+ if (vptr->rev_id < REV_ID_VT3216_A0) {
+ if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ else
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ }
+ /*
+ * Only enable CD heart beat counter in 10HD mode
+ */
+ if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ else
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+ }
/*
- * Don't drop CE or RL error frame although RXOK is off
+ * Get link status from PHYSR0
*/
- if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
- if (velocity_receive_frame(vptr, rd_curr) < 0)
- stats->rx_dropped++;
- } else {
- if (rd->rdesc0.RSR & RSR_CRC)
- stats->rx_crc_errors++;
- if (rd->rdesc0.RSR & RSR_FAE)
- stats->rx_frame_errors++;
+ linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
- stats->rx_dropped++;
+ if (linked) {
+ vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
+ } else {
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
- rd->size |= RX_INTEN;
+ velocity_print_link_status(vptr);
+ enable_flow_control_ability(vptr);
- rd_curr++;
- if (rd_curr >= vptr->options.numrx)
- rd_curr = 0;
- } while (++works <= 15);
+ /*
+ * Re-enable auto-polling because SRCI will disable
+ * auto-polling
+ */
- vptr->rx.curr = rd_curr;
+ enable_mii_autopoll(regs);
- if ((works > 0) && (velocity_rx_refill(vptr) > 0))
- velocity_give_many_rx_descs(vptr);
+ if (vptr->mii_status & VELOCITY_LINK_FAIL)
+ netif_stop_queue(vptr->dev);
+ else
+ netif_wake_queue(vptr->dev);
- VAR_USED(stats);
+ };
+ if (status & ISR_MIBFI)
+ velocity_update_hw_mibs(vptr);
+ if (status & ISR_LSTEI)
+ mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ * tx_srv - transmit interrupt service
+ * @vptr; Velocity
+ * @status:
+ *
+ * Scan the queues looking for transmitted packets that
+ * we can complete and clean up. Update any statistics as
+ * necessary/
+ */
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+ struct tx_desc *td;
+ int qnum;
+ int full = 0;
+ int idx;
+ int works = 0;
+ struct velocity_td_info *tdinfo;
+ struct net_device_stats *stats = &vptr->dev->stats;
+
+ for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
+ for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
+ idx = (idx + 1) % vptr->options.numtx) {
+
+ /*
+ * Get Tx Descriptor
+ */
+ td = &(vptr->tx.rings[qnum][idx]);
+ tdinfo = &(vptr->tx.infos[qnum][idx]);
+
+ if (td->tdesc0.len & OWNED_BY_NIC)
+ break;
+
+ if ((works++ > 15))
+ break;
+
+ if (td->tdesc0.TSR & TSR0_TERR) {
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ if (td->tdesc0.TSR & TSR0_CDH)
+ stats->tx_heartbeat_errors++;
+ if (td->tdesc0.TSR & TSR0_CRS)
+ stats->tx_carrier_errors++;
+ if (td->tdesc0.TSR & TSR0_ABT)
+ stats->tx_aborted_errors++;
+ if (td->tdesc0.TSR & TSR0_OWC)
+ stats->tx_window_errors++;
+ } else {
+ stats->tx_packets++;
+ stats->tx_bytes += tdinfo->skb->len;
+ }
+ velocity_free_tx_buf(vptr, tdinfo);
+ vptr->tx.used[qnum]--;
+ }
+ vptr->tx.tail[qnum] = idx;
+
+ if (AVAIL_TD(vptr, qnum) < 1)
+ full = 1;
+ }
+ /*
+ * Look to see if we should kick the transmit network
+ * layer for more work.
+ */
+ if (netif_queue_stopped(vptr->dev) && (full == 0)
+ && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+ netif_wake_queue(vptr->dev);
+ }
return works;
}
@@ -1441,7 +1914,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
* Process the status bits for the received packet and determine
* if the checksum was computed and verified by the hardware
*/
-
static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
@@ -1450,9 +1922,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
if (rd->rdesc1.CSM & CSM_IPOK) {
if ((rd->rdesc1.CSM & CSM_TCPKT) ||
(rd->rdesc1.CSM & CSM_UDPKT)) {
- if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+ if (!(rd->rdesc1.CSM & CSM_TUPOK))
return;
- }
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -1509,6 +1980,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
}
}
+
/**
* velocity_receive_frame - received packet processor
* @vptr: velocity we are handling
@@ -1517,7 +1989,6 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
* A packet has arrived. We process the packet and if appropriate
* pass the frame up the network stack
*/
-
static int velocity_receive_frame(struct velocity_info *vptr, int idx)
{
void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
@@ -1579,320 +2050,118 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
return 0;
}
-/**
- * velocity_alloc_rx_buf - allocate aligned receive buffer
- * @vptr: velocity
- * @idx: ring index
- *
- * Allocate a new full sized buffer for the reception of a frame and
- * map it into PCI space for the hardware to use. The hardware
- * requires *64* byte alignment of the buffer which makes life
- * less fun than would be ideal.
- */
-
-static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
-{
- struct rx_desc *rd = &(vptr->rx.ring[idx]);
- struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-
- rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
- if (rd_info->skb == NULL)
- return -ENOMEM;
-
- /*
- * Do the gymnastics to get the buffer head for data at
- * 64byte alignment.
- */
- skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
- rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
- vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
-
- /*
- * Fill in the descriptor to match
- */
-
- *((u32 *) & (rd->rdesc0)) = 0;
- rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
- rd->pa_low = cpu_to_le32(rd_info->skb_dma);
- rd->pa_high = 0;
- return 0;
-}
/**
- * tx_srv - transmit interrupt service
- * @vptr; Velocity
- * @status:
+ * velocity_rx_srv - service RX interrupt
+ * @vptr: velocity
+ * @status: adapter status (unused)
*
- * Scan the queues looking for transmitted packets that
- * we can complete and clean up. Update any statistics as
- * necessary/
+ * Walk the receive ring of the velocity adapter and remove
+ * any received packets from the receive queue. Hand the ring
+ * slots back to the adapter for reuse.
*/
-
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
{
- struct tx_desc *td;
- int qnum;
- int full = 0;
- int idx;
- int works = 0;
- struct velocity_td_info *tdinfo;
struct net_device_stats *stats = &vptr->dev->stats;
+ int rd_curr = vptr->rx.curr;
+ int works = 0;
- for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
- for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
- idx = (idx + 1) % vptr->options.numtx) {
+ do {
+ struct rx_desc *rd = vptr->rx.ring + rd_curr;
- /*
- * Get Tx Descriptor
- */
- td = &(vptr->tx.rings[qnum][idx]);
- tdinfo = &(vptr->tx.infos[qnum][idx]);
+ if (!vptr->rx.info[rd_curr].skb)
+ break;
- if (td->tdesc0.len & OWNED_BY_NIC)
- break;
+ if (rd->rdesc0.len & OWNED_BY_NIC)
+ break;
- if ((works++ > 15))
- break;
+ rmb();
- if (td->tdesc0.TSR & TSR0_TERR) {
- stats->tx_errors++;
- stats->tx_dropped++;
- if (td->tdesc0.TSR & TSR0_CDH)
- stats->tx_heartbeat_errors++;
- if (td->tdesc0.TSR & TSR0_CRS)
- stats->tx_carrier_errors++;
- if (td->tdesc0.TSR & TSR0_ABT)
- stats->tx_aborted_errors++;
- if (td->tdesc0.TSR & TSR0_OWC)
- stats->tx_window_errors++;
- } else {
- stats->tx_packets++;
- stats->tx_bytes += tdinfo->skb->len;
- }
- velocity_free_tx_buf(vptr, tdinfo);
- vptr->tx.used[qnum]--;
- }
- vptr->tx.tail[qnum] = idx;
+ /*
+ * Don't drop CE or RL error frame although RXOK is off
+ */
+ if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
+ if (velocity_receive_frame(vptr, rd_curr) < 0)
+ stats->rx_dropped++;
+ } else {
+ if (rd->rdesc0.RSR & RSR_CRC)
+ stats->rx_crc_errors++;
+ if (rd->rdesc0.RSR & RSR_FAE)
+ stats->rx_frame_errors++;
- if (AVAIL_TD(vptr, qnum) < 1) {
- full = 1;
+ stats->rx_dropped++;
}
- }
- /*
- * Look to see if we should kick the transmit network
- * layer for more work.
- */
- if (netif_queue_stopped(vptr->dev) && (full == 0)
- && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
- netif_wake_queue(vptr->dev);
- }
- return works;
-}
-/**
- * velocity_print_link_status - link status reporting
- * @vptr: velocity to report on
- *
- * Turn the link status of the velocity card into a kernel log
- * description of the new link state, detailing speed and duplex
- * status
- */
+ rd->size |= RX_INTEN;
-static void velocity_print_link_status(struct velocity_info *vptr)
-{
+ rd_curr++;
+ if (rd_curr >= vptr->options.numrx)
+ rd_curr = 0;
+ } while (++works <= 15);
- if (vptr->mii_status & VELOCITY_LINK_FAIL) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
- } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+ vptr->rx.curr = rd_curr;
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
- else if (vptr->mii_status & VELOCITY_SPEED_100)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+ if ((works > 0) && (velocity_rx_refill(vptr) > 0))
+ velocity_give_many_rx_descs(vptr);
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
- } else {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_100_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
- break;
- case SPD_DPX_100_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
- break;
- case SPD_DPX_10_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
- break;
- case SPD_DPX_10_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
- break;
- default:
- break;
- }
- }
+ VAR_USED(stats);
+ return works;
}
+
/**
- * velocity_error - handle error from controller
- * @vptr: velocity
- * @status: card status
- *
- * Process an error report from the hardware and attempt to recover
- * the card itself. At the moment we cannot recover from some
- * theoretically impossible errors but this could be fixed using
- * the pci_device_failed logic to bounce the hardware
+ * velocity_intr - interrupt callback
+ * @irq: interrupt number
+ * @dev_instance: interrupting device
*
+ * Called whenever an interrupt is generated by the velocity
+ * adapter IRQ line. We may not be the source of the interrupt
+ * and need to identify initially if we are, and if not exit as
+ * efficiently as possible.
*/
-
-static void velocity_error(struct velocity_info *vptr, int status)
+static irqreturn_t velocity_intr(int irq, void *dev_instance)
{
+ struct net_device *dev = dev_instance;
+ struct velocity_info *vptr = netdev_priv(dev);
+ u32 isr_status;
+ int max_count = 0;
- if (status & ISR_TXSTLI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
- BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
- writew(TRDCSR_RUN, &regs->TDCSRClr);
- netif_stop_queue(vptr->dev);
+ spin_lock(&vptr->lock);
+ isr_status = mac_read_isr(vptr->mac_regs);
- /* FIXME: port over the pci_device_failed code and use it
- here */
+ /* Not us ? */
+ if (isr_status == 0) {
+ spin_unlock(&vptr->lock);
+ return IRQ_NONE;
}
- if (status & ISR_SRCI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int linked;
-
- if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- vptr->mii_status = check_connection_type(regs);
-
- /*
- * If it is a 3119, disable frame bursting in
- * halfduplex mode and enable it in fullduplex
- * mode
- */
- if (vptr->rev_id < REV_ID_VT3216_A0) {
- if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- else
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- }
- /*
- * Only enable CD heart beat counter in 10HD mode
- */
- if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
- BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
- } else {
- BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
- }
- }
- /*
- * Get link status from PHYSR0
- */
- linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
-
- if (linked) {
- vptr->mii_status &= ~VELOCITY_LINK_FAIL;
- netif_carrier_on(vptr->dev);
- } else {
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- netif_carrier_off(vptr->dev);
- }
-
- velocity_print_link_status(vptr);
- enable_flow_control_ability(vptr);
-
- /*
- * Re-enable auto-polling because SRCI will disable
- * auto-polling
- */
-
- enable_mii_autopoll(regs);
-
- if (vptr->mii_status & VELOCITY_LINK_FAIL)
- netif_stop_queue(vptr->dev);
- else
- netif_wake_queue(vptr->dev);
-
- };
- if (status & ISR_MIBFI)
- velocity_update_hw_mibs(vptr);
- if (status & ISR_LSTEI)
- mac_rx_queue_wake(vptr->mac_regs);
-}
-
-/**
- * velocity_free_tx_buf - free transmit buffer
- * @vptr: velocity
- * @tdinfo: buffer
- *
- * Release an transmit buffer. If the buffer was preallocated then
- * recycle it, if not then unmap the buffer.
- */
-
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
-{
- struct sk_buff *skb = tdinfo->skb;
- int i;
- int pktlen;
+ mac_disable_int(vptr->mac_regs);
/*
- * Don't unmap the pre-allocated tx_bufs
+ * Keep processing the ISR until we have completed
+ * processing and the isr_status becomes zero
*/
- if (tdinfo->skb_dma) {
- pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
- for (i = 0; i < tdinfo->nskb_dma; i++) {
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
-#else
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
-#endif
- tdinfo->skb_dma[i] = 0;
+ while (isr_status != 0) {
+ mac_write_isr(vptr->mac_regs, isr_status);
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+ velocity_error(vptr, isr_status);
+ if (isr_status & (ISR_PRXI | ISR_PPRXI))
+ max_count += velocity_rx_srv(vptr, isr_status);
+ if (isr_status & (ISR_PTXI | ISR_PPTXI))
+ max_count += velocity_tx_srv(vptr, isr_status);
+ isr_status = mac_read_isr(vptr->mac_regs);
+ if (max_count > vptr->options.int_works) {
+ printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+ dev->name);
+ max_count = 0;
}
}
- dev_kfree_skb_irq(skb);
- tdinfo->skb = NULL;
-}
-
-static int velocity_init_rings(struct velocity_info *vptr, int mtu)
-{
- int ret;
-
- velocity_set_rxbufsize(vptr, mtu);
-
- ret = velocity_init_dma_rings(vptr);
- if (ret < 0)
- goto out;
-
- ret = velocity_init_rd_ring(vptr);
- if (ret < 0)
- goto err_free_dma_rings_0;
-
- ret = velocity_init_td_ring(vptr);
- if (ret < 0)
- goto err_free_rd_ring_1;
-out:
- return ret;
-
-err_free_rd_ring_1:
- velocity_free_rd_ring(vptr);
-err_free_dma_rings_0:
- velocity_free_dma_rings(vptr);
- goto out;
-}
+ spin_unlock(&vptr->lock);
+ mac_enable_int(vptr->mac_regs);
+ return IRQ_HANDLED;
-static void velocity_free_rings(struct velocity_info *vptr)
-{
- velocity_free_td_ring(vptr);
- velocity_free_rd_ring(vptr);
- velocity_free_dma_rings(vptr);
}
/**
@@ -1905,7 +2174,6 @@ static void velocity_free_rings(struct velocity_info *vptr)
* All the ring allocation and set up is done on open for this
* adapter to minimise memory usage when inactive
*/
-
static int velocity_open(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -1939,6 +2207,24 @@ out:
}
/**
+ * velocity_shutdown - shut down the chip
+ * @vptr: velocity to deactivate
+ *
+ * Shuts down the internal operations of the velocity and
+ * disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ mac_disable_int(regs);
+ writel(CR0_STOP, &regs->CR0Set);
+ writew(0xFFFF, &regs->TDCSRClr);
+ writeb(0xFF, &regs->RDCSRClr);
+ safe_disable_mii_autopoll(regs);
+ mac_clear_isr(regs);
+}
+
+/**
* velocity_change_mtu - MTU change callback
* @dev: network device
* @new_mtu: desired MTU
@@ -1947,7 +2233,6 @@ out:
* this interface. It gets called on a change by the network layer.
* Return zero for success or negative posix error code.
*/
-
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2021,22 +2306,127 @@ out_0:
}
/**
- * velocity_shutdown - shut down the chip
- * @vptr: velocity to deactivate
+ * velocity_mii_ioctl - MII ioctl handler
+ * @dev: network device
+ * @ifr: the ifreq block for the ioctl
+ * @cmd: the command
*
- * Shuts down the internal operations of the velocity and
- * disables interrupts, autopolling, transmit and receive
+ * Process MII requests made via ioctl from the network layer. These
+ * are used by tools like kudzu to interrogate the link state of the
+ * hardware
*/
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ unsigned long flags;
+ struct mii_ioctl_data *miidata = if_mii(ifr);
+ int err;
-static void velocity_shutdown(struct velocity_info *vptr)
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+ return -ETIMEDOUT;
+ break;
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ spin_lock_irqsave(&vptr->lock, flags);
+ err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ check_connection_type(vptr->mac_regs);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+/**
+ * velocity_ioctl - ioctl entry point
+ * @dev: network device
+ * @rq: interface request ioctl
+ * @cmd: command code
+ *
+ * Called when the user issues an ioctl request to the network
+ * device in question. The velocity interface supports MII.
+ */
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- mac_disable_int(regs);
- writel(CR0_STOP, &regs->CR0Set);
- writew(0xFFFF, &regs->TDCSRClr);
- writeb(0xFF, &regs->RDCSRClr);
- safe_disable_mii_autopoll(regs);
- mac_clear_isr(regs);
+ struct velocity_info *vptr = netdev_priv(dev);
+ int ret;
+
+ /* If we are asked for information and the device is power
+ saving then we need to bring the device back up to talk to it */
+
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D0);
+
+ switch (cmd) {
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ case SIOCSMIIREG: /* Write to MII PHY register. */
+ ret = velocity_mii_ioctl(dev, rq, cmd);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+
+ return ret;
+}
+
+/**
+ * velocity_get_status - statistics callback
+ * @dev: network device
+ *
+ * Callback from the network layer to allow driver statistics
+ * to be resynchronized with hardware collected state. In the
+ * case of the velocity we need to pull the MIB counters from
+ * the hardware into the counters before letting the network
+ * layer display them.
+ */
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ /* If the hardware is down, don't touch MII */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ spin_lock_irq(&vptr->lock);
+ velocity_update_hw_mibs(vptr);
+ spin_unlock_irq(&vptr->lock);
+
+ dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+ dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+ dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+// unsigned long rx_dropped; /* no space in linux buffers */
+ dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+ /* detailed rx_errors: */
+// unsigned long rx_length_errors;
+// unsigned long rx_over_errors; /* receiver ring buff overflow */
+ dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+// unsigned long rx_frame_errors; /* recv'd frame alignment error */
+// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+// unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+// unsigned long tx_fifo_errors;
+
+ return &dev->stats;
}
/**
@@ -2046,7 +2436,6 @@ static void velocity_shutdown(struct velocity_info *vptr)
* Callback from the network layer when the velocity is being
* deactivated by the network layer
*/
-
static int velocity_close(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2076,7 +2465,6 @@ static int velocity_close(struct net_device *dev)
* Called by the networ layer to request a packet is queued to
* the velocity. Returns zero on success.
*/
-
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2088,20 +2476,12 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
__le16 len;
int index;
-
if (skb_padto(skb, ETH_ZLEN))
goto out;
pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
len = cpu_to_le16(pktlen);
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
- kfree_skb(skb);
- return 0;
- }
-#endif
-
spin_lock_irqsave(&vptr->lock, flags);
index = vptr->tx.curr[qnum];
@@ -2111,59 +2491,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->tdesc1.TCR = TCR0_TIC;
td_ptr->td_buf[0].size &= ~TD_QUEUE;
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 0) {
- int nfrags = skb_shinfo(skb)->nr_frags;
- tdinfo->skb = skb;
- if (nfrags > 6) {
- skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
- tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.len = len;
- td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->tx.buf[0].pa_high = 0;
- td_ptr->tx.buf[0].size = len; /* queue is 0 anyway */
- tdinfo->nskb_dma = 1;
- } else {
- int i = 0;
- tdinfo->nskb_dma = 0;
- tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
-
- td_ptr->tdesc0.len = len;
-
- /* FIXME: support 48bit DMA later */
- td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
- td_ptr->tx.buf[i].pa_high = 0;
- td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb));
-
- for (i = 0; i < nfrags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- void *addr = (void *)page_address(frag->page) + frag->page_offset;
-
- tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
-
- td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
- td_ptr->tx.buf[i + 1].pa_high = 0;
- td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size);
- }
- tdinfo->nskb_dma = i - 1;
- }
+ /*
+ * Map the linear network buffer into PCI space and
+ * add it to the transmit ring.
+ */
+ tdinfo->skb = skb;
+ tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+ td_ptr->tdesc0.len = len;
+ td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+ td_ptr->td_buf[0].pa_high = 0;
+ td_ptr->td_buf[0].size = len;
+ tdinfo->nskb_dma = 1;
- } else
-#endif
- {
- /*
- * Map the linear network buffer into PCI space and
- * add it to the transmit ring.
- */
- tdinfo->skb = skb;
- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
- td_ptr->tdesc0.len = len;
- td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].size = len;
- tdinfo->nskb_dma = 1;
- }
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
@@ -2206,782 +2545,533 @@ out:
return NETDEV_TX_OK;
}
+
+static const struct net_device_ops velocity_netdev_ops = {
+ .ndo_open = velocity_open,
+ .ndo_stop = velocity_close,
+ .ndo_start_xmit = velocity_xmit,
+ .ndo_get_stats = velocity_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_multicast_list = velocity_set_multi,
+ .ndo_change_mtu = velocity_change_mtu,
+ .ndo_do_ioctl = velocity_ioctl,
+ .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
+ .ndo_vlan_rx_register = velocity_vlan_rx_register,
+};
+
/**
- * velocity_intr - interrupt callback
- * @irq: interrupt number
- * @dev_instance: interrupting device
+ * velocity_init_info - init private data
+ * @pdev: PCI device
+ * @vptr: Velocity info
+ * @info: Board type
*
- * Called whenever an interrupt is generated by the velocity
- * adapter IRQ line. We may not be the source of the interrupt
- * and need to identify initially if we are, and if not exit as
- * efficiently as possible.
+ * Set up the initial velocity_info struct for the device that has been
+ * discovered.
*/
-
-static irqreturn_t velocity_intr(int irq, void *dev_instance)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
- struct net_device *dev = dev_instance;
- struct velocity_info *vptr = netdev_priv(dev);
- u32 isr_status;
- int max_count = 0;
-
-
- spin_lock(&vptr->lock);
- isr_status = mac_read_isr(vptr->mac_regs);
-
- /* Not us ? */
- if (isr_status == 0) {
- spin_unlock(&vptr->lock);
- return IRQ_NONE;
- }
-
- mac_disable_int(vptr->mac_regs);
-
- /*
- * Keep processing the ISR until we have completed
- * processing and the isr_status becomes zero
- */
-
- while (isr_status != 0) {
- mac_write_isr(vptr->mac_regs, isr_status);
- if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
- velocity_error(vptr, isr_status);
- if (isr_status & (ISR_PRXI | ISR_PPRXI))
- max_count += velocity_rx_srv(vptr, isr_status);
- if (isr_status & (ISR_PTXI | ISR_PPTXI))
- max_count += velocity_tx_srv(vptr, isr_status);
- isr_status = mac_read_isr(vptr->mac_regs);
- if (max_count > vptr->options.int_works)
- {
- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
- dev->name);
- max_count = 0;
- }
- }
- spin_unlock(&vptr->lock);
- mac_enable_int(vptr->mac_regs);
- return IRQ_HANDLED;
+ memset(vptr, 0, sizeof(struct velocity_info));
+ vptr->pdev = pdev;
+ vptr->chip_id = info->chip_id;
+ vptr->tx.numq = info->txqueue;
+ vptr->multicast_limit = MCAM_SIZE;
+ spin_lock_init(&vptr->lock);
+ INIT_LIST_HEAD(&vptr->list);
}
-
/**
- * velocity_set_multi - filter list change callback
- * @dev: network device
+ * velocity_get_pci_info - retrieve PCI info for device
+ * @vptr: velocity device
+ * @pdev: PCI device it matches
*
- * Called by the network layer when the filter lists need to change
- * for a velocity adapter. Reload the CAMs with the new address
- * filter ruleset.
+ * Retrieve the PCI configuration space data that interests us from
+ * the kernel PCI layer
*/
-
-static void velocity_set_multi(struct net_device *dev)
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u8 rx_mode;
- int i;
- struct dev_mc_list *mclist;
+ vptr->rev_id = pdev->revision;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
- } else if ((dev->mc_count > vptr->multicast_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB);
- } else {
- int offset = MCAM_SIZE - vptr->multicast_limit;
- mac_get_cam_mask(regs, vptr->mCAMmask);
+ pci_set_master(pdev);
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- mac_set_cam(regs, i + offset, mclist->dmi_addr);
- vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
- }
+ vptr->ioaddr = pci_resource_start(pdev, 0);
+ vptr->memaddr = pci_resource_start(pdev, 1);
- mac_set_cam_mask(regs, vptr->mCAMmask);
- rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
+ return -EINVAL;
}
- if (dev->mtu > 1500)
- rx_mode |= RCR_AL;
- BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
+ return -EINVAL;
+ }
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
+ return -EINVAL;
+ }
+ vptr->pdev = pdev;
+
+ return 0;
}
/**
- * velocity_get_status - statistics callback
- * @dev: network device
+ * velocity_print_info - per driver data
+ * @vptr: velocity
*
- * Callback from the network layer to allow driver statistics
- * to be resynchronized with hardware collected state. In the
- * case of the velocity we need to pull the MIB counters from
- * the hardware into the counters before letting the network
- * layer display them.
+ * Print per driver data as the kernel driver finds Velocity
+ * hardware
*/
-
-static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+static void __devinit velocity_print_info(struct velocity_info *vptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
-
- /* If the hardware is down, don't touch MII */
- if(!netif_running(dev))
- return &dev->stats;
-
- spin_lock_irq(&vptr->lock);
- velocity_update_hw_mibs(vptr);
- spin_unlock_irq(&vptr->lock);
-
- dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
- dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
- dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
-
-// unsigned long rx_dropped; /* no space in linux buffers */
- dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
- /* detailed rx_errors: */
-// unsigned long rx_length_errors;
-// unsigned long rx_over_errors; /* receiver ring buff overflow */
- dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
-// unsigned long rx_frame_errors; /* recv'd frame alignment error */
-// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
-// unsigned long rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
-// unsigned long tx_fifo_errors;
+ struct net_device *dev = vptr->dev;
- return &dev->stats;
+ printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+ printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ dev->name,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
-
-/**
- * velocity_ioctl - ioctl entry point
- * @dev: network device
- * @rq: interface request ioctl
- * @cmd: command code
- *
- * Called when the user issues an ioctl request to the network
- * device in question. The velocity interface supports MII.
- */
-
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 velocity_get_link(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
- int ret;
-
- /* If we are asked for information and the device is power
- saving then we need to bring the device back up to talk to it */
-
- if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D0);
-
- switch (cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- case SIOCGMIIREG: /* Read MII PHY register. */
- case SIOCSMIIREG: /* Write to MII PHY register. */
- ret = velocity_mii_ioctl(dev, rq, cmd);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
- if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-
- return ret;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
-/*
- * Definition for our device driver. The PCI layer interface
- * uses this to handle all our card discover and plugging
- */
-
-static struct pci_driver velocity_driver = {
- .name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = __devexit_p(velocity_remove1),
-#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
-#endif
-};
/**
- * velocity_init_module - load time function
+ * velocity_found1 - set up discovered velocity card
+ * @pdev: PCI device
+ * @ent: PCI device table entry that matched
*
- * Called when the velocity module is loaded. The PCI driver
- * is registered with the PCI layer, and in turn will call
- * the probe functions for each velocity adapter installed
- * in the system.
+ * Configure a discovered adapter from scratch. Return a negative
+ * errno error code on failure paths.
*/
-
-static int __init velocity_init_module(void)
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ret;
+ static int first = 1;
+ struct net_device *dev;
+ int i;
+ const char *drv_string;
+ const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
+ struct velocity_info *vptr;
+ struct mac_regs __iomem *regs;
+ int ret = -ENOMEM;
- velocity_register_notifier();
- ret = pci_register_driver(&velocity_driver);
- if (ret < 0)
- velocity_unregister_notifier();
- return ret;
-}
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
+ if (velocity_nics >= MAX_UNITS) {
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
+ return -ENODEV;
+ }
-/**
- * velocity_cleanup - module unload
- *
- * When the velocity hardware is unloaded this function is called.
- * It will clean up the notifiers and the unregister the PCI
- * driver interface for this hardware. This in turn cleans up
- * all discovered interfaces before returning from the function
- */
+ dev = alloc_etherdev(sizeof(struct velocity_info));
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
+ goto out;
+ }
-static void __exit velocity_cleanup_module(void)
-{
- velocity_unregister_notifier();
- pci_unregister_driver(&velocity_driver);
-}
+ /* Chain it all together */
-module_init(velocity_init_module);
-module_exit(velocity_cleanup_module);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ vptr = netdev_priv(dev);
-/*
- * MII access , media link mode setting functions
- */
+ if (first) {
+ printk(KERN_INFO "%s Ver. %s\n",
+ VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+ printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+ printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+ first = 0;
+ }
+ velocity_init_info(pdev, vptr, info);
-/**
- * mii_init - set up MII
- * @vptr: velocity adapter
- * @mii_status: links tatus
- *
- * Set up the PHY for the current link state.
- */
+ vptr->dev = dev;
-static void mii_init(struct velocity_info *vptr, u32 mii_status)
-{
- u16 BMCR;
+ dev->irq = pdev->irq;
- switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
- case PHYID_CICADA_CS8201:
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- /*
- * Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
- * legacy-forced issue.
- */
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- /*
- * Turn on Link/Activity LED enable bit for CIS8201
- */
- MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
- break;
- case PHYID_VT3216_32BIT:
- case PHYID_VT3216_64BIT:
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- /*
- * Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
- * legacy-forced issue
- */
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- break;
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err_free_dev;
- case PHYID_MARVELL_1000:
- case PHYID_MARVELL_1000S:
- /*
- * Assert CRS on Transmit
- */
- MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- break;
- default:
- ;
- }
- velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
- if (BMCR & BMCR_ISO) {
- BMCR &= ~BMCR_ISO;
- velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+ ret = velocity_get_pci_info(vptr, pdev);
+ if (ret < 0) {
+ /* error message already printed */
+ goto err_disable;
}
-}
-/**
- * safe_disable_mii_autopoll - autopoll off
- * @regs: velocity registers
- *
- * Turn off the autopoll and wait for it to disable on the chip
- */
-
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- u16 ww;
-
- /* turn off MAUTO */
- writeb(0, &regs->MIICR);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
+ ret = pci_request_regions(pdev, VELOCITY_NAME);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "No PCI resources.\n");
+ goto err_disable;
}
-}
-
-/**
- * enable_mii_autopoll - turn on autopolling
- * @regs: velocity registers
- *
- * Enable the MII link status autopoll feature on the Velocity
- * hardware. Wait for it to enable.
- */
-static void enable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- int ii;
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
+ if (regs == NULL) {
+ ret = -EIO;
+ goto err_release_res;
+ }
- writeb(0, &(regs->MIICR));
- writeb(MIIADR_SWMPL, &regs->MIIADR);
+ vptr->mac_regs = regs;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ mac_wol_reset(regs);
- writeb(MIICR_MAUTO, &regs->MIICR);
+ dev->base_addr = vptr->ioaddr;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(&regs->PAR[i]);
-}
-/**
- * velocity_mii_read - read MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: buffer for received data
- *
- * Perform a single read of an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ drv_string = dev_driver_string(&pdev->dev);
-static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
-{
- u16 ww;
+ velocity_get_options(&vptr->options, velocity_nics, drv_string);
/*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
+ * Mask out the options cannot be set to the chip
*/
- safe_disable_mii_autopoll(regs);
-
- writeb(index, &regs->MIIADR);
- BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+ vptr->options.flags &= info->flags;
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- if (!(readb(&regs->MIICR) & MIICR_RCMD))
- break;
- }
+ /*
+ * Enable the chip specified capbilities
+ */
- *data = readw(&regs->MIIDATA);
+ vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ vptr->wol_opts = vptr->options.wol_opts;
+ vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-/**
- * velocity_mii_write - write MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: 16bit data for the MII register
- *
- * Perform a single write to an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
-{
- u16 ww;
+ dev->irq = pdev->irq;
+ dev->netdev_ops = &velocity_netdev_ops;
+ dev->ethtool_ops = &velocity_ethtool_ops;
- /*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
- */
- safe_disable_mii_autopoll(regs);
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_HW_VLAN_RX;
- /* MII reg offset */
- writeb(mii_addr, &regs->MIIADR);
- /* set MII data */
- writew(data, &regs->MIIDATA);
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+ dev->features |= NETIF_F_IP_CSUM;
- /* turn on MIICR_WCMD */
- BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+ ret = register_netdev(dev);
+ if (ret < 0)
+ goto err_iounmap;
- /* W_MAX_TIMEOUT is the timeout period */
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(5);
- if (!(readb(&regs->MIICR) & MIICR_WCMD))
- break;
+ if (!velocity_get_link(dev)) {
+ netif_carrier_off(dev);
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
}
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ velocity_print_info(vptr);
+ pci_set_drvdata(pdev, dev);
-/**
- * velocity_get_opt_media_mode - get media selection
- * @vptr: velocity adapter
- *
- * Get the media mode stored in EEPROM or module options and load
- * mii_status accordingly. The requested link state information
- * is also returned.
- */
+ /* and leave the chip powered down */
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
-{
- u32 status = 0;
+ pci_set_power_state(pdev, PCI_D3hot);
+#ifdef CONFIG_PM
+ {
+ unsigned long flags;
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_AUTO:
- status = VELOCITY_AUTONEG_ENABLE;
- break;
- case SPD_DPX_100_FULL:
- status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_10_FULL:
- status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_100_HALF:
- status = VELOCITY_SPEED_100;
- break;
- case SPD_DPX_10_HALF:
- status = VELOCITY_SPEED_10;
- break;
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_add(&vptr->list, &velocity_dev_list);
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
- vptr->mii_status = status;
- return status;
-}
-
-/**
- * mii_set_auto_on - autonegotiate on
- * @vptr: velocity
- *
- * Enable autonegotation on this interface
- */
+#endif
+ velocity_nics++;
+out:
+ return ret;
-static void mii_set_auto_on(struct velocity_info *vptr)
-{
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
- MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
- else
- MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+err_iounmap:
+ iounmap(regs);
+err_release_res:
+ pci_release_regions(pdev);
+err_disable:
+ pci_disable_device(pdev);
+err_free_dev:
+ free_netdev(dev);
+ goto out;
}
-/*
-static void mii_set_auto_off(struct velocity_info * vptr)
-{
- MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-*/
-
+#ifdef CONFIG_PM
/**
- * set_mii_flow_control - flow control setup
- * @vptr: velocity interface
+ * wol_calc_crc - WOL CRC
+ * @pattern: data pattern
+ * @mask_pattern: mask
*
- * Set up the flow control on this interface according to
- * the supplied user/eeprom options.
+ * Compute the wake on lan crc hashes for the packet header
+ * we are interested in.
*/
-
-static void set_mii_flow_control(struct velocity_info *vptr)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
{
- /*Enable or Disable PAUSE in ANAR */
- switch (vptr->options.flow_cntl) {
- case FLOW_CNTL_TX:
- MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ u16 crc = 0xFFFF;
+ u8 mask;
+ int i, j;
- case FLOW_CNTL_RX:
- MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ for (i = 0; i < size; i++) {
+ mask = mask_pattern[i];
- case FLOW_CNTL_TX_RX:
- MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ /* Skip this loop if the mask equals to zero */
+ if (mask == 0x00)
+ continue;
- case FLOW_CNTL_DISABLE:
- MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
- default:
- break;
+ for (j = 0; j < 8; j++) {
+ if ((mask & 0x01) == 0) {
+ mask >>= 1;
+ continue;
+ }
+ mask >>= 1;
+ crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
+ }
}
+ /* Finally, invert the result once to get the correct data */
+ crc = ~crc;
+ return bitrev32(crc) >> 16;
}
/**
- * velocity_set_media_mode - set media mode
- * @mii_status: old MII link state
+ * velocity_set_wol - set up for wake on lan
+ * @vptr: velocity to set WOL status on
*
- * Check the media link state and configure the flow control
- * PHY and also velocity hardware setup accordingly. In particular
- * we need to set up CD polling and frame bursting.
+ * Set a card up for wake on lan either by unicast or by
+ * ARP packet.
+ *
+ * FIXME: check static buffer is safe here
*/
-
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+static int velocity_set_wol(struct velocity_info *vptr)
{
- u32 curr_status;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ static u8 buf[256];
+ int i;
- vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
- curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+ static u32 mask_pattern[2][4] = {
+ {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
+ {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
+ };
- /* Set mii link status */
- set_mii_flow_control(vptr);
+ writew(0xFFFF, &regs->WOLCRClr);
+ writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+ writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
/*
- Check if new status is consisent with current status
- if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
- || (mii_status==curr_status)) {
- vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
- vptr->mii_status=check_connection_type(vptr->mac_regs);
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
- return 0;
- }
+ if (vptr->wol_opts & VELOCITY_WOL_PHY)
+ writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
*/
- if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
- MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
- }
+ if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+ writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- /*
- * If connection type is AUTO
- */
- if (mii_status & VELOCITY_AUTONEG_ENABLE) {
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
- /* clear force MAC mode bit */
- BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
- /* set duplex mode of MAC according to duplex mode of MII */
- MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
- MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+ if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+ struct arp_packet *arp = (struct arp_packet *) buf;
+ u16 crc;
+ memset(buf, 0, sizeof(struct arp_packet) + 7);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- } else {
- u16 ANAR;
- u8 CHIPGCR;
+ for (i = 0; i < 4; i++)
+ writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
- /*
- * 1. if it's 3119, disable frame bursting in halfduplex mode
- * and enable it in fullduplex mode
- * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
- * 3. only enable CD heart beat counter in 10HD mode
- */
+ arp->type = htons(ETH_P_ARP);
+ arp->ar_op = htons(1);
- /* set force MAC mode bit */
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ memcpy(arp->ar_tip, vptr->ip_addr, 4);
- CHIPGCR = readb(&regs->CHIPGCR);
- CHIPGCR &= ~CHIPGCR_FCGMII;
+ crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
+ (u8 *) & mask_pattern[0][0]);
- if (mii_status & VELOCITY_DUPLEX_FULL) {
- CHIPGCR |= CHIPGCR_FCFDX;
- writeb(CHIPGCR, &regs->CHIPGCR);
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- } else {
- CHIPGCR &= ~CHIPGCR_FCFDX;
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
- writeb(CHIPGCR, &regs->CHIPGCR);
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- }
+ writew(crc, &regs->PatternCRC[0]);
+ writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+ }
+
+ BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+ BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+ writew(0x0FFF, &regs->WOLSRClr);
+
+ if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+ }
- if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
- BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
- } else {
- BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
- }
- /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
- velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
- ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
- if (mii_status & VELOCITY_SPEED_100) {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_TXFD;
- else
- ANAR |= ANAR_TX;
- } else {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_10FD;
- else
- ANAR |= ANAR_10;
- }
- velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ {
+ u8 GCR;
+ GCR = readb(&regs->CHIPGCR);
+ GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+ writeb(GCR, &regs->CHIPGCR);
}
- /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
- /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
- return VELOCITY_LINK_CHANGE;
+
+ BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+ /* Turn on SWPTAG just before entering power mode */
+ BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+ /* Go to bed ..... */
+ BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ return 0;
}
/**
- * mii_check_media_mode - check media state
- * @regs: velocity registers
+ * velocity_save_context - save registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Check the current MII status and determine the link status
- * accordingly
+ * Retrieve the current configuration from the velocity hardware
+ * and stash it in the context structure, for use by the context
+ * restore functions. This allows us to save things we need across
+ * power down states
*/
-
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
{
- u32 status = 0;
- u16 ANAR;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u16 i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
- status |= VELOCITY_LINK_FAIL;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
- else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
- status |= (VELOCITY_SPEED_1000);
- else {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if (ANAR & ANAR_TXFD)
- status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
- else if (ANAR & ANAR_TX)
- status |= VELOCITY_SPEED_100;
- else if (ANAR & ANAR_10FD)
- status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
- else
- status |= (VELOCITY_SPEED_10);
- }
+ for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
- == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
- if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
- }
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- return status;
}
-static u32 check_connection_type(struct mac_regs __iomem * regs)
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
{
- u32 status = 0;
- u8 PHYSR0;
- u16 ANAR;
- PHYSR0 = readb(&regs->PHYSR0);
-
- /*
- if (!(PHYSR0 & PHYSR0_LINKGD))
- status|=VELOCITY_LINK_FAIL;
- */
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
- if (PHYSR0 & PHYSR0_FDPX)
- status |= VELOCITY_DUPLEX_FULL;
+ if (!netif_running(vptr->dev))
+ return 0;
- if (PHYSR0 & PHYSR0_SPDG)
- status |= VELOCITY_SPEED_1000;
- else if (PHYSR0 & PHYSR0_SPD10)
- status |= VELOCITY_SPEED_10;
- else
- status |= VELOCITY_SPEED_100;
+ netif_device_detach(vptr->dev);
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
- == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
- if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
+ spin_lock_irqsave(&vptr->lock, flags);
+ pci_save_state(pdev);
+#ifdef ETHTOOL_GWOL
+ if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+ velocity_get_ip(vptr);
+ velocity_save_context(vptr, &vptr->context);
+ velocity_shutdown(vptr);
+ velocity_set_wol(vptr);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ velocity_save_context(vptr, &vptr->context);
+ velocity_shutdown(vptr);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
-
- return status;
+#else
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ return 0;
}
/**
- * enable_flow_control_ability - flow control
- * @vptr: veloity to configure
+ * velocity_restore_context - restore registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Set up flow control according to the flow control options
- * determined by the eeprom/configuration.
+ * Reload the register configuration from the velocity context
+ * created by velocity_save_context.
*/
-
-static void enable_flow_control_ability(struct velocity_info *vptr)
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- switch (vptr->options.flow_cntl) {
+ /* Just skip cr0 */
+ for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+ /* Clear */
+ writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+ /* Set */
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+ }
- case FLOW_CNTL_DEFAULT:
- if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- case FLOW_CNTL_TX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+}
- case FLOW_CNTL_RX:
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+static int velocity_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
+ int i;
- case FLOW_CNTL_TX_RX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- break;
+ if (!netif_running(vptr->dev))
+ return 0;
- case FLOW_CNTL_DISABLE:
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, 0, 0);
+ pci_restore_state(pdev);
- default:
- break;
+ mac_wol_reset(vptr->mac_regs);
+
+ spin_lock_irqsave(&vptr->lock, flags);
+ velocity_restore_context(vptr, &vptr->context);
+ velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+ mac_disable_int(vptr->mac_regs);
+
+ velocity_tx_srv(vptr, 0);
+
+ for (i = 0; i < vptr->tx.numq; i++) {
+ if (vptr->tx.used[i])
+ mac_tx_queue_wake(vptr->mac_regs, i);
}
+ mac_enable_int(vptr->mac_regs);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ netif_device_attach(vptr->dev);
+
+ return 0;
}
+#endif
+
+/*
+ * Definition for our device driver. The PCI layer interface
+ * uses this to handle all our card discover and plugging
+ */
+static struct pci_driver velocity_driver = {
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+ .probe = velocity_found1,
+ .remove = __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+ .suspend = velocity_suspend,
+ .resume = velocity_resume,
+#endif
+};
/**
@@ -2991,7 +3081,6 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
* Called before an ethtool operation. We need to make sure the
* chip is out of D3 state before we poke at it.
*/
-
static int velocity_ethtool_up(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3007,7 +3096,6 @@ static int velocity_ethtool_up(struct net_device *dev)
* Called after an ethtool operation. Restore the chip back to D3
* state if it isn't running.
*/
-
static void velocity_ethtool_down(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3018,7 +3106,7 @@ static void velocity_ethtool_down(struct net_device *dev)
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
@@ -3072,13 +3160,6 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
return ret;
}
-static u32 velocity_get_link(struct net_device *dev)
-{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
-}
-
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3157,338 +3238,86 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.complete = velocity_ethtool_down
};
-/**
- * velocity_mii_ioctl - MII ioctl handler
- * @dev: network device
- * @ifr: the ifreq block for the ioctl
- * @cmd: the command
- *
- * Process MII requests made via ioctl from the network layer. These
- * are used by tools like kudzu to interrogate the link state of the
- * hardware
- */
-
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+#ifdef CONFIG_PM
+#ifdef CONFIG_INET
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct velocity_info *vptr;
unsigned long flags;
- struct mii_ioctl_data *miidata = if_mii(ifr);
- int err;
- switch (cmd) {
- case SIOCGMIIPHY:
- miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
- break;
- case SIOCGMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
- return -ETIMEDOUT;
- break;
- case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- spin_lock_irqsave(&vptr->lock, flags);
- err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
- spin_unlock_irqrestore(&vptr->lock, flags);
- check_connection_type(vptr->mac_regs);
- if(err)
- return err;
- break;
- default:
- return -EOPNOTSUPP;
+ if (dev_net(dev) != &init_net)
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_for_each_entry(vptr, &velocity_dev_list, list) {
+ if (vptr->dev == dev) {
+ velocity_get_ip(vptr);
+ break;
+ }
}
- return 0;
-}
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-#ifdef CONFIG_PM
+ return NOTIFY_DONE;
+}
+#endif /* CONFIG_INET */
+#endif /* CONFIG_PM */
-/**
- * velocity_save_context - save registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Retrieve the current configuration from the velocity hardware
- * and stash it in the context structure, for use by the context
- * restore functions. This allows us to save things we need across
- * power down states
- */
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+static struct notifier_block velocity_inetaddr_notifier = {
+ .notifier_call = velocity_netdev_event,
+};
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+static void velocity_register_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u16 i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
+ register_inetaddr_notifier(&velocity_inetaddr_notifier);
}
-/**
- * velocity_restore_context - restore registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Reload the register configuration from the velocity context
- * created by velocity_save_context.
- */
-
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+static void velocity_unregister_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
-
- /* Just skip cr0 */
- for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
- /* Clear */
- writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
- /* Set */
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
-
- for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+ unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+#else
- for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
+#define velocity_register_notifier() do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
-}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */
/**
- * wol_calc_crc - WOL CRC
- * @pattern: data pattern
- * @mask_pattern: mask
+ * velocity_init_module - load time function
*
- * Compute the wake on lan crc hashes for the packet header
- * we are interested in.
+ * Called when the velocity module is loaded. The PCI driver
+ * is registered with the PCI layer, and in turn will call
+ * the probe functions for each velocity adapter installed
+ * in the system.
*/
-
-static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static int __init velocity_init_module(void)
{
- u16 crc = 0xFFFF;
- u8 mask;
- int i, j;
-
- for (i = 0; i < size; i++) {
- mask = mask_pattern[i];
-
- /* Skip this loop if the mask equals to zero */
- if (mask == 0x00)
- continue;
+ int ret;
- for (j = 0; j < 8; j++) {
- if ((mask & 0x01) == 0) {
- mask >>= 1;
- continue;
- }
- mask >>= 1;
- crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
- }
- }
- /* Finally, invert the result once to get the correct data */
- crc = ~crc;
- return bitrev32(crc) >> 16;
+ velocity_register_notifier();
+ ret = pci_register_driver(&velocity_driver);
+ if (ret < 0)
+ velocity_unregister_notifier();
+ return ret;
}
/**
- * velocity_set_wol - set up for wake on lan
- * @vptr: velocity to set WOL status on
- *
- * Set a card up for wake on lan either by unicast or by
- * ARP packet.
+ * velocity_cleanup - module unload
*
- * FIXME: check static buffer is safe here
+ * When the velocity hardware is unloaded this function is called.
+ * It will clean up the notifiers and the unregister the PCI
+ * driver interface for this hardware. This in turn cleans up
+ * all discovered interfaces before returning from the function
*/
-
-static int velocity_set_wol(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- static u8 buf[256];
- int i;
-
- static u32 mask_pattern[2][4] = {
- {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
- {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
- };
-
- writew(0xFFFF, &regs->WOLCRClr);
- writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
- writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
-
- /*
- if (vptr->wol_opts & VELOCITY_WOL_PHY)
- writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
- */
-
- if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
- writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- }
-
- if (vptr->wol_opts & VELOCITY_WOL_ARP) {
- struct arp_packet *arp = (struct arp_packet *) buf;
- u16 crc;
- memset(buf, 0, sizeof(struct arp_packet) + 7);
-
- for (i = 0; i < 4; i++)
- writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
-
- arp->type = htons(ETH_P_ARP);
- arp->ar_op = htons(1);
-
- memcpy(arp->ar_tip, vptr->ip_addr, 4);
-
- crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
- (u8 *) & mask_pattern[0][0]);
-
- writew(crc, &regs->PatternCRC[0]);
- writew(WOLCR_ARP_EN, &regs->WOLCRSet);
- }
-
- BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
- BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
-
- writew(0x0FFF, &regs->WOLSRClr);
-
- if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
- if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
- MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
-
- MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
- }
-
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
-
- {
- u8 GCR;
- GCR = readb(&regs->CHIPGCR);
- GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
- writeb(GCR, &regs->CHIPGCR);
- }
-
- BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
- /* Turn on SWPTAG just before entering power mode */
- BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
- /* Go to bed ..... */
- BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
- return 0;
-}
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- netif_device_detach(vptr->dev);
-
- spin_lock_irqsave(&vptr->lock, flags);
- pci_save_state(pdev);
-#ifdef ETHTOOL_GWOL
- if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
- velocity_get_ip(vptr);
- velocity_save_context(vptr, &vptr->context);
- velocity_shutdown(vptr);
- velocity_set_wol(vptr);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- pci_set_power_state(pdev, PCI_D3hot);
- } else {
- velocity_save_context(vptr, &vptr->context);
- velocity_shutdown(vptr);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- }
-#else
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
- spin_unlock_irqrestore(&vptr->lock, flags);
- return 0;
-}
-
-static int velocity_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
- int i;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, 0, 0);
- pci_restore_state(pdev);
-
- mac_wol_reset(vptr->mac_regs);
-
- spin_lock_irqsave(&vptr->lock, flags);
- velocity_restore_context(vptr, &vptr->context);
- velocity_init_registers(vptr, VELOCITY_INIT_WOL);
- mac_disable_int(vptr->mac_regs);
-
- velocity_tx_srv(vptr, 0);
-
- for (i = 0; i < vptr->tx.numq; i++) {
- if (vptr->tx.used[i]) {
- mac_tx_queue_wake(vptr->mac_regs, i);
- }
- }
-
- mac_enable_int(vptr->mac_regs);
- spin_unlock_irqrestore(&vptr->lock, flags);
- netif_device_attach(vptr->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_INET
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+static void __exit velocity_cleanup_module(void)
{
- struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
- struct net_device *dev = ifa->ifa_dev->dev;
- struct velocity_info *vptr;
- unsigned long flags;
-
- if (dev_net(dev) != &init_net)
- return NOTIFY_DONE;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_for_each_entry(vptr, &velocity_dev_list, list) {
- if (vptr->dev == dev) {
- velocity_get_ip(vptr);
- break;
- }
- }
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-
- return NOTIFY_DONE;
+ velocity_unregister_notifier();
+ pci_unregister_driver(&velocity_driver);
}
-#endif
-#endif
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 4cd3f6c97379..2f00c13ab502 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -96,8 +96,8 @@
* Bits in the CSM register
*/
-#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok
-#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok
+#define CSM_IPOK 0x40 //IP Checksum validation ok
+#define CSM_TUPOK 0x20 //TCP/UDP Checksum validation ok
#define CSM_FRAG 0x10 //Fragment IP datagram
#define CSM_IPKT 0x04 //Received an IP packet
#define CSM_TCPKT 0x02 //Received a TCP packet
@@ -819,7 +819,7 @@ enum velocity_owner {
* Bits in the EECSR register
*/
-#define EECSR_EMBP 0x40 /* eeprom embeded programming */
+#define EECSR_EMBP 0x40 /* eeprom embedded programming */
#define EECSR_RELOAD 0x20 /* eeprom content reload */
#define EECSR_DPM 0x10 /* eeprom direct programming */
#define EECSR_ECS 0x08 /* eeprom CS pin */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 2a6e81d5b579..a6f903f00924 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = {
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
+ .set_ufo = ethtool_op_set_ufo,
.get_link = ethtool_op_get_link,
};
@@ -1005,7 +1006,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
+ VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_F_NOTIFY_ON_EMPTY,
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 58d2551c78ed..9e94c4b0fb18 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
break;
- case 2:
- hldev->kdfc = (u8 __iomem *)(hldev->bar1 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
- case 4:
- hldev->kdfc = (u8 __iomem *)(hldev->bar2 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
default:
break;
}
@@ -831,8 +823,6 @@ vxge_hw_device_initialize(
sizeof(struct vxge_hw_device_config));
hldev->bar0 = attr->bar0;
- hldev->bar1 = attr->bar1;
- hldev->bar2 = attr->bar2;
hldev->pdev = attr->pdev;
hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index afbdf6f4d224..224acea771ed 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{
* @major_revision: PCI Device major revision
* @minor_revision: PCI Device minor revision
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: Physical device handle
* @config: Confguration passed by the LL driver at initialization
* @link_state: Link state
@@ -698,8 +696,6 @@ struct __vxge_hw_device {
u8 major_revision;
u8 minor_revision;
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct net_device *ndev;
struct vxge_hw_device_config config;
@@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info {
/**
* struct vxge_hw_device_attr - Device memory spaces.
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: PCI device object.
*
- * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device
+ * Device memory spaces. Includes configuration, BAR0 etc. per device
* mapped memories. Also, includes a pointer to OS-specific PCI device object.
*/
struct vxge_hw_device_attr {
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct vxge_hw_uld_cbs uld_callbacks;
};
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index 6034497536a4..335140d2834a 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
if (ring->vlgrp && ext_info->vlan &&
(ring->vlan_tag_strip ==
VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
- vlan_gro_receive(&ring->napi, ring->vlgrp,
+ vlan_gro_receive(ring->napi_p, ring->vlgrp,
ext_info->vlan, skb);
else
- napi_gro_receive(&ring->napi, skb);
+ napi_gro_receive(ring->napi_p, skb);
} else {
if (ring->vlgrp && vlan &&
(ring->vlan_tag_strip ==
@@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
pkt_length = dma_sizes;
+ pkt_length -= ETH_FCS_LEN;
+
vxge_debug_rx(VXGE_TRACE,
"%s: %s:%d Packet Length = %d",
ring->ndev->name, __func__, __LINE__, pkt_length);
@@ -817,7 +819,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
u64 dma_pointer;
struct vxge_tx_priv *txdl_priv = NULL;
struct __vxge_hw_fifo *fifo_hw;
- u32 max_mss = 0x0;
int offload_type;
unsigned long flags = 0;
int vpath_no = 0;
@@ -969,10 +970,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
int mss = vxge_tcp_mss(skb);
if (mss) {
- max_mss = dev->mtu + ETH_HLEN -
- VXGE_HW_TCPIP_HEADER_MAX_SIZE;
- if (mss > max_mss)
- mss = max_mss;
vxge_debug_tx(VXGE_TRACE,
"%s: %s:%d mss = %d",
dev->name, __func__, __LINE__, mss);
@@ -1000,7 +997,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
VXGE_COMPLETE_VPATH_TX(fifo);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
dev->name, __func__, __LINE__);
- return 0;
+ return NETDEV_TX_OK;
_exit0:
vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
@@ -1024,7 +1021,7 @@ _exit2:
spin_unlock_irqrestore(&fifo->tx_lock, flags);
VXGE_COMPLETE_VPATH_TX(fifo);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2137,16 +2134,16 @@ int vxge_open_vpaths(struct vxgedev *vdev)
*/
static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
{
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id;
- struct vxgedev *vdev;
struct net_device *dev;
+ struct __vxge_hw_device *hldev;
u64 reason;
enum vxge_hw_status status;
+ struct vxgedev *vdev = (struct vxgedev *) dev_id;;
vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- dev = hldev->ndev;
- vdev = netdev_priv(dev);
+ dev = vdev->ndev;
+ hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
if (pci_channel_offline(vdev->pdev))
return IRQ_NONE;
@@ -2417,15 +2414,13 @@ static void vxge_rem_isr(struct vxgedev *vdev)
#endif
if (vdev->config.intr_type == INTA) {
synchronize_irq(vdev->pdev->irq);
- free_irq(vdev->pdev->irq, hldev);
+ free_irq(vdev->pdev->irq, vdev);
}
}
static int vxge_add_isr(struct vxgedev *vdev)
{
int ret = 0;
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
#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;
@@ -2579,7 +2574,7 @@ INTA_MODE:
if (vdev->config.intr_type == INTA) {
ret = request_irq((int) vdev->pdev->irq,
vxge_isr_napi,
- IRQF_SHARED, vdev->desc[0], hldev);
+ IRQF_SHARED, vdev->desc[0], vdev);
if (ret) {
vxge_debug_init(VXGE_ERR,
"%s %s-%d: ISR registration failed",
@@ -2712,11 +2707,15 @@ vxge_open(struct net_device *dev)
netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
vdev->config.napi_weight);
napi_enable(&vdev->napi);
+ for (i = 0; i < vdev->no_of_vpath; i++)
+ vdev->vpaths[i].ring.napi_p = &vdev->napi;
} else {
for (i = 0; i < vdev->no_of_vpath; i++) {
netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
vxge_poll_msix, vdev->config.napi_weight);
napi_enable(&vdev->vpaths[i].ring.napi);
+ vdev->vpaths[i].ring.napi_p =
+ &vdev->vpaths[i].ring.napi;
}
}
@@ -2890,6 +2889,9 @@ int do_vxge_close(struct net_device *dev, int do_io)
vdev = (struct vxgedev *)netdev_priv(dev);
hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ if (unlikely(!is_vxge_card_up(vdev)))
+ return 0;
+
/* If vxge_handle_crit_err task is executing,
* wait till it completes. */
while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
@@ -3954,6 +3956,9 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
netif_device_detach(netdev);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
if (netif_running(netdev)) {
/* Bring down the card, while avoiding PCI I/O */
do_vxge_close(netdev, 0);
@@ -4152,18 +4157,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
attr.bar0,
(unsigned long long)pci_resource_start(pdev, 0));
- attr.bar1 = pci_ioremap_bar(pdev, 2);
- if (!attr.bar1) {
- vxge_debug_init(VXGE_ERR,
- "%s : cannot remap io memory bar2", __func__);
- ret = -ENODEV;
- goto _exit3;
- }
- vxge_debug_ll_config(VXGE_TRACE,
- "pci ioremap bar1: %p:0x%llx",
- attr.bar1,
- (unsigned long long)pci_resource_start(pdev, 2));
-
status = vxge_hw_device_hw_info_get(attr.bar0,
&ll_config.device_hw_info);
if (status != VXGE_HW_OK) {
@@ -4171,17 +4164,17 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: Reading of hardware info failed."
"Please try upgrading the firmware.", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
if (ll_config.device_hw_info.fw_version.major !=
- VXGE_DRIVER_VERSION_MAJOR) {
+ VXGE_DRIVER_FW_VERSION_MAJOR) {
vxge_debug_init(VXGE_ERR,
- "FW Ver.(maj): %d not driver's expected version: %d",
- ll_config.device_hw_info.fw_version.major,
- VXGE_DRIVER_VERSION_MAJOR);
+ "%s: Incorrect firmware version."
+ "Please upgrade the firmware to version 1.x.x",
+ VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vpath_mask = ll_config.device_hw_info.vpath_mask;
@@ -4189,7 +4182,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_TRACE,
"%s: No vpaths available in device", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_debug_ll_config(VXGE_TRACE,
@@ -4222,7 +4215,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_ERR,
"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
ret = 0;
- goto _exit4;
+ goto _exit3;
}
/* Setting driver callbacks */
@@ -4235,7 +4228,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_ERR,
"Failed to initialize device (%d)", status);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
@@ -4260,7 +4253,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
&vdev)) {
ret = -EINVAL;
- goto _exit5;
+ goto _exit4;
}
vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
@@ -4271,7 +4264,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
hldev->ndev = vdev->ndev;
vdev->mtu = VXGE_HW_DEFAULT_MTU;
vdev->bar0 = attr.bar0;
- vdev->bar1 = attr.bar1;
vdev->max_vpath_supported = max_vpath_supported;
vdev->no_of_vpath = no_of_vpath;
@@ -4336,6 +4328,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
ll_config.device_hw_info.fw_version.version,
ll_config.device_hw_info.fw_date.date);
+ if (new_device) {
+ switch (ll_config.device_hw_info.function_mode) {
+ case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_SRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ }
+ }
+
vxge_print_parm(vdev, vpath_mask);
/* Store the fw version for ethttool option */
@@ -4353,7 +4366,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: mac_addr_list : memory allocation failed",
vdev->ndev->name);
ret = -EPERM;
- goto _exit6;
+ goto _exit5;
}
macaddr = (u8 *)&entry->macaddr;
memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4361,6 +4374,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vdev->vpaths[i].mac_addr_cnt = 1;
}
+ kfree(device_config);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
vdev->ndev->name, __func__, __LINE__);
@@ -4370,16 +4384,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
return 0;
-_exit6:
+_exit5:
for (i = 0; i < vdev->no_of_vpath; i++)
vxge_free_mac_add_list(&vdev->vpaths[i]);
vxge_device_unregister(hldev);
-_exit5:
+_exit4:
pci_disable_sriov(pdev);
vxge_hw_device_terminate(hldev);
-_exit4:
- iounmap(attr.bar1);
_exit3:
iounmap(attr.bar0);
_exit2:
@@ -4438,7 +4450,6 @@ vxge_remove(struct pci_dev *pdev)
kfree(vdev->vpaths);
iounmap(vdev->bar0);
- iounmap(vdev->bar1);
pci_disable_sriov(pdev);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 9704b2bd4320..18d824c3ab93 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -21,7 +21,7 @@
#define VXGE_DRIVER_NAME "vxge"
#define VXGE_DRIVER_VENDOR "Neterion, Inc"
-#define VXGE_DRIVER_VERSION_MAJOR 0
+#define VXGE_DRIVER_FW_VERSION_MAJOR 1
#define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
@@ -260,6 +260,7 @@ struct vxge_ring {
int gro_enable;
struct napi_struct napi;
+ struct napi_struct *napi_p;
#define VXGE_MAX_MAC_ADDR_COUNT 30
@@ -363,7 +364,6 @@ struct vxgedev {
struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
void __iomem *bar0;
- void __iomem *bar1;
struct vxge_sw_stats stats;
int mtu;
/* Below variables are used for vpath selection to transmit a packet */
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 10f4da32929f..9a3b823e08d4 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63)
/*0x01e18*/ u64 xmac_gen_err_mask;
/*0x01e20*/ u64 xmac_gen_err_alarm;
-/*0x01e28*/ u64 xmac_link_err_port_reg[2];
+/*0x01e28*/ u64 xmac_link_err_port0_reg;
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11)
@@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
vxge_mBIT(47)
-/*0x01e30*/ u64 xmac_link_err_port_mask[2];
-/*0x01e38*/ u64 xmac_link_err_port_alarm[2];
+/*0x01e30*/ u64 xmac_link_err_port0_mask;
+/*0x01e38*/ u64 xmac_link_err_port0_alarm;
+/*0x01e40*/ u64 xmac_link_err_port1_reg;
+/*0x01e48*/ u64 xmac_link_err_port1_mask;
+/*0x01e50*/ u64 xmac_link_err_port1_alarm;
/*0x01e58*/ u64 xgxs_gen_err_reg;
#define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63)
/*0x01e60*/ u64 xgxs_gen_err_mask;
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 7567a1140d07..8260b91fd795 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -35,8 +35,6 @@
VXGE_HW_HEADER_VLAN_SIZE + \
VXGE_HW_HEADER_SNAP_SIZE)
-#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64)
-
/* 32bit alignments */
#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2
#define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 82786ffb7dd9..580c6eb077b9 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -18,6 +18,6 @@
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "0"
#define VXGE_VERSION_FIX "4"
-#define VXGE_VERSION_BUILD "17795"
+#define VXGE_VERSION_BUILD "17899"
#define VXGE_VERSION_FOR "k"
#endif
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index f525f9fe74db..4ae9bd297cc2 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
free_packet:
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* Get Ethernet-style interface statistics.
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 2fa275a58f9d..8526b6d1ee4d 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
ret = 0;
if (!skb || !dev)
- return(0);
+ return NETDEV_TX_OK;
dlp = netdev_priv(dev);
@@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
/* Alan Cox recommends always returning 0, and always freeing the packet */
/* experience suggest a slightly more conservative approach */
- if (!ret)
+ if (ret == NETDEV_TX_OK)
{
dev_kfree_skb(skb);
netif_wake_queue(dev);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 8face5db8f32..e81946d98543 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (dscc4_tx_quiescent(dpriv, dev))
dscc4_do_tx(dpriv, dev);
- return 0;
+ return NETDEV_TX_OK;
}
static int dscc4_close(struct net_device *dev)
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 25c9ef6a1815..20a1237a3d74 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name)
*/
break;
}
-
- case NET_RX_CN_LOW:
- {
- dbg(DBG_ASS, "%s: Receive Low Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_MOD:
- {
- dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_HIGH:
- {
- dbg(DBG_ASS, "%s: Receive High Congestion\n", name);
- break;
- }
-
case NET_RX_DROP:
{
dbg(DBG_ASS, "%s: Received packet dropped\n", name);
@@ -2313,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dbg(DBG_ASS,
"Tried to transmit but no carrier on card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/* Drop it if it's too big! MTU failure ? */
@@ -2322,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
LEN_TX_BUFFER);
dev_kfree_skb(skb);
dev->stats.tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2356,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dbg(DBG_ASS, "Tx queue overflow card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2373,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
fst_q_work_item(&fst_work_txq, card->card_no);
tasklet_schedule(&fst_tx_task);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index bfa0161a02d3..52438c76bf8a 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
GFP_ATOMIC)) {
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_put(skb, pad);
memset(skb->data + len, 0, pad);
@@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_compressed++;
skb->dev = pvc->frad;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline void fr_log_dlci_active(pvc_device *pvc)
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 45b1822c962d..d1492ae5d30a 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev)
lmc_softc_t *sc = dev_to_sc(dev);
u32 flag;
int entry;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
unsigned long flags;
lmc_trace(dev, "lmc_start_xmit in");
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index d14e95a08d66..85c02a2ec2e7 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -463,7 +463,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, p );
spin_unlock( &nl->lock );
netif_start_queue( dev );
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -483,7 +483,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, dev );
spin_unlock( &nl->lock );
- return 0;
+ return NETDEV_TX_OK;
}
#endif /* CONFIG_SBNI_MULTILINE */
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index e4ad7b6b52eb..03b76adbe5f0 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock(&port->lock);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d67e208ab375..1047920e742c 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR "%s: xmit call when iface is down\n",
dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
switch (skb->data[0]) {
@@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
case 0x02: /* Disconnect request .. do nothing - hang up ?? */
err = lapb_disconnect_request(dev);
if (err != LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
default:
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_pull(skb, 1); /* Remove control byte */
/*
@@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK) {
printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 2538825d1c66..ea7b29034aab 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -58,6 +58,7 @@
*/
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
@@ -501,15 +502,12 @@ void i2400ms_remove(struct sdio_func *func)
d_fnend(3, dev, "SDIO func %p\n", func);
}
-enum {
- I2400MS_INTEL_VID = 0x89,
-};
-
static
const struct sdio_device_id i2400ms_sdio_ids[] = {
- /* Intel: i2400m WiMAX over SDIO */
- { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) },
- { }, /* end: all zeroes */
+ /* Intel: i2400m WiMAX (iwmc3200) over SDIO */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) },
+ { /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5bc00db21b24..ca7a8a31d0b9 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -428,10 +428,12 @@ config RTL8187
Micronet SP907GK V5
Encore ENUWI-G2
Trendnet TEW-424UB
- ASUS P5B Deluxe
+ ASUS P5B Deluxe/P5K Premium motherboards
Toshiba Satellite Pro series of laptops
Asus Wireless Link
- Linksys WUSB54GC-EU
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
Thanks to Realtek for their support!
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 2b9e379994a1..5695911bc602 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
rx_status.band = IEEE80211_BAND_2GHZ;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
}
entry = (++priv->cur_rx) % priv->rx_ring_size;
@@ -1963,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- ieee80211_stop_queues(dev);
- adm8211_stop(dev);
- }
-
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -1978,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
static int adm8211_resume(struct pci_dev *pdev)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- adm8211_start(dev);
- ieee80211_wake_queues(dev);
- }
-
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index c70604f0329e..c150c4858576 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (!skb) {
airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return 0;
+ return NETDEV_TX_OK;
}
npacks = skb_queue_len (&ai->txq);
@@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
return NETDEV_TX_BUSY;
}
skb_queue_tail (&ai->txq, skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
set_bit(FLAG_PENDING_XMIT, &ai->flags);
mpi_send_packet (dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_end_xmit11(struct net_device *dev) {
@@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit11(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_read_stats(struct net_device *dev)
@@ -5918,20 +5918,19 @@ static int airo_set_essid(struct net_device *dev,
readSsidRid(local, &SSID_rid);
/* Check if we asked for `any' */
- if(dwrq->flags == 0) {
+ if (dwrq->flags == 0) {
/* Just send an empty SSID list */
memset(&SSID_rid, 0, sizeof(SSID_rid));
} else {
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG ;
- }
+
/* Check if index is valid */
- if((index < 0) || (index >= 4)) {
+ if (index >= ARRAY_SIZE(SSID_rid.ssids))
return -EINVAL;
- }
/* Set the SSID */
memset(SSID_rid.ssids[index].ssid, 0,
@@ -6819,7 +6818,7 @@ static int airo_set_txpow(struct net_device *dev,
return -EINVAL;
}
clear_bit (FLAG_RADIO_OFF, &local->flags);
- for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+ for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
if (v == cap_rid.txPowerLevels[i]) {
readConfigRid(local, 1);
local->config.txPower = v;
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index d84caf198a23..f96c634e2d35 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
ARLAN_DEBUG_ENTRY("arlan_mac_addr");
return -EINVAL;
- if (!netif_running(dev))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
arlan_process_interrupt(dev);
ARLAN_DEBUG_EXIT("arlan_tx");
- return 0;
+ return NETDEV_TX_OK;
bad_end:
arlan_process_interrupt(dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 4efbdbe6d6bf..13303fa34734 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param)
at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
priv->rx_skb->len, priv->rx_skb->data_len);
- ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
/* Use a new skb for the next receive */
priv->rx_skb = NULL;
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index bb97981fb248..e6c3ee3e0581 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_NUM_MAX_BA_RETRY 5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum ar9170_tid_state {
+ AR9170_TID_STATE_INVALID,
+ AR9170_TID_STATE_SHUTDOWN,
+ AR9170_TID_STATE_PROGRESS,
+ AR9170_TID_STATE_COMPLETE,
+};
+
+struct ar9170_sta_tid {
+ struct list_head list;
+ struct sk_buff_head queue;
+ u8 addr[ETH_ALEN];
+ u16 ssn;
+ u16 tid;
+ enum ar9170_tid_state state;
+ bool active;
+ u8 retry;
+};
+
#define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8
+#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff
+#define AR9170_NUM_TX_STATUS 128
+#define AR9170_NUM_TX_AGG_MAX 30
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
@@ -187,14 +228,25 @@ struct ar9170 {
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor;
+ /* tx ampdu */
+ struct sk_buff_head tx_status_ampdu;
+ spinlock_t tx_ampdu_list_lock;
+ struct list_head tx_ampdu_list;
+ unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
+
+ /* (cached) HW A-MPDU settings */
+ u8 global_ampdu_density;
+ u8 global_ampdu_factor;
};
struct ar9170_sta_info {
+ struct ar9170_sta_tid agg[AR9170_NUM_TID];
+ unsigned int ampdu_max_len;
};
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 9d38cf60a0db..85a1452a7c3c 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_ht;
+module_param_named(ht, modparam_ht, bool, S_IRUGO);
+MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
+
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
- .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
+#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb)))
+
+#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags,
+ ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
+#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue)
{
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags);
}
+#endif /* AR9170_QUEUE_DEBUG */
+#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
- wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
- ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+ " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+ ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
+#endif /* AR9170_QUEUE_STOP_DEBUG */
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{
unsigned long flags;
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- __ar9170_dump_txstats(ar);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+ spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
+ printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
+ spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
}
-#endif /* AR9170_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
+static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
+{
+ struct sk_buff_head success;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned long queue_bitmap = 0;
+
+ skb_queue_head_init(&success);
+
+ while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
+ __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
+
+ ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
+ wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
+ __ar9170_dump_txqueue(ar, &success);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = __skb_dequeue(&success))) {
+ struct ieee80211_tx_info *txinfo;
+
+ queue_bitmap |= BIT(skb_get_queue_mapping(skb));
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ txinfo->flags |= IEEE80211_TX_STAT_ACK;
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ }
+
+ for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+ ieee80211_wake_queue(ar->hw, i);
+ }
+
+ if (queue_bitmap)
+ ar9170_tx(ar);
+}
+
+static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_BA_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status_ampdu, skb);
+ ar9170_tx_fake_ampdu_status(ar);
+ ar->tx_ampdu_pending--;
+
+ if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
+}
+
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- dev_kfree_skb_any(skb);
+ ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL;
}
+static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+
+ while (count) {
+ skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
+ if (!skb)
+ break;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ /* FIXME: maybe more ? */
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ count--;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ if (count) {
+ printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
+ "suitable frames left in tx_status queue.\n",
+ wiphy_name(ar->hw->wiphy), count);
+
+ ar9170_dump_tx_status_ampdu(ar);
+ }
+#endif /* AR9170_TXAGG_DEBUG */
+}
+
/*
* This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are
@@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
+ ar9170_tx_fake_ampdu_status(ar);
+
if (resched)
queue_delayed_work(ar->hw->workqueue,
&ar->tx_janitor,
@@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case 0xc4:
+ /* BlockACK bitmap */
+ break;
+
case 0xc5:
/* BlockACK events */
+ ar9170_handle_block_ack(ar,
+ le16_to_cpu(cmd->ba_fail_cnt.failed),
+ le16_to_cpu(cmd->ba_fail_cnt.rate));
+ ar9170_tx_fake_ampdu_status(ar);
break;
case 0xc6:
@@ -917,8 +1063,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
ar9170_rx_phy_status(ar, phy, &status);
skb = ar9170_rx_copy_data(buf, mpdu_len);
- if (likely(skb))
- ieee80211_rx_irqsafe(ar->hw, skb, &status);
+ if (likely(skb)) {
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(ar->hw, skb);
+ }
}
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
@@ -1096,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ /* set sane AMPDU defaults */
+ ar->global_ampdu_density = 6;
+ ar->global_ampdu_factor = 3;
+
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1141,6 +1293,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor);
+#ifdef CONFIG_AR9170_LEDS
+ cancel_delayed_work_sync(&ar->led_work);
+#endif
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex);
@@ -1157,9 +1312,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]);
}
+ skb_queue_purge(&ar->tx_status_ampdu);
+
mutex_unlock(&ar->mutex);
}
+static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
+}
+
+static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
+ struct sk_buff *src)
+{
+ struct ar9170_tx_control *dst_txc, *src_txc;
+ struct ieee80211_tx_info *dst_info, *src_info;
+ struct ar9170_tx_info *dst_arinfo, *src_arinfo;
+
+ src_txc = (void *) src->data;
+ src_info = IEEE80211_SKB_CB(src);
+ src_arinfo = (void *) src_info->rate_driver_data;
+
+ dst_txc = (void *) dst->data;
+ dst_info = IEEE80211_SKB_CB(dst);
+ dst_arinfo = (void *) dst_info->rate_driver_data;
+
+ dst_txc->phy_control = src_txc->phy_control;
+
+ /* same MCS for the whole aggregate */
+ memcpy(dst_info->driver_rates, src_info->driver_rates,
+ sizeof(dst_info->driver_rates));
+}
+
static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -1228,6 +1414,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
goto out;
}
@@ -1358,6 +1545,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
}
+static bool ar9170_tx_ampdu(struct ar9170 *ar)
+{
+ struct sk_buff_head agg;
+ struct ar9170_sta_tid *tid_info = NULL, *tmp;
+ struct sk_buff *skb, *first = NULL;
+ unsigned long flags, f2;
+ unsigned int i = 0;
+ u16 seq, queue, tmpssn;
+ bool run = false;
+
+ skb_queue_head_init(&agg);
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (list_empty(&ar->tx_ampdu_list)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: aggregation list is empty.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ goto out_unlock;
+ }
+
+ list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
+ if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ if (++i > 64) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: enough frames aggregated.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ break;
+ }
+
+ queue = TID_TO_WME_AC(tid_info->tid);
+
+ if (skb_queue_len(&ar->tx_pending[queue]) >=
+ AR9170_NUM_TX_AGG_MAX) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queue %d full.\n",
+ wiphy_name(ar->hw->wiphy), queue);
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ list_del_init(&tid_info->list);
+
+ spin_lock_irqsave(&tid_info->queue.lock, f2);
+ tmpssn = seq = tid_info->ssn;
+ first = skb_peek(&tid_info->queue);
+
+ if (likely(first))
+ tmpssn = ar9170_get_seq(first);
+
+ if (unlikely(tmpssn != seq)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
+ wiphy_name(ar->hw->wiphy), seq, tmpssn);
+#endif /* AR9170_TXAGG_DEBUG */
+ tid_info->ssn = tmpssn;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
+ "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid, tid_info->ssn,
+ skb_queue_len(&tid_info->queue));
+ __ar9170_dump_txqueue(ar, &tid_info->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = skb_peek(&tid_info->queue))) {
+ if (unlikely(ar9170_get_seq(skb) != seq))
+ break;
+
+ __skb_unlink(skb, &tid_info->queue);
+ tid_info->ssn = seq = GET_NEXT_SEQ(seq);
+
+ if (unlikely(skb_get_queue_mapping(skb) != queue)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
+ "!match.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid,
+ TID_TO_WME_AC(tid_info->tid),
+ skb_get_queue_mapping(skb));
+#endif /* AR9170_TXAGG_DEBUG */
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (unlikely(first == skb)) {
+ ar9170_tx_prepare_phy(ar, skb);
+ __skb_queue_tail(&agg, skb);
+ first = skb;
+ } else {
+ ar9170_tx_copy_phy(ar, skb, first);
+ __skb_queue_tail(&agg, skb);
+ }
+
+ if (unlikely(skb_queue_len(&agg) ==
+ AR9170_NUM_TX_AGG_MAX))
+ break;
+ }
+
+ if (skb_queue_empty(&tid_info->queue))
+ tid_info->active = false;
+ else
+ list_add_tail(&tid_info->list,
+ &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&tid_info->queue.lock, f2);
+
+ if (unlikely(skb_queue_empty(&agg))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queued empty list!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ /*
+ * tell the FW/HW that this is the last frame,
+ * that way it will wait for the immediate block ack.
+ */
+ if (likely(skb_peek_tail(&agg)))
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &agg);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+
+ spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
+ skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+ spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
+ run = true;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ __skb_queue_purge(&agg);
+
+ return run;
+}
+
static void ar9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1382,11 +1722,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
- printk(KERN_DEBUG "stuck frames: ===> \n");
+ printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+ wiphy_name(ar->hw->wiphy));
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: stop queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue;
@@ -1401,8 +1747,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space,
frames);
-
- ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1430,6 +1774,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending++;
+
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1438,6 +1785,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending--;
+
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1459,13 +1809,18 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed =>\n",
+ printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
}
@@ -1477,6 +1832,90 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
+static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct ar9170_sta_info *sta_info;
+ struct ar9170_sta_tid *agg;
+ struct sk_buff *iter;
+ unsigned long flags, f2;
+ unsigned int max;
+ u16 tid, seq, qseq;
+ bool run = false, queue = false;
+
+ tid = ar9170_get_tid(skb);
+ seq = ar9170_get_seq(skb);
+ txinfo = IEEE80211_SKB_CB(skb);
+ sta_info = (void *) txinfo->control.sta->drv_priv;
+ agg = &sta_info->agg[tid];
+ max = sta_info->ampdu_max_len;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+
+ if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
+ "for ESS:%pM tid:%d state:%d.\n",
+ wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
+ agg->state);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ if (!agg->active) {
+ agg->active = true;
+ agg->ssn = seq;
+ queue = true;
+ }
+
+ /* check if seq is within the BA window */
+ if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
+ "fit into BA window (%d - %d)\n",
+ wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
+ (agg->ssn + max) & 0xfff);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ spin_lock_irqsave(&agg->queue.lock, f2);
+
+ skb_queue_reverse_walk(&agg->queue, iter) {
+ qseq = ar9170_get_seq(iter);
+
+ if (GET_NEXT_SEQ(qseq) == seq) {
+ __skb_queue_after(&agg->queue, iter, skb);
+ goto queued;
+ }
+ }
+
+ __skb_queue_head(&agg->queue, skb);
+
+queued:
+ spin_unlock_irqrestore(&agg->queue.lock, f2);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
+ wiphy_name(ar->hw->wiphy), skb);
+ __ar9170_dump_txqueue(ar, &agg->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
+ run = true;
+
+ if (queue)
+ list_add_tail(&agg->list, &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ return run;
+
+err_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ dev_kfree_skb_irq(skb);
+ return false;
+}
+
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ar9170 *ar = hw->priv;
@@ -1490,8 +1929,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- /* drop frame, we do not allow TX A-MPDU aggregation yet. */
- goto err_free;
+ bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+ if (run || !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1929,6 +2370,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ memset(sta_info, 0, sizeof(*sta_info));
+
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+ ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+
+ if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+ ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+ sta_info->agg[i].active = false;
+ sta_info->agg[i].ssn = 0;
+ sta_info->agg[i].retry = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ break;
+
+ case STA_NOTIFY_REMOVE:
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+ skb_queue_purge(&sta_info->agg[i].queue);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (IS_STARTED(ar) && ar->filter_changed)
+ queue_work(ar->hw->workqueue, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1983,18 +2471,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
+ unsigned long flags;
+
+ if (!modparam_ht)
+ return -EOPNOTSUPP;
+
switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
+ !list_empty(&tid_info->list)) {
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
+ "is in a very bad state!\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ return -EBUSY;
+ }
+
+ *ssn = tid_info->ssn;
+ tid_info->state = AR9170_TID_STATE_PROGRESS;
+ tid_info->active = false;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ tid_info->state = AR9170_TID_STATE_SHUTDOWN;
+ list_del_init(&tid_info->list);
+ tid_info->active = false;
+ skb_queue_purge(&tid_info->queue);
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ break;
+
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- /*
- * Something goes wrong -- RX locks up
- * after a while of receiving aggregated
- * frames -- not enabling for now.
- */
- return -EOPNOTSUPP;
+ /* Handled by firmware */
+ break;
+
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static const struct ieee80211_ops ar9170_ops = {
@@ -2043,6 +2578,8 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
+ spin_lock_init(&ar->tx_ampdu_list_lock);
+ skb_queue_head_init(&ar->tx_status_ampdu);
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]);
@@ -2051,6 +2588,7 @@ void *ar9170_alloc(size_t priv_size)
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
+ INIT_LIST_HEAD(&ar->tx_ampdu_list);
/* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0];
@@ -2064,6 +2602,13 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
+ if (modparam_ht) {
+ ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ } else {
+ ar9170_band_2GHz.ht_cap.ht_supported = false;
+ ar9170_band_5GHz.ht_cap.ht_supported = false;
+ }
+
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2085,10 +2630,10 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
{
#define RW 8 /* number of words to read at once */
#define RB (sizeof(u32) * RW)
- DECLARE_MAC_BUF(mbuf);
u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW];
+ unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2125,6 +2670,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++;
}
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams)
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 754b1f8d8da9..1aec7afdffa7 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
usb_set_intfdata(intf, aru);
- SET_IEEE80211_DEV(ar->hw, &udev->dev);
+ SET_IEEE80211_DEV(ar->hw, &intf->dev);
init_usb_anchor(&aru->rx_submitted);
init_usb_anchor(&aru->tx_pending);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6358233bac99..91375113916b 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -713,8 +713,8 @@ struct ath5k_gain {
* Used internaly for reset_tx_queue).
* Also see struct struct ieee80211_channel.
*/
-#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
/*
* The following structure is used to map 2GHz channels to
@@ -1029,14 +1029,15 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
enum nl80211_iftype ah_op_mode;
- enum ath5k_power_mode ah_power_mode;
- struct ieee80211_channel ah_current_channel;
+ struct ieee80211_channel *ah_current_channel;
bool ah_turbo;
bool ah_calibration;
- bool ah_running;
bool ah_single_chip;
bool ah_combined_mic;
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+ u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
u16 ah_mac_revision;
@@ -1044,13 +1045,6 @@ struct ath5k_hw {
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
- enum ath5k_version ah_version;
- enum ath5k_radio ah_radio;
- u32 ah_phy;
-
- bool ah_5ghz;
- bool ah_2ghz;
-
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
@@ -1058,7 +1052,6 @@ struct ath5k_hw {
u32 ah_aifs;
u32 ah_cw_min;
u32 ah_cw_max;
- bool ah_software_retry;
u32 ah_limit_tx_retries;
/* Antenna Control */
@@ -1066,6 +1059,7 @@ struct ath5k_hw {
u8 ah_ant_mode;
u8 ah_tx_ant;
u8 ah_def_ant;
+ bool ah_software_retry;
u8 ah_sta_id[ETH_ALEN];
@@ -1075,7 +1069,6 @@ struct ath5k_hw {
u8 ah_bssid[ETH_ALEN];
u8 ah_bssid_mask[ETH_ALEN];
- u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
struct ath_regulatory ah_regulatory;
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index c41ef58393e7..9a84d9410b27 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ath5k_hw_rfgain_opt_init(ah);
+ /* turn on HW LEDs */
+ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+
return ah;
err_free:
kfree(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index ea045151f953..7db32ce3dbd8 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = {
* Prototypes - MAC 802.11 stack related functions
*/
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
@@ -248,6 +250,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
static const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -265,6 +269,8 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
};
/*
@@ -297,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf);
+ struct ath5k_buf *bf,
+ struct ath5k_txq *txq);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -512,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, &pdev->dev);
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
@@ -666,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
- free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (err) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_no_irq;
- }
-
ath5k_led_enable(sc);
return 0;
-
-err_no_irq:
- pci_disable_device(pdev);
- return err;
}
#endif /* CONFIG_PM */
@@ -785,12 +782,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_desc;
}
sc->bhalq = ret;
+ sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+ if (IS_ERR(sc->cabq)) {
+ ATH5K_ERR(sc, "can't setup cab queue\n");
+ ret = PTR_ERR(sc->cabq);
+ goto err_bhal;
+ }
sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
if (IS_ERR(sc->txq)) {
ATH5K_ERR(sc, "can't setup xmit queue\n");
ret = PTR_ERR(sc->txq);
- goto err_bhal;
+ goto err_queues;
}
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
@@ -1228,10 +1231,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
}
static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+ struct ath5k_txq *txq)
{
struct ath5k_hw *ah = sc->ah;
- struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1901,7 +1904,8 @@ accept:
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_check_ibss_tsf(sc, skb, &rxs);
- __ieee80211_rx(sc->hw, skb, &rxs);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
+ ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
bf->skbaddr = next_skb_addr;
@@ -2078,13 +2082,6 @@ err_unmap:
return ret;
}
-static void ath5k_beacon_disable(struct ath5k_softc *sc)
-{
- sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- ath5k_hw_set_imr(sc->ah, sc->imask);
- ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
-}
-
/*
* Transmit a beacon frame at SWBA. Dynamic updates to the
* frame contents are done as needed and the slot time is
@@ -2098,6 +2095,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
{
struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct sk_buff *skb;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
@@ -2151,6 +2149,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ while (skb) {
+ ath5k_tx_queue(sc->hw, skb, sc->cabq);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ }
+
sc->bsent++;
}
@@ -2271,13 +2275,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
struct ath5k_hw *ah = sc->ah;
unsigned long flags;
- ath5k_hw_set_imr(ah, 0);
+ spin_lock_irqsave(&sc->block, flags);
sc->bmisscount = 0;
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- if (sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_MESH_POINT ||
- sc->opmode == NL80211_IFTYPE_AP) {
+ if (sc->enable_beacon) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2290,16 +2292,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
- if (ath5k_hw_hasveol(ah)) {
- spin_lock_irqsave(&sc->block, flags);
+ if (ath5k_hw_hasveol(ah))
ath5k_beacon_send(sc);
- spin_unlock_irqrestore(&sc->block, flags);
- }
} else
ath5k_beacon_update_timers(sc, -1);
+ } else {
+ ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
}
ath5k_hw_set_imr(ah, sc->imask);
+ mmiowb();
+ spin_unlock_irqrestore(&sc->block, flags);
}
static void ath5k_tasklet_beacon(unsigned long data)
@@ -2598,6 +2601,14 @@ static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
+
+ return ath5k_tx_queue(hw, skb, sc->txq);
+}
+
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
+{
+ struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
unsigned long flags;
int hdrlen;
@@ -2641,7 +2652,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
bf->skb = skb;
- if (ath5k_txbuf_setup(sc, bf)) {
+ if (ath5k_txbuf_setup(sc, bf, txq)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -2676,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
@@ -2776,7 +2787,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
- ath5k_beacon_disable(sc);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@@ -2970,6 +2980,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (modparam_nohwcrypt)
return -EOPNOTSUPP;
+ if (sc->opmode == NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
switch (key->alg) {
case ALG_WEP:
case ALG_TKIP:
@@ -3105,25 +3118,6 @@ out:
return ret;
}
-/*
- * Update the beacon and reconfigure the beacon queues.
- */
-static void
-ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int ret;
- unsigned long flags;
- struct ath5k_softc *sc = hw->priv;
-
- spin_lock_irqsave(&sc->block, flags);
- ret = ath5k_beacon_update(hw, vif);
- spin_unlock_irqrestore(&sc->block, flags);
- if (ret == 0) {
- ath5k_beacon_config(sc);
- mmiowb();
- }
-}
-
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
@@ -3146,6 +3140,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ unsigned long flags;
mutex_lock(&sc->lock);
if (WARN_ON(sc->vif != vif))
@@ -3167,15 +3162,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->assoc = bss_conf->assoc;
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
}
- if (changes & BSS_CHANGED_BEACON &&
- (vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MESH_POINT ||
- vif->type == NL80211_IFTYPE_AP)) {
- ath5k_beacon_reconfig(hw, vif);
+ if (changes & BSS_CHANGED_BEACON) {
+ spin_lock_irqsave(&sc->block, flags);
+ ath5k_beacon_update(hw, vif);
+ spin_unlock_irqrestore(&sc->block, flags);
}
+ if (changes & BSS_CHANGED_BEACON_ENABLED)
+ sc->enable_beacon = bss_conf->enable_beacon;
+
+ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON_INT))
+ ath5k_beacon_config(sc);
+
unlock:
mutex_unlock(&sc->lock);
}
+
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (!sc->assoc)
+ ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index f9b7f2f819b7..778e422946ab 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -114,8 +114,7 @@ struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
- /* FIXME: how many does it really need? */
- struct ieee80211_tx_queue_stats tx_stats[16];
+ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -171,9 +170,8 @@ struct ath5k_softc {
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
- struct ath5k_txq txqs[2]; /* beacon and tx */
-
- struct ath5k_txq *txq; /* beacon and tx*/
+ struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
+ struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
@@ -187,10 +185,12 @@ struct ath5k_softc {
bintval, /* beacon interval in TU */
bsent;
unsigned int nexttbtt; /* next beacon time in TU */
+ struct ath5k_txq *cabq; /* content after beacon */
struct timer_list calib_tim; /* calibration timer */
int power_level; /* Requested tx power in dbm */
bool assoc; /* assocate state */
+ bool enable_beacon; /* true if beacons are on */
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4904a07e4b59..747508c15d34 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath5k_global_debugfs);
- sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_debug = debugfs_create_file("debug",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_debug);
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
+ sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_registers);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_beacon);
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a876ca8d69ef..2075ba993966 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
AR5K_PHY_CCKTXCTL_WORLD);
}
- ah->ah_current_channel.center_freq = channel->center_freq;
- ah->ah_current_channel.hw_value = channel->hw_value;
+ ah->ah_current_channel = channel;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
return 0;
@@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
void
ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
{
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
u8 def_ant, tx_ant, ee_mode;
@@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
/*Just a try M.F.*/
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
ATH5K_TRACE(ah->ah_sc);
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 73407b3f53ef..6d5aaf00d8bb 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
AR5K_QCU_MISC_CBREXP_DIS |
- AR5K_QCU_MISC_RDY_VEOL_POLICY |
AR5K_QCU_MISC_CBREXP_BCN_DIS);
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 6809b54a2ad7..c63ea6afd96f 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -339,9 +339,9 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SISR2_QCU_TXURN_S 0
-#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
@@ -430,9 +430,9 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0
-#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */
@@ -982,7 +982,7 @@
#define AR5K_5414_CBCFG_BUF_DIS 0x10 /* Disable buffer */
/*
- * PCI-E Power managment configuration
+ * PCI-E Power management configuration
* and status register [5424+]
*/
#define AR5K_PCIE_PM_CTL 0x4068 /* Register address */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index bd0a97a38d34..86733fdb4774 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
}
commit:
- ah->ah_power_mode = mode;
ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 2d79610bce12..0f4a6d862d3a 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -18,6 +18,6 @@ config ATH9K_DEBUG
Say Y, if you need ath9k to display debug messages.
Pass the debug mask as a module parameter:
- modprobe ath9k debug=0x00002000
+ modprobe ath9k debug=0x00000200
- Look in ath9k/core.h for possible debug masks
+ Look in ath9k/debug.h for possible debug masks
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 1aeafb511ddd..aad259b4c197 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -478,6 +478,18 @@ void ath9k_ani_reset(struct ath_hw *ah)
"Reset ANI state opmode %u\n", ah->opmode);
ah->stats.ast_ani_reset++;
+ if (ah->opmode == NL80211_IFTYPE_AP) {
+ /*
+ * ath9k_hw_ani_control() will only process items set on
+ * ah->ani_function
+ */
+ if (IS_CHAN_2GHZ(chan))
+ ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+ ATH9K_ANI_FIRSTEP_LEVEL);
+ else
+ ah->ani_function = 0;
+ }
+
ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5efc9345ca0d..bda0f302340c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
-#define ATH_11N_TXMAXTRY 10
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
@@ -191,12 +190,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
-#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
#define IEEE80211_WEP_IVLEN 3
#define IEEE80211_WEP_KIDLEN 1
#define IEEE80211_WEP_CRCLEN 4
@@ -226,6 +222,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
+#define ATH_TX_COMPLETE_POLL_INT 1000
+
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
@@ -239,8 +237,8 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u8 axq_aggr_depth;
- u32 axq_totalqueued;
bool stopped;
+ bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf;
/* first desc of the last descriptor that contains CTS */
@@ -272,7 +270,6 @@ struct ath_atx_tid {
int sched;
int paused;
u8 state;
- int addba_exchangeattempts;
};
struct ath_atx_ac {
@@ -292,12 +289,28 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
+#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))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
+ int last_rssi;
};
struct ath_tx {
@@ -348,9 +361,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
-int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn);
+void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
/********/
@@ -541,6 +554,8 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
+ spinlock_t ani_lock;
+ spinlock_t sc_pm_lock;
struct mutex mutex;
u8 curbssid[ETH_ALEN];
@@ -557,7 +572,8 @@ struct ath_softc {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
- atomic_t ps_usecount;
+ bool ps_enabled;
+ unsigned long ps_usecount;
enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width;
@@ -590,6 +606,7 @@ struct ath_softc {
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
+ struct delayed_work tx_complete_work;
};
struct ath_wiphy {
@@ -654,27 +671,8 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- if (atomic_inc_return(&sc->ps_usecount) == 1)
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
- sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- }
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
- if (atomic_dec_and_test(&sc->ps_usecount))
- if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
- !(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,
- sc->sc_ah->restore_mode);
-}
-
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
int ath9k_wiphy_add(struct ath_softc *sc);
@@ -690,6 +688,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
struct ath_wiphy *selected);
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);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 3639a2e6987d..45c4ea57616b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
- /*
- * It looks like mac80211 may end up using beacon interval of zero in
- * some cases (at least for mesh point). Avoid getting into an
- * infinite loop by using a bit safer value instead..
- */
- if (intval == 0)
- intval = 100;
/* Pull nexttbtt forward to reflect the current TSF */
@@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
iftype = sc->sc_ah->opmode;
}
+ /*
+ * It looks like mac80211 may end up using beacon interval of zero in
+ * some cases (at least for mesh point). Avoid getting into an
+ * infinite loop by using a bit safer value instead. To be safe,
+ * do sanity check on beacon interval for all operating modes.
+ */
+ if (cur_conf->beacon_interval == 0)
+ cur_conf->beacon_interval = 100;
switch (iftype) {
case NL80211_IFTYPE_AP:
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a32d7e7fecbe..d1bbb02af8de 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
- if (!AR_SREV_9280(ah)) {
+ if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
@@ -154,7 +154,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
- if (!AR_SREV_9280(ah)) {
+ if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
@@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
if (AR_SREV_9285(ah))
chainmask = 0x9;
- else if (AR_SREV_9280(ah))
+ else if (AR_SREV_9280(ah) || AR_SREV_9287(ah))
chainmask = 0x1B;
else
chainmask = 0x3F;
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
int i, j;
+ s16 noise_floor;
+
+ if (AR_SREV_9280(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+ else if (AR_SREV_9285(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+ else
+ noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
}
}
}
@@ -866,7 +873,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah);
- if (OLC_FOR_AR9280_20_LATER)
+ if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah);
ath9k_hw_getnf(ah, chan);
ath9k_hw_loadnf(ah, ah->curchan);
@@ -922,8 +929,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
return false;
} else {
if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ if (!AR_SREV_9287_10_OR_LATER(ah))
+ REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
+ AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_FLTR_CAL);
}
/* Calibrate the AGC */
@@ -941,8 +951,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
}
if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+ if (!AR_SREV_9287_10_OR_LATER(ah))
+ REG_SET_BIT(ah, AR_PHY_ADC_CTL,
+ AR_PHY_ADC_CTL_OFF_PWDADC);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_FLTR_CAL);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index fe5367f14148..547e697b9055 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
extern const struct ath9k_percal_data adc_dc_cal_single_sample;
extern const struct ath9k_percal_data adc_init_dc_cal;
-#define AR_PHY_CCA_MAX_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
+#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6d20725d6451..9e369208f7dc 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = {
.owner = THIS_MODULE
};
+#define PR(str, elem) \
+ do { \
+ len += snprintf(buf + len, size - len, \
+ "%s%13u%11u%10u%10u\n", str, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \
+} while(0)
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char *buf;
+ unsigned int len = 0, size = 2048;
+ ssize_t retval = 0;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return 0;
+
+ len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
+
+ PR("MPDUs Queued: ", queued);
+ PR("MPDUs Completed: ", completed);
+ PR("Aggregates: ", a_aggr);
+ PR("AMPDUs Queued: ", a_queued);
+ PR("AMPDUs Completed:", a_completed);
+ PR("AMPDUs Retried: ", a_retries);
+ PR("AMPDUs XRetried: ", a_xretries);
+ PR("FIFO Underrun: ", fifo_underrun);
+ PR("TXOP Exceeded: ", xtxop);
+ PR("TXTIMER Expiry: ", timer_exp);
+ PR("DESC CFG Error: ", desc_cfg_err);
+ PR("DATA Underrun: ", data_underrun);
+ PR("DELIM Underrun: ", delim_underrun);
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+ struct ath_desc *ds = bf->bf_desc;
+
+ if (bf_isampdu(bf)) {
+ if (bf_isxretried(bf))
+ TX_STAT_INC(txq->axq_qnum, a_xretries);
+ else
+ TX_STAT_INC(txq->axq_qnum, a_completed);
+ } else {
+ TX_STAT_INC(txq->axq_qnum, completed);
+ }
+
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
+ TX_STAT_INC(txq->axq_qnum, fifo_underrun);
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
+ TX_STAT_INC(txq->axq_qnum, xtxop);
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
+ TX_STAT_INC(txq->axq_qnum, timer_exp);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
+ TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
+ TX_STAT_INC(txq->axq_qnum, data_underrun);
+ if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
+ TX_STAT_INC(txq->axq_qnum, delim_underrun);
+}
+
+static const struct file_operations fops_xmit = {
+ .read = read_file_xmit,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
int ath9k_init_debug(struct ath_softc *sc)
{
@@ -500,35 +577,42 @@ int ath9k_init_debug(struct ath_softc *sc)
goto err;
sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
+ S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
if (!sc->debug.debugfs_debug)
goto err;
- sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+ sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dma);
if (!sc->debug.debugfs_dma)
goto err;
sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_interrupt);
if (!sc->debug.debugfs_interrupt)
goto err;
sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_rcstat);
if (!sc->debug.debugfs_rcstat)
goto err;
sc->debug.debugfs_wiphy = debugfs_create_file(
- "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+ "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
&fops_wiphy);
if (!sc->debug.debugfs_wiphy)
goto err;
+ sc->debug.debugfs_xmit = debugfs_create_file("xmit",
+ S_IRUSR,
+ sc->debug.debugfs_phy,
+ sc, &fops_xmit);
+ if (!sc->debug.debugfs_xmit)
+ goto err;
+
return 0;
err:
ath9k_exit_debug(sc);
@@ -537,6 +621,7 @@ err:
void ath9k_exit_debug(struct ath_softc *sc)
{
+ debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat);
debugfs_remove(sc->debug.debugfs_interrupt);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index edda15bf2c15..5e56b79d0cb0 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -35,6 +35,15 @@ enum ATH_DEBUG {
#define DBG_DEFAULT (ATH_DBG_FATAL)
+struct ath_txq;
+struct ath_buf;
+
+#ifdef CONFIG_ATH9K_DEBUG
+#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
+#else
+#define TX_STAT_INC(q, c) do { } while (0)
+#endif
+
#ifdef CONFIG_ATH9K_DEBUG
/**
@@ -87,9 +96,45 @@ struct ath_rc_stats {
u8 per;
};
+/**
+ * struct ath_tx_stats - Statistics about TX
+ * @queued: Total MPDUs (non-aggr) queued
+ * @completed: Total MPDUs (non-aggr) completed
+ * @a_aggr: Total no. of aggregates queued
+ * @a_queued: Total AMPDUs queued
+ * @a_completed: Total AMPDUs completed
+ * @a_retries: No. of AMPDUs retried (SW)
+ * @a_xretries: No. of AMPDUs dropped due to xretries
+ * @fifo_underrun: FIFO underrun occurrences
+ Valid only for:
+ - non-aggregate condition.
+ - first packet of aggregate.
+ * @xtxop: No. of frames filtered because of TXOP limit
+ * @timer_exp: Transmit timer expiry
+ * @desc_cfg_err: Descriptor configuration errors
+ * @data_urn: TX data underrun errors
+ * @delim_urn: TX delimiter underrun errors
+ */
+struct ath_tx_stats {
+ u32 queued;
+ u32 completed;
+ u32 a_aggr;
+ u32 a_queued;
+ u32 a_completed;
+ u32 a_retries;
+ u32 a_xretries;
+ u32 fifo_underrun;
+ u32 xtxop;
+ u32 timer_exp;
+ u32 desc_cfg_err;
+ u32 data_underrun;
+ u32 delim_underrun;
+};
+
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
+ struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
};
struct ath9k_debug {
@@ -100,6 +145,7 @@ struct ath9k_debug {
struct dentry *debugfs_interrupt;
struct dentry *debugfs_rcstat;
struct dentry *debugfs_wiphy;
+ struct dentry *debugfs_xmit;
struct ath_stats stats;
};
@@ -110,6 +156,8 @@ int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
+void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf);
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per);
@@ -148,6 +196,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
{
}
+static inline void ath_debug_stat_tx(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+}
+
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per)
{
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index a2fda702b620..6fb1a8034b3c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -460,7 +460,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
integer = swab32(eep->modalHeader.antCtrlCommon);
eep->modalHeader.antCtrlCommon = integer;
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
integer = swab32(eep->modalHeader.antCtrlChain[i]);
eep->modalHeader.antCtrlChain[i] = integer;
}
@@ -914,7 +914,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ctlMode, numCtlModes, isHt40CtlMode,
(pCtlMode[ctlMode] & EXT_ADDITIVE));
- for (i = 0; (i < AR5416_NUM_CTLS) &&
+ for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
@@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+ /* Set the block 1 value to block 0 value */
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[0]);
}
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
if (AR_SREV_9285_11(ah))
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
@@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
/* Initialize Ant Diversity settings from EEPROM */
- if (pModal->version == 3) {
+ if (pModal->version >= 3) {
ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
regVal = REG_READ(ah, 0x99ac);
@@ -2516,10 +2534,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
targetPowerCck.tPow2x[1];
ratesArray[rate5_5s] = ratesArray[rate5_5l] =
targetPowerCck.tPow2x[2];
- ;
ratesArray[rate11s] = ratesArray[rate11l] =
targetPowerCck.tPow2x[3];
- ;
}
if (IS_CHAN_HT40(chan)) {
for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
@@ -2765,11 +2781,1210 @@ static struct eeprom_ops eep_def_ops = {
.get_spur_channel = ath9k_hw_def_get_spur_channel
};
+
+static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
+{
+ return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
+}
+
+static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
+{
+ return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
+}
+
+static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
+{
+ struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ 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");
+ }
+
+ for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / 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");
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+}
+static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
+{
+#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16))
+ u32 sum = 0, el, integer;
+ u16 temp, word, magic, magic2, *eepdata;
+ int i, addr;
+ bool need_swap = false;
+ struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+
+ 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");
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+ if (magic != AR5416_EEPROM_MAGIC) {
+
+
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ need_swap = true;
+ eepdata = (u16 *)(&ah->eeprom);
+
+ for (addr = 0; addr < SIZE_EEPROM_87; addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+ }
+ } else {
+ DPRINTF(ah->ah_sc, 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");
+
+ if (need_swap)
+ el = swab16(ah->eeprom.map9287.baseEepHeader.length);
+ else
+ el = ah->eeprom.map9287.baseEepHeader.length;
+
+ eepdata = (u16 *)(&ah->eeprom);
+ for (i = 0; i < min(el, SIZE_EEPROM_87); i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ integer = swab32(eep->modalHeader.antCtrlCommon);
+ eep->modalHeader.antCtrlCommon = integer;
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ integer = swab32(eep->modalHeader.antCtrlChain[i]);
+ eep->modalHeader.antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(eep->modalHeader.spurChans[i].spurChan);
+ eep->modalHeader.spurChans[i].spurChan = word;
+ }
+ }
+
+ 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));
+ return -EINVAL;
+ }
+
+ return 0;
+#undef SIZE_EEPROM_87
+}
+
+static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
+ enum eeprom_param param)
+{
+ struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+ struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+ u16 ver_minor;
+
+ ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+ switch (param) {
+ case EEP_NFTHRESH_2:
+ return pModal->noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_MINOR_REV:
+ return ver_minor;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ case EEP_DEV_TYPE:
+ return pBase->deviceType;
+ case EEP_OL_PWRCTRL:
+ return pBase->openLoopPwrCntl;
+ case EEP_TEMPSENSE_SLOPE:
+ if (ver_minor >= AR9287_EEP_MINOR_VER_2)
+ return pBase->tempSensSlope;
+ else
+ return 0;
+ case EEP_TEMPSENSE_SLOPE_PAL_ON:
+ if (ver_minor >= AR9287_EEP_MINOR_VER_3)
+ return pBase->tempSensSlopePalOn;
+ else
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+
+static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_ar9287 *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+#define TMP_VAL_VPD_TABLE \
+ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR9287_NUM_PD_GAINS];
+ u8 maxPwrT4[AR9287_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+ static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR9287_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)), bChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR9287_PD_GAIN_ICEPTS, vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers. synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] = (u16)((maxPwrT4[i] +
+ minPwrT4[i+1]) / 4);
+
+ pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
+ pPdGainBoundaries[i]);
+
+
+ if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else
+ minDelta = 0;
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else
+ ss = (int16_t)((pPdGainBoundaries[i-1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+ while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] +
+ tPdGainOverlap - (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1)))
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR9287_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR9287_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pPdGainBoundaries[i-1];
+ i++;
+ }
+
+ while (k < AR9287_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k-1];
+ k++;
+ }
+
+#undef TMP_VAL_VPD_TABLE
+}
+
+static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
+ u8 *pCalChans, u16 availPiers,
+ int8_t *pPwr)
+{
+ u8 pcdac, i = 0;
+ u16 idxL = 0, idxR = 0, numPiers;
+ bool match;
+ struct chan_centers centers;
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ pCalChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0];
+ *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0];
+ } else {
+ pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0];
+ *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
+ pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+ }
+
+ while ((pcdac > ah->originalGain[i]) &&
+ (i < (AR9280_TX_GAIN_TABLE_SIZE - 1)))
+ i++;
+}
+
+static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
+ int32_t txPower, u16 chain)
+{
+ u32 tmpVal;
+ u32 a;
+
+ tmpVal = REG_READ(ah, 0xa270);
+ tmpVal = tmpVal & 0xFCFFFFFF;
+ tmpVal = tmpVal | (0x3 << 24);
+ REG_WRITE(ah, 0xa270, tmpVal);
+
+ tmpVal = REG_READ(ah, 0xb270);
+ tmpVal = tmpVal & 0xFCFFFFFF;
+ tmpVal = tmpVal | (0x3 << 24);
+ REG_WRITE(ah, 0xb270, tmpVal);
+
+ if (chain == 0) {
+ tmpVal = REG_READ(ah, 0xa398);
+ tmpVal = tmpVal & 0xff00ffff;
+ a = (txPower)&0xff;
+ tmpVal = tmpVal | (a << 16);
+ REG_WRITE(ah, 0xa398, tmpVal);
+ }
+
+ if (chain == 1) {
+ tmpVal = REG_READ(ah, 0xb398);
+ tmpVal = tmpVal & 0xff00ffff;
+ a = (txPower)&0xff;
+ tmpVal = tmpVal | (a << 16);
+ REG_WRITE(ah, 0xb398, tmpVal);
+ }
+}
+
+
+static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
+ struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset)
+{
+ struct cal_data_per_freq_ar9287 *pRawDataset;
+ struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
+ u16 numPiers = 0, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
+ u32 reg32, regOffset, regChainOffset;
+ int16_t modalIdx, diff = 0;
+ struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+ xpdMask = pEepData->modalHeader.xpdGain;
+ if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+ AR9287_EEP_MINOR_VER_2)
+ pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
+ else
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR9287_NUM_2G_CAL_PIERS;
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ pRawDatasetOpenLoop =
+ (struct cal_data_op_loop_ar9287 *)
+ pEepData->calPierData2G[0];
+ ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
+ }
+ }
+
+ numXpdGain = 0;
+ for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR9287_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR9287_PD_GAINS_IN_MASK-i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)
+ pEepData->calPierData2G[i];
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ int8_t txPower;
+ ar9287_eeprom_get_tx_gain_index(ah, chan,
+ pRawDatasetOpenLoop,
+ pCalBChans, numPiers,
+ &txPower);
+ ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
+ } else {
+ pRawDataset =
+ (struct cal_data_per_freq_ar9287 *)
+ pEepData->calPierData2G[i];
+ ath9k_hw_get_AR9287_gain_boundaries_pdadcs(
+ ah, chan, pRawDataset,
+ pCalBChans, numPiers,
+ pdGainOverlap_t2,
+ &tMinCalPower, gainBoundaries,
+ pdadcValues, numXpdGain);
+ }
+
+ if (i == 0) {
+ if (!ath9k_hw_AR9287_get_eeprom(
+ ah, EEP_OL_PWRCTRL)) {
+ REG_WRITE(ah, AR_PHY_TPCRG5 +
+ regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+ SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+ }
+
+ if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
+ pEepData->baseEepHeader.pwrTableOffset) {
+ diff = (u16)
+ (pEepData->baseEepHeader.pwrTableOffset
+ - (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+ diff *= 2;
+
+ for (j = 0;
+ j < ((u16)AR9287_NUM_PDADC_VALUES-diff);
+ j++)
+ pdadcValues[j] = pdadcValues[j+diff];
+
+ for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
+ j < AR9287_NUM_PDADC_VALUES; j++)
+ pdadcValues[j] =
+ pdadcValues[
+ AR9287_NUM_PDADC_VALUES-diff];
+ }
+ if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ regOffset = AR_PHY_BASE + (672 << 2) +
+ regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4*j + 0]
+ & 0xFF) << 0) |
+ ((pdadcValues[4*j + 1]
+ & 0xFF) << 8) |
+ ((pdadcValues[4*j + 2]
+ & 0xFF) << 16) |
+ ((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]);
+
+ regOffset += 4;
+ }
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+}
+
+
+static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl,
+ u16 AntennaReduction, u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
+
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9,
+ AR5416_MAX_RATE_POWER };
+ int i;
+ int16_t twiceLargestAntenna;
+ struct cal_ctl_data_ar9287 *rep;
+ struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
+ targetPowerCck = {0, {0, 0, 0, 0} };
+ struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
+ targetPowerCckExt = {0, {0, 0, 0, 0} };
+ struct cal_target_power_ht targetPowerHt20,
+ targetPowerHt40 = {0, {0, 0, 0, 0} };
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT,
+ CTL_11G_EXT, CTL_2GHT40};
+ u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u16 twiceMinEdgePower;
+ struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ tx_chainmask = ah->txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
+ pEepData->modalHeader.antennaGainCh[1]);
+
+ twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+ if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX)
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+ break;
+ case 2:
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ break;
+ case 3:
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ break;
+ }
+ scaledPower = max((u16)0, scaledPower);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+ SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR9287_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR9287_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR9287_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR9287_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+
+ if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+ ah->eep_ops->get_eeprom_rev(ah) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d,"
+ "EXT_ADDITIVE %d\n", ctlMode, numCtlModes,
+ isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE));
+ for (i = 0; (i < AR9287_NUM_CTLS)
+ && pEepData->ctlIndex[i]; i++) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "LOOP-Ctlidx %d: cfgCtl 0x%2.2x"
+ "pCtlMode 0x%2.2x ctlIndex 0x%2.2x"
+ "chan %d chanctl=xxxx\n",
+ i, cfgCtl, pCtlMode[ctlMode],
+ pEepData->ctlIndex[i], chan->channel);
+
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->ctlIndex[i] &
+ CTL_MODE_M) | SD_NO_CTL))) {
+
+ rep = &(pEepData->ctlData[i]);
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(
+ freq,
+ rep->ctlEdges[ar5416_get_ntxchains(
+ tx_chainmask) - 1],
+ IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "MATCH-EE_IDX %d: ch %d is2 %d"
+ "2xMinEdge %d chainmask %d chains %d\n",
+ i, freq, IS_CHAN_2GHZ(chan),
+ twiceMinEdgePower, tx_chainmask,
+ ar5416_get_ntxchains(tx_chainmask));
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+ twiceMaxEdgePower = min(
+ twiceMaxEdgePower,
+ twiceMinEdgePower);
+ else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d"
+ "sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
+
+
+ switch (pCtlMode[ctlMode]) {
+
+ case CTL_11B:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerCck.tPow2x);
+ i++) {
+ targetPowerCck.tPow2x[i] = (u8)min(
+ (u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
+ i++) {
+ targetPowerOfdm.tPow2x[i] = (u8)min(
+ (u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerHt20.tPow2x);
+ i++) {
+ targetPowerHt20.tPow2x[i] = (u8)min(
+ (u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] = (u8)min(
+ (u16)targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11A_EXT:
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] = (u8)min(
+ (u16)targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = 0;
+ i < ARRAY_SIZE(targetPowerHt40.tPow2x);
+ i++) {
+ targetPowerHt40.tPow2x[i] = (u8)min(
+ (u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] =
+ targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+ targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] = ratesArray[rate11l] =
+ targetPowerCck.tPow2x[3];
+ }
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
+ ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
+
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ if (IS_CHAN_2GHZ(chan))
+ ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+ }
+#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
+#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
+}
+
+static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
+ struct ath9k_channel *chan, u16 cfgCtl,
+ u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
+#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
+ struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+ AR9287_EEP_MINOR_VER_2)
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+
+ ath9k_hw_set_AR9287_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit);
+
+
+ ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR9287_MAX_RATE_POWER)
+ ratesArray[i] = AR9287_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
+ }
+
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0)
+ );
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0)
+ );
+
+ if (IS_CHAN_2GHZ(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0)
+ );
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0)
+ );
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)
+ );
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)
+ );
+
+ if (IS_CHAN_HT40(chan)) {
+ if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)
+ );
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)
+ );
+ } else {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0)
+ );
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0)
+ );
+
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0)
+ );
+ }
+
+
+ if (IS_CHAN_2GHZ(chan))
+ i = rate1l;
+ else
+ i = rate6mb;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->regulatory.max_power_level =
+ ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
+ else
+ ah->regulatory.max_power_level = ratesArray[i];
+
+ switch (ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ ah->regulatory.max_power_level +=
+ INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ ah->regulatory.max_power_level +=
+ INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
+ }
+}
+
+static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ return;
+}
+
+static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+
+ u16 antWrites[AR9287_ANT_16S];
+ u32 regChainOffset;
+ u8 txRxAttenLocal;
+ int i, j, offset_num;
+
+ pModal = &eep->modalHeader;
+
+ antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
+ antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
+ antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
+ antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
+ antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
+ antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
+ antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
+ antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
+
+ offset_num = 8;
+
+ for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
+ antWrites[j++] = 0;
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
+ antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
+ antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
+ }
+
+
+ REG_WRITE(ah, AR_PHY_SWITCH_COM,
+ ah->eep_ops->get_eeprom_antenna_cfg(ah, chan));
+
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[i]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
+ & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[i]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+ pModal->bswAtten[i]);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN,
+ txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN,
+ pModal->rxTxMarginCh[i]);
+ }
+
+
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
+ else
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
+
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+ | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+ | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+ | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
+ AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
+
+ REG_RMW_FIELD(ah, AR_PHY_CCA,
+ AR9280_PHY_CCA_THRESH62, pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+ AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1,
+ AR9287_AN_RF2G3_DB1_S, pModal->db1);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2,
+ AR9287_AN_RF2G3_DB2_S, pModal->db2);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_CCK,
+ AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_PSK,
+ AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_QAM,
+ AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
+ AR9287_AN_RF2G3_OB_PAL_OFF,
+ AR9287_AN_RF2G3_OB_PAL_OFF_S,
+ pModal->ob_pal_off);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S,
+ pModal->db1);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2,
+ AR9287_AN_RF2G3_DB2_S, pModal->db2);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_CCK,
+ AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_PSK,
+ AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_QAM,
+ AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
+ AR9287_AN_RF2G3_OB_PAL_OFF,
+ AR9287_AN_RF2G3_OB_PAL_OFF_S,
+ pModal->ob_pal_off);
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
+ AR9287_AN_TOP2_XPABIAS_LVL,
+ AR9287_AN_TOP2_XPABIAS_LVL_S,
+ pModal->xpaBiasLvl);
+}
+
+static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
+ enum ieee80211_band freq_band)
+{
+ return 1;
+}
+
+
+
+
+static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+ return pModal->antCtrlCommon & 0xFFFF;
+}
+
+
+static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
+ u16 i, bool is2GHz)
+{
+#define EEP_MAP9287_SPURCHAN \
+ (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+ 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]);
+
+ 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);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ spur_val = EEP_MAP9287_SPURCHAN;
+ break;
+ }
+
+ return spur_val;
+
+#undef EEP_MAP9287_SPURCHAN
+}
+
+static struct eeprom_ops eep_AR9287_ops = {
+ .check_eeprom = ath9k_hw_AR9287_check_eeprom,
+ .get_eeprom = ath9k_hw_AR9287_get_eeprom,
+ .fill_eeprom = ath9k_hw_AR9287_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_AR9287_set_board_values,
+ .set_addac = ath9k_hw_AR9287_set_addac,
+ .set_txpower = ath9k_hw_AR9287_set_txpower,
+ .get_spur_channel = ath9k_hw_AR9287_get_spur_channel
+};
+
+
int ath9k_hw_eeprom_attach(struct ath_hw *ah)
{
int status;
-
- if (AR_SREV_9285(ah)) {
+ if (AR_SREV_9287(ah)) {
+ ah->eep_map = EEP_MAP_AR9287;
+ ah->eep_ops = &eep_AR9287_ops;
+ } else if (AR_SREV_9285(ah)) {
ah->eep_map = EEP_MAP_4KBITS;
ah->eep_ops = &eep_4k_ops;
} else {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 67b8bd12941a..7ddd016a99ff 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -100,6 +100,8 @@
#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \
+ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
@@ -176,6 +178,57 @@
#define AR9280_TX_GAIN_TABLE_SIZE 22
+#define AR9287_EEP_VER 0xE
+#define AR9287_EEP_VER_MINOR_MASK 0xFFF
+#define AR9287_EEP_MINOR_VER_1 0x1
+#define AR9287_EEP_MINOR_VER_2 0x2
+#define AR9287_EEP_MINOR_VER_3 0x3
+#define AR9287_EEP_MINOR_VER AR9287_EEP_MINOR_VER_3
+#define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER
+#define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1
+
+#define AR9287_EEP_START_LOC 128
+#define AR9287_NUM_2G_CAL_PIERS 3
+#define AR9287_NUM_2G_CCK_TARGET_POWERS 3
+#define AR9287_NUM_2G_20_TARGET_POWERS 3
+#define AR9287_NUM_2G_40_TARGET_POWERS 3
+#define AR9287_NUM_CTLS 12
+#define AR9287_NUM_BAND_EDGES 4
+#define AR9287_NUM_PD_GAINS 4
+#define AR9287_PD_GAINS_IN_MASK 4
+#define AR9287_PD_GAIN_ICEPTS 1
+#define AR9287_EEPROM_MODAL_SPURS 5
+#define AR9287_MAX_RATE_POWER 63
+#define AR9287_NUM_PDADC_VALUES 128
+#define AR9287_NUM_RATES 16
+#define AR9287_BCHAN_UNUSED 0xFF
+#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR9287_OPFLAGS_11A 0x01
+#define AR9287_OPFLAGS_11G 0x02
+#define AR9287_OPFLAGS_2G_HT40 0x08
+#define AR9287_OPFLAGS_2G_HT20 0x20
+#define AR9287_OPFLAGS_5G_HT40 0x04
+#define AR9287_OPFLAGS_5G_HT20 0x10
+#define AR9287_EEPMISC_BIG_ENDIAN 0x01
+#define AR9287_EEPMISC_WOW 0x02
+#define AR9287_MAX_CHAINS 2
+#define AR9287_ANT_16S 32
+#define AR9287_custdatasize 20
+
+#define AR9287_NUM_ANT_CHAIN_FIELDS 6
+#define AR9287_NUM_ANT_COMMON_FIELDS 4
+#define AR9287_SIZE_ANT_CHAIN_FIELD 2
+#define AR9287_SIZE_ANT_COMMON_FIELD 4
+#define AR9287_ANT_CHAIN_MASK 0x3
+#define AR9287_ANT_COMMON_MASK 0xf
+#define AR9287_CHAIN_0_IDX 0
+#define AR9287_CHAIN_1_IDX 1
+#define AR9287_DATA_SZ 32
+
+#define AR9287_PWR_TABLE_OFFSET_DB -5
+
+#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
@@ -199,7 +252,11 @@ enum eeprom_param {
EEP_OL_PWRCTRL,
EEP_RC_CHAIN_MASK,
EEP_DAC_HPWR_5G,
- EEP_FRAC_N_5G
+ EEP_FRAC_N_5G,
+ EEP_DEV_TYPE,
+ EEP_TEMPSENSE_SLOPE,
+ EEP_TEMPSENSE_SLOPE_PAL_ON,
+ EEP_PWR_TABLE_OFFSET
};
enum ar5416_rates {
@@ -368,6 +425,65 @@ struct modal_eep_4k_header {
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
} __packed;
+struct base_eep_ar9287_header {
+ u16 length;
+ u16 checksum;
+ u16 version;
+ u8 opCapFlags;
+ u8 eepMisc;
+ u16 regDmn[2];
+ u8 macAddr[6];
+ u8 rxMask;
+ u8 txMask;
+ u16 rfSilent;
+ u16 blueToothOptions;
+ u16 deviceCap;
+ u32 binBuildNumber;
+ u8 deviceType;
+ u8 openLoopPwrCntl;
+ int8_t pwrTableOffset;
+ int8_t tempSensSlope;
+ int8_t tempSensSlopePalOn;
+ u8 futureBase[29];
+} __packed;
+
+struct modal_eep_ar9287_header {
+ u32 antCtrlChain[AR9287_MAX_CHAINS];
+ u32 antCtrlCommon;
+ int8_t antennaGainCh[AR9287_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR9287_MAX_CHAINS];
+ u8 rxTxMarginCh[AR9287_MAX_CHAINS];
+ int8_t adcDesiredSize;
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ int8_t iqCalICh[AR9287_MAX_CHAINS];
+ int8_t iqCalQCh[AR9287_MAX_CHAINS];
+ u8 pdGainOverlap;
+ u8 xpaBiasLvl;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR9287_MAX_CHAINS];
+ u8 bswMargin[AR9287_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 version;
+ u8 db1;
+ u8 db2;
+ u8 ob_cck;
+ u8 ob_psk;
+ u8 ob_qam;
+ u8 ob_pal_off;
+ u8 futureModal[30];
+ struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
+} __packed;
+
+
struct cal_data_per_freq {
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
@@ -402,6 +518,29 @@ struct cal_ctl_edges {
} __packed;
#endif
+struct cal_data_op_loop_ar9287 {
+ u8 pwrPdg[2][5];
+ u8 vpdPdg[2][5];
+ u8 pcdac[2][5];
+ u8 empty[2][5];
+} __packed;
+
+
+struct cal_data_per_freq_ar9287 {
+ u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+} __packed;
+
+union cal_data_per_freq_ar9287_u {
+ struct cal_data_op_loop_ar9287 calDataOpen;
+ struct cal_data_per_freq_ar9287 calDataClose;
+} __packed;
+
+struct cal_ctl_data_ar9287 {
+ struct cal_ctl_edges
+ ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES];
+} __packed;
+
struct cal_ctl_data {
struct cal_ctl_edges
ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
@@ -461,6 +600,27 @@ struct ar5416_eeprom_4k {
u8 padding;
} __packed;
+struct ar9287_eeprom_t {
+ struct base_eep_ar9287_header baseEepHeader;
+ u8 custData[AR9287_DATA_SZ];
+ struct modal_eep_ar9287_header modalHeader;
+ u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS];
+ union cal_data_per_freq_ar9287_u
+ calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
+ struct cal_target_power_leg
+ calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
+ struct cal_target_power_leg
+ calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
+ u8 ctlIndex[AR9287_NUM_CTLS];
+ struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS];
+ u8 padding;
+} __packed;
+
+
enum reg_ext_bitmap {
REG_EXT_JAPAN_MIDBAND = 1,
REG_EXT_FCC_DFS_HT40 = 2,
@@ -480,6 +640,7 @@ struct ath9k_country_entry {
enum ath9k_eep_map {
EEP_MAP_DEFAULT = 0x0,
EEP_MAP_4KBITS,
+ EEP_MAP_AR9287,
EEP_MAP_MAX
};
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 34935a8ee59d..431854ccb65b 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -380,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid)
return "Atheros 9280";
case AR9285_DEVID_PCIE:
return "Atheros 9285";
+ case AR5416_DEVID_AR9287_PCI:
+ case AR5416_DEVID_AR9287_PCIE:
+ return "Atheros 9287";
}
return NULL;
@@ -475,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
ah->gbeacon_rate = 0;
+ ah->power_mode = ATH9K_PM_UNDEFINED;
+
return ah;
}
@@ -660,7 +665,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
(ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
(ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
- (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
+ (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) &&
+ (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) {
DPRINTF(sc, ATH_DBG_FATAL,
"Mac Chip Rev 0x%02x.%x is not supported by "
"this driver\n", ah->hw_version.macVersion,
@@ -700,8 +706,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
ah->ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+ ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+ if (ah->config.pcie_clock_req)
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_off_L1_9287_1_1,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+ else
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+ 2);
+ } else if (AR_SREV_9287_10_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
+ ARRAY_SIZE(ar9287Common_9287_1_0), 2);
+
+ if (ah->config.pcie_clock_req)
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_off_L1_9287_1_0,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
+ else
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
+ ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
+ 2);
+ } else if (AR_SREV_9285_12_OR_LATER(ah)) {
- if (AR_SREV_9285_12_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
@@ -842,7 +877,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (ecode != 0)
goto bad;
- if (AR_SREV_9285_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9287Modes_rx_gain_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+ else if (AR_SREV_9287_10(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9287Modes_rx_gain_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
+ else if (AR_SREV_9280_20(ah))
+ ath9k_hw_init_rxgain_ini(ah);
+
+ if (AR_SREV_9287_11(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9287Modes_tx_gain_9287_1_1,
+ ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+ } else if (AR_SREV_9287_10(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9287Modes_tx_gain_9287_1_0,
+ ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
+ } else if (AR_SREV_9280_20(ah)) {
+ ath9k_hw_init_txgain_ini(ah);
+ } else if (AR_SREV_9285_12_OR_LATER(ah)) {
u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
/* txgain table */
@@ -858,14 +914,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
- /* rxgain table */
- if (AR_SREV_9280_20(ah))
- ath9k_hw_init_rxgain_ini(ah);
-
- /* txgain table */
- if (AR_SREV_9280_20(ah))
- ath9k_hw_init_txgain_ini(ah);
-
ath9k_hw_fill_cap_info(ah);
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@@ -1165,6 +1213,8 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE:
case AR9285_DEVID_PCIE:
+ case AR5416_DEVID_AR9287_PCI:
+ case AR5416_DEVID_AR9287_PCIE:
ah = ath9k_hw_do_attach(devid, sc, error);
break;
default:
@@ -1341,10 +1391,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
DO_DELAY(regWrites);
}
- if (AR_SREV_9280(ah))
+ if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
- if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah))
+ if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+ AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@@ -2254,6 +2305,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+ if (AR_SREV_9287_10_OR_LATER(ah)) {
+ /* Enable ASYNC FIFO */
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+ REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+ REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ 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);
if (r)
return r;
@@ -2330,6 +2391,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_user_settings(ah);
+ if (AR_SREV_9287_10_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+ AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+ AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+ AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+ REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+ REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+ REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+ AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+ REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+ AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+ }
+ if (AR_SREV_9287_10_OR_LATER(ah)) {
+ REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+ }
+
REG_WRITE(ah, AR_STA_ID1,
REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
@@ -2345,7 +2427,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_bb(ah, chan);
if (!ath9k_hw_init_cal(ah, chan))
- return -EIO;;
+ return -EIO;
rx_chainmask = ah->rxchainmask;
if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2728,7 +2810,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+ enum ath9k_power_mode mode)
{
int status = true, setChip = true;
static const char *modes[] = {
@@ -2738,6 +2821,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
"UNDEFINED"
};
+ if (ah->power_mode == mode)
+ return status;
+
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
modes[ah->power_mode], modes[mode]);
@@ -2762,6 +2848,51 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_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);
+}
+
/*
* Helper for ASPM support.
*
@@ -3305,7 +3436,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
if (ah->config.ht_enable) {
if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3595,7 +3725,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
if (gpio >= ah->caps.num_gpio_pins)
return 0xffffffff;
- if (AR_SREV_9285_10_OR_LATER(ah))
+ if (AR_SREV_9287_10_OR_LATER(ah))
+ return MS_REG_READ(AR9287, gpio) != 0;
+ else if (AR_SREV_9285_10_OR_LATER(ah))
return MS_REG_READ(AR9285, gpio) != 0;
else if (AR_SREV_9280_10_OR_LATER(ah))
return MS_REG_READ(AR928X, gpio) != 0;
@@ -3791,19 +3923,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- int count;
+ 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");
- count = 0;
- while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
- count++;
- if (count > 10) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- break;
- }
- udelay(10);
- }
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+ ath9k_ps_restore(ah->ah_sc);
}
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d0b31ad4603..2e196df10894 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -42,6 +42,9 @@
#define AR_SUBVENDOR_ID_NEW_A 0x7065
#define AR5416_MAGIC 0x19641014
+#define AR5416_DEVID_AR9287_PCI 0x002D
+#define AR5416_DEVID_AR9287_PCIE 0x002E
+
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
@@ -95,6 +98,7 @@
#define MAX_RATE_POWER 63
#define AH_WAIT_TIMEOUT 100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000
@@ -113,15 +117,14 @@
enum wireless_mode {
ATH9K_MODE_11A = 0,
- ATH9K_MODE_11B = 2,
- ATH9K_MODE_11G = 3,
- ATH9K_MODE_11NA_HT20 = 6,
- ATH9K_MODE_11NG_HT20 = 7,
- ATH9K_MODE_11NA_HT40PLUS = 8,
- ATH9K_MODE_11NA_HT40MINUS = 9,
- ATH9K_MODE_11NG_HT40PLUS = 10,
- ATH9K_MODE_11NG_HT40MINUS = 11,
- ATH9K_MODE_MAX
+ ATH9K_MODE_11G,
+ ATH9K_MODE_11NA_HT20,
+ ATH9K_MODE_11NG_HT20,
+ ATH9K_MODE_11NA_HT40PLUS,
+ ATH9K_MODE_11NA_HT40MINUS,
+ ATH9K_MODE_11NG_HT40PLUS,
+ ATH9K_MODE_11NG_HT40MINUS,
+ ATH9K_MODE_MAX,
};
enum ath9k_hw_caps {
@@ -400,6 +403,7 @@ struct ath_hw {
union {
struct ar5416_eeprom_def def;
struct ar5416_eeprom_4k map4k;
+ struct ar9287_eeprom_t map9287;
} eeprom;
const struct eeprom_ops *eep_ops;
enum ath9k_eep_map eep_map;
@@ -417,7 +421,6 @@ struct ath_hw {
enum nl80211_iftype opmode;
enum ath9k_power_mode power_mode;
- enum ath9k_power_mode restore_mode;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
struct ar5416Stats stats;
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34b79a1..af4a1bafa7e7 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 */
+/* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
{ 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
{ 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
{ 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
{ 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
{ 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
- { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+ { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+ { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+ { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
};
static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
@@ -4846,3 +4849,1519 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
};
+
+/* AR9287 Revision 10 */
+static const u_int32_t ar9287Modes_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
+ { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
+ { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
+ { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u_int32_t ar9287Common_9287_1_0[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007020, 0x00000000 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x18487320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d4, 0x00000000 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x000000ff },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x01c81043 },
+ { 0x00008360, 0xffffffff },
+ { 0x00008364, 0xffffffff },
+ { 0x00008368, 0x00000000 },
+ { 0x00008370, 0x00000000 },
+ { 0x00008374, 0x000000ff },
+ { 0x00008378, 0x00000000 },
+ { 0x0000837c, 0x00000000 },
+ { 0x00008380, 0xffffffff },
+ { 0x00008384, 0xffffffff },
+ { 0x00008390, 0x0fffffff },
+ { 0x00008394, 0x0fffffff },
+ { 0x00008398, 0x00000000 },
+ { 0x0000839c, 0x00000000 },
+ { 0x000083a0, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x10002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009930, 0x00000000 },
+ { 0x0000a930, 0x00000000 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x00009970, 0x990bb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x0c6f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099c4, 0x06336f77 },
+ { 0x000099c8, 0x6af65329 },
+ { 0x000099cc, 0x08f186c8 },
+ { 0x000099d0, 0x00046384 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+ { 0x0000a208, 0x803e4788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f7180 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a264, 0x00418a11 },
+ { 0x0000b264, 0x00418a11 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000b398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a1e },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000b3f4, 0x00000000 },
+ { 0x0000a7d8, 0x00000001 },
+ { 0x00007800, 0x00000800 },
+ { 0x00007804, 0x6c35ffb0 },
+ { 0x00007808, 0x6db6c000 },
+ { 0x0000780c, 0x6db6cb30 },
+ { 0x00007810, 0x6db6cb6c },
+ { 0x00007814, 0x0501e200 },
+ { 0x00007818, 0x0094128d },
+ { 0x0000781c, 0x976ee392 },
+ { 0x00007820, 0xf75ff6fc },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb003012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x00140000 },
+ { 0x00007838, 0x0e4548d8 },
+ { 0x0000783c, 0x54214514 },
+ { 0x00007840, 0x02025820 },
+ { 0x00007844, 0x71c0d388 },
+ { 0x00007848, 0x934934a8 },
+ { 0x00007850, 0x00000000 },
+ { 0x00007854, 0x00000800 },
+ { 0x00007858, 0x6c35ffb0 },
+ { 0x0000785c, 0x6db6c000 },
+ { 0x00007860, 0x6db6cb2c },
+ { 0x00007864, 0x6db6cb6c },
+ { 0x00007868, 0x0501e200 },
+ { 0x0000786c, 0x0094128d },
+ { 0x00007870, 0x976ee392 },
+ { 0x00007874, 0xf75ff6fc },
+ { 0x00007878, 0x00040000 },
+ { 0x0000787c, 0xdb003012 },
+ { 0x00007880, 0x04924914 },
+ { 0x00007884, 0x21084210 },
+ { 0x00007888, 0x001b6db0 },
+ { 0x0000788c, 0x00376b63 },
+ { 0x00007890, 0x06db6db6 },
+ { 0x00007894, 0x006d8000 },
+ { 0x00007898, 0x48100000 },
+ { 0x0000789c, 0x00000000 },
+ { 0x000078a0, 0x08000000 },
+ { 0x000078a4, 0x0007ffd8 },
+ { 0x000078a8, 0x0007ffd8 },
+ { 0x000078ac, 0x001c0020 },
+ { 0x000078b0, 0x000611eb },
+ { 0x000078b4, 0x40008080 },
+ { 0x000078b8, 0x2a850160 },
+};
+
+static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
+ { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
+ { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
+ { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
+ { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
+ { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
+ { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 },
+ { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 },
+ { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 },
+ { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 },
+ { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 },
+ { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 },
+ { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 },
+ { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 },
+ { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 },
+ { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe },
+ { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e },
+ { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e },
+ { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be },
+ { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
+ { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+};
+
+
+static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+ { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+/* AR9287 Revision 11 */
+
+static const u_int32_t ar9287Modes_9287_1_1[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
+ { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
+ { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 },
+ { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
+ { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u_int32_t ar9287Common_9287_1_1[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007020, 0x00000000 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x18487320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d4, 0x00000000 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0x88a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x000000ff },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x01c81043 },
+ { 0x00008360, 0xffffffff },
+ { 0x00008364, 0xffffffff },
+ { 0x00008368, 0x00000000 },
+ { 0x00008370, 0x00000000 },
+ { 0x00008374, 0x000000ff },
+ { 0x00008378, 0x00000000 },
+ { 0x0000837c, 0x00000000 },
+ { 0x00008380, 0xffffffff },
+ { 0x00008384, 0xffffffff },
+ { 0x00008390, 0x0fffffff },
+ { 0x00008394, 0x0fffffff },
+ { 0x00008398, 0x00000000 },
+ { 0x0000839c, 0x00000000 },
+ { 0x000083a0, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x10002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009930, 0x00000000 },
+ { 0x0000a930, 0x00000000 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x00009970, 0x990bb514 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x0c6f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099c4, 0x06336f77 },
+ { 0x000099c8, 0x6af6532f },
+ { 0x000099cc, 0x08f186c8 },
+ { 0x000099d0, 0x00046384 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+ { 0x0000a208, 0x803e4788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f7180 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a264, 0x00418a11 },
+ { 0x0000b264, 0x00418a11 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000b398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a1e },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000b3f4, 0x00000000 },
+ { 0x0000a7d8, 0x000003f1 },
+ { 0x00007800, 0x00000800 },
+ { 0x00007804, 0x6c35ffc2 },
+ { 0x00007808, 0x6db6c000 },
+ { 0x0000780c, 0x6db6cb30 },
+ { 0x00007810, 0x6db6cb6c },
+ { 0x00007814, 0x0501e200 },
+ { 0x00007818, 0x0094128d },
+ { 0x0000781c, 0x976ee392 },
+ { 0x00007820, 0xf75ff6fc },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb003012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x00140000 },
+ { 0x00007838, 0x0e4548d8 },
+ { 0x0000783c, 0x54214514 },
+ { 0x00007840, 0x02025830 },
+ { 0x00007844, 0x71c0d388 },
+ { 0x00007848, 0x934934a8 },
+ { 0x00007850, 0x00000000 },
+ { 0x00007854, 0x00000800 },
+ { 0x00007858, 0x6c35ffc2 },
+ { 0x0000785c, 0x6db6c000 },
+ { 0x00007860, 0x6db6cb30 },
+ { 0x00007864, 0x6db6cb6c },
+ { 0x00007868, 0x0501e200 },
+ { 0x0000786c, 0x0094128d },
+ { 0x00007870, 0x976ee392 },
+ { 0x00007874, 0xf75ff6fc },
+ { 0x00007878, 0x00040000 },
+ { 0x0000787c, 0xdb003012 },
+ { 0x00007880, 0x04924914 },
+ { 0x00007884, 0x21084210 },
+ { 0x00007888, 0x001b6db0 },
+ { 0x0000788c, 0x00376b63 },
+ { 0x00007890, 0x06db6db6 },
+ { 0x00007894, 0x006d8000 },
+ { 0x00007898, 0x48100000 },
+ { 0x0000789c, 0x00000000 },
+ { 0x000078a0, 0x08000000 },
+ { 0x000078a4, 0x0007ffd8 },
+ { 0x000078a8, 0x0007ffd8 },
+ { 0x000078ac, 0x001c0020 },
+ { 0x000078b0, 0x00060aeb },
+ { 0x000078b4, 0x40008080 },
+ { 0x000078b8, 0x2a850160 },
+};
+
+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 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
+ { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
+ { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
+ { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
+ { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
+ { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
+ { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 },
+ { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 },
+ { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 },
+ { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa },
+ { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac },
+ { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 },
+ { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 },
+ { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 },
+ { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 },
+ { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c },
+ { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e },
+ { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be },
+ { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
+ { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+};
+
+static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
+ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
+ { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+ { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 8ae4ec21667b..6f923e318727 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
- ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
- ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
- ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
- ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
- ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
- ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
- ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+ ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+ } else {
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt11);
+ ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt12);
+ }
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
else
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 66a6c1f5022a..75ddb2acb644 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -17,8 +17,6 @@
#include <linux/nl80211.h>
#include "ath9k.h"
-#define ATH_PCI_VERSION "0.1"
-
static char *dev_info = "ath9k";
MODULE_AUTHOR("Atheros Communications");
@@ -342,6 +340,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning.
* we are most likely not on our home channel.
*/
+ spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;
@@ -405,6 +404,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);
set_timer:
+ spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -460,9 +460,10 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an);
- an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}
@@ -496,8 +497,7 @@ static void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_TX)
ath_tx_tasklet(sc);
- if ((status & ATH9K_INT_TSFOOR) &&
- (sc->hw->conf.flags & IEEE80211_CONF_PS)) {
+ if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
/*
* TSF sync does not look correct; remain awake to sync with
* the next Beacon.
@@ -885,8 +885,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)
{
-#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
-#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
+ u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -894,50 +893,48 @@ static void setup_ht_cap(struct ath_softc *sc,
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
- ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
- ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
+ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
/* 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;
- switch(sc->rx_chainmask) {
- case 1:
- ht_info->mcs.rx_mask[0] = 0xff;
- break;
- case 3:
- case 5:
- case 7:
- default:
- ht_info->mcs.rx_mask[0] = 0xff;
- ht_info->mcs.rx_mask[1] = 0xff;
- break;
+ if (tx_streams != rx_streams) {
+ DPRINTF(sc, 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);
}
- ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_info->mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ ht_info->mcs.rx_mask[1] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_vif *avp = (void *)vif->drv_priv;
if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->curbssid);
/* New association, store aid */
- if (avp->av_opmode == NL80211_IFTYPE_STATION) {
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ sc->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc);
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->sc_flags |= SC_OP_BEACON_SYNC;
- }
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->sc_flags |= SC_OP_BEACON_SYNC;
/* Configure the beacon */
ath_beacon_config(sc, vif);
@@ -952,6 +949,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
} else {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
+ /* Stop ANI */
+ del_timer_sync(&sc->ani.timer);
}
}
@@ -1255,6 +1254,7 @@ void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1281,7 +1281,6 @@ void ath_detach(struct ath_softc *sc)
ath9k_hw_detach(sc->sc_ah);
ath9k_exit_debug(sc);
- ath9k_ps_restore(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1311,6 +1310,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->ani_lock);
+ spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -1536,7 +1537,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->max_rates = 4;
hw->channel_change_time = 5000;
hw->max_listen_interval = 10;
- hw->max_rate_tries = ATH_11N_TXMAXTRY;
+ /* Hardware supports 10 but we use 4 */
+ hw->max_rate_tries = 4;
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
@@ -1973,6 +1975,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -1994,7 +1998,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
goto exit;
}
- if (sc->hw->conf.flags & IEEE80211_CONF_PS) {
+ if (sc->ps_enabled) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
/*
* mac80211 does not set PM field for normal data frames, so we
@@ -2092,8 +2096,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
- ieee80211_stop_queues(hw);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
@@ -2196,7 +2198,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP ||
+ conf->type == NL80211_IFTYPE_ADHOC ||
+ conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);
out:
@@ -2249,9 +2253,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
+ bool all_wiphys_idle = false, disable_radio = false;
mutex_lock(&sc->mutex);
+ /* Leave this as the first check */
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+ spin_lock_bh(&sc->wiphy_lock);
+ all_wiphys_idle = ath9k_all_wiphys_idle(sc);
+ spin_unlock_bh(&sc->wiphy_lock);
+
+ if (conf->flags & IEEE80211_CONF_IDLE){
+ if (all_wiphys_idle)
+ disable_radio = true;
+ }
+ else if (all_wiphys_idle) {
+ ath_radio_enable(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps &
@@ -2263,8 +2286,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
ath9k_hw_setrxabort(sc->sc_ah, 1);
}
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+ sc->ps_enabled = true;
} else {
+ sc->ps_enabled = false;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -2319,6 +2343,11 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
+ if (disable_radio) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_radio_disable(sc);
+ }
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2638,19 +2667,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
- ret = ath_tx_aggr_start(sc, sta, tid, ssn);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to start TX aggregation\n");
- else
- ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ ath_tx_aggr_start(sc, sta, tid, ssn);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
- ret = ath_tx_aggr_stop(sc, sta, tid);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to stop TX aggregation\n");
-
+ ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2681,9 +2702,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2691,11 +2712,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
struct ieee80211_ops ath9k_ops = {
@@ -2728,7 +2749,8 @@ static struct {
{ AR_SREV_VERSION_9100, "9100" },
{ AR_SREV_VERSION_9160, "9160" },
{ AR_SREV_VERSION_9280, "9280" },
- { AR_SREV_VERSION_9285, "9285" }
+ { AR_SREV_VERSION_9285, "9285" },
+ { AR_SREV_VERSION_9287, "9287" }
};
static struct {
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 170c5b32e49b..cd4841be80af 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ 0 }
};
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index c70f530642f6..de4fadadbce5 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -375,6 +375,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_CHAN_INFO_GAIN 0x9CFC
#define AR_PHY_MODE 0xA200
+#define AR_PHY_MODE_ASYNCFIFO 0x80
#define AR_PHY_MODE_AR2133 0x08
#define AR_PHY_MODE_AR5111 0x00
#define AR_PHY_MODE_AR5112 0x08
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba06e78b2f50..a07efa22551e 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -22,133 +22,132 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 0, 2, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 1, 1, 1, 0 },
+ 0, 1, 1, 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 2, 4, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 3, 3, 3, 0 },
+ 2, 3, 3, 3, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 4, 10, 3, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 20, 3, 6, 6, 6, 6, 0 },
+ 4, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 7, 7, 7, 0 },
+ 4, 7, 7, 7, 7, 0 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 8, 24, 3216 },
+ 0, 8, 24, 8, 24, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 9, 25, 6434 },
+ 2, 9, 25, 9, 25, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 10, 26, 9650 },
+ 2, 10, 26, 10, 26, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 11, 27, 12868 },
+ 4, 11, 27, 11, 27, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 12, 28, 19304 },
+ 4, 12, 28, 12, 28, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 13, 29, 25740 },
+ 4, 13, 29, 13, 29, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 14, 30, 28956 },
+ 4, 14, 30, 14, 30, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 15, 32, 32180 },
+ 4, 15, 31, 15, 32, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
- 8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+ 8, 3, 16, 33, 16, 33, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 17, 34, 12860 },
+ 2, 17, 34, 17, 34, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 18, 35, 19300 },
+ 2, 18, 35, 18, 35, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 19, 36, 25736 },
+ 4, 19, 36, 19, 36, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 20, 37, 38600 },
+ 4, 20, 37, 20, 37, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 21, 38, 51472 },
+ 4, 21, 38, 21, 38, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 22, 39, 57890 },
+ 4, 22, 39, 22, 39, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 23, 41, 64320 },
+ 4, 23, 40, 23, 41, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 24, 24, 6684 },
+ 0, 8, 24, 24, 24, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 25, 25, 13368 },
+ 2, 9, 25, 25, 25, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 26, 26, 20052 },
+ 2, 10, 26, 26, 26, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 27, 27, 26738 },
+ 4, 11, 27, 27, 27, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 28, 28, 40104 },
+ 4, 12, 28, 28, 28, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 29, 29, 53476 },
+ 4, 13, 29, 29, 29, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 30, 30, 60156 },
+ 4, 14, 30, 30, 30, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 66840 },
+ 4, 15, 31, 32, 32, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 74200 },
+ 4, 15, 31, 32, 32, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 0, 2, 3, 16, 33, 33, 33, 13360 },
+ 0, 16, 33, 33, 33, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 34, 34, 26720 },
+ 2, 17, 34, 34, 34, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 35, 35, 40080 },
+ 2, 18, 35, 35, 35, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 36, 36, 53440 },
+ 4, 19, 36, 36, 36, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 37, 37, 80160 },
+ 4, 20, 37, 37, 37, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 38, 38, 106880 },
+ 4, 21, 38, 38, 38, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 39, 39, 120240 },
+ 4, 22, 39, 39, 39, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 133600 },
+ 4, 23, 40, 41, 41, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 148400 },
+ 4, 23, 40, 41, 41, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -160,145 +159,144 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 1, 1, 1, 0 },
+ 1, 1, 1, 1, 1, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 3, 3, 3, 0 },
+ 3, 3, 3, 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 6, 6, 6, 0 },
+ 6, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 7, 7, 7, 0 },
+ 6, 7, 7, 7, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
- 8, 10, 3, 8, 8, 8, 8, 0 },
+ 8, 8, 8, 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 9, 9, 9, 0 },
+ 8, 9, 9, 9, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 20, 3, 10, 10, 10, 10, 0 },
+ 8, 10, 10, 10, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 11, 11, 11, 0 },
+ 8, 11, 11, 11, 11, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 4, 2, 3, 12, 28, 12, 28, 3216 },
+ 4, 12, 28, 12, 28, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 6, 4, 3, 13, 29, 13, 29, 6434 },
+ 6, 13, 29, 13, 29, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 6, 6, 3, 14, 30, 14, 30, 9650 },
+ 6, 14, 30, 14, 30, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 15, 31, 12868 },
+ 8, 15, 31, 15, 31, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 16, 32, 19304 },
+ 8, 16, 32, 16, 32, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 17, 33, 25740 },
+ 8, 17, 33, 17, 33, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 18, 34, 28956 },
+ 8, 18, 34, 18, 34, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 19, 36, 32180 },
+ 8, 19, 35, 19, 36, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
- 4, 2, 3, 20, 37, 20, 37, 6430 },
+ 4, 20, 37, 20, 37, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 6, 4, 3, 21, 38, 21, 38, 12860 },
+ 6, 21, 38, 21, 38, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 6, 6, 3, 22, 39, 22, 39, 19300 },
+ 6, 22, 39, 22, 39, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 23, 40, 25736 },
+ 8, 23, 40, 23, 40, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 24, 41, 38600 },
+ 8, 24, 41, 24, 41, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 25, 42, 51472 },
+ 8, 25, 42, 25, 42, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 26, 44, 57890 },
+ 8, 26, 43, 26, 44, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 27, 45, 64320 },
+ 8, 27, 44, 27, 45, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 8, 2, 3, 12, 28, 28, 28, 6684 },
+ 8, 12, 28, 28, 28, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 8, 4, 3, 13, 29, 29, 29, 13368 },
+ 8, 13, 29, 29, 29, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 8, 6, 3, 14, 30, 30, 30, 20052 },
+ 8, 14, 30, 30, 30, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 31, 31, 26738 },
+ 8, 15, 31, 31, 31, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 32, 32, 40104 },
+ 8, 16, 32, 32, 32, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 33, 33, 53476 },
+ 8, 17, 33, 33, 33, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 34, 34, 60156 },
+ 8, 18, 34, 34, 34, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 8, 23, 3, 19, 35, 36, 36, 66840 },
+ 8, 19, 35, 36, 36, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 36, 36, 74200 },
+ 8, 19, 35, 36, 36, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 8, 2, 3, 20, 37, 37, 37, 13360 },
+ 8, 20, 37, 37, 37, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 8, 4, 3, 21, 38, 38, 38, 26720 },
+ 8, 21, 38, 38, 38, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 8, 6, 3, 22, 39, 39, 39, 40080 },
+ 8, 22, 39, 39, 39, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 40, 40, 53440 },
+ 8, 23, 40, 40, 40, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 41, 41, 80160 },
+ 8, 24, 41, 41, 41, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 42, 42, 106880 },
+ 8, 25, 42, 42, 42, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 43, 43, 120240 },
+ 8, 26, 43, 43, 43, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 8, 23, 3, 27, 44, 45, 45, 133600 },
+ 8, 27, 44, 45, 45, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 45, 45, 148400 },
+ 8, 27, 44, 45, 45, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -307,31 +305,30 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
- 0, 2, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 0 },
+ 0, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
- 2, 4, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 0 },
+ 2, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
- 4, 10, 3, 4, 0 },
+ 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 19, 3, 6, 0 },
+ 4, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 0 },
+ 4, 7, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -340,64 +337,42 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 0 },
+ 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 0 },
+ 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 0 },
+ 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 0 },
+ 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 0 },
+ 6, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 8, 10, 3, 8, 0 },
+ 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 0 },
+ 8, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 19, 3, 10, 0 },
+ 8, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 0 },
+ 8, 11, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11b_ratetable = {
- 4,
- {
- { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0x1b, 0x00, (0x80|2),
- 0, 0, 1, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1800, 0x1a, 0x04, (0x80|4),
- 1, 1, 1, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4300, 0x19, 0x04, (0x80|11),
- 1, 2, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 7100, 0x18, 0x04, (0x80|22),
- 1, 4, 100, 3, 0 },
- },
- 100, /* probe interval */
- 100, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -454,13 +429,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
- u8 index)
-{
- ASSERT(index <= ath_rc_priv->rate_table_size);
- return ath_rc_priv->valid_rate_index[index];
-}
-
static inline
int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
@@ -501,9 +469,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate, u8 *next_idx)
+ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
@@ -629,52 +597,20 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
return hi;
}
-static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- int *is_probing)
+/* Finds the highest rate index we can use */
+static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ int *is_probing)
{
- u32 dt, best_thruput, this_thruput, now_msec;
+ u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
- int8_t rssi_last, rssi_reduce = 0, index = 0;
-
- *is_probing = 0;
-
- rssi_last = median(ath_rc_priv->rssi_last,
- ath_rc_priv->rssi_last_prev,
- ath_rc_priv->rssi_last_prev2);
-
- /*
- * Age (reduce) last ack rssi based on how old it is.
- * The bizarre numbers are so the delta is 160msec,
- * meaning we divide by 16.
- * 0msec <= dt <= 25msec: don't derate
- * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB
- * 185msec <= dt: derate by 10dB
- */
+ int8_t index = 0;
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - ath_rc_priv->rssi_time;
-
- if (dt >= 185)
- rssi_reduce = 10;
- else if (dt >= 25)
- rssi_reduce = (u8)((dt - 25) >> 4);
-
- /* Now reduce rssi_last by rssi_reduce */
- if (rssi_last < rssi_reduce)
- rssi_last = 0;
- else
- rssi_last -= rssi_reduce;
-
- /*
- * Now look up the rate in the rssi table and return it.
- * If no rates match then we return 0 (lowest rate)
- */
-
+ *is_probing = 0;
best_thruput = 0;
maxindex = ath_rc_priv->max_valid_rate-1;
-
minindex = 0;
best_rate = minindex;
@@ -700,7 +636,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = ath_rc_priv->state[rate].per;
+ per_thres = ath_rc_priv->per[rate];
if (per_thres < 12)
per_thres = 12;
@@ -714,7 +650,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
}
rate = best_rate;
- ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
@@ -741,10 +676,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- ASSERT((rate_table->info[rate].valid &&
- (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
- (rate_table->info[rate].valid_single_stream &&
- !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+ if (rate_table->info[rate].valid &&
+ (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ return rate;
+
+ if (rate_table->info[rate].valid_single_stream &&
+ !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+ return rate;
+
+ /* This should not happen */
+ WARN_ON(1);
+
+ rate = ath_rc_priv->valid_rate_index[0];
return rate;
}
@@ -796,7 +739,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
* just CTS. Note that this is only done for OFDM/HT unicast frames.
*/
if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
- !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
@@ -806,50 +748,37 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
tx_info->control.rts_cts_rate_idx = cix;
}
-static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 rix, u16 stepdown,
- u16 min_rate)
-{
- u32 j;
- u8 nextindex = 0;
-
- if (min_rate) {
- for (j = RATE_TABLE_SIZE; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- } else {
- for (j = stepdown; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- }
- return rix;
-}
-
-static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_rate_control *txrc)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
+ struct ath_softc *sc = priv;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate = 0, i = 0, rix, nrix;
+ u8 try_per_rate, i = 0, rix, nrix;
int is_probe = 0;
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ /*
+ * For Multi Rate Retry we use a different number of
+ * retry attempt counts. This ends up looking like this:
+ *
+ * MRR[0] = 2
+ * MRR[1] = 2
+ * MRR[2] = 2
+ * MRR[3] = 4
+ *
+ */
+ try_per_rate = sc->hw->max_rate_tries;
+
rate_table = sc->cur_rate_table;
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
nrix = rix;
if (is_probe) {
@@ -858,18 +787,15 @@ static void ath_rc_ratefind(struct ath_softc *sc,
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, nrix, 0);
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, 0);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
@@ -877,18 +803,14 @@ static void ath_rc_ratefind(struct ath_softc *sc,
/* Fill in the other rates for multirate retry */
for ( ; i < 4; i++) {
- u8 try_num;
- u8 min_rate;
-
- try_num = ((i + 1) == 4) ?
- ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == 4) && 0);
+ /* Use twice the number of tries for the last MRR segment. */
+ if (i + 1 == 4)
+ try_per_rate = 4;
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, min_rate);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_num, nrix, 1);
+ try_per_rate, nrix, 1);
}
/*
@@ -925,9 +847,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
*
* FIXME: Fix duration
*/
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
rates[1].count = rates[2].count = rates[3].count = 0;
rates[1].idx = rates[2].idx = rates[3].idx = 0;
rates[0].count = ATH_TXMAXTRY;
@@ -960,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc,
100 * 9 / 10
};
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
if (xretries) {
if (xretries == 1) {
- ath_rc_priv->state[tx_rate].per += 30;
- if (ath_rc_priv->state[tx_rate].per > 100)
- ath_rc_priv->state[tx_rate].per = 100;
+ ath_rc_priv->per[tx_rate] += 30;
+ if (ath_rc_priv->per[tx_rate] > 100)
+ ath_rc_priv->per[tx_rate] = 100;
} else {
/* xretries == 2 */
count = ARRAY_SIZE(nretry_to_per_lookup);
@@ -974,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
retries = count - 1;
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) + (100 >> 3));
}
@@ -1010,18 +931,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
n_frames = tx_info_priv->n_frames * (retries + 1);
cur_per = (100 * n_bad_frames / n_frames) >> 3;
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
- ath_rc_priv->state[tx_rate].per = new_per;
+ ath_rc_priv->per[tx_rate] = new_per;
}
} else {
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) +
(nretry_to_per_lookup[retries] >> 3));
}
- ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
- ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
- ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
@@ -1045,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->probe_rate;
probe_rate = ath_rc_priv->probe_rate;
- if (ath_rc_priv->state[probe_rate].per > 30)
- ath_rc_priv->state[probe_rate].per = 20;
+ if (ath_rc_priv->per[probe_rate] > 30)
+ ath_rc_priv->per[probe_rate] = 20;
ath_rc_priv->probe_rate = 0;
@@ -1065,18 +982,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
/*
* Don't update anything. We don't know if
* this was because of collisions or poor signal.
- *
- * Later: if rssi_ack is close to
- * ath_rc_priv->state[txRate].rssi_thres and we see lots
- * of retries, then we could increase
- * ath_rc_priv->state[txRate].rssi_thres.
*/
ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
- int32_t rssi_ackAvg;
- int8_t rssi_thres;
- int8_t rssi_ack_vmin;
-
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
@@ -1086,43 +994,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (tx_info_priv->tx.ts_rssi <
- rate_table->info[tx_rate].rssi_ack_validmin)
- goto exit;
-
- /* Average the rssi */
- if (tx_rate != ath_rc_priv->rssi_sum_rate) {
- ath_rc_priv->rssi_sum_rate = tx_rate;
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
- }
-
- ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_sum_cnt++;
-
- if (ath_rc_priv->rssi_sum_cnt < 4)
- goto exit;
-
- rssi_ackAvg =
- (ath_rc_priv->rssi_sum + 2) / 4;
- rssi_thres =
- ath_rc_priv->state[tx_rate].rssi_thres;
- rssi_ack_vmin =
- rate_table->info[tx_rate].rssi_ack_validmin;
-
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
-
- /* Now reduce the current rssi threshold */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- ath_rc_priv->state[tx_rate].rssi_thres--;
- }
-
- state_change = true;
}
}
-exit:
+
return state_change;
}
@@ -1134,11 +1008,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_tx_info_priv *tx_info_priv,
int tx_rate, int xretries, int retries)
{
-#define CHK_RSSI(rate) \
- ((ath_rc_priv->state[(rate)].rssi_thres + \
- rate_table->info[(rate)].rssi_ack_deltamin) > \
- ath_rc_priv->state[(rate)+1].rssi_thres)
-
u32 now_msec = jiffies_to_msecs(jiffies);
int rate;
u8 last_per;
@@ -1149,14 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
return;
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- tx_info_priv->tx.ts_rssi =
- tx_info_priv->tx.ts_rssi < 3 ? 0 :
- tx_info_priv->tx.ts_rssi - 3;
-
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
/* Update PER first */
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
@@ -1167,114 +1029,55 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
- (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
ath_rc_priv->probe_time = now_msec;
}
- if (state_change) {
- /*
- * Make sure the rates above this have higher rssi thresholds.
- * (Note: Monotonicity is kept within the OFDM rates and
- * within the CCK rates. However, no adjustment is
- * made to keep the rssi thresholds monotonically
- * increasing between the CCK and OFDM rates.)
- */
- for (rate = tx_rate; rate < size - 1; rate++) {
- if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- ath_rc_priv->state[rate+1].rssi_thres =
- ath_rc_priv->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin;
- }
- }
-
- /* Make sure the rates below this have lower rssi thresholds. */
- for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- if (ath_rc_priv->state[rate+1].rssi_thres <
- rate_table->info[rate].rssi_ack_deltamin)
- ath_rc_priv->state[rate].rssi_thres = 0;
- else {
- ath_rc_priv->state[rate].rssi_thres =
- ath_rc_priv->state[rate+1].rssi_thres -
- rate_table->info[rate].rssi_ack_deltamin;
- }
-
- if (ath_rc_priv->state[rate].rssi_thres <
- rate_table->info[rate].rssi_ack_validmin) {
- ath_rc_priv->state[rate].rssi_thres =
- rate_table->info[rate].rssi_ack_validmin;
- }
- }
- }
- }
-
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (ath_rc_priv->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->per[tx_rate] < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
break;
- if (ath_rc_priv->state[rate].per >
- ath_rc_priv->state[rate+1].per) {
- ath_rc_priv->state[rate].per =
- ath_rc_priv->state[rate+1].per;
+ if (ath_rc_priv->per[rate] >
+ ath_rc_priv->per[rate+1]) {
+ ath_rc_priv->per[rate] =
+ ath_rc_priv->per[rate+1];
}
}
}
/* Maintain monotonicity for rates above the current rate */
for (rate = tx_rate; rate < size - 1; rate++) {
- if (ath_rc_priv->state[rate+1].per <
- ath_rc_priv->state[rate].per)
- ath_rc_priv->state[rate+1].per =
- ath_rc_priv->state[rate].per;
- }
-
- /* Every so often, we reduce the thresholds and
- * PER (different for CCK and OFDM). */
- if (now_msec - ath_rc_priv->rssi_down_time >=
- rate_table->rssi_reduce_interval) {
-
- for (rate = 0; rate < size; rate++) {
- if (ath_rc_priv->state[rate].rssi_thres >
- rate_table->info[rate].rssi_ack_validmin)
- ath_rc_priv->state[rate].rssi_thres -= 1;
- }
- ath_rc_priv->rssi_down_time = now_msec;
+ if (ath_rc_priv->per[rate+1] <
+ ath_rc_priv->per[rate])
+ ath_rc_priv->per[rate+1] =
+ ath_rc_priv->per[rate];
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
if (now_msec - ath_rc_priv->per_down_time >=
- rate_table->rssi_reduce_interval) {
+ rate_table->probe_interval) {
for (rate = 0; rate < size; rate++) {
- ath_rc_priv->state[rate].per =
- 7 * ath_rc_priv->state[rate].per / 8;
+ ath_rc_priv->per[rate] =
+ 7 * ath_rc_priv->per[rate] / 8;
}
ath_rc_priv->per_down_time = now_msec;
}
ath_debug_stat_retries(sc, tx_rate, xretries, retries,
- ath_rc_priv->state[tx_rate].per);
+ ath_rc_priv->per[tx_rate]);
-#undef CHK_RSSI
}
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
@@ -1410,9 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc,
/* Initialize thresholds according to the global rate table */
for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
- ath_rc_priv->state[i].rssi_thres =
- rate_table->info[i].rssi_ack_validmin;
- ath_rc_priv->state[i].per = 0;
+ ath_rc_priv->per[i] = 0;
}
/* Determine the valid rates */
@@ -1521,7 +1322,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * Adjust the long retry as if the frame was tried hw->max_rate_tries
* times. This affects how ratectrl updates PER for the failed rate.
*/
if (tx_info_priv->tx.ts_flags &
@@ -1536,7 +1337,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
+ (is_underrun) ? sc->hw->max_rate_tries :
tx_info_priv->tx.ts_longretry);
/* Check if aggregation has to be enabled for this tid */
@@ -1560,31 +1361,6 @@ exit:
kfree(tx_info_priv);
}
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ieee80211_supported_band *sband = txrc->sband;
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- __le16 fc = hdr->frame_control;
-
- /* lowest rate for management and NO_ACK frames */
- if (!ieee80211_is_data(fc) ||
- tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) {
- tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
- tx_info->control.rates[0].count =
- (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : ATH_MGT_TXMAXTRY;
- return;
- }
-
- /* Find tx rate for unicast frames */
- ath_rc_ratefind(sc, ath_rc_priv, txrc);
-}
-
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
@@ -1697,7 +1473,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
return NULL;
}
- rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
return rate_priv;
@@ -1725,8 +1500,6 @@ static struct rate_control_ops ath_rate_ops = {
void ath_rate_attach(struct ath_softc *sc)
{
- sc->hw_rate_table[ATH9K_MODE_11B] =
- &ar5416_11b_ratetable;
sc->hw_rate_table[ATH9K_MODE_11A] =
&ar5416_11a_ratetable;
sc->hw_rate_table[ATH9K_MODE_11G] =
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index e3abd76103fd..fa21a628ddd0 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -112,8 +112,6 @@ struct ath_rate_table {
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
- int8_t rssi_ack_validmin;
- int8_t rssi_ack_deltamin;
u8 base_index;
u8 cw40index;
u8 sgi_index;
@@ -121,15 +119,9 @@ struct ath_rate_table {
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
- u32 rssi_reduce_interval;
u8 initial_ratemax;
};
-struct ath_tx_ratectrl_state {
- int8_t rssi_thres; /* required rssi for this rate (dB) */
- u8 per; /* recent estimate of packet error rate (%) */
-};
-
struct ath_rateset {
u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX];
@@ -138,22 +130,14 @@ struct ath_rateset {
/**
* struct ath_rate_priv - Rate Control priv data
* @state: RC state
- * @rssi_last: last ACK rssi
- * @rssi_last_lookup: last ACK rssi used for lookup
- * @rssi_last_prev: previous last ACK rssi
- * @rssi_last_prev2: 2nd previous last ACK rssi
- * @rssi_sum_cnt: count of rssi_sum for averaging
- * @rssi_sum_rate: rate that we are averaging
- * @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at
- * @rssi_time: msec timestamp for last ack rssi
- * @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
+ * @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
@@ -161,13 +145,6 @@ struct ath_rateset {
* @neg_ht_rates: Negotiated HT rates
*/
struct ath_rate_priv {
- int8_t rssi_last;
- int8_t rssi_last_lookup;
- int8_t rssi_last_prev;
- int8_t rssi_last_prev2;
- int32_t rssi_sum_cnt;
- int32_t rssi_sum_rate;
- int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
u8 hw_maxretry_pktcnt;
@@ -177,14 +154,12 @@ struct ath_rate_priv {
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rate_max_phy;
- u32 rssi_time;
- u32 rssi_down_time;
+ u8 per[RATE_TABLE_SIZE];
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
u32 prev_data_rix;
u32 tx_triglevel_max;
- struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cece1c4c6bda..61edfab20ffc 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
@@ -229,17 +233,57 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
}
}
+ rcu_read_lock();
+ sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
+ !ds->ds_rxstat.rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (ds->ds_rxstat.rs_rssi < 0)
+ ds->ds_rxstat.rs_rssi = 0;
+ else if (ds->ds_rxstat.rs_rssi > 127)
+ ds->ds_rxstat.rs_rssi = 127;
+
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;
- /* at 45 you will be able to use MCS 15 reliably. A more elaborate
- * scheme can be used here but it requires tables of SNR/throughput for
- * each possible mode used. */
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ /*
+ * Theory for reporting quality:
+ *
+ * At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
+ * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
+ * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
+ *
+ * MCS 7 is the highets MCS index usable by a 1-stream device.
+ * MCS 15 is the highest MCS index usable by a 2-stream device.
+ *
+ * All ath9k devices are either 1-stream or 2-stream.
+ *
+ * How many bars you see is derived from the qual reporting.
+ *
+ * A more elaborate scheme can be used here but it requires tables
+ * of SNR/throughput for each possible mode used. For the MCS table
+ * you can refer to the wireless wiki:
+ *
+ * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+ *
+ */
+ if (conf_is_ht(&hw->conf))
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ else
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
/* rssi can be more than 45 though, anything above that
* should be considered at 100% */
@@ -505,11 +549,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
return false;
}
-static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
-{
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-}
-
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
@@ -521,6 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (memcmp(sc->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 "
@@ -528,14 +569,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_beacon_config(sc, NULL);
}
- if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
- /* We are not in PS mode anymore; remain awake */
- DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
- "awake\n");
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
- return;
- }
-
if (ath_beacon_dtim_pending_cab(skb)) {
/*
* Remain awake waiting for buffered broadcast/multicast
@@ -556,11 +589,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
}
-
- /* No more broadcast/multicast frames to be received at this point. */
- ath_rx_ps_back_to_sleep(sc);
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
@@ -578,13 +609,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
/*
* No more broadcast/multicast frames to be received at this
* point.
*/
- ath_rx_ps_back_to_sleep(sc);
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ DPRINTF(sc, 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)) {
@@ -619,13 +650,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
- if (nskb)
- __ieee80211_rx(aphy->hw, nskb, rx_status);
+ if (nskb) {
+ memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+ sizeof(*rx_status));
+ ieee80211_rx(aphy->hw, nskb);
+ }
}
- __ieee80211_rx(sc->hw, skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(sc->hw, skb);
} else {
/* Deliver unicast frames based on receiver address */
- __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 52605246679f..8302aeb62e5d 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -574,6 +574,7 @@
#define AR_D_GBL_IFS_SIFS 0x1030
#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
#define AR_D_TXBLK_BASE 0x1038
@@ -589,10 +590,12 @@
#define AR_D_GBL_IFS_SLOT 0x1070
#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420
#define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB
#define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@@ -738,6 +741,9 @@
#define AR_SREV_REVISION_9285_10 0
#define AR_SREV_REVISION_9285_11 1
#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -794,6 +800,21 @@
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
AR_SREV_REVISION_9285_12)))
+#define AR_SREV_9287(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
+#define AR_SREV_9287_11(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -809,6 +830,9 @@
#define AR_AHB_PAGE_SIZE_1K 0x00000000
#define AR_AHB_PAGE_SIZE_2K 0x00000008
#define AR_AHB_PAGE_SIZE_4K 0x00000010
+#define AR_AHB_CUSTOM_BURST_EN 0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S 6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3
#define AR_INTR_RTC_IRQ 0x00000001
#define AR_INTR_MAC_IRQ 0x00000002
@@ -885,6 +909,7 @@ enum {
#define AR_NUM_GPIO 14
#define AR928X_NUM_GPIO 10
#define AR9285_NUM_GPIO 12
+#define AR9287_NUM_GPIO 11
#define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000
@@ -893,6 +918,8 @@ enum {
#define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12
+#define AR9287_GPIO_IN_VAL 0x003FF800
+#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT 0x404c
#define AR_GPIO_OE_OUT_DRV 0x3
@@ -1154,6 +1181,33 @@ enum {
#define AR9285_AN_TOP4 0x7870
#define AR9285_AN_TOP4_DEFAULT 0x10142c00
+#define AR9287_AN_RF2G3_CH0 0x7808
+#define AR9287_AN_RF2G3_CH1 0x785c
+#define AR9287_AN_RF2G3_DB1 0xE0000000
+#define AR9287_AN_RF2G3_DB1_S 29
+#define AR9287_AN_RF2G3_DB2 0x1C000000
+#define AR9287_AN_RF2G3_DB2_S 26
+#define AR9287_AN_RF2G3_OB_CCK 0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S 23
+#define AR9287_AN_RF2G3_OB_PSK 0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S 20
+#define AR9287_AN_RF2G3_OB_QAM 0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S 17
+#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14
+
+#define AR9287_AN_TXPC0 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S 14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST 1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3
+
+#define AR9287_AN_TOP2 0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
@@ -1188,6 +1242,7 @@ enum {
#define AR_TIME_OUT_ACK_S 0
#define AR_TIME_OUT_CTS 0x3FFF0000
#define AR_TIME_OUT_CTS_S 16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56
#define AR_RSSI_THR 0x8018
#define AR_RSSI_THR_MASK 0x000000FF
@@ -1203,6 +1258,7 @@ enum {
#define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23
+#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074
#define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000
@@ -1468,6 +1524,10 @@ enum {
#define AR_SLP_MIB_CLEAR 0x00000001
#define AR_SLP_MIB_PENDING 0x00000002
+#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000
+
+
#define AR_2040_MODE 0x8318
#define AR_2040_JOINED_RX_CLEAR 0x00000001
@@ -1485,6 +1545,39 @@ enum {
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
+#define AR_PCU_MISC_MODE2_RESERVED 0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+
+
+#define AR_AES_MUTE_MASK0 0x805c
+#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1 0x8060
+#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S 0
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
+
+#define AR_RATE_DURATION_0 0x8700
+#define AR_RATE_DURATION_31 0x87CC
+#define AR_RATE_DURATION_32 0x8780
+#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 1ff429b027d7..e1d419e02b4a 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
sc->wiphy_scheduler_int);
}
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+ unsigned int i;
+ if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+ return false;
+ }
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (!aphy)
+ continue;
+ if (aphy->state != ATH_WIPHY_INACTIVE)
+ return false;
+ }
+ return true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4ccf48e396df..b7806e2ca0e1 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq,
struct list_head *bf_q,
int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
@@ -73,18 +74,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
/* Aggregation logic */
/*********************/
-static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
- struct ath_atx_tid *tid;
- tid = ATH_AN_2_TID(an, tidno);
-
- if (tid->state & AGGR_ADDBA_COMPLETE ||
- tid->state & AGGR_ADDBA_PROGRESS)
- return 1;
- else
- return 0;
-}
-
static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
{
struct ath_atx_ac *ac = tid->ac;
@@ -224,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_update_baw(sc, tid, bf->bf_seqno);
spin_unlock(&txq->axq_lock);
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
spin_lock(&txq->axq_lock);
}
@@ -232,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
tid->baw_tail = tid->baw_head;
}
-static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
+static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
{
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
bf->bf_state.bf_type |= BUF_RETRY;
bf->bf_retries++;
+ TX_STAT_INC(txq->axq_qnum, a_retries);
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -250,7 +241,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
struct ath_buf *tbf;
spin_lock_bh(&sc->tx.txbuflock);
- ASSERT(!list_empty((&sc->tx.txbuf)));
+ if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+ spin_unlock_bh(&sc->tx.txbuflock);
+ return NULL;
+ }
tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
list_del(&tbf->list);
spin_unlock_bh(&sc->tx.txbuflock);
@@ -337,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (!(tid->state & AGGR_CLEANUP) &&
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, bf);
+ ath_tx_set_retry(sc, txq, bf);
txpending = 1;
} else {
bf->bf_state.bf_type |= BUF_XRETRY;
@@ -384,13 +378,31 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_rc_status(bf, ds, nbad, txok, false);
}
- ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
} else {
/* retry the un-acked ones */
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last);
+ /*
+ * Update tx baw and complete the frame with
+ * failed status if we run out of tx buf
+ */
+ if (!tbf) {
+ spin_lock_bh(&txq->axq_lock);
+ ath_tx_update_baw(sc, tid,
+ bf->bf_seqno);
+ spin_unlock_bh(&txq->axq_lock);
+
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ ath_tx_rc_status(bf, ds, nbad,
+ 0, false);
+ ath_tx_complete_buf(sc, bf, txq,
+ &bf_head, 0, 0);
+ break;
+ }
+
ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
list_add_tail(&tbf->list, &bf_head);
} else {
@@ -414,7 +426,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (tid->state & AGGR_CLEANUP) {
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
/* send buffered frames as singles */
@@ -447,7 +458,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ieee80211_tx_rate *rates;
struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frmlen;
- u16 aggr_limit, legacy = 0, maxampdu;
+ u16 aggr_limit, legacy = 0;
int i;
skb = bf->bf_mpdu;
@@ -482,16 +493,15 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
return 0;
- aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT);
+ aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
/*
* h/w can accept aggregates upto 16 bit lengths (65535).
* The IE, however can hold upto 65536, which shows up here
* as zero. Ignore 65536 since we are constrained by hw.
*/
- maxampdu = tid->an->maxampdu;
- if (maxampdu)
- aggr_limit = min(aggr_limit, maxampdu);
+ if (tid->an->maxampdu)
+ aggr_limit = min(aggr_limit, tid->an->maxampdu);
return aggr_limit;
}
@@ -499,7 +509,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
/*
* Returns the number of delimiters to be added to
* meet the minimum required mpdudensity.
- * caller should make sure that the rate is HT rate .
*/
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, u16 frmlen)
@@ -507,7 +516,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
const struct ath_rate_table *rt = sc->cur_rate_table;
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- u32 nsymbits, nsymbols, mpdudensity;
+ u32 nsymbits, nsymbols;
u16 minlen;
u8 rc, flags, rix;
int width, half_gi, ndelim, mindelim;
@@ -529,14 +538,12 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* on highest rate in rate series (i.e. first rate) to determine
* required minimum length for subframe. Take into account
* whether high rate is 20 or 40Mhz and half or full GI.
- */
- mpdudensity = tid->an->mpdudensity;
-
- /*
+ *
* If there is no mpdu density restriction, no further calculation
* is needed.
*/
- if (mpdudensity == 0)
+
+ if (tid->an->mpdudensity == 0)
return ndelim;
rix = tx_info->control.rates[0].idx;
@@ -546,9 +553,9 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi)
- nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
+ nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
else
- nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
+ nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
if (nsymbols == 0)
nsymbols = 1;
@@ -565,6 +572,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
}
static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
+ struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_q)
{
@@ -629,6 +637,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
bf_prev->bf_desc->ds_link = bf->bf_daddr;
}
bf_prev = bf;
+
} while (!list_empty(&tid->buf_q));
bf_first->bf_al = al;
@@ -651,7 +660,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_q);
- status = ath_tx_form_aggr(sc, tid, &bf_q);
+ status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
/*
* no frames picked up to be aggregated;
@@ -682,30 +691,26 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_aggr_depth++;
ath_tx_txqaddbuf(sc, txq, &bf_q);
+ TX_STAT_INC(txq->axq_qnum, a_aggr);
} while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED);
}
-int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn)
+void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
{
struct ath_atx_tid *txtid;
struct ath_node *an;
an = (struct ath_node *)sta->drv_priv;
-
- if (sc->sc_flags & SC_OP_TXAGGR) {
- txtid = ATH_AN_2_TID(an, tid);
- txtid->state |= AGGR_ADDBA_PROGRESS;
- ath_tx_pause_tid(sc, txtid);
- *ssn = txtid->seq_start;
- }
-
- return 0;
+ txtid = ATH_AN_2_TID(an, tid);
+ txtid->state |= AGGR_ADDBA_PROGRESS;
+ ath_tx_pause_tid(sc, txtid);
+ *ssn = txtid->seq_start;
}
-int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
@@ -715,12 +720,11 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
INIT_LIST_HEAD(&bf_head);
if (txtid->state & AGGR_CLEANUP)
- return 0;
+ return;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
- txtid->addba_exchangeattempts = 0;
- return 0;
+ return;
}
ath_tx_pause_tid(sc, txtid);
@@ -739,7 +743,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
}
list_move_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, txtid, bf->bf_seqno);
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
}
spin_unlock_bh(&txq->axq_lock);
@@ -747,11 +751,8 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
txtid->state |= AGGR_CLEANUP;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
- txtid->addba_exchangeattempts = 0;
ath_tx_flush_tid(sc, txtid);
}
-
- return 0;
}
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
@@ -780,14 +781,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
txtid = ATH_AN_2_TID(an, tidno);
- if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
- if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
- (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
- txtid->addba_exchangeattempts++;
+ if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
- }
- }
-
return false;
}
@@ -870,8 +865,8 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0;
txq->axq_aggr_depth = 0;
- txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL;
+ txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
return &sc->tx.txq[qnum];
@@ -1035,9 +1030,13 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
else
- ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
}
+ spin_lock_bh(&txq->axq_lock);
+ txq->axq_tx_inprogress = false;
+ spin_unlock_bh(&txq->axq_lock);
+
/* flush any pending frames if aggregation is enabled */
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
@@ -1118,8 +1117,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused)
continue;
- if ((txq->axq_depth % 2) == 0)
- ath_tx_sched_aggr(sc, txq, tid);
+ ath_tx_sched_aggr(sc, txq, tid);
/*
* add tid to round-robin queue if more frames
@@ -1183,7 +1181,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
list_splice_tail_init(head, &txq->axq_q);
txq->axq_depth++;
- txq->axq_totalqueued++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
DPRINTF(sc, ATH_DBG_QUEUE,
@@ -1231,6 +1228,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type |= BUF_AMPDU;
+ TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
/*
* Do not queue to h/w when any of the following conditions is true:
@@ -1277,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = bf;
ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head);
+ TX_STAT_INC(txq->axq_qnum, queued);
}
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1290,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_nframes = 1;
ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head);
+ TX_STAT_INC(txq->axq_qnum, queued);
}
static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
@@ -1636,7 +1636,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
goto tx_done;
}
- if (ath_aggr_query(sc, an, bf->bf_tidno)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
@@ -1815,6 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq,
struct list_head *bf_q,
int txok, int sendbar)
{
@@ -1822,7 +1823,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
unsigned long flags;
int tx_flags = 0;
-
if (sendbar)
tx_flags = ATH_TX_BAR;
@@ -1835,6 +1835,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
ath_tx_complete(sc, skb, tx_flags);
+ ath_debug_stat_tx(sc, txq, bf);
/*
* Return the list of ath_buf of this mpdu to free queue
@@ -1962,19 +1963,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
- txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
-
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to remove
- * the last holding descriptor in BH context.
- */
- spin_lock_bh(&sc->tx.txbuflock);
- list_move_tail(&bf_held->list, &sc->tx.txbuf);
- spin_unlock_bh(&sc->tx.txbuflock);
-
break;
} else {
bf = list_entry(bf_held->list.next,
@@ -2011,6 +2000,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0);
+ txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
if (bf_held) {
@@ -2033,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
else
- ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);
ath_wake_mac80211_queue(sc, txq);
@@ -2044,6 +2034,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}
+static void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset) {
+ DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_reset(sc, false);
+ }
+
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+
void ath_tx_tasklet(struct ath_softc *sc)
{
@@ -2084,6 +2108,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err;
}
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
err:
if (error != 0)
ath_tx_cleanup(sc);
@@ -2122,7 +2148,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
- tid->addba_exchangeattempts = 0;
}
for (acno = 0, ac = &an->ac[acno];
@@ -2179,7 +2204,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->sched = false;
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
}
}
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index eef370bd1211..077bcc142cde 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -474,6 +474,21 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
return 0;
}
+/*
+ * Some users have reported their EEPROM programmed with
+ * 0x8000 set, this is not a supported regulatory domain
+ * but since we have more than one user with it we need
+ * a solution for them. We default to 0x64, which is the
+ * default Atheros world regulatory domain.
+ */
+static void ath_regd_sanitize(struct ath_regulatory *reg)
+{
+ if (reg->current_rd != COUNTRY_ERD_FLAG)
+ return;
+ printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n");
+ reg->current_rd = 0x64;
+}
+
int
ath_regd_init(struct ath_regulatory *reg,
struct wiphy *wiphy,
@@ -486,6 +501,8 @@ ath_regd_init(struct ath_regulatory *reg,
if (!reg)
return -EINVAL;
+ ath_regd_sanitize(reg);
+
printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
if (!ath_regd_is_eeprom_valid(reg)) {
@@ -569,7 +586,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
default:
return NO_CTL;
}
-
- return NO_CTL;
}
EXPORT_SYMBOL(ath_regd_get_band_ctl);
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 4d0e298cd1c7..ad6d938d3cf6 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -450,7 +450,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
{CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"},
- {CTRY_THAILAND, NULL1_WORLD, "TH"},
+ {CTRY_THAILAND, FCC3_WORLD, "TH"},
{CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"},
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 291a94bd46fd..ed06d58bf09d 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
!(*priv->present_callback)(priv->card)) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->station_state != STATION_STATE_READY) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* first ensure the timer func cannot run */
@@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_bh(&priv->timerlock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
@@ -3330,7 +3330,7 @@ static void atmel_smooth_qual(struct atmel_private *priv)
priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID;
}
-/* deals with incoming managment frames. */
+/* deals with incoming management frames. */
static void atmel_management_frame(struct atmel_private *priv,
struct ieee80211_hdr *header,
u16 frame_len, u8 rssi)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9cd706..3f4360ad0e4e 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
static void b43_dump_keymemory(struct b43_wldev *dev)
{
unsigned int i, index, offset;
- DECLARE_MAC_BUF(macbuf);
u8 mac[ETH_ALEN];
u16 algo;
u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
((index - 4) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
- printk(" MAC: %s",
- print_mac(macbuf, mac));
+ printk(" MAC: %pM", mac);
} else
printk(" DEFAULT KEY");
printk("\n");
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 55f36a7254d9..5b85e7d73592 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
goto drop;
}
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index b8e39dd06e99..f79cee82601b 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
}
dev->stats.last_rx = jiffies;
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index d313b005114e..1fe1bbabb907 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (local->ddev != dev) {
@@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"AP device with Ethernet net dev\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
if (local->iw_mode == IW_MODE_REPEAT) {
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"non-WDS link in Repeater mode\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else if (local->iw_mode == IW_MODE_INFRA &&
(local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
memcmp(skb->data + ETH_ALEN, dev->dev_addr,
@@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (pskb_expand_head(skb, need_headroom, need_tailroom,
GFP_ATOMIC)) {
kfree_skb(skb);
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else if (skb_headroom(skb) < need_headroom) {
struct sk_buff *tmp = skb;
@@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(tmp);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
iface->stats.tx_packets++;
@@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
"expected 0x%08x)\n",
dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 24) {
printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, meta->ethertype);
hostap_dump_tx_80211(dev->name, skb);
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
}
break;
case AP_TX_DROP:
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
case AP_TX_RETRY:
@@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
case AP_TX_BUFFERED:
/* do not free skb here, it will be freed when the
* buffered frame is sent/timed out */
- ret = 0;
+ ret = NETDEV_TX_OK;
goto tx_exit;
}
@@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"frame (drop_unencrypted=1)\n", dev->name);
}
iface->stats.tx_dropped++;
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
printk(KERN_DEBUG "%s: TX - encryption failed\n",
dev->name);
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"expected 0x%08x) after hostap_tx_encrypt\n",
dev->name, meta->magic,
HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
}
if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
} else {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_packets++;
iface->stats.tx_bytes += skb->len;
}
fail:
- if (!ret && skb)
+ if (ret == NETDEV_TX_OK && skb)
dev_kfree_skb(skb);
tx_exit:
if (tx.sta_ptr)
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 633740277352..ad8eab4a639b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
* irq structure is initialized.
*/
if (link->conf.Attributes & CONF_ENABLE_IRQ) {
- 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 = prism2_interrupt;
link->irq.Instance = dev;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 44c29b3f6728..2dc1cdbb4939 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
struct ipw_priv *priv =
container_of(work, struct ipw_priv, qos_activate);
- if (priv == NULL)
- return;
-
mutex_lock(&priv->mutex);
if (priv->status & STATUS_ASSOCIATED)
@@ -11436,11 +11433,11 @@ static struct pci_device_id card_ids[] = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
- {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x104f), 0},
+ {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
/* required last entry */
{0,}
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da2ad5437ce5..2e8f84fb29fa 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (ret == 0) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index e092af09d6bf..99310c033253 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -9,6 +9,9 @@ config IWLWIFI
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"
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 7da52f1cc1d6..5f7c52053c18 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -46,7 +46,7 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
@@ -55,13 +55,88 @@
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
+
+/*
+ * For 1000, use advance thermal throttling critical temperature threshold,
+ * but legacy thermal management implementation for now.
+ * This is for the reason of 1000 uCode using advance thermal throttling API
+ * but not implement ct_kill_exit based on ct_kill exit temperature
+ * so the thermal throttling will still based on legacy thermal throttling
+ * management.
+ * The code here need to be modified once 1000 uCode has the advanced thermal
+ * throttling algorithm in place
+ */
+static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
+{
+ /* want Celsius */
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+ priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+static struct iwl_lib_ops iwl1000_lib = {
+ .set_hw_params = iwl5000_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,
+ .txq_agg_enable = iwl5000_txq_agg_enable,
+ .txq_agg_disable = iwl5000_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .setup_deferred_work = iwl5000_setup_deferred_work,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .send_tx_power = iwl5000_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .reset = iwl5000_apm_reset,
+ .stop = iwl5000_apm_stop,
+ .config = iwl5000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+ EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl1000_set_ct_threshold,
+ },
+};
+
+static struct iwl_ops iwl1000_ops = {
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl1000_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+};
+
struct iwl_cfg iwl1000_bgn_cfg = {
.name = "1000 Series BGN",
.fw_name_pre = IWL1000_FW_PRE,
.ucode_api_max = IWL1000_UCODE_API_MAX,
.ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
+ .ops = &iwl1000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 73f93a0ff2df..b569c6f38e5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -232,9 +232,8 @@ struct iwl3945_eeprom {
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
-#define TFD_QUEUE_MIN 0
-#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */
-
+/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
+#define IWL39_NUM_QUEUES 5
#define IWL_NUM_SCAN_RATES (2)
#define IWL_DEFAULT_TX_RETRY 15
@@ -280,8 +279,6 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */
#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
-#define IWL39_MAX_NUM_QUEUES 8
-
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 225e5f889346..8c29ded7d02c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -79,11 +79,10 @@ 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)
-static int iwl3945_led_cmd_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb)
+static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
- return 1;
}
static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
@@ -99,8 +98,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
- .meta.flags = CMD_ASYNC,
- .meta.u.callback = iwl3945_led_cmd_callback,
+ .flags = CMD_ASYNC,
+ .callback = iwl3945_led_cmd_callback,
};
return iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 5eb538d18a80..a16bd4147eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
s8 scale_action = 0;
unsigned long flags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc;
- u16 rate_mask = 0;
+ u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
s8 max_rate_idx = -1;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE(priv, "enter\n");
- if (sta)
- rate_mask = sta->supp_rates[sband->band];
-
- /* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK ||
- !sta || !priv_sta) {
- IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
- if (!rate_mask)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
+
+ rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */
max_rate_idx = txrc->max_rate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 46288e724889..e1b0ef3c56a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
}
static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100)
{
- if (priv->debug_level & IWL_DL_RX)
+ if (iwl_debug_level & IWL_DL_RX)
_iwl3945_dbg_report_frame(priv, pkt, header, group100);
}
@@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
if (ieee80211_is_data(hdr->frame_control))
priv->rxtxpackets += len;
#endif
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
rxb->skb = NULL;
}
@@ -748,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (counter)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->cmd[index]->meta, mapping),
- pci_unmap_len(&txq->cmd[index]->meta, len),
+ pci_unmap_addr(&txq->meta[index], mapping),
+ pci_unmap_len(&txq->meta[index], len),
PCI_DMA_TODEVICE);
/* unmap chunks if any */
@@ -773,9 +774,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
* iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
*
*/
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
- struct ieee80211_tx_info *info,
- struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id)
{
u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
@@ -962,7 +965,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
goto error;
/* Tx queue(s) */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -1139,7 +1142,7 @@ 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++)
+ 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
@@ -1155,7 +1158,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
/* reset TFD queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@@ -1857,7 +1860,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC,
.len = sizeof(rxon_assoc),
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
.data = &rxon_assoc,
};
const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
@@ -1881,14 +1884,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->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.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return rc;
}
@@ -1986,7 +1989,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
staging_rxon->reserved4 = 0;
staging_rxon->reserved5 = 0;
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -2551,7 +2554,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = TFD_QUEUE_MAX;
+ priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@@ -2562,6 +2565,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
+ priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
return 0;
}
@@ -2784,11 +2788,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}
+#define IWL3945_UCODE_GET(item) \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon,
};
+static struct iwl_ucode_ops iwl3945_ucode = {
+ .get_header_size = iwl3945_ucode_get_header_size,
+ .get_build = iwl3945_ucode_get_build,
+ .get_inst_size = iwl3945_ucode_get_inst_size,
+ .get_data_size = iwl3945_ucode_get_data_size,
+ .get_init_size = iwl3945_ucode_get_init_size,
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
+ .get_boot_size = iwl3945_ucode_get_boot_size,
+ .get_data = iwl3945_ucode_get_data,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2829,6 +2872,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};
static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index fbb3a573463e..f24036909916 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -111,9 +111,6 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
-
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
@@ -257,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl3945_frame *frame, u8 rate);
-void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
- struct ieee80211_tx_info *info,
- struct ieee80211_hdr *hdr,
- int sta_id, int tx_id);
+void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id);
extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8f3d4bc6a03f..670214823cb9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Begin load bsm\n");
- priv->ucode_type = UCODE_RT;
+ priv->ucode_type = UCODE_INIT;
/* make sure bootstrap program is no larger than BSM's SRAM size */
if (len > IWL49_MAX_BSM_SIZE)
@@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
*/
static void iwl4965_init_alive_start(struct iwl_priv *priv)
{
+ int ret;
+
/* Check alive response for "valid" sign from uCode */
if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
/* We had an error bringing up the hardware, so take it
@@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
goto restart;
}
+ priv->ucode_type = UCODE_RT;
+ if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_WARN(priv, "Runtime uCode already alive? "
+ "Waiting for alive anyway\n");
+ clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ /* FIXME: if STATUS_RT_UCODE_ALIVE timeout
+ * go back to restart the download Init uCode again
+ * this might cause to trap in the restart loop
+ */
+ priv->ucode_type = UCODE_NONE;
+ if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_ERR(priv, "Runtime timeout after %dms\n",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ goto restart;
+ }
+ }
return;
restart:
@@ -728,7 +752,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.min_nrg_cck = 97,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 85,
.auto_corr_min_ofdm_mrc = 170,
@@ -752,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
{
/* want Kelvin */
- priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+ priv->hw_params.ct_kill_threshold =
+ CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY);
}
/**
@@ -1772,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
}
priv->temperature = temp;
+ iwl_tt_handler(priv);
set_bit(STATUS_TEMPERATURE, &priv->status);
if (!priv->disable_tx_power_cal &&
@@ -2221,12 +2247,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}
+#define IWL4965_UCODE_GET(item) \
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL4965_UCODE_GET(inst_size);
+IWL4965_UCODE_GET(data_size);
+IWL4965_UCODE_GET(init_size);
+IWL4965_UCODE_GET(init_data_size);
+IWL4965_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
};
+static struct iwl_ucode_ops iwl4965_ucode = {
+ .get_header_size = iwl4965_ucode_get_header_size,
+ .get_build = iwl4965_ucode_get_build,
+ .get_inst_size = iwl4965_ucode_get_inst_size,
+ .get_data_size = iwl4965_ucode_get_data_size,
+ .get_init_size = iwl4965_ucode_get_init_size,
+ .get_init_data_size = iwl4965_ucode_get_init_data_size,
+ .get_boot_size = iwl4965_ucode_get_boot_size,
+ .get_data = iwl4965_ucode_get_data,
+};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2287,6 +2351,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};
static struct iwl_ops iwl4965_ops = {
+ .ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
@@ -2313,8 +2378,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
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_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b3c648ce8c7b..ddd64fef3039 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
}
-static int iwl5000_apm_init(struct iwl_priv *priv)
+int iwl5000_apm_init(struct iwl_priv *priv)
{
int ret = 0;
@@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
}
/* FIXME: this is identical to 4965 */
-static void iwl5000_apm_stop(struct iwl_priv *priv)
+void iwl5000_apm_stop(struct iwl_priv *priv)
{
unsigned long flags;
@@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
}
-static int iwl5000_apm_reset(struct iwl_priv *priv)
+int iwl5000_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
@@ -198,7 +198,7 @@ out:
}
-static void iwl5000_nic_config(struct iwl_priv *priv)
+void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
+ /* Setting digital SVR for 1000 card to 1.32V */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+ }
+
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -283,7 +290,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
return (address & ADDRESS_MSK) + (offset << 1);
}
-static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
+u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
{
struct iwl_eeprom_calib_hdr {
u8 version;
@@ -388,7 +395,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
.auto_corr_min_ofdm_x1 = 120,
@@ -407,7 +414,29 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.nrg_th_ofdm = 95,
};
-static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ /* max = min for performance bug in 5150 DSP */
+ .auto_corr_max_ofdm_x1 = 105,
+ .auto_corr_max_ofdm_mrc_x1 = 220,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+};
+
+const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
u32 address = eeprom_indirect_address(priv, offset);
@@ -418,7 +447,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
{
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
- s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) -
+ s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
iwl_temp_calib_to_offset(priv);
priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
@@ -427,7 +456,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
}
/*
@@ -602,7 +631,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
return ret;
}
-static int iwl5000_load_ucode(struct iwl_priv *priv)
+int iwl5000_load_ucode(struct iwl_priv *priv)
{
int ret = 0;
@@ -629,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
return ret;
}
-static void iwl5000_init_alive_start(struct iwl_priv *priv)
+void iwl5000_init_alive_start(struct iwl_priv *priv)
{
int ret = 0;
@@ -705,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
sizeof(coex_cmd), &coex_cmd);
}
-static int iwl5000_alive_notify(struct iwl_priv *priv)
+int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
unsigned long flags;
@@ -792,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
return 0;
}
-static int iwl5000_hw_set_hw_params(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)) {
@@ -826,8 +855,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IEEE80211_BAND_5GHZ);
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.sens = &iwl5000_sensitivity;
-
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;
@@ -836,9 +863,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
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 */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5150:
+ priv->hw_params.sens = &iwl5150_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_DC) |
BIT(IWL_CALIB_LO) |
@@ -847,6 +876,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
break;
default:
+ priv->hw_params.sens = &iwl5000_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
@@ -862,7 +892,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
/**
* iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
u16 byte_cnt)
{
@@ -902,7 +932,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
-static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
@@ -957,7 +987,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
(1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
-static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{
unsigned long flags;
@@ -1018,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
return 0;
}
-static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+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) ||
@@ -1061,7 +1091,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
* Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access
*/
-static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
{
iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
}
@@ -1282,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
return len;
}
-static void iwl5000_setup_deferred_work(struct iwl_priv *priv)
+void iwl5000_setup_deferred_work(struct iwl_priv *priv)
{
/* in 5000 the tx power calibration is done in uCode */
priv->disable_tx_power_cal = 1;
}
-static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+void iwl5000_rx_handler_setup(struct iwl_priv *priv)
{
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@@ -1299,7 +1329,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
}
-static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+int iwl5000_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
(addr < IWL50_RTC_DATA_UPPER_BOUND);
@@ -1351,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwl5000_send_tx_power(struct iwl_priv *priv)
+int iwl5000_send_tx_power(struct iwl_priv *priv)
{
struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd;
@@ -1371,10 +1401,11 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv)
NULL);
}
-static void iwl5000_temperature(struct iwl_priv *priv)
+void iwl5000_temperature(struct iwl_priv *priv)
{
/* store temperature from statistics (in Celsius) */
priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+ iwl_tt_handler(priv);
}
static void iwl5150_temperature(struct iwl_priv *priv)
@@ -1426,6 +1457,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+#define IWL5000_UCODE_GET(item) \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ if (api_ver <= 2) \
+ return le32_to_cpu(ucode->u.v1.item); \
+ return le32_to_cpu(ucode->u.v2.item); \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+ if (api_ver <= 2)
+ return UCODE_HEADER_SIZE(1);
+ return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return 0;
+ return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return (u8 *) ucode->u.v1.data;
+ return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@@ -1441,6 +1510,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi,
};
+struct iwl_ucode_ops iwl5000_ucode = {
+ .get_header_size = iwl5000_ucode_get_header_size,
+ .get_build = iwl5000_ucode_get_build,
+ .get_inst_size = iwl5000_ucode_get_inst_size,
+ .get_data_size = iwl5000_ucode_get_data_size,
+ .get_init_size = iwl5000_ucode_get_init_size,
+ .get_init_data_size = iwl5000_ucode_get_init_data_size,
+ .get_boot_size = iwl5000_ucode_get_boot_size,
+ .get_data = iwl5000_ucode_get_data,
+};
+
struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1542,12 +1622,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};
struct iwl_ops iwl5000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
static struct iwl_ops iwl5150_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
@@ -1664,8 +1746,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf55..59ff73536f3a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 3
+#define IWL6050_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@@ -61,6 +61,63 @@
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
+static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
+{
+ /* want Celsius */
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+ priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+static struct iwl_lib_ops iwl6000_lib = {
+ .set_hw_params = iwl5000_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,
+ .txq_agg_enable = iwl5000_txq_agg_enable,
+ .txq_agg_disable = iwl5000_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .setup_deferred_work = iwl5000_setup_deferred_work,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .send_tx_power = iwl5000_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .reset = iwl5000_apm_reset,
+ .stop = iwl5000_apm_stop,
+ .config = iwl5000_nic_config,
+ .set_pwr_src = iwl_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+ EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwl5000_eeprom_calib_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl6000_set_ct_threshold,
+ },
+};
+
static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
@@ -69,7 +126,8 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};
static struct iwl_ops iwl6000_ops = {
- .lib = &iwl5000_lib,
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index ff20e5048a55..52a4810274e9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
@@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
int ret = 0;
u8 update_search_tbl_counter = 0;
+ if (!iwl_ht_enabled(priv))
+ /* stay in Legacy */
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+ else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
+ tbl->action > IWL_LEGACY_SWITCH_SISO)
+ tbl->action = IWL_LEGACY_SWITCH_SISO;
for (; ;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0;
int ret;
+ if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
+ tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
+ /* stay in SISO */
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0;
int ret;
+ if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
+ (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
+ /* switch in SISO */
+ tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
int ret;
u8 update_search_tbl_counter = 0;
+ if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
+ (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
+ /* switch in SISO */
+ tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+ }
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -2003,6 +2026,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
}
/*
+ * setup rate table in uCode
+ * return rate_n_flags as used in the table
+ */
+static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 is_green)
+{
+ u32 rate;
+
+ /* Update uCode's rate table. */
+ rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+ rs_fill_link_cmd(priv, lq_sta, rate);
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+
+ return rate;
+}
+
+/*
* Do rate scaling and search for new modulation mode.
*/
static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -2098,6 +2140,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (!((1 << index) & rate_scale_index_msk)) {
IWL_ERR(priv, "Current Rate is not valid\n");
+ if (lq_sta->search_better_tbl) {
+ /* revert to active table if search table is not valid*/
+ tbl->lq_type = LQ_NONE;
+ lq_sta->search_better_tbl = 0;
+ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ /* get "active" rate info */
+ index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ rate = rs_update_rate_tbl(priv, lq_sta,
+ tbl, index, is_green);
+ }
return;
}
@@ -2149,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl->expected_tpt[index] + 64) / 128));
/* If we are searching for better modulation mode, check success. */
- if (lq_sta->search_better_tbl) {
-
+ if (lq_sta->search_better_tbl &&
+ (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) {
/* If good success, continue using the "search" mode;
* no need to send new link quality command, since we're
* continuing to use the setup that we've been trying. */
@@ -2278,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
((sr > IWL_RATE_HIGH_TH) ||
(current_tpt > (100 * tbl->expected_tpt[low]))))
scale_action = 0;
-
+ if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
+ scale_action = -1;
+ if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI &&
+ (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
+ scale_action = -1;
switch (scale_action) {
case -1:
/* Decrease starting rate, update uCode's rate table */
@@ -2308,15 +2364,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_update:
/* Replace uCode's rate table for the destination station. */
- if (update_lq) {
- rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
- rs_fill_link_cmd(priv, lq_sta, rate);
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
- }
-
- /* Should we stay with this modulation mode, or search for a new one? */
- rs_stay_in_table(lq_sta);
+ if (update_lq)
+ rate = rs_update_rate_tbl(priv, lq_sta,
+ tbl, index, is_green);
+ if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) {
+ /* Should we stay with this modulation mode,
+ * or search for a new one? */
+ rs_stay_in_table(lq_sta);
+ }
/*
* Search for new modulation mode if we're:
* 1) Not changing rates right now
@@ -2373,7 +2429,8 @@ lq_update:
* have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */
if (lq_sta->enable_counter &&
- (lq_sta->action_counter >= tbl1->max_search)) {
+ (lq_sta->action_counter >= tbl1->max_search) &&
+ iwl_ht_enabled(priv)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != MAX_TID_COUNT)) {
@@ -2466,7 +2523,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = priv_sta;
int rate_idx;
- u64 mask_bit = 0;
IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
@@ -2481,22 +2537,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
lq_sta->max_rate_idx = -1;
}
- if (sta)
- mask_bit = sta->supp_rates[sband->band];
-
/* Send management frames and NO_ACK data using lowest rate. */
- if (!ieee80211_is_data(hdr->frame_control) ||
- info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
- if (!mask_bit)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rate_idx = lq_sta->last_txrate_idx;
@@ -2673,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
rs_initialize_lq(priv, conf, sta, lq_sta);
}
-static void rs_fill_link_cmd(const struct iwl_priv *priv,
+static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 new_rate)
{
struct iwl_scale_tbl_info tbl_type;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 6d1519e1f011..4cb1a1b73483 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
priv->staging_rxon.bssid_addr);
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
/* Apply the new configuration
* RXON unassoc clears the station table in uCode, send it before
@@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (num_tbs)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->cmd[index]->meta, mapping),
- pci_unmap_len(&txq->cmd[index]->meta, len),
+ pci_unmap_addr(&txq->meta[index], mapping),
+ pci_unmap_len(&txq->meta[index], len),
PCI_DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */
@@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
return 0;
}
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-
-#define MAX_UCODE_BEACON_INTERVAL 4096
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- if (!new_val)
- new_val = MAX_UCODE_BEACON_INTERVAL;
-
- return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 tsf;
- s32 interval_tm, rem;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
- priv->rxon_timing.atim_window = 0;
- } else {
- beacon_int = iwl_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
-
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
-
- tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
- rem = do_div(tsf, interval_tm);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
/******************************************************************************
*
* Generic RX handler implementations
@@ -597,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
+ set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive_init,
&pkt->u.alive_frame,
sizeof(struct iwl_init_alive_resp));
pwork = &priv->init_alive_start;
} else {
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+ set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive, &pkt->u.alive_frame,
sizeof(struct iwl_alive_resp));
pwork = &priv->alive_start;
@@ -697,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- unsigned long reg_flags;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -717,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
- }
-
- if (flags & RF_CARD_DISABLED) {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
- CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
- iwl_read32(priv, CSR_UCODE_DRV_GP1);
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv))
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
+ if (flags & RF_CARD_DISABLED)
+ iwl_tt_enter_ct_kill(priv);
}
+ if (!(flags & RF_CARD_DISABLED))
+ iwl_tt_exit_ct_kill(priv);
if (flags & HW_CARD_DISABLED)
set_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -964,7 +896,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -983,7 +915,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -999,7 +931,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1024,7 +956,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1113,7 +1045,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1144,7 +1076,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@@ -1156,7 +1088,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1172,7 +1104,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1197,7 +1129,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1348,7 +1280,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
@@ -1357,7 +1289,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, build;
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1387,23 +1320,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;
- /* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ /* Make sure that we got at least the v1 header! */
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -1429,6 +1365,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -1443,12 +1382,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size !=
+ priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
- (int)ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -1528,42 +1469,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -1812,6 +1753,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+ ret = iwl_set_hw_ready(priv);
+ if (priv->hw_ready)
+ return ret;
+
+ /* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -1819,6 +1765,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ /* HW should be ready by now, check again. */
if (ret != -ETIMEDOUT)
iwl_set_hw_ready(priv);
@@ -1831,6 +1778,7 @@ static int __iwl_up(struct iwl_priv *priv)
{
int i;
int ret;
+ unsigned long status;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1908,6 +1856,51 @@ static int __iwl_up(struct iwl_priv *priv)
/* start card; "initialize" will load runtime ucode */
iwl_nic_start(priv);
+ /* Just finish download Init or Runtime uCode image to device
+ * now we wait here for uCode send REPLY_ALIVE notification
+ * to indicate uCode is ready.
+ * 1) For Init uCode image, all iwlagn devices should wait here
+ * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
+ * receive the REPLY_ALIVE notification, go back and try to
+ * download the Init uCode image again.
+ * 2) For Runtime uCode image, all iwlagn devices except 4965
+ * wait here on STATUS_RT_UCODE_ALIVE status bit; if
+ * timeout before receive the REPLY_ALIVE notification, go back
+ * and download the Runtime uCode image again.
+ * 3) For 4965 Runtime uCode, it will not go through this path,
+ * need to wait for STATUS_RT_UCODE_ALIVE status bit in
+ * iwl4965_init_alive_start() function; if timeout, need to
+ * restart and download Init uCode image.
+ */
+ if (priv->ucode_type == UCODE_INIT)
+ status = STATUS_INIT_UCODE_ALIVE;
+ else
+ status = STATUS_RT_UCODE_ALIVE;
+ if (test_bit(status, &priv->status)) {
+ IWL_WARN(priv,
+ "%s uCode already alive? "
+ "Waiting for alive anyway\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime");
+ clear_bit(status, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(status, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ if (!test_bit(status, &priv->status)) {
+ priv->ucode_type =
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? UCODE_NONE : UCODE_INIT;
+ IWL_ERR(priv,
+ "%s timeout after %dms\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ continue;
+ }
+ }
IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
return 0;
@@ -2331,7 +2324,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (priv->hw_params.sw_crypto) {
+ if (priv->cfg->mod_params->sw_crypto) {
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -2455,14 +2448,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -2476,7 +2471,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -2675,38 +2670,16 @@ static ssize_t show_power_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
- int mode = priv->power_data.user_power_setting;
int level = priv->power_data.power_mode;
char *p = buf;
- p += sprintf(p, "INDEX:%d\t", level);
- p += sprintf(p, "USER:%d\n", mode);
+ p += sprintf(p, "%d\n", level);
return p - buf + 1;
}
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level);
-static ssize_t show_qos(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- char *p = buf;
- int q;
-
- for (q = 0; q < AC_NUM; q++) {
- p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
- p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
- priv->qos_data.def_qos_parm.ac[q].cw_min,
- priv->qos_data.def_qos_parm.ac[q].cw_max,
- priv->qos_data.def_qos_parm.ac[q].aifsn,
- priv->qos_data.def_qos_parm.ac[q].edca_txop);
- }
-
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -2807,7 +2780,6 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_debug_level.attr,
#endif
&dev_attr_version.attr,
- &dev_attr_qos.attr,
NULL
};
@@ -2851,7 +2823,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- if (cfg->mod_params->debug & IWL_DL_INFO)
+ if (iwl_debug_level & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n");
iwl_hw_ops.hw_scan = NULL;
@@ -2873,7 +2845,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -3036,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
test_bit(STATUS_RF_KILL_HW, &priv->status));
iwl_power_initialize(priv);
+ iwl_tt_initialize(priv);
return 0;
out_remove_sysfs:
@@ -3088,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv);
}
+ iwl_tt_exit(priv);
+
/* make sure we flush any pending irq or
* tasklet for the driver
*/
@@ -3233,3 +3207,11 @@ static void __exit iwl_exit(void)
module_exit(iwl_exit);
module_init(iwl_init);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug50, iwl_debug_level, uint, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
+module_param_named(debug, iwl_debug_level, uint, 0644);
+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 a5d63672ad39..13180d6ee2f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
struct iwl_host_cmd hcmd = {
.id = REPLY_PHY_CALIBRATION_CMD,
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
for (i = 0; i < IWL_CALIB_MAX; i++) {
@@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
/* increase energy threshold (reduce nrg value)
* to decrease sensitivity */
- if (data->nrg_th_cck >
- (ranges->max_nrg_cck + NRG_STEP_CCK))
- data->nrg_th_cck = data->nrg_th_cck
- - NRG_STEP_CCK;
- else
- data->nrg_th_cck = ranges->max_nrg_cck;
+ data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
/* Else if we got fewer than desired, increase sensitivity */
} else if (false_alarms < min_false_alarms) {
data->nrg_curr_state = IWL_FA_TOO_FEW;
@@ -424,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
.len = sizeof(struct iwl_sensitivity_cmd),
- .meta.flags = CMD_ASYNC,
+ .flags = CMD_ASYNC,
.data = &cmd,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index c87033bf3ad2..39ede5727fe4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd {
} __attribute__ ((packed));
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
+#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
+#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -1922,7 +1924,7 @@ struct iwl_link_qual_general_params {
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
/**
@@ -2411,6 +2413,13 @@ struct iwl_ct_kill_config {
__le32 critical_temperature_R;
} __attribute__ ((packed));
+/* 1000, and 6x00 */
+struct iwl_ct_kill_throttling_config {
+ __le32 critical_temperature_exit;
+ __le32 reserved;
+ __le32 critical_temperature_enter;
+} __attribute__ ((packed));
+
/******************************************************************************
* (8)
* Scan Commands, Responses, Notifications:
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6ab07165ea28..8570d56b3124 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX }
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
static irqreturn_t iwl_isr(int irq, void *data);
/*
@@ -629,12 +632,73 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
if (!sta_ht_inf->ht_supported)
return 0;
}
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (priv->disable_ht40)
+ return 0;
+#endif
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
iwl_ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+ new_val = beacon_val / beacon_factor;
+
+ if (!new_val)
+ new_val = max_beacon_val;
+
+ return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 tsf;
+ s32 interval_tm, rem;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+ priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+ beacon_int = priv->beacon_int;
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ beacon_int = priv->vif->bss_conf.beacon_int;
+
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ beacon_int = iwl_adjust_beacon_interval(beacon_int,
+ priv->hw_params.max_beacon_itrvl * 1024);
+ priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+ tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+ interval_tm = beacon_int * 1024;
+ rem = do_div(tsf, interval_tm);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_ASSOC(priv,
+ "beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
+
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -1218,7 +1282,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
- iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
@@ -1231,9 +1295,212 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
-#endif
+
+static const char *desc_lookup_text[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAK_POINT"
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+ "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+ int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+ if (i < 0 || i > max)
+ i = max;
+
+ return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ count = iwl_read_targ_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+ IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+ priv->status, count);
+ }
+
+ desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERR(priv, "Desc Time "
+ "data1 data2 line\n");
+ IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
+ IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0) {
+ /* data, 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);
+ }
+ }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(priv, base);
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+ return;
+ }
+
+ IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
+#endif
+/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
void iwl_irq_handle_error(struct iwl_priv *priv)
@@ -1245,7 +1512,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_FW_ERRORS) {
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv);
iwl_print_rx_config_cmd(priv);
@@ -1325,7 +1592,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1361,7 +1629,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
int iwl_set_hw_params(struct iwl_priv *priv)
{
- priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
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)
@@ -1370,6 +1637,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
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.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
if (priv->cfg->mod_params->disable_11n)
priv->cfg->sku &= ~IWL_SKU_N;
@@ -1484,31 +1753,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_uninit_drv);
-
-void iwl_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-EXPORT_SYMBOL(iwl_disable_interrupts);
-
-void iwl_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-EXPORT_SYMBOL(iwl_enable_interrupts);
-
-
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */
@@ -1742,7 +1986,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
"fh 0x%08x\n", inta, inta_mask, inta_fh);
@@ -1849,7 +2093,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
u32 stat_flags = 0;
struct iwl_host_cmd cmd = {
.id = REPLY_STATISTICS_CMD,
- .meta.flags = flags,
+ .flags = flags,
.len = sizeof(stat_flags),
.data = (u8 *) &stat_flags,
};
@@ -1981,194 +2225,10 @@ int iwl_verify_ucode(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_verify_ucode);
-static const char *desc_lookup_text[] = {
- "OK",
- "FAIL",
- "BAD_PARAM",
- "BAD_CHECKSUM",
- "NMI_INTERRUPT_WDG",
- "SYSASSERT",
- "FATAL_ERROR",
- "BAD_COMMAND",
- "HW_ERROR_TUNE_LOCK",
- "HW_ERROR_TEMPERATURE",
- "ILLEGAL_CHAN_FREQ",
- "VCC_NOT_STABLE",
- "FH_ERROR",
- "NMI_INTERRUPT_HOST",
- "NMI_INTERRUPT_ACTION_PT",
- "NMI_INTERRUPT_UNKNOWN",
- "UCODE_VERSION_MISMATCH",
- "HW_ERROR_ABS_LOCK",
- "HW_ERROR_CAL_LOCK_FAIL",
- "NMI_INTERRUPT_INST_ACTION_PT",
- "NMI_INTERRUPT_DATA_ACTION_PT",
- "NMI_TRM_HW_ER",
- "NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAK_POINT"
- "DEBUG_0",
- "DEBUG_1",
- "DEBUG_2",
- "DEBUG_3",
- "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
- int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
- if (i < 0 || i > max)
- i = max;
-
- return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
- return;
- }
-
- count = iwl_read_targ_mem(priv, base);
-
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IWL_ERR(priv, "Start IWL Error Log Dump:\n");
- IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
- IWL_ERR(priv, "Desc Time "
- "data1 data2 line\n");
- IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
- desc_lookup(desc), desc, time, data1, data2, line);
- IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
- IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
- ilink1, ilink2);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
-
- if (num_events == 0)
- return;
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* "time" is actually "data" for mode 0 (no timestamp).
- * place event id # at far right for easier visual parsing. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- time = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- if (mode == 0) {
- /* data, 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);
- }
- }
-}
-
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
- return;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
- }
-
- IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
- size, num_wraps);
-
- /* if uCode has wrapped back to top of log, start at the oldest entry,
- * i.e the next one that uCode would fill. */
- if (num_wraps)
- iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
- /* (then/else) start at top of log */
- iwl_print_event_log(priv, 0, next_entry, mode);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
+ struct iwl_ct_kill_throttling_config adv_cmd;
unsigned long flags;
int ret = 0;
@@ -2176,10 +2236,28 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
spin_unlock_irqrestore(&priv->lock, flags);
+ priv->power_data.ct_kill_toggle = false;
+
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_1000:
+ case CSR_HW_REV_TYPE_6x00:
+ case CSR_HW_REV_TYPE_6x50:
+ adv_cmd.critical_temperature_enter =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
+ adv_cmd.critical_temperature_exit =
+ cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ sizeof(adv_cmd), &adv_cmd);
+ break;
+ default:
+ cmd.critical_temperature_R =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
- cmd.critical_temperature_R =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ sizeof(cmd), &cmd);
+ break;
+ }
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
sizeof(cmd), &cmd);
if (ret)
@@ -2208,7 +2286,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
.id = REPLY_CARD_STATE_CMD,
.len = sizeof(u32),
.data = &flags,
- .meta.flags = meta_flag,
+ .flags = meta_flag,
};
return iwl_send_cmd(priv, &cmd);
@@ -2234,7 +2312,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n",
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
- iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
}
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dabf663e36e5..febcf76e1d41 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv);
};
+struct iwl_ucode_ops {
+ u32 (*get_header_size)(u32);
+ u32 (*get_build)(const struct iwl_ucode_header *, u32);
+ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
+ u8 * (*get_data)(const struct iwl_ucode_header *, u32);
+};
+
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
};
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;
@@ -178,7 +190,6 @@ struct iwl_ops {
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
- u32 debug; /* def: 0 = minimal debug log messages */
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 */
@@ -384,7 +395,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-int iwl_scan_initiate(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ie, int ie_len, int left);
@@ -398,7 +408,6 @@ void iwl_bg_scan_check(struct work_struct *data);
void iwl_bg_abort_scan(struct work_struct *work);
void iwl_bg_scan_completed(struct work_struct *work);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-int iwl_send_scan_abort(struct iwl_priv *priv);
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -437,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
u16 len, const void *data);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data,
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb));
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
@@ -449,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
/*****************************************************
* PCI *
*****************************************************/
-void iwl_disable_interrupts(struct iwl_priv *priv);
-void iwl_enable_interrupts(struct iwl_priv *priv);
irqreturn_t iwl_isr_legacy(int irq, void *data);
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
@@ -474,7 +481,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
/*****************************************************
* Error Handling Debugging
******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_clear_isr_stats(struct iwl_priv *priv);
@@ -503,6 +509,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17
#define STATUS_MODE_PENDING 18
+#define STATUS_INIT_UCODE_ALIVE 19
+#define STATUS_RT_UCODE_ALIVE 20
static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -556,6 +564,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
{
return priv->cfg->ops->hcmd->rxon_assoc(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 2cf014f523be..fbe177608bc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -30,16 +30,23 @@
#define __iwl_debug_h__
struct iwl_priv;
+extern u32 iwl_debug_level;
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
#define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
#define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
+#define iwl_print_hex_error(priv, p, len) \
+do { \
+ print_hex_dump(KERN_ERR, "iwl data: ", \
+ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
+} while (0)
+
#ifdef CONFIG_IWLWIFI_DEBUG
#define IWL_DEBUG(__priv, level, fmt, args...) \
do { \
- if (__priv->debug_level & (level)) \
+ if (iwl_debug_level & (level)) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
@@ -47,15 +54,15 @@ do { \
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
do { \
- if ((__priv->debug_level & (level)) && net_ratelimit()) \
+ if ((iwl_debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
} while (0)
-#define iwl_print_hex_dump(priv, level, p, len) \
+#define iwl_print_hex_dump(level, p, len) \
do { \
- if (priv->debug_level & level) \
+ if (iwl_debug_level & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
@@ -76,6 +83,12 @@ struct iwl_debugfs {
struct dentry *file_channels;
struct dentry *file_status;
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;
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
@@ -93,8 +106,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else
#define IWL_DEBUG(__priv, level, fmt, args...)
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- void *p, u32 len)
+static inline void iwl_print_hex_dump(int level, void *p, u32 len)
{}
#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 11e08c068917..7707a2655994 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -49,7 +49,8 @@
#define DEBUGFS_ADD_FILE(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, priv, \
&iwl_dbgfs_##name##_ops); \
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \
@@ -57,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
+ debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -65,7 +67,7 @@
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \
+ debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -566,6 +568,133 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0, i;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ for (i = 0; i < AC_NUM; i++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tcw_min\tcw_max\taifsn\ttxop\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+ priv->qos_data.def_qos_parm.ac[i].cw_min,
+ priv->qos_data.def_qos_parm.ac[i].cw_max,
+ priv->qos_data.def_qos_parm.ac[i].aifsn,
+ priv->qos_data.def_qos_parm.ac[i].edca_txop);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ 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)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "allow blinking: %s\n",
+ (priv->allow_blinking) ? "True" : "False");
+ if (priv->allow_blinking) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Led blinking rate: %u\n",
+ priv->last_blink_rate);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Last blink time: %lu\n",
+ priv->last_blink_time);
+ }
+
+ 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,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ struct iwl_tt_restriction *restriction;
+ char buf[100];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Thermal Throttling Mode: %s\n",
+ (priv->power_data.adv_tt)
+ ? "Advance" : "Legacy");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Thermal Throttling State: %d\n",
+ tt->state);
+ if (priv->power_data.adv_tt) {
+ restriction = tt->restriction + tt->state;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Tx mode: %d\n",
+ restriction->tx_stream);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Rx mode: %d\n",
+ restriction->rx_stream);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "HT mode: %d\n",
+ restriction->is_ht);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int ht40;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &ht40) != 1)
+ return -EFAULT;
+ if (!iwl_is_associated(priv))
+ priv->disable_ht40 = ht40 ? true : false;
+ else {
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change to 40MHz channel support is not allowed\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[100];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "11n 40MHz Mode: %s\n",
+ priv->disable_ht40 ? "Disabled" : "Enabled");
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
@@ -576,6 +705,12 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
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);
/*
* Create the debugfs files and directories
@@ -612,10 +747,19 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(channels, data);
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(thermal_throttling, data);
+ DEBUGFS_ADD_FILE(disable_ht40, data);
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
- DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+ &priv->disable_tx_power_cal);
return 0;
err:
@@ -643,10 +787,18 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
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);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index e2d620f0b6e8..0ee3ad245697 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -63,9 +63,12 @@ extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_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;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -78,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
+extern int iwl5000_apm_init(struct iwl_priv *priv);
+extern void iwl5000_apm_stop(struct iwl_priv *priv);
+extern int iwl5000_apm_reset(struct iwl_priv *priv);
+extern void iwl5000_nic_config(struct iwl_priv *priv);
+extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
+extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+ size_t offset);
+extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
+extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern int iwl5000_load_ucode(struct iwl_priv *priv);
+extern void iwl5000_init_alive_start(struct iwl_priv *priv);
+extern int iwl5000_alive_notify(struct iwl_priv *priv);
+extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
+extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+ int tx_fifo, int sta_id, int tid, u16 ssn_idx);
+extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo);
+extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
+extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
+extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
+extern int iwl5000_send_tx_power(struct iwl_priv *priv);
+extern void iwl5000_temperature(struct iwl_priv *priv);
/* CT-KILL constants */
-#define CT_KILL_THRESHOLD 110 /* in Celsius */
+#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */
+#define CT_KILL_THRESHOLD 114 /* in Celsius */
+#define CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
@@ -119,6 +150,31 @@ struct iwl_rx_mem_buffer {
struct list_head list;
};
+/* defined below */
+struct iwl_device_cmd;
+
+struct iwl_cmd_meta {
+ /* only for SYNC commands, iff the reply skb is wanted */
+ struct iwl_host_cmd *source;
+ /*
+ * only for ASYNC commands
+ * (which is somewhat stupid -- look at iwl-sta.c for instance
+ * which duplicates a bunch of code because the callback isn't
+ * invoked for SYNC commands, if it were and its result passed
+ * through it would be simpler...)
+ */
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb);
+
+ /* The CMD_SIZE_HUGE flag bit indicates that the command
+ * structure is stored at the end of the shared queue memory. */
+ u32 flags;
+
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+ DECLARE_PCI_UNMAP_LEN(len)
+};
+
/*
* Generic queue structure
*
@@ -146,7 +202,8 @@ struct iwl_tx_info {
* struct iwl_tx_queue - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor
* @bd: base of circular buffer of TFDs
- * @cmd: array of command/Tx buffers
+ * @cmd: array of command/TX buffer pointers
+ * @meta: array of meta data for each command/tx buffer
* @dma_addr_cmd: physical address of cmd/tx buffer array
* @txb: array of per-TFD driver data
* @need_update: indicates need to update read/write index
@@ -161,7 +218,8 @@ struct iwl_tx_info {
struct iwl_tx_queue {
struct iwl_queue q;
void *tfds;
- struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
+ struct iwl_device_cmd **cmd;
+ struct iwl_cmd_meta *meta;
struct iwl_tx_info *txb;
u8 need_update;
u8 sched_retry;
@@ -258,8 +316,10 @@ struct iwl_channel_info {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
+/* Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate the 4 standard TX queues, 1 command
+ * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
+#define IWL_MIN_NUM_QUEUES 10
/* Power management (not Tx power) structures */
@@ -296,35 +356,16 @@ enum {
CMD_WANT_SKB = (1 << 2),
};
-struct iwl_cmd;
-struct iwl_priv;
-
-struct iwl_cmd_meta {
- struct iwl_cmd_meta *source;
- union {
- struct sk_buff *skb;
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb);
- } __attribute__ ((packed)) u;
-
- /* The CMD_SIZE_HUGE flag bit indicates that the command
- * structure is stored at the end of the shared queue memory. */
- u32 flags;
- DECLARE_PCI_UNMAP_ADDR(mapping)
- DECLARE_PCI_UNMAP_LEN(len)
-} __attribute__ ((packed));
-
#define IWL_CMD_MAX_PAYLOAD 320
/**
- * struct iwl_cmd
+ * struct iwl_device_cmd
*
* For allocation of the command and tx queues, this establishes the overall
* size of the largest command we send to uCode, except for a scan command
* (which is relatively huge; space is allocated separately).
*/
-struct iwl_cmd {
- struct iwl_cmd_meta meta; /* driver data */
+struct iwl_device_cmd {
struct iwl_cmd_header hdr; /* uCode API */
union {
u32 flags;
@@ -336,17 +377,20 @@ struct iwl_cmd {
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
+
struct iwl_host_cmd {
- u8 id;
- u16 len;
- struct iwl_cmd_meta meta;
const void *data;
+ struct sk_buff *reply_skb;
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb);
+ u32 flags;
+ u16 len;
+ u8 id;
};
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
- sizeof(struct iwl_cmd_meta))
-
/*
* RX related structures and functions
*/
@@ -447,8 +491,16 @@ union iwl_ht_rate_supp {
};
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
-#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+/*
+ * Maximal MPDU density for TX aggregation
+ * 4 - 2us density
+ * 5 - 4us density
+ * 6 - 8us density
+ * 7 - 16us density
+ */
+#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
struct iwl_ht_info {
/* self configuration data */
@@ -523,15 +575,29 @@ struct fw_desc {
};
/* uCode file layout */
-struct iwl_ucode {
- __le32 ver; /* major/minor/API/serial */
- __le32 inst_size; /* bytes of runtime instructions */
- __le32 data_size; /* bytes of runtime data */
- __le32 init_size; /* bytes of initialization instructions */
- __le32 init_data_size; /* bytes of initialization data */
- __le32 boot_size; /* bytes of bootstrap instructions */
- u8 data[0]; /* data in same order as "size" elements */
+struct iwl_ucode_header {
+ __le32 ver; /* major/minor/API/serial */
+ union {
+ struct {
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v1;
+ struct {
+ __le32 build; /* build number */
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v2;
+ } u;
};
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
@@ -608,11 +674,13 @@ struct iwl_hw_params {
u8 max_stations;
u8 bcast_sta_id;
u8 fat_channel;
- u8 sw_crypto;
+ u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
u32 max_data_size;
u32 max_bsm_size;
u32 ct_kill_threshold; /* value in hw-dependent units */
+ u32 ct_kill_exit_threshold; /* value in hw-dependent units */
+ /* for 1000, 6000 series and up */
u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens;
};
@@ -755,6 +823,8 @@ struct iwl_calib_result {
size_t buf_len;
};
+#define UCODE_ALIVE_TIMEOUT (5 * HZ)
+
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
@@ -1092,9 +1162,9 @@ struct iwl_priv {
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
- u32 debug_level;
u32 framecnt_to_us;
atomic_t restrict_refcnt;
+ bool disable_ht40;
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */
struct iwl_debugfs *dbgfs;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a2f341..51eed7226669 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
/* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_NONE:
+ IWL_ERR(priv, "Unknown hardware type\n");
+ return -ENOENT;
case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
@@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
u32 otpgp;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
-
+ if (priv->nvm_device_type == -ENOENT)
+ return -ENOENT;
/* allocate eeprom */
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
priv->cfg->eeprom_size =
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 17d61ac8ed61..b82ad15d5189 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -103,22 +103,23 @@ EXPORT_SYMBOL(get_cmd_string);
#define HOST_COMPLETE_TIMEOUT (HZ / 2)
-static int iwl_generic_cmd_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_generic_cmd_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *pkt = NULL;
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in %s.\n",
get_cmd_string(cmd->hdr.cmd));
- return 1;
+ 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);
- return 1;
+ return;
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -127,29 +128,26 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
case SENSITIVITY_CMD:
IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- break;
+ break;
default:
IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
}
#endif
-
- /* Let iwl_tx_complete free the response skb */
- return 1;
}
static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
int ret;
- BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+ BUG_ON(!(cmd->flags & CMD_ASYNC));
/* An asynchronous command can not expect an SKB to be set. */
- BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+ BUG_ON(cmd->flags & CMD_WANT_SKB);
/* Assign a generic callback if one is not provided */
- if (!cmd->meta.u.callback)
- cmd->meta.u.callback = iwl_generic_cmd_callback;
+ if (!cmd->callback)
+ cmd->callback = iwl_generic_cmd_callback;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EBUSY;
@@ -168,10 +166,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx;
int ret;
- BUG_ON(cmd->meta.flags & CMD_ASYNC);
+ BUG_ON(cmd->flags & CMD_ASYNC);
/* A synchronous command can not have a callback set. */
- BUG_ON(cmd->meta.u.callback != NULL);
+ BUG_ON(cmd->callback);
if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERR(priv,
@@ -183,9 +181,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
- if (cmd->meta.flags & CMD_WANT_SKB)
- cmd->meta.source = &cmd->meta;
-
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
@@ -222,7 +217,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO;
goto fail;
}
- if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id));
ret = -EIO;
@@ -233,20 +228,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto out;
cancel:
- if (cmd->meta.flags & CMD_WANT_SKB) {
- struct iwl_cmd *qcmd;
-
- /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ if (cmd->flags & CMD_WANT_SKB) {
+ /*
+ * Cancel the CMD_WANT_SKB flag for the cmd in the
* TX cmd queue. Otherwise in case the cmd comes
* in later, it will possibly set an invalid
- * address (cmd->meta.source). */
- qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
- qcmd->meta.flags &= ~CMD_WANT_SKB;
+ * address (cmd->meta.source).
+ */
+ priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+ ~CMD_WANT_SKB;
}
fail:
- if (cmd->meta.u.skb) {
- dev_kfree_skb_any(cmd->meta.u.skb);
- cmd->meta.u.skb = NULL;
+ if (cmd->reply_skb) {
+ dev_kfree_skb_any(cmd->reply_skb);
+ cmd->reply_skb = NULL;
}
out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@@ -256,7 +251,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync);
int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
- if (cmd->meta.flags & CMD_ASYNC)
+ if (cmd->flags & CMD_ASYNC)
return iwl_send_cmd_async(priv, cmd);
return iwl_send_cmd_sync(priv, cmd);
@@ -277,9 +272,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data,
- int (*callback)(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb))
+ void (*callback)(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb))
{
struct iwl_host_cmd cmd = {
.id = id,
@@ -287,8 +282,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
.data = data,
};
- cmd.meta.flags |= CMD_ASYNC;
- cmd.meta.u.callback = callback;
+ cmd.flags |= CMD_ASYNC;
+ cmd.callback = callback;
return iwl_send_cmd_async(priv, &cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index a1328c3c81ae..bd0b12efb5c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 5e64252f80f6..7cce8f85bcc6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -54,7 +54,7 @@ static const char *led_type_str[] = {
static const struct {
- u16 tpt;
+ u16 tpt; /* Mb/s */
u8 on_time;
u8 off_time;
} blink_tbl[] =
@@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
- .meta.flags = CMD_ASYNC,
- .meta.u.callback = NULL,
+ .flags = CMD_ASYNC,
+ .callback = NULL,
};
u32 reg;
@@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
}
/* Set led pattern command */
-static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
+static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
@@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
}
/* Set led register off */
-static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
+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);
@@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
#if 0
/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+static int iwl_led_on(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
}
/* Set led off command */
-int iwl4965_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_off(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */
-static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
+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);
@@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "Associated\n");
priv->allow_blinking = 1;
- return iwl4965_led_on_reg(priv, led_id);
+ return iwl_led_on_reg(priv, led_id);
}
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
{
@@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
+ * calculate blink rate according to last second Tx/Rx activities
*/
static int iwl_get_blink_rate(struct iwl_priv *priv)
{
int i;
- u64 current_tpt = priv->tx_stats[2].bytes;
- /* FIXME: + priv->rx_stats[2].bytes; */
+ /* count both tx and rx traffic to be able to
+ * handle traffic in either direction
+ */
+ u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wraparound */
@@ -314,7 +316,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;
- iwl4965_led_pattern(priv, IWL_LED_LINK,
+ iwl_led_pattern(priv, IWL_LED_LINK,
IWL_SOLID_BLINK_IDX);
}
return;
@@ -328,7 +330,7 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
@@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
wiphy_name(priv->hw->wiphy));
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
+ 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],
@@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
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 = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
@@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
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 = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index f2ea3f05f6e1..00937b3ee8ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -36,6 +36,7 @@
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
+#include "iwl-io.h"
#include "iwl-commands.h"
#include "iwl-debug.h"
#include "iwl-power.h"
@@ -97,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
};
+/* default Thermal Throttling transaction table
+ * Current state | Throttling Down | Throttling Up
+ *=============================================================================
+ * 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_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}
+};
+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}
+};
+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}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+ {IWL_TX_MULTI, true, IWL_RX_MULTI},
+ {IWL_TX_SINGLE, true, IWL_RX_MULTI},
+ {IWL_TX_SINGLE, false, IWL_RX_SINGLE},
+ {IWL_TX_NONE, false, IWL_RX_NONE}
+};
/* set card power command */
static int iwl_set_power(struct iwl_priv *priv, void *cmd)
@@ -211,6 +251,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
struct iwl_power_mgr *setting = &(priv->power_data);
int ret = 0;
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
u16 uninitialized_var(final_mode);
bool update_chains;
@@ -223,6 +264,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
if (setting->power_disabled)
final_mode = IWL_POWER_MODE_CAM;
+ if (tt->state >= IWL_TI_1) {
+ /* TT power setting overwrite user & system power setting */
+ final_mode = tt->tt_power_mode;
+ }
if (iwl_is_ready_rf(priv) &&
((setting->power_mode != final_mode) || force)) {
struct iwl_powertable_cmd cmd;
@@ -267,6 +312,487 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
}
EXPORT_SYMBOL(iwl_power_set_user_mode);
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->power_data.adv_tt)
+ return true;
+ restriction = tt->restriction + tt->state;
+ return restriction->is_ht;
+}
+EXPORT_SYMBOL(iwl_ht_enabled);
+
+u8 iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->power_data.adv_tt)
+ return IWL_TX_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->tx_stream;
+}
+EXPORT_SYMBOL(iwl_tx_ant_restriction);
+
+u8 iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->power_data.adv_tt)
+ return IWL_RX_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->rx_stream;
+}
+EXPORT_SYMBOL(iwl_rx_ant_restriction);
+
+#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ unsigned long flags;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ if (priv->power_data.ct_kill_toggle) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ priv->power_data.ct_kill_toggle = false;
+ } else {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ priv->power_data.ct_kill_toggle = true;
+ }
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ if (!iwl_grab_nic_access(priv))
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ /* Reschedule the ct_kill timer to occur in
+ * CT_KILL_EXIT_DURATION seconds to ensure we get a
+ * thermal update */
+ mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
+ CT_KILL_EXIT_DURATION * HZ);
+ }
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+ bool stop)
+{
+ if (stop) {
+ IWL_DEBUG_POWER(priv, "Stop all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+ IWL_DEBUG_POWER(priv,
+ "Schedule 5 seconds CT_KILL Timer\n");
+ mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
+ CT_KILL_EXIT_DURATION * HZ);
+ } else {
+ IWL_DEBUG_POWER(priv, "Wake all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_wake_queues(priv->hw);
+ }
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ enum iwl_tt_state new_state;
+ struct iwl_power_mgr *setting = &priv->power_data;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+#endif
+ /* in Celsius */
+ if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+ new_state = IWL_TI_CT_KILL;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+ new_state = IWL_TI_2;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+ new_state = IWL_TI_1;
+ else
+ new_state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ tt->tt_previous_temp = temp;
+#endif
+ if (tt->state != new_state) {
+ if (tt->state == IWL_TI_0) {
+ tt->sys_power_mode = setting->power_mode;
+ IWL_DEBUG_POWER(priv, "current power mode: %u\n",
+ setting->power_mode);
+ }
+ switch (new_state) {
+ case IWL_TI_0:
+ /* when system ready to go back to IWL_TI_0 state
+ * using system power mode instead of TT power mode
+ * revert back to the orginal power mode which was saved
+ * before enter Thermal Throttling state
+ * update priv->power_data.user_power_setting to the
+ * required power mode to make sure
+ * iwl_power_update_mode() will update power correctly.
+ */
+ priv->power_data.user_power_setting =
+ tt->sys_power_mode;
+ tt->tt_power_mode = tt->sys_power_mode;
+ break;
+ case IWL_TI_1:
+ tt->tt_power_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_TI_2:
+ tt->tt_power_mode = IWL_POWER_INDEX_4;
+ break;
+ default:
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+ break;
+ }
+ if (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");
+ } else {
+ if (new_state == IWL_TI_CT_KILL)
+ iwl_perform_ct_kill_task(priv, true);
+ else if (tt->state == IWL_TI_CT_KILL &&
+ new_state != IWL_TI_CT_KILL)
+ iwl_perform_ct_kill_task(priv, false);
+ tt->state = new_state;
+ IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
+ tt->state);
+ IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
+ tt->tt_power_mode);
+ }
+ }
+}
+
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ * Actions include relaxing the power down sleep thresholds and
+ * decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ * Condition Nxt State Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ * IWL_TI_0 T >= 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_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)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ int i;
+ bool changed = false;
+ enum iwl_tt_state old_state;
+ struct iwl_tt_trans *transaction;
+
+ old_state = tt->state;
+ for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+ /* based on the current TT state,
+ * find the curresponding transaction table
+ * each table has (IWL_TI_STATE_MAX - 1) entries
+ * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+ * will advance to the correct table.
+ * then based on the current temperature
+ * find the next state need to transaction to
+ * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+ * in the current table to see if transaction is needed
+ */
+ transaction = tt->transaction +
+ ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+ if (temp >= transaction->tt_low &&
+ temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d "
+ "degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+ tt->tt_previous_temp = temp;
+#endif
+ if (old_state !=
+ transaction->next_state) {
+ changed = true;
+ tt->state =
+ transaction->next_state;
+ }
+ break;
+ }
+ }
+ if (changed) {
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_power_mgr *setting = &priv->power_data;
+
+ if (tt->state >= IWL_TI_1) {
+ /* if switching from IWL_TI_0 to other TT state
+ * save previous power setting in tt->sys_power_mode */
+ if (old_state == IWL_TI_0)
+ tt->sys_power_mode = setting->power_mode;
+ /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+ if (!iwl_ht_enabled(priv))
+ /* disable HT */
+ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+ RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+ RXON_FLG_FAT_PROT_MSK |
+ RXON_FLG_HT_PROT_MSK);
+ else {
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+
+ } else {
+ /* restore system power setting */
+ /* the previous power mode was saved in
+ * tt->sys_power_mode when system move into
+ * Thermal Throttling state
+ * set power_data.user_power_setting to the previous
+ * system power mode to make sure power will get
+ * updated correctly
+ */
+ priv->power_data.user_power_setting =
+ tt->sys_power_mode;
+ tt->tt_power_mode = tt->sys_power_mode;
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+ if (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");
+ tt->state = old_state;
+ } else {
+ IWL_DEBUG_POWER(priv,
+ "Thermal Throttling to new state: %u\n",
+ tt->state);
+ if (old_state != IWL_TI_CT_KILL &&
+ tt->state == IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
+ iwl_perform_ct_kill_task(priv, true);
+
+ } else if (old_state == IWL_TI_CT_KILL &&
+ tt->state != IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
+ iwl_perform_ct_kill_task(priv, false);
+ }
+ }
+ }
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (tt->state != IWL_TI_CT_KILL) {
+ IWL_ERR(priv, "Device reached critical temperature "
+ "- ucode going to sleep!\n");
+ if (!priv->power_data.adv_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_MINIMAL_POWER_THRESHOLD);
+ else
+ iwl_advance_tt_handler(priv,
+ CT_KILL_THRESHOLD + 1);
+ }
+}
+EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ /* stop ct_kill_exit_tm timer */
+ del_timer_sync(&priv->power_data.ct_kill_exit_tm);
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ IWL_ERR(priv,
+ "Device temperature below critical"
+ "- ucode awake!\n");
+ if (!priv->power_data.adv_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+ else
+ iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
+ }
+}
+EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+ s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+ temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+ if (!priv->power_data.adv_tt)
+ iwl_legacy_tt_handler(priv, temp);
+ else
+ iwl_advance_tt_handler(priv, temp);
+}
+EXPORT_SYMBOL(iwl_tt_handler);
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ * Initialize Thermal Index and temperature threshold table
+ * Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+ struct iwl_power_mgr *setting = &priv->power_data;
+ int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+ struct iwl_tt_trans *transaction;
+
+ IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
+
+ memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+ tt->state = IWL_TI_0;
+ tt->sys_power_mode = setting->power_mode;
+ tt->tt_power_mode = tt->sys_power_mode;
+ init_timer(&priv->power_data.ct_kill_exit_tm);
+ priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
+ priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_6x00:
+ case CSR_HW_REV_TYPE_6x50:
+ IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
+ tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
+ IWL_TI_STATE_MAX, GFP_KERNEL);
+ tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
+ IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
+ GFP_KERNEL);
+ if (!tt->restriction || !tt->transaction) {
+ IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+ priv->power_data.adv_tt = false;
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ } else {
+ transaction = tt->transaction +
+ (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_0[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_1[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_2[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_3[0], size);
+ size = sizeof(struct iwl_tt_restriction) *
+ IWL_TI_STATE_MAX;
+ memcpy(tt->restriction,
+ &restriction_range[0], size);
+ priv->power_data.adv_tt = true;
+ }
+ break;
+ default:
+ IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
+ priv->power_data.adv_tt = false;
+ break;
+ }
+}
+EXPORT_SYMBOL(iwl_tt_initialize);
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->power_data.tt;
+
+ /* stop ct_kill_exit_tm timer if activated */
+ del_timer_sync(&priv->power_data.ct_kill_exit_tm);
+
+ if (priv->power_data.adv_tt) {
+ /* free advance thermal throttling memory */
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ }
+}
+EXPORT_SYMBOL(iwl_tt_exit);
+
/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 37ba3bb7a25a..3d49b7a45b74 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,6 +33,84 @@
struct iwl_priv;
+#define IWL_ABSOLUTE_ZERO 0
+#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
+#define IWL_TT_INCREASE_MARGIN 5
+
+/* Tx/Rx restrictions */
+#define IWL_TX_MULTI 0x02
+#define IWL_TX_SINGLE 0x01
+#define IWL_TX_NONE 0x00
+#define IWL_RX_MULTI 0x02
+#define IWL_RX_SINGLE 0x01
+#define IWL_RX_NONE 0x00
+
+/* Thermal Throttling State Machine states */
+enum iwl_tt_state {
+ IWL_TI_0, /* normal temperature, system power state */
+ IWL_TI_1, /* high temperature detect, low power state */
+ IWL_TI_2, /* higher temperature detected, lower power state */
+ IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+ IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table used
+ * by advance thermal throttling management
+ * based on the current thermal throttling state, determine
+ * number of tx/rx streams; and the status of HT operation
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ */
+struct iwl_tt_restriction {
+ u8 tx_stream;
+ bool is_ht;
+ u8 rx_stream;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table; used by
+ * advance thermal throttling algorithm to determine next
+ * thermal state to go based on the current temperature
+ * @next_state: next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ */
+struct iwl_tt_trans {
+ enum iwl_tt_state next_state;
+ u32 tt_low;
+ u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @state: current Thermal Throttling state
+ * @tt_power_mode: Thermal Throttling power mode index
+ * being used to set power level when
+ * when thermal throttling state != IWL_TI_0
+ * the tt_power_mode should set to different
+ * power mode based on the current tt state
+ * @sys_power_mode: previous system power mode
+ * before transition into TT state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ * thermal throttling to determine how many tx/rx streams
+ * should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ * state transaction
+ */
+struct iwl_tt_mgmt {
+ enum iwl_tt_state state;
+ u8 tt_power_mode;
+ u8 sys_power_mode;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ s32 tt_previous_temp;
+#endif
+ struct iwl_tt_restriction *restriction;
+ struct iwl_tt_trans *transaction;
+};
+
enum {
IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
IWL_POWER_INDEX_1,
@@ -59,10 +137,25 @@ struct iwl_power_mgr {
u8 power_mode;
u8 user_power_setting; /* set by user through sysfs */
u8 power_disabled; /* set by mac80211's CONF_PS */
+ struct iwl_tt_mgmt tt; /* Thermal Throttling Management */
+ bool adv_tt; /* false: legacy mode */
+ /* true: advance mode */
+ bool ct_kill_toggle; /* use to toggle the CSR bit when
+ * checking uCode temperature
+ */
+ struct timer_list ct_kill_exit_tm;
};
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
+bool iwl_ht_enabled(struct iwl_priv *priv);
+u8 iwl_tx_ant_restriction(struct iwl_priv *priv);
+u8 iwl_rx_ant_restriction(struct iwl_priv *priv);
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
void iwl_power_initialize(struct iwl_priv *priv);
#endif /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 3b9cac3fd216..d393e8f02102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 2b8d40b37a1c..5d5f2153f445 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u32 tsf_low;
int rssi;
- if (likely(!(priv->debug_level & IWL_DL_RX)))
+ if (likely(!(iwl_debug_level & IWL_DL_RX)))
return;
/* MAC header */
@@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+ iwl_print_hex_dump(IWL_DL_RX, header, length);
}
#endif
@@ -927,12 +927,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
hdr = (struct ieee80211_hdr *)rxb->skb->data;
/* in case of HW accelerated crypto and bad decryption, drop */
- if (!priv->hw_params.sw_crypto &&
+ if (!priv->cfg->mod_params->sw_crypto &&
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
priv->alloc_rxb_skb--;
rxb->skb = NULL;
}
@@ -1060,11 +1061,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
/* Set "1" to report good data frames in groups of 100 */
#ifdef CONFIG_IWLWIFI_DEBUG
- if (unlikely(priv->debug_level & IWL_DL_RX))
+ if (unlikely(iwl_debug_level & IWL_DL_RX))
iwl_dbg_report_frame(priv, rx_start, len, header, 1);
#endif
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
- rx_status.signal, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.qual,
(unsigned long long)rx_status.mactime);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e26875dbe859..c4c916df4a43 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -109,13 +109,13 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
-int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rx_packet *res;
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD,
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
};
/* If there isn't a scan actively going on in the hardware
@@ -132,7 +132,7 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be
@@ -146,11 +146,10 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
-EXPORT_SYMBOL(iwl_send_scan_abort);
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- channel =
- ieee80211_frequency_to_channel(channels[i].center_freq);
+ channel = ieee80211_frequency_to_channel(chan->center_freq);
scan_ch->channel = cpu_to_le16(channel);
ch_info = iwl_get_channel_info(priv, band, channel);
@@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
}
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
}
-int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv)
{
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
@@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
}
IWL_DEBUG_INFO(priv, "Starting scan...\n");
- if (priv->cfg->sku & IWL_SKU_G)
- priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
- if (priv->cfg->sku & IWL_SKU_A)
- priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
return 0;
}
-EXPORT_SYMBOL(iwl_scan_initiate);
#define IWL_DELAY_NEXT_SCAN (HZ*2)
@@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
{
unsigned long flags;
struct iwl_priv *priv = hw->priv;
- int ret;
+ int ret, i;
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
+ priv->scan_bands = 0;
+ for (i = 0; i < req->n_channels; i++)
+ priv->scan_bands |= BIT(req->channels[i]->band);
+
priv->scan_request = req;
ret = iwl_scan_initiate(priv);
@@ -570,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl_scan_cmd),
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
struct iwl_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 2addf735b193..79ea5cc2c89a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -97,8 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
-static int iwl_add_sta_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_add_sta_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta =
@@ -107,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
- return 1;
+ return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
- return 1;
+ return;
}
switch (res->u.add_sta.status) {
@@ -126,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
res->u.add_sta.status);
break;
}
-
- /* We didn't cache the SKB; let the caller free it */
- return 1;
}
int iwl_send_add_sta(struct iwl_priv *priv,
@@ -139,14 +137,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = {
.id = REPLY_ADD_STA,
- .meta.flags = flags,
+ .flags = flags,
.data = data,
};
if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl_add_sta_callback;
+ cmd.callback = iwl_add_sta_callback;
else
- cmd.meta.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB;
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd);
@@ -154,7 +152,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
@@ -175,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
@@ -324,8 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
-static int iwl_remove_sta_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+static void iwl_remove_sta_callback(struct iwl_priv *priv,
+ struct iwl_device_cmd *cmd,
+ struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta =
@@ -334,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
- return 1;
+ return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
- return 1;
+ return;
}
switch (res->u.rem_sta.status) {
@@ -352,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
break;
}
-
- /* We didn't cache the SKB; let the caller free it */
- return 1;
}
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
@@ -368,7 +364,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
struct iwl_host_cmd cmd = {
.id = REPLY_REMOVE_STA,
.len = sizeof(struct iwl_rem_sta_cmd),
- .meta.flags = flags,
+ .flags = flags,
.data = &rm_sta_cmd,
};
@@ -377,15 +373,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl_remove_sta_callback;
+ cmd.callback = iwl_remove_sta_callback;
else
- cmd.meta.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB;
ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
@@ -406,7 +402,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
}
priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return ret;
}
@@ -525,7 +521,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
struct iwl_host_cmd cmd = {
.id = REPLY_WEPKEY,
.data = wep_cmd,
- .meta.flags = CMD_ASYNC,
+ .flags = CMD_ASYNC,
};
memset(wep_cmd, 0, cmd_size +
@@ -566,6 +562,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
+ IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+ keyconf->keyidx);
if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
IWL_ERR(priv, "index %d not used in uCode key table.\n",
@@ -573,6 +571,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
priv->default_wep_key--;
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret);
@@ -853,6 +856,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
@@ -918,7 +926,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_TX_LINK_QUALITY_CMD,
.len = sizeof(struct iwl_link_quality_cmd),
- .meta.flags = flags,
+ .flags = flags,
.data = lq,
};
@@ -1044,11 +1052,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
/* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
@@ -1082,7 +1089,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
"Defaulting to broadcast...\n",
hdr->addr1);
- iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
default:
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 85ae7a62109c..6bb9602f3477 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
- len = sizeof(struct iwl_cmd) * q->n_window;
+ len = sizeof(struct iwl_device_cmd) * q->n_window;
/* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
@@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
kfree(txq->txb);
txq->txb = NULL;
+ /* deallocate arrays */
+ kfree(txq->cmd);
+ kfree(txq->meta);
+ txq->cmd = NULL;
+ txq->meta = NULL;
+
/* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq));
}
@@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
if (q->n_bd == 0)
return;
- len = sizeof(struct iwl_cmd) * q->n_window;
+ len = sizeof(struct iwl_device_cmd) * q->n_window;
len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */
@@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
{
int i, len;
int ret;
+ int actual_slots = slots_num;
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
- len = sizeof(struct iwl_cmd);
- for (i = 0; i <= slots_num; i++) {
- if (i == slots_num) {
- if (txq_id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
- else
- continue;
- }
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ actual_slots++;
+
+ txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+ GFP_KERNEL);
+ txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+ GFP_KERNEL);
+
+ if (!txq->meta || !txq->cmd)
+ goto out_free_arrays;
+
+ len = sizeof(struct iwl_device_cmd);
+ for (i = 0; i < actual_slots; i++) {
+ /* only happens for cmd queue */
+ if (i == slots_num)
+ len += IWL_MAX_SCAN_SIZE;
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
@@ -348,6 +363,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
+ /* aggregation TX queues will get their ID when aggregation begins */
+ if (txq_id <= IWL_TX_FIFO_AC3)
+ txq->swq_id = txq_id;
+
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -360,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
return 0;
err:
- for (i = 0; i < slots_num; i++) {
+ for (i = 0; i < actual_slots; i++)
kfree(txq->cmd[i]);
- txq->cmd[i] = NULL;
- }
+out_free_arrays:
+ kfree(txq->meta);
+ kfree(txq->cmd);
- if (txq_id == IWL_CMD_QUEUE_NUM) {
- kfree(txq->cmd[slots_num]);
- txq->cmd[slots_num] = NULL;
- }
return -ENOMEM;
}
EXPORT_SYMBOL(iwl_tx_queue_init);
@@ -669,7 +685,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_tx_queue *txq;
struct iwl_queue *q;
- struct iwl_cmd *out_cmd;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
struct iwl_tx_cmd *tx_cmd;
int swq_id, txq_id;
dma_addr_t phys_addr;
@@ -720,8 +737,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock;
}
- spin_unlock_irqrestore(&priv->lock, flags);
-
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
@@ -729,13 +744,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
- goto drop;
+ goto drop_unlock;
}
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
- swq_id = skb_get_queue_mapping(skb);
- txq_id = swq_id;
+ txq_id = skb_get_queue_mapping(skb);
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
@@ -746,18 +760,19 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
- }
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
}
txq = &priv->txq[txq_id];
+ swq_id = txq->swq_id;
q = &txq->q;
- txq->swq_id = swq_id;
- spin_lock_irqsave(&priv->lock, flags);
+ if (unlikely(iwl_queue_space(q) < q->high_mark))
+ goto drop_unlock;
+
+ if (ieee80211_is_data_qos(fc))
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -765,6 +780,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[q->write_ptr];
+ out_meta = &txq->meta[q->write_ptr];
tx_cmd = &out_cmd->cmd.tx;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -827,8 +843,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, len,
PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
- pci_unmap_len_set(&out_cmd->meta, len, len);
+ pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -868,11 +884,12 @@ int iwl_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_cmd->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
/* Set up entry for this TFD in Tx byte-count array */
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
le16_to_cpu(tx_cmd->len));
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
@@ -901,7 +918,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
drop_unlock:
spin_unlock_irqrestore(&priv->lock, flags);
-drop:
return -1;
}
EXPORT_SYMBOL(iwl_tx_skb);
@@ -921,7 +937,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
- struct iwl_cmd *out_cmd;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
int len, ret;
@@ -935,25 +952,31 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
* we will need to increase the size of the TFD entries */
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
- !(cmd->meta.flags & CMD_SIZE_HUGE));
+ !(cmd->flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL");
+ IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO;
}
- if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space for Tx\n");
return -ENOSPC;
}
spin_lock_irqsave(&priv->hcmd_lock, flags);
- idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+ idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
out_cmd = txq->cmd[idx];
+ out_meta = &txq->meta[idx];
+
+ out_meta->flags = cmd->flags;
+ if (cmd->flags & CMD_WANT_SKB)
+ out_meta->source = cmd;
+ if (cmd->flags & CMD_ASYNC)
+ out_meta->callback = cmd->callback;
out_cmd->hdr.cmd = cmd->id;
- memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
/* At this point, the out_cmd now has all of the incoming cmd
@@ -962,9 +985,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
out_cmd->hdr.flags = 0;
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
INDEX_TO_SEQ(q->write_ptr));
- if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
- len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta);
+ len = sizeof(struct iwl_device_cmd);
len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0;
@@ -996,8 +1019,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
- pci_unmap_len_set(&out_cmd->meta, len, fix_size);
+ pci_unmap_addr_set(out_meta, mapping, phys_addr);
+ pci_unmap_len_set(out_meta, len, fix_size);
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, fix_size, 1,
@@ -1066,8 +1089,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
}
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
- pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
+ pci_unmap_addr(&txq->meta[cmd_idx], mapping),
+ pci_unmap_len(&txq->meta[cmd_idx], len),
PCI_DMA_BIDIRECTIONAL);
for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
@@ -1098,7 +1121,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
int index = SEQ_TO_INDEX(sequence);
int cmd_index;
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
- struct iwl_cmd *cmd;
+ struct iwl_device_cmd *cmd;
+ struct iwl_cmd_meta *meta;
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
@@ -1108,24 +1132,24 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
txq_id, sequence,
priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
- iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
+ iwl_print_hex_error(priv, pkt, 32);
return;
}
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+ meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
/* Input error checking is done when commands are added to queue. */
- if (cmd->meta.flags & CMD_WANT_SKB) {
- cmd->meta.source->u.skb = rxb->skb;
- rxb->skb = NULL;
- } else if (cmd->meta.u.callback &&
- !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ if (meta->flags & CMD_WANT_SKB) {
+ meta->source->reply_skb = rxb->skb;
rxb->skb = NULL;
+ } else if (meta->callback)
+ meta->callback(priv, cmd, rxb->skb);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
- if (!(cmd->meta.flags & CMD_ASYNC)) {
+ if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
}
@@ -1170,6 +1194,8 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
IWL_ERR(priv, "Start AGG on invalid station\n");
return -ENXIO;
}
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
@@ -1186,6 +1212,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
tid_data = &priv->stations[sta_id].tid[tid];
*ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
+ priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
spin_unlock_irqrestore(&priv->sta_lock, flags);
ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index cb9bd4c8f25e..5ded8983b915 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_MAX_NUM_QUEUES,
+ .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -361,79 +361,9 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
priv->shared_phys);
}
-#define MAX_UCODE_BEACON_INTERVAL 1024
-#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA)
-
-static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor =
- (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- return cpu_to_le16(new_val);
-}
-
-static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 interval_tm_unit;
- u64 tsf, result;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
- tsf = priv->timestamp;
-
- beacon_int = priv->beacon_int;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- if (beacon_int == 0) {
- priv->rxon_timing.beacon_interval = cpu_to_le16(100);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
- } else {
- priv->rxon_timing.beacon_interval =
- cpu_to_le16(beacon_int);
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- }
-
- priv->rxon_timing.atim_window = 0;
- } else {
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- interval_tm_unit =
- (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
- result = do_div(tsf, interval_tm_unit);
- priv->rxon_timing.beacon_init_val =
- cpu_to_le32((u32) ((u64) interval_tm_unit - result));
-
- IWL_DEBUG_ASSOC(priv,
- "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
- struct iwl_cmd *cmd,
+ struct iwl_device_cmd *cmd,
struct sk_buff *skb_frag,
int sta_id)
{
@@ -473,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
* handle build REPLY_TX command notification.
*/
static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
+ struct iwl_device_cmd *cmd,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id)
{
@@ -546,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl3945_tx_cmd *tx;
struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL;
- struct iwl_cmd *out_cmd = NULL;
+ struct iwl_device_cmd *out_cmd;
+ struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
int txq_id = skb_get_queue_mapping(skb);
@@ -635,6 +566,7 @@ 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;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx, 0, sizeof(*tx));
@@ -682,8 +614,8 @@ 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_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
ieee80211_hdrlen(fc));
/*
@@ -712,8 +644,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to
* provide to unmap command*/
- pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
- pci_unmap_len_set(&out_cmd->meta, len, len);
+ pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
@@ -823,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum,
- .meta.flags = CMD_WANT_SKB,
+ .flags = CMD_WANT_SKB,
};
u32 add_time = le64_to_cpu(params->start_time);
int rc;
@@ -864,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO;
@@ -887,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break;
}
- dev_kfree_skb_any(cmd.meta.u.skb);
+ dev_kfree_skb_any(cmd.reply_skb);
return rc;
}
@@ -996,7 +928,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+ IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
(flags & SW_CARD_DISABLED) ? "Kill" : "On");
@@ -1714,7 +1646,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -1733,7 +1665,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1749,7 +1681,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1828,7 +1760,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1844,7 +1776,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl3945_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -1855,19 +1787,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- scan_ch->channel = channels[i].hw_value;
+ scan_ch->channel = chan->hw_value;
ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
@@ -1882,7 +1814,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
* and use long active_dwell time.
*/
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
scan_ch->type = 0; /* passive */
if (IWL_UCODE_API(priv->ucode_ver) == 1)
scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
@@ -2111,7 +2043,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/
static int iwl3945_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
@@ -2152,22 +2084,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error;
/* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -2208,12 +2142,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
- ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %zd does not match expected size\n",
+ ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -2296,44 +2231,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode instr len %zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl3945_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode data len %zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init instr len %zd\n", len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init data len %zd\n", len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) boot instr len %zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -2784,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl3945_scan_cmd),
- .meta.flags = CMD_SIZE_HUGE,
+ .flags = CMD_SIZE_HUGE,
};
int rc = 0;
struct iwl3945_scan_cmd *scan;
@@ -3066,7 +3001,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (rc)
@@ -3261,7 +3196,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
/* RXON Timing */
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing),
&priv->rxon_timing);
@@ -3375,13 +3310,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -3395,7 +3332,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -3643,12 +3580,10 @@ static ssize_t show_power_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
- int mode = priv->power_data.user_power_setting;
int level = priv->power_data.power_mode;
char *p = buf;
- p += sprintf(p, "INDEX:%d\t", level);
- p += sprintf(p, "USER:%d\n", mode);
+ p += sprintf(p, "%d\n", level);
return p - buf + 1;
}
@@ -4019,15 +3954,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev);
- if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_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, IWL39_MAX_NUM_QUEUES);
- err = -EINVAL;
- goto out_ieee80211_free_hw;
- }
-
/*
* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan.
@@ -4044,7 +3970,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = iwl3945_mod_params.debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -4340,14 +4265,12 @@ 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_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
-module_param_named(debug, iwl3945_mod_params.debug, uint, 0444);
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
+#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index 030401d367d3..c62da435285a 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -2,7 +2,6 @@ config IWM
tristate "Intel Wireless Multicomm 3200 WiFi driver"
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
- select WIRELESS_EXT
select FW_LOADER
help
The Intel Wireless Multicomm 3200 hardware is a combo
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile
index 927f022545c1..d34291b652d3 100644
--- a/drivers/net/wireless/iwmc3200wifi/Makefile
+++ b/drivers/net/wireless/iwmc3200wifi/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_IWM) := iwmc3200wifi.o
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
-iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o
+iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 96f714e6e12b..3f5a08fa401f 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/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
@@ -130,6 +131,133 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
.n_bitrates = iwm_a_rates_size,
};
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+ const u8 *mac_addr, struct key_params *params)
+{
+ key->hdr.key_idx = key_index;
+ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+ key->hdr.multicast = 1;
+ memset(key->hdr.mac, 0xff, ETH_ALEN);
+ } else {
+ key->hdr.multicast = 0;
+ memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+ }
+
+ if (params) {
+ if (params->key_len > WLAN_MAX_KEY_LEN ||
+ params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+ return -EINVAL;
+
+ key->cipher = params->cipher;
+ key->key_len = params->key_len;
+ key->seq_len = params->seq_len;
+ memcpy(key->key, params->key, key->key_len);
+ memcpy(key->seq, params->seq, key->seq_len);
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ int ret;
+
+ IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+ memset(key, 0, sizeof(struct iwm_key));
+ ret = iwm_key_init(key, key_index, mac_addr, params);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Invalid key_params\n");
+ return ret;
+ }
+
+ return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params*))
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ struct key_params params;
+
+ IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+ memset(&params, 0, sizeof(params));
+
+ params.cipher = key->cipher;
+ params.key_len = key->key_len;
+ params.seq_len = key->seq_len;
+ params.seq = key->seq;
+ params.key = key->key;
+
+ callback(cookie, &params);
+
+ return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+ return 0;
+ }
+
+ if (key_index == iwm->default_key)
+ iwm->default_key = -1;
+
+ return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 key_index)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_ERR(iwm, "Key %d not used\n", key_index);
+ return -EINVAL;
+ }
+
+ iwm->default_key = key_index;
+
+ return iwm_set_tx_key(iwm, key_index);
+}
+
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ if (memcmp(mac, iwm->bssid, ETH_ALEN))
+ return -ENOENT;
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = iwm->rate * 10;
+
+ if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = iwm->wstats.qual.level;
+ }
+
+ return 0;
+}
+
+
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +295,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
return 0;
}
-static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *ndev;
struct wireless_dev *wdev;
struct iwm_priv *iwm;
u32 old_mode;
- /* we're under RTNL */
- ndev = __dev_get_by_index(&init_net, ifindex);
- if (!ndev)
- return -ENODEV;
-
wdev = ndev->ieee80211_ptr;
iwm = ndev_to_iwm(ndev);
old_mode = iwm->conf.mode;
@@ -329,12 +452,245 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return 0;
}
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+ enum nl80211_auth_type sme_auth_type)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+ *auth_type = UMAC_AUTH_TYPE_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+ IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ } else {
+ IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ }
+
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+ if (!wpa_version) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+ return 0;
+ }
+
+ if (wpa_version & NL80211_WPA_VERSION_2)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+ return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+ u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+ &iwm->umac_profile->sec.mcast_cipher;
+
+ if (!cipher) {
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ return 0;
+ }
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X)
+ *auth_type = UMAC_AUTH_TYPE_8021X;
+ else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ else
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ } else {
+ IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ int ret;
+
+ if (!test_bit(IWM_STATUS_READY, &iwm->status))
+ return -EIO;
+
+ if (!sme->ssid)
+ return -EINVAL;
+
+ if (chan)
+ iwm->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+ memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->bssid) {
+ IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+ memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+ iwm->umac_profile->bss_num = 1;
+ } else {
+ memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+ iwm->umac_profile->bss_num = 0;
+ }
+
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+ true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+ if (iwm->umac_profile_active)
+ return iwm_invalidate_mlme_profile(iwm);
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+ enum tx_power_setting type, int dbm)
+{
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ *dbm = iwm->txpower;
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ u32 power_index;
+
+ if (enabled)
+ power_index = IWM_POWER_INDEX_DEFAULT;
+ else
+ power_index = IWM_POWER_INDEX_MIN;
+
+ if (power_index == iwm->conf.power_index)
+ return 0;
+
+ iwm->conf.power_index = power_index;
+
+ return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
+ .add_key = iwm_cfg80211_add_key,
+ .get_key = iwm_cfg80211_get_key,
+ .del_key = iwm_cfg80211_del_key,
+ .set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss,
+ .set_tx_power = iwm_cfg80211_set_txpower,
+ .get_tx_power = iwm_cfg80211_get_txpower,
+ .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+};
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
};
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
@@ -379,6 +735,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
ret = wiphy_register(wdev->wiphy);
if (ret < 0) {
dev_err(dev, "Couldn't register wiphy device\n");
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 834a7f544e5d..0d6637005f42 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -70,14 +70,27 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
bool resp)
{
+ struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
struct iwm_umac_cmd umac_cmd;
+ int ret;
+ u8 oid = hdr->oid;
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
- return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
- payload, payload_size);
+ ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+ payload, payload_size);
+
+ if (resp) {
+ ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+ test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+ 3 * HZ);
+
+ return ret ? 0 : -EBUSY;
+ }
+
+ return ret;
}
static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -106,7 +119,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
{5, 5, 0, COEX_CALIBRATION_FLAGS},
- {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+ {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -331,8 +344,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
return ret;
}
-int iwm_send_umac_config(struct iwm_priv *iwm,
- __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
{
int ret;
@@ -360,6 +372,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_WIRELESS_MODE,
+ iwm->conf.wireless_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_COEX_MODE, iwm->conf.coexist_mode);
if (ret < 0)
return ret;
@@ -401,7 +419,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_PM_CTRL_FLAGS, 0x30001);
+ CFG_PM_CTRL_FLAGS, 0x1);
if (ret < 0)
return ret;
@@ -461,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
target_cmd.eop = 1;
ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
- if (ret < 0)
+ if (ret < 0) {
IWM_ERR(iwm, "Couldn't send READ command\n");
+ return ret;
+ }
/* When succeding, the send_target routine returns the seq number */
seq_num = ret;
@@ -482,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
kfree(cmd);
- return ret;
+ return 0;
}
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -492,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
mac_align, sizeof(mac_align));
- if (ret < 0)
+ if (ret)
return ret;
if (is_valid_ether_addr(mac_align))
@@ -510,9 +530,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
{
struct iwm_umac_tx_key_id tx_key_id;
- if (!iwm->default_key || !iwm->default_key->in_use)
- return -EINVAL;
-
tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
sizeof(struct iwm_umac_wifi_if));
@@ -555,10 +572,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
return 0;
}
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key)
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
{
- int ret;
+ int ret = 0;
u8 cmd[64], *sta_addr, *key_data, key_len;
s8 key_idx;
u16 cmd_size = 0;
@@ -568,15 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
- if (set_tx_key)
- iwm->default_key = key;
-
- /*
- * We check if our current profile is valid.
- * If not, we dont push the key, we just cache them,
- * so that with the next siwsessid call, the keys
- * will be actually pushed.
- */
if (!remove) {
ret = iwm_check_profile(iwm);
if (ret < 0)
@@ -589,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_idx = key->hdr.key_idx;
if (!remove) {
- IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
- key_idx, set_tx_key);
+ IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -602,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
iwm->umac_profile->sec.auth_type,
iwm->umac_profile->sec.flags);
- switch (key->alg) {
- case UMAC_CIPHER_TYPE_WEP_40:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
wep40->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -617,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;
- case UMAC_CIPHER_TYPE_WEP_104:
+ case WLAN_CIPHER_SUITE_WEP104:
wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
wep104->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -631,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;
- case UMAC_CIPHER_TYPE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key_hdr->key_idx++;
ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
ccmp->hdr.buf_size =
@@ -643,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(ccmp->key, key_data, key_len);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_ccmp);
break;
- case UMAC_CIPHER_TYPE_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key_hdr->key_idx++;
tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
tkip->hdr.buf_size =
@@ -666,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
IWM_TKIP_MIC_SIZE);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_tkip);
break;
@@ -676,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
return -ENOTSUPP;
}
- if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
- (key->alg == UMAC_CIPHER_TYPE_TKIP))
+ if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
+ (key->cipher == WLAN_CIPHER_SUITE_CCMP))
/*
* UGLY_UGLY_UGLY
* Copied HACK from the MWG driver.
@@ -688,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
schedule_timeout_interruptible(usecs_to_jiffies(300));
ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
- if (ret < 0)
- goto err;
-
- /*
- * We need a default key only if it is set and
- * if we're doing WEP.
- */
- if (iwm->default_key == key &&
- ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
- (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
- ret = iwm_set_tx_key(iwm, key_idx);
- if (ret < 0)
- goto err;
- }
} else {
struct iwm_umac_key_remove key_remove;
+ IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
+
key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
key_remove.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -715,23 +709,19 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
sizeof(struct iwm_umac_key_remove),
1);
- if (ret < 0)
+ if (ret)
return ret;
- iwm->keys[key_idx].in_use = 0;
+ iwm->keys[key_idx].key_len = 0;
}
- return 0;
-
- err:
- kfree(key);
return ret;
}
int iwm_send_mlme_profile(struct iwm_priv *iwm)
{
- int ret, i;
+ int ret;
struct iwm_umac_profile profile;
memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -741,45 +731,18 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
sizeof(struct iwm_umac_wifi_if));
ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Send profile command failed\n");
return ret;
}
- /* Wait for the profile to be active */
- ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- iwm->umac_profile_active == 1,
- 3 * HZ);
- if (!ret)
- return -EBUSY;
-
-
- for (i = 0; i < IWM_NUM_KEYS; i++)
- if (iwm->keys[i].in_use) {
- int default_key = 0;
- struct iwm_key *key = &iwm->keys[i];
-
- if (key == iwm->default_key)
- default_key = 1;
-
- /* Wait for the profile before sending the keys */
- wait_event_interruptible_timeout(iwm->mlme_queue,
- (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
- test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
- 3 * HZ);
-
- ret = iwm_set_key(iwm, 0, default_key, key);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
{
- int ret;
struct iwm_umac_invalidate_profile invalid;
+ int ret;
invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
invalid.hdr.buf_size =
@@ -789,16 +752,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
invalid.reason = WLAN_REASON_UNSPECIFIED;
ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
- if (ret < 0)
+ if (ret)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0),
- 2 * HZ);
- if (!ret)
- return -EBUSY;
+ (iwm->umac_profile_active == 0), 2 * HZ);
- return 0;
+ return ret ? 0 : -EBUSY;
}
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -881,7 +841,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
}
ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Couldn't send scan request\n");
return ret;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 36b13a130595..e24d5b633997 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -106,8 +106,7 @@ enum {
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
- CFG_TLC_FIXED_RATE,
- CFG_TLC_FIXED_RATE_FLAGS,
+ CFG_TLC_FIXED_MCS,
CFG_TLC_CONTROL_FLAGS,
CFG_TLC_SR_MIN_FAIL,
CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
/* Wireless mode */
#define WIRELESS_MODE_11A 0x1
#define WIRELESS_MODE_11G 0x2
+#define WIRELESS_MODE_11N 0x4
#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
#define UMAC_PROFILE_QOS_ALLOWED 0x2
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
index 0f34b84fd2eb..365910fbe01e 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm)
return -ENOMEM;
for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
- break;
-#endif
ret = iwm_eeprom_read(iwm, i);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index ec1a15a5a0e4..0f32cab9ced4 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
*/
int iwm_load_fw(struct iwm_priv *iwm)
{
+ unsigned long init_calib_map, periodic_calib_map;
int ret;
/* We first start downloading the UMAC */
@@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm)
return ret;
}
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
- &iwm->conf.periodic_calib_map);
- }
-#endif
+ init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+ periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
+
/* Read RX IQ calibration result from EEPROM */
- if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
+ if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
iwm_store_rxiq_calib_result(iwm);
set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
}
iwm_send_prio_table(iwm);
- iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+ iwm_send_init_calib_cfg(iwm, init_calib_map);
- while (iwm->calib_done_map != iwm->conf.init_calib_map) {
+ while (iwm->calib_done_map != init_calib_map) {
ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
if (ret) {
@@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
}
IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
"0x%lx, requested calibrations: 0x%lx\n",
- iwm->calib_done_map, iwm->conf.init_calib_map);
+ iwm->calib_done_map, init_calib_map);
}
/* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
- iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+ iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index ee127fe4f43f..c430418248b4 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -105,9 +105,9 @@
#include "umac.h"
#include "debug.h"
-static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
- struct iwm_nonwifi_cmd *cmd,
- struct iwm_udma_nonwifi_cmd *udma_cmd)
+static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+ struct iwm_nonwifi_cmd *cmd,
+ struct iwm_udma_nonwifi_cmd *udma_cmd)
{
INIT_LIST_HEAD(&cmd->pending);
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->seq_num = iwm->nonwifi_seq_num;
udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
- cmd->seq_num = iwm->nonwifi_seq_num++;
+ iwm->nonwifi_seq_num++;
iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->buf.len = 0;
memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+
+ return cmd->seq_num;
}
u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
const void *payload)
{
struct iwm_nonwifi_cmd *cmd;
- int ret;
+ int ret, seq_num;
cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
return -ENOMEM;
}
- iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+ seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
if (ret < 0)
return ret;
- return cmd->seq_num;
+ return seq_num;
}
static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 77c339f8516c..7a51bc340fda 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -52,8 +52,6 @@
#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
#define IWM_AUTHOR "<ilw@linux.intel.com>"
-#define CONFIG_IWM_B0_HW_SUPPORT 1
-
#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,7 @@
struct iwm_conf {
u32 sdio_ior_timeout;
- unsigned long init_calib_map;
- unsigned long periodic_calib_map;
+ unsigned long calib_map;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -87,9 +84,6 @@ struct iwm_conf {
u8 ibss_channel;
u8 mac_addr[ETH_ALEN];
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- bool hw_b0;
-#endif
};
enum {
@@ -162,13 +156,11 @@ struct iwm_umac_key_hdr {
struct iwm_key {
struct iwm_umac_key_hdr hdr;
- u8 in_use;
- u8 alg;
- u32 flags;
- u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 key_len;
- u8 key[32];
+ u32 cipher;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+ int key_len;
+ int seq_len;
};
#define IWM_RX_ID_HASH 0xff
@@ -186,10 +178,6 @@ struct iwm_key {
#define IWM_STATUS_ASSOCIATING 3
#define IWM_STATUS_ASSOCIATED 4
-#define IWM_RADIO_RFKILL_OFF 0
-#define IWM_RADIO_RFKILL_HW 1
-#define IWM_RADIO_RFKILL_SW 2
-
struct iwm_tx_queue {
int id;
struct sk_buff_head queue;
@@ -223,7 +211,6 @@ struct iwm_priv {
struct iwm_conf conf;
unsigned long status;
- unsigned long radio;
struct list_head pending_notif;
wait_queue_head_t notif_queue;
@@ -242,6 +229,7 @@ struct iwm_priv {
u8 bssid[ETH_ALEN];
u8 channel;
u16 rate;
+ u32 txpower;
struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
struct list_head bss_list;
@@ -276,7 +264,10 @@ struct iwm_priv {
struct iwm_tx_queue txq[IWM_TX_QUEUES];
struct iwm_key keys[IWM_NUM_KEYS];
- struct iwm_key *default_key;
+ s8 default_key;
+
+ DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+ wait_queue_head_t wifi_ntfy_queue;
wait_queue_head_t mlme_queue;
@@ -289,7 +280,11 @@ struct iwm_priv {
struct timer_list watchdog;
struct work_struct reset_worker;
struct mutex mutex;
- struct rfkill *rfkill;
+
+ u8 *req_ie;
+ int req_ie_len;
+ u8 *resp_ie;
+ int resp_ie_len;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
@@ -311,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm)
#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
-extern const struct iw_handler_def iwm_iw_handler_def;
-
void *iwm_if_alloc(int sizeof_bus, struct device *dev,
struct iwm_if_ops *if_ops);
void iwm_if_free(struct iwm_priv *iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index db2e5eea1895..19213e165f5f 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -396,6 +396,10 @@ enum {
CALIBRATION_CMD_NUM,
};
+#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
+#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
+#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
+
struct iwm_lmac_calib_hdr {
u8 opcode;
u8 first_grp;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 8be206d58222..cf2574442b57 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,11 +53,7 @@
static struct iwm_conf def_iwm_conf = {
.sdio_ior_timeout = 5000,
- .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
- BIT(PHY_CALIBRATE_LO_CMD) |
- BIT(PHY_CALIBRATE_TX_IQ_CMD) |
- BIT(PHY_CALIBRATE_RX_IQ_CMD),
- .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
+ .calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
BIT(PHY_CALIBRATE_LO_CMD) |
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
INIT_LIST_HEAD(&iwm->pending_notif);
init_waitqueue_head(&iwm->notif_queue);
init_waitqueue_head(&iwm->nonwifi_queue);
+ init_waitqueue_head(&iwm->wifi_ntfy_queue);
init_waitqueue_head(&iwm->mlme_queue);
memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
spin_lock_init(&iwm->tx_credit.lock);
@@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
for (i = 0; i < IWM_NUM_KEYS; i++)
memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
- iwm->default_key = NULL;
+ iwm->default_key = -1;
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
@@ -500,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ kfree(iwm->req_ie);
+ iwm->req_ie = NULL;
+ iwm->req_ie_len = 0;
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = NULL;
+ iwm->resp_ie_len = 0;
+
del_timer_sync(&iwm->watchdog);
}
@@ -518,13 +522,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
{
int ret;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
- return 0;
- }
-#endif
-
ret = iwm_send_umac_channel_list(iwm);
if (ret) {
IWM_ERR(iwm, "Send channel list failed\n");
@@ -642,19 +639,10 @@ int __iwm_up(struct iwm_priv *iwm)
}
}
- iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
- GFP_KERNEL);
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
- goto err_fw;
- }
-
- iwm_init_default_profile(iwm, iwm->umac_profile);
-
ret = iwm_channels_init(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't init channels\n");
- goto err_profile;
+ goto err_fw;
}
/* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +650,6 @@ int __iwm_up(struct iwm_priv *iwm)
return 0;
- err_profile:
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
-
err_fw:
iwm_eeprom_exit(iwm);
@@ -704,11 +688,10 @@ int __iwm_down(struct iwm_priv *iwm)
clear_bit(IWM_STATUS_READY, &iwm->status);
iwm_eeprom_exit(iwm);
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
iwm_bss_list_clean(iwm);
-
- iwm->default_key = NULL;
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+ iwm->umac_profile_active = false;
+ iwm->default_key = -1;
iwm->core_enabled = 0;
ret = iwm_bus_disable(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index aaa20c6885c8..35ec006c2d2c 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -48,29 +48,22 @@
#include <linux/netdevice.h>
#include "iwm.h"
+#include "commands.h"
#include "cfg80211.h"
#include "debug.h"
static int iwm_open(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_up(iwm);
- return ret;
+ return iwm_up(iwm);
}
static int iwm_stop(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_down(iwm);
-
- return ret;
+ return iwm_down(iwm);
}
/*
@@ -106,10 +99,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
int ret = 0;
wdev = iwm_wdev_alloc(sizeof_bus, dev);
- if (!wdev) {
- dev_err(dev, "no memory for wireless device instance\n");
- return ERR_PTR(-ENOMEM);
- }
+ if (IS_ERR(wdev))
+ return wdev;
iwm = wdev_to_iwm(wdev);
iwm->bus_ops = if_ops;
@@ -130,13 +121,24 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
}
ndev->netdev_ops = &iwm_netdev_ops;
- ndev->wireless_handlers = &iwm_iw_handler_def;
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
+ iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+ GFP_KERNEL);
+ if (!iwm->umac_profile) {
+ dev_err(dev, "Couldn't alloc memory for profile\n");
+ goto out_profile;
+ }
+
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+
return iwm;
+ out_profile:
+ free_netdev(ndev);
+
out_priv:
iwm_priv_deinit(iwm);
@@ -151,8 +153,10 @@ void iwm_if_free(struct iwm_priv *iwm)
return;
free_netdev(iwm_to_ndev(iwm));
- iwm_wdev_free(iwm);
iwm_priv_deinit(iwm);
+ kfree(iwm->umac_profile);
+ iwm->umac_profile = NULL;
+ iwm_wdev_free(iwm);
}
int iwm_if_add(struct iwm_priv *iwm)
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index d73cf96c6dc6..86079a187eef 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err;
-
IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
@@ -143,17 +142,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_umac_notif_init_complete *init_complete =
(struct iwm_umac_notif_init_complete *)(buf);
u16 status = le16_to_cpu(init_complete->status);
+ bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
- if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+ if (blocked)
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- } else {
+ else
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- }
+
+ wiphy_rfkill_set_hw_state(wiphy, blocked);
return 0;
}
@@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
hdr = (struct iwm_umac_wifi_in_hdr *)buf;
- IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+ IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
- IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
- le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
- IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
- IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
- le16_to_cpu(tx_resp->retry_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
- IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
- le16_to_cpu(tx_resp->byte_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+ IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+ le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+ IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+ IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+ le16_to_cpu(tx_resp->retry_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+ IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+ le16_to_cpu(tx_resp->byte_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
return 0;
}
@@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
- ticket->id);
+ IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
/*
@@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
u16 id, buf_offset;
u32 packet_size;
- IWM_DBG_NTF(iwm, DBG, "\n");
+ IWM_DBG_RX(iwm, DBG, "\n");
wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
- IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
- wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+ IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+ wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
@@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
{
struct iwm_umac_notif_assoc_complete *complete =
(struct iwm_umac_notif_assoc_complete *)buf;
- union iwreq_data wrqu;
IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
complete->bssid, complete->status);
- memset(&wrqu, 0, sizeof(wrqu));
-
clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
switch (le32_to_cpu(complete->status)) {
@@ -520,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm_link_on(iwm);
- memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
break;
case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -528,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm->channel = 0;
iwm_link_off(iwm);
+
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
default:
break;
}
- if (iwm->conf.mode == UMAC_MODE_IBSS) {
- cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
- return 0;
- }
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+ return 0;
+ ibss:
+ cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
return 0;
}
@@ -769,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_mgt_frame *mgt_frame =
- (struct iwm_umac_notif_mgt_frame *)buf;
+ (struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
u8 *ie;
- unsigned int event;
- union iwreq_data wrqu;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) {
ie = mgt->u.assoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
ie = mgt->u.reassoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
ie = mgt->u.assoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
ie = mgt->u.reassoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else {
IWM_ERR(iwm, "Unsupported management frame");
return 0;
}
- wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
-
- IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
- wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
-
return 0;
}
@@ -875,6 +892,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
/* UMAC passes rate info multiplies by 2 */
iwm->rate = max_rate >> 1;
}
+ iwm->txpower = le32_to_cpu(stats->tx_power);
wstats->status = 0;
@@ -922,13 +940,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
return -EINVAL;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
- if (eeprom_proxy->buf[0] == 0xff)
- iwm->conf.hw_b0 = 1;
- }
-#endif
-
switch (hdr_type) {
case IWM_UMAC_CMD_EEPROM_TYPE_READ:
memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
@@ -993,12 +1004,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
(struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
- "oid is %d\n", hdr->oid);
+ "oid is 0x%x\n", hdr->oid);
+
+ if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+ set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+ wake_up_interruptible(&iwm->wifi_ntfy_queue);
+ } else
+ return -EINVAL;
switch (hdr->oid) {
case UMAC_WIFI_IF_CMD_SET_PROFILE:
iwm->umac_profile_active = 1;
- wake_up_interruptible(&iwm->mlme_queue);
break;
default:
break;
@@ -1010,6 +1026,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1035,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- if (flags & IWM_CARD_STATE_HW_DISABLED)
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- else
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+ wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
return 0;
}
@@ -1362,13 +1376,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
skb->dev = iwm_to_ndev(iwm);
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb));
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += skb->len;
- if (netif_rx(skb) == NET_RX_DROP) {
+ if (netif_rx_ni(skb) == NET_RX_DROP) {
IWM_ERR(iwm, "Packet dropped\n");
ndev->stats.rx_dropped++;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 916681837fd2..8b1de84003ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
@@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
@@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = {
static int __init iwm_sdio_init_module(void)
{
- int ret;
-
- ret = sdio_register_driver(&iwm_sdio_driver);
-
- return ret;
+ return sdio_register_driver(&iwm_sdio_driver);
}
static void __exit iwm_sdio_exit_module(void)
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
index b3c156b08dda..aab6b6892e45 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.h
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.h
@@ -39,9 +39,6 @@
#ifndef __IWM_SDIO_H__
#define __IWM_SDIO_H__
-#define SDIO_VENDOR_ID_INTEL 0x89
-#define SDIO_DEVICE_ID_IWM 0x1403
-
#define IWM_SDIO_DATA_ADDR 0x0
#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
#define IWM_SDIO_INTR_STATUS_ADDR 0x13
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 4a95cce1f0a6..c5a14ae3160a 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
+#define WIFI_IF_NTFY_MAX 0xff
+
/* Notification structures */
struct iwm_umac_notif_wifi_if {
struct iwm_umac_wifi_in_hdr hdr;
@@ -613,6 +615,7 @@ struct iwm_umac_notif_alive {
} __attribute__ ((packed));
struct iwm_umac_notif_init_complete {
+ struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
} __attribute__ ((packed));
@@ -641,6 +644,11 @@ struct iwm_fw_error_hdr {
__le32 umac_status;
__le32 lmac_status;
__le32 sdio_status;
+ __le32 dbm_sample_ctrl;
+ __le32 dbm_buf_base;
+ __le32 dbm_buf_end;
+ __le32 dbm_buf_write_ptr;
+ __le32 dbm_buf_cycle_cnt;
} __attribute__ ((packed));
struct iwm_umac_notif_error {
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
deleted file mode 100644
index 584c94d0f399..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * Intel Wireless Multicomm 3200 WiFi driver
- *
- * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
- * Samuel Ortiz <samuel.ortiz@intel.com>
- * Zhu Yi <yi.zhu@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-
-#include "iwm.h"
-#include "umac.h"
-#include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iw_statistics *wstats = &iwm->wstats;
-
- if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- memset(wstats, 0, sizeof(struct iw_statistics));
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
-
-static int iwm_wext_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (freq->flags == IW_FREQ_AUTO)
- return 0;
-
- /* frequency/channel can only be set in IBSS mode */
- if (iwm->conf.mode != UMAC_MODE_IBSS)
- return -EOPNOTSUPP;
-
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
-}
-
-static int iwm_wext_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->e = 0;
- freq->m = iwm->channel;
-
- return 0;
-}
-
-static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
- iwm->umac_profile->bssid[0]);
- memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
- iwm->umac_profile->bss_num = 0;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
- ap_addr->sa_data);
- memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
- ETH_ALEN);
- iwm->umac_profile->bss_num = 1;
- }
-
- if (iwm->umac_profile_active) {
- if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
- return 0;
-
- iwm_invalidate_mlme_profile(iwm);
- }
-
- if (iwm->umac_profile->ssid.ssid_len)
- return iwm_send_mlme_profile(iwm);
-
- return 0;
-}
-
-static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- switch (iwm->conf.mode) {
- case UMAC_MODE_IBSS:
- return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
- case UMAC_MODE_BSS:
- if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- size_t len = data->length;
- int ret;
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (iwm->umac_profile_active) {
- if (iwm->umac_profile->ssid.ssid_len == len &&
- !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
- return 0;
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
-
- iwm->umac_profile->ssid.ssid_len = len;
- memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- if (iwm->conf.mode == UMAC_MODE_IBSS)
- return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- data->length = iwm->umac_profile->ssid.ssid_len;
- if (data->length) {
- memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
- data->flags = 1;
- } else
- data->flags = 0;
-
- return 0;
-}
-
-static struct iwm_key *
-iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
- struct iw_encode_ext *ext, u8 alg)
-{
- struct iwm_key *key = &iwm->keys[key_idx];
-
- memset(key, 0, sizeof(struct iwm_key));
- memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
- key->hdr.key_idx = key_idx;
- if (is_broadcast_ether_addr(ext->addr.sa_data))
- key->hdr.multicast = 1;
-
- key->in_use = in_use;
- key->flags = ext->ext_flags;
- key->alg = alg;
- key->key_len = ext->key_len;
- memcpy(key->key, ext->key, ext->key_len);
-
- return key;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- rate->value = iwm->rate * 1000000;
-
- return 0;
-}
-
-static int iwm_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key_buf)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *uninitialized_var(key);
- int idx, i, uninitialized_var(alg), remove = 0, ret;
-
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "UMAC profile not allocated yet\n");
- return -ENODEV;
- }
-
- if (erq->length == WLAN_KEY_LEN_WEP40) {
- alg = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- } else if (erq->length == WLAN_KEY_LEN_WEP104) {
- alg = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- }
-
- if (erq->flags & IW_ENCODE_RESTRICTED)
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- else
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- else
- iwm->default_key = &iwm->keys[idx];
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if (erq->length == 0) {
- if (!iwm->keys[idx].in_use)
- return -EINVAL;
- iwm->default_key = &iwm->keys[idx];
- }
-
- if (erq->length) {
- key = &iwm->keys[idx];
- memset(key, 0, sizeof(struct iwm_key));
- memset(key->hdr.mac, 0xff, ETH_ALEN);
- key->hdr.key_idx = idx;
- key->hdr.multicast = 1;
- key->in_use = !remove;
- key->alg = alg;
- key->key_len = erq->length;
- memcpy(key->key, key_buf, erq->length);
-
- IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
- idx, !!iwm->default_key);
- }
-
- if (remove) {
- if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
- int j;
- for (j = 0; j < IWM_NUM_KEYS; j++)
- if (iwm->keys[j].in_use) {
- struct iwm_key *k = &iwm->keys[j];
-
- k->in_use = 0;
- ret = iwm_set_key(iwm, remove, 0, k);
- if (ret < 0)
- return ret;
- }
-
- iwm->umac_profile->sec.ucast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.mcast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.auth_type =
- UMAC_AUTH_TYPE_OPEN;
-
- return 0;
- } else {
- key->in_use = 0;
- return iwm_set_key(iwm, remove, 0, key);
- }
- }
-
- /*
- * If we havent set a profile yet, we cant set keys.
- * Keys will be pushed after we're associated.
- */
- if (!iwm->umac_profile_active)
- return 0;
-
- /*
- * If there is a current active profile, but no
- * default key, it's not worth trying to associate again.
- */
- if (!iwm->default_key)
- return 0;
-
- /*
- * Here we have an active profile, but a key setting changed.
- * We thus have to invalidate the current profile, and push the
- * new one. Keys will be pushed when association takes place.
- */
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int idx, i;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!iwm->default_key) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_NOKEY;
- return 0;
- } else
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
-
- erq->flags = idx + 1;
-
- if (!iwm->keys[idx].in_use) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- memcpy(key, iwm->keys[idx].key,
- min_t(int, erq->length, iwm->keys[idx].key_len));
- erq->length = iwm->keys[idx].key_len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
- switch (iwm->umac_profile->sec.auth_type) {
- case UMAC_AUTH_TYPE_OPEN:
- erq->flags |= IW_ENCODE_OPEN;
- break;
- default:
- erq->flags |= IW_ENCODE_RESTRICTED;
- break;
- }
- }
-
- return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
- else
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
- return 0;
-}
-
-static int iwm_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- u32 power_index;
-
- if (wrq->disabled) {
- power_index = IWM_POWER_INDEX_MIN;
- goto set;
- } else
- power_index = IWM_POWER_INDEX_DEFAULT;
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_ON:
- case IW_POWER_MODE:
- case IW_POWER_ALL_R:
- break;
- default:
- return -EINVAL;
- }
-
- set:
- if (power_index == iwm->conf.power_index)
- return 0;
-
- iwm->conf.power_index = power_index;
-
- return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_POWER_INDEX, iwm->conf.power_index);
-}
-
-static int iwm_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
-
- return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
- *auth_type = UMAC_AUTH_TYPE_8021X;
- else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- else
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- } else {
- IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
- u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
- &iwm->umac_profile->sec.mcast_cipher;
-
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- *profile_cipher = UMAC_CIPHER_TYPE_NONE;
- break;
- case IW_AUTH_CIPHER_WEP40:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
- break;
- case IW_AUTH_CIPHER_TKIP:
- *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_AUTH_CIPHER_CCMP:
- *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
- break;
- case IW_AUTH_CIPHER_WEP104:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
- break;
- default:
- IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- switch (auth_alg) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- *auth_type = UMAC_AUTH_TYPE_OPEN;
- break;
- case IW_AUTH_ALG_SHARED_KEY:
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
- if (*auth_type == UMAC_AUTH_TYPE_8021X)
- return -EINVAL;
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- } else {
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- }
- break;
- case IW_AUTH_ALG_LEAP:
- default:
- IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int ret;
-
- if ((data->flags) &
- (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
- IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
- /* We need to invalidate the current profile */
- if (iwm->umac_profile_active) {
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
- }
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- return iwm_set_wpa_version(iwm, data->value);
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- return iwm_set_cipher(iwm, data->value, 1);
- break;
- case IW_AUTH_CIPHER_GROUP:
- return iwm_set_cipher(iwm, data->value, 0);
- break;
- case IW_AUTH_KEY_MGMT:
- return iwm_set_key_mgt(iwm, data->value);
- break;
- case IW_AUTH_80211_AUTH_ALG:
- return iwm_set_auth_alg(iwm, data->value);
- break;
- default:
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- return 0;
-}
-
-static int iwm_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *key;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int uninitialized_var(alg), idx, i, remove = 0;
-
- IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
- IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
- IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- remove = 1;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len == WLAN_KEY_LEN_WEP40)
- alg = UMAC_CIPHER_TYPE_WEP_40;
- else if (ext->key_len == WLAN_KEY_LEN_WEP104)
- alg = UMAC_CIPHER_TYPE_WEP_104;
- else {
- IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
- return -EINVAL;
- }
-
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = UMAC_CIPHER_TYPE_CCMP;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- idx = erq->flags & IW_ENCODE_INDEX;
-
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if ((erq->length == 0) ||
- (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
- iwm->default_key = &iwm->keys[idx];
- if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
- return iwm_set_tx_key(iwm, idx);
- }
-
- key = iwm_key_init(iwm, idx, !remove, ext, alg);
-
- return iwm_set_key(iwm, remove, !iwm->default_key, key);
-}
-
-static const iw_handler iwm_handlers[] =
-{
- (iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
- (iw_handler) NULL, /* SIOCSIWNWID */
- (iw_handler) NULL, /* SIOCGIWNWID */
- (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
- (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
- (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
- (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
- (iw_handler) NULL, /* SIOCSIWSENS */
- (iw_handler) NULL, /* SIOCGIWSENS */
- (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
- (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
- (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
- (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
- (iw_handler) NULL, /* SIOCSIWSPY */
- (iw_handler) NULL, /* SIOCGIWSPY */
- (iw_handler) NULL, /* SIOCSIWTHRSPY */
- (iw_handler) NULL, /* SIOCGIWTHRSPY */
- (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
- (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
- (iw_handler) NULL, /* SIOCSIWMLME */
- (iw_handler) NULL, /* SIOCGIWAPLIST */
- (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
- (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
- (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
- (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
- (iw_handler) NULL, /* SIOCSIWNICKN */
- (iw_handler) NULL, /* SIOCGIWNICKN */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
- (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
- (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
- (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
- (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
- (iw_handler) NULL, /* SIOCSIWRETRY */
- (iw_handler) NULL, /* SIOCGIWRETRY */
- (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
- (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
- (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
- (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWGENIE */
- (iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
- (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
- (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
- (iw_handler) NULL, /* SIOCGIWENCODEEXT */
- (iw_handler) NULL, /* SIOCSIWPMKSA */
- (iw_handler) NULL, /* -- hole -- */
-};
-
-const struct iw_handler_def iwm_iw_handler_def = {
- .num_standard = ARRAY_SIZE(iwm_handlers),
- .standard = (iw_handler *) iwm_handlers,
- .get_wireless_stats = iwm_get_wireless_stats,
-};
-
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b374119033..1902b6f0b78c 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,7 @@
/* Copyright (C) 2006, Red Hat, Inc. */
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include <linux/if_arp.h>
@@ -43,21 +44,21 @@ static int get_common_rates(struct lbs_private *priv,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
- size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
- u8 tmp[30];
+ u8 tmp[(ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1)];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
- for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
- for (j = 0; rates[j] && (j < *rates_size); j++) {
+ for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
+ for (j = 0; j < *rates_size && rates[j]; j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates,
+ ARRAY_SIZE(lbs_bg_rates));
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
@@ -69,10 +70,7 @@ static int get_common_rates(struct lbs_private *priv,
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
- goto done;
}
- ret = 0;
-
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
@@ -129,7 +127,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
{
struct cmd_ds_802_11_authenticate cmd;
int ret = -1;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -138,8 +135,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
cmd.authtype = iw_auth_to_ieee_auth(auth);
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bssid), cmd.authtype);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
@@ -322,7 +318,7 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
memcpy(&rates->rates, &bss->rates, MAX_RATES);
- tmplen = MAX_RATES;
+ tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@@ -342,8 +338,6 @@ static int lbs_associate(struct lbs_private *priv,
/* Firmware v9+ indicate authentication suites as a TLV */
if (priv->fwrelease >= 0x09000000) {
- DECLARE_MAC_BUF(mac);
-
auth = (struct mrvl_ie_auth_type *) pos;
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth->header.len = cpu_to_le16(2);
@@ -351,8 +345,8 @@ static int lbs_associate(struct lbs_private *priv,
auth->auth = cpu_to_le16(tmpauth);
pos += sizeof(auth->header) + 2;
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+ bss->bssid, priv->secinfo.auth_mode);
}
/* WPA/WPA2 IEs */
@@ -598,7 +592,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+ ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
@@ -1368,11 +1362,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
if (ret)
goto out;
+ memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
+ sizeof(struct enc_key));
+
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
+
+ memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
+ sizeof(struct enc_key));
}
out:
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 01db705a38ec..685098148e10 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -135,8 +135,14 @@ int lbs_update_hw_spec(struct lbs_private *priv)
/* Clamp region code to 8-bit since FW spec indicates that it should
* only ever be 8-bit, even though the field size is 16-bit. Some firmware
* returns non-zero high 8 bits here.
+ *
+ * Firmware version 4.0.102 used in CF8381 has region code shifted. We
+ * need to check for this problem and handle it properly.
*/
- priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
+ priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
+ else
+ priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
/* use the region code to search for the index */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 48da157d6cda..72f3479a4d70 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -234,6 +234,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
/** Mesh enable bit in FW capability */
#define MESH_CAPINFO_ENABLE_MASK (1<<16)
+/** FW definition from Marvell v4 */
+#define MRVL_FW_V4 (0x04)
/** FW definition from Marvell v5 */
#define MRVL_FW_V5 (0x05)
/** FW definition from Marvell v10 */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f9ec69e04734..578c69783589 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -260,7 +260,6 @@ struct lbs_private {
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate;
- char ps_supported;
u8 needtowakeup;
struct assoc_request * pending_assoc_req;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 2a5b083bf9bd..f658fd6a2c0c 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out3;
}
- /* The firmware for the CF card supports powersave */
- priv->ps_supported = 1;
-
ret = 0;
goto out;
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 8cdb88c6ca28..485a8d406525 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret)
goto err_activate_card;
- if (priv->fwcapinfo & FW_CAPINFO_PS)
- priv->ps_supported = 1;
-
out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -1096,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
- card->priv->surpriseremoved = 1;
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
+ card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 6564282ce476..963c20125fc9 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %lu\n",
+ "our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->fw_ready = 1;
- priv->ps_supported = 1;
/* Initialize interrupt handling stuff. */
card->run_thread = 1;
@@ -1171,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
- priv->surpriseremoved = 1;
lbs_stop_card(priv);
+ lbs_remove_card(priv); /* will call free_netdev */
+
+ priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
- lbs_remove_card(priv); /* will call free_netdev */
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 1844c5adf6e9..92bc8c5f1ca2 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
lbs_pr_info("Firmware does not seem to support PS mode\n");
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
- priv->ps_supported = 1;
} else {
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 601b54249677..6c95af3023cc 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -5,6 +5,7 @@
* for sending scan commands to the firmware.
*/
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <asm/unaligned.h>
@@ -876,7 +877,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = 0;
- for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
/* Bit rate given in 500 kb/s units */
iwe.u.bitrate.value = bss->rates[j] * 500000;
current_val = iwe_stream_add_value(info, start, current_val,
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8bc1907458b1..e96451ce470b 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (!priv->ps_supported) {
+ if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
if (vwrq->disabled)
return 0;
else
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 10a99e26d392..4872345a2f61 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
skb_reserve(skb, 2);
}
- ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(priv->hw, skb);
return 0;
}
EXPORT_SYMBOL_GPL(lbtf_rx);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a111bda392e2..930f5c7da4a6 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
@@ -314,7 +316,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* TODO: allow packet injection */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -404,11 +406,19 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
- /* TODO: simulate signal strength (and optional packet drop) */
+ /* TODO: simulate real signal strength (and optional packet loss) */
+ rx_status.signal = -50;
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ /* release the skb's source info */
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +440,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
ETH_ALEN) == 0)
ack = true;
- ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(data2->hw, nskb);
}
spin_unlock(&hwsim_radio_lock);
@@ -690,6 +701,74 @@ static int mac80211_hwsim_conf_tx(
return 0;
}
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+ __HWSIM_TM_ATTR_INVALID = 0,
+ HWSIM_TM_ATTR_CMD = 1,
+ HWSIM_TM_ATTR_PS = 2,
+
+ /* keep last */
+ __HWSIM_TM_ATTR_AFTER_LAST,
+ HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+ HWSIM_TM_CMD_SET_PS = 0,
+ HWSIM_TM_CMD_GET_PS = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+ [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+ void *data, int len)
+{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+ struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+ struct sk_buff *skb;
+ int err, ps;
+
+ err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+ hwsim_testmode_policy);
+ if (err)
+ return err;
+
+ if (!tb[HWSIM_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+ case HWSIM_TM_CMD_SET_PS:
+ if (!tb[HWSIM_TM_ATTR_PS])
+ return -EINVAL;
+ ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+ return hwsim_fops_ps_write(hwsim, ps);
+ case HWSIM_TM_CMD_GET_PS:
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ nla_total_size(sizeof(u32)));
+ if (!skb)
+ return -ENOMEM;
+ NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+ return cfg80211_testmode_reply(skb);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return -ENOBUFS;
+}
+#endif
+
static const struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@@ -703,13 +782,14 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
+ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
};
static void mac80211_hwsim_free(void)
{
struct list_head tmplist, *i, *tmp;
- struct mac80211_hwsim_data *data;
+ struct mac80211_hwsim_data *data, *tmpdata;
INIT_LIST_HEAD(&tmplist);
@@ -718,7 +798,7 @@ static void mac80211_hwsim_free(void)
list_move(i, &tmplist);
spin_unlock_bh(&hwsim_radio_lock);
- list_for_each_entry(data, &tmplist, list) {
+ list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
debugfs_remove(data->debugfs_group);
debugfs_remove(data->debugfs_ps);
debugfs_remove(data->debugfs);
@@ -757,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = dat;
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_pspoll *pspoll;
@@ -787,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
@@ -945,7 +1023,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->flags = IEEE80211_HW_MFP_CAPABLE;
+ hw->flags = IEEE80211_HW_MFP_CAPABLE |
+ IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
@@ -1167,8 +1246,8 @@ static void __exit exit_mac80211_hwsim(void)
{
printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
- unregister_netdev(hwsim_mon);
mac80211_hwsim_free();
+ unregister_netdev(hwsim_mon);
}
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a263d5c84c08..4f725473fb73 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
status.flag = 0;
status.band = IEEE80211_BAND_2GHZ;
status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
- ieee80211_rx_irqsafe(hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(hw, skb);
processed++;
}
@@ -2270,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
struct mwl8k_cmd_update_sta_db *cmd;
struct peer_capability_info *peer_info;
struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
- DECLARE_MAC_BUF(mac);
int rc;
__u8 count, *rates;
@@ -3479,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
{
struct ieee80211_hw *hw;
struct mwl8k_priv *priv;
- DECLARE_MAC_BUF(mac);
int rc;
int i;
u8 *fw;
@@ -3668,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
MWL8K_DESC);
printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
- printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
- print_mac(mac, hw->wiphy->perm_addr));
+ printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
+ hw->wiphy->perm_addr);
return 0;
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index d63c8992f229..712f26eef35d 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* netwave_start_xmit */
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 44411eb4e91b..83b635fd7784 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,6 +1,7 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+ depends on CFG80211
select WIRELESS_EXT
select FW_LOADER
select CRYPTO
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 1fc7409d6699..9abd6329bcbd 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the orinoco wireless device drivers.
#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
obj-$(CONFIG_HERMES) += orinoco.o
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 8c4065f1b0d0..c60df2c1aca3 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -27,6 +27,7 @@
struct airport {
struct macio_dev *mdev;
void __iomem *vaddr;
+ unsigned int irq;
int irq_requested;
int ndev_registered;
};
@@ -34,8 +35,9 @@ struct airport {
static int
airport_suspend(struct macio_dev *mdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -48,18 +50,10 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
return 0;
}
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
+ orinoco_down(priv);
orinoco_unlock(priv, &flags);
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(mdev), 0, 0);
@@ -69,8 +63,9 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
static int
airport_resume(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -80,47 +75,27 @@ airport_resume(struct macio_dev *mdev)
macio_get_of_node(mdev), 0, 1);
msleep(200);
- enable_irq(dev->irq);
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
- dev->name, err);
- return 0;
- }
+ enable_irq(card->irq);
spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
- dev->name, err);
- }
-
-
+ err = orinoco_up(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ return err;
}
static int
airport_detach(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
struct airport *card = priv->card;
if (card->ndev_registered)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
card->ndev_registered = 0;
if (card->irq_requested)
- free_irq(dev->irq, dev);
+ free_irq(card->irq, priv);
card->irq_requested = 0;
if (card->vaddr)
@@ -134,7 +109,7 @@ airport_detach(struct macio_dev *mdev)
ssleep(1);
macio_set_drvdata(mdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
return 0;
}
@@ -146,7 +121,6 @@ static int airport_hard_reset(struct orinoco_private *priv)
* re-initialize properly, it falls in a screaming heap
* shortly afterwards. */
#if 0
- struct net_device *dev = priv->ndev;
struct airport *card = priv->card;
/* Vitally important. If we don't do this it seems we get an
@@ -154,7 +128,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
* hw_unavailable is already set it doesn't get ACKed, we get
* into an interrupt loop and the PMU decides to turn us
* off. */
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(card->mdev), 0, 0);
@@ -163,7 +137,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
macio_get_of_node(card->mdev), 0, 1);
ssleep(1);
- enable_irq(dev->irq);
+ enable_irq(card->irq);
ssleep(1);
#endif
@@ -174,7 +148,6 @@ static int
airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct orinoco_private *priv;
- struct net_device *dev;
struct airport *card;
unsigned long phys_addr;
hermes_t *hw;
@@ -185,33 +158,29 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
}
/* Allocate space for private device-specific data */
- dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+ airport_hard_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
return -ENODEV;
}
- priv = netdev_priv(dev);
card = priv->card;
hw = &priv->hw;
card->mdev = mdev;
- if (macio_request_resource(mdev, 0, "airport")) {
+ if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(dev);
+ free_orinocodev(priv);
return -EBUSY;
}
- SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
- macio_set_drvdata(mdev, dev);
+ macio_set_drvdata(mdev, priv);
/* Setup interrupts & base address */
- dev->irq = macio_irq(mdev, 0);
+ card->irq = macio_irq(mdev, 0);
phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (!card->vaddr) {
printk(KERN_ERR PFX "ioremap() failed\n");
@@ -228,18 +197,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
/* Reset it before we get the interrupt */
hermes_init(hw);
- if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+ if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
+ printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
goto failed;
}
card->irq_requested = 1;
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
- printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
card->ndev_registered = 1;
return 0;
failed:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
new file mode 100644
index 000000000000..1a87d3a0967c
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -0,0 +1,162 @@
+/* cfg80211 support
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "main.h"
+#include "orinoco.h"
+
+#include "cfg.h"
+
+/* Supported bitrates. Must agree with hw.c */
+static struct ieee80211_rate orinoco_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20 },
+ { .bitrate = 55 },
+ { .bitrate = 110 },
+};
+
+static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
+
+/* Called after orinoco_private is allocated. */
+void orinoco_wiphy_init(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+
+ wiphy->privid = orinoco_wiphy_privid;
+
+ set_wiphy_dev(wiphy, priv->dev);
+}
+
+/* Called after firmware is initialised */
+int orinoco_wiphy_register(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int i, channels = 0;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ wiphy->max_scan_ssids = 1;
+ else
+ wiphy->max_scan_ssids = 0;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: should we set if we only have demo ad-hoc?
+ * (priv->has_port3)
+ */
+ if (priv->has_ibss)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+ if (!priv->broken_monitor || force_monitor)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
+ priv->band.bitrates = orinoco_rates;
+ priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
+
+ /* Only support channels allowed by the card EEPROM */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (priv->channel_mask & (1 << i)) {
+ priv->channels[i].center_freq =
+ ieee80211_dsss_chan_to_freq(i+1);
+ channels++;
+ }
+ }
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = channels;
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ i = 0;
+ if (priv->has_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
+ i++;
+
+ if (priv->has_big_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
+ i++;
+ }
+ }
+ if (priv->has_wpa) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
+ i++;
+ }
+ wiphy->cipher_suites = priv->cipher_suites;
+ wiphy->n_cipher_suites = i;
+
+ wiphy->rts_threshold = priv->rts_thresh;
+ if (!priv->has_mwo)
+ wiphy->frag_threshold = priv->frag_thresh;
+
+ return wiphy_register(wiphy);
+}
+
+static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EINVAL;
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ wiphy_name(wiphy));
+ err = -EINVAL;
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err) {
+ priv->iw_mode = type;
+ set_port_type(priv);
+ err = orinoco_commit(priv);
+ }
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err;
+
+ if (!request)
+ return -EINVAL;
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ priv->scan_request = request;
+
+ err = orinoco_hw_trigger_scan(priv, request->ssids);
+
+ return err;
+}
+
+const struct cfg80211_ops orinoco_cfg_ops = {
+ .change_virtual_intf = orinoco_change_vif,
+ .scan = orinoco_scan,
+};
diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h
new file mode 100644
index 000000000000..3ddc96a06cd7
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.h
@@ -0,0 +1,15 @@
+/* cfg80211 support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef ORINOCO_CFG_H
+#define ORINOCO_CFG_H
+
+#include <net/cfg80211.h>
+
+extern const struct cfg80211_ops orinoco_cfg_ops;
+
+void orinoco_wiphy_init(struct wiphy *wiphy);
+int orinoco_wiphy_register(struct wiphy *wiphy);
+
+#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 1084b43e04bc..1257250a1e22 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
+#include <linux/device.h>
#include "hermes.h"
#include "hermes_dld.h"
@@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
const void *end;
const char *firmware;
const char *fw_err;
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int err = 0;
pda = kzalloc(fw->pda_size, GFP_KERNEL);
@@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
else
firmware = fw->sta_fw;
- printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
- dev->name, firmware);
+ dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
/* Read current plug data */
err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
- printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Read PDA returned %d\n", err);
if (err)
goto free;
@@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) {
- printk(KERN_ERR "%s: Cannot find firmware %s\n",
- dev->name, firmware);
+ dev_err(dev, "Cannot find firmware %s\n", firmware);
err = -ENOENT;
goto free;
}
@@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
fw_err = validate_fw(hdr, fw_entry->size);
if (fw_err) {
- printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
- "Aborting download\n",
- dev->name, fw_err);
+ dev_warn(dev, "Invalid firmware image detected (%s). "
+ "Aborting download\n", fw_err);
err = -EINVAL;
goto abort;
}
/* Enable aux port to allow programming */
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
- printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program init returned %d\n", err);
if (err != 0)
goto abort;
@@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
end = fw_entry->data + fw_entry->size;
err = hermes_program(hw, first_block, end);
- printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program returned %d\n", err);
if (err != 0)
goto abort;
@@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
&pda[fw->pda_size / sizeof(*pda)]);
- printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Apply PDA returned %d\n", err);
if (err)
goto abort;
/* Tell card we've finished */
err = hermesi_program_end(hw);
- printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program end returned %d\n", err);
if (err != 0)
goto abort;
/* Check if we're running */
- printk(KERN_DEBUG "%s: hermes_present returned %d\n",
- dev->name, hermes_present(hw));
+ dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
abort:
/* If we requested the firmware, release it. */
@@ -282,14 +279,13 @@ static int
symbol_dl_firmware(struct orinoco_private *priv,
const struct fw_info *fw)
{
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int ret;
const struct firmware *fw_entry;
if (!orinoco_cached_fw_get(priv, true)) {
if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
return -ENOENT;
}
} else
@@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, true))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Primary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Primary firmware download failed\n");
return ret;
}
if (!orinoco_cached_fw_get(priv, false)) {
if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
return -ENOENT;
}
} else
@@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, false))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Secondary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Secondary firmware download failed\n");
}
return ret;
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index f2c918c2572d..1a2fca76fd3c 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
u16 rlength, rtype;
unsigned nwords;
- if ((bufsize < 0) || (bufsize % 2))
+ if (bufsize % 2)
return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index c78c442a02c8..2dddbb597c4d 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -342,7 +342,7 @@ struct agere_ext_scan_info {
__le64 timestamp;
__le16 beacon_interval;
__le16 capabilities;
- u8 data[316];
+ u8 data[0];
} __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a9ba195cdada..a3eefe109df4 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw,
/* Open auxiliary port */
ret = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+ pr_debug(PFX "AUX enable returned %d\n", ret);
if (ret)
return ret;
@@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw,
/* Close aux port */
ret = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+ pr_debug(PFX "AUX disable returned %d\n", ret);
/* Check PDA length */
pda_size = le16_to_cpu(pda[0]);
- printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
+ pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
+ pda_size, pda_len);
if (pda_size > pda_len)
return -EINVAL;
@@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
return err;
err = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+ pr_debug(PFX "AUX enable returned %d\n", err);
if (err)
return err;
- printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+ pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
err = hermes_doicmd_wait(hw,
HERMES_PROGRAM_ENABLE_VOLATILE,
offset & 0xFFFFu,
offset >> 16,
0,
NULL);
- printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
- err);
+ pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
return err;
}
@@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw)
rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
- printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
+ pr_debug(PFX "PROGRAM_DISABLE returned %d, "
+ "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+ rc, resp.resp0, resp.resp1, resp.resp2);
if ((rc == 0) &&
((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
rc = -EIO;
err = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+ pr_debug(PFX "AUX disable returned %d\n", err);
/* Acknowledge any outstanding command */
hermes_write_regn(hw, EVACK, 0xFFFF);
@@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
while ((blkaddr != BLOCK_END) &&
(((void *) blk + blklen) <= end)) {
- printk(KERN_DEBUG PFX
- "Programming block of length %d to address 0x%08x\n",
- blklen, blkaddr);
+ pr_debug(PFX "Programming block of length %d "
+ "to address 0x%08x\n", blklen, blkaddr);
#if !LIMIT_PROGRAM_SIZE
/* wl_lkm driver splits this into writes of 2000 bytes */
@@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
addr = blkaddr;
while (addr < (blkaddr + blklen)) {
- printk(KERN_DEBUG PFX
- "Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- len, addr, &blk->data[addr - blkaddr]);
+ pr_debug(PFX "Programming subblock of length %d "
+ "to address 0x%08x. Data @ %p\n",
+ len, addr, &blk->data[addr - blkaddr]);
hermes_aux_setaddr(hw, addr);
hermes_write_bytes(hw, HERMES_AUXDATA,
@@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
if (pdi)
- printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Found record 0x%04x at %p\n",
+ record_id, pdi);
switch (record_id) {
case 0x110: /* Modem REFDAC values */
@@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
default_pdi = NULL;
if (outdoor_pdi) {
pdi = outdoor_pdi;
- printk(KERN_DEBUG PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
+ pr_debug(PFX
+ "Using outdoor record 0x%04x at %p\n",
+ record_id + 1, pdi);
}
break;
case 0x5: /* HWIF Compatiblity */
@@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
if (!pdi && default_pdi) {
/* Use default */
pdi = default_pdi;
- printk(KERN_DEBUG PFX
- "Using default record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Using default record 0x%04x at %p\n",
+ record_id, pdi);
}
if (pdi) {
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 632fac86a308..fa508af1a351 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -3,16 +3,22 @@
* See copyright notice in main.c
*/
#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/if_arp.h>
#include <linux/ieee80211.h>
#include <linux/wireless.h>
-
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
#include "hw.h"
+#define SYMBOL_MAX_VER_LEN (14)
+
+/* Symbol firmware has a bug allocating buffers larger than this */
+#define TX_NICBUF_SIZE_BUG 1585
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -36,6 +42,343 @@ static const struct {
};
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+/* Firmware version encoding */
+struct comp_id {
+ u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+ if (nic_id->id < 0x8000)
+ return FIRMWARE_TYPE_AGERE;
+ else if (nic_id->id == 0x8000 && nic_id->major == 0)
+ return FIRMWARE_TYPE_SYMBOL;
+ else
+ return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* 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
+ */
+int determine_fw_capabilities(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct comp_id nic_id, sta_id;
+ unsigned int firmver;
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+ /* Get the hardware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+ if (err) {
+ dev_err(dev, "Cannot read hardware identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&nic_id.id);
+ le16_to_cpus(&nic_id.variant);
+ le16_to_cpus(&nic_id.major);
+ le16_to_cpus(&nic_id.minor);
+ dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
+ nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+
+ priv->firmware_type = determine_firmware_type(&nic_id);
+
+ /* Get the firmware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+ if (err) {
+ dev_err(dev, "Cannot read station identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&sta_id.id);
+ le16_to_cpus(&sta_id.variant);
+ le16_to_cpus(&sta_id.major);
+ le16_to_cpus(&sta_id.minor);
+ dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
+ sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
+
+ switch (sta_id.id) {
+ case 0x15:
+ dev_err(dev, "Primary firmware is active\n");
+ return -ENODEV;
+ case 0x14b:
+ dev_err(dev, "Tertiary firmware is active\n");
+ return -ENODEV;
+ case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
+ case 0x21: /* Symbol Spectrum24 Trilogy */
+ break;
+ default:
+ dev_notice(dev, "Unknown station ID, please report\n");
+ break;
+ }
+
+ /* Default capabilities */
+ priv->has_sensitivity = 1;
+ priv->has_mwo = 0;
+ priv->has_preamble = 0;
+ priv->has_port3 = 1;
+ priv->has_ibss = 1;
+ priv->has_wep = 0;
+ priv->has_big_wep = 0;
+ priv->has_alt_txcntl = 0;
+ priv->has_ext_scan = 0;
+ priv->has_wpa = 0;
+ priv->do_fw_download = 0;
+
+ /* Determine capabilities from the firmware version */
+ switch (priv->firmware_type) {
+ 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);
+
+ firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+ priv->has_ibss = (firmver >= 0x60006);
+ priv->has_wep = (firmver >= 0x40020);
+ priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+ Gold cards from the others? */
+ priv->has_mwo = (firmver >= 0x60000);
+ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+ priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->do_fw_download = 1;
+ priv->broken_monitor = (firmver >= 0x80000);
+ priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_wpa = (firmver >= 0x9002a);
+ /* Tested with Agere firmware :
+ * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+ * Tested CableTron firmware : 4.32 => Anton */
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+ /* Intel MAC : 00:02:B3:* */
+ /* 3Com MAC : 00:50:DA:* */
+ memset(tmp, 0, sizeof(tmp));
+ /* Get the Symbol firmware version */
+ err = hermes_read_ltv(hw, USER_BAP,
+ HERMES_RID_SECONDARYVERSION_SYMBOL,
+ SYMBOL_MAX_VER_LEN, NULL, &tmp);
+ if (err) {
+ dev_warn(dev, "Error %d reading Symbol firmware info. "
+ "Wildly guessing capabilities...\n", err);
+ firmver = 0;
+ tmp[0] = '\0';
+ } else {
+ /* The firmware revision is a string, the format is
+ * something like : "V2.20-01".
+ * Quick and dirty parsing... - Jean II
+ */
+ firmver = ((tmp[1] - '0') << 16)
+ | ((tmp[3] - '0') << 12)
+ | ((tmp[4] - '0') << 8)
+ | ((tmp[6] - '0') << 4)
+ | (tmp[7] - '0');
+
+ tmp[SYMBOL_MAX_VER_LEN] = '\0';
+ }
+
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Symbol %s", tmp);
+
+ priv->has_ibss = (firmver >= 0x20000);
+ priv->has_wep = (firmver >= 0x15012);
+ priv->has_big_wep = (firmver >= 0x20000);
+ priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+ (firmver >= 0x29000 && firmver < 0x30000) ||
+ firmver >= 0x31000;
+ priv->has_preamble = (firmver >= 0x20000);
+ priv->ibss_port = 4;
+
+ /* Symbol firmware is found on various cards, but
+ * there has been no attempt to check firmware
+ * download on non-spectrum_cs based cards.
+ *
+ * Given that the Agere firmware download works
+ * differently, we should avoid doing a firmware
+ * download with the Symbol algorithm on non-spectrum
+ * cards.
+ *
+ * For now we can identify a spectrum_cs based card
+ * because it has a firmware reset function.
+ */
+ priv->do_fw_download = (priv->stop_fw != NULL);
+
+ priv->broken_disableport = (firmver == 0x25013) ||
+ (firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
+ /* Tested with Intel firmware : 0x20015 => Jean II */
+ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+ * Samsung, Compaq 100/200 and Proxim are slightly
+ * 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);
+
+ firmver = ((unsigned long)sta_id.major << 16) |
+ ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+ priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+ priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
+
+ if (firmver >= 0x000800)
+ priv->ibss_port = 0;
+ else {
+ dev_notice(dev, "Intersil firmware earlier than v0.8.x"
+ " - several features not supported\n");
+ priv->ibss_port = 1;
+ }
+ break;
+ }
+ dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+
+ return 0;
+}
+
+/* Read settings from EEPROM into our private structure.
+ * MAC address gets dropped into callers buffer
+ * Can be called before netdev registration.
+ */
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
+{
+ struct device *dev = priv->dev;
+ struct hermes_idstring nickbuf;
+ hermes_t *hw = &priv->hw;
+ int len;
+ int err;
+ u16 reclen;
+
+ /* Get the MAC address */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ ETH_ALEN, NULL, dev_addr);
+ if (err) {
+ dev_warn(dev, "Failed to read MAC address!\n");
+ goto out;
+ }
+
+ dev_dbg(dev, "MAC address %pM\n", dev_addr);
+
+ /* Get the station name */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ sizeof(nickbuf), &reclen, &nickbuf);
+ if (err) {
+ dev_err(dev, "failed to read station name\n");
+ goto out;
+ }
+ if (nickbuf.len)
+ len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+ else
+ len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+ memcpy(priv->nick, &nickbuf.val, len);
+ priv->nick[len] = '\0';
+
+ dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
+
+ /* Get allowed channels */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+ &priv->channel_mask);
+ if (err) {
+ dev_err(dev, "Failed to read channel list!\n");
+ goto out;
+ }
+
+ /* Get initial AP density */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+ &priv->ap_density);
+ if (err || priv->ap_density < 1 || priv->ap_density > 3)
+ priv->has_sensitivity = 0;
+
+ /* Get initial RTS threshold */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ &priv->rts_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read RTS threshold!\n");
+ goto out;
+ }
+
+ /* Get initial fragmentation settings */
+ if (priv->has_mwo)
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ &priv->mwo_robust);
+ else
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ &priv->frag_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read fragmentation settings!\n");
+ goto out;
+ }
+
+ /* Power management setup */
+ if (priv->has_pm) {
+ priv->pm_on = 0;
+ priv->pm_mcast = 1;
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ &priv->pm_period);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "period!\n");
+ goto out;
+ }
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ &priv->pm_timeout);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "timeout!\n");
+ goto out;
+ }
+ }
+
+ /* Preamble setup */
+ if (priv->has_preamble) {
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ &priv->preamble);
+ }
+
+out:
+ return err;
+}
+
+/* Can be called before netdev registration */
+int orinoco_hw_allocate_fid(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+ if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+ /* Try workaround for old Symbol firmware bug */
+ priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+
+ dev_warn(dev, "Firmware ALLOC bug detected "
+ "(old Symbol firmware?). Work around %s\n",
+ err ? "failed!" : "ok.");
+ }
+
+ return err;
+}
+
int orinoco_get_bitratemode(int bitrate, int automatic)
{
int ratemode = -1;
@@ -63,6 +406,237 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
*automatic = bitrate_table[ratemode].automatic;
}
+int orinoco_hw_program_rids(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ struct wireless_dev *wdev = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct hermes_idstring idbuf;
+
+ /* Set the MAC address */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting MAC address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set up the link mode */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+ priv->port_type);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting port type\n",
+ dev->name, err);
+ return err;
+ }
+ /* Set the channel/frequency */
+ if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFOWNCHANNEL,
+ priv->channel);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting channel %d\n",
+ dev->name, err, priv->channel);
+ return err;
+ }
+ }
+
+ if (priv->has_ibss) {
+ u16 createibss;
+
+ if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+ printk(KERN_WARNING "%s: This firmware requires an "
+ "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+ /* With wvlan_cs, in this case, we would crash.
+ * hopefully, this driver will behave better...
+ * Jean II */
+ createibss = 0;
+ } else {
+ createibss = priv->createibss;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFCREATEIBSS,
+ createibss);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the desired ESSID */
+ idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+ memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+ /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the station name */
+ idbuf.len = cpu_to_le16(strlen(priv->nick));
+ memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting nickname\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set AP density */
+ if (priv->has_sensitivity) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSYSTEMSCALE,
+ priv->ap_density);
+ if (err) {
+ printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+ "Disabling sensitivity control\n",
+ dev->name, err);
+
+ priv->has_sensitivity = 0;
+ }
+ }
+
+ /* Set RTS threshold */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ priv->rts_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set fragmentation threshold or MWO robustness */
+ if (priv->has_mwo)
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ priv->mwo_robust);
+ else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ priv->frag_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set bitrate */
+ err = __orinoco_hw_set_bitrate(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting bitrate\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set power management */
+ if (priv->has_pm) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMENABLED,
+ priv->pm_on);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMULTICASTRECEIVE,
+ priv->pm_mcast);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ priv->pm_period);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ priv->pm_timeout);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set preamble - only for Symbol so far... */
+ if (priv->has_preamble) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ priv->preamble);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting preamble\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set up encryption */
+ if (priv->has_wep || priv->has_wpa) {
+ err = __orinoco_hw_setup_enc(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d activating encryption\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
+ /* Reset promiscuity / multicast*/
+ priv->promiscuous = 0;
+ priv->mc_count = 0;
+
+ /* Record mode change */
+ wdev->iftype = priv->iw_mode;
+
+ return 0;
+}
+
/* Get tsc from the firmware */
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
{
@@ -314,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
} else
master_wep_flag = 0;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
/* Master WEP setting : on/off */
@@ -334,8 +908,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
* rsc must be 8 bytes
* tsc must be 8 bytes or NULL
*/
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc)
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc)
{
struct {
__le16 idx;
@@ -345,6 +919,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
u8 rx_mic[MIC_KEYLEN];
u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
} __attribute__ ((packed)) buf;
+ hermes_t *hw = &priv->hw;
int ret;
int err;
int k;
@@ -582,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
+
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ __le16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ break;
+ }
+ case FIRMWARE_TYPE_AGERE:
+ if (ssid->ssid_len > 0) {
+ struct hermes_idstring idbuf;
+ size_t len = ssid->ssid_len;
+
+ idbuf.len = cpu_to_le16(len);
+ memcpy(idbuf.val, ssid->ssid, len);
+
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ HERMES_BYTES_TO_RECLEN(len + 2),
+ &idbuf);
+ } else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
+
+ if (priv->has_ext_scan) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANCHANNELS2GHZ,
+ 0x7FFF);
+ if (err)
+ goto out;
+
+ err = hermes_inquire(hw,
+ HERMES_INQ_CHANNELINFO);
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ break;
+ }
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index dc3f23a9c1c7..27b427649d1b 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/wireless.h>
+#include <net/cfg80211.h>
/* Hardware BAPs */
#define USER_BAP 0
@@ -23,17 +24,21 @@
struct orinoco_private;
struct dev_addr_list;
+int determine_fw_capabilities(struct orinoco_private *priv);
+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);
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
+int orinoco_hw_program_rids(struct orinoco_private *priv);
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
int __orinoco_hw_set_wap(struct orinoco_private *priv);
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc);
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
struct dev_addr_list *mc_list,
@@ -43,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
int orinoco_hw_get_freq(struct orinoco_private *priv);
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
int *numrates, s32 *rates, int max);
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid);
#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index a370e510f19f..e8c550a61f33 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -80,6 +80,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -88,6 +89,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes_rid.h"
#include "hermes_dld.h"
@@ -96,6 +98,7 @@
#include "mic.h"
#include "fw.h"
#include "wext.h"
+#include "cfg.h"
#include "main.h"
#include "orinoco.h"
@@ -142,13 +145,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-#define SYMBOL_MAX_VER_LEN (14)
#define MAX_IRQLOOPS_PER_IRQ 10
#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
* how many events the
* device could
* legitimately generate */
-#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
#define DUMMY_FID 0xFFFF
@@ -205,11 +206,21 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct orinoco_scan_data {
+ void *buf;
+ size_t len;
+ int type;
+ struct list_head list;
+};
+
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static void __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_up(struct orinoco_private *priv);
+static int __orinoco_down(struct orinoco_private *priv);
+static int __orinoco_commit(struct orinoco_private *priv);
/********************************************************************/
/* Internal helper functions */
@@ -218,11 +229,11 @@ static void __orinoco_set_multicast_list(struct net_device *dev);
void set_port_type(struct orinoco_private *priv)
{
switch (priv->iw_mode) {
- case IW_MODE_INFRA:
+ case NL80211_IFTYPE_STATION:
priv->port_type = 1;
priv->createibss = 0;
break;
- case IW_MODE_ADHOC:
+ case NL80211_IFTYPE_ADHOC:
if (priv->prefer_port3) {
priv->port_type = 3;
priv->createibss = 0;
@@ -231,7 +242,7 @@ void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
- case IW_MODE_MONITOR:
+ case NL80211_IFTYPE_MONITOR:
priv->port_type = 3;
priv->createibss = 0;
break;
@@ -247,14 +258,14 @@ void set_port_type(struct orinoco_private *priv)
static int orinoco_open(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (!err)
priv->open = 1;
@@ -266,7 +277,7 @@ static int orinoco_open(struct net_device *dev)
static int orinoco_stop(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
/* We mustn't use orinoco_lock() here, because we need to be
@@ -276,7 +287,7 @@ static int orinoco_stop(struct net_device *dev)
priv->open = 0;
- err = __orinoco_down(dev);
+ err = __orinoco_down(priv);
spin_unlock_irq(&priv->lock);
@@ -285,14 +296,14 @@ static int orinoco_stop(struct net_device *dev)
static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
return &priv->stats;
}
static void orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) {
@@ -307,7 +318,7 @@ static void orinoco_set_multicast_list(struct net_device *dev)
static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
return -EINVAL;
@@ -328,7 +339,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
int err = 0;
@@ -355,7 +366,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+ if (!netif_carrier_ok(dev) ||
+ (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -518,7 +530,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 fid = hermes_read_regn(hw, ALLOCFID);
if (fid != priv->txfid) {
@@ -533,7 +545,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
stats->tx_packets++;
@@ -545,7 +557,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status;
@@ -601,7 +613,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
static void orinoco_tx_timeout(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
@@ -650,7 +662,7 @@ static void orinoco_stat_gather(struct net_device *dev,
struct sk_buff *skb,
struct hermes_rx_descriptor *desc)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
/* Using spy support with lots of Rx packets, like in an
* infrastructure (AP), will really slow down everything, because
@@ -687,7 +699,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
int err;
int len;
struct sk_buff *skb;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
@@ -778,7 +790,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
@@ -816,7 +828,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
}
/* Handle frames in monitor mode */
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
orinoco_rx_monitor(dev, rxfid, desc);
goto out;
}
@@ -902,7 +914,7 @@ static void orinoco_rx(struct net_device *dev,
struct hermes_rx_descriptor *desc,
struct sk_buff *skb)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 status, fc;
int length;
@@ -1016,8 +1028,8 @@ static void orinoco_rx(struct net_device *dev,
static void orinoco_rx_isr_tasklet(unsigned long data)
{
- struct net_device *dev = (struct net_device *) data;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = (struct orinoco_private *) data;
+ struct net_device *dev = priv->ndev;
struct orinoco_rx_data *rx_data, *temp;
struct hermes_rx_descriptor *desc;
struct sk_buff *skb;
@@ -1260,9 +1272,81 @@ static void orinoco_send_wevents(struct work_struct *work)
orinoco_unlock(priv, &flags);
}
+static void qbuf_scan(struct orinoco_private *priv, void *buf,
+ int len, int type)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->buf = buf;
+ sd->len = len;
+ sd->type = type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void qabort_scan(struct orinoco_private *priv)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->len = -1; /* Abort */
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void orinoco_process_scan_results(struct work_struct *work)
+{
+ struct orinoco_private *priv =
+ container_of(work, struct orinoco_private, process_scan);
+ struct orinoco_scan_data *sd, *temp;
+ unsigned long flags;
+ void *buf;
+ int len;
+ int type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ buf = sd->buf;
+ len = sd->len;
+ type = sd->type;
+
+ list_del(&sd->list);
+ kfree(sd);
+
+ if (len > 0) {
+ if (type == HERMES_INQ_CHANNELINFO)
+ orinoco_add_extscan_result(priv, buf, len);
+ else
+ orinoco_add_hostscan_results(priv, buf, len);
+
+ kfree(buf);
+ } else if (priv->scan_request) {
+ /* Either abort or complete the scan */
+ cfg80211_scan_done(priv->scan_request, (len < 0));
+ priv->scan_request = NULL;
+ }
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 infofid;
struct {
__le16 len;
@@ -1327,7 +1411,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
break;
if (len != sizeof(linkstatus)) {
@@ -1346,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
* the hostscan frame can be requested. */
if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_inprogress) {
+ priv->has_hostscan && priv->scan_request) {
hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
break;
}
@@ -1372,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
break;
case HERMES_INQ_SCAN:
- if (!priv->scan_inprogress && priv->bssid_fixed &&
+ if (!priv->scan_request && priv->bssid_fixed &&
priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
schedule_work(&priv->join_work);
break;
@@ -1382,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
case HERMES_INQ_HOSTSCAN_SYMBOL: {
/* Result of a scanning. Contains information about
* cells in the vicinity - Jean II */
- union iwreq_data wrqu;
unsigned char *buf;
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
/* Sanity check */
if (len > 4096) {
printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
dev->name, len);
+ qabort_scan(priv);
break;
}
/* Allocate buffer for results */
buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL)
+ if (buf == NULL) {
/* No memory, so can't printk()... */
+ qabort_scan(priv);
break;
+ }
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
if (err) {
kfree(buf);
+ qabort_scan(priv);
break;
}
@@ -1419,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
#endif /* ORINOCO_DEBUG */
- if (orinoco_process_scan_results(priv, buf, len) == 0) {
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
- }
- kfree(buf);
+ qbuf_scan(priv, buf, len, type);
}
break;
case HERMES_INQ_CHANNELINFO:
{
struct agere_ext_scan_info *bss;
- if (!priv->scan_inprogress) {
+ if (!priv->scan_request) {
printk(KERN_DEBUG "%s: Got chaninfo without scan, "
"len=%d\n", dev->name, len);
break;
@@ -1444,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* An empty result indicates that the scan is complete */
if (len == 0) {
- union iwreq_data wrqu;
-
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ qbuf_scan(priv, NULL, len, type);
break;
}
/* Sanity check */
- else if (len > sizeof(*bss)) {
- printk(KERN_WARNING
- "%s: Ext scan results too large (%d bytes). "
- "Truncating results to %zd bytes.\n",
- dev->name, len, sizeof(*bss));
- len = sizeof(*bss);
- } else if (len < (offsetof(struct agere_ext_scan_info,
+ else if (len < (offsetof(struct agere_ext_scan_info,
data) + 2)) {
/* Drop this result now so we don't have to
* keep checking later */
@@ -1472,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
}
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kmalloc(len, GFP_ATOMIC);
if (bss == NULL)
break;
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
infofid, sizeof(info));
- if (err) {
+ if (err)
kfree(bss);
- break;
- }
-
- orinoco_add_ext_scan_result(priv, bss);
+ else
+ qbuf_scan(priv, bss, len, type);
- kfree(bss);
break;
}
case HERMES_INQ_SEC_STAT_AGERE:
@@ -1501,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* We don't actually do anything about it */
break;
}
+
+ return;
}
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
@@ -1513,15 +1573,15 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
/* Internal hardware control routines */
/********************************************************************/
-int __orinoco_up(struct net_device *dev)
+static int __orinoco_up(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
netif_carrier_off(dev); /* just to make sure */
- err = __orinoco_program_rids(dev);
+ err = __orinoco_commit(priv);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
@@ -1541,11 +1601,10 @@ int __orinoco_up(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_up);
-int __orinoco_down(struct net_device *dev)
+static int __orinoco_down(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
@@ -1573,31 +1632,9 @@ int __orinoco_down(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_down);
-static int orinoco_allocate_fid(struct net_device *dev)
+static int orinoco_reinit_firmware(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-
- printk(KERN_WARNING "%s: firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- dev->name, err ? "failed!" : "ok.");
- }
-
- return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
@@ -1608,246 +1645,15 @@ int orinoco_reinit_firmware(struct net_device *dev)
priv->do_fw_download = 0;
}
if (!err)
- err = orinoco_allocate_fid(dev);
+ err = orinoco_hw_allocate_fid(priv);
return err;
}
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-int __orinoco_program_rids(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-
- /* Set the MAC address */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
- /* Set the desired ESSID */
- idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
- memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
- /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* Set the station name */
- idbuf.len = cpu_to_le16(strlen(priv->nick));
- memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == IW_MODE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_MONITOR, 0, NULL);
- } else {
- /* Disable monitor mode */
- dev->type = ARPHRD_ETHER;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Set promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* FIXME: what about netif_tx_lock */
- __orinoco_set_multicast_list(dev);
-
- return 0;
-}
-/* FIXME: return int? */
-static void
+static int
__orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int promisc, mc_count;
@@ -1864,6 +1670,8 @@ __orinoco_set_multicast_list(struct net_device *dev)
err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
promisc);
+
+ return err;
}
/* This must be called from user context, without locks held - use
@@ -1896,9 +1704,11 @@ void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags);
- /* Scanning support: Cleanup of driver struct */
- orinoco_clear_scan_results(priv, 0);
- priv->scan_inprogress = 0;
+ /* Scanning support: Notify scan cancellation */
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
@@ -1909,7 +1719,7 @@ void orinoco_reset(struct work_struct *work)
}
}
- err = orinoco_reinit_firmware(dev);
+ err = orinoco_reinit_firmware(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
dev->name, err);
@@ -1924,7 +1734,7 @@ void orinoco_reset(struct work_struct *work)
/* priv->open or priv->hw_unavailable might have changed while
* we dropped the lock */
if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
dev->name, err);
@@ -1941,6 +1751,64 @@ void orinoco_reset(struct work_struct *work)
printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
}
+static int __orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ int err = 0;
+
+ err = orinoco_hw_program_rids(priv);
+
+ /* FIXME: what about netif_tx_lock */
+ (void) __orinoco_set_multicast_list(dev);
+
+ return err;
+}
+
+/* Ensures configuration changes are applied. May result in a reset.
+ * The caller should hold priv->lock
+ */
+int orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ if (priv->broken_disableport) {
+ schedule_work(&priv->reset_work);
+ return 0;
+ }
+
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to disable port "
+ "while reconfiguring card\n", dev->name);
+ priv->broken_disableport = 1;
+ goto out;
+ }
+
+ err = __orinoco_commit(priv);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
+
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+ schedule_work(&priv->reset_work);
+ err = 0;
+ }
+ return err;
+}
+
/********************************************************************/
/* Interrupt handler */
/********************************************************************/
@@ -1960,8 +1828,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
irqreturn_t orinoco_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_id;
+ struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
u16 evstat, events;
@@ -2096,227 +1964,12 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
/* Initialization */
/********************************************************************/
-struct comp_id {
- u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
- dev->name, nic_id.id, nic_id.variant,
- nic_id.major, nic_id.minor);
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
- dev->name, sta_id.id, sta_id.variant,
- sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- printk(KERN_ERR "%s: Primary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x14b:
- printk(KERN_ERR "%s: Tertiary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
- dev->name);
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- 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);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 3Com MAC : 00:50:DA:* */
- memset(tmp, 0, sizeof(tmp));
- /* Get the Symbol firmware version */
- err = hermes_read_ltv(hw, USER_BAP,
- HERMES_RID_SECONDARYVERSION_SYMBOL,
- SYMBOL_MAX_VER_LEN, NULL, &tmp);
- if (err) {
- printk(KERN_WARNING
- "%s: Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n",
- dev->name, err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * 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);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- printk(KERN_NOTICE "%s: Intersil firmware earlier "
- "than v0.8.x - several features not supported\n",
- dev->name);
- priv->ibss_port = 1;
- }
- break;
- }
- printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
- priv->fw_name);
-
- return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
+int orinoco_init(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct device *dev = priv->dev;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
hermes_t *hw = &priv->hw;
int err = 0;
- struct hermes_idstring nickbuf;
- u16 reclen;
- int len;
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2325,15 +1978,14 @@ static int orinoco_init(struct net_device *dev)
/* Initialize the firmware */
err = hermes_init(hw);
if (err != 0) {
- printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
- dev->name, err);
+ dev_err(dev, "Failed to initialize firmware (err = %d)\n",
+ err);
goto out;
}
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
@@ -2347,147 +1999,41 @@ static int orinoco_init(struct net_device *dev)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
}
if (priv->has_port3)
- printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
- dev->name);
+ dev_info(dev, "Ad-hoc demo mode supported\n");
if (priv->has_ibss)
- printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
- dev->name);
- if (priv->has_wep) {
- printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
- priv->has_big_wep ? "104" : "40");
- }
+ dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
+ if (priv->has_wep)
+ dev_info(dev, "WEP supported, %s-bit key\n",
+ priv->has_big_wep ? "104" : "40");
if (priv->has_wpa) {
- printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+ dev_info(dev, "WPA-PSK supported\n");
if (orinoco_mic_init(priv)) {
- printk(KERN_ERR "%s: Failed to setup MIC crypto "
- "algorithm. Disabling WPA support\n", dev->name);
+ dev_err(dev, "Failed to setup MIC crypto algorithm. "
+ "Disabling WPA support\n");
priv->has_wpa = 0;
}
}
- /* Now we have the firmware capabilities, allocate appropiate
- * sized scan buffers */
- if (orinoco_bss_data_allocate(priv))
- goto out;
- orinoco_bss_data_init(priv);
-
- /* Get the MAC address */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev->dev_addr);
- if (err) {
- printk(KERN_WARNING "%s: failed to read MAC address!\n",
- dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "%s: MAC address %pM\n",
- dev->name, dev->dev_addr);
-
- /* Get the station name */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- printk(KERN_ERR "%s: failed to read station name\n",
- dev->name);
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
- err = orinoco_allocate_fid(dev);
- if (err) {
- printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
- dev->name);
- goto out;
- }
-
- /* Get allowed channels */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- printk(KERN_ERR "%s: failed to read channel list!\n",
- dev->name);
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: failed to read RTS threshold!\n",
- dev->name);
+ err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
+ if (err)
goto out;
- }
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
+ err = orinoco_hw_allocate_fid(priv);
if (err) {
- printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
- dev->name);
+ dev_err(dev, "Failed to allocate NIC buffer!\n");
goto out;
}
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management period!\n",
- dev->name);
- goto out;
- }
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management timeout!\n",
- dev->name);
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err)
- goto out;
- }
-
/* Set up the default configuration */
- priv->iw_mode = IW_MODE_INFRA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
/* By default use IEEE/IBSS ad-hoc mode if we have it */
priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
set_port_type(priv);
@@ -2502,20 +2048,25 @@ static int orinoco_init(struct net_device *dev)
priv->wpa_ie_len = 0;
priv->wpa_ie = NULL;
+ if (orinoco_wiphy_register(wiphy)) {
+ err = -ENODEV;
+ goto out;
+ }
+
/* Make the hardware available, as long as it hasn't been
* removed elsewhere (e.g. by PCMCIA hot unplug) */
spin_lock_irq(&priv->lock);
priv->hw_unavailable--;
spin_unlock_irq(&priv->lock);
- printk(KERN_DEBUG "%s: ready\n", dev->name);
+ dev_dbg(dev, "Ready\n");
out:
return err;
}
+EXPORT_SYMBOL(orinoco_init);
static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_init = orinoco_init,
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = orinoco_xmit,
@@ -2527,40 +2078,64 @@ static const struct net_device_ops orinoco_netdev_ops = {
.ndo_get_stats = orinoco_get_stats,
};
-struct net_device
+/* Allocate private data.
+ *
+ * This driver has a number of structures associated with it
+ * netdev - Net device structure for each network interface
+ * wiphy - structure associated with wireless phy
+ * wireless_dev (wdev) - structure for each wireless interface
+ * hw - structure for hermes chip info
+ * card - card specific structure for use by the card driver
+ * (airport, orinoco_cs)
+ * priv - orinoco private data
+ * device - generic linux device structure
+ *
+ * +---------+ +---------+
+ * | wiphy | | netdev |
+ * | +-------+ | +-------+
+ * | | priv | | | wdev |
+ * | | +-----+ +-+-------+
+ * | | | hw |
+ * | +-+-----+
+ * | | card |
+ * +-+-------+
+ *
+ * priv has a link to netdev and device
+ * wdev has a link to wiphy
+ */
+struct orinoco_private
*alloc_orinocodev(int sizeof_card,
struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int))
{
- struct net_device *dev;
struct orinoco_private *priv;
+ struct wiphy *wiphy;
- dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
- if (!dev)
+ /* allocate wiphy
+ * NOTE: We only support a single virtual interface
+ * but this may change when monitor mode is added
+ */
+ wiphy = wiphy_new(&orinoco_cfg_ops,
+ sizeof(struct orinoco_private) + sizeof_card);
+ if (!wiphy)
return NULL;
- priv = netdev_priv(dev);
- priv->ndev = dev;
+
+ priv = wiphy_priv(wiphy);
+ priv->dev = device;
+
if (sizeof_card)
priv->card = (void *)((unsigned long)priv
+ sizeof(struct orinoco_private));
else
priv->card = NULL;
- priv->dev = device;
- /* Setup / override net_device fields */
- 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;
+ orinoco_wiphy_init(wiphy);
+
#ifdef WIRELESS_SPY
priv->wireless_data.spy_data = &priv->spy_data;
- dev->wireless_data = &priv->wireless_data;
#endif
- /* Reserve space in skb for the SNAP header */
- dev->hard_header_len += ENCAPS_OVERHEAD;
-
/* Set up default callbacks */
priv->hard_reset = hard_reset;
priv->stop_fw = stop_fw;
@@ -2576,9 +2151,12 @@ struct net_device
INIT_LIST_HEAD(&priv->rx_list);
tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
- (unsigned long) dev);
+ (unsigned long) priv);
+
+ spin_lock_init(&priv->scan_lock);
+ INIT_LIST_HEAD(&priv->scan_list);
+ INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
- netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
@@ -2589,14 +2167,91 @@ struct net_device
/* Register PM notifiers */
orinoco_register_pm_notifier(priv);
- return dev;
+ return priv;
}
EXPORT_SYMBOL(alloc_orinocodev);
-void free_orinocodev(struct net_device *dev)
+/* We can only support a single interface. We provide a separate
+ * function to set it up to distinguish between hardware
+ * initialisation and interface setup.
+ *
+ * The base_addr and irq parameters are passed on to netdev for use
+ * with SIOCGIFMAP.
+ */
+int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq)
+{
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct wireless_dev *wdev;
+ struct net_device *dev;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct wireless_dev));
+
+ if (!dev)
+ return -ENOMEM;
+
+ /* Initialise wireless_dev */
+ wdev = netdev_priv(dev);
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ /* Setup / override net_device fields */
+ 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;
+#endif
+ /* we use the default eth_mac_addr for setting the MAC addr */
+
+ /* Reserve space in skb for the SNAP header */
+ dev->hard_header_len += ENCAPS_OVERHEAD;
+
+ netif_carrier_off(dev);
+
+ memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+
+ dev->base_addr = base_addr;
+ dev->irq = irq;
+
+ SET_NETDEV_DEV(dev, priv->dev);
+ ret = register_netdev(dev);
+ if (ret)
+ goto fail;
+
+ priv->ndev = dev;
+
+ /* Report what we've done */
+ dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
+
+ return 0;
+
+ fail:
+ free_netdev(dev);
+ return ret;
+}
+EXPORT_SYMBOL(orinoco_if_add);
+
+void orinoco_if_del(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+}
+EXPORT_SYMBOL(orinoco_if_del);
+
+void free_orinocodev(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct wiphy *wiphy = priv_to_wiphy(priv);
struct orinoco_rx_data *rx_data, *temp;
+ struct orinoco_scan_data *sd, *sdtemp;
+
+ wiphy_unregister(wiphy);
/* If the tasklet is scheduled when we call tasklet_kill it
* will run one final time. However the tasklet will only
@@ -2612,21 +2267,80 @@ void free_orinocodev(struct net_device *dev)
kfree(rx_data);
}
+ cancel_work_sync(&priv->process_scan);
+ /* Explicitly drain priv->scan_list */
+ list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
+ list_del(&sd->list);
+
+ if ((sd->len > 0) && sd->buf)
+ kfree(sd->buf);
+ kfree(sd);
+ }
+
orinoco_unregister_pm_notifier(priv);
orinoco_uncache_fw(priv);
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
- orinoco_bss_data_free(priv);
- free_netdev(dev);
+ wiphy_free(wiphy);
}
EXPORT_SYMBOL(free_orinocodev);
+int orinoco_up(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = orinoco_reinit_firmware(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ goto exit;
+ }
+
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(priv);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+exit:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(orinoco_up);
+
+void orinoco_down(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ err = __orinoco_down(priv);
+ if (err)
+ printk(KERN_WARNING "%s: Error %d downing interface\n",
+ dev->name, err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(orinoco_down);
+
static void orinoco_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ 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);
diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
index af2bae4fe395..21ab36cd76c7 100644
--- a/drivers/net/wireless/orinoco/main.h
+++ b/drivers/net/wireless/orinoco/main.h
@@ -29,10 +29,9 @@ struct net_device;
struct work_struct;
void set_port_type(struct orinoco_private *priv);
-int __orinoco_program_rids(struct net_device *dev);
+int orinoco_commit(struct orinoco_private *priv);
void orinoco_reset(struct work_struct *work);
-
/* Information element helpers - find a home for these... */
static inline u8 *orinoco_get_ie(u8 *data, size_t len,
enum ieee80211_eid eid)
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 8e5a72cc297f..5f4f5c9eef79 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
@@ -47,18 +48,6 @@ typedef enum {
FIRMWARE_TYPE_SYMBOL
} fwtype_t;
-struct bss_element {
- union hermes_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
-struct xbss_element {
- struct agere_ext_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
struct firmware;
struct orinoco_private {
@@ -67,6 +56,10 @@ struct orinoco_private {
int (*hard_reset)(struct orinoco_private *);
int (*stop_fw)(struct orinoco_private *, int);
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[14];
+ u32 cipher_suites[3];
+
/* Synchronisation stuff */
spinlock_t lock;
int hw_unavailable;
@@ -116,7 +109,7 @@ struct orinoco_private {
unsigned int broken_monitor:1;
/* Configuration paramaters */
- u32 iw_mode;
+ enum nl80211_iftype iw_mode;
int prefer_port3;
u16 encode_alg, wep_restrict, tx_key;
struct orinoco_key keys[ORINOCO_MAX_KEYS];
@@ -140,12 +133,10 @@ struct orinoco_private {
int promiscuous, mc_count;
/* Scanning support */
- struct list_head bss_list;
- struct list_head bss_free_list;
- void *bss_xbss_data;
-
- int scan_inprogress; /* Scan pending... */
- u32 scan_mode; /* Type of scan done */
+ struct cfg80211_scan_request *scan_request;
+ struct work_struct process_scan;
+ struct list_head scan_list;
+ spinlock_t scan_lock; /* protects the scan list */
/* WPA support */
u8 *wpa_ie;
@@ -182,14 +173,18 @@ extern int orinoco_debug;
/* Exported prototypes */
/********************************************************************/
-extern struct net_device *alloc_orinocodev(
+extern struct orinoco_private *alloc_orinocodev(
int sizeof_card, struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
+extern void free_orinocodev(struct orinoco_private *priv);
+extern int orinoco_init(struct orinoco_private *priv);
+extern int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq);
+extern void orinoco_if_del(struct orinoco_private *priv);
+extern int orinoco_up(struct orinoco_private *priv);
+extern void orinoco_down(struct orinoco_private *priv);
extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
/********************************************************************/
@@ -215,4 +210,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv,
spin_unlock_irqrestore(&priv->lock, *flags);
}
+/*** Navigate from net_device to orinoco_private ***/
+static inline struct orinoco_private *ndev_priv(struct net_device *dev)
+{
+ struct wireless_dev *wdev = netdev_priv(dev);
+ return wdev_priv(wdev);
+}
#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index b381aed24d73..38c1c9d2abb8 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
static int
orinoco_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- orinoco_cs_hard_reset, NULL);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ orinoco_cs_hard_reset, NULL);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link)
*/
static void orinoco_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
orinoco_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* orinoco_cs_detach */
/*
@@ -239,8 +237,7 @@ next_entry:
static int
orinoco_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -295,29 +292,27 @@ orinoco_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
cs_failed:
@@ -336,8 +331,7 @@ orinoco_cs_config(struct pcmcia_device *link)
static void
orinoco_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -353,62 +347,26 @@ orinoco_cs_release(struct pcmcia_device *link)
static int orinoco_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
- int err = 0;
- unsigned long flags;
/* This is probably racy, but I can't think of
a better way, short of rewriting the PCMCIA
layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ orinoco_down(priv);
return 0;
}
static int orinoco_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
int err = 0;
- unsigned long flags;
-
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ err = orinoco_up(priv);
return err;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index b01726255c6f..c13a4c383410 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev);
@@ -181,24 +180,22 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_nortel_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -217,24 +214,28 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -256,17 +257,16 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
/* Clear LEDs */
iowrite16(0, card->bridge_io + 10);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index 78cafff1fb2e..fea7781948e7 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io;
err = pci_enable_device(pdev);
@@ -139,22 +138,20 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_pci_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -167,24 +164,28 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -200,13 +201,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index c655b4a3de16..ea7231af40a8 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
@@ -21,30 +21,10 @@ struct orinoco_pci_card {
#ifdef CONFIG_PM
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
- dev->name);
- return err;
- }
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: error %d bringing interface down "
- "for suspend\n", dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- free_irq(pdev->irq, dev);
+ orinoco_down(priv);
+ free_irq(pdev->irq, priv);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -54,9 +34,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int orinoco_pci_resume(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->ndev;
int err;
pci_set_power_state(pdev, 0);
@@ -69,7 +48,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ dev->name, priv);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
dev->name);
@@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
return -EBUSY;
}
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: error %d re-initializing firmware "
- "on resume\n", dev->name, err);
- return err;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
+ err = orinoco_up(priv);
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on resume\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
#else
#define orinoco_pci_suspend NULL
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index a2a4471c0337..3f2942a1e4f5 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *attr_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -220,24 +219,22 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_plx_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -256,24 +253,28 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -295,14 +296,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index cda0e6e4d7a1..d3452548cc71 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -124,23 +123,21 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_tmd_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -153,24 +150,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -189,14 +190,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 89d699d4dfe6..d2f10e9c2162 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -5,147 +5,166 @@
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "orinoco.h"
+#include "main.h"
#include "scan.h"
-#define ORINOCO_MAX_BSS_COUNT 64
+#define ZERO_DBM_OFFSET 0x95
+#define MAX_SIGNAL_LEVEL 0x8A
+#define MIN_SIGNAL_LEVEL 0x2F
-#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
+#define SIGNAL_TO_DBM(x) \
+ (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
+ - ZERO_DBM_OFFSET)
+#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-int orinoco_bss_data_allocate(struct orinoco_private *priv)
+static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
{
- if (priv->bss_xbss_data)
- return 0;
-
- if (priv->has_ext_scan)
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct xbss_element),
- GFP_KERNEL);
- else
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct bss_element),
- GFP_KERNEL);
-
- if (!priv->bss_xbss_data) {
- printk(KERN_WARNING "Out of memory allocating beacons");
- return -ENOMEM;
+ int i;
+ u8 rate;
+
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 5; i++) {
+ rate = le16_to_cpu(rates[i]);
+ /* NULL terminated */
+ if (rate == 0x0)
+ break;
+ buf[i + 2] = rate;
}
- return 0;
-}
+ buf[1] = i;
-void orinoco_bss_data_free(struct orinoco_private *priv)
-{
- kfree(priv->bss_xbss_data);
- priv->bss_xbss_data = NULL;
+ return i + 2;
}
-void orinoco_bss_data_init(struct orinoco_private *priv)
+static int prism_build_supp_rates(u8 *buf, const u8 *rates)
{
int i;
- INIT_LIST_HEAD(&priv->bss_free_list);
- INIT_LIST_HEAD(&priv->bss_list);
- if (priv->has_ext_scan)
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_XBSS[i].list),
- &priv->bss_free_list);
- else
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_BSS[i].list),
- &priv->bss_free_list);
-
-}
-
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age)
-{
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
- struct xbss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
- }
- } else {
- struct bss_element *bss;
- struct bss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 8; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
+ }
+ buf[1] = i;
+
+ /* We might still have another 2 rates, which need to go in
+ * extended supported rates */
+ if (i == 8 && rates[i] > 0) {
+ buf[10] = WLAN_EID_EXT_SUPP_RATES;
+ for (; i < 10; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
}
+ buf[11] = i - 8;
}
+
+ return (i < 8) ? i + 2 : i + 4;
}
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom)
+static void orinoco_add_hostscan_result(struct orinoco_private *priv,
+ const union hermes_scan_info *bss)
{
- struct xbss_element *bss = NULL;
- int found = 0;
-
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.bssid, atom->bssid))
- continue;
- /* ESSID lengths */
- if (bss->bss.data[1] != atom->data[1])
- continue;
- if (memcmp(&bss->bss.data[2], &atom->data[2],
- atom->data[1]))
- continue;
- found = 1;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u8 ie_buf[46];
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ int ie_len;
+ int freq;
+ int len;
+
+ len = le16_to_cpu(bss->a.essid_len);
+
+ /* Reconstruct SSID and bitrate IEs to pass up */
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = len;
+ memcpy(&ie_buf[2], bss->a.essid, len);
+
+ ie = ie_buf + len + 2;
+ ie_len = ie_buf[1] + 2;
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ ie_len += symbol_build_supp_rates(ie, bss->s.rates);
break;
- }
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct xbss_element, list);
- list_del(priv->bss_free_list.next);
+ case FIRMWARE_TYPE_INTERSIL:
+ ie_len += prism_build_supp_rates(ie, bss->p.rates);
+ break;
- list_add_tail(&bss->list, &priv->bss_list);
+ case FIRMWARE_TYPE_AGERE:
+ default:
+ break;
}
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+ channel = ieee80211_get_channel(wiphy, freq);
+ timestamp = 0;
+ capability = le16_to_cpu(bss->a.capabilities);
+ beacon_interval = le16_to_cpu(bss->a.beacon_interv);
+ signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
+
+ cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+ capability, beacon_interval, ie_buf, ie_len,
+ signal, GFP_KERNEL);
}
-int orinoco_process_scan_results(struct orinoco_private *priv,
- unsigned char *buf,
- int len)
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *bss,
+ size_t len)
{
- int offset; /* In the scan data */
- union hermes_scan_info *atom;
- int atom_len;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ size_t ie_len;
+ int chan, freq;
+
+ ie_len = len - sizeof(*bss);
+ ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+ chan = ie ? ie[2] : 0;
+ freq = ieee80211_dsss_chan_to_freq(chan);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ timestamp = le64_to_cpu(bss->timestamp);
+ capability = le16_to_cpu(bss->capabilities);
+ beacon_interval = le16_to_cpu(bss->beacon_interval);
+ ie = bss->data;
+ signal = SIGNAL_TO_MBM(bss->level);
+
+ cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+ capability, beacon_interval, ie, ie_len,
+ signal, GFP_KERNEL);
+}
+
+void orinoco_add_hostscan_results(struct orinoco_private *priv,
+ unsigned char *buf,
+ size_t len)
+{
+ int offset; /* In the scan data */
+ size_t atom_len;
+ bool abort = false;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE:
atom_len = sizeof(struct agere_scan_apinfo);
offset = 0;
break;
+
case FIRMWARE_TYPE_SYMBOL:
/* Lack of documentation necessitates this hack.
* Different firmwares have 68 or 76 byte long atoms.
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
atom_len = 68;
offset = 0;
break;
+
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
@@ -170,64 +190,41 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %d\n", priv->ndev->name,
+ "data: %zu\n", priv->ndev->name,
atom_len);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+
default:
- return -EOPNOTSUPP;
+ abort = true;
+ goto scan_abort;
}
/* Check that we got an whole number of atoms */
if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %d, "
- "atom_len %d, offset %d\n", priv->ndev->name, len,
+ printk(KERN_ERR "%s: Unexpected scan data length %zu, "
+ "atom_len %zu, offset %d\n", priv->ndev->name, len,
atom_len, offset);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
- orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
- /* Read the entries one by one */
+ /* Process the entries one by one */
for (; offset + atom_len <= len; offset += atom_len) {
- int found = 0;
- struct bss_element *bss = NULL;
+ union hermes_scan_info *atom;
- /* Get next atom */
atom = (union hermes_scan_info *) (buf + offset);
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
- continue;
- if (le16_to_cpu(bss->bss.a.essid_len) !=
- le16_to_cpu(atom->a.essid_len))
- continue;
- if (memcmp(bss->bss.a.essid, atom->a.essid,
- le16_to_cpu(atom->a.essid_len)))
- continue;
- found = 1;
- break;
- }
-
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct bss_element, list);
- list_del(priv->bss_free_list.next);
-
- list_add_tail(&bss->list, &priv->bss_list);
- }
-
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ orinoco_add_hostscan_result(priv, atom);
}
- return 0;
+ scan_abort:
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
index f319f7466af1..2dc4e046dbdb 100644
--- a/drivers/net/wireless/orinoco/scan.h
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -9,21 +9,12 @@
struct orinoco_private;
struct agere_ext_scan_info;
-/* Setup and free memory for scan results */
-int orinoco_bss_data_allocate(struct orinoco_private *priv);
-void orinoco_bss_data_free(struct orinoco_private *priv);
-void orinoco_bss_data_init(struct orinoco_private *priv);
-
/* Add scan results */
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom);
-int orinoco_process_scan_results(struct orinoco_private *dev,
- unsigned char *buf,
- int len);
-
-/* Clear scan results */
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age);
-
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *atom,
+ size_t len);
+void orinoco_add_hostscan_results(struct orinoco_private *dev,
+ unsigned char *buf,
+ size_t len);
#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 38e5198e44c7..c361310b885d 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
static int
spectrum_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ spectrum_cs_hard_reset,
+ spectrum_cs_stop_firmware);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link)
*/
static void spectrum_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
spectrum_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* spectrum_cs_detach */
/*
@@ -306,8 +304,7 @@ next_entry:
static int
spectrum_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -362,34 +359,31 @@ spectrum_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
/* Reset card */
if (spectrum_cs_hard_reset(priv) != 0)
goto failed;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
-
return 0;
cs_failed:
@@ -408,8 +402,7 @@ spectrum_cs_config(struct pcmcia_device *link)
static void
spectrum_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -427,23 +420,11 @@ spectrum_cs_release(struct pcmcia_device *link)
static int
spectrum_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = link->priv;
int err = 0;
/* Mark the device as stopped, to block IO until later */
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
+ orinoco_down(priv);
return err;
}
@@ -451,33 +432,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
static int
spectrum_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
+ struct orinoco_private *priv = link->priv;
+ int err = orinoco_up(priv);
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3f0814234392..b6ff3dbb7dd6 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -7,6 +7,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
@@ -23,7 +24,7 @@
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err;
@@ -51,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
* here so we're not safe to sleep here. */
hermes_inquire(hw, HERMES_INQ_TALLIES);
- if (priv->iw_mode == IW_MODE_ADHOC) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
memset(&wstats->qual, 0, sizeof(wstats->qual));
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
@@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_ioctl_getname(struct net_device *dev,
- struct iw_request_info *info,
- char *name,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int numrates;
- int err;
-
- err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
- if (!err && (numrates > 2))
- strcpy(name, "IEEE 802.11b");
- else
- strcpy(name, "IEEE 802.11-DS");
-
- return 0;
-}
-
static int orinoco_ioctl_setwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -142,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev,
goto out;
}
- if (priv->iw_mode != IW_MODE_INFRA) {
+ if (priv->iw_mode != NL80211_IFTYPE_STATION) {
printk(KERN_WARNING "%s: Manual roaming supported only in "
"managed mode\n", dev->name);
err = -EOPNOTSUPP;
@@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
@@ -190,184 +172,12 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
return err;
}
-static int orinoco_ioctl_setmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (priv->iw_mode == *mode)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (*mode) {
- case IW_MODE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EOPNOTSUPP;
- break;
-
- case IW_MODE_INFRA:
- break;
-
- case IW_MODE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- printk(KERN_WARNING "%s: Monitor mode support is "
- "buggy in this firmware, not enabling\n",
- dev->name);
- err = -EOPNOTSUPP;
- }
- break;
-
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- if (err == -EINPROGRESS) {
- priv->iw_mode = *mode;
- set_port_type(priv);
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
-
- *mode = priv->iw_mode;
- return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *rrq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- struct iw_range *range = (struct iw_range *) extra;
- int numrates;
- int i, k;
-
- rrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 22;
-
- /* Set available channels/frequencies */
- range->num_channels = NUM_CHANNELS;
- k = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- range->freq[k].i = i + 1;
- range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
- 100000);
- range->freq[k].e = 1;
- k++;
- }
-
- if (k >= IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = k;
- range->sensitivity = 3;
-
- if (priv->has_wep) {
- range->max_encoding_tokens = ORINOCO_MAX_KEYS;
- range->encoding_size[0] = SMALL_KEY_SIZE;
- range->num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range->encoding_size[1] = LARGE_KEY_SIZE;
- range->num_encoding_sizes = 2;
- }
- }
-
- if (priv->has_wpa)
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
- if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
- /* Quality stats meaningless in ad-hoc mode */
- } else {
- range->max_qual.qual = 0x8b - 0x2f;
- range->max_qual.level = 0x2f - 0x95 - 1;
- range->max_qual.noise = 0x2f - 0x95 - 1;
- /* Need to get better values */
- range->avg_qual.qual = 0x24;
- range->avg_qual.level = 0xC2;
- range->avg_qual.noise = 0x9E;
- }
-
- err = orinoco_hw_get_bitratelist(priv, &numrates,
- range->bitrate, IW_MAX_BITRATES);
- if (err)
- return err;
- range->num_bitrates = numrates;
-
- /* Set an indication of the max TCP throughput in bit/s that we can
- * expect using this interface. May be use for QoS stuff...
- * Jean II */
- if (numrates > 2)
- range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
- else
- range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->min_pmp = 0;
- range->max_pmp = 65535000;
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1000; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R);
-
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 0;
- range->max_retry = 65535; /* ??? */
- range->min_r_time = 0;
- range->max_r_time = 65535 * 1000; /* ??? */
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- range->scan_capa = IW_SCAN_CAPA_ESSID;
- else
- range->scan_capa = IW_SCAN_CAPA_NONE;
-
- /* Event capability (kernel) */
- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- /* Event capability (driver) */
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
- IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
- return 0;
-}
-
static int orinoco_ioctl_setiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
int setindex = priv->tx_key;
int encode_alg = priv->encode_alg;
@@ -469,7 +279,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
unsigned long flags;
@@ -508,7 +318,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -539,7 +349,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int active;
int err = 0;
unsigned long flags;
@@ -562,59 +372,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (nrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, nickbuf, nrq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
- orinoco_unlock(priv, &flags);
-
- nrq->length = strlen(priv->nick);
-
- return 0;
-}
-
static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int chan = -1;
unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
/* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == IW_MODE_INFRA)
+ if (priv->iw_mode == NL80211_IFTYPE_STATION)
return -EBUSY;
if ((frq->e == 0) && (frq->m <= 1000)) {
@@ -640,7 +409,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
return -EBUSY;
priv->channel = chan;
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
/* Fast channel change - no commit if successful */
hermes_t *hw = &priv->hw;
err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
@@ -657,7 +426,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int tmp;
/* Locking done in there */
@@ -676,7 +445,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
u16 val;
int err;
@@ -705,7 +474,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = srq->value;
unsigned long flags;
@@ -728,7 +497,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = rrq->value;
unsigned long flags;
@@ -752,7 +521,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
rrq->value = priv->rts_thresh;
rrq->disabled = (rrq->value == 2347);
@@ -766,7 +535,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -806,7 +575,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err;
u16 val;
@@ -847,7 +616,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int ratemode;
int bitrate; /* 100s of kilobits */
unsigned long flags;
@@ -881,7 +650,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int bitrate, automatic;
unsigned long flags;
@@ -910,7 +679,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -964,7 +733,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 enable, period, timeout, mcast;
@@ -1018,7 +787,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, alg = ext->alg, set_key = 1;
@@ -1079,7 +848,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
case IW_ENCODE_ALG_TKIP:
{
- hermes_t *hw = &priv->hw;
u8 *tkip_iv = NULL;
if (!priv->has_wpa ||
@@ -1094,7 +862,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
tkip_iv = &ext->rx_seq[0];
- err = __orinoco_hw_set_tkip_key(hw, idx,
+ err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
(u8 *) &priv->tkip_key[idx],
tkip_iv, NULL);
@@ -1120,7 +888,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, max_key_len;
@@ -1177,7 +945,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_param *param = &wrqu->param;
unsigned long flags;
@@ -1255,7 +1023,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_param *param = &wrqu->param;
unsigned long flags;
int ret = 0;
@@ -1295,7 +1063,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u8 *buf;
unsigned long flags;
@@ -1338,7 +1106,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
@@ -1367,7 +1135,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_mlme *mlme = (struct iw_mlme *)extra;
unsigned long flags;
@@ -1408,7 +1176,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 short_limit, long_limit, lifetime;
@@ -1462,7 +1230,7 @@ static int orinoco_ioctl_reset(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1487,7 +1255,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
unsigned long flags;
@@ -1508,7 +1276,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->ibss_port;
@@ -1520,7 +1288,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
int err = 0;
unsigned long flags;
@@ -1566,7 +1334,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->prefer_port3;
@@ -1578,7 +1346,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int val;
@@ -1610,7 +1378,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
if (!priv->has_preamble)
@@ -1630,7 +1398,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
struct iw_point *data,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int rid = data->flags;
u16 length;
@@ -1661,519 +1429,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
return err;
}
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- struct iw_scan_req *si = (struct iw_scan_req *) extra;
- int err = 0;
- unsigned long flags;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == IW_MODE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Note : because we don't lock out the irq handler, the way
- * we access scan variables in priv is critical.
- * o scan_inprogress : not touched by irq handler
- * o scan_mode : not touched by irq handler
- * Before modifying anything on those variables, please think hard !
- * Jean II */
-
- /* Save flags */
- priv->scan_mode = srq->flags;
-
- /* Always trigger scanning, even if it's in progress.
- * This way, if the info frame get lost, we will recover somewhat
- * gracefully - Jean II */
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- }
- break;
- case FIRMWARE_TYPE_AGERE:
- if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
- struct hermes_idstring idbuf;
- size_t len = min(sizeof(idbuf.val),
- (size_t) si->essid_len);
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, si->essid, len);
-
- err = hermes_write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- /* Clear scan results at the start of
- * an extended scan */
- orinoco_clear_scan_results(priv,
- msecs_to_jiffies(15000));
-
- /* TODO: Is this available on older firmware?
- * Can we use it to scan specific channels
- * for IW_SCAN_THIS_FREQ? */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- /* One more client */
- if (!err)
- priv->scan_inprogress = 1;
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- union hermes_scan_info *bss,
- unsigned long last_scanned)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->a.essid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = le16_to_cpu(bss->a.capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- channel = bss->s.channel;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
- iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* Bit rate is not available in Lucent/Agere firmwares */
- if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
- char *current_val = current_ev + iwe_stream_lcp_len(info);
- int i;
- int step;
-
- if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
- step = 2;
- else
- step = 1;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 10 values */
- for (i = 0; i < 10; i += step) {
- /* NULL terminated */
- if (bss->p.rates[i] == 0x0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value =
- ((bss->p.rates[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info, current_ev,
- current_val,
- end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->a.beacon_interv));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- struct agere_ext_scan_info *bss,
- unsigned long last_scanned)
-{
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
- u8 *ie;
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- ie = bss->data;
- iwe.u.data.length = ie[1];
- if (iwe.u.data.length) {
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, &ie[2]);
- }
-
- /* Add mode */
- capabilities = le16_to_cpu(bss->capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- iwe.cmd = SIOCGIWMODE;
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
- channel = ie ? ie[2] : 0;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = bss->level - 0x95;
- iwe.u.qual.noise = bss->noise - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* WPA IE */
- ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- /* RSN IE */
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
- if (ie) {
- char *p = current_ev + iwe_stream_lcp_len(info);
- int i;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 2; i < (ie[1] + 2); i++) {
- iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
- p = iwe_stream_add_value(info, current_ev, p, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if (p > (current_ev + iwe_stream_lcp_len(info)))
- current_ev = p;
- }
-
- /* Timestamp */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length =
- snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
- (unsigned long long) le64_to_cpu(bss->timestamp));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->beacon_interval));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- unsigned long flags;
- char *current_ev = extra;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (priv->scan_inprogress) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy.
- * Second, we grab some rtnetlink lock before comming
- * here (in dev_ioctl()).
- * Third, we generate an Wireless Event, so the
- * caller can wait itself on that - Jean II */
- err = -EAGAIN;
- goto out;
- }
-
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev =
- orinoco_translate_ext_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- } else {
- struct bss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev = orinoco_translate_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
- }
-
- srq->length = (current_ev - extra);
- srq->flags = (__u16) priv->scan_mode;
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
/* Commit handler, called after set operations */
static int orinoco_ioctl_commit(struct net_device *dev,
@@ -2181,50 +1436,17 @@ static int orinoco_ioctl_commit(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
if (!priv->open)
return 0;
- if (priv->broken_disableport) {
- orinoco_reset(&priv->reset_work);
- return 0;
- }
-
if (orinoco_lock(priv, &flags) != 0)
return err;
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
+ err = orinoco_commit(priv);
orinoco_unlock(priv, &flags);
return err;
@@ -2258,26 +1480,24 @@ static const struct iw_priv_args orinoco_privtab[] = {
[IW_IOCTL_IDX(id)] = (iw_handler) func
static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname),
+ STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
- STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode),
- STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode),
+ STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
+ STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
- STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange),
+ STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
- STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan),
- STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan),
+ STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
+ STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
- STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick),
- STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick),
STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts),
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
index c2050dee6293..b542e68f1781 100644
--- a/drivers/net/wireless/p54/Makefile
+++ b/drivers/net/wireless/p54/Makefile
@@ -1,3 +1,6 @@
+p54common-objs := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS) += led.o
+
obj-$(CONFIG_P54_COMMON) += p54common.o
obj-$(CONFIG_P54_USB) += p54usb.o
obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
new file mode 100644
index 000000000000..0efe67deedee
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -0,0 +1,753 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/sort.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_rate p54_arates[] = {
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+#define CHAN_HAS_CAL BIT(0)
+#define CHAN_HAS_LIMIT BIT(1)
+#define CHAN_HAS_CURVE BIT(2)
+#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+ u16 freq;
+ u16 data;
+ int index;
+ enum ieee80211_band band;
+};
+
+struct p54_channel_list {
+ struct p54_channel_entry *channels;
+ size_t entries;
+ size_t max_entries;
+ size_t band_channel_num[IEEE80211_NUM_BANDS];
+};
+
+static int p54_get_band_from_freq(u16 freq)
+{
+ /* FIXME: sync these values with the 802.11 spec */
+
+ if ((freq >= 2412) && (freq <= 2484))
+ return IEEE80211_BAND_2GHZ;
+
+ if ((freq >= 4920) && (freq <= 5825))
+ return IEEE80211_BAND_5GHZ;
+
+ return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+ const void *_b)
+{
+ const struct p54_channel_entry *a = _a;
+ const struct p54_channel_entry *b = _b;
+
+ return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+ struct ieee80211_supported_band *band_entry,
+ enum ieee80211_band band)
+{
+ /* TODO: generate rate array dynamically */
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ band_entry->bitrates = p54_bgrates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ band_entry->bitrates = p54_arates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+ struct p54_channel_list *list,
+ enum ieee80211_band band)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_supported_band *tmp, *old;
+ unsigned int i, j;
+ int ret = -ENOMEM;
+
+ if ((!list->entries) || (!list->band_channel_num[band]))
+ return 0;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ goto err_out;
+
+ tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+ list->band_channel_num[band], GFP_KERNEL);
+ if (!tmp->channels)
+ goto err_out;
+
+ ret = p54_fill_band_bitrates(dev, tmp, band);
+ if (ret)
+ goto err_out;
+
+ for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+ (i < list->entries); i++) {
+
+ if (list->channels[i].band != band)
+ continue;
+
+ if (list->channels[i].data != CHAN_HAS_ALL) {
+ printk(KERN_ERR "%s:%s%s%s is/are missing for "
+ "channel:%d [%d MHz].\n",
+ wiphy_name(dev->wiphy),
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
+ }
+
+ tmp->channels[j].band = list->channels[i].band;
+ tmp->channels[j].center_freq = list->channels[i].freq;
+ j++;
+ }
+
+ tmp->n_channels = list->band_channel_num[band];
+ old = priv->band_table[band];
+ priv->band_table[band] = tmp;
+ if (old) {
+ kfree(old->channels);
+ kfree(old);
+ }
+
+ return 0;
+
+err_out:
+ if (tmp) {
+ kfree(tmp->channels);
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
+{
+ int band, i;
+
+ /*
+ * usually all lists in the eeprom are mostly sorted.
+ * so it's very likely that the entry we are looking for
+ * is right at the end of the list
+ */
+ for (i = list->entries; i >= 0; i--) {
+ if (freq == list->channels[i].freq) {
+ list->channels[i].data |= data;
+ break;
+ }
+ }
+
+ if ((i < 0) && (list->entries < list->max_entries)) {
+ /* entry does not exist yet. Initialize a new one. */
+ band = p54_get_band_from_freq(freq);
+
+ /*
+ * filter out frequencies which don't belong into
+ * any supported band.
+ */
+ if (band < 0)
+ return ;
+
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ list->channels[i].freq = freq;
+ list->channels[i].data = data;
+ list->channels[i].band = band;
+ list->channels[i].index = ieee80211_frequency_to_channel(freq);
+ /* TODO: parse output_limit and fill max_power */
+ }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_channel_list *list;
+ unsigned int i, j, max_channel_num;
+ int ret = -ENOMEM;
+ u16 freq;
+
+ if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+ (priv->iq_autocal_len != priv->output_limit->entries))
+ printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+ "to use all channels with this device.\n",
+ wiphy_name(dev->wiphy));
+
+ max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+ priv->iq_autocal_len);
+ max_channel_num = max_t(unsigned int, max_channel_num,
+ priv->curve_data->entries);
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ goto free;
+
+ list->max_entries = max_channel_num;
+ list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+ max_channel_num, GFP_KERNEL);
+ if (!list->channels)
+ goto free;
+
+ for (i = 0; i < max_channel_num; i++) {
+ if (i < priv->iq_autocal_len) {
+ freq = le16_to_cpu(priv->iq_autocal[i].freq);
+ p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+ }
+
+ if (i < priv->output_limit->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ }
+
+ if (i < priv->curve_data->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->curve_data->entry_size +
+ priv->curve_data->offset +
+ priv->curve_data->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+ }
+ }
+
+ /* sort the list by the channel index */
+ sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+ p54_compare_channels, NULL);
+
+ for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+ if (list->band_channel_num[i]) {
+ ret = p54_generate_band(dev, list, i);
+ if (ret)
+ goto free;
+
+ j++;
+ }
+ }
+ if (j == 0) {
+ /* no useable band available. */
+ ret = -EINVAL;
+ }
+
+free:
+ if (list) {
+ kfree(list->channels);
+ kfree(list);
+ }
+
+ return ret;
+}
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev0 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ dst = target;
+ src = source;
+
+ dst->rf_power = src->rf_power;
+ dst->pa_detector = src->pa_detector;
+ dst->data_64qam = src->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+ dst->data_16qam = SUB(src->pcv, 12);
+ dst->data_qpsk = SUB(dst->data_16qam, 12);
+ dst->data_bpsk = SUB(dst->data_qpsk, 12);
+ dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ }
+
+ return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev1 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ memcpy(target, source, sizeof(*src));
+
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ source++;
+ }
+
+ return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+ "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+ u16 type)
+{
+ struct p54_common *priv = dev->priv;
+ int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+ int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+ int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+ int i;
+
+ if (len != (entry_size * num_entries)) {
+ printk(KERN_ERR "%s: unknown rssi calibration data packing "
+ " type:(%x) len:%d.\n",
+ wiphy_name(dev->wiphy), type, len);
+
+ print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ struct pda_rssi_cal_entry *cal = data +
+ (offset + i * entry_size);
+ priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+ priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+ }
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+ void *data, int len)
+{
+ struct pda_country *country;
+
+ if (len != sizeof(*country)) {
+ printk(KERN_ERR "%s: found possible invalid default country "
+ "eeprom entry. (entry size: %d)\n",
+ wiphy_name(dev->wiphy), len);
+
+ print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ country = (struct pda_country *) data;
+ if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+ regulatory_hint(dev->wiphy, country->alpha2);
+ else {
+ /* TODO:
+ * write a shared/common function that converts
+ * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+ * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+ */
+ }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+ u8 *data, size_t len)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (len < 2)
+ return -EINVAL;
+
+ if (data[0] != 0) {
+ printk(KERN_ERR "%s: unknown output power db revision:%x\n",
+ wiphy_name(dev->wiphy), data[0]);
+ return -EINVAL;
+ }
+
+ if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+ return -EINVAL;
+
+ priv->output_limit = kmalloc(data[1] *
+ sizeof(struct pda_channel_output_limit) +
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit)
+ return -ENOMEM;
+
+ priv->output_limit->offset = 0;
+ priv->output_limit->entries = data[1];
+ priv->output_limit->entry_size =
+ sizeof(struct pda_channel_output_limit);
+ priv->output_limit->len = priv->output_limit->entry_size *
+ priv->output_limit->entries +
+ priv->output_limit->offset;
+
+ memcpy(priv->output_limit->data, &data[2],
+ data[1] * sizeof(struct pda_channel_output_limit));
+
+ return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+ size_t total_len)
+{
+ struct p54_cal_database *dst;
+ size_t payload_len, entries, entry_size, offset;
+
+ payload_len = le16_to_cpu(src->len);
+ entries = le16_to_cpu(src->entries);
+ entry_size = le16_to_cpu(src->entry_size);
+ offset = le16_to_cpu(src->offset);
+ if (((entries * entry_size + offset) != payload_len) ||
+ (payload_len + sizeof(*src) != total_len))
+ return NULL;
+
+ dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ dst->entries = entries;
+ dst->entry_size = entry_size;
+ dst->offset = offset;
+ dst->len = payload_len;
+
+ memcpy(dst->data, src->data, payload_len);
+ return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap;
+ struct pda_entry *entry;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+ u8 *end = (u8 *)eeprom + len;
+ u16 synth = 0;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+ /* verify that at least the entry length/code fits */
+ while ((u8 *)entry <= end - sizeof(*entry)) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+
+ /* abort if entry exceeds whole structure */
+ if ((u8 *)entry + sizeof(*entry) + data_len > end)
+ break;
+
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ if (data_len != ETH_ALEN)
+ break;
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (priv->output_limit)
+ break;
+ err = p54_convert_output_limits(dev, entry->data,
+ data_len);
+ if (err)
+ goto err;
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA: {
+ struct pda_pa_curve_data *curve_data =
+ (struct pda_pa_curve_data *)entry->data;
+ if (data_len < sizeof(*curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ switch (curve_data->cal_method_rev) {
+ case 0:
+ err = p54_convert_rev0(dev, curve_data);
+ break;
+ case 1:
+ err = p54_convert_rev1(dev, curve_data);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown curve data "
+ "revision %d\n",
+ wiphy_name(dev->wiphy),
+ curve_data->cal_method_rev);
+ err = -ENODEV;
+ break;
+ }
+ if (err)
+ goto err;
+ }
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_DEFAULT_COUNTRY:
+ p54_parse_default_country(dev, entry->data, data_len);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct exp_if *exp_if = tmp;
+ if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+ synth = le16_to_cpu(exp_if->variant);
+ tmp += sizeof(*exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ if (data_len < 2)
+ break;
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION:
+ case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+ case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+ p54_parse_rssical(dev, entry->data, data_len,
+ le16_to_cpu(entry->code));
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
+ __le16 *src = (void *) entry->data;
+ s16 *dst = (void *) &priv->rssical_db;
+ int i;
+
+ if (data_len != sizeof(priv->rssical_db)) {
+ err = -EINVAL;
+ goto err;
+ }
+ for (i = 0; i < sizeof(priv->rssical_db) /
+ sizeof(*src); i++)
+ *(dst++) = (s16) le16_to_cpu(*(src++));
+ }
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->output_limit || data_len < sizeof(*pda))
+ break;
+ priv->output_limit = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->curve_data || data_len < sizeof(*pda))
+ break;
+ priv->curve_data = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_END:
+ /* make it overrun */
+ entry_len = len;
+ break;
+ default:
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ }
+
+ if (!synth || !priv->iq_autocal || !priv->output_limit ||
+ !priv->curve_data) {
+ printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+ wiphy_name(dev->wiphy));
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = p54_generate_channel_lists(dev);
+ if (err)
+ goto err;
+
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+ p54_init_xbow_synth(priv);
+ if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ priv->band_table[IEEE80211_BAND_2GHZ];
+ if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ priv->band_table[IEEE80211_BAND_5GHZ];
+ if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+ priv->rx_diversity_mask = 3;
+ if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+ priv->tx_diversity_mask = 3;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+ wiphy_name(dev->wiphy));
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
+ p54_rf_chips[priv->rxhw]);
+
+ return 0;
+
+err:
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+
+ printk(KERN_ERR "%s: eeprom parse failed!\n",
+ wiphy_name(dev->wiphy));
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+ int ret = -ENOMEM;
+ void *eeprom;
+
+ maxblocksize = EEPROM_READBACK_LEN;
+ if (priv->fw_var >= 0x509)
+ maxblocksize -= 0xc;
+ else
+ maxblocksize -= 0x4;
+
+ eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+ if (unlikely(!eeprom))
+ goto free;
+
+ while (eeprom_size) {
+ blocksize = min(eeprom_size, maxblocksize);
+ ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+ offset, blocksize);
+ if (unlikely(ret))
+ goto free;
+
+ offset += blocksize;
+ eeprom_size -= blocksize;
+ }
+
+ ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+ kfree(eeprom);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
new file mode 100644
index 000000000000..9051aef11249
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.h
@@ -0,0 +1,226 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ * Copyright (C) 2001 Intersil Americas Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+ __le32 magic;
+ __le16 pad;
+ __le16 len;
+ __le32 arm_opcode;
+ u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+ __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_entry {
+ __le16 mul;
+ __le16 add;
+} __packed;
+
+struct pda_country {
+ u8 regdomain;
+ u8 alpha2[2];
+ u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+ struct {
+ u8 gain_5GHz; /* 0.25 dBi units */
+ u8 gain_2GHz; /* 0.25 dBi units */
+ } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+ __le16 entries;
+ __le16 entry_size;
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+#define PDR_NIC_RAM_SIZE 0x0005
+#define PDR_RFMODEM_SUP_RANGE 0x0006
+#define PDR_PRISM_MAC_SUP_RANGE 0x0007
+#define PDR_NIC_ID 0x0008
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET 0x0104
+#define PDR_DEFAULT_CHAN 0x0105
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_IFR_SETTING 0x0200
+#define PDR_RFR_SETTING 0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS 0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS 0x0203
+#define PDR_3861_IFRF_REG_SETTINGS 0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400
+#define PDR_PRISM_USB_ID 0x0401
+#define PDR_PRISM_PCI_ID 0x0402
+#define PDR_PRISM_PCI_IF_CONFIG 0x0403
+#define PDR_PRISM_PCI_PM_CONFIG 0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER 0x0000
+#define PDR_INTERFACE_ROLE_CLIENT 0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE 0x80
+#define PDR_COUNTRY_CERT_CODE_REAL 0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
+#define PDR_COUNTRY_CERT_BAND 0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
+#define PDR_COUNTRY_CERT_IODOOR 0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
+#define PDR_COUNTRY_CERT_INDEX 0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK 0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
+#define PDR_SYNTH_FRONTEND_XBOW 0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
+#define PDR_SYNTH_IQ_CAL_MASK 0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
+#define PDR_SYNTH_24_GHZ_MASK 0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
+#define PDR_SYNTH_5_GHZ_MASK 0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
+#define PDR_SYNTH_RX_DIV_MASK 0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
+#define PDR_SYNTH_TX_DIV_MASK 0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
+#define PDR_SYNTH_ASM_MASK 0x0400
+#define PDR_SYNTH_ASM_XSWON 0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
new file mode 100644
index 000000000000..21f19018fab5
--- /dev/null
+++ b/drivers/net/wireless/p54/fwio.c
@@ -0,0 +1,715 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+ int maxlen;
+
+ if (priv->rx_start)
+ return 0;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data && (bootrec->data +
+ (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ priv->fw_interface = be32_to_cpup((__be32 *)
+ bootrec->data);
+ switch (priv->fw_interface) {
+ case FW_LM86:
+ case FW_LM20:
+ case FW_LM87: {
+ char *iftype = (char *)bootrec->data;
+ printk(KERN_INFO "%s: p54 detected a LM%c%c "
+ "firmware\n",
+ wiphy_name(priv->hw->wiphy),
+ iftype[2], iftype[3]);
+ break;
+ }
+ case FW_FMAC:
+ default:
+ printk(KERN_ERR "%s: unsupported firmware\n",
+ wiphy_name(priv->hw->wiphy));
+ return -ENODEV;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+ fw_version = (unsigned char *) bootrec->data;
+ break;
+ case BR_CODE_DESCR: {
+ struct bootrec_desc *desc =
+ (struct bootrec_desc *)bootrec->data;
+ priv->rx_start = le32_to_cpu(desc->rx_start);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+ priv->headroom = desc->headroom;
+ priv->tailroom = desc->tailroom;
+ priv->privacy_caps = desc->privacy_caps;
+ priv->rx_keycache_size = desc->rx_keycache_size;
+ if (le32_to_cpu(bootrec->len) == 11)
+ priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+ else
+ priv->rx_mtu = (size_t)
+ 0x620 - priv->tx_hdr_len;
+ maxlen = priv->tx_hdr_len + /* USB devices */
+ sizeof(struct p54_rx_data) +
+ 4 + /* rx alignment */
+ IEEE80211_MAX_FRAG_THRESHOLD;
+ if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+ printk(KERN_INFO "p54: rx_mtu reduced from %d "
+ "to %d\n", priv->rx_mtu, maxlen);
+ priv->rx_mtu = maxlen;
+ }
+ break;
+ }
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+ wiphy_name(priv->hw->wiphy), fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var < 0x500)
+ printk(KERN_INFO "%s: you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n",
+ wiphy_name(priv->hw->wiphy));
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+
+ if (priv->fw_var >= 0x500) {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+ } else {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+ }
+ priv->hw->queues = P54_QUEUE_AC_NUM;
+ }
+
+ printk(KERN_INFO "%s: cryptographic accelerator "
+ "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+ "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+ BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+ "YES" : "no");
+
+ if (priv->rx_keycache_size) {
+ /*
+ * NOTE:
+ *
+ * The firmware provides at most 255 (0 - 254) slots
+ * for keys which are then used to offload decryption.
+ * As a result the 255 entry (aka 0xff) can be used
+ * safely by the driver to mark keys that didn't fit
+ * into the full cache. This trick saves us from
+ * keeping a extra list for uploaded keys.
+ */
+
+ priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+ priv->rx_keycache_size), GFP_KERNEL);
+
+ if (!priv->used_rxkeys)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+ u16 payload_len, u16 type, gfp_t memflags)
+{
+ struct p54_hdr *hdr;
+ struct sk_buff *skb;
+ size_t frame_len = sizeof(*hdr) + payload_len;
+
+ if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+ return NULL;
+
+ if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+ return NULL;
+
+ skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, priv->tx_hdr_len);
+
+ hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->len = cpu_to_le16(payload_len);
+ hdr->type = cpu_to_le16(type);
+ hdr->tries = hdr->rts_tries = 0;
+ return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+ struct sk_buff *skb;
+ size_t eeprom_hdr_size;
+ int ret = 0;
+
+ if (priv->fw_var >= 0x509)
+ eeprom_hdr_size = sizeof(*eeprom_hdr);
+ else
+ eeprom_hdr_size = 0x4;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+ len, P54_CONTROL_TYPE_EEPROM_READBACK,
+ GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ mutex_lock(&priv->eeprom_mutex);
+ priv->eeprom = buf;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+ eeprom_hdr_size + len);
+
+ if (priv->fw_var < 0x509) {
+ eeprom_hdr->v1.offset = cpu_to_le16(offset);
+ eeprom_hdr->v1.len = cpu_to_le16(len);
+ } else {
+ eeprom_hdr->v2.offset = cpu_to_le32(offset);
+ eeprom_hdr->v2.len = cpu_to_le16(len);
+ eeprom_hdr->v2.magic2 = 0xf;
+ memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+ }
+
+ p54_tx(priv, skb);
+
+ if (!wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ)) {
+ printk(KERN_ERR "%s: device does not respond!\n",
+ wiphy_name(priv->hw->wiphy));
+ ret = -EBUSY;
+ }
+ priv->eeprom = NULL;
+ mutex_unlock(&priv->eeprom_mutex);
+ return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+ struct sk_buff *skb;
+ struct p54_tim *tim;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+ P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+ struct sk_buff *skb;
+ struct p54_sta_unlock *sta;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+ memcpy(sta->addr, addr, ETH_ALEN);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+ struct sk_buff *skb;
+ struct p54_txcancel *cancel;
+ u32 _req_id = le32_to_cpu(req_id);
+
+ if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+ return -EINVAL;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+ P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+ cancel->req_id = req_id;
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_setup_mac *setup;
+ u16 mode;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+ P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+ if (priv->hw->conf.radio_enabled) {
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ mode = P54_FILTER_TYPE_STATION;
+ break;
+ case NL80211_IFTYPE_AP:
+ mode = P54_FILTER_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ mode = P54_FILTER_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ mode = P54_FILTER_TYPE_PROMISCUOUS;
+ break;
+ default:
+ mode = P54_FILTER_TYPE_HIBERNATE;
+ break;
+ }
+
+ /*
+ * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+ * STSW45X0C LMAC API - page 12
+ */
+ if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
+ (priv->filter_flags & FIF_OTHER_BSS)) &&
+ (mode != P54_FILTER_TYPE_PROMISCUOUS))
+ mode |= P54_FILTER_TYPE_TRANSPARENT;
+ } else
+ mode = P54_FILTER_TYPE_HIBERNATE;
+
+ setup->mac_mode = cpu_to_le16(mode);
+ memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+ setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+ setup->rx_align = 0;
+ if (priv->fw_var < 0x500) {
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(setup->v1.rts_rates, 0, 8);
+ setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v1.unalloc0 = cpu_to_le16(0);
+ } else {
+ setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v2.truncate = cpu_to_le16(48896);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ setup->v2.sbss_offset = 0;
+ setup->v2.mcast_window = 0;
+ setup->v2.rx_rssi_threshold = 0;
+ setup->v2.rx_ed_threshold = 0;
+ setup->v2.ref_clock = cpu_to_le32(644245094);
+ setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+ setup->v2.osc_start_delay = cpu_to_le16(65535);
+ }
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ struct p54_scan_head *head;
+ struct p54_iq_autocal_entry *iq_autocal;
+ union p54_scan_body_union *body;
+ struct p54_scan_tail_rate *rate;
+ struct pda_rssi_cal_entry *rssi;
+ unsigned int i;
+ void *entry;
+ int band = priv->hw->conf.channel->band;
+ __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+ 2 + sizeof(*iq_autocal) + sizeof(*body) +
+ sizeof(*rate) + 2 * sizeof(*rssi),
+ P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+ memset(head->scan_params, 0, sizeof(head->scan_params));
+ head->mode = cpu_to_le16(mode);
+ head->dwell = cpu_to_le16(dwell);
+ head->freq = freq;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+ *pa_power_points = cpu_to_le16(0x0c);
+ }
+
+ iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(iq_autocal, &priv->iq_autocal[i].params,
+ sizeof(struct p54_iq_autocal_entry));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+ body = (void *) skb_put(skb, sizeof(body->longbow));
+ else
+ body = (void *) skb_put(skb, sizeof(body->normal));
+
+ for (i = 0; i < priv->output_limit->entries; i++) {
+ __le16 *entry_freq = (void *) (priv->output_limit->data +
+ priv->output_limit->entry_size * i);
+
+ if (*entry_freq != freq)
+ continue;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.power_limits,
+ (void *) entry_freq + sizeof(__le16),
+ priv->output_limit->entry_size);
+ } else {
+ struct pda_channel_output_limit *limits =
+ (void *) entry_freq;
+
+ body->normal.val_barker = 0x38;
+ body->normal.val_bpsk = body->normal.dup_bpsk =
+ limits->val_bpsk;
+ body->normal.val_qpsk = body->normal.dup_qpsk =
+ limits->val_qpsk;
+ body->normal.val_16qam = body->normal.dup_16qam =
+ limits->val_16qam;
+ body->normal.val_64qam = body->normal.dup_64qam =
+ limits->val_64qam;
+ }
+ break;
+ }
+ if (i == priv->output_limit->entries)
+ goto err;
+
+ entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+ for (i = 0; i < priv->curve_data->entries; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += priv->curve_data->entry_size;
+ continue;
+ }
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.curve_data,
+ (void *) entry + sizeof(__le16),
+ priv->curve_data->entry_size);
+ } else {
+ struct p54_scan_body *chan = &body->normal;
+ struct pda_pa_curve_data *curve_data =
+ (void *) priv->curve_data->data;
+
+ entry += sizeof(__le16);
+ chan->pa_points_per_curve = 8;
+ memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memcpy(chan->curve_data, entry,
+ sizeof(struct p54_pa_curve_data_sample) *
+ min((u8)8, curve_data->points_per_channel));
+ }
+ break;
+ }
+ if (i == priv->curve_data->entries)
+ goto err;
+
+ if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].add);
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ /* Longbow frontend needs ever more */
+ rssi = (void *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
+ }
+
+ if (priv->fw_var >= 0x509) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ hdr = (struct p54_hdr *) skb->data;
+ hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+ p54_tx(priv, skb);
+ return 0;
+
+err:
+ printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
+ wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
+ priv->hw->conf.channel->center_freq));
+
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_led *led;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+ P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ led = (struct p54_led *) skb_put(skb, sizeof(*led));
+ led->flags = cpu_to_le16(0x0003);
+ led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+ led->delay[0] = cpu_to_le16(1);
+ led->delay[1] = cpu_to_le16(0);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_edcf *edcf;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+ P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+ if (priv->use_short_slot) {
+ edcf->slottime = 9;
+ edcf->sifs = 0x10;
+ edcf->eofpad = 0x00;
+ } else {
+ edcf->slottime = 20;
+ edcf->sifs = 0x0a;
+ edcf->eofpad = 0x06;
+ }
+ /* (see prism54/isl_oid.h for further details) */
+ edcf->frameburst = cpu_to_le16(0);
+ edcf->round_trip_delay = cpu_to_le16(0);
+ edcf->flags = 0;
+ memset(edcf->mapping, 0, sizeof(edcf->mapping));
+ memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_psm *psm;
+ unsigned int i;
+ u16 mode;
+
+ if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+ !priv->powersave_override)
+ mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+ P54_PSM_CHECKSUM | P54_PSM_MCBC;
+ else
+ mode = P54_PSM_CAM;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+ P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+ psm->mode = cpu_to_le16(mode);
+ psm->aid = cpu_to_le16(priv->aid);
+ for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+ psm->intervals[i].interval =
+ cpu_to_le16(priv->hw->conf.listen_interval);
+ psm->intervals[i].periods = cpu_to_le16(1);
+ }
+
+ psm->beacon_rssi_skip_max = 200;
+ psm->rssi_delta_threshold = 0;
+ psm->nr = 1;
+ psm->exclude[0] = WLAN_EID_TIM;
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_xbow_synth *xbow;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+ xbow->magic1 = cpu_to_le16(0x1);
+ xbow->magic2 = cpu_to_le16(0x2);
+ xbow->freq = cpu_to_le16(5390);
+ memset(xbow->padding, 0, sizeof(xbow->padding));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+ u8 *addr, u8* key)
+{
+ struct sk_buff *skb;
+ struct p54_keycache *rxkey;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+ P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+ rxkey->entry = slot;
+ rxkey->key_id = idx;
+ rxkey->key_type = algo;
+ if (addr)
+ memcpy(rxkey->mac, addr, ETH_ALEN);
+ else
+ memset(rxkey->mac, ~0, ETH_ALEN);
+
+ switch (algo) {
+ case P54_CRYPTO_WEP:
+ case P54_CRYPTO_AESCCMP:
+ rxkey->key_len = min_t(u8, 16, len);
+ memcpy(rxkey->key, key, rxkey->key_len);
+ break;
+
+ case P54_CRYPTO_TKIPMICHAEL:
+ rxkey->key_len = 24;
+ memcpy(rxkey->key, key, 16);
+ memcpy(&(rxkey->key[16]), &(key
+ [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+ break;
+
+ case P54_CRYPTO_NONE:
+ rxkey->key_len = 0;
+ memset(rxkey->key, 0, sizeof(rxkey->key));
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
+ wiphy_name(priv->hw->wiphy), algo);
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct p54_tx_info *p54info;
+ struct sk_buff *skb;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+ sizeof(struct p54_statistics),
+ P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ /*
+ * The statistic feedback causes some extra headaches here, if it
+ * is not to crash/corrupt the firmware data structures.
+ *
+ * Unlike all other Control Get OIDs we can not use helpers like
+ * skb_put to reserve the space for the data we're requesting.
+ * Instead the extra frame length -which will hold the results later-
+ * will only be told to the p54_assign_address, so that following
+ * frames won't be placed into the allegedly empty area.
+ */
+ txinfo = IEEE80211_SKB_CB(skb);
+ p54info = (void *) txinfo->rate_driver_data;
+ p54info->extra_len = sizeof(struct p54_statistics);
+
+ p54_tx(priv, skb);
+ return 0;
+}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
new file mode 100644
index 000000000000..c00115b206d4
--- /dev/null
+++ b/drivers/net/wireless/p54/led.c
@@ -0,0 +1,163 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ led_work.work);
+ int err, i, tmp, blink_delay = 400;
+ bool rerun = false;
+
+ /* Don't toggle the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].toggled) {
+ priv->softled_state |= BIT(i);
+
+ tmp = 70 + 200 / (priv->leds[i].toggled);
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ if (priv->leds[i].led_dev.brightness == LED_OFF)
+ rerun = true;
+
+ priv->leds[i].toggled =
+ !!priv->leds[i].led_dev.brightness;
+ } else
+ priv->softled_state &= ~BIT(i);
+
+ err = p54_set_leds(priv);
+ if (err && net_ratelimit())
+ printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
+ wiphy_name(priv->hw->wiphy), err);
+
+ if (rerun)
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+ led_dev);
+ struct ieee80211_hw *dev = led->hw_dev;
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ if ((brightness) && (led->registered)) {
+ led->toggled++;
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ HZ/10);
+ }
+}
+
+static int p54_register_led(struct p54_common *priv,
+ unsigned int led_index,
+ char *name, char *trigger)
+{
+ struct p54_led_dev *led = &priv->leds[led_index];
+ int err;
+
+ if (led->registered)
+ return -EEXIST;
+
+ snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+ wiphy_name(priv->hw->wiphy), name);
+ led->hw_dev = priv->hw;
+ led->index = led_index;
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = trigger;
+ led->led_dev.brightness_set = p54_led_brightness_set;
+
+ err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
+ if (err)
+ printk(KERN_ERR "%s: Failed to register %s LED.\n",
+ wiphy_name(priv->hw->wiphy), name);
+ else
+ led->registered = 1;
+
+ return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+ int err;
+
+ /*
+ * TODO:
+ * Figure out if the EEPROM contains some hints about the number
+ * of available/programmable LEDs of the device.
+ */
+
+ INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+ err = p54_register_led(priv, 0, "assoc",
+ ieee80211_get_assoc_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 1, "tx",
+ ieee80211_get_tx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 2, "rx",
+ ieee80211_get_rx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 3, "radio",
+ ieee80211_get_radio_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_set_leds(priv);
+ return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+ if (priv->leds[i].registered) {
+ priv->leds[i].registered = false;
+ priv->leds[i].toggled = 0;
+ led_classdev_unregister(&priv->leds[i].led_dev);
+ }
+ }
+
+ cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
new file mode 100644
index 000000000000..04b63ec80fa4
--- /dev/null
+++ b/drivers/net/wireless/p54/lmac.h
@@ -0,0 +1,558 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+ P54_CONTROL_TYPE_SETUP = 0,
+ P54_CONTROL_TYPE_SCAN,
+ P54_CONTROL_TYPE_TRAP,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_RX_KEYCACHE,
+ P54_CONTROL_TYPE_TIM,
+ P54_CONTROL_TYPE_PSM,
+ P54_CONTROL_TYPE_TXCANCEL,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_BURST,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED,
+ P54_CONTROL_TYPE_GPIO,
+ P54_CONTROL_TYPE_TIMER,
+ P54_CONTROL_TYPE_MODULATION,
+ P54_CONTROL_TYPE_SYNTH_CONFIG,
+ P54_CONTROL_TYPE_DETECTOR_VALUE,
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+ P54_CONTROL_TYPE_CCE_QUIET,
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+ P54_CONTROL_TYPE_PCS,
+ P54_CONTROL_TYPE_BT_BALANCER = 28,
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+ P54_CONTROL_TYPE_ARPTABLE = 31,
+ P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
+struct p54_hdr {
+ __le16 flags;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum p54_control_frame_types */
+ u8 rts_tries;
+ u8 tries;
+ u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb) \
+ (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \
+
+#define FREE_AFTER_TX(skb) \
+ ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb) \
+ (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+#define GET_HW_QUEUE(skb) \
+ (((struct p54_tx_data *)((struct p54_hdr *) \
+ skb->data)->data)->hw_queue)
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */
+#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */
+#define IF_ID_PRODUCT 0x0009
+#define IF_ID_OEM 0x000a
+#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */
+
+struct exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __packed;
+
+struct dep_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+ union {
+ struct {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+ } __packed v1;
+ struct {
+ __le32 offset;
+ __le16 len;
+ u8 magic2;
+ u8 pad;
+ u8 magic[4];
+ u8 data[0];
+ } __packed v2;
+ } __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+ P54_DECRYPT_NONE = 0,
+ P54_DECRYPT_OK,
+ P54_DECRYPT_NOKEY,
+ P54_DECRYPT_NOMICHAEL,
+ P54_DECRYPT_NOCKIPMIC,
+ P54_DECRYPT_FAIL_WEP,
+ P54_DECRYPT_FAIL_TKIP,
+ P54_DECRYPT_FAIL_MICHAEL,
+ P54_DECRYPT_FAIL_CKIPKP,
+ P54_DECRYPT_FAIL_CKIPMIC,
+ P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+ __le16 flags;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u8 decrypt_status;
+ u8 rssi_raw;
+ __le32 tsf32;
+ __le32 unalloc0;
+ u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+ P54_TRAP_SCAN = 0,
+ P54_TRAP_TIMER,
+ P54_TRAP_BEACON_TX,
+ P54_TRAP_FAA_RADIO_ON,
+ P54_TRAP_FAA_RADIO_OFF,
+ P54_TRAP_RADAR,
+ P54_TRAP_NO_BEACON,
+ P54_TRAP_TBTT,
+ P54_TRAP_SCO_ENTER,
+ P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+ __le16 event;
+ __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+ P54_TX_OK = 0,
+ P54_TX_FAILED,
+ P54_TX_PSM,
+ P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+ u8 status;
+ u8 tries;
+ u8 ack_rssi;
+ u8 quality;
+ __le16 seq;
+ u8 antenna;
+ u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+ P54_CRYPTO_NONE = 0,
+ P54_CRYPTO_WEP,
+ P54_CRYPTO_TKIP,
+ P54_CRYPTO_TKIPMICHAEL,
+ P54_CRYPTO_CCX_WEPMIC,
+ P54_CRYPTO_CCX_KPMIC,
+ P54_CRYPTO_CCX_KP,
+ P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+ P54_QUEUE_BEACON = 0,
+ P54_QUEUE_FWSCAN = 1,
+ P54_QUEUE_MGMT = 2,
+ P54_QUEUE_CAB = 3,
+ P54_QUEUE_DATA = 4,
+
+ P54_QUEUE_AC_NUM = 4,
+ P54_QUEUE_AC_VO = 4,
+ P54_QUEUE_AC_VI = 5,
+ P54_QUEUE_AC_BE = 6,
+ P54_QUEUE_AC_BK = 7,
+
+ /* keep last */
+ P54_QUEUE_NUM = 8,
+};
+
+#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+ u8 rateset[8];
+ u8 rts_rate_idx;
+ u8 crypt_offset;
+ u8 key_type;
+ u8 key_len;
+ u8 key[16];
+ u8 hw_queue;
+ u8 backlog;
+ __le16 durations[4];
+ u8 tx_antenna;
+ union {
+ struct {
+ u8 cts_rate;
+ __le16 output_power;
+ } __packed longbow;
+ struct {
+ u8 output_power;
+ u8 cts_rate;
+ u8 unalloc;
+ } __packed normal;
+ } __packed;
+ u8 unalloc2[2];
+ u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE 0
+#define P54_FILTER_TYPE_STATION BIT(0)
+#define P54_FILTER_TYPE_IBSS BIT(1)
+#define P54_FILTER_TYPE_AP BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE BIT(5)
+#define P54_FILTER_TYPE_NOACK BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
+
+struct p54_setup_mac {
+ __le16 mac_mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 rx_antenna;
+ u8 rx_align;
+ union {
+ struct {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 wakeup_timer;
+ __le16 unalloc0;
+ } __packed v1;
+ struct {
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 timer;
+ __le16 truncate;
+ __le32 basic_rate_mask;
+ u8 sbss_offset;
+ u8 mcast_window;
+ u8 rx_rssi_threshold;
+ u8 rx_ed_threshold;
+ __le32 ref_clock;
+ __le16 lpf_bandwidth;
+ __le16 osc_start_delay;
+ } __packed v2;
+ } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT BIT(0)
+#define P54_SCAN_TRAP BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+ __le16 mode;
+ __le16 dwell;
+ u8 scan_params[20];
+ __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __packed;
+
+struct p54_scan_body {
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct p54_pa_curve_data_sample curve_data[8];
+ u8 dup_bpsk;
+ u8 dup_qpsk;
+ u8 dup_16qam;
+ u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+ __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+ __le16 rf_power;
+ __le16 pa_detector;
+ struct {
+ __le16 data[4];
+ } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+ struct p54_channel_output_limit_longbow power_limits;
+ struct p54_pa_curve_data_sample_longbow curve_data[8];
+ __le16 unkn[6]; /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+ struct p54_scan_body normal;
+ struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+ __le16 flags;
+ __le16 mask[2];
+ __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+ u8 flags;
+ u8 slottime;
+ u8 sifs;
+ u8 eofpad;
+ struct p54_edcf_queue_param queue[8];
+ u8 mapping[4];
+ __le16 frameburst;
+ __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+ __le32 rx_success;
+ __le32 rx_bad_fcs;
+ __le32 rx_abort;
+ __le32 rx_abort_phy;
+ __le32 rts_success;
+ __le32 rts_fail;
+ __le32 tsf32;
+ __le32 airtime;
+ __le32 noise;
+ __le32 sample_noise[8];
+ __le32 sample_cca;
+ __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+ __le16 magic1;
+ __le16 magic2;
+ __le16 freq;
+ u32 padding[5];
+} __packed;
+
+struct p54_timer {
+ __le32 interval;
+} __packed;
+
+struct p54_keycache {
+ u8 entry;
+ u8 key_id;
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[24];
+} __packed;
+
+struct p54_burst {
+ u8 flags;
+ u8 queue;
+ u8 backlog;
+ u8 pad;
+ __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+ __le16 interval;
+ __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM 0
+#define P54_PSM BIT(0)
+#define P54_PSM_DTIM BIT(1)
+#define P54_PSM_MCBC BIT(2)
+#define P54_PSM_CHECKSUM BIT(3)
+#define P54_PSM_SKIP_MORE_DATA BIT(4)
+#define P54_PSM_BEACON_TIMEOUT BIT(5)
+#define P54_PSM_HFOSLEEP BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
+#define P54_PSM_LPIT BIT(8)
+#define P54_PSM_BF_UCAST_SKIP BIT(9)
+#define P54_PSM_BF_MCAST_SKIP BIT(10)
+
+struct p54_psm {
+ __le16 mode;
+ __le16 aid;
+ struct p54_psm_interval intervals[4];
+ u8 beacon_rssi_skip_max;
+ u8 rssi_delta_threshold;
+ u8 nr;
+ u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+ __le16 filter_enable;
+ __le16 num_address;
+ u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+ __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+ u8 count;
+ u8 padding[3];
+ __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+ __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+ __le16 prio_thresh;
+ __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+ __le16 filter_enable;
+ u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+ u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len);
+
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
new file mode 100644
index 000000000000..955f6d7ec16a
--- /dev/null
+++ b/drivers/net/wireless/p54/main.c
@@ -0,0 +1,637 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ struct ieee80211_sta *sta)
+{
+ struct p54_common *priv = dev->priv;
+ switch (notify_cmd) {
+ case STA_NOTIFY_ADD:
+ case STA_NOTIFY_REMOVE:
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ case STA_NOTIFY_AWAKE:
+ /* update the firmware's filter table */
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct p54_common *priv = dev->priv;
+
+ return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
+
+ if (skb->len <= sizeof(mgmt))
+ return NULL;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
+ u8 *tim;
+ u8 dtim_len;
+ u8 dtim_period;
+ u8 *next;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return 0;
+
+ dtim_len = tim[1];
+ dtim_period = tim[3];
+ next = tim + 2 + dtim_len;
+
+ if (dtim_len < 3)
+ return -EINVAL;
+
+ memmove(tim, next, skb_tail_pointer(skb) - next);
+ tim = skb_tail_pointer(skb) - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ tim[0] = WLAN_EID_TIM;
+ tim[1] = 3;
+ tim[2] = 0;
+ tim[3] = dtim_period;
+ tim[4] = 0;
+
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+
+ return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *beacon;
+ int ret;
+
+ beacon = ieee80211_beacon_get(priv->hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ ret = p54_beacon_format_ie_tim(beacon);
+ if (ret)
+ return ret;
+
+ /*
+ * During operation, the firmware takes care of beaconing.
+ * The driver only needs to upload a new beacon template, once
+ * the template was changed by the stack or userspace.
+ *
+ * LMAC API 3.2.2 also specifies that the driver does not need
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+ WARN_ON(p54_tx_80211(priv->hw, beacon));
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+ return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ mutex_lock(&priv->conf_mutex);
+ err = priv->open(dev);
+ if (err)
+ goto out;
+ P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+ err = p54_set_edcf(priv);
+ if (err)
+ goto out;
+
+ memset(priv->bssid, ~0, ETH_ALEN);
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ err = p54_setup_mac(priv);
+ if (err) {
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ goto out;
+ }
+
+ queue_delayed_work(dev->workqueue, &priv->work, 0);
+
+ priv->softled_state = 0;
+ err = p54_set_leds(priv);
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->softled_state = 0;
+ p54_set_leds(priv);
+
+ cancel_delayed_work_sync(&priv->work);
+
+ priv->stop(dev);
+ skb_queue_purge(&priv->tx_pending);
+ skb_queue_purge(&priv->tx_queue);
+ for (i = 0; i < P54_QUEUE_NUM; i++) {
+ priv->tx_stats[i].count = 0;
+ priv->tx_stats[i].len = 0;
+ }
+
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tsf_high32 = priv->tsf_low32 = 0;
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (priv->mode != NL80211_IFTYPE_MONITOR) {
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ priv->vif = conf->vif;
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ priv->mode = conf->type;
+ break;
+ default:
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->vif = NULL;
+
+ /*
+ * LMAC API 3.2.2 states that any active beacon template must be
+ * canceled by the driver before attempting a mode transition.
+ */
+ if (le32_to_cpu(priv->beacon_req_id) != 0) {
+ p54_tx_cancel(priv, priv->beacon_req_id);
+ wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
+ }
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ memset(priv->bssid, 0, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+ int ret = 0;
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ priv->output_power = conf->power_level << 2;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ret = p54_set_ps(priv);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS;
+
+ priv->filter_flags = *total_flags;
+
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ p54_setup_mac(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ int ret;
+
+ mutex_lock(&priv->conf_mutex);
+ if ((params) && !(queue > 4)) {
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
+ } else
+ ret = -EINVAL;
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ work.work);
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ /*
+ * TODO: walk through tx_queue and do the following tasks
+ * 1. initiate bursts.
+ * 2. cancel stuck frames / reset the device if necessary.
+ */
+
+ p54_fetch_statistics(priv);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
+ sizeof(stats[0]) * dev->queues);
+ return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & BSS_CHANGED_BSSID) {
+ memcpy(priv->bssid, info->bssid, ETH_ALEN);
+ p54_setup_mac(priv);
+ }
+
+ if (changed & BSS_CHANGED_BEACON) {
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ p54_setup_mac(priv);
+ p54_beacon_update(priv, vif);
+ p54_set_edcf(priv);
+ }
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+ priv->use_short_slot = info->use_short_slot;
+ p54_set_edcf(priv);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(priv);
+ if (priv->fw_var >= 0x500)
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(priv);
+ } else {
+ priv->wakeup_timer = 500;
+ priv->aid = 0;
+ }
+ }
+
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct p54_common *priv = dev->priv;
+ int slot, ret = 0;
+ u8 algo = 0;
+ u8 *addr = NULL;
+
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->conf_mutex);
+ if (cmd == SET_KEY) {
+ switch (key->alg) {
+ case ALG_TKIP:
+ if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+ BR_DESC_PRIV_CAP_TKIP))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_TKIPMICHAEL;
+ break;
+ case ALG_WEP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_WEP;
+ break;
+ case ALG_CCMP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_AESCCMP;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ slot = bitmap_find_free_region(priv->used_rxkeys,
+ priv->rx_keycache_size, 0);
+
+ if (slot < 0) {
+ /*
+ * The device supports the choosen algorithm, but the
+ * firmware does not provide enough key slots to store
+ * all of them.
+ * But encryption offload for outgoing frames is always
+ * possible, so we just pretend that the upload was
+ * successful and do the decryption in software.
+ */
+
+ /* mark the key as invalid. */
+ key->hw_key_idx = 0xff;
+ goto out_unlock;
+ }
+ } else {
+ slot = key->hw_key_idx;
+
+ if (slot == 0xff) {
+ /* This key was not uploaded into the rx key cache. */
+
+ goto out_unlock;
+ }
+
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ algo = 0;
+ }
+
+ if (sta)
+ addr = sta->addr;
+
+ ret = p54_upload_key(priv, algo, slot, key->keyidx,
+ key->keylen, addr, key->key);
+ if (ret) {
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ key->hw_key_idx = slot;
+
+out_unlock:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx_80211,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .set_tim = p54_set_tim,
+ .sta_notify = p54_sta_notify,
+ .set_key = p54_set_key,
+ .config = p54_config,
+ .bss_info_changed = p54_bss_info_changed,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->hw = dev;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
+ spin_lock_init(&priv->tx_stats_lock);
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx_pending);
+ dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_NOISE_DBM;
+
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+ priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+ priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+ priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+ priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+ dev->queues = 1;
+ priv->noise = -94;
+ /*
+ * We support at most 8 tries no matter which rate they're at,
+ * we cannot support max_rates * max_rate_tries as we set it
+ * here, but setting it correctly to 4/2 or so would limit us
+ * artificially if the RC algorithm wants just two rates, so
+ * let's say 4/7, we'll redistribute it at TX time, see the
+ * comments there.
+ */
+ dev->max_rates = 4;
+ dev->max_rate_tries = 7;
+ dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+ sizeof(struct p54_tx_data);
+
+ mutex_init(&priv->conf_mutex);
+ mutex_init(&priv->eeprom_mutex);
+ init_completion(&priv->eeprom_comp);
+ init_completion(&priv->beacon_comp);
+ INIT_DELAYED_WORK(&priv->work, p54_work);
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ dev_err(pdev, "Cannot register device (%d).\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_P54_LEDS
+ err = p54_init_leds(priv);
+ if (err)
+ return err;
+#endif /* CONFIG_P54_LEDS */
+
+ dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(priv->band_table[i]);
+
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->used_rxkeys);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+ priv->used_rxkeys = NULL;
+ ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+ p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+ ieee80211_unregister_hw(dev);
+ mutex_destroy(&priv->conf_mutex);
+ mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index db3df947d8ed..1afc39410e85 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -1,6 +1,3 @@
-#ifndef P54_H
-#define P54_H
-
/*
* Shared defines for all mac80211 Prism54 code
*
@@ -14,39 +11,78 @@
* published by the Free Software Foundation.
*/
+#ifndef P54_H
+#define P54_H
+
#ifdef CONFIG_P54_LEDS
#include <linux/leds.h>
#endif /* CONFIG_P54_LEDS */
-enum p54_control_frame_types {
- P54_CONTROL_TYPE_SETUP = 0,
- P54_CONTROL_TYPE_SCAN,
- P54_CONTROL_TYPE_TRAP,
- P54_CONTROL_TYPE_DCFINIT,
- P54_CONTROL_TYPE_RX_KEYCACHE,
- P54_CONTROL_TYPE_TIM,
- P54_CONTROL_TYPE_PSM,
- P54_CONTROL_TYPE_TXCANCEL,
- P54_CONTROL_TYPE_TXDONE,
- P54_CONTROL_TYPE_BURST,
- P54_CONTROL_TYPE_STAT_READBACK,
- P54_CONTROL_TYPE_BBP,
- P54_CONTROL_TYPE_EEPROM_READBACK,
- P54_CONTROL_TYPE_LED,
- P54_CONTROL_TYPE_GPIO,
- P54_CONTROL_TYPE_TIMER,
- P54_CONTROL_TYPE_MODULATION,
- P54_CONTROL_TYPE_SYNTH_CONFIG,
- P54_CONTROL_TYPE_DETECTOR_VALUE,
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
- P54_CONTROL_TYPE_CCE_QUIET,
- P54_CONTROL_TYPE_PSM_STA_UNLOCK,
- P54_CONTROL_TYPE_PCS,
- P54_CONTROL_TYPE_BT_BALANCER = 28,
- P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
- P54_CONTROL_TYPE_ARPTABLE = 31,
- P54_CONTROL_TYPE_BT_OPTIONS = 35
-};
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER 0x0000
+#define BR_INTERFACE_ROLE_CLIENT 0x8000
+
+#define BR_DESC_PRIV_CAP_WEP BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
+
+struct bootrec_desc {
+ __le16 modes;
+ __le16 flags;
+ __le32 rx_start;
+ __le32 rx_end;
+ u8 headroom;
+ u8 tailroom;
+ u8 tx_queues;
+ u8 tx_depth;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
+ u8 time_size;
+ u8 padding;
+ u8 rates[16];
+ u8 padding2[4];
+ __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+ __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+ char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+ __le16 crc;
+ u8 padding[2];
+ u8 md5[16];
+} __packed;
/* provide 16 bytes for the transport back-end */
#define P54_TX_INFO_DATA_SIZE 16
@@ -55,34 +91,30 @@ enum p54_control_frame_types {
struct p54_tx_info {
u32 start_addr;
u32 end_addr;
- void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ union {
+ void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ struct {
+ u32 extra_len;
+ };
+ };
};
#define P54_MAX_CTRL_FRAME_LEN 0x1000
-#define P54_HDR_FLAG_CONTROL BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
-
-struct p54_hdr {
- __le16 flags;
- __le16 len;
- __le32 req_id;
- __le16 type; /* enum p54_control_frame_types */
- u8 rts_tries;
- u8 tries;
- u8 data[0];
-} __attribute__ ((packed));
-
-#define FREE_AFTER_TX(skb) \
- ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
- flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = cpu_to_le16(_txop); \
+} while (0)
struct p54_edcf_queue_param {
__le16 aifs;
__le16 cwmin;
__le16 cwmax;
__le16 txop;
-} __attribute__ ((packed));
+} __packed;
struct p54_rssi_linear_approximation {
s16 mul;
@@ -101,13 +133,6 @@ struct p54_cal_database {
#define EEPROM_READBACK_LEN 0x3fc
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
enum fw_state {
FW_STATE_OFF,
FW_STATE_BOOTING,
@@ -138,6 +163,7 @@ struct p54_common {
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
+ struct sk_buff_head tx_pending;
struct sk_buff_head tx_queue;
struct mutex conf_mutex;
@@ -156,6 +182,7 @@ struct p54_common {
/* (e)DCF / QOS state */
bool use_short_slot;
+ spinlock_t tx_stats_lock;
struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
@@ -171,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+ struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
@@ -181,7 +209,9 @@ struct p54_common {
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
u16 aid;
- struct sk_buff *cached_beacon;
+ bool powersave_override;
+ __le32 beacon_req_id;
+ struct completion beacon_comp;
/* cryptographic engine information */
u8 privacy_caps;
@@ -202,15 +232,20 @@ struct p54_common {
/* eeprom handling */
void *eeprom;
struct completion eeprom_comp;
+ struct mutex eeprom_mutex;
};
+/* interfaces for the drivers */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
int p54_read_eeprom(struct ieee80211_hw *dev);
+
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
void p54_free_common(struct ieee80211_hw *dev);
+void p54_unregister_common(struct ieee80211_hw *dev);
+
#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
deleted file mode 100644
index 22ca122bd798..000000000000
--- a/drivers/net/wireless/p54/p54common.c
+++ /dev/null
@@ -1,2688 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "p54common.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static struct ieee80211_rate p54_bgrates[] = {
- { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_bgchannels[] = {
- { .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, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
- .channels = p54_bgchannels,
- .n_channels = ARRAY_SIZE(p54_bgchannels),
- .bitrates = p54_bgrates,
- .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
-static struct ieee80211_rate p54_arates[] = {
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_achannels[] = {
- { .center_freq = 4920 },
- { .center_freq = 4940 },
- { .center_freq = 4960 },
- { .center_freq = 4980 },
- { .center_freq = 5040 },
- { .center_freq = 5060 },
- { .center_freq = 5080 },
- { .center_freq = 5170 },
- { .center_freq = 5180 },
- { .center_freq = 5190 },
- { .center_freq = 5200 },
- { .center_freq = 5210 },
- { .center_freq = 5220 },
- { .center_freq = 5230 },
- { .center_freq = 5240 },
- { .center_freq = 5260 },
- { .center_freq = 5280 },
- { .center_freq = 5300 },
- { .center_freq = 5320 },
- { .center_freq = 5500 },
- { .center_freq = 5520 },
- { .center_freq = 5540 },
- { .center_freq = 5560 },
- { .center_freq = 5580 },
- { .center_freq = 5600 },
- { .center_freq = 5620 },
- { .center_freq = 5640 },
- { .center_freq = 5660 },
- { .center_freq = 5680 },
- { .center_freq = 5700 },
- { .center_freq = 5745 },
- { .center_freq = 5765 },
- { .center_freq = 5785 },
- { .center_freq = 5805 },
- { .center_freq = 5825 },
-};
-
-static struct ieee80211_supported_band band_5GHz = {
- .channels = p54_achannels,
- .n_channels = ARRAY_SIZE(p54_achannels),
- .bitrates = p54_arates,
- .n_bitrates = ARRAY_SIZE(p54_arates),
-};
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
- struct p54_common *priv = dev->priv;
- struct bootrec_exp_if *exp_if;
- struct bootrec *bootrec;
- u32 *data = (u32 *)fw->data;
- u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
- u8 *fw_version = NULL;
- size_t len;
- int i;
- int maxlen;
-
- if (priv->rx_start)
- return 0;
-
- while (data < end_data && *data)
- data++;
-
- while (data < end_data && !*data)
- data++;
-
- bootrec = (struct bootrec *) data;
-
- while (bootrec->data <= end_data &&
- (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
- u32 code = le32_to_cpu(bootrec->code);
- switch (code) {
- case BR_CODE_COMPONENT_ID:
- priv->fw_interface = be32_to_cpup((__be32 *)
- bootrec->data);
- switch (priv->fw_interface) {
- case FW_LM86:
- case FW_LM20:
- case FW_LM87: {
- char *iftype = (char *)bootrec->data;
- printk(KERN_INFO "%s: p54 detected a LM%c%c "
- "firmware\n",
- wiphy_name(dev->wiphy),
- iftype[2], iftype[3]);
- break;
- }
- case FW_FMAC:
- default:
- printk(KERN_ERR "%s: unsupported firmware\n",
- wiphy_name(dev->wiphy));
- return -ENODEV;
- }
- break;
- case BR_CODE_COMPONENT_VERSION:
- /* 24 bytes should be enough for all firmwares */
- if (strnlen((unsigned char*)bootrec->data, 24) < 24)
- fw_version = (unsigned char*)bootrec->data;
- break;
- case BR_CODE_DESCR: {
- struct bootrec_desc *desc =
- (struct bootrec_desc *)bootrec->data;
- priv->rx_start = le32_to_cpu(desc->rx_start);
- /* FIXME add sanity checking */
- priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
- priv->headroom = desc->headroom;
- priv->tailroom = desc->tailroom;
- priv->privacy_caps = desc->privacy_caps;
- priv->rx_keycache_size = desc->rx_keycache_size;
- if (le32_to_cpu(bootrec->len) == 11)
- priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
- else
- priv->rx_mtu = (size_t)
- 0x620 - priv->tx_hdr_len;
- maxlen = priv->tx_hdr_len + /* USB devices */
- sizeof(struct p54_rx_data) +
- 4 + /* rx alignment */
- IEEE80211_MAX_FRAG_THRESHOLD;
- if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
- printk(KERN_INFO "p54: rx_mtu reduced from %d "
- "to %d\n", priv->rx_mtu,
- maxlen);
- priv->rx_mtu = maxlen;
- }
- break;
- }
- case BR_CODE_EXPOSED_IF:
- exp_if = (struct bootrec_exp_if *) bootrec->data;
- for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
- if (exp_if[i].if_id == cpu_to_le16(0x1a))
- priv->fw_var = le16_to_cpu(exp_if[i].variant);
- break;
- case BR_CODE_DEPENDENT_IF:
- break;
- case BR_CODE_END_OF_BRA:
- case LEGACY_BR_CODE_END_OF_BRA:
- end_data = NULL;
- break;
- default:
- break;
- }
- bootrec = (struct bootrec *)&bootrec->data[len];
- }
-
- if (fw_version)
- printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
- wiphy_name(dev->wiphy), fw_version,
- priv->fw_var >> 8, priv->fw_var & 0xff);
-
- if (priv->fw_var < 0x500)
- printk(KERN_INFO "%s: you are using an obsolete firmware. "
- "visit http://wireless.kernel.org/en/users/Drivers/p54 "
- "and grab one for \"kernel >= 2.6.28\"!\n",
- wiphy_name(dev->wiphy));
-
- if (priv->fw_var >= 0x300) {
- /* Firmware supports QoS, use it! */
- priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
- priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
- dev->queues = P54_QUEUE_AC_NUM;
- }
-
- if (!modparam_nohwcrypt) {
- printk(KERN_INFO "%s: cryptographic accelerator "
- "WEP:%s, TKIP:%s, CCMP:%s\n",
- wiphy_name(dev->wiphy),
- (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
- "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
- BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
- (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
- "YES" : "no");
-
- if (priv->rx_keycache_size) {
- /*
- * NOTE:
- *
- * The firmware provides at most 255 (0 - 254) slots
- * for keys which are then used to offload decryption.
- * As a result the 255 entry (aka 0xff) can be used
- * safely by the driver to mark keys that didn't fit
- * into the full cache. This trick saves us from
- * keeping a extra list for uploaded keys.
- */
-
- priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
- priv->rx_keycache_size), GFP_KERNEL);
-
- if (!priv->used_rxkeys)
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev0 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- dst = target;
- src = source;
-
- dst->rf_power = src->rf_power;
- dst->pa_detector = src->pa_detector;
- dst->data_64qam = src->pcv;
- /* "invent" the points for the other modulations */
-#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
- dst->data_16qam = SUB(src->pcv, 12);
- dst->data_qpsk = SUB(dst->data_16qam, 12);
- dst->data_bpsk = SUB(dst->data_qpsk, 12);
- dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- }
-
- return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev1 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- memcpy(target, source, sizeof(*src));
-
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- source++;
- }
-
- return 0;
-}
-
-static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
- "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
-static int p54_init_xbow_synth(struct ieee80211_hw *dev);
-
-static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
- u16 type)
-{
- struct p54_common *priv = dev->priv;
- int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
- int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
- int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
- int i;
-
- if (len != (entry_size * num_entries)) {
- printk(KERN_ERR "%s: unknown rssi calibration data packing "
- " type:(%x) len:%d.\n",
- wiphy_name(dev->wiphy), type, len);
-
- print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- for (i = 0; i < num_entries; i++) {
- struct pda_rssi_cal_entry *cal = data +
- (offset + i * entry_size);
- priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
- priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
- }
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
- void *data, int len)
-{
- struct pda_country *country;
-
- if (len != sizeof(*country)) {
- printk(KERN_ERR "%s: found possible invalid default country "
- "eeprom entry. (entry size: %d)\n",
- wiphy_name(dev->wiphy), len);
-
- print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- country = (struct pda_country *) data;
- if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
- regulatory_hint(dev->wiphy, country->alpha2);
- else {
- /* TODO:
- * write a shared/common function that converts
- * "Regulatory domain codes" (802.11-2007 14.8.2.2)
- * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
- */
- }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
- u8 *data, size_t len)
-{
- struct p54_common *priv = dev->priv;
-
- if (len < 2)
- return -EINVAL;
-
- if (data[0] != 0) {
- printk(KERN_ERR "%s: unknown output power db revision:%x\n",
- wiphy_name(dev->wiphy), data[0]);
- return -EINVAL;
- }
-
- if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
- return -EINVAL;
-
- priv->output_limit = kmalloc(data[1] *
- sizeof(struct pda_channel_output_limit) +
- sizeof(*priv->output_limit), GFP_KERNEL);
-
- if (!priv->output_limit)
- return -ENOMEM;
-
- priv->output_limit->offset = 0;
- priv->output_limit->entries = data[1];
- priv->output_limit->entry_size =
- sizeof(struct pda_channel_output_limit);
- priv->output_limit->len = priv->output_limit->entry_size *
- priv->output_limit->entries +
- priv->output_limit->offset;
-
- memcpy(priv->output_limit->data, &data[2],
- data[1] * sizeof(struct pda_channel_output_limit));
-
- return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
- size_t total_len)
-{
- struct p54_cal_database *dst;
- size_t payload_len, entries, entry_size, offset;
-
- payload_len = le16_to_cpu(src->len);
- entries = le16_to_cpu(src->entries);
- entry_size = le16_to_cpu(src->entry_size);
- offset = le16_to_cpu(src->offset);
- if (((entries * entry_size + offset) != payload_len) ||
- (payload_len + sizeof(*src) != total_len))
- return NULL;
-
- dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
- if (!dst)
- return NULL;
-
- dst->entries = entries;
- dst->entry_size = entry_size;
- dst->offset = offset;
- dst->len = payload_len;
-
- memcpy(dst->data, src->data, payload_len);
- return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
- struct p54_common *priv = dev->priv;
- struct eeprom_pda_wrap *wrap = NULL;
- struct pda_entry *entry;
- unsigned int data_len, entry_len;
- void *tmp;
- int err;
- u8 *end = (u8 *)eeprom + len;
- u16 synth = 0;
-
- wrap = (struct eeprom_pda_wrap *) eeprom;
- entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
- /* verify that at least the entry length/code fits */
- while ((u8 *)entry <= end - sizeof(*entry)) {
- entry_len = le16_to_cpu(entry->len);
- data_len = ((entry_len - 1) << 1);
-
- /* abort if entry exceeds whole structure */
- if ((u8 *)entry + sizeof(*entry) + data_len > end)
- break;
-
- switch (le16_to_cpu(entry->code)) {
- case PDR_MAC_ADDRESS:
- if (data_len != ETH_ALEN)
- break;
- SET_IEEE80211_PERM_ADDR(dev, entry->data);
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
- if (priv->output_limit)
- break;
- err = p54_convert_output_limits(dev, entry->data,
- data_len);
- if (err)
- goto err;
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA: {
- struct pda_pa_curve_data *curve_data =
- (struct pda_pa_curve_data *)entry->data;
- if (data_len < sizeof(*curve_data)) {
- err = -EINVAL;
- goto err;
- }
-
- switch (curve_data->cal_method_rev) {
- case 0:
- err = p54_convert_rev0(dev, curve_data);
- break;
- case 1:
- err = p54_convert_rev1(dev, curve_data);
- break;
- default:
- printk(KERN_ERR "%s: unknown curve data "
- "revision %d\n",
- wiphy_name(dev->wiphy),
- curve_data->cal_method_rev);
- err = -ENODEV;
- break;
- }
- if (err)
- goto err;
- }
- break;
- case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
- if (!priv->iq_autocal) {
- err = -ENOMEM;
- goto err;
- }
-
- memcpy(priv->iq_autocal, entry->data, data_len);
- priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
- break;
- case PDR_DEFAULT_COUNTRY:
- p54_parse_default_country(dev, entry->data, data_len);
- break;
- case PDR_INTERFACE_LIST:
- tmp = entry->data;
- while ((u8 *)tmp < entry->data + data_len) {
- struct bootrec_exp_if *exp_if = tmp;
- if (le16_to_cpu(exp_if->if_id) == 0xf)
- synth = le16_to_cpu(exp_if->variant);
- tmp += sizeof(struct bootrec_exp_if);
- }
- break;
- case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
- if (data_len < 2)
- break;
- priv->version = *(u8 *)(entry->data + 1);
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION:
- case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
- case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
- p54_parse_rssical(dev, entry->data, data_len,
- le16_to_cpu(entry->code));
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
- __le16 *src = (void *) entry->data;
- s16 *dst = (void *) &priv->rssical_db;
- int i;
-
- if (data_len != sizeof(priv->rssical_db)) {
- err = -EINVAL;
- goto err;
- }
- for (i = 0; i < sizeof(priv->rssical_db) /
- sizeof(*src); i++)
- *(dst++) = (s16) le16_to_cpu(*(src++));
- }
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->output_limit || data_len < sizeof(*pda))
- break;
- priv->output_limit = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->curve_data || data_len < sizeof(*pda))
- break;
- priv->curve_data = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_END:
- /* make it overrun */
- entry_len = len;
- break;
- case PDR_MANUFACTURING_PART_NUMBER:
- case PDR_PDA_VERSION:
- case PDR_NIC_SERIAL_NUMBER:
- case PDR_REGULATORY_DOMAIN_LIST:
- case PDR_TEMPERATURE_TYPE:
- case PDR_PRISM_PCI_IDENTIFIER:
- case PDR_COUNTRY_INFORMATION:
- case PDR_OEM_NAME:
- case PDR_PRODUCT_NAME:
- case PDR_UTF8_OEM_NAME:
- case PDR_UTF8_PRODUCT_NAME:
- case PDR_COUNTRY_LIST:
- case PDR_ANTENNA_GAIN:
- case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
- case PDR_REGULATORY_POWER_LIMITS:
- case PDR_RADIATED_TRANSMISSION_CORRECTION:
- case PDR_PRISM_TX_IQ_CALIBRATION:
- case PDR_BASEBAND_REGISTERS:
- case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
- break;
- default:
- printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
- wiphy_name(dev->wiphy),
- le16_to_cpu(entry->code));
- break;
- }
-
- entry = (void *)entry + (entry_len + 1)*2;
- }
-
- if (!synth || !priv->iq_autocal || !priv->output_limit ||
- !priv->curve_data) {
- printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
- wiphy_name(dev->wiphy));
- err = -EINVAL;
- goto err;
- }
-
- priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
- p54_init_xbow_synth(dev);
- if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
- if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
- if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
- priv->rx_diversity_mask = 3;
- if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
- priv->tx_diversity_mask = 3;
-
- if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
- u8 perm_addr[ETH_ALEN];
-
- printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
- wiphy_name(dev->wiphy));
- random_ether_addr(perm_addr);
- SET_IEEE80211_PERM_ADDR(dev, perm_addr);
- }
-
- printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
- wiphy_name(dev->wiphy),
- dev->wiphy->perm_addr,
- priv->version, p54_rf_chips[priv->rxhw]);
-
- return 0;
-
- err:
- if (priv->iq_autocal) {
- kfree(priv->iq_autocal);
- priv->iq_autocal = NULL;
- }
-
- if (priv->output_limit) {
- kfree(priv->output_limit);
- priv->output_limit = NULL;
- }
-
- if (priv->curve_data) {
- kfree(priv->curve_data);
- priv->curve_data = NULL;
- }
-
- printk(KERN_ERR "%s: eeprom parse failed!\n",
- wiphy_name(dev->wiphy));
- return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
-{
- struct p54_common *priv = dev->priv;
- int band = dev->conf.channel->band;
-
- if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
- else
- /*
- * TODO: find the correct formula
- */
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
-}
-
-static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
- struct ieee80211_rx_status rx_status = {0};
- u16 freq = le16_to_cpu(hdr->freq);
- size_t header_len = sizeof(*hdr);
- u32 tsf32;
- u8 rate = hdr->rate & 0xf;
-
- /*
- * If the device is in a unspecified state we have to
- * ignore all data frames. Else we could end up with a
- * nasty crash.
- */
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return 0;
-
- if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
- return 0;
- }
-
- if (hdr->decrypt_status == P54_DECRYPT_OK)
- rx_status.flag |= RX_FLAG_DECRYPTED;
- if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
- (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
- rx_status.flag |= RX_FLAG_MMIC_ERROR;
-
- rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
- rx_status.noise = priv->noise;
- if (hdr->rate & 0x10)
- rx_status.flag |= RX_FLAG_SHORTPRE;
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
- else
- rx_status.rate_idx = rate;
-
- rx_status.freq = freq;
- rx_status.band = dev->conf.channel->band;
- rx_status.antenna = hdr->antenna;
-
- tsf32 = le32_to_cpu(hdr->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
- priv->tsf_low32 = tsf32;
-
- rx_status.flag |= RX_FLAG_TSFT;
-
- if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- header_len += hdr->align[0];
-
- skb_pull(skb, header_len);
- skb_trim(skb, le16_to_cpu(hdr->len));
-
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
- return -1;
-}
-
-static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < dev->queues; i++)
- if (priv->tx_stats[i + P54_QUEUE_DATA].len <
- priv->tx_stats[i + P54_QUEUE_DATA].limit)
- ieee80211_wake_queue(dev, i);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- unsigned long flags;
-
- if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
- return;
-
- /*
- * don't try to free an already unlinked skb
- */
- if (unlikely((!skb->next) || (!skb->prev)))
- return;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->prev);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- if (skb->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- __skb_unlink(skb, &priv->tx_queue);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- dev_kfree_skb_any(skb);
- p54_wake_free_queues(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
- __le32 req_id)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
-
- if (hdr->req_id == req_id) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return NULL;
-}
-
-static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
- struct sk_buff *entry;
- u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
- struct p54_tx_info *range = NULL;
- unsigned long flags;
- int count, idx;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = (struct sk_buff *) priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- struct p54_hdr *entry_hdr;
- struct p54_tx_data *entry_data;
- unsigned int pad = 0, frame_len;
-
- range = (void *)info->rate_driver_data;
- if (range->start_addr != addr) {
- entry = entry->next;
- continue;
- }
-
- if (entry->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(entry->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
-
- __skb_unlink(entry, &priv->tx_queue);
-
- frame_len = entry->len;
- entry_hdr = (struct p54_hdr *) entry->data;
- entry_data = (struct p54_tx_data *) entry_hdr->data;
- if (priv->tx_stats[entry_data->hw_queue].len)
- priv->tx_stats[entry_data->hw_queue].len--;
- priv->stats.dot11ACKFailureCount += payload->tries - 1;
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- /*
- * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
- * generated by the driver. Therefore tx_status is bogus
- * and we don't want to confuse the mac80211 stack.
- */
- if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
- if (entry_data->hw_queue == P54_QUEUE_BEACON)
- priv->cached_beacon = NULL;
-
- kfree_skb(entry);
- goto out;
- }
-
- /*
- * Clear manually, ieee80211_tx_info_clear_status would
- * clear the counts too and we need them.
- */
- memset(&info->status.ampdu_ack_len, 0,
- sizeof(struct ieee80211_tx_info) -
- offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
- BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
- status.ampdu_ack_len) != 23);
-
- if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- pad = entry_data->align[0];
-
- /* walk through the rates array and adjust the counts */
- count = payload->tries;
- for (idx = 0; idx < 4; idx++) {
- if (count >= info->status.rates[idx].count) {
- count -= info->status.rates[idx].count;
- } else if (count > 0) {
- info->status.rates[idx].count = count;
- count = 0;
- } else {
- info->status.rates[idx].idx = -1;
- info->status.rates[idx].count = 0;
- }
- }
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (!payload->status))
- info->flags |= IEEE80211_TX_STAT_ACK;
- if (payload->status & P54_TX_PSM_CANCELLED)
- info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- info->status.ack_signal = p54_rssi_to_dbm(dev,
- (int)payload->ack_rssi);
-
- /* Undo all changes to the frame. */
- switch (entry_data->key_type) {
- case P54_CRYPTO_TKIPMICHAEL: {
- u8 *iv = (u8 *)(entry_data->align + pad +
- entry_data->crypt_offset);
-
- /* Restore the original TKIP IV. */
- iv[2] = iv[0];
- iv[0] = iv[1];
- iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
-
- frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
- break;
- }
- case P54_CRYPTO_AESCCMP:
- frame_len -= 8; /* remove CCMP_MIC */
- break;
- case P54_CRYPTO_WEP:
- frame_len -= 4; /* remove WEP_ICV */
- break;
- }
- skb_trim(entry, frame_len);
- skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry);
- goto out;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-out:
- p54_wake_free_queues(dev);
-}
-
-static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
- struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
- struct p54_common *priv = dev->priv;
-
- if (!priv->eeprom)
- return ;
-
- if (priv->fw_var >= 0x509) {
- memcpy(priv->eeprom, eeprom->v2.data,
- le16_to_cpu(eeprom->v2.len));
- } else {
- memcpy(priv->eeprom, eeprom->v1.data,
- le16_to_cpu(eeprom->v1.len));
- }
-
- complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
- u32 tsf32;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- tsf32 = le32_to_cpu(stats->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- priv->tsf_low32 = tsf32;
-
- priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
- priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
- priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
- priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-
- p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
-}
-
-static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_trap *trap = (struct p54_trap *) hdr->data;
- u16 event = le16_to_cpu(trap->event);
- u16 freq = le16_to_cpu(trap->frequency);
-
- switch (event) {
- case P54_TRAP_BEACON_TX:
- break;
- case P54_TRAP_RADAR:
- printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
- wiphy_name(dev->wiphy), freq);
- break;
- case P54_TRAP_NO_BEACON:
- if (priv->vif)
- ieee80211_beacon_loss(priv->vif);
- break;
- case P54_TRAP_SCAN:
- break;
- case P54_TRAP_TBTT:
- break;
- case P54_TRAP_TIMER:
- break;
- default:
- printk(KERN_INFO "%s: received event:%x freq:%d\n",
- wiphy_name(dev->wiphy), event, freq);
- break;
- }
-}
-
-static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
- switch (le16_to_cpu(hdr->type)) {
- case P54_CONTROL_TYPE_TXDONE:
- p54_rx_frame_sent(dev, skb);
- break;
- case P54_CONTROL_TYPE_TRAP:
- p54_rx_trap(dev, skb);
- break;
- case P54_CONTROL_TYPE_BBP:
- break;
- case P54_CONTROL_TYPE_STAT_READBACK:
- p54_rx_stats(dev, skb);
- break;
- case P54_CONTROL_TYPE_EEPROM_READBACK:
- p54_rx_eeprom_readback(dev, skb);
- break;
- default:
- printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
- wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
- break;
- }
-
- return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
- if (type & P54_HDR_FLAG_CONTROL)
- return p54_rx_control(dev, skb);
- else
- return p54_rx_data(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_rx_frame_sent or
- * p54_free_skb frees allocated areas.
- */
-static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_hdr *data, u32 len)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- struct sk_buff *target_skb = NULL;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- u32 last_addr = priv->rx_start;
- u32 largest_hole = 0;
- u32 target_addr = priv->rx_start;
- unsigned long flags;
- unsigned int left;
- len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
-
- if (!skb)
- return -EINVAL;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
-
- left = skb_queue_len(&priv->tx_queue);
- if (unlikely(left >= 28)) {
- /*
- * The tx_queue is nearly full!
- * We have throttle normal data traffic, because we must
- * have a few spare slots for control frames left.
- */
- ieee80211_stop_queues(dev);
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_TIMEOUT));
-
- if (unlikely(left == 32)) {
- /*
- * The tx_queue is now really full.
- *
- * TODO: check if the device has crashed and reset it.
- */
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return -ENOSPC;
- }
- }
-
- entry = priv->tx_queue.next;
- while (left--) {
- u32 hole_size;
- info = IEEE80211_SKB_CB(entry);
- range = (void *)info->rate_driver_data;
- hole_size = range->start_addr - last_addr;
- if (!target_skb && hole_size >= len) {
- target_skb = entry->prev;
- hole_size -= len;
- target_addr = last_addr;
- }
- largest_hole = max(largest_hole, hole_size);
- last_addr = range->end_addr;
- entry = entry->next;
- }
- if (!target_skb && priv->rx_end - last_addr >= len) {
- target_skb = priv->tx_queue.prev;
- largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
- if (!skb_queue_empty(&priv->tx_queue)) {
- info = IEEE80211_SKB_CB(target_skb);
- range = (void *)info->rate_driver_data;
- target_addr = range->end_addr;
- }
- } else
- largest_hole = max(largest_hole, priv->rx_end - last_addr);
-
- if (!target_skb) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- ieee80211_stop_queues(dev);
- return -ENOSPC;
- }
-
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- range->start_addr = target_addr;
- range->end_addr = target_addr + len;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
- 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
- ieee80211_stop_queues(dev);
-
- data->req_id = cpu_to_le32(target_addr + priv->headroom);
- return 0;
-}
-
-static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags,
- u16 payload_len, u16 type, gfp_t memflags)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct sk_buff *skb;
- size_t frame_len = sizeof(*hdr) + payload_len;
-
- if (frame_len > P54_MAX_CTRL_FRAME_LEN)
- return NULL;
-
- skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
- if (!skb)
- return NULL;
- skb_reserve(skb, priv->tx_hdr_len);
-
- hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->len = cpu_to_le16(payload_len);
- hdr->type = cpu_to_le16(type);
- hdr->tries = hdr->rts_tries = 0;
-
- if (p54_assign_address(dev, skb, hdr, frame_len)) {
- kfree_skb(skb);
- return NULL;
- }
- return skb;
-}
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct p54_eeprom_lm86 *eeprom_hdr;
- struct sk_buff *skb;
- size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
- int ret = -ENOMEM;
- void *eeprom = NULL;
-
- maxblocksize = EEPROM_READBACK_LEN;
- if (priv->fw_var >= 0x509)
- maxblocksize -= 0xc;
- else
- maxblocksize -= 0x4;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
- maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
- GFP_KERNEL);
- if (!skb)
- goto free;
- priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
- if (!priv->eeprom)
- goto free;
- eeprom = kzalloc(eeprom_size, GFP_KERNEL);
- if (!eeprom)
- goto free;
-
- eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
- sizeof(*eeprom_hdr) + maxblocksize);
-
- while (eeprom_size) {
- blocksize = min(eeprom_size, maxblocksize);
- if (priv->fw_var < 0x509) {
- eeprom_hdr->v1.offset = cpu_to_le16(offset);
- eeprom_hdr->v1.len = cpu_to_le16(blocksize);
- } else {
- eeprom_hdr->v2.offset = cpu_to_le32(offset);
- eeprom_hdr->v2.len = cpu_to_le16(blocksize);
- eeprom_hdr->v2.magic2 = 0xf;
- memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
- }
- priv->tx(dev, skb);
-
- if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(dev->wiphy));
- ret = -EBUSY;
- goto free;
- }
-
- memcpy(eeprom + offset, priv->eeprom, blocksize);
- offset += blocksize;
- eeprom_size -= blocksize;
- }
-
- ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
- kfree(priv->eeprom);
- priv->eeprom = NULL;
- p54_free_skb(dev, skb);
- kfree(eeprom);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
- bool set)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_tim *tim;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
- P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
- tim->count = 1;
- tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_sta_unlock *sta;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
- P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
- memcpy(sta->addr, addr, ETH_ALEN);
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- enum sta_notify_cmd notify_cmd,
- struct ieee80211_sta *sta)
-{
- switch (notify_cmd) {
- case STA_NOTIFY_ADD:
- case STA_NOTIFY_REMOVE:
- /*
- * Notify the firmware that we don't want or we don't
- * need to buffer frames for this station anymore.
- */
-
- p54_sta_unlock(dev, sta->addr);
- break;
- case STA_NOTIFY_AWAKE:
- /* update the firmware's filter table */
- p54_sta_unlock(dev, sta->addr);
- break;
- default:
- break;
- }
-}
-
-static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_txcancel *cancel;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
- P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *)entry->data;
- cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
- cancel->req_id = hdr->req_id;
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
- u16 *flags, u16 *aid)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct p54_common *priv = dev->priv;
- int ret = 1;
-
- switch (priv->mode) {
- case NL80211_IFTYPE_MONITOR:
- /*
- * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
- * every frame in promiscuous/monitor mode.
- * see STSW45x0C LMAC API - page 12.
- */
- *aid = 0;
- *flags = P54_HDR_FLAG_DATA_OUT_PROMISC;
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_STATION:
- *aid = 1;
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- } else
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- *aid = 0;
- *queue = P54_QUEUE_CAB;
- return 0;
- }
-
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- if (ieee80211_is_probe_resp(hdr->frame_control)) {
- *aid = 0;
- *queue = P54_QUEUE_MGMT;
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
- P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- return 0;
- } else if (ieee80211_is_beacon(hdr->frame_control)) {
- *aid = 0;
-
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- /*
- * Injecting beacons on top of a AP is
- * not a good idea... nevertheless,
- * it should be doable.
- */
-
- *queue += P54_QUEUE_DATA;
- return 1;
- }
-
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
- *queue = P54_QUEUE_BEACON;
- *extra_len = IEEE80211_MAX_TIM_LEN;
- return 0;
- } else {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- }
- } else
- *queue += P54_QUEUE_DATA;
-
- if (info->control.sta)
- *aid = info->control.sta->aid;
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- break;
- }
- return ret;
-}
-
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
-{
- switch (alg) {
- case ALG_WEP:
- return P54_CRYPTO_WEP;
- case ALG_TKIP:
- return P54_CRYPTO_TKIPMICHAEL;
- case ALG_CCMP:
- return P54_CRYPTO_AESCCMP;
- default:
- return 0;
- }
-}
-
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_queue_stats *current_queue;
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct p54_tx_data *txhdr;
- size_t padding, len, tim_len = 0;
- int i, j, ridx, ret;
- u16 hdr_flags = 0, aid = 0;
- u8 rate, queue, crypt_offset = 0;
- u8 cts_rate = 0x20;
- u8 rc_flags;
- u8 calculated_tries[4];
- u8 nrates = 0, nremaining = 8;
-
- queue = skb_get_queue_mapping(skb);
-
- ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
- current_queue = &priv->tx_stats[queue];
- if (unlikely((current_queue->len > current_queue->limit) && ret))
- return NETDEV_TX_BUSY;
- current_queue->len++;
- current_queue->count++;
- if ((current_queue->len == current_queue->limit) && ret)
- ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
-
- padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
- len = skb->len;
-
- if (info->control.hw_key) {
- crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
- if (info->control.hw_key->alg == ALG_TKIP) {
- u8 *iv = (u8 *)(skb->data + crypt_offset);
- /*
- * The firmware excepts that the IV has to have
- * this special format
- */
- iv[1] = iv[0];
- iv[0] = iv[2];
- iv[2] = 0;
- }
- }
-
- txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
- hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
- if (padding)
- hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
- hdr->type = cpu_to_le16(aid);
- hdr->rts_tries = info->control.rates[0].count;
-
- /*
- * we register the rates in perfect order, and
- * RTS/CTS won't happen on 5 GHz
- */
- cts_rate = info->control.rts_cts_rate_idx;
-
- memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
- /* see how many rates got used */
- for (i = 0; i < 4; i++) {
- if (info->control.rates[i].idx < 0)
- break;
- nrates++;
- }
-
- /* limit tries to 8/nrates per rate */
- for (i = 0; i < nrates; i++) {
- /*
- * The magic expression here is equivalent to 8/nrates for
- * all values that matter, but avoids division and jumps.
- * Note that nrates can only take the values 1 through 4.
- */
- calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
- info->control.rates[i].count);
- nremaining -= calculated_tries[i];
- }
-
- /* if there are tries left, distribute from back to front */
- for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
- int tmp = info->control.rates[i].count - calculated_tries[i];
-
- if (tmp <= 0)
- continue;
- /* RC requested more tries at this rate */
-
- tmp = min_t(int, tmp, nremaining);
- calculated_tries[i] += tmp;
- nremaining -= tmp;
- }
-
- ridx = 0;
- for (i = 0; i < nrates && ridx < 8; i++) {
- /* we register the rates in perfect order */
- rate = info->control.rates[i].idx;
- if (info->band == IEEE80211_BAND_5GHZ)
- rate += 4;
-
- /* store the count we actually calculated for TX status */
- info->control.rates[i].count = calculated_tries[i];
-
- rc_flags = info->control.rates[i].flags;
- if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
- rate |= 0x10;
- cts_rate |= 0x10;
- }
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
- rate |= 0x40;
- else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- rate |= 0x20;
- for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
- txhdr->rateset[ridx] = rate;
- ridx++;
- }
- }
-
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
- hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
- /* TODO: enable bursting */
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->tries = ridx;
- txhdr->rts_rate_idx = 0;
- if (info->control.hw_key) {
- txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
- txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
- memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
- if (info->control.hw_key->alg == ALG_TKIP) {
- if (unlikely(skb_tailroom(skb) < 12))
- goto err;
- /* reserve space for the MIC key */
- len += 8;
- memcpy(skb_put(skb, 8), &(info->control.hw_key->key
- [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
- }
- /* reserve some space for ICV */
- len += info->control.hw_key->icv_len;
- memset(skb_put(skb, info->control.hw_key->icv_len), 0,
- info->control.hw_key->icv_len);
- } else {
- txhdr->key_type = 0;
- txhdr->key_len = 0;
- }
- txhdr->crypt_offset = crypt_offset;
- txhdr->hw_queue = queue;
- txhdr->backlog = current_queue->len;
- memset(txhdr->durations, 0, sizeof(txhdr->durations));
- txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
- 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- txhdr->longbow.cts_rate = cts_rate;
- txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
- } else {
- txhdr->normal.output_power = priv->output_power;
- txhdr->normal.cts_rate = cts_rate;
- }
- if (padding)
- txhdr->align[0] = padding;
-
- hdr->len = cpu_to_le16(len);
- /* modifies skb->cb and with it info, so must be last! */
- if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
- goto err;
- priv->tx(dev, skb);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
-
- return NETDEV_TX_OK;
-
- err:
- skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
- current_queue->len--;
- current_queue->count--;
- return NETDEV_TX_BUSY;
-}
-
-static int p54_setup_mac(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_setup_mac *setup;
- u16 mode;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
- P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
- if (dev->conf.radio_enabled) {
- switch (priv->mode) {
- case NL80211_IFTYPE_STATION:
- mode = P54_FILTER_TYPE_STATION;
- break;
- case NL80211_IFTYPE_AP:
- mode = P54_FILTER_TYPE_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- mode = P54_FILTER_TYPE_IBSS;
- break;
- case NL80211_IFTYPE_MONITOR:
- mode = P54_FILTER_TYPE_PROMISCUOUS;
- break;
- default:
- mode = P54_FILTER_TYPE_HIBERNATE;
- break;
- }
-
- /*
- * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
- * STSW45X0C LMAC API - page 12
- */
- if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
- (priv->filter_flags & FIF_OTHER_BSS)) &&
- (mode != P54_FILTER_TYPE_PROMISCUOUS))
- mode |= P54_FILTER_TYPE_TRANSPARENT;
- } else
- mode = P54_FILTER_TYPE_HIBERNATE;
-
- setup->mac_mode = cpu_to_le16(mode);
- memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
- memcpy(setup->bssid, priv->bssid, ETH_ALEN);
- setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
- setup->rx_align = 0;
- if (priv->fw_var < 0x500) {
- setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- memset(setup->v1.rts_rates, 0, 8);
- setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v1.rxhw = cpu_to_le16(priv->rxhw);
- setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
- setup->v1.unalloc0 = cpu_to_le16(0);
- } else {
- setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v2.rxhw = cpu_to_le16(priv->rxhw);
- setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
- setup->v2.truncate = cpu_to_le16(48896);
- setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- setup->v2.sbss_offset = 0;
- setup->v2.mcast_window = 0;
- setup->v2.rx_rssi_threshold = 0;
- setup->v2.rx_ed_threshold = 0;
- setup->v2.ref_clock = cpu_to_le32(644245094);
- setup->v2.lpf_bandwidth = cpu_to_le16(65535);
- setup->v2.osc_start_delay = cpu_to_le16(65535);
- }
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_scan_head *head;
- struct p54_iq_autocal_entry *iq_autocal;
- union p54_scan_body_union *body;
- struct p54_scan_tail_rate *rate;
- struct pda_rssi_cal_entry *rssi;
- unsigned int i;
- void *entry;
- int band = dev->conf.channel->band;
- __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
- 2 + sizeof(*iq_autocal) + sizeof(*body) +
- sizeof(*rate) + 2 * sizeof(*rssi),
- P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
- memset(head->scan_params, 0, sizeof(head->scan_params));
- head->mode = cpu_to_le16(mode);
- head->dwell = cpu_to_le16(dwell);
- head->freq = freq;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
- *pa_power_points = cpu_to_le16(0x0c);
- }
-
- iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
- for (i = 0; i < priv->iq_autocal_len; i++) {
- if (priv->iq_autocal[i].freq != freq)
- continue;
-
- memcpy(iq_autocal, &priv->iq_autocal[i].params,
- sizeof(struct p54_iq_autocal_entry));
- break;
- }
- if (i == priv->iq_autocal_len)
- goto err;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
- body = (void *) skb_put(skb, sizeof(body->longbow));
- else
- body = (void *) skb_put(skb, sizeof(body->normal));
-
- for (i = 0; i < priv->output_limit->entries; i++) {
- __le16 *entry_freq = (void *) (priv->output_limit->data +
- priv->output_limit->entry_size * i);
-
- if (*entry_freq != freq)
- continue;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.power_limits,
- (void *) entry_freq + sizeof(__le16),
- priv->output_limit->entry_size);
- } else {
- struct pda_channel_output_limit *limits =
- (void *) entry_freq;
-
- body->normal.val_barker = 0x38;
- body->normal.val_bpsk = body->normal.dup_bpsk =
- limits->val_bpsk;
- body->normal.val_qpsk = body->normal.dup_qpsk =
- limits->val_qpsk;
- body->normal.val_16qam = body->normal.dup_16qam =
- limits->val_16qam;
- body->normal.val_64qam = body->normal.dup_64qam =
- limits->val_64qam;
- }
- break;
- }
- if (i == priv->output_limit->entries)
- goto err;
-
- entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
- for (i = 0; i < priv->curve_data->entries; i++) {
- if (*((__le16 *)entry) != freq) {
- entry += priv->curve_data->entry_size;
- continue;
- }
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.curve_data,
- (void *) entry + sizeof(__le16),
- priv->curve_data->entry_size);
- } else {
- struct p54_scan_body *chan = &body->normal;
- struct pda_pa_curve_data *curve_data =
- (void *) priv->curve_data->data;
-
- entry += sizeof(__le16);
- chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
- memcpy(chan->curve_data, entry,
- sizeof(struct p54_pa_curve_data_sample) *
- min((u8)8, curve_data->points_per_channel));
- }
- break;
- }
- if (i == priv->curve_data->entries)
- goto err;
-
- if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
- rssi->add = cpu_to_le16(priv->rssical_db[band].add);
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- /* Longbow frontend needs ever more */
- rssi = (void *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
- rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
- }
-
- if (priv->fw_var >= 0x509) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- hdr = (struct p54_hdr *) skb->data;
- hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
- priv->tx(dev, skb);
- return 0;
-
- err:
- printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
- p54_free_skb(dev, skb);
- return -EINVAL;
-}
-
-static int p54_set_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_led *led;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
- P54_CONTROL_TYPE_LED, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- led = (struct p54_led *) skb_put(skb, sizeof(*led));
- led->flags = cpu_to_le16(0x0003);
- led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
- led->delay[0] = cpu_to_le16(1);
- led->delay[1] = cpu_to_le16(0);
- priv->tx(dev, skb);
- return 0;
-}
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
-do { \
- queue.aifs = cpu_to_le16(ai_fs); \
- queue.cwmin = cpu_to_le16(cw_min); \
- queue.cwmax = cpu_to_le16(cw_max); \
- queue.txop = cpu_to_le16(_txop); \
-} while(0)
-
-static int p54_set_edcf(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_edcf *edcf;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
- P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
- if (priv->use_short_slot) {
- edcf->slottime = 9;
- edcf->sifs = 0x10;
- edcf->eofpad = 0x00;
- } else {
- edcf->slottime = 20;
- edcf->sifs = 0x0a;
- edcf->eofpad = 0x06;
- }
- /* (see prism54/isl_oid.h for further details) */
- edcf->frameburst = cpu_to_le16(0);
- edcf->round_trip_delay = cpu_to_le16(0);
- edcf->flags = 0;
- memset(edcf->mapping, 0, sizeof(edcf->mapping));
- memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_set_ps(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_psm *psm;
- u16 mode;
- int i;
-
- if (dev->conf.flags & IEEE80211_CONF_PS)
- mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
- P54_PSM_CHECKSUM | P54_PSM_MCBC;
- else
- mode = P54_PSM_CAM;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
- P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
- psm->mode = cpu_to_le16(mode);
- psm->aid = cpu_to_le16(priv->aid);
- for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
- psm->intervals[i].interval =
- cpu_to_le16(dev->conf.listen_interval);
- psm->intervals[i].periods = cpu_to_le16(1);
- }
-
- psm->beacon_rssi_skip_max = 200;
- psm->rssi_delta_threshold = 0;
- psm->nr = 10;
- psm->exclude[0] = 0;
-
- priv->tx(dev, skb);
-
- return 0;
-}
-
-static int p54_beacon_tim(struct sk_buff *skb)
-{
- /*
- * the good excuse for this mess is ... the firmware.
- * The dummy TIM MUST be at the end of the beacon frame,
- * because it'll be overwritten!
- */
-
- struct ieee80211_mgmt *mgmt = (void *)skb->data;
- u8 *pos, *end;
-
- if (skb->len <= sizeof(mgmt))
- return -EINVAL;
-
- pos = (u8 *)mgmt->u.beacon.variable;
- end = skb->data + skb->len;
- while (pos < end) {
- if (pos + 2 + pos[1] > end)
- return -EINVAL;
-
- if (pos[0] == WLAN_EID_TIM) {
- u8 dtim_len = pos[1];
- u8 dtim_period = pos[3];
- u8 *next = pos + 2 + dtim_len;
-
- if (dtim_len < 3)
- return -EINVAL;
-
- memmove(pos, next, end - next);
-
- if (dtim_len > 3)
- skb_trim(skb, skb->len - (dtim_len - 3));
-
- pos = end - (dtim_len + 2);
-
- /* add the dummy at the end */
- pos[0] = WLAN_EID_TIM;
- pos[1] = 3;
- pos[2] = 0;
- pos[3] = dtim_period;
- pos[4] = 0;
- return 0;
- }
- pos += 2 + pos[1];
- }
- return 0;
-}
-
-static int p54_beacon_update(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *beacon;
- int ret;
-
- if (priv->cached_beacon) {
- p54_tx_cancel(dev, priv->cached_beacon);
- /* wait for the last beacon the be freed */
- msleep(10);
- }
-
- beacon = ieee80211_beacon_get(dev, vif);
- if (!beacon)
- return -ENOMEM;
- ret = p54_beacon_tim(beacon);
- if (ret)
- return ret;
- ret = p54_tx(dev, beacon);
- if (ret)
- return ret;
- priv->cached_beacon = beacon;
- priv->tsf_high32 = 0;
- priv->tsf_low32 = 0;
-
- return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- mutex_lock(&priv->conf_mutex);
- err = priv->open(dev);
- if (err)
- goto out;
- P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
- P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
- P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
- P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
- err = p54_set_edcf(dev);
- if (err)
- goto out;
-
- memset(priv->bssid, ~0, ETH_ALEN);
- priv->mode = NL80211_IFTYPE_MONITOR;
- err = p54_setup_mac(dev);
- if (err) {
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- goto out;
- }
-
- queue_delayed_work(dev->workqueue, &priv->work, 0);
-
- priv->softled_state = 0;
- err = p54_set_leds(dev);
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return err;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
-
- mutex_lock(&priv->conf_mutex);
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->softled_state = 0;
- p54_set_leds(dev);
-
-#ifdef CONFIG_P54_LEDS
- cancel_delayed_work_sync(&priv->led_work);
-#endif /* CONFIG_P54_LEDS */
- cancel_delayed_work_sync(&priv->work);
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
-
- priv->stop(dev);
- while ((skb = skb_dequeue(&priv->tx_queue)))
- kfree_skb(skb);
- priv->cached_beacon = NULL;
- priv->tsf_high32 = priv->tsf_low32 = 0;
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- if (priv->mode != NL80211_IFTYPE_MONITOR) {
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- priv->vif = conf->vif;
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- priv->mode = conf->type;
- break;
- default:
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
- return 0;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
- priv->mode = NL80211_IFTYPE_MONITOR;
- memset(priv->mac_addr, 0, ETH_ALEN);
- memset(priv->bssid, 0, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
- int ret = 0;
- struct p54_common *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_POWER)
- priv->output_power = conf->power_level << 2;
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- ret = p54_set_ps(dev);
- if (ret)
- goto out;
- }
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
-{
- struct p54_common *priv = dev->priv;
-
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS;
-
- priv->filter_flags = *total_flags;
-
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
- p54_setup_mac(dev);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if ((params) && !(queue > 4)) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(dev);
- } else
- ret = -EINVAL;
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static int p54_init_xbow_synth(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_xbow_synth *xbow;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
- xbow->magic1 = cpu_to_le16(0x1);
- xbow->magic2 = cpu_to_le16(0x2);
- xbow->freq = cpu_to_le16(5390);
- memset(xbow->padding, 0, sizeof(xbow->padding));
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_work(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- work.work);
- struct ieee80211_hw *dev = priv->hw;
- struct sk_buff *skb;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- /*
- * TODO: walk through tx_queue and do the following tasks
- * 1. initiate bursts.
- * 2. cancel stuck frames / reset the device if necessary.
- */
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
- sizeof(struct p54_statistics),
- P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
- if (!skb)
- return ;
-
- priv->tx(dev, skb);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
- struct ieee80211_low_level_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->stats, sizeof(*stats));
- return 0;
-}
-
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
- sizeof(stats[0]) * dev->queues);
- return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & BSS_CHANGED_BSSID) {
- memcpy(priv->bssid, info->bssid, ETH_ALEN);
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BEACON) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- ret = p54_beacon_update(dev, vif);
- if (ret)
- goto out;
- }
- /* XXX: this mimics having two callbacks... clean up */
- out:
- mutex_unlock(&priv->conf_mutex);
-
- if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
- priv->use_short_slot = info->use_short_slot;
- p54_set_edcf(dev);
- }
- if (changed & BSS_CHANGED_BASIC_RATES) {
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- priv->basic_rate_mask = (info->basic_rates << 4);
- else
- priv->basic_rate_mask = info->basic_rates;
- p54_setup_mac(dev);
- if (priv->fw_var >= 0x500)
- p54_scan(dev, P54_SCAN_EXIT, 0);
- }
- if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc) {
- priv->aid = info->aid;
- priv->wakeup_timer = info->beacon_int *
- info->dtim_period * 5;
- p54_setup_mac(dev);
- }
- }
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_keycache *rxkey;
- int slot, ret = 0;
- u8 algo = 0;
-
- if (modparam_nohwcrypt)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->conf_mutex);
- if (cmd == SET_KEY) {
- switch (key->alg) {
- case ALG_TKIP:
- if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
- BR_DESC_PRIV_CAP_TKIP))) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_TKIPMICHAEL;
- break;
- case ALG_WEP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_WEP;
- break;
- case ALG_CCMP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_AESCCMP;
- break;
- default:
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- slot = bitmap_find_free_region(priv->used_rxkeys,
- priv->rx_keycache_size, 0);
-
- if (slot < 0) {
- /*
- * The device supports the choosen algorithm, but the
- * firmware does not provide enough key slots to store
- * all of them.
- * But encryption offload for outgoing frames is always
- * possible, so we just pretend that the upload was
- * successful and do the decryption in software.
- */
-
- /* mark the key as invalid. */
- key->hw_key_idx = 0xff;
- goto out_unlock;
- }
- } else {
- slot = key->hw_key_idx;
-
- if (slot == 0xff) {
- /* This key was not uploaded into the rx key cache. */
-
- goto out_unlock;
- }
-
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- algo = 0;
- }
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
- P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
- if (!skb) {
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- ret = -ENOSPC;
- goto out_unlock;
- }
-
- rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
- rxkey->entry = slot;
- rxkey->key_id = key->keyidx;
- rxkey->key_type = algo;
- if (sta)
- memcpy(rxkey->mac, sta->addr, ETH_ALEN);
- else
- memset(rxkey->mac, ~0, ETH_ALEN);
- if (key->alg != ALG_TKIP) {
- rxkey->key_len = min((u8)16, key->keylen);
- memcpy(rxkey->key, key->key, rxkey->key_len);
- } else {
- rxkey->key_len = 24;
- memcpy(rxkey->key, key->key, 16);
- memcpy(&(rxkey->key[16]), &(key->key
- [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
- }
-
- priv->tx(dev, skb);
- key->hw_key_idx = slot;
-
-out_unlock:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-#ifdef CONFIG_P54_LEDS
-static void p54_update_leds(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- led_work.work);
- int err, i, tmp, blink_delay = 400;
- bool rerun = false;
-
- /* Don't toggle the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].toggled) {
- priv->softled_state |= BIT(i);
-
- tmp = 70 + 200 / (priv->leds[i].toggled);
- if (tmp < blink_delay)
- blink_delay = tmp;
-
- if (priv->leds[i].led_dev.brightness == LED_OFF)
- rerun = true;
-
- priv->leds[i].toggled =
- !!priv->leds[i].led_dev.brightness;
- } else
- priv->softled_state &= ~BIT(i);
-
- err = p54_set_leds(priv->hw);
- if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update LEDs.\n",
- wiphy_name(priv->hw->wiphy));
-
- if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- msecs_to_jiffies(blink_delay));
-}
-
-static void p54_led_brightness_set(struct led_classdev *led_dev,
- enum led_brightness brightness)
-{
- struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
- led_dev);
- struct ieee80211_hw *dev = led->hw_dev;
- struct p54_common *priv = dev->priv;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- if (brightness) {
- led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
- }
-}
-
-static int p54_register_led(struct ieee80211_hw *dev,
- unsigned int led_index,
- char *name, char *trigger)
-{
- struct p54_common *priv = dev->priv;
- struct p54_led_dev *led = &priv->leds[led_index];
- int err;
-
- if (led->registered)
- return -EEXIST;
-
- snprintf(led->name, sizeof(led->name), "p54-%s::%s",
- wiphy_name(dev->wiphy), name);
- led->hw_dev = dev;
- led->index = led_index;
- led->led_dev.name = led->name;
- led->led_dev.default_trigger = trigger;
- led->led_dev.brightness_set = p54_led_brightness_set;
-
- err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
- if (err)
- printk(KERN_ERR "%s: Failed to register %s LED.\n",
- wiphy_name(dev->wiphy), name);
- else
- led->registered = 1;
-
- return err;
-}
-
-static int p54_init_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- /*
- * TODO:
- * Figure out if the EEPROM contains some hints about the number
- * of available/programmable LEDs of the device.
- */
-
- INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
- err = p54_register_led(dev, 0, "assoc",
- ieee80211_get_assoc_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 1, "tx",
- ieee80211_get_tx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 2, "rx",
- ieee80211_get_rx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 3, "radio",
- ieee80211_get_radio_led_name(dev));
- if (err)
- return err;
-
- err = p54_set_leds(dev);
- return err;
-}
-
-static void p54_unregister_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].registered)
- led_classdev_unregister(&priv->leds[i].led_dev);
-}
-#endif /* CONFIG_P54_LEDS */
-
-static const struct ieee80211_ops p54_ops = {
- .tx = p54_tx,
- .start = p54_start,
- .stop = p54_stop,
- .add_interface = p54_add_interface,
- .remove_interface = p54_remove_interface,
- .set_tim = p54_set_tim,
- .sta_notify = p54_sta_notify,
- .set_key = p54_set_key,
- .config = p54_config,
- .bss_info_changed = p54_bss_info_changed,
- .configure_filter = p54_configure_filter,
- .conf_tx = p54_conf_tx,
- .get_stats = p54_get_stats,
- .get_tx_stats = p54_get_tx_stats
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
- struct ieee80211_hw *dev;
- struct p54_common *priv;
-
- dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
- if (!dev)
- return NULL;
-
- priv = dev->priv;
- priv->hw = dev;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->basic_rate_mask = 0x15f;
- skb_queue_head_init(&priv->tx_queue);
- dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
-
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- dev->channel_change_time = 1000; /* TODO: find actual value */
- priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
- priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
- priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
- priv->tx_stats[P54_QUEUE_CAB].limit = 3;
- priv->tx_stats[P54_QUEUE_DATA].limit = 5;
- dev->queues = 1;
- priv->noise = -94;
- /*
- * We support at most 8 tries no matter which rate they're at,
- * we cannot support max_rates * max_rate_tries as we set it
- * here, but setting it correctly to 4/2 or so would limit us
- * artificially if the RC algorithm wants just two rates, so
- * let's say 4/7, we'll redistribute it at TX time, see the
- * comments there.
- */
- dev->max_rates = 4;
- dev->max_rate_tries = 7;
- dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
- sizeof(struct p54_tx_data);
-
- mutex_init(&priv->conf_mutex);
- init_completion(&priv->eeprom_comp);
- INIT_DELAYED_WORK(&priv->work, p54_work);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(p54_init_common);
-
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
-{
- int err;
-
- err = ieee80211_register_hw(dev);
- if (err) {
- dev_err(pdev, "Cannot register device (%d).\n", err);
- return err;
- }
-
-#ifdef CONFIG_P54_LEDS
- err = p54_init_leds(dev);
- if (err)
- return err;
-#endif /* CONFIG_P54_LEDS */
-
- dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_register_common);
-
-void p54_free_common(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- kfree(priv->iq_autocal);
- kfree(priv->output_limit);
- kfree(priv->curve_data);
- kfree(priv->used_rxkeys);
-
-#ifdef CONFIG_P54_LEDS
- p54_unregister_leds(dev);
-#endif /* CONFIG_P54_LEDS */
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
deleted file mode 100644
index 75ead7a150fc..000000000000
--- a/drivers/net/wireless/p54/p54common.h
+++ /dev/null
@@ -1,644 +0,0 @@
-#ifndef P54COMMON_H
-#define P54COMMON_H
-
-/*
- * Common code specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- * Copyright (C) 2007 Conexant Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct bootrec {
- __le32 code;
- __le32 len;
- u32 data[10];
-} __attribute__((packed));
-
-#define PDR_SYNTH_FRONTEND_MASK 0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
-#define PDR_SYNTH_FRONTEND_XBOW 0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
-#define PDR_SYNTH_IQ_CAL_MASK 0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
-#define PDR_SYNTH_24_GHZ_MASK 0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
-#define PDR_SYNTH_5_GHZ_MASK 0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
-#define PDR_SYNTH_RX_DIV_MASK 0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
-#define PDR_SYNTH_TX_DIV_MASK 0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
-
-struct bootrec_exp_if {
- __le16 role;
- __le16 if_id;
- __le16 variant;
- __le16 btm_compat;
- __le16 top_compat;
-} __attribute__((packed));
-
-#define BR_DESC_PRIV_CAP_WEP BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
-
-struct bootrec_desc {
- __le16 modes;
- __le16 flags;
- __le32 rx_start;
- __le32 rx_end;
- u8 headroom;
- u8 tailroom;
- u8 tx_queues;
- u8 tx_depth;
- u8 privacy_caps;
- u8 rx_keycache_size;
- u8 time_size;
- u8 padding;
- u8 rates[16];
- u8 padding2[4];
- __le16 rx_mtu;
-} __attribute__((packed));
-
-#define BR_CODE_MIN 0x80000000
-#define BR_CODE_COMPONENT_ID 0x80000001
-#define BR_CODE_COMPONENT_VERSION 0x80000002
-#define BR_CODE_DEPENDENT_IF 0x80000003
-#define BR_CODE_EXPOSED_IF 0x80000004
-#define BR_CODE_DESCR 0x80000101
-#define BR_CODE_MAX 0x8FFFFFFF
-#define BR_CODE_END_OF_BRA 0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-
-#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
-#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
- __le16 len; /* includes both code and data */
- __le16 code;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct eeprom_pda_wrap {
- __le32 magic;
- __le16 pad;
- __le16 len;
- __le32 arm_opcode;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct p54_iq_autocal_entry {
- __le16 iq_param[4];
-} __attribute__ ((packed));
-
-struct pda_iq_autocal_entry {
- __le16 freq;
- struct p54_iq_autocal_entry params;
-} __attribute__ ((packed));
-
-struct pda_channel_output_limit {
- __le16 freq;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- u8 rate_set_mask;
- u8 rate_set_size;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev0 {
- u8 rf_power;
- u8 pa_detector;
- u8 pcv;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev1 {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
- u8 padding;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data {
- u8 cal_method_rev;
- u8 channels;
- u8 points_per_channel;
- u8 padding;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct pda_rssi_cal_entry {
- __le16 mul;
- __le16 add;
-} __attribute__ ((packed));
-
-struct pda_country {
- u8 regdomain;
- u8 alpha2[2];
- u8 flags;
-} __attribute__ ((packed));
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
- __le16 rf_power_points[12];
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample_longbow {
- __le16 rf_power;
- __le16 pa_detector;
- struct {
- __le16 data[4];
- } points[3] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct pda_custom_wrapper {
- __le16 entries;
- __le16 entry_size;
- __le16 offset;
- __le16 len;
- u8 data[0];
-} __attribute__ ((packed));
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END 0x0000
-#define PDR_MANUFACTURING_PART_NUMBER 0x0001
-#define PDR_PDA_VERSION 0x0002
-#define PDR_NIC_SERIAL_NUMBER 0x0003
-
-#define PDR_MAC_ADDRESS 0x0101
-#define PDR_REGULATORY_DOMAIN_LIST 0x0103
-#define PDR_TEMPERATURE_TYPE 0x0107
-
-#define PDR_PRISM_PCI_IDENTIFIER 0x0402
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION 0x1000
-#define PDR_INTERFACE_LIST 0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
-#define PDR_OEM_NAME 0x1003
-#define PDR_PRODUCT_NAME 0x1004
-#define PDR_UTF8_OEM_NAME 0x1005
-#define PDR_UTF8_PRODUCT_NAME 0x1006
-#define PDR_COUNTRY_LIST 0x1007
-#define PDR_DEFAULT_COUNTRY 0x1008
-
-#define PDR_ANTENNA_GAIN 0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
-#define PDR_REGULATORY_POWER_LIMITS 0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS 0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE 0x80
-#define PDR_COUNTRY_CERT_CODE_REAL 0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
-#define PDR_COUNTRY_CERT_BAND 0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
-#define PDR_COUNTRY_CERT_IODOOR 0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
-#define PDR_COUNTRY_CERT_INDEX 0x0F
-
-struct p54_eeprom_lm86 {
- union {
- struct {
- __le16 offset;
- __le16 len;
- u8 data[0];
- } v1;
- struct {
- __le32 offset;
- __le16 len;
- u8 magic2;
- u8 pad;
- u8 magic[4];
- u8 data[0];
- } v2;
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-enum p54_rx_decrypt_status {
- P54_DECRYPT_NONE = 0,
- P54_DECRYPT_OK,
- P54_DECRYPT_NOKEY,
- P54_DECRYPT_NOMICHAEL,
- P54_DECRYPT_NOCKIPMIC,
- P54_DECRYPT_FAIL_WEP,
- P54_DECRYPT_FAIL_TKIP,
- P54_DECRYPT_FAIL_MICHAEL,
- P54_DECRYPT_FAIL_CKIPKP,
- P54_DECRYPT_FAIL_CKIPMIC,
- P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
- __le16 flags;
- __le16 len;
- __le16 freq;
- u8 antenna;
- u8 rate;
- u8 rssi;
- u8 quality;
- u8 decrypt_status;
- u8 rssi_raw;
- __le32 tsf32;
- __le32 unalloc0;
- u8 align[0];
-} __attribute__ ((packed));
-
-enum p54_trap_type {
- P54_TRAP_SCAN = 0,
- P54_TRAP_TIMER,
- P54_TRAP_BEACON_TX,
- P54_TRAP_FAA_RADIO_ON,
- P54_TRAP_FAA_RADIO_OFF,
- P54_TRAP_RADAR,
- P54_TRAP_NO_BEACON,
- P54_TRAP_TBTT,
- P54_TRAP_SCO_ENTER,
- P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
- __le16 event;
- __le16 frequency;
-} __attribute__ ((packed));
-
-enum p54_frame_sent_status {
- P54_TX_OK = 0,
- P54_TX_FAILED,
- P54_TX_PSM,
- P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
- u8 status;
- u8 tries;
- u8 ack_rssi;
- u8 quality;
- __le16 seq;
- u8 antenna;
- u8 padding;
-} __attribute__ ((packed));
-
-enum p54_tx_data_crypt {
- P54_CRYPTO_NONE = 0,
- P54_CRYPTO_WEP,
- P54_CRYPTO_TKIP,
- P54_CRYPTO_TKIPMICHAEL,
- P54_CRYPTO_CCX_WEPMIC,
- P54_CRYPTO_CCX_KPMIC,
- P54_CRYPTO_CCX_KP,
- P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
- P54_QUEUE_BEACON = 0,
- P54_QUEUE_FWSCAN = 1,
- P54_QUEUE_MGMT = 2,
- P54_QUEUE_CAB = 3,
- P54_QUEUE_DATA = 4,
-
- P54_QUEUE_AC_NUM = 4,
- P54_QUEUE_AC_VO = 4,
- P54_QUEUE_AC_VI = 5,
- P54_QUEUE_AC_BE = 6,
- P54_QUEUE_AC_BK = 7,
-
- /* keep last */
- P54_QUEUE_NUM = 8,
-};
-
-struct p54_tx_data {
- u8 rateset[8];
- u8 rts_rate_idx;
- u8 crypt_offset;
- u8 key_type;
- u8 key_len;
- u8 key[16];
- u8 hw_queue;
- u8 backlog;
- __le16 durations[4];
- u8 tx_antenna;
- union {
- struct {
- u8 cts_rate;
- __le16 output_power;
- } __attribute__((packed)) longbow;
- struct {
- u8 output_power;
- u8 cts_rate;
- u8 unalloc;
- } __attribute__ ((packed)) normal;
- } __attribute__ ((packed));
- u8 unalloc2[2];
- u8 align[0];
-} __attribute__ ((packed));
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE 0
-#define P54_FILTER_TYPE_STATION BIT(0)
-#define P54_FILTER_TYPE_IBSS BIT(1)
-#define P54_FILTER_TYPE_AP BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE BIT(5)
-#define P54_FILTER_TYPE_NOACK BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
-
-struct p54_setup_mac {
- __le16 mac_mode;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 rx_antenna;
- u8 rx_align;
- union {
- struct {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 wakeup_timer;
- __le16 unalloc0;
- } v1 __attribute__ ((packed));
- struct {
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 timer;
- __le16 truncate;
- __le32 basic_rate_mask;
- u8 sbss_offset;
- u8 mcast_window;
- u8 rx_rssi_threshold;
- u8 rx_ed_threshold;
- __le32 ref_clock;
- __le16 lpf_bandwidth;
- __le16 osc_start_delay;
- } v2 __attribute__ ((packed));
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT BIT(0)
-#define P54_SCAN_TRAP BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
- __le16 mode;
- __le16 dwell;
- u8 scan_params[20];
- __le16 freq;
-} __attribute__ ((packed));
-
-struct p54_scan_body {
- u8 pa_points_per_curve;
- u8 val_barker;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- struct p54_pa_curve_data_sample curve_data[8];
- u8 dup_bpsk;
- u8 dup_qpsk;
- u8 dup_16qam;
- u8 dup_64qam;
-} __attribute__ ((packed));
-
-struct p54_scan_body_longbow {
- struct p54_channel_output_limit_longbow power_limits;
- struct p54_pa_curve_data_sample_longbow curve_data[8];
- __le16 unkn[6]; /* maybe more power_limits or rate_mask */
-} __attribute__ ((packed));
-
-union p54_scan_body_union {
- struct p54_scan_body normal;
- struct p54_scan_body_longbow longbow;
-} __attribute__ ((packed));
-
-struct p54_scan_tail_rate {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
-} __attribute__ ((packed));
-
-struct p54_led {
- __le16 flags;
- __le16 mask[2];
- __le16 delay[2];
-} __attribute__ ((packed));
-
-struct p54_edcf {
- u8 flags;
- u8 slottime;
- u8 sifs;
- u8 eofpad;
- struct p54_edcf_queue_param queue[8];
- u8 mapping[4];
- __le16 frameburst;
- __le16 round_trip_delay;
-} __attribute__ ((packed));
-
-struct p54_statistics {
- __le32 rx_success;
- __le32 rx_bad_fcs;
- __le32 rx_abort;
- __le32 rx_abort_phy;
- __le32 rts_success;
- __le32 rts_fail;
- __le32 tsf32;
- __le32 airtime;
- __le32 noise;
- __le32 sample_noise[8];
- __le32 sample_cca;
- __le32 sample_tx;
-} __attribute__ ((packed));
-
-struct p54_xbow_synth {
- __le16 magic1;
- __le16 magic2;
- __le16 freq;
- u32 padding[5];
-} __attribute__ ((packed));
-
-struct p54_timer {
- __le32 interval;
-} __attribute__ ((packed));
-
-struct p54_keycache {
- u8 entry;
- u8 key_id;
- u8 mac[ETH_ALEN];
- u8 padding[2];
- u8 key_type;
- u8 key_len;
- u8 key[24];
-} __attribute__ ((packed));
-
-struct p54_burst {
- u8 flags;
- u8 queue;
- u8 backlog;
- u8 pad;
- __le16 durations[32];
-} __attribute__ ((packed));
-
-struct p54_psm_interval {
- __le16 interval;
- __le16 periods;
-} __attribute__ ((packed));
-
-#define P54_PSM_CAM 0
-#define P54_PSM BIT(0)
-#define P54_PSM_DTIM BIT(1)
-#define P54_PSM_MCBC BIT(2)
-#define P54_PSM_CHECKSUM BIT(3)
-#define P54_PSM_SKIP_MORE_DATA BIT(4)
-#define P54_PSM_BEACON_TIMEOUT BIT(5)
-#define P54_PSM_HFOSLEEP BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
-#define P54_PSM_LPIT BIT(8)
-#define P54_PSM_BF_UCAST_SKIP BIT(9)
-#define P54_PSM_BF_MCAST_SKIP BIT(10)
-
-struct p54_psm {
- __le16 mode;
- __le16 aid;
- struct p54_psm_interval intervals[4];
- u8 beacon_rssi_skip_max;
- u8 rssi_delta_threshold;
- u8 nr;
- u8 exclude[1];
-} __attribute__ ((packed));
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
- __le16 filter_enable;
- __le16 num_address;
- u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __attribute__ ((packed));
-
-struct p54_txcancel {
- __le32 req_id;
-} __attribute__ ((packed));
-
-struct p54_sta_unlock {
- u8 addr[ETH_ALEN];
- u16 padding;
-} __attribute__ ((packed));
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
- u8 count;
- u8 padding[3];
- __le16 entry[8];
-} __attribute__ ((packed));
-
-struct p54_cce_quiet {
- __le32 period;
-} __attribute__ ((packed));
-
-struct p54_bt_balancer {
- __le16 prio_thresh;
- __le16 acl_thresh;
-} __attribute__ ((packed));
-
-struct p54_arp_table {
- __le16 filter_enable;
- u8 ipv4_addr[4];
-} __attribute__ ((packed));
-
-#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index b1610ea4bb3d..d348c265e867 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54pci.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_common:
release_firmware(priv->firmware);
- p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_dev:
pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
err_free_reg:
pci_release_regions(pdev);
@@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
- p54_free_common(dev);
iounmap(priv->map);
pci_release_regions(pdev);
pci_disable_device(pdev);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 83116baeb110..eef532987d05 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -34,7 +34,7 @@
#include "p54spi_eeprom.h"
#include "p54.h"
-#include "p54common.h"
+#include "lmac.h"
MODULE_FIRMWARE("3826.arm");
MODULE_ALIAS("stlc45xx");
@@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
spi_sync(priv->spi, &m);
}
-static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
-{
- __le16 val;
-
- p54spi_spi_read(priv, addr, &val, sizeof(val));
-
- return le16_to_cpu(val);
-}
-
static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
{
__le32 val;
@@ -139,37 +130,12 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
p54spi_spi_write(priv, addr, &val, sizeof(val));
}
-struct p54spi_spi_reg {
- u16 address; /* __le16 ? */
- u16 length;
- char *name;
-};
-
-static const struct p54spi_spi_reg p54spi_registers_array[] =
-{
- { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " },
- { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " },
- { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " },
- { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" },
- { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" },
- { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " },
- { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " },
- { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" },
- { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " },
- { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " },
- { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " },
- { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " },
- { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
-};
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
{
int i;
for (i = 0; i < 2000; i++) {
- __le32 buffer = p54spi_read32(priv, reg);
+ u32 buffer = p54spi_read32(priv, reg);
if ((buffer & bits) == bits)
return 1;
}
@@ -179,8 +145,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
const void *buf, size_t len)
{
- if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED))) {
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
dev_err(&priv->spi->dev, "spi_write_dma not allowed "
"to DMA write.\n");
return -EAGAIN;
@@ -333,7 +298,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
/* And wait for the READY interrupt */
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_READY))) {
+ SPI_HOST_INT_READY)) {
dev_err(&priv->spi->dev, "INT_READY timeout\n");
return -EBUSY;
}
@@ -444,7 +409,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
goto out;
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ SPI_HOST_INT_WR_READY)) {
dev_err(&priv->spi->dev, "WR_READY timeout\n");
ret = -EAGAIN;
goto out;
@@ -635,7 +600,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)
hw = p54_init_common(sizeof(*priv));
if (!hw) {
- dev_err(&priv->spi->dev, "could not alloc ieee80211_hw");
+ dev_err(&spi->dev, "could not alloc ieee80211_hw");
return -ENOMEM;
}
@@ -713,7 +678,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
{
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- ieee80211_unregister_hw(priv->hw);
+ p54_unregister_common(priv->hw);
free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
@@ -724,7 +689,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
mutex_destroy(&priv->mutex);
p54_free_common(priv->hw);
- ieee80211_free_hw(priv->hw);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 0e877a104a89..e44460ff149c 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54usb.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -245,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb)
+ if (!data_urb) {
+ p54_free_skb(dev, skb);
return;
+ }
hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -268,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
- struct urb *int_urb, *data_urb;
+ struct urb *int_urb = NULL, *data_urb = NULL;
struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
- struct net2280_reg_write *reg;
- int err = 0;
+ struct net2280_reg_write *reg = NULL;
+ int err = -ENOMEM;
reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg)
- return;
+ goto out;
int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!int_urb) {
- kfree(reg);
- return;
- }
+ if (!int_urb)
+ goto out;
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb) {
- kfree(reg);
- usb_free_urb(int_urb);
- return;
- }
+ if (!data_urb)
+ goto out;
reg->port = cpu_to_le16(NET2280_DEV_U32);
reg->addr = cpu_to_le32(P54U_DEV_BASE);
@@ -303,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
p54u_tx_dummy_cb, dev);
/*
- * This flag triggers a code path in the USB subsystem that will
- * free what's inside the transfer_buffer after the callback routine
- * has completed.
+ * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+ * free what is inside the transfer_buffer after the last reference to
+ * the int_urb is dropped.
*/
int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+ reg = NULL;
usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
@@ -328,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_unanchor_urb(data_urb);
goto out;
}
- out:
+out:
usb_free_urb(int_urb);
usb_free_urb(data_urb);
if (err) {
- skb_pull(skb, sizeof(*hdr));
+ kfree(reg);
p54_free_skb(dev, skb);
}
}
@@ -961,7 +960,7 @@ err_free_fw:
release_firmware(priv->fw);
err_free_dev:
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
return err;
@@ -975,13 +974,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
- ieee80211_free_hw(dev);
}
static int p54u_pre_reset(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
new file mode 100644
index 000000000000..c32a0d2fa1f7
--- /dev/null
+++ b/drivers/net/wireless/p54/txrx.c
@@ -0,0 +1,860 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+ unsigned long flags;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ unsigned int i = 0;
+ u32 prev_addr;
+ u32 largest_hole = 0, free;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+ wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+
+ prev_addr = priv->rx_start;
+ skb_queue_walk(&priv->tx_queue, skb) {
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ hdr = (void *) skb->data;
+
+ free = range->start_addr - prev_addr;
+ printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
+ "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+ "mem:{start:%04x end:%04x, free:%d}]\n",
+ wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
+ le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+ le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+ range->start_addr, range->end_addr, free);
+
+ prev_addr = range->end_addr;
+ largest_hole = max(largest_hole, free);
+ }
+ free = priv->rx_end - prev_addr;
+ largest_hole = max(largest_hole, free);
+ printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
+ wiphy_name(priv->hw->wiphy), free, largest_hole);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct sk_buff *entry, *target_skb = NULL;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct p54_hdr *data = (void *) skb->data;
+ unsigned long flags;
+ u32 last_addr = priv->rx_start;
+ u32 target_addr = priv->rx_start;
+ u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ len = (range->extra_len + len) & ~0x3;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+ /*
+ * The tx_queue is now really full.
+ *
+ * TODO: check if the device has crashed and reset it.
+ */
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -EBUSY;
+ }
+
+ skb_queue_walk(&priv->tx_queue, entry) {
+ u32 hole_size;
+ info = IEEE80211_SKB_CB(entry);
+ range = (void *) info->rate_driver_data;
+ hole_size = range->start_addr - last_addr;
+
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ break;
+ }
+ last_addr = range->end_addr;
+ }
+ if (unlikely(!target_skb)) {
+ if (priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ info = IEEE80211_SKB_CB(target_skb);
+ range = (void *)info->rate_driver_data;
+ target_addr = range->end_addr;
+ }
+ } else {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -ENOSPC;
+ }
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ if (IS_DATA_FRAME(skb) &&
+ unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+ priv->beacon_req_id = data->req_id;
+
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = skb_dequeue(&priv->tx_pending);
+ if (unlikely(!skb))
+ return ;
+
+ ret = p54_assign_address(priv, skb);
+ if (unlikely(ret))
+ skb_queue_head(&priv->tx_pending, skb);
+ else
+ priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ p54_tx_pending(priv);
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ for (i = 0; i < priv->hw->queues; i++) {
+ if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+ priv->tx_stats[i + P54_QUEUE_DATA].limit)
+ ieee80211_wake_queue(priv->hw, i);
+ }
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+ struct sk_buff *skb,
+ const u16 p54_queue)
+{
+ struct ieee80211_tx_queue_stats *queue;
+ unsigned long flags;
+
+ if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+ return -EINVAL;
+
+ queue = &priv->tx_stats[p54_queue];
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return -ENOSPC;
+ }
+
+ queue->len++;
+ queue->count++;
+
+ if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+ ieee80211_stop_queue(priv->hw, ac_queue);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ if (IS_DATA_FRAME(skb)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ priv->tx_stats[GET_HW_QUEUE(skb)].len--;
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+ if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+ if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+ /* this is the active beacon set anymore */
+ priv->beacon_req_id = 0;
+ }
+ complete(&priv->beacon_comp);
+ }
+ }
+ p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ if (unlikely(!skb))
+ return ;
+
+ skb_unlink(skb, &priv->tx_queue);
+ p54_tx_qos_accounting_free(priv, skb);
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+ const __le32 req_id)
+{
+ struct sk_buff *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk(&priv->tx_queue, entry) {
+ struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+ if (hdr->req_id == req_id) {
+ __skb_unlink(entry, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ p54_tx_qos_accounting_free(priv, entry);
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+ skb_queue_tail(&priv->tx_pending, skb);
+ p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+ int band = priv->hw->conf.channel->band;
+
+ if (priv->rxhw != 5)
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+ else
+ /*
+ * TODO: find the correct formula
+ */
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+}
+
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool new_psm;
+
+ /* only beacons have a TIM IE */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ if (!priv->aid)
+ return;
+
+ /* only consider beacons from the associated BSSID */
+ if (compare_ether_addr(hdr->addr3, priv->bssid))
+ return;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+ if (new_psm != priv->powersave_override) {
+ priv->powersave_override = new_psm;
+ p54_set_ps(priv);
+ }
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ u16 freq = le16_to_cpu(hdr->freq);
+ size_t header_len = sizeof(*hdr);
+ u32 tsf32;
+ u8 rate = hdr->rate & 0xf;
+
+ /*
+ * If the device is in a unspecified state we have to
+ * ignore all data frames. Else we could end up with a
+ * nasty crash.
+ */
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return 0;
+
+ if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+ return 0;
+
+ if (hdr->decrypt_status == P54_DECRYPT_OK)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+ (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+ rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
+ rx_status->noise = priv->noise;
+ if (hdr->rate & 0x10)
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+ else
+ rx_status->rate_idx = rate;
+
+ rx_status->freq = freq;
+ rx_status->band = priv->hw->conf.channel->band;
+ rx_status->antenna = hdr->antenna;
+
+ tsf32 = le32_to_cpu(hdr->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+ priv->tsf_low32 = tsf32;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ header_len += hdr->align[0];
+
+ skb_pull(skb, header_len);
+ skb_trim(skb, le16_to_cpu(hdr->len));
+ if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+ p54_pspoll_workaround(priv, skb);
+
+ ieee80211_rx_irqsafe(priv->hw, skb);
+
+ queue_delayed_work(priv->hw->workqueue, &priv->work,
+ msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+ return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+ struct ieee80211_tx_info *info;
+ struct p54_hdr *entry_hdr;
+ struct p54_tx_data *entry_data;
+ struct sk_buff *entry;
+ unsigned int pad = 0, frame_len;
+ int count, idx;
+
+ entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+ if (unlikely(!entry))
+ return ;
+
+ frame_len = entry->len;
+ info = IEEE80211_SKB_CB(entry);
+ entry_hdr = (struct p54_hdr *) entry->data;
+ entry_data = (struct p54_tx_data *) entry_hdr->data;
+ priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+ /*
+ * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+ * generated by the driver. Therefore tx_status is bogus
+ * and we don't want to confuse the mac80211 stack.
+ */
+ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+ dev_kfree_skb_any(entry);
+ return ;
+ }
+
+ /*
+ * Clear manually, ieee80211_tx_info_clear_status would
+ * clear the counts too and we need them.
+ */
+ memset(&info->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+ status.ampdu_ack_len) != 23);
+
+ if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ pad = entry_data->align[0];
+
+ /* walk through the rates array and adjust the counts */
+ count = payload->tries;
+ for (idx = 0; idx < 4; idx++) {
+ if (count >= info->status.rates[idx].count) {
+ count -= info->status.rates[idx].count;
+ } else if (count > 0) {
+ info->status.rates[idx].count = count;
+ count = 0;
+ } else {
+ info->status.rates[idx].idx = -1;
+ info->status.rates[idx].count = 0;
+ }
+ }
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (!payload->status))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (payload->status & P54_TX_PSM_CANCELLED)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.ack_signal = p54_rssi_to_dbm(priv,
+ (int)payload->ack_rssi);
+
+ /* Undo all changes to the frame. */
+ switch (entry_data->key_type) {
+ case P54_CRYPTO_TKIPMICHAEL: {
+ u8 *iv = (u8 *)(entry_data->align + pad +
+ entry_data->crypt_offset);
+
+ /* Restore the original TKIP IV. */
+ iv[2] = iv[0];
+ iv[0] = iv[1];
+ iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
+
+ frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+ break;
+ }
+ case P54_CRYPTO_AESCCMP:
+ frame_len -= 8; /* remove CCMP_MIC */
+ break;
+ case P54_CRYPTO_WEP:
+ frame_len -= 4; /* remove WEP_ICV */
+ break;
+ }
+
+ skb_trim(entry, frame_len);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+ struct sk_buff *tmp;
+
+ if (!priv->eeprom)
+ return ;
+
+ if (priv->fw_var >= 0x509) {
+ memcpy(priv->eeprom, eeprom->v2.data,
+ le16_to_cpu(eeprom->v2.len));
+ } else {
+ memcpy(priv->eeprom, eeprom->v1.data,
+ le16_to_cpu(eeprom->v1.len));
+ }
+
+ priv->eeprom = NULL;
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+ complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+ struct sk_buff *tmp;
+ u32 tsf32;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ tsf32 = le32_to_cpu(stats->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ priv->tsf_low32 = tsf32;
+
+ priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+ priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+ priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+ priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_trap *trap = (struct p54_trap *) hdr->data;
+ u16 event = le16_to_cpu(trap->event);
+ u16 freq = le16_to_cpu(trap->frequency);
+
+ switch (event) {
+ case P54_TRAP_BEACON_TX:
+ break;
+ case P54_TRAP_RADAR:
+ printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+ wiphy_name(priv->hw->wiphy), freq);
+ break;
+ case P54_TRAP_NO_BEACON:
+ if (priv->vif)
+ ieee80211_beacon_loss(priv->vif);
+ break;
+ case P54_TRAP_SCAN:
+ break;
+ case P54_TRAP_TBTT:
+ break;
+ case P54_TRAP_TIMER:
+ break;
+ default:
+ printk(KERN_INFO "%s: received event:%x freq:%d\n",
+ wiphy_name(priv->hw->wiphy), event, freq);
+ break;
+ }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_TRAP:
+ p54_rx_trap(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ case P54_CONTROL_TYPE_STAT_READBACK:
+ p54_rx_stats(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_EEPROM_READBACK:
+ p54_rx_eeprom_readback(priv, skb);
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+ return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+ if (type & P54_HDR_FLAG_CONTROL)
+ return p54_rx_control(priv, skb);
+ else
+ return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+ struct ieee80211_tx_info *info, u8 *queue,
+ u32 *extra_len, u16 *flags, u16 *aid,
+ bool *burst_possible)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ *burst_possible = true;
+ else
+ *burst_possible = false;
+
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+ if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+ switch (priv->mode) {
+ case NL80211_IFTYPE_MONITOR:
+ /*
+ * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+ * every frame in promiscuous/monitor mode.
+ * see STSW45x0C LMAC API - page 12.
+ */
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+ break;
+ case NL80211_IFTYPE_STATION:
+ *aid = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ *aid = 0;
+ *queue = P54_QUEUE_CAB;
+ return;
+ }
+
+ if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+ if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+ P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ return;
+ } else if (ieee80211_is_beacon(hdr->frame_control)) {
+ *aid = 0;
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ /*
+ * Injecting beacons on top of a AP is
+ * not a good idea... nevertheless,
+ * it should be doable.
+ */
+
+ return;
+ }
+
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+ *queue = P54_QUEUE_BEACON;
+ *extra_len = IEEE80211_MAX_TIM_LEN;
+ return;
+ }
+ }
+
+ if (info->control.sta)
+ *aid = info->control.sta->aid;
+ break;
+ }
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+ switch (alg) {
+ case ALG_WEP:
+ return P54_CRYPTO_WEP;
+ case ALG_TKIP:
+ return P54_CRYPTO_TKIPMICHAEL;
+ case ALG_CCMP:
+ return P54_CRYPTO_AESCCMP;
+ default:
+ return 0;
+ }
+}
+
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct p54_tx_info *p54info;
+ struct p54_hdr *hdr;
+ struct p54_tx_data *txhdr;
+ unsigned int padding, len, extra_len;
+ int i, j, ridx;
+ u16 hdr_flags = 0, aid = 0;
+ u8 rate, queue = 0, crypt_offset = 0;
+ u8 cts_rate = 0x20;
+ u8 rc_flags;
+ u8 calculated_tries[4];
+ u8 nrates = 0, nremaining = 8;
+ bool burst_allowed = false;
+
+ p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+ &hdr_flags, &aid, &burst_allowed);
+
+ if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+ if (!IS_QOS_QUEUE(queue)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ } else {
+ return NETDEV_TX_BUSY;
+ }
+ }
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ if (info->control.hw_key) {
+ crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ u8 *iv = (u8 *)(skb->data + crypt_offset);
+ /*
+ * The firmware excepts that the IV has to have
+ * this special format
+ */
+ iv[1] = iv[0];
+ iv[0] = iv[2];
+ iv[2] = 0;
+ }
+ }
+
+ txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+ hdr->type = cpu_to_le16(aid);
+ hdr->rts_tries = info->control.rates[0].count;
+
+ /*
+ * we register the rates in perfect order, and
+ * RTS/CTS won't happen on 5 GHz
+ */
+ cts_rate = info->control.rts_cts_rate_idx;
+
+ memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+ /* see how many rates got used */
+ for (i = 0; i < dev->max_rates; i++) {
+ if (info->control.rates[i].idx < 0)
+ break;
+ nrates++;
+ }
+
+ /* limit tries to 8/nrates per rate */
+ for (i = 0; i < nrates; i++) {
+ /*
+ * The magic expression here is equivalent to 8/nrates for
+ * all values that matter, but avoids division and jumps.
+ * Note that nrates can only take the values 1 through 4.
+ */
+ calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+ info->control.rates[i].count);
+ nremaining -= calculated_tries[i];
+ }
+
+ /* if there are tries left, distribute from back to front */
+ for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+ int tmp = info->control.rates[i].count - calculated_tries[i];
+
+ if (tmp <= 0)
+ continue;
+ /* RC requested more tries at this rate */
+
+ tmp = min_t(int, tmp, nremaining);
+ calculated_tries[i] += tmp;
+ nremaining -= tmp;
+ }
+
+ ridx = 0;
+ for (i = 0; i < nrates && ridx < 8; i++) {
+ /* we register the rates in perfect order */
+ rate = info->control.rates[i].idx;
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate += 4;
+
+ /* store the count we actually calculated for TX status */
+ info->control.rates[i].count = calculated_tries[i];
+
+ rc_flags = info->control.rates[i].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+ rate |= 0x10;
+ cts_rate |= 0x10;
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ burst_allowed = false;
+ rate |= 0x40;
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ rate |= 0x20;
+ burst_allowed = false;
+ }
+ for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+ txhdr->rateset[ridx] = rate;
+ ridx++;
+ }
+ }
+
+ if (burst_allowed)
+ hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+ /* TODO: enable bursting */
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->tries = ridx;
+ txhdr->rts_rate_idx = 0;
+ if (info->control.hw_key) {
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+ memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ /* reserve space for the MIC key */
+ len += 8;
+ memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+ [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+ }
+ /* reserve some space for ICV */
+ len += info->control.hw_key->icv_len;
+ memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+ info->control.hw_key->icv_len);
+ } else {
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
+ }
+ txhdr->crypt_offset = crypt_offset;
+ txhdr->hw_queue = queue;
+ txhdr->backlog = priv->tx_stats[queue].len - 1;
+ memset(txhdr->durations, 0, sizeof(txhdr->durations));
+ txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
+ 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
+ if (priv->rxhw == 5) {
+ txhdr->longbow.cts_rate = cts_rate;
+ txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+ } else {
+ txhdr->normal.output_power = priv->output_power;
+ txhdr->normal.cts_rate = cts_rate;
+ }
+ if (padding)
+ txhdr->align[0] = padding;
+
+ hdr->len = cpu_to_le16(len);
+ /* modifies skb->cb and with it info, so must be last! */
+ p54info = (void *) info->rate_driver_data;
+ p54info->extra_len = extra_len;
+
+ p54_tx(priv, skb);
+ return NETDEV_TX_OK;
+}
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 8f6210993448..c255d9c6a5f1 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
/* unlock the driver code */
spin_unlock_irqrestore(&priv->slock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_free:
ndev->stats.tx_dropped++;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 30876728d7e6..83d366258c81 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = {
/* 3COM 3CRWE154G72 Wireless LAN adapter */
{
- 0x10b7, 0x6001,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0
+ PCI_VDEVICE(3COM, 0x6001), 0
},
/* Intersil PRISM Indigo Wireless LAN adapter */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 698b11b1cadb..325206969c97 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
@@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
default:
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
} /* ray_dev_start_xmit */
/*===========================================================================*/
@@ -1511,9 +1511,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev)
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
- if (local == (ray_dev_t *) NULL)
- return (iw_stats *) NULL;
-
local->wstats.status = local->card_status;
#ifdef WIRELESS_SPY
if ((local->spy_data.spy_number > 0)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3bec3dbd3450..09c0702ae645 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval,
/* Assume that Broadcom 4320 (only chipset at time of writing known to be
* based on wireless rndis) has default txpower of 13dBm.
* This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- * 13dBm == 19.9mW
+ * 100% : 20 mW ~ 13dBm
+ * 75% : 15 mW ~ 12dBm
+ * 50% : 10 mW ~ 10dBm
+ * 25% : 5 mW ~ 7dBm
*/
-#define BCM4320_DEFAULT_TXPOWER 20
+#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
+#define BCM4320_DEFAULT_TXPOWER_DBM_75 12
+#define BCM4320_DEFAULT_TXPOWER_DBM_50 10
+#define BCM4320_DEFAULT_TXPOWER_DBM_25 7
/* codes for "status" field of completion messages */
@@ -420,21 +426,30 @@ struct rndis_wlan_private {
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+
static struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
+ .set_wiphy_params = rndis_set_wiphy_params,
+ .set_tx_power = rndis_set_tx_power,
+ .get_tx_power = rndis_get_tx_power,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
-static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
static const unsigned char zero_bssid[ETH_ALEN] = {0,};
static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
@@ -447,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
}
-static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
+static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
{
- return BCM4320_DEFAULT_TXPOWER *
- bcm4320_power_output[priv->param_power_output] / 100;
+ switch (priv->param_power_output) {
+ default:
+ case 3:
+ return BCM4320_DEFAULT_TXPOWER_DBM_100;
+ case 2:
+ return BCM4320_DEFAULT_TXPOWER_DBM_75;
+ case 1:
+ return BCM4320_DEFAULT_TXPOWER_DBM_50;
+ case 0:
+ return BCM4320_DEFAULT_TXPOWER_DBM_25;
+ }
}
@@ -968,6 +992,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
}
+static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+
+ if (rts_threshold < 0 || rts_threshold > 2347)
+ rts_threshold = 2347;
+
+ tmp = cpu_to_le32(rts_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
+static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
+
+ if (frag_threshold < 256 || frag_threshold > 2346)
+ frag_threshold = 2346;
+
+ tmp = cpu_to_le32(frag_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
static void set_default_iw_params(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1222,20 +1276,14 @@ static void set_multicast_list(struct usbnet *usbdev)
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *dev;
- struct usbnet *usbdev;
+ struct usbnet *usbdev = netdev_priv(dev);
int mode;
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
- usbdev = netdev_priv(dev);
-
switch (type) {
case NL80211_IFTYPE_ADHOC:
mode = NDIS_80211_INFRA_ADHOC;
@@ -1251,6 +1299,64 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
}
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ int err;
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ err = set_frag_threshold(usbdev, wiphy->frag_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ err = set_rts_threshold(usbdev, wiphy->rts_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
+
+ /* Device doesn't support changing txpower after initialization, only
+ * turn off/on radio. Support 'auto' mode and setting same dBm that is
+ * currently used.
+ */
+ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+ if (!priv->radio_on)
+ disassociate(usbdev, 1); /* turn on radio */
+
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ *dbm = get_bcm4320_power_dbm(priv);
+
+ devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+
+ return 0;
+}
+
+
#define SCAN_DELAY_JIFFIES (HZ)
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request)
@@ -1766,74 +1872,6 @@ static int rndis_iw_get_genie(struct net_device *dev,
}
-static int rndis_iw_set_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- devdbg(usbdev, "SIOCSIWRTS");
-
- tmp = cpu_to_le32(wrqu->rts.value);
- return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
- if (ret == 0) {
- wrqu->rts.value = le32_to_cpu(tmp);
- wrqu->rts.flags = 1;
- wrqu->rts.disabled = 0;
- }
-
- devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
-
- return ret;
-}
-
-
-static int rndis_iw_set_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
-
- devdbg(usbdev, "SIOCSIWFRAG");
-
- tmp = cpu_to_le32(wrqu->frag.value);
- return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- &len);
- if (ret == 0) {
- wrqu->frag.value = le32_to_cpu(tmp);
- wrqu->frag.flags = 1;
- wrqu->frag.disabled = 0;
- }
- devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
- return ret;
-}
-
-
static int rndis_iw_set_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -1882,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev,
}
-static int rndis_iw_get_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power;
-
- if (priv->radio_on) {
- /* fake since changing tx_power (by userlevel) not supported */
- tx_power = cpu_to_le32(get_bcm4320_power(priv));
-
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = le32_to_cpu(tx_power);
- wrqu->txpower.disabled = 0;
- } else {
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = 0;
- wrqu->txpower.disabled = 1;
- }
-
- devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
-
- return 0;
-}
-
-
-static int rndis_iw_set_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power = 0;
-
- if (!wrqu->txpower.disabled) {
- if (wrqu->txpower.flags == IW_TXPOW_MWATT)
- tx_power = cpu_to_le32(wrqu->txpower.value);
- else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
- if (wrqu->txpower.value > 20)
- tx_power = cpu_to_le32(128);
- else if (wrqu->txpower.value < -43)
- tx_power = cpu_to_le32(127);
- else {
- signed char tmp;
- tmp = wrqu->txpower.value;
- tmp = -12 - tmp;
- tmp <<= 2;
- tx_power = cpu_to_le32((unsigned char)tmp);
- }
- }
- }
-
- devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
-
- if (le32_to_cpu(tx_power) != 0) {
- /* txpower unsupported, just turn radio on */
- if (!priv->radio_on)
- return disassociate(usbdev, 1);
- return 0; /* all ready on */
- }
-
- /* tx_power == 0, turn off radio */
- return disassociate(usbdev, 0);
-}
-
-
static int rndis_iw_get_rate(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -2022,12 +1995,12 @@ static const iw_handler rndis_iw_handler[] =
IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid,
IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid,
IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate,
- IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts,
- IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts,
- IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag,
- IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag,
- IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower,
- IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower,
+ IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts,
+ IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts,
+ IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag,
+ IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag,
+ IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower,
+ IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower,
IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode,
IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth,
@@ -2475,6 +2448,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
+ /* set default rts/frag */
+ rndis_set_wiphy_params(wiphy,
+ WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
+
/* turn radio on */
priv->radio_on = 1;
disassociate(usbdev, 1);
@@ -2522,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ devdbg(usbdev, "rndis_wlan_reset");
return deauthenticate(usbdev);
}
+static int rndis_wlan_stop(struct usbnet *usbdev)
+{
+ devdbg(usbdev, "rndis_wlan_stop");
+ return disassociate(usbdev, 0);
+}
+
+
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
@@ -2535,6 +2520,7 @@ static const struct driver_info bcm4320b_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2548,6 +2534,7 @@ static const struct driver_info bcm4320a_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2561,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 8aab3e6754bd..f970aa25326a 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
boolean
-config RT2X00_LIB_RFKILL
- boolean
- default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n)
- select INPUT_POLLDEV
-
-comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00"
- depends on RT2X00_LIB=y && INPUT=m
-
config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index bfc7226f0afe..13043ea97667 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 435f945fe64d..30185ad28d93 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2400pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
@@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1567,12 +1561,14 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index ec3b004ddc3c..ccd644104ad1 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -928,7 +928,7 @@
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 08b30d01e67d..3b3171578b14 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2500pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
@@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1866,12 +1860,14 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index ce2f065c7486..54d37957883c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1218,7 +1218,7 @@
#define RXD_W10_DROP FIELD32(0x00000001)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 66daf68ff0ee..de48c5c68eff 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
@@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
}
-#else
-#define rt2500usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
@@ -1550,7 +1546,9 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
- if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0)) {
+ if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
+ rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
@@ -1601,10 +1599,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be disabled.
@@ -1900,11 +1896,13 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 5bc46fe72179..b01edca42583 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -831,7 +831,7 @@
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37561667925b..9efb41710508 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
}
-#else
-#define rt2800usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2800usb_brightness_set(struct led_classdev *led_cdev,
@@ -1914,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time
- * to be fully awake and the radio can be enabled.
+ * to be fully awake and then the radio can be enabled.
*/
rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1);
@@ -1922,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
break;
case STATE_RADIO_OFF:
/*
- * After the radio has been disablee, the device should
+ * After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800usb_disable_radio(rt2x00dev);
@@ -2224,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2385,10 +2379,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Store led settings, for correct led behaviour.
@@ -2792,6 +2784,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800usb_get_tkip_seq,
@@ -2800,6 +2793,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.conf_tx = rt2800usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2800usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 61a8be61d3f5..2d9dc3783361 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -1921,7 +1921,7 @@ struct mac_iveiv_entry {
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_G_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index a498dde024e1..cbec91ef6f76 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -245,7 +245,7 @@ struct link_ant {
struct antenna_setup active;
/*
- * RSSI information for the different antenna's.
+ * RSSI information for the different antennas.
* These statistics are used to determine when
* to switch antenna when using software diversity.
*
@@ -594,7 +594,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements
@@ -634,7 +633,7 @@ struct rt2x00_dev {
* The structure stored in here depends on the
* system bus (PCI or USB).
* When accessing this variable, the rt2x00dev_{pci,usb}
- * macro's should be used for correct typecasting.
+ * macros should be used for correct typecasting.
*/
struct device *dev;
@@ -651,18 +650,6 @@ struct rt2x00_dev {
enum ieee80211_band curr_band;
/*
- * rfkill structure for RF state switching support.
- * This will only be compiled in when required.
- */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
- unsigned long rfkill_state;
-#define RFKILL_STATE_ALLOCATED 1
-#define RFKILL_STATE_REGISTERED 2
-#define RFKILL_STATE_BLOCKED 3
- struct input_polled_dev *rfkill_poll_dev;
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
- /*
* If enabled, the debugfs interface structures
* required for deregistration of debugfs.
*/
@@ -975,6 +962,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -992,6 +981,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 3e019a12df2e..3845316ccd39 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -124,7 +124,7 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
}
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+ struct antenna_setup ant)
{
struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active;
@@ -132,16 +132,16 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
/*
* Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver.
- * If that happes fallback to hardware default,
+ * If that happens, fallback to hardware defaults,
* or our own default.
* The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already
* active setting. If that has happened we can quit.
*/
- ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx);
- ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx);
+ ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx);
+ ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx);
- if (ant->rx == active->rx && ant->tx == active->tx)
+ if (ant.rx == active->rx && ant.tx == active->tx)
return;
/*
@@ -156,11 +156,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
- rt2x00dev->ops->lib->config_ant(rt2x00dev, ant);
+ rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant);
rt2x00link_reset_tuner(rt2x00dev, true);
- memcpy(active, ant, sizeof(*ant));
+ memcpy(active, &ant, sizeof(ant));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index bc4e81e21841..30fbd3bbe08b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !hw_key || entry->skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !key || skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
return overhead;
/*
@@ -131,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
- /* IV/EIV data has officially be stripped */
+ /* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 57813e72c808..658a63bfb761 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
/*
@@ -449,7 +448,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* mac80211 will clean up the skb structure.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
@@ -870,7 +870,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_register(rt2x00dev);
rt2x00leds_register(rt2x00dev);
- rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -902,7 +901,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Free extra components
*/
rt2x00debug_deregister(rt2x00dev);
- rt2x00rfkill_free(rt2x00dev);
rt2x00leds_unregister(rt2x00dev);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0bf2715fa93a..eeb2881e818e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -30,10 +30,8 @@
/*
* Interval defines
- * Both the link tuner as the rfkill will be called once per second.
*/
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
-#define RFKILL_POLL_INTERVAL 1000
/*
* rt2x00_rate: Per rate device information
@@ -90,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant);
+ struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
const unsigned int changed_flags);
@@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
/*
* RFkill handlers.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
-#else
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
-static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-}
-
-static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-}
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
/*
* LED handlers
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index eb9b981b9139..79915687e744 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/*
* During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
+ * from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
* performance, then there really is nothing for us
@@ -173,7 +173,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
@@ -213,7 +213,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
- rt2x00lib_config_antenna(rt2x00dev, &new_ant);
+ rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4c06b4e1f08..7de1a2cdcf8c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
- skb->do_not_encrypt = 1;
+ /* Disable hardware encryption */
+ rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
@@ -340,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
int status;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -377,7 +378,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
*/
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
rt2x00lib_config_antenna(rt2x00dev,
- &rt2x00dev->default_ant);
+ rt2x00dev->default_ant);
/* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
@@ -453,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
sizeof(crypto->rx_mic));
}
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00lib_beacondone(rt2x00dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
@@ -576,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
int update_bssid = 0;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -687,3 +698,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
+
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index b5e06347c8a7..47d175a13790 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -29,7 +29,7 @@
#include <linux/prefetch.h>
/**
- * DOC: Entrie frame size
+ * DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
@@ -45,13 +45,13 @@
/**
* DOC: Number of entries per queue
*
- * Under normal load without fragmentation 12 entries are sufficient
+ * Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code we need to add some additional margins to
+ * and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up
* completely.
- * Since we don't use preallocated DMA having a large number of queue entries
- * will have only minimal impact on the memory requirements for the queue.
+ * Since we don't use preallocated DMA, having a large number of queue entries
+ * will have minimal impact on the memory requirements for the queue.
*/
#define RX_ENTRIES 24
#define TX_ENTRIES 24
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 861322d97fce..983e52e127a7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -176,8 +176,8 @@ struct rt2x00_field32 {
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
- * Macro's to find first set bit in a variable.
- * These macro's behaves the same as the __ffs() function with
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
deleted file mode 100644
index b6d4c6700bf3..000000000000
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
- <http://rt2x00.serialmonkey.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the
- Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- Module: rt2x00rfkill
- Abstract: rt2x00 rfkill routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
-{
- struct rt2x00_dev *rt2x00dev = poll_dev->private;
- int state, old_state;
-
- if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- /*
- * Poll latest state, if the state is different then the previous state,
- * we should generate an input event.
- */
- state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
- old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-
- if (old_state != state) {
- input_report_switch(poll_dev->input, SW_RFKILL_ALL, state);
- change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
- }
-}
-
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) {
- ERROR(rt2x00dev, "Failed to register polled device.\n");
- return;
- }
-
- __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-
- /*
- * Force initial poll which will detect the initial device state,
- * and correctly sends the signal to the input layer about this
- * state.
- */
- rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev);
-}
-
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- input_unregister_polled_device(rt2x00dev->rfkill_poll_dev);
-
- __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
- struct input_polled_dev *poll_dev;
-
- if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- ERROR(rt2x00dev, "Failed to allocate polled device.\n");
- return;
- }
-
- poll_dev->private = rt2x00dev;
- poll_dev->poll = rt2x00rfkill_poll;
- poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
-
- poll_dev->input->name = rt2x00dev->ops->name;
- poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
- poll_dev->input->id.bustype = BUS_HOST;
- poll_dev->input->id.vendor = 0x1814;
- poll_dev->input->id.product = rt2x00dev->chip.rt;
- poll_dev->input->id.version = rt2x00dev->chip.rev;
- poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
- poll_dev->input->evbit[0] = BIT(EV_SW);
- poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL);
-
- rt2x00dev->rfkill_poll_dev = poll_dev;
-
- __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
- if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED,
- &rt2x00dev->rfkill_state))
- return;
-
- input_free_polled_device(rt2x00dev->rfkill_poll_dev);
- rt2x00dev->rfkill_poll_dev = NULL;
-}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 49b29ff90c47..fb95b8cc4fe9 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
}
-#else
-#define rt61pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt61pci_brightness_set(struct led_classdev *led_cdev,
@@ -2316,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
/*
- * Determine number of antenna's.
+ * Determine number of antennas.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset and RF programming sequence.
@@ -2722,12 +2716,14 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6c71f77c8165..93eb699165cc 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W15_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index c18848836f2d..4f9b1772e1a1 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT7);
}
-#else
-#define rt73usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt73usb_brightness_set(struct led_classdev *led_cdev,
@@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset.
@@ -2247,12 +2241,14 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index c8016f65b4bd..81fe0be51c42 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
/*
* EEPROM antenna.
- * ANTENNA_NUM: Number of antenna's.
+ * ANTENNA_NUM: Number of antennas.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W5_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 7e65d7c31802..09f46abc730a 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
@@ -280,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
(ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
- if (remainder > 0 && remainder <= 6)
+ if (remainder <= 6)
plcp_len |= 1 << 15;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 294250e294dd..c9b9dbe584c6 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.flag |= RX_FLAG_TSFT;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index b44253592243..cf9f899fe0e6 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -208,11 +208,12 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
- rtl8187_unregister_led(&priv->led_tx);
/* turn the LED off before exiting */
queue_delayed_work(dev->workqueue, &priv->led_off, 0);
cancel_delayed_work_sync(&priv->led_off);
+ cancel_delayed_work_sync(&priv->led_on);
rtl8187_unregister_led(&priv->led_rx);
+ rtl8187_unregister_led(&priv->led_tx);
}
#endif /* def CONFIG_RTL8187_LED */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a56b71f..73300c226f67 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index ab7fc5c0c8b4..5cb5329a20d1 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*********************** HARDWARE CONFIGURATION ***********************/
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index c6d300666ad8..b9748d432019 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
wv_packet_write(dev, skb->data, skb->len);
@@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return(0);
+ return NETDEV_TX_OK;
}
/********************** HARDWARE CONFIGURATION **********************/
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index a82c4cd436d8..82a0f97975de 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,11 +1,18 @@
-config WL12XX
- tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+menuconfig WL12XX
+ boolean "TI wl12xx driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable TI wl12xx driver support. The drivers make
+ use of the mac80211 stack.
+
+config WL1251
+ tristate "TI wl1251 support"
+ depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on
- TI wl1251/wl1271 chipsets.
+ TI wl1251 chipset.
- If you choose to build a module, it'll be called wl12xx. Say N if
+ If you choose to build a module, it'll be called wl1251. Say N if
unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index d43de27dc54c..d5595a841f5f 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,5 @@
-wl12xx-objs = main.o spi.o event.o tx.o rx.o \
- ps.o cmd.o acx.o boot.o init.o wl1251.o \
- debugfs.o
-obj-$(CONFIG_WL12XX) += wl12xx.o
+wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \
+ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+ wl1251_acx.o wl1251_boot.o wl1251_init.o \
+ wl1251_ops.o wl1251_debugfs.o
+obj-$(CONFIG_WL1251) += wl1251.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
deleted file mode 100644
index 1cfd458ad5ab..000000000000
--- a/drivers/net/wireless/wl12xx/acx.c
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "acx.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
- u8 mgt_rate, u8 mgt_mod)
-{
- int ret;
- struct acx_fw_gen_frame_rates rates;
-
- wl12xx_debug(DEBUG_ACX, "acx frame rates");
-
- rates.header.id = ACX_FW_GEN_FRAME_RATES;
- rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
- sizeof(struct acx_header);
-
- rates.tx_ctrl_frame_rate = ctrl_rate;
- rates.tx_ctrl_frame_mod = ctrl_mod;
- rates.tx_mgt_frame_rate = mgt_rate;
- rates.tx_mgt_frame_mod = mgt_mod;
-
- ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
- if (ret < 0) {
- wl12xx_error("Failed to set FW rates and modulation");
- return ret;
- }
-
- return 0;
-}
-
-
-int wl12xx_acx_station_id(struct wl12xx *wl)
-{
- int ret, i;
- struct dot11_station_id mac;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
-
- mac.header.id = DOT11_STATION_ID;
- mac.header.len = sizeof(mac) - sizeof(struct acx_header);
-
- for (i = 0; i < ETH_ALEN; i++)
- mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
-
- ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
-{
- struct acx_dot11_default_key default_key;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
-
- default_key.header.id = DOT11_DEFAULT_KEY;
- default_key.header.len = sizeof(default_key) -
- sizeof(struct acx_header);
-
- default_key.id = key_id;
-
- ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
- if (ret < 0) {
- wl12xx_error("Couldnt set default key");
- return ret;
- }
-
- wl->default_key = key_id;
-
- return 0;
-}
-
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
-{
- struct acx_wake_up_condition wake_up;
-
- wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
-
- wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
- wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
-
- wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
- wake_up.listen_interval = listen_interval;
-
- return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
-}
-
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
-{
- int ret;
- struct acx_sleep_auth auth;
-
- wl12xx_debug(DEBUG_ACX, "acx sleep auth");
-
- auth.header.id = ACX_SLEEP_AUTH;
- auth.header.len = sizeof(auth) - sizeof(struct acx_header);
-
- auth.sleep_auth = sleep_auth;
-
- ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
-{
- struct wl12xx_command cmd;
- struct acx_revision *rev;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx fw rev");
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return ret;
- }
-
- rev = (struct acx_revision *) &cmd.parameters;
-
- /* be careful with the buffer sizes */
- strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
- /*
- * if the firmware version string is exactly
- * sizeof(rev->fw_version) long or fw_len is less than
- * sizeof(rev->fw_version) it won't be null terminated
- */
- buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
- return 0;
-}
-
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
-{
- struct acx_current_tx_power ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
-
- if (power < 0 || power > 25)
- return -EINVAL;
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = DOT11_CUR_TX_PWR;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.current_tx_power = power * 10;
-
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("configure of tx power failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_feature_cfg(struct wl12xx *wl)
-{
- struct acx_feature_config feature;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx feature cfg");
-
- memset(&feature, 0, sizeof(feature));
-
- feature.header.id = ACX_FEATURE_CFG;
- feature.header.len = sizeof(feature) - sizeof(struct acx_header);
-
- /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
- feature.data_flow_options = 0;
- feature.options = 0;
-
- ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
- if (ret < 0)
- wl12xx_error("Couldnt set HW encryption");
-
- return ret;
-}
-
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
-{
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx mem map");
-
- ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
- if (ret < 0)
- return ret;
- else if (cmd.status != CMD_STATUS_SUCCESS)
- return -EIO;
-
- memcpy(mem_map, &cmd.parameters, len);
-
- return 0;
-}
-
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
- struct acx_data_path_params_resp *data_path)
-{
- struct acx_data_path_params params;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data path params");
-
- params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
- params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
-
- params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
- params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
-
- params.tx_complete_threshold = 1;
-
- params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
-
- params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
-
- params.header.id = ACX_DATA_PATH_PARAMS;
- params.header.len = sizeof(params) - sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
- if (ret < 0)
- return ret;
-
-
- ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
- sizeof(struct acx_data_path_params_resp),
- &cmd);
-
- if (ret < 0) {
- wl12xx_warning("failed to read data path parameters: %d", ret);
- return ret;
- } else if (cmd.status != CMD_STATUS_SUCCESS) {
- wl12xx_warning("data path parameter acx status failed");
- return -EIO;
- }
-
- memcpy(data_path, &cmd.parameters, sizeof(*data_path));
-
- return 0;
-}
-
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
-{
- struct rx_msdu_lifetime msdu_lifetime;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
-
- msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
- msdu_lifetime.header.len = sizeof(msdu_lifetime) -
- sizeof(struct acx_header);
- msdu_lifetime.lifetime = life_time;
-
- ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
- if (ret < 0) {
- wl12xx_warning("failed to set rx msdu life time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
- struct acx_rx_config rx_config;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx config");
-
- rx_config.header.id = ACX_RX_CFG;
- rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
- rx_config.config_options = config;
- rx_config.filter_options = filter;
-
- ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_pd_threshold(struct wl12xx *wl)
-{
- struct acx_packet_detection packet_detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
-
- /* FIXME: threshold value not set */
- packet_detection.header.id = ACX_PD_THRESHOLD;
- packet_detection.header.len = sizeof(packet_detection) -
- sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &packet_detection,
- sizeof(packet_detection));
- if (ret < 0) {
- wl12xx_warning("failed to set pd threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
-{
- struct acx_slot slot;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx slot");
-
- slot.header.id = ACX_SLOT;
- slot.header.len = sizeof(slot) - sizeof(struct acx_header);
-
- slot.wone_index = STATION_WONE_INDEX;
- slot.slot_time = slot_time;
-
- ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
- if (ret < 0) {
- wl12xx_warning("failed to set slot time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
-{
- struct multicast_grp_addr_start multicast;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx group address tbl");
-
- /* MAC filtering */
- multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
- multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
-
- multicast.enabled = 0;
- multicast.num_groups = 0;
- memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
-
- ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
- if (ret < 0) {
- wl12xx_warning("failed to set group addr table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
-{
- struct acx_rx_timeout rx_timeout;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx service period timeout");
-
- /* RX timeout */
- rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
- rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
-
- rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
-
- ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
- if (ret < 0) {
- wl12xx_warning("failed to set service period timeout: %d",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
-{
- struct acx_rts_threshold rts;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rts threshold");
-
- rts.header.id = DOT11_RTS_THRESHOLD;
- rts.header.len = sizeof(rts) - sizeof(struct acx_header);
-
- rts.threshold = rts_threshold;
-
- ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
- if (ret < 0) {
- wl12xx_warning("failed to set rts threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
-{
- struct acx_beacon_filter_option beacon_filter;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
-
- beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
- beacon_filter.header.len = sizeof(beacon_filter) -
- sizeof(struct acx_header);
-
- beacon_filter.enable = 0;
- beacon_filter.max_num_beacons = 0;
-
- ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter opt: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
-{
- struct acx_beacon_filter_ie_table ie_table;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
-
- ie_table.header.id = ACX_BEACON_FILTER_TABLE;
- ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
-
- ie_table.num_ie = 0;
- memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
-
- ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_enable(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex pta;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg enable");
-
- pta.header.id = ACX_SG_ENABLE;
- pta.header.len = sizeof(pta) - sizeof(struct acx_header);
-
- pta.enable = SG_ENABLE;
-
- ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
- if (ret < 0) {
- wl12xx_warning("failed to set softgemini enable: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_cfg(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex_param param;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg cfg");
-
- /* BT-WLAN coext parameters */
- param.header.id = ACX_SG_CFG;
- param.header.len = sizeof(param) - sizeof(struct acx_header);
-
- 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;
-
- ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
- if (ret < 0) {
- wl12xx_warning("failed to set sg config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_cca_threshold(struct wl12xx *wl)
-{
- struct acx_energy_detection detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx cca threshold");
-
- detection.header.id = ACX_CCA_THRESHOLD;
- detection.header.len = sizeof(detection) - sizeof(struct acx_header);
-
- detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection.tx_energy_detection = 0;
-
- ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
- if (ret < 0) {
- wl12xx_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
-{
- struct acx_beacon_broadcast bb;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
-
- bb.header.id = ACX_BCN_DTIM_OPTIONS;
- bb.header.len = sizeof(bb) - sizeof(struct acx_header);
-
- 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;
-
- ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
-{
- struct acx_aid acx_aid;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx aid");
-
- acx_aid.header.id = ACX_AID;
- acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
-
- acx_aid.aid = aid;
-
- ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
-{
- struct acx_event_mask mask;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
-
- mask.header.id = ACX_EVENT_MBOX_MASK;
- mask.header.len = sizeof(mask) - sizeof(struct acx_header);
-
- /* high event mask is unused */
- mask.high_event_mask = 0xffffffff;
-
- mask.event_mask = event_mask;
-
- ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
-{
- struct acx_preamble ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_PREAMBLE_TYPE;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.preamble = preamble;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of preamble failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
- enum acx_ctsprotect_type ctsprotect)
-{
- struct acx_ctsprotect ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_CTS_PROTECTION;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.ctsprotect = ctsprotect;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of ctsprotect failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
-{
- struct wl12xx_command *answer;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx statistics");
-
- answer = kmalloc(sizeof(*answer), GFP_KERNEL);
- if (!answer) {
- wl12xx_warning("could not allocate memory for acx statistics");
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
- answer);
- if (ret < 0) {
- wl12xx_warning("acx statistics failed: %d", ret);
- goto out;
- }
-
- memcpy(stats, answer->parameters, sizeof(*stats));
-
-out:
- kfree(answer);
- return ret;
-}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
deleted file mode 100644
index f73ab602b7ae..000000000000
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ /dev/null
@@ -1,353 +0,0 @@
-#include "cmd.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
-{
- struct wl12xx_command cmd;
- unsigned long timeout;
- size_t cmd_len;
- u32 intr;
- int ret = 0;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.id = type;
- cmd.status = 0;
- memcpy(cmd.parameters, buf, buf_len);
- cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN;
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
-
- timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- while (!(intr & wl->chip.intr_cmd_complete)) {
- if (time_after(jiffies, timeout)) {
- wl12xx_error("command complete timeout");
- ret = -ETIMEDOUT;
- goto out;
- }
-
- msleep(1);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- }
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
- wl->chip.intr_cmd_complete);
-
-out:
- wl12xx_ps_elp_sleep(wl);
-
- return ret;
-}
-
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd test");
-
- ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
- if (ret < 0) {
- wl12xx_warning("TEST command failed");
- return ret;
- }
-
- if (answer) {
- struct wl12xx_command *cmd_answer;
-
- /*
- * The test command got in, we can read the answer.
- * The answer would be a wl12xx_command, where the
- * parameter array contains the actual answer.
- */
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd_answer = buf;
- if (cmd_answer->status != CMD_STATUS_SUCCESS)
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
- }
-
- return 0;
-}
-
-
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer)
-{
- struct wl12xx_command *cmd;
- struct acx_header header;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd interrogate");
-
- header.id = ie_id;
- header.len = ie_len - sizeof(header);
-
- ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header));
- if (ret < 0) {
- wl12xx_error("INTERROGATE command failed");
- return ret;
- }
-
- wl12xx_ps_elp_wakeup(wl);
-
- /* the interrogate command got in, we can read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
- CMDMBOX_HEADER_LEN + ie_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd = answer;
- if (cmd->status != CMD_STATUS_SUCCESS)
- wl12xx_error("INTERROGATE command error: %d",
- cmd->status);
-
- return 0;
-
-}
-
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd configure");
-
- ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie,
- ie_len);
- if (ret < 0) {
- wl12xx_warning("CONFIGURE command NOK");
- return ret;
- }
-
- return 0;
-
-}
-
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
- void *bitmap, u16 bitmap_len, u8 bitmap_control)
-{
- struct vbm_update_request vbm;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd vbm");
-
- /* Count and period will be filled by the target */
- vbm.tim.bitmap_ctrl = bitmap_control;
- if (bitmap_len > PARTIAL_VBM_MAX) {
- wl12xx_warning("cmd vbm len is %d B, truncating to %d",
- bitmap_len, PARTIAL_VBM_MAX);
- bitmap_len = PARTIAL_VBM_MAX;
- }
- memcpy(vbm.tim.pvb_field, bitmap, bitmap_len);
- vbm.tim.identity = identity;
- vbm.tim.length = bitmap_len + 3;
-
- vbm.len = cpu_to_le16(bitmap_len + 5);
-
- ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm));
- if (ret < 0) {
- wl12xx_error("VBM command failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable)
-{
- int ret;
- u16 cmd_rx, cmd_tx;
-
- wl12xx_debug(DEBUG_CMD, "cmd data path");
-
- if (enable) {
- cmd_rx = CMD_ENABLE_RX;
- cmd_tx = CMD_ENABLE_TX;
- } else {
- cmd_rx = CMD_DISABLE_RX;
- cmd_tx = CMD_DISABLE_TX;
- }
-
- ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("rx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("tx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- return 0;
-}
-
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
-{
- unsigned long timeout;
- struct cmd_join join = {};
- int ret, i;
- u8 *bssid;
-
- /* FIXME: this should be in main.c */
- ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
- DEFAULT_HW_GEN_MODULATION_TYPE,
- wl->tx_mgmt_frm_rate,
- wl->tx_mgmt_frm_mod);
- if (ret < 0)
- return ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd join");
-
- /* Reverse order BSSID */
- bssid = (u8 *)&join.bssid_lsb;
- 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.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
-
- join.beacon_interval = beacon_interval;
- join.dtim_interval = dtim_interval;
- join.bss_type = bss_type;
- join.channel = wl->channel;
- join.ctrl = JOIN_CMD_CTRL_TX_FLUSH;
-
- ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join));
- if (ret < 0) {
- wl12xx_error("failed to initiate cmd join");
- return ret;
- }
-
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
-
- /*
- * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
- * simplify locking we just sleep instead, for now
- */
- if (wait)
- msleep(10);
-
- return 0;
-}
-
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
-{
- int ret;
- struct acx_ps_params ps_params;
-
- /* FIXME: this should be in ps.c */
- ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int);
- if (ret < 0) {
- wl12xx_error("Couldnt set wake up conditions");
- return ret;
- }
-
- wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
-
- ps_params.ps_mode = 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 */
-
- ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params,
- sizeof(ps_params));
- if (ret < 0) {
- wl12xx_error("cmd set_ps_mode failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
-{
- struct cmd_read_write_memory mem_cmd, *mem_answer;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd read memory");
-
- memset(&mem_cmd, 0, sizeof(mem_cmd));
- mem_cmd.addr = addr;
- mem_cmd.size = len;
-
- ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd));
- if (ret < 0) {
- wl12xx_error("read memory command failed: %d", ret);
- return ret;
- }
-
- /* the read command got in, we can now read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
- CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
-
- if (cmd.status != CMD_STATUS_SUCCESS)
- wl12xx_error("error in read command result: %d", cmd.status);
-
- mem_answer = (struct cmd_read_write_memory *) cmd.parameters;
- memcpy(answer, mem_answer->value, len);
-
- return 0;
-}
-
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
- void *buf, size_t buf_len)
-{
- struct wl12xx_cmd_packet_template template;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
-
- memset(&template, 0, sizeof(template));
-
- WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
- buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
- template.size = cpu_to_le16(buf_len);
-
- if (buf)
- memcpy(template.template, buf, buf_len);
-
- ret = wl12xx_cmd_send(wl, cmd_id, &template,
- sizeof(template.size) + buf_len);
- if (ret < 0) {
- wl12xx_warning("cmd set_template failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index e421643215cd..2de47cc32b8b 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -26,7 +26,6 @@
#define __REG_H__
#include <linux/bitops.h>
-#include "wl12xx.h"
#define REGISTERS_BASE 0x00300000
#define DRPW_BASE 0x00310000
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 1f4a44330394..665aca02bea9 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -1,7 +1,8 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Kalle Valo <kalle.valo@nokia.com>
*
@@ -24,142 +25,396 @@
#ifndef __WL1251_H__
#define __WL1251_H__
+#include <linux/mutex.h>
+#include <linux/list.h>
#include <linux/bitops.h>
-
-#include "wl12xx.h"
-#include "acx.h"
-
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
-
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-
-void wl1251_setup(struct wl12xx *wl);
-
-
-struct wl1251_acx_memory {
- __le16 num_stations; /* number of STAs to be supported. */
- u16 reserved_1;
+#include <net/mac80211.h>
+
+#define DRIVER_NAME "wl1251"
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+ DEBUG_NONE = 0,
+ DEBUG_IRQ = BIT(0),
+ DEBUG_SPI = BIT(1),
+ DEBUG_BOOT = BIT(2),
+ DEBUG_MAILBOX = BIT(3),
+ DEBUG_NETLINK = BIT(4),
+ DEBUG_EVENT = BIT(5),
+ DEBUG_TX = BIT(6),
+ DEBUG_RX = BIT(7),
+ DEBUG_SCAN = BIT(8),
+ DEBUG_CRYPT = BIT(9),
+ DEBUG_PSM = BIT(10),
+ DEBUG_MAC80211 = BIT(11),
+ DEBUG_CMD = BIT(12),
+ DEBUG_ACX = BIT(13),
+ DEBUG_ALL = ~0,
+};
+
+#define DEBUG_LEVEL (DEBUG_NONE)
+
+#define DEBUG_DUMP_LIMIT 1024
+
+#define wl1251_error(fmt, arg...) \
+ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define wl1251_warning(fmt, arg...) \
+ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define wl1251_notice(fmt, arg...) \
+ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_info(fmt, arg...) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_debug(level, fmt, arg...) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ } while (0)
+
+#define wl1251_dump(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
+ } while (0)
+
+#define wl1251_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
+ } while (0)
+
+#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
+ CFG_BSSID_FILTER_EN)
+
+#define WL1251_DEFAULT_RX_FILTER (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 WL1251_BUSY_WORD_LEN 8
+
+struct boot_attr {
+ u32 radio_type;
+ u8 mac_clock;
+ u8 arm_clock;
+ int firmware_debug;
+ u32 minor;
+ u32 major;
+ u32 bugfix;
+};
+
+enum wl1251_state {
+ WL1251_STATE_OFF,
+ WL1251_STATE_ON,
+ WL1251_STATE_PLT,
+};
+
+enum wl1251_partition_type {
+ PART_DOWN,
+ PART_WORK,
+ PART_DRPW,
+
+ PART_TABLE_LEN
+};
+
+struct wl1251_partition {
+ u32 size;
+ u32 start;
+};
+
+struct wl1251_partition_set {
+ struct wl1251_partition mem;
+ struct wl1251_partition reg;
+};
+
+struct wl1251;
+
+/* FIXME: I'm not sure about this structure name */
+struct wl1251_chip {
+ u32 id;
+
+ const char *fw_filename;
+ const char *nvs_filename;
+
+ char fw_ver[21];
+
+ unsigned int power_on_sleep;
+ int intr_cmd_complete;
+ int intr_init_complete;
+
+ int (*op_upload_fw)(struct wl1251 *wl);
+ int (*op_upload_nvs)(struct wl1251 *wl);
+ int (*op_boot)(struct wl1251 *wl);
+ void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag);
+ void (*op_target_enable_interrupts)(struct wl1251 *wl);
+ int (*op_hw_init)(struct wl1251 *wl);
+ int (*op_plt_init)(struct wl1251 *wl);
+ void (*op_tx_flush)(struct wl1251 *wl);
+ void (*op_fw_version)(struct wl1251 *wl);
+ int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait);
+
+ struct wl1251_partition_set *p_table;
+ enum wl12xx_acx_int_reg *acx_reg_table;
+};
+
+struct wl1251_stats {
+ struct acx_statistics *fw_stats;
+ unsigned long fw_stats_update;
+
+ unsigned int retry_count;
+ unsigned int excessive_retries;
+};
+
+struct wl1251_debugfs {
+ struct dentry *rootdir;
+ struct dentry *fw_statistics;
+
+ struct dentry *tx_internal_desc_overflow;
+
+ struct dentry *rx_out_of_mem;
+ struct dentry *rx_hdr_overflow;
+ struct dentry *rx_hw_stuck;
+ struct dentry *rx_dropped;
+ struct dentry *rx_fcs_err;
+ struct dentry *rx_xfr_hint_trig;
+ struct dentry *rx_path_reset;
+ struct dentry *rx_reset_counter;
+
+ struct dentry *dma_rx_requested;
+ struct dentry *dma_rx_errors;
+ struct dentry *dma_tx_requested;
+ struct dentry *dma_tx_errors;
+
+ struct dentry *isr_cmd_cmplt;
+ struct dentry *isr_fiqs;
+ struct dentry *isr_rx_headers;
+ struct dentry *isr_rx_mem_overflow;
+ struct dentry *isr_rx_rdys;
+ struct dentry *isr_irqs;
+ struct dentry *isr_tx_procs;
+ struct dentry *isr_decrypt_done;
+ struct dentry *isr_dma0_done;
+ struct dentry *isr_dma1_done;
+ struct dentry *isr_tx_exch_complete;
+ struct dentry *isr_commands;
+ struct dentry *isr_rx_procs;
+ struct dentry *isr_hw_pm_mode_changes;
+ struct dentry *isr_host_acknowledges;
+ struct dentry *isr_pci_pm;
+ struct dentry *isr_wakeups;
+ struct dentry *isr_low_rssi;
+
+ struct dentry *wep_addr_key_count;
+ struct dentry *wep_default_key_count;
+ /* skipping wep.reserved */
+ struct dentry *wep_key_not_found;
+ struct dentry *wep_decrypt_fail;
+ struct dentry *wep_packets;
+ struct dentry *wep_interrupt;
+
+ struct dentry *pwr_ps_enter;
+ struct dentry *pwr_elp_enter;
+ struct dentry *pwr_missing_bcns;
+ struct dentry *pwr_wake_on_host;
+ struct dentry *pwr_wake_on_timer_exp;
+ struct dentry *pwr_tx_with_ps;
+ struct dentry *pwr_tx_without_ps;
+ struct dentry *pwr_rcvd_beacons;
+ struct dentry *pwr_power_save_off;
+ struct dentry *pwr_enable_ps;
+ struct dentry *pwr_disable_ps;
+ struct dentry *pwr_fix_tsf_ps;
+ /* skipping cont_miss_bcns_spread for now */
+ struct dentry *pwr_rcvd_awake_beacons;
+
+ struct dentry *mic_rx_pkts;
+ struct dentry *mic_calc_failure;
+
+ struct dentry *aes_encrypt_fail;
+ struct dentry *aes_decrypt_fail;
+ struct dentry *aes_encrypt_packets;
+ struct dentry *aes_decrypt_packets;
+ struct dentry *aes_encrypt_interrupt;
+ struct dentry *aes_decrypt_interrupt;
+
+ struct dentry *event_heart_beat;
+ struct dentry *event_calibration;
+ struct dentry *event_rx_mismatch;
+ struct dentry *event_rx_mem_empty;
+ struct dentry *event_rx_pool;
+ struct dentry *event_oom_late;
+ struct dentry *event_phy_transmit_error;
+ struct dentry *event_tx_stuck;
+
+ struct dentry *ps_pspoll_timeouts;
+ struct dentry *ps_upsd_timeouts;
+ struct dentry *ps_upsd_max_sptime;
+ struct dentry *ps_upsd_max_apturn;
+ struct dentry *ps_pspoll_max_apturn;
+ struct dentry *ps_pspoll_utilization;
+ struct dentry *ps_upsd_utilization;
+
+ struct dentry *rxpipe_rx_prep_beacon_drop;
+ struct dentry *rxpipe_descr_host_int_trig_rx_data;
+ struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
+ struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
+ struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
+
+ struct dentry *tx_queue_len;
+
+ struct dentry *retry_count;
+ struct dentry *excessive_retries;
+};
+
+struct wl1251 {
+ struct ieee80211_hw *hw;
+ bool mac80211_registered;
+
+ struct spi_device *spi;
+
+ void (*set_power)(bool enable);
+ int irq;
+
+ enum wl1251_state state;
+ struct mutex mutex;
+
+ int physical_mem_addr;
+ int physical_reg_addr;
+ int virtual_mem_addr;
+ int virtual_reg_addr;
+
+ struct wl1251_chip chip;
+
+ int cmd_box_addr;
+ int event_box_addr;
+ struct boot_attr boot_attr;
+
+ u8 *fw;
+ size_t fw_len;
+ u8 *nvs;
+ size_t nvs_len;
+
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+ u8 bss_type;
+ u8 listen_int;
+ int channel;
+
+ void *target_mem_map;
+ struct acx_data_path_params_resp *data_path;
+
+ /* Number of TX packets transferred to the FW, modulo 16 */
+ u32 data_in_count;
+
+ /* Frames scheduled for transmission, not handled yet */
+ struct sk_buff_head tx_queue;
+ bool tx_queue_stopped;
+
+ struct work_struct tx_work;
+ struct work_struct filter_work;
+
+ /* Pending TX frames */
+ struct sk_buff *tx_frames[16];
/*
- * Nmber of memory buffers for the RX mem pool.
- * The actual number may be less if there are
- * not enough blocks left for the minimum num
- * of TX ones.
+ * Index pointing to the next TX complete entry
+ * in the cyclic XT complete array we get from
+ * the FW.
*/
- u8 rx_mem_block_num;
- u8 reserved_2;
- u8 num_tx_queues; /* From 1 to 16 */
- u8 host_if_options; /* HOST_IF* */
- u8 tx_min_mem_block_num;
- u8 num_ssid_profiles;
- __le16 debug_buffer_size;
-} __attribute__ ((packed));
-
-
-#define ACX_RX_DESC_MIN 1
-#define ACX_RX_DESC_MAX 127
-#define ACX_RX_DESC_DEF 32
-struct wl1251_acx_rx_queue_config {
- u8 num_descs;
- u8 pad;
- u8 type;
- u8 priority;
- __le32 dma_address;
-} __attribute__ ((packed));
-
-#define ACX_TX_DESC_MIN 1
-#define ACX_TX_DESC_MAX 127
-#define ACX_TX_DESC_DEF 16
-struct wl1251_acx_tx_queue_config {
- u8 num_descs;
- u8 pad[2];
- u8 attributes;
-} __attribute__ ((packed));
-
-#define MAX_TX_QUEUE_CONFIGS 5
-#define MAX_TX_QUEUES 4
-struct wl1251_acx_config_memory {
- struct acx_header header;
-
- struct wl1251_acx_memory mem_config;
- struct wl1251_acx_rx_queue_config rx_queue_config;
- struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
-
-struct wl1251_acx_mem_map {
- struct acx_header header;
-
- void *code_start;
- void *code_end;
-
- void *wep_defkey_start;
- void *wep_defkey_end;
+ u32 next_tx_complete;
- void *sta_table_start;
- void *sta_table_end;
+ /* FW Rx counter */
+ u32 rx_counter;
- void *packet_template_start;
- void *packet_template_end;
+ /* Rx frames handled */
+ u32 rx_handled;
- void *queue_memory_start;
- void *queue_memory_end;
+ /* Current double buffer */
+ u32 rx_current_buffer;
+ u32 rx_last_id;
- void *packet_memory_pool_start;
- void *packet_memory_pool_end;
+ /* The target interrupt mask */
+ u32 intr_mask;
+ struct work_struct irq_work;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ /* The mbox event mask */
+ u32 event_mask;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ /* Mailbox pointers */
+ u32 mbox_ptr[2];
- /* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ /* Are we currently scanning */
+ bool scanning;
- /* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+ /* Our association ID */
+ u16 aid;
-/*************************************************************************
+ /* Default key (for WEP) */
+ u32 default_key;
- Host Interrupt Register (WiLink -> Host)
+ unsigned int tx_mgmt_frm_rate;
+ unsigned int tx_mgmt_frm_mod;
-**************************************************************************/
+ unsigned int rx_config;
+ unsigned int rx_filter;
-/* RX packet is ready in Xfer buffer #0 */
-#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+ /* is firmware in elp mode */
+ bool elp;
-/* TX result(s) are in the TX complete buffer */
-#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+ /* we can be in psm, but not in elp, we have to differentiate */
+ bool psm;
-/* OBSOLETE */
-#define WL1251_ACX_INTR_TX_XFR BIT(2)
+ /* PSM mode requested */
+ bool psm_requested;
-/* RX packet is ready in Xfer buffer #1 */
-#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+ /* in dBm */
+ int power_level;
-/* Event was entered to Event MBOX #A */
-#define WL1251_ACX_INTR_EVENT_A BIT(4)
+ struct wl1251_stats stats;
+ struct wl1251_debugfs debugfs;
-/* Event was entered to Event MBOX #B */
-#define WL1251_ACX_INTR_EVENT_B BIT(5)
+ u32 buffer_32;
+ u32 buffer_cmd;
+ u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
+ struct wl1251_rx_descriptor *rx_descriptor;
+};
-/* OBSOLETE */
-#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+int wl1251_plt_start(struct wl1251 *wl);
+int wl1251_plt_stop(struct wl1251 *wl);
-/* Trace meassge on MBOX #A */
-#define WL1251_ACX_INTR_TRACE_A BIT(7)
+#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
+#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-/* Trace meassge on MBOX #B */
-#define WL1251_ACX_INTR_TRACE_B BIT(8)
+#define WL1251_DEFAULT_POWER_LEVEL 20
-/* Command processing completion */
-#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+#define WL1251_TX_QUEUE_MAX_LENGTH 20
-/* Init sequence is done */
-#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+/* Different chips need different sleep times after power on. WL1271 needs
+ * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
+ * know the chip ID, we change the sleep value in the wl1251 chip structure,
+ * so in subsequent power ons, we don't waste more time then needed. */
+#define WL1251_DEFAULT_POWER_ON_SLEEP 200
-#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+#define CHIP_ID_1251_PG10 (0x7010101)
+#define CHIP_ID_1251_PG11 (0x7020101)
+#define CHIP_ID_1251_PG12 (0x7030101)
+#define CHIP_ID_1271_PG10 (0x4030101)
+#define CHIP_ID_1271_PG20 (0x4030111)
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
new file mode 100644
index 000000000000..a46c92a29526
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -0,0 +1,840 @@
+#include "wl1251_acx.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
+ u8 mgt_rate, u8 mgt_mod)
+{
+ struct acx_fw_gen_frame_rates *rates;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx frame rates");
+
+ rates = kzalloc(sizeof(*rates), GFP_KERNEL);
+ if (!rates) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rates->tx_ctrl_frame_rate = ctrl_rate;
+ rates->tx_ctrl_frame_mod = ctrl_mod;
+ rates->tx_mgt_frame_rate = mgt_rate;
+ rates->tx_mgt_frame_mod = mgt_mod;
+
+ ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES,
+ rates, sizeof(*rates));
+ if (ret < 0) {
+ wl1251_error("Failed to set FW rates and modulation");
+ goto out;
+ }
+
+out:
+ kfree(rates);
+ return ret;
+}
+
+
+int wl1251_acx_station_id(struct wl1251 *wl)
+{
+ struct acx_dot11_station_id *mac;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
+
+ mac = kzalloc(sizeof(*mac), GFP_KERNEL);
+ if (!mac) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
+
+ ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
+ if (ret < 0)
+ goto out;
+
+out:
+ kfree(mac);
+ return ret;
+}
+
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
+{
+ struct acx_dot11_default_key *default_key;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
+
+ default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
+ if (!default_key) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ default_key->id = key_id;
+
+ ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
+ default_key, sizeof(*default_key));
+ if (ret < 0) {
+ wl1251_error("Couldn't set default key");
+ goto out;
+ }
+
+ wl->default_key = key_id;
+
+out:
+ kfree(default_key);
+ return ret;
+}
+
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval)
+{
+ struct acx_wake_up_condition *wake_up;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx wake up conditions");
+
+ wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+ if (!wake_up) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
+
+ ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+ wake_up, sizeof(*wake_up));
+ if (ret < 0) {
+ wl1251_warning("could not set wake up conditions: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(wake_up);
+ return ret;
+}
+
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
+{
+ struct acx_sleep_auth *auth;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sleep auth");
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ auth->sleep_auth = sleep_auth;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+ if (ret < 0)
+ return ret;
+
+out:
+ kfree(auth);
+ return ret;
+}
+
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
+{
+ struct acx_revision *rev;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx fw rev");
+
+ rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ if (!rev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ /* be careful with the buffer sizes */
+ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+ /*
+ * if the firmware version string is exactly
+ * sizeof(rev->fw_version) long or fw_len is less than
+ * sizeof(rev->fw_version) it won't be null terminated
+ */
+ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+ kfree(rev);
+ return ret;
+}
+
+int wl1251_acx_tx_power(struct wl1251 *wl, int power)
+{
+ struct acx_current_tx_power *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+ if (power < 0 || power > 25)
+ return -EINVAL;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->current_tx_power = power * 10;
+
+ ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("configure of tx power failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_feature_cfg(struct wl1251 *wl)
+{
+ struct acx_feature_config *feature;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx feature cfg");
+
+ feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+ if (!feature) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->data_flow_options = 0;
+ feature->options = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
+ feature, sizeof(*feature));
+ if (ret < 0) {
+ wl1251_error("Couldn't set HW encryption");
+ goto out;
+ }
+
+out:
+ kfree(feature);
+ return ret;
+}
+
+int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map,
+ size_t len)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx mem map");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_acx_data_path_params(struct wl1251 *wl,
+ struct acx_data_path_params_resp *resp)
+{
+ struct acx_data_path_params *params;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data path params");
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
+ params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
+
+ params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
+ params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
+
+ params->tx_complete_threshold = 1;
+
+ params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
+
+ params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
+
+ ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS,
+ params, sizeof(*params));
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */
+ ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
+ resp, sizeof(*resp));
+
+ if (ret < 0) {
+ wl1251_warning("failed to read data path parameters: %d", ret);
+ goto out;
+ } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) {
+ wl1251_warning("data path parameter acx status failed");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
+{
+ struct acx_rx_msdu_lifetime *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->lifetime = life_time;
+ ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx msdu life time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+ struct acx_rx_config *rx_config;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx config");
+
+ rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+ if (!rx_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_config->config_options = config;
+ rx_config->filter_options = filter;
+
+ ret = wl1251_cmd_configure(wl, ACX_RX_CFG,
+ rx_config, sizeof(*rx_config));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_config);
+ return ret;
+}
+
+int wl1251_acx_pd_threshold(struct wl1251 *wl)
+{
+ struct acx_packet_detection *pd;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data pd threshold");
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: threshold value not set */
+
+ ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+ if (ret < 0) {
+ wl1251_warning("failed to set pd threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pd);
+ return 0;
+}
+
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
+{
+ struct acx_slot *slot;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx slot");
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ slot->wone_index = STATION_WONE_INDEX;
+ slot->slot_time = slot_time;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+ if (ret < 0) {
+ wl1251_warning("failed to set slot time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(slot);
+ return ret;
+}
+
+int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+{
+ struct acx_dot11_grp_addr_tbl *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx group address tbl");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* MAC filtering */
+ acx->enabled = 0;
+ acx->num_groups = 0;
+ memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+ ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set group addr table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_service_period_timeout(struct wl1251 *wl)
+{
+ struct acx_rx_timeout *rx_timeout;
+ int ret;
+
+ rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+ if (!rx_timeout) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1251_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;
+
+ ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+ rx_timeout, sizeof(*rx_timeout));
+ if (ret < 0) {
+ wl1251_warning("failed to set service period timeout: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_timeout);
+ return ret;
+}
+
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
+{
+ struct acx_rts_threshold *rts;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rts threshold");
+
+ rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+ if (!rts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rts->threshold = rts_threshold;
+
+ ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+ if (ret < 0) {
+ wl1251_warning("failed to set rts threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rts);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_option *beacon_filter;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
+
+ beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+ if (!beacon_filter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ beacon_filter->enable = 0;
+ beacon_filter->max_num_beacons = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+ beacon_filter, sizeof(*beacon_filter));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter opt: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(beacon_filter);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_ie_table *ie_table;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter table");
+
+ ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+ if (!ie_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ie_table->num_ie = 0;
+ memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+ ie_table, sizeof(*ie_table));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(ie_table);
+ return ret;
+}
+
+int wl1251_acx_sg_enable(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex *pta;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg enable");
+
+ pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+ if (!pta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pta->enable = SG_ENABLE;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+ if (ret < 0) {
+ wl1251_warning("failed to set softgemini enable: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pta);
+ return ret;
+}
+
+int wl1251_acx_sg_cfg(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex_param *param;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* 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;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1251_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1251_acx_cca_threshold(struct wl1251 *wl)
+{
+ struct acx_energy_detection *detection;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx cca threshold");
+
+ detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+ if (!detection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+ detection->tx_energy_detection = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
+ detection, sizeof(*detection));
+ if (ret < 0) {
+ wl1251_warning("failed to set cca threshold: %d", ret);
+ return ret;
+ }
+
+out:
+ kfree(detection);
+ return ret;
+}
+
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
+{
+ struct acx_beacon_broadcast *bb;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb) {
+ ret = -ENOMEM;
+ 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;
+
+ ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bb);
+ return ret;
+}
+
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
+{
+ struct acx_aid *acx_aid;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx aid");
+
+ acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+ if (!acx_aid) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx_aid->aid = aid;
+
+ ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+ if (ret < 0) {
+ wl1251_warning("failed to set aid: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx_aid);
+ return ret;
+}
+
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
+{
+ struct acx_event_mask *mask;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx event mbox mask");
+
+ mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* high event mask is unused */
+ mask->high_event_mask = 0xffffffff;
+
+ mask->event_mask = event_mask;
+
+ ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+ mask, sizeof(*mask));
+ if (ret < 0) {
+ wl1251_warning("failed to set acx_event_mbox_mask: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mask);
+ return ret;
+}
+
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
+{
+ struct acx_preamble *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_preamble");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->preamble = preamble;
+
+ ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of preamble failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_cts_protect(struct wl1251 *wl,
+ enum acx_ctsprotect_type ctsprotect)
+{
+ struct acx_ctsprotect *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ctsprotect = ctsprotect;
+
+ ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of ctsprotect failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
+{
+ struct acx_tsf_info *tsf_info;
+ int ret;
+
+ tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+ if (!tsf_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
+ tsf_info, sizeof(*tsf_info));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ *mactime = tsf_info->current_tsf_lsb |
+ (tsf_info->current_tsf_msb << 31);
+
+out:
+ kfree(tsf_info);
+ return ret;
+}
+
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx statistics");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats,
+ sizeof(*stats));
+ if (ret < 0) {
+ wl1251_warning("acx statistics failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index fb2d2340993c..2e7b1933a8f9 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,14 +22,20 @@
*
*/
-#ifndef __WL12XX_ACX_H__
-#define __WL12XX_ACX_H__
+#ifndef __WL1251_ACX_H__
+#define __WL1251_ACX_H__
-#include "wl12xx.h"
+#include "wl1251.h"
+#include "wl1251_cmd.h"
/* Target's information element */
struct acx_header {
+ struct wl1251_cmd_header cmd;
+
+ /* acx (or information element) header */
u16 id;
+
+ /* payload length (not including headers */
u16 len;
};
@@ -85,15 +91,15 @@ struct acx_revision {
u32 hw_version;
} __attribute__ ((packed));
-enum wl12xx_psm_mode {
+enum wl1251_psm_mode {
/* Active mode */
- WL12XX_PSM_CAM = 0,
+ WL1251_PSM_CAM = 0,
/* Power save mode */
- WL12XX_PSM_PS = 1,
+ WL1251_PSM_PS = 1,
/* Extreme low power */
- WL12XX_PSM_ELP = 2,
+ WL1251_PSM_ELP = 2,
};
struct acx_sleep_auth {
@@ -107,25 +113,6 @@ struct acx_sleep_auth {
u8 padding[3];
} __attribute__ ((packed));
-#define TIM_ELE_ID 5
-#define PARTIAL_VBM_MAX 251
-
-struct tim {
- u8 identity;
- u8 length;
- u8 dtim_count;
- u8 dtim_period;
- u8 bitmap_ctrl;
- u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
-
-/* Virtual Bit Map update */
-struct vbm_update_request {
- __le16 len;
- u8 padding[2];
- struct tim tim;
-} __attribute__ ((packed));
-
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
HOSTIF_PCI_MASTER_HOST_DIRECT,
@@ -202,7 +189,7 @@ struct acx_data_path_params_resp {
#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF
#define RX_MSDU_LIFETIME_DEF 512000
-struct rx_msdu_lifetime {
+struct acx_rx_msdu_lifetime {
struct acx_header header;
/*
@@ -368,7 +355,7 @@ struct acx_slot {
#define ADDRESS_GROUP_MAX (8)
#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
-struct multicast_grp_addr_start {
+struct acx_dot11_grp_addr_tbl {
struct acx_header header;
u8 enabled;
@@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates {
} __attribute__ ((packed));
/* STA MAC */
-struct dot11_station_id {
+struct acx_dot11_station_id {
struct acx_header header;
u8 mac[ETH_ALEN];
u8 pad[2];
} __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
-
struct acx_feature_config {
struct acx_header header;
@@ -753,67 +731,6 @@ struct acx_feature_config {
u32 data_flow_options;
} __attribute__ ((packed));
-enum acx_key_action {
- KEY_ADD_OR_REPLACE = 1,
- KEY_REMOVE = 2,
- KEY_SET_ID = 3,
- MAX_KEY_ACTION = 0xffff,
-};
-
-enum acx_key_type {
- KEY_WEP_DEFAULT = 0,
- KEY_WEP_ADDR = 1,
- KEY_AES_GROUP = 4,
- KEY_AES_PAIRWISE = 5,
- KEY_WEP_GROUP = 6,
- KEY_TKIP_MIC_GROUP = 10,
- KEY_TKIP_MIC_PAIRWISE = 11,
-};
-
-/*
- *
- * key_type_e key size key format
- * ---------- --------- ----------
- * 0x00 5, 13, 29 Key data
- * 0x01 5, 13, 29 Key data
- * 0x04 16 16 bytes of key data
- * 0x05 16 16 bytes of key data
- * 0x0a 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- * 0x0b 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- *
- */
-
-struct acx_set_key {
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- u16 key_action;
-
- u16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
struct acx_current_tx_power {
struct acx_header header;
@@ -839,26 +756,6 @@ struct acx_tsf_info {
u8 pad[3];
} __attribute__ ((packed));
-/* 802.11 PS */
-enum acx_ps_mode {
- STATION_ACTIVE_MODE,
- STATION_POWER_SAVE_MODE
-};
-
-struct acx_ps_params {
- u8 ps_mode; /* STATION_* */
- u8 send_null_data; /* Do we have to send NULL data packet ? */
- u8 retries; /* Number of retires for the initial NULL data packet */
-
- /*
- * TUs during which the target stays awake after switching
- * to power save mode.
- */
- u8 hang_over_period;
- u16 null_data_rate;
- u8 pad[2];
-} __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*/
@@ -892,6 +789,7 @@ enum acx_preamble_type {
struct acx_preamble {
struct acx_header header;
+
/*
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
@@ -1210,36 +1108,39 @@ enum {
};
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod);
-int wl12xx_acx_station_id(struct wl12xx *wl);
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id);
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval);
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth);
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len);
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power);
-int wl12xx_acx_feature_cfg(struct wl12xx *wl);
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len);
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
+int wl1251_acx_station_id(struct wl1251 *wl);
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id);
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval);
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
+int wl1251_acx_tx_power(struct wl1251 *wl, int power);
+int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_mem_map(struct wl1251 *wl,
+ struct acx_header *mem_map, size_t len);
+int wl1251_acx_data_path_params(struct wl1251 *wl,
struct acx_data_path_params_resp *data_path);
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time);
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_acx_pd_threshold(struct wl12xx *wl);
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time);
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl);
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl);
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold);
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl);
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl);
-int wl12xx_acx_sg_enable(struct wl12xx *wl);
-int wl12xx_acx_sg_cfg(struct wl12xx *wl);
-int wl12xx_acx_cca_threshold(struct wl12xx *wl);
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl);
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid);
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask);
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble);
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_acx_pd_threshold(struct wl1251 *wl);
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_service_period_timeout(struct wl1251 *wl);
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_sg_enable(struct wl1251 *wl);
+int wl1251_acx_sg_cfg(struct wl1251 *wl);
+int wl1251_acx_cca_threshold(struct wl1251 *wl);
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
+int wl1251_acx_cts_protect(struct wl1251 *wl,
enum acx_ctsprotect_type ctsprotect);
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats);
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
-#endif /* __WL12XX_ACX_H__ */
+#endif /* __WL1251_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 48ac08c429bd..d8a155dc2fa1 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,41 +24,41 @@
#include <linux/gpio.h>
#include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_boot.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
-static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
+static void wl1251_boot_enable_interrupts(struct wl1251 *wl)
{
enable_irq(wl->irq);
}
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl)
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
{
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
- wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
-int wl12xx_boot_soft_reset(struct wl12xx *wl)
+int wl1251_boot_soft_reset(struct wl1251 *wl)
{
unsigned long timeout;
u32 boot_data;
/* perform soft reset */
- wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+ wl1251_reg_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 = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
- wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
if (time_after(jiffies, timeout)) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
- wl12xx_error("soft reset timeout");
+ wl1251_error("soft reset timeout");
return -1;
}
@@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl)
}
/* disable Rx/Tx */
- wl12xx_reg_write32(wl, ENABLE, 0x0);
+ wl1251_reg_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl12xx_reg_write32(wl, SPARE_A2, 0xffff);
+ wl1251_reg_write32(wl, SPARE_A2, 0xffff);
return 0;
}
-int wl12xx_boot_init_seq(struct wl12xx *wl)
+int wl1251_boot_init_seq(struct wl1251 *wl)
{
u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
@@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
};
/* read NVS params */
- scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6);
- wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
+ scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
+ wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
/* read ELP_CMD */
- elp_cmd = wl12xx_reg_read32(wl, ELP_CMD);
- wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
+ elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
+ wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
/* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
ref_freq = scr_pad6 & 0x000000FF;
- wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
+ wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
- wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9);
+ wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
/*
* PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
*/
- wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6);
+ wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
/*
* set the clock detect feature to work in the restart wu procedure
@@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* (ELP_CFG_MODE[13:12])
*/
tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
- wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp);
+ wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
/* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
elp_cmd |= 0x00000040;
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
/* PG 1.2: Set the BB PLL stable time to be 1000usec
* (PLL_STABLE_TIME) */
- wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
+ wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
/* PG 1.2: read clock request time */
- init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME);
+ init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
/*
* PG 1.2: set the clock request time to be ref_clk_settling_time -
@@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
tmp = init_data - 0x21;
else
tmp = 0;
- wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp);
+ wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
/* set BB PLL configurations in RF AFE */
- wl12xx_reg_write32(wl, 0x003058cc, 0x4B5);
+ wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
/* set RF_AFE_REG_5 */
- wl12xx_reg_write32(wl, 0x003058d4, 0x50);
+ wl1251_reg_write32(wl, 0x003058d4, 0x50);
/* set RF_AFE_CTRL_REG_2 */
- wl12xx_reg_write32(wl, 0x00305948, 0x11c001);
+ wl1251_reg_write32(wl, 0x00305948, 0x11c001);
/*
* change RF PLL and BB PLL divider for VCO clock and adjust VCO
* bais current(RF_AFE_REG_13)
*/
- wl12xx_reg_write32(wl, 0x003058f4, 0x1e);
+ wl1251_reg_write32(wl, 0x003058f4, 0x1e);
/* set BB PLL configurations */
tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
- wl12xx_reg_write32(wl, 0x00305840, tmp);
+ wl1251_reg_write32(wl, 0x00305840, tmp);
/* set fractional divider according to Appendix C-BB PLL
* Calculations
*/
tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
- wl12xx_reg_write32(wl, 0x00305844, tmp);
+ wl1251_reg_write32(wl, 0x00305844, tmp);
/* set the initial data for the sigma delta */
- wl12xx_reg_write32(wl, 0x00305848, 0x3039);
+ wl1251_reg_write32(wl, 0x00305848, 0x3039);
/*
* set the accumulator attenuation value, calibration loop1
@@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
*/
tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
(LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
- wl12xx_reg_write32(wl, 0x00305854, tmp);
+ wl1251_reg_write32(wl, 0x00305854, tmp);
/*
* set the calibration stop time after holdoff time expires and set
* settling time HOLD_OFF_TIME_BB
*/
tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
- wl12xx_reg_write32(wl, 0x00305858, tmp);
+ wl1251_reg_write32(wl, 0x00305858, tmp);
/*
* set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
@@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* BB_ILOOPF[7:3]
*/
tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
- wl12xx_reg_write32(wl, 0x003058f8, tmp);
+ wl1251_reg_write32(wl, 0x003058f8, tmp);
/*
* set regulator output voltage for n divider to
@@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
* PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
*/
- wl12xx_reg_write32(wl, 0x003058f0, 0x29);
+ wl1251_reg_write32(wl, 0x003058f0, 0x29);
/* enable restart wakeup sequence (ELP_CMD[0]) */
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
/* restart sequence completed */
udelay(2000);
@@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
return 0;
}
-int wl12xx_boot_run_firmware(struct wl12xx *wl)
+int wl1251_boot_run_firmware(struct wl1251 *wl)
{
int loop, ret;
u32 chip_id, interrupt;
wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
- wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+ wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
if (chip_id != wl->chip.id) {
- wl12xx_error("chip id doesn't match after firmware boot");
+ wl1251_error("chip id doesn't match after firmware boot");
return -EIO;
}
@@ -232,63 +232,65 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
- wl12xx_error("error reading hardware complete "
+ wl1251_error("error reading hardware complete "
"init indication");
return -EIO;
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & wl->chip.intr_init_complete) {
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
wl->chip.intr_init_complete);
break;
}
}
if (loop >= INIT_LOOP) {
- wl12xx_error("timeout waiting for the hardware to "
+ wl1251_error("timeout waiting for the hardware to "
"complete initialization");
return -EIO;
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
wl->chip.p_table[PART_WORK].mem.start,
wl->chip.p_table[PART_WORK].mem.size,
wl->chip.p_table[PART_WORK].reg.start,
wl->chip.p_table[PART_WORK].reg.size);
- wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+ wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
+ wl->chip.op_fw_version(wl);
+
/*
* in case of full asynchronous mode the firmware event must be
* ready to receive event from the command mailbox
*/
/* enable gpio interrupts */
- wl12xx_boot_enable_interrupts(wl);
+ wl1251_boot_enable_interrupts(wl);
wl->chip.op_target_enable_interrupts(wl);
/* unmask all mbox events */
wl->event_mask = 0xffffffff;
- ret = wl12xx_event_unmask(wl);
+ ret = wl1251_event_unmask(wl);
if (ret < 0) {
- wl12xx_error("EVENT mask setting failed");
+ wl1251_error("EVENT mask setting failed");
return ret;
}
- wl12xx_event_mbox_config(wl);
+ wl1251_event_mbox_config(wl);
/* firmware startup completed */
return 0;
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa73132baae..798362d71e3f 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,12 +24,12 @@
#ifndef __BOOT_H__
#define __BOOT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_boot_soft_reset(struct wl12xx *wl);
-int wl12xx_boot_init_seq(struct wl12xx *wl);
-int wl12xx_boot_run_firmware(struct wl12xx *wl);
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl);
+int wl1251_boot_soft_reset(struct wl1251 *wl);
+int wl1251_boot_init_seq(struct wl1251 *wl);
+int wl1251_boot_run_firmware(struct wl1251 *wl);
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
new file mode 100644
index 000000000000..dc04d1fc2ee4
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -0,0 +1,428 @@
+#include "wl1251_cmd.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
+
+/**
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct wl1251_cmd_header *cmd;
+ unsigned long timeout;
+ u32 intr;
+ int ret = 0;
+
+ cmd = buf;
+ cmd->id = id;
+ cmd->status = 0;
+
+ WARN_ON(len % 4 != 0);
+
+ wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ while (!(intr & wl->chip.intr_cmd_complete)) {
+ if (time_after(jiffies, timeout)) {
+ wl1251_error("command complete timeout");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ msleep(1);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ }
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl->chip.intr_cmd_complete);
+
+out:
+ return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd test");
+
+ ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+ if (ret < 0) {
+ wl1251_warning("TEST command failed");
+ return ret;
+ }
+
+ if (answer) {
+ struct wl1251_command *cmd_answer;
+
+ /*
+ * The test command got in, we can read the answer.
+ * The answer would be a wl1251_command, where the
+ * parameter array contains the actual answer.
+ */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+ cmd_answer = buf;
+
+ if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("TEST command answer error: %d",
+ cmd_answer->header.status);
+ }
+
+ return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd interrogate");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_error("INTERROGATE command failed");
+ goto out;
+ }
+
+ /* the interrogate command got in, we can read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+ acx = buf;
+ if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ wl1251_error("INTERROGATE command error: %d",
+ acx->cmd.status);
+
+out:
+ return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd configure");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len);
+ if (ret < 0) {
+ wl1251_warning("CONFIGURE command NOK");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
+ void *bitmap, u16 bitmap_len, u8 bitmap_control)
+{
+ struct wl1251_cmd_vbm_update *vbm;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd vbm");
+
+ vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
+ if (!vbm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Count and period will be filled by the target */
+ vbm->tim.bitmap_ctrl = bitmap_control;
+ if (bitmap_len > PARTIAL_VBM_MAX) {
+ wl1251_warning("cmd vbm len is %d B, truncating to %d",
+ bitmap_len, PARTIAL_VBM_MAX);
+ bitmap_len = PARTIAL_VBM_MAX;
+ }
+ memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
+ vbm->tim.identity = identity;
+ vbm->tim.length = bitmap_len + 3;
+
+ vbm->len = cpu_to_le16(bitmap_len + 5);
+
+ ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
+ if (ret < 0) {
+ wl1251_error("VBM command failed");
+ goto out;
+ }
+
+out:
+ kfree(vbm);
+ return 0;
+}
+
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+{
+ struct cmd_enabledisable_path *cmd;
+ int ret;
+ u16 cmd_rx, cmd_tx;
+
+ wl1251_debug(DEBUG_CMD, "cmd data path");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->channel = channel;
+
+ if (enable) {
+ cmd_rx = CMD_ENABLE_RX;
+ cmd_tx = CMD_ENABLE_TX;
+ } else {
+ cmd_rx = CMD_DISABLE_RX;
+ cmd_tx = CMD_DISABLE_TX;
+ }
+
+ ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("rx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+ ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("tx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ return ret;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait)
+{
+ unsigned long timeout;
+ struct cmd_join *join;
+ int ret, i;
+ u8 *bssid;
+
+ join = kzalloc(sizeof(*join), GFP_KERNEL);
+ if (!join) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: this should be in main.c */
+ ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
+ DEFAULT_HW_GEN_MODULATION_TYPE,
+ wl->tx_mgmt_frm_rate,
+ wl->tx_mgmt_frm_mod);
+ if (ret < 0)
+ goto out;
+
+ wl1251_debug(DEBUG_CMD, "cmd join");
+
+ /* Reverse order BSSID */
+ bssid = (u8 *) &join->bssid_lsb;
+ 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->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+ RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+ join->beacon_interval = beacon_interval;
+ join->dtim_interval = dtim_interval;
+ join->bss_type = bss_type;
+ join->channel = wl->channel;
+ join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
+
+ ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+ if (ret < 0) {
+ wl1251_error("failed to initiate cmd join");
+ goto out;
+ }
+
+ timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+
+ /*
+ * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
+ * simplify locking we just sleep instead, for now
+ */
+ if (wait)
+ msleep(10);
+
+out:
+ kfree(join);
+ return ret;
+}
+
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
+{
+ struct wl1251_cmd_ps_params *ps_params = NULL;
+ int ret = 0;
+
+ /* FIXME: this should be in ps.c */
+ ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0) {
+ wl1251_error("couldn't set wake up conditions");
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_CMD, "cmd set ps mode");
+
+ ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+ if (!ps_params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ps_params->ps_mode = 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 */
+
+ ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+ sizeof(*ps_params));
+ if (ret < 0) {
+ wl1251_error("cmd set_ps_mode failed");
+ goto out;
+ }
+
+out:
+ kfree(ps_params);
+ return ret;
+}
+
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len)
+{
+ struct cmd_read_write_memory *cmd;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd read memory");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ WARN_ON(len > MAX_READ_SIZE);
+ len = min_t(size_t, len, MAX_READ_SIZE);
+
+ cmd->addr = addr;
+ cmd->size = len;
+
+ ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("read memory command failed: %d", ret);
+ goto out;
+ }
+
+ /* the read command got in, we can now read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("error in read command result: %d",
+ cmd->header.status);
+
+ memcpy(answer, cmd->value, len);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
+ void *buf, size_t buf_len)
+{
+ struct wl1251_cmd_packet_template *cmd;
+ size_t cmd_len;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id);
+
+ WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE);
+ buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE);
+ cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
+
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->size = cpu_to_le16(buf_len);
+
+ if (buf)
+ memcpy(cmd->data, buf, buf_len);
+
+ ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len);
+ if (ret < 0) {
+ wl1251_warning("cmd set_template failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index aa307dcd081f..64f228dd9a9b 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,37 +22,32 @@
*
*/
-#ifndef __WL12XX_CMD_H__
-#define __WL12XX_CMD_H__
+#ifndef __WL1251_CMD_H__
+#define __WL1251_CMD_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len);
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer);
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer);
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len);
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
+struct acx_header;
+
+int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable);
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
u16 beacon_interval, u8 wait);
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode);
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer);
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len);
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
void *buf, size_t buf_len);
/* unit ms */
-#define WL12XX_COMMAND_TIMEOUT 2000
-
-#define WL12XX_MAX_TEMPLATE_SIZE 300
+#define WL1251_COMMAND_TIMEOUT 2000
-struct wl12xx_cmd_packet_template {
- __le16 size;
- u8 template[WL12XX_MAX_TEMPLATE_SIZE];
-} __attribute__ ((packed));
-
-enum wl12xx_commands {
+enum wl1251_commands {
CMD_RESET = 0,
CMD_INTERROGATE = 1, /*use this to read information elements*/
CMD_CONFIGURE = 2, /*use this to write information elements*/
@@ -100,9 +95,15 @@ enum wl12xx_commands {
#define MAX_CMD_PARAMS 572
-struct wl12xx_command {
+struct wl1251_cmd_header {
u16 id;
u16 status;
+ /* payload */
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct wl1251_command {
+ struct wl1251_cmd_header header;
u8 parameters[MAX_CMD_PARAMS];
};
@@ -144,6 +145,8 @@ enum {
#define MAX_READ_SIZE 256
struct cmd_read_write_memory {
+ struct wl1251_cmd_header header;
+
/* The address of the memory to read from or write to.*/
u32 addr;
@@ -211,6 +214,8 @@ struct basic_scan_channel_parameters {
#define SCAN_MAX_NUM_OF_CHANNELS 16
struct cmd_scan {
+ struct wl1251_cmd_header header;
+
struct basic_scan_parameters params;
struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
} __attribute__ ((packed));
@@ -227,6 +232,8 @@ enum {
struct cmd_join {
+ struct wl1251_cmd_header header;
+
u32 bssid_lsb;
u16 bssid_msb;
u16 beacon_interval; /* in TBTTs */
@@ -261,5 +268,140 @@ struct cmd_join {
u8 reserved;
} __attribute__ ((packed));
+struct cmd_enabledisable_path {
+ struct wl1251_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+#define WL1251_MAX_TEMPLATE_SIZE 300
+
+struct wl1251_cmd_packet_template {
+ struct wl1251_cmd_header header;
+
+ __le16 size;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID 5
+#define PARTIAL_VBM_MAX 251
+
+struct wl1251_tim {
+ u8 identity;
+ u8 length;
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bitmap_ctrl;
+ u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+/* Virtual Bit Map update */
+struct wl1251_cmd_vbm_update {
+ struct wl1251_cmd_header header;
+ __le16 len;
+ u8 padding[2];
+ struct wl1251_tim tim;
+} __attribute__ ((packed));
+
+enum wl1251_cmd_ps_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE
+};
+
+struct wl1251_cmd_ps_params {
+ struct wl1251_cmd_header header;
+
+ u8 ps_mode; /* STATION_* */
+ u8 send_null_data; /* Do we have to send NULL data packet ? */
+ u8 retries; /* Number of retires for the initial NULL data packet */
+
+ /*
+ * TUs during which the target stays awake after switching
+ * to power save mode.
+ */
+ u8 hang_over_period;
+ u16 null_data_rate;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct wl1251_cmd_trigger_scan_to {
+ struct wl1251_cmd_header header;
+
+ u32 timeout;
+};
+
+/* 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 wl1251_cmd_key_action {
+ KEY_ADD_OR_REPLACE = 1,
+ KEY_REMOVE = 2,
+ KEY_SET_ID = 3,
+ MAX_KEY_ACTION = 0xffff,
+};
+
+enum wl1251_cmd_key_type {
+ KEY_WEP_DEFAULT = 0,
+ KEY_WEP_ADDR = 1,
+ KEY_AES_GROUP = 4,
+ KEY_AES_PAIRWISE = 5,
+ KEY_WEP_GROUP = 6,
+ KEY_TKIP_MIC_GROUP = 10,
+ KEY_TKIP_MIC_PAIRWISE = 11,
+};
+
+/*
+ *
+ * key_type_e key size key format
+ * ---------- --------- ----------
+ * 0x00 5, 13, 29 Key data
+ * 0x01 5, 13, 29 Key data
+ * 0x04 16 16 bytes of key data
+ * 0x05 16 16 bytes of key data
+ * 0x0a 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ * 0x0b 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ *
+ */
+
+struct wl1251_cmd_set_keys {
+ struct wl1251_cmd_header header;
+
+ /* Ignored for default WEP key */
+ u8 addr[ETH_ALEN];
+
+ /* key_action_e */
+ u16 key_action;
+
+ u16 reserved_1;
+
+ /* key size in bytes */
+ u8 key_size;
+
+ /* key_type_e */
+ u8 key_type;
+ u8 ssid_profile;
+
+ /*
+ * TKIP, AES: frame's key id field.
+ * For WEP default key: key id;
+ */
+ u8 id;
+ u8 reserved_2[6];
+ u8 key[MAX_KEY_SIZE];
+ u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
-#endif /* __WL12XX_CMD_H__ */
+#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index cdb368ce4dae..a00723059f83 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,15 +21,16 @@
*
*/
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
#include <linux/skbuff.h>
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
/* ms */
-#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
+#define WL1251_DEBUGFS_STATS_LIFETIME 1000
/* debugfs macros idea from mac80211 */
@@ -37,7 +38,7 @@
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
@@ -47,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
\
static const struct file_operations name## _ops = { \
.read = name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_ADD(name, parent) \
@@ -70,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
- wl12xx_debugfs_update_stats(wl); \
+ wl1251_debugfs_update_stats(wl); \
\
res = scnprintf(buf, buflen, fmt "\n", \
wl->stats.fw_stats->sub.name); \
@@ -83,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
\
static const struct file_operations sub## _ ##name## _ops = { \
.read = sub## _ ##name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_FWSTATS_ADD(sub, name) \
@@ -92,21 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \
#define DEBUGFS_FWSTATS_DEL(sub, name) \
DEBUGFS_DEL(sub## _ ##name)
-static void wl12xx_debugfs_update_stats(struct wl12xx *wl)
+static void wl1251_debugfs_update_stats(struct wl1251 *wl)
{
+ int ret;
+
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_ON &&
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1251_STATE_ON &&
time_after(jiffies, wl->stats.fw_stats_update +
- msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) {
- wl12xx_acx_statistics(wl, wl->stats.fw_stats);
+ msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) {
+ wl1251_acx_statistics(wl, wl->stats.fw_stats);
wl->stats.fw_stats_update = jiffies;
}
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
}
-static int wl12xx_open_file_generic(struct inode *inode, struct file *file)
+static int wl1251_open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
@@ -211,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- struct wl12xx *wl = file->private_data;
+ struct wl1251 *wl = file->private_data;
u32 queue_len;
char buf[20];
int res;
@@ -224,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
static const struct file_operations tx_queue_len_ops = {
.read = tx_queue_len_read,
- .open = wl12xx_open_file_generic,
+ .open = wl1251_open_file_generic,
};
-static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
+static void wl1251_debugfs_delete_files(struct wl1251 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -325,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
DEBUGFS_DEL(excessive_retries);
}
-static int wl12xx_debugfs_add_files(struct wl12xx *wl)
+static int wl1251_debugfs_add_files(struct wl1251 *wl)
{
int ret = 0;
@@ -426,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl)
out:
if (ret < 0)
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
return ret;
}
-void wl12xx_debugfs_reset(struct wl12xx *wl)
+void wl1251_debugfs_reset(struct wl1251 *wl)
{
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
wl->stats.retry_count = 0;
wl->stats.excessive_retries = 0;
}
-int wl12xx_debugfs_init(struct wl12xx *wl)
+int wl1251_debugfs_init(struct wl1251 *wl)
{
int ret;
@@ -469,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl)
wl->stats.fw_stats_update = jiffies;
- ret = wl12xx_debugfs_add_files(wl);
+ ret = wl1251_debugfs_add_files(wl);
if (ret < 0)
goto err_file;
@@ -492,9 +502,9 @@ err:
return ret;
}
-void wl12xx_debugfs_exit(struct wl12xx *wl)
+void wl1251_debugfs_exit(struct wl1251 *wl)
{
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
kfree(wl->stats.fw_stats);
wl->stats.fw_stats = NULL;
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcbcc874..6dc3d080853c 100644
--- a/drivers/net/wireless/wl12xx/debugfs.h
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,13 +21,13 @@
*
*/
-#ifndef WL12XX_DEBUGFS_H
-#define WL12XX_DEBUGFS_H
+#ifndef WL1251_DEBUGFS_H
+#define WL1251_DEBUGFS_H
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_debugfs_init(struct wl12xx *wl);
-void wl12xx_debugfs_exit(struct wl12xx *wl);
-void wl12xx_debugfs_reset(struct wl12xx *wl);
+int wl1251_debugfs_init(struct wl1251 *wl);
+void wl1251_debugfs_exit(struct wl1251 *wl);
+void wl1251_debugfs_reset(struct wl1251 *wl);
-#endif /* WL12XX_DEBUGFS_H */
+#endif /* WL1251_DEBUGFS_H */
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca89a7e..1a0a0bc1a31f 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/wl1251_event.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,16 +22,16 @@
*
*/
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
-static int wl12xx_event_scan_complete(struct wl12xx *wl,
+static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
+ wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
mbox->scheduled_scan_status,
mbox->scheduled_scan_channels);
@@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl,
return 0;
}
-static void wl12xx_event_mbox_dump(struct event_mailbox *mbox)
+static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:");
- wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
- wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+ wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
+ wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+ wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
}
-static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
+static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
{
int ret;
u32 vector;
- wl12xx_event_mbox_dump(mbox);
+ wl1251_event_mbox_dump(mbox);
vector = mbox->events_vector & ~(mbox->events_mask);
- wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+ wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
- ret = wl12xx_event_scan_complete(wl, mbox);
+ ret = wl1251_event_scan_complete(wl, mbox);
if (ret < 0)
return ret;
}
if (vector & BSS_LOSE_EVENT_ID) {
- wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+ wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
if (wl->psm_requested && wl->psm) {
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
}
@@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
return 0;
}
-int wl12xx_event_unmask(struct wl12xx *wl)
+int wl1251_event_unmask(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask));
+ ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
if (ret < 0)
return ret;
return 0;
}
-void wl12xx_event_mbox_config(struct wl12xx *wl)
+void wl1251_event_mbox_config(struct wl1251 *wl)
{
- wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
- wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+ wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
- wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+ wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
if (mbox_num > 1)
return -EINVAL;
/* first we read the mbox descriptor */
- wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox));
/* process the descriptor */
- ret = wl12xx_event_process(wl, &mbox);
+ ret = wl1251_event_process(wl, &mbox);
if (ret < 0)
return ret;
/* then we let the firmware know it can go on...*/
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7438a7..be0ac54d6246 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_EVENT_H__
-#define __WL12XX_EVENT_H__
+#ifndef __WL1251_EVENT_H__
+#define __WL1251_EVENT_H__
/*
* Mbox events
@@ -114,8 +114,8 @@ struct event_mailbox {
u8 padding[19];
} __attribute__ ((packed));
-int wl12xx_event_unmask(struct wl12xx *wl);
-void wl12xx_event_mbox_config(struct wl12xx *wl);
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox);
+int wl1251_event_unmask(struct wl1251 *wl);
+void wl1251_event_mbox_config(struct wl1251 *wl);
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
index 2a573a6010bd..df6c60f0fd66 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -24,64 +24,64 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "init.h"
+#include "wl1251_init.h"
#include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_feature_cfg(wl);
+ ret = wl1251_acx_feature_cfg(wl);
if (ret < 0) {
- wl12xx_warning("couldn't set feature config");
+ wl1251_warning("couldn't set feature config");
return ret;
}
- ret = wl12xx_acx_default_key(wl, wl->default_key);
+ ret = wl1251_acx_default_key(wl, wl->default_key);
if (ret < 0) {
- wl12xx_warning("couldn't set default key");
+ wl1251_warning("couldn't set default key");
return ret;
}
return 0;
}
-int wl12xx_hw_init_templates_config(struct wl12xx *wl)
+int wl1251_hw_init_templates_config(struct wl1251 *wl)
{
int ret;
u8 partial_vbm[PARTIAL_VBM_MAX];
/* send empty templates for fw memory reservation */
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
sizeof(struct wl12xx_probe_req_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
sizeof(struct wl12xx_ps_poll_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
sizeof
(struct wl12xx_qos_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
sizeof
(struct wl12xx_probe_resp_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
sizeof
(struct wl12xx_beacon_template));
if (ret < 0)
@@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl)
/* tim templates, first reserve space then allocate an empty one */
memset(partial_vbm, 0, PARTIAL_VBM_MAX);
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter)
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
{
int ret;
- ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rx_config(wl, config, filter);
+ ret = wl1251_acx_rx_config(wl, config, filter);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_phy_config(struct wl12xx *wl)
+int wl1251_hw_init_phy_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_pd_threshold(wl);
+ ret = wl1251_acx_pd_threshold(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME);
+ ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
if (ret < 0)
return ret;
- ret = wl12xx_acx_group_address_tbl(wl);
+ ret = wl1251_acx_group_address_tbl(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_service_period_timeout(wl);
+ ret = wl1251_acx_service_period_timeout(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl)
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_beacon_filter_opt(wl);
+ ret = wl1251_acx_beacon_filter_opt(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_beacon_filter_table(wl);
+ ret = wl1251_acx_beacon_filter_table(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_pta(struct wl12xx *wl)
+int wl1251_hw_init_pta(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_sg_enable(wl);
+ ret = wl1251_acx_sg_enable(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_sg_cfg(wl);
+ ret = wl1251_acx_sg_cfg(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl)
+int wl1251_hw_init_energy_detection(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_cca_threshold(wl);
+ ret = wl1251_acx_cca_threshold(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl)
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_bcn_dtim_options(wl);
+ ret = wl1251_acx_bcn_dtim_options(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_power_auth(struct wl12xx *wl)
+int wl1251_hw_init_power_auth(struct wl1251 *wl)
{
- return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
}
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
index c8b6cd0b7c3e..8596188e834e 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,20 +21,19 @@
*
*/
-#ifndef __WL12XX_INIT_H__
-#define __WL12XX_INIT_H__
+#ifndef __WL1251_INIT_H__
+#define __WL1251_INIT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl);
-int wl12xx_hw_init_templates_config(struct wl12xx *wl);
-int wl12xx_hw_init_mem_config(struct wl12xx *wl);
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_hw_init_phy_config(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl);
-int wl12xx_hw_init_pta(struct wl12xx *wl);
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl);
-int wl12xx_hw_init_power_auth(struct wl12xx *wl);
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
+int wl1251_hw_init_templates_config(struct wl1251 *wl);
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_hw_init_phy_config(struct wl1251 *wl);
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl);
+int wl1251_hw_init_pta(struct wl1251 *wl);
+int wl1251_hw_init_energy_detection(struct wl1251 *wl);
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl);
+int wl1251_hw_init_power_auth(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 603d6114882e..da4c688c46af 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -31,38 +31,38 @@
#include <linux/etherdevice.h>
#include <linux/spi/wl12xx.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "wl1251.h"
-#include "spi.h"
-#include "event.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
-
-static void wl12xx_disable_interrupts(struct wl12xx *wl)
+#include "wl1251_ops.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
+
+static void wl1251_disable_interrupts(struct wl1251 *wl)
{
disable_irq(wl->irq);
}
-static void wl12xx_power_off(struct wl12xx *wl)
+static void wl1251_power_off(struct wl1251 *wl)
{
wl->set_power(false);
}
-static void wl12xx_power_on(struct wl12xx *wl)
+static void wl1251_power_on(struct wl1251 *wl)
{
wl->set_power(true);
}
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+static irqreturn_t wl1251_irq(int irq, void *cookie)
{
- struct wl12xx *wl;
+ struct wl1251 *wl;
- wl12xx_debug(DEBUG_IRQ, "IRQ");
+ wl1251_debug(DEBUG_IRQ, "IRQ");
wl = cookie;
@@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie)
return IRQ_HANDLED;
}
-static int wl12xx_fetch_firmware(struct wl12xx *wl)
+static int wl1251_fetch_firmware(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get firmware: %d", ret);
+ wl1251_error("could not get firmware: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("firmware size is not multiple of 32 bits: %zu",
+ wl1251_error("firmware size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
if (!wl->fw) {
- wl12xx_error("could not allocate memory for the firmware");
+ wl1251_error("could not allocate memory for the firmware");
ret = -ENOMEM;
goto out;
}
@@ -109,7 +109,7 @@ out:
return ret;
}
-static int wl12xx_fetch_nvs(struct wl12xx *wl)
+static int wl1251_fetch_nvs(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get nvs file: %d", ret);
+ wl1251_error("could not get nvs file: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("nvs size is not multiple of 32 bits: %zu",
+ wl1251_error("nvs size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
- wl12xx_error("could not allocate memory for the nvs file");
+ wl1251_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
goto out;
}
@@ -147,74 +147,70 @@ out:
return ret;
}
-static void wl12xx_fw_wakeup(struct wl12xx *wl)
+static void wl1251_fw_wakeup(struct wl1251 *wl)
{
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
- if (!(elp_reg & ELPCTRL_WLAN_READY)) {
- wl12xx_warning("WLAN not ready");
- elp_reg = ELPCTRL_WAKE_UP_WLAN_READY;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- }
+ if (!(elp_reg & ELPCTRL_WLAN_READY))
+ wl1251_warning("WLAN not ready");
}
-static int wl12xx_chip_wakeup(struct wl12xx *wl)
+static int wl1251_chip_wakeup(struct wl1251 *wl)
{
int ret = 0;
- wl12xx_power_on(wl);
+ wl1251_power_on(wl);
msleep(wl->chip.power_on_sleep);
- wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl1251_spi_reset(wl);
+ wl1251_spi_init(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
0x00000000,
0x00000000,
REGISTERS_BASE,
REGISTERS_DOWN_SIZE);
/* ELP module wake up */
- wl12xx_fw_wakeup(wl);
+ wl1251_fw_wakeup(wl);
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
switch (wl->chip.id) {
case CHIP_ID_1251_PG12:
- wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip.id);
wl1251_setup(wl);
break;
- case CHIP_ID_1271_PG10:
case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
default:
- wl12xx_error("unsupported chip id: 0x%x", wl->chip.id);
+ wl1251_error("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
if (wl->fw == NULL) {
- ret = wl12xx_fetch_firmware(wl);
+ ret = wl1251_fetch_firmware(wl);
if (ret < 0)
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
- ret = wl12xx_fetch_nvs(wl);
+ ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
@@ -223,88 +219,51 @@ out:
return ret;
}
-static void wl12xx_filter_work(struct work_struct *work)
+static void wl1251_filter_work(struct work_struct *work)
{
- struct wl12xx *wl =
- container_of(work, struct wl12xx, filter_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, filter_work);
int ret;
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
-out:
- mutex_unlock(&wl->mutex);
-}
-
-int wl12xx_plt_start(struct wl12xx *wl)
-{
- int ret;
-
- wl12xx_notice("power up");
-
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot go into PLT state because not "
- "in off state: %d", wl->state);
- return -EBUSY;
- }
-
- wl->state = WL12XX_STATE_PLT;
-
- ret = wl12xx_chip_wakeup(wl);
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- return ret;
+ goto out_sleep;
- ret = wl->chip.op_boot(wl);
- if (ret < 0)
- return ret;
-
- wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
- ret = wl->chip.op_plt_init(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_plt_stop(struct wl12xx *wl)
-{
- wl12xx_notice("power down");
-
- if (wl->state != WL12XX_STATE_PLT) {
- wl12xx_error("cannot power down because not in PLT "
- "state: %d", wl->state);
- return -EBUSY;
- }
-
- wl12xx_disable_interrupts(wl);
- wl12xx_power_off(wl);
-
- wl->state = WL12XX_STATE_OFF;
-
- return 0;
+out:
+ mutex_unlock(&wl->mutex);
}
-
-static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
skb_queue_tail(&wl->tx_queue, skb);
+ /*
+ * The chip specific setup must run before the first TX packet -
+ * before that, the tx_work will not be initialized!
+ */
+
schedule_work(&wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) {
+ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
ieee80211_stop_queues(wl->hw);
/*
@@ -318,25 +277,25 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int wl12xx_op_start(struct ieee80211_hw *hw)
+static int wl1251_op_start(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 start");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 start");
mutex_lock(&wl->mutex);
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot start because not in off state: %d",
+ if (wl->state != WL1251_STATE_OFF) {
+ wl1251_error("cannot start because not in off state: %d",
wl->state);
ret = -EBUSY;
goto out;
}
- ret = wl12xx_chip_wakeup(wl);
+ ret = wl1251_chip_wakeup(wl);
if (ret < 0)
- return ret;
+ goto out;
ret = wl->chip.op_boot(wl);
if (ret < 0)
@@ -346,34 +305,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw)
if (ret < 0)
goto out;
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
- wl->state = WL12XX_STATE_ON;
+ wl->state = WL1251_STATE_ON;
- wl12xx_info("firmware booted (%s)", wl->chip.fw_ver);
+ wl1251_info("firmware booted (%s)", wl->chip.fw_ver);
out:
if (ret < 0)
- wl12xx_power_off(wl);
+ wl1251_power_off(wl);
mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl1251_op_stop(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_info("down");
+ wl1251_info("down");
- wl12xx_debug(DEBUG_MAC80211, "mac80211 stop");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 stop");
mutex_lock(&wl->mutex);
- WARN_ON(wl->state != WL12XX_STATE_ON);
+ WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
mutex_unlock(&wl->mutex);
@@ -382,9 +341,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->scanning = false;
}
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
- wl12xx_disable_interrupts(wl);
+ wl1251_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
@@ -395,9 +354,8 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl12xx_tx_flush(wl);
-
- wl12xx_power_off(wl);
+ wl->chip.op_tx_flush(wl);
+ wl1251_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
wl->listen_int = 1;
@@ -412,22 +370,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->elp = false;
wl->psm = 0;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
- wl12xx_debugfs_reset(wl);
+ wl1251_debugfs_reset(wl);
mutex_unlock(&wl->mutex);
}
-static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
+static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- struct wl12xx *wl = hw->priv;
- DECLARE_MAC_BUF(mac);
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
- conf->type, print_mac(mac, conf->mac_addr));
+ wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
@@ -446,7 +403,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
}
@@ -456,13 +413,13 @@ out:
return ret;
}
-static void wl12xx_op_remove_interface(struct ieee80211_hw *hw,
+static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
}
-static int wl12xx_build_null_data(struct wl12xx *wl)
+static int wl1251_build_null_data(struct wl1251 *wl)
{
struct wl12xx_null_data_template template;
@@ -478,12 +435,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl)
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC);
- return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template,
+ return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
sizeof(template));
}
-static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
+static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
{
struct wl12xx_ps_poll_template template;
@@ -492,41 +449,45 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
template.aid = aid;
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template,
+ return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
sizeof(template));
}
-static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
+static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int channel, ret = 0;
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level);
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (channel != wl->channel) {
/* FIXME: use beacon interval provided by mac80211 */
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- goto out;
+ goto out_sleep;
wl->channel = channel;
}
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
- goto out;
+ goto out_sleep;
if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
- wl12xx_info("psm enabled");
+ wl1251_debug(DEBUG_PSM, "psm enabled");
wl->psm_requested = true;
@@ -535,49 +496,53 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
- ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
- wl12xx_info("psm disabled");
+ wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
if (wl->psm)
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
}
if (conf->power_level != wl->power_level) {
- ret = wl12xx_acx_tx_power(wl, conf->power_level);
+ ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
goto out;
wl->power_level = conf->power_level;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
+
return ret;
}
-#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
FIF_OTHER_BSS)
-static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
+static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *total,
int mc_count,
struct dev_addr_list *mc_list)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
- *total &= WL12XX_SUPPORTED_FILTERS;
- changed &= WL12XX_SUPPORTED_FILTERS;
+ *total &= WL1251_SUPPORTED_FILTERS;
+ changed &= WL1251_SUPPORTED_FILTERS;
if (changed == 0)
/* no filters which we support changed */
@@ -585,8 +550,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
/* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
if (*total & FIF_PROMISC_IN_BSS) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
@@ -618,7 +583,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
}
/* HW encryption */
-static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
+static int wl1251_set_key_type(struct wl1251 *wl,
+ struct wl1251_cmd_set_keys *key,
enum set_key_cmd cmd,
struct ieee80211_key_conf *mac80211_key,
const u8 *addr)
@@ -648,95 +614,116 @@ static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
default:
- wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg);
+ wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
return -EOPNOTSUPP;
}
return 0;
}
-static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- struct wl12xx *wl = hw->priv;
- struct acx_set_key wl_key;
+ struct wl1251 *wl = hw->priv;
+ struct wl1251_cmd_set_keys *wl_cmd;
const u8 *addr;
int ret;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- wl12xx_debug(DEBUG_MAC80211, "mac80211 set key");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 set key");
- memset(&wl_key, 0, sizeof(wl_key));
+ wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL);
+ if (!wl_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
addr = sta ? sta->addr : bcast_addr;
- wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
- wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
- wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+ wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+ wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+ wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
key->alg, key->keyidx, key->keylen, key->flags);
- wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+ wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+
+ if (is_zero_ether_addr(addr)) {
+ /* We dont support TX only encryption */
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
switch (cmd) {
case SET_KEY:
- wl_key.key_action = KEY_ADD_OR_REPLACE;
+ wl_cmd->key_action = KEY_ADD_OR_REPLACE;
break;
case DISABLE_KEY:
- wl_key.key_action = KEY_REMOVE;
+ wl_cmd->key_action = KEY_REMOVE;
break;
default:
- wl12xx_error("Unsupported key cmd 0x%x", cmd);
+ wl1251_error("Unsupported key cmd 0x%x", cmd);
break;
}
- ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr);
+ ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
if (ret < 0) {
- wl12xx_error("Set KEY type failed");
- goto out;
+ wl1251_error("Set KEY type failed");
+ goto out_sleep;
}
- if (wl_key.key_type != KEY_WEP_DEFAULT)
- memcpy(wl_key.addr, addr, ETH_ALEN);
+ if (wl_cmd->key_type != KEY_WEP_DEFAULT)
+ memcpy(wl_cmd->addr, addr, ETH_ALEN);
- if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) ||
- (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) {
+ if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) ||
+ (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
- memcpy(wl_key.key, key->key, 16);
- memcpy(wl_key.key + 16, key->key + 24, 8);
- memcpy(wl_key.key + 24, key->key + 16, 8);
+ memcpy(wl_cmd->key, key->key, 16);
+ memcpy(wl_cmd->key + 16, key->key + 24, 8);
+ memcpy(wl_cmd->key + 24, key->key + 16, 8);
} else {
- memcpy(wl_key.key, key->key, key->keylen);
+ memcpy(wl_cmd->key, key->key, key->keylen);
}
- wl_key.key_size = key->keylen;
+ wl_cmd->key_size = key->keylen;
- wl_key.id = key->keyidx;
- wl_key.ssid_profile = 0;
+ wl_cmd->id = key->keyidx;
+ wl_cmd->ssid_profile = 0;
- wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key));
+ wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd));
- if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) {
- wl12xx_error("Set KEY failed");
- ret = -EOPNOTSUPP;
- goto out;
+ ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd));
+ if (ret < 0) {
+ wl1251_warning("could not set keys");
+ goto out_sleep;
}
-out:
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out_unlock:
mutex_unlock(&wl->mutex);
+
+out:
+ kfree(wl_cmd);
+
return ret;
}
-static int wl12xx_build_basic_rates(char *rates)
+static int wl1251_build_basic_rates(char *rates)
{
u8 index = 0;
@@ -748,7 +735,7 @@ static int wl12xx_build_basic_rates(char *rates)
return index;
}
-static int wl12xx_build_extended_rates(char *rates)
+static int wl1251_build_extended_rates(char *rates)
{
u8 index = 0;
@@ -765,7 +752,7 @@ static int wl12xx_build_extended_rates(char *rates)
}
-static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
+static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
@@ -792,31 +779,30 @@ static int wl12xx_build_probe_req(struct wl12xx *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 = wl12xx_build_basic_rates(rates->rates);
+ rates->header.len = wl1251_build_basic_rates(rates->rates);
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 = wl12xx_build_extended_rates(rates->rates);
+ rates->header.len = wl1251_build_extended_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
- wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+ wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template,
+ return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
size);
}
-static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
+static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
u8 active_scan, u8 high_prio, u8 num_channels,
u8 probe_requests)
{
+ struct wl1251_cmd_trigger_scan_to *trigger = NULL;
+ struct cmd_scan *params = NULL;
int i, ret;
- u32 split_scan = 0;
u16 scan_options = 0;
- struct cmd_scan *params;
- struct wl12xx_command *cmd_answer;
if (wl->scanning)
return -EINVAL;
@@ -864,33 +850,38 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
memset(params->params.ssid, 0, 32);
}
- ret = wl12xx_build_probe_req(wl, ssid, len);
+ ret = wl1251_build_probe_req(wl, ssid, len);
if (ret < 0) {
- wl12xx_error("PROBE request template failed");
+ wl1251_error("PROBE request template failed");
goto out;
}
- ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan,
- sizeof(u32));
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger)
+ goto out;
+
+ trigger->timeout = 0;
+
+ ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger));
if (ret < 0) {
- wl12xx_error("Split SCAN failed");
+ wl1251_error("trigger scan to failed for hw scan");
goto out;
}
- wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+ wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
- ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0)
- wl12xx_error("SCAN failed");
+ wl1251_error("SCAN failed");
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
- cmd_answer = (struct wl12xx_command *) params;
- if (cmd_answer->status != CMD_STATUS_SUCCESS) {
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
+ if (params->header.status != CMD_STATUS_SUCCESS) {
+ wl1251_error("TEST command answer error: %d",
+ params->header.status);
wl->scanning = false;
ret = -EIO;
goto out;
@@ -902,15 +893,15 @@ out:
}
-static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
size_t ssid_len = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
@@ -918,85 +909,108 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
}
mutex_lock(&wl->mutex);
- ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
return ret;
}
-static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
- ret = wl12xx_acx_rts_threshold(wl, (u16) value);
+ mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
- wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret);
+ goto out;
+
+ ret = wl1251_acx_rts_threshold(wl, (u16) value);
+ if (ret < 0)
+ wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
+static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
- enum acx_ps_mode mode;
- struct wl12xx *wl = hw->priv;
+ enum wl1251_cmd_ps_mode mode;
+ struct wl1251 *wl = hw->priv;
struct sk_buff *beacon;
int ret;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
- ret = wl12xx_build_ps_poll(wl, wl->aid);
+ ret = wl1251_build_ps_poll(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
- ret = wl12xx_acx_aid(wl, wl->aid);
+ ret = wl1251_acx_aid(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl12xx_ps_set_mode(wl, mode);
+ ret = wl1251_ps_set_mode(wl, mode);
if (ret < 0)
- goto out;
+ goto out_sleep;
}
}
}
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
- ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT);
else
- ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
- wl12xx_warning("Set slot time failed %d", ret);
- goto out;
+ wl1251_warning("Set slot time failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
if (bss_conf->use_cts_prot)
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE);
else
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
- wl12xx_warning("Set ctsprotect failed %d", ret);
+ wl1251_warning("Set ctsprotect failed %d", ret);
goto out;
}
}
@@ -1004,20 +1018,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
goto out;
if (wl->bss_type != BSS_TYPE_IBSS) {
- ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1);
+ ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1);
if (ret < 0)
- goto out;
+ goto out_sleep;
+ wl1251_warning("Set ctsprotect failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
beacon->len);
if (ret < 0) {
@@ -1025,7 +1041,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
beacon->len);
dev_kfree_skb(beacon);
@@ -1033,19 +1049,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
goto out;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
/* can't be const, mac80211 writes to this */
-static struct ieee80211_rate wl12xx_rates[] = {
+static struct ieee80211_rate wl1251_rates[] = {
{ .bitrate = 10,
.hw_value = 0x1,
.hw_value_short = 0x1, },
@@ -1088,7 +1107,7 @@ static struct ieee80211_rate wl12xx_rates[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_channel wl12xx_channels[] = {
+static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
@@ -1105,28 +1124,28 @@ static struct ieee80211_channel wl12xx_channels[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_supported_band wl12xx_band_2ghz = {
- .channels = wl12xx_channels,
- .n_channels = ARRAY_SIZE(wl12xx_channels),
- .bitrates = wl12xx_rates,
- .n_bitrates = ARRAY_SIZE(wl12xx_rates),
+static struct ieee80211_supported_band wl1251_band_2ghz = {
+ .channels = wl1251_channels,
+ .n_channels = ARRAY_SIZE(wl1251_channels),
+ .bitrates = wl1251_rates,
+ .n_bitrates = ARRAY_SIZE(wl1251_rates),
};
-static const struct ieee80211_ops wl12xx_ops = {
- .start = wl12xx_op_start,
- .stop = wl12xx_op_stop,
- .add_interface = wl12xx_op_add_interface,
- .remove_interface = wl12xx_op_remove_interface,
- .config = wl12xx_op_config,
- .configure_filter = wl12xx_op_configure_filter,
- .tx = wl12xx_op_tx,
- .set_key = wl12xx_op_set_key,
- .hw_scan = wl12xx_op_hw_scan,
- .bss_info_changed = wl12xx_op_bss_info_changed,
- .set_rts_threshold = wl12xx_op_set_rts_threshold,
+static const struct ieee80211_ops wl1251_ops = {
+ .start = wl1251_op_start,
+ .stop = wl1251_op_stop,
+ .add_interface = wl1251_op_add_interface,
+ .remove_interface = wl1251_op_remove_interface,
+ .config = wl1251_op_config,
+ .configure_filter = wl1251_op_configure_filter,
+ .tx = wl1251_op_tx,
+ .set_key = wl1251_op_set_key,
+ .hw_scan = wl1251_op_hw_scan,
+ .bss_info_changed = wl1251_op_bss_info_changed,
+ .set_rts_threshold = wl1251_op_set_rts_threshold,
};
-static int wl12xx_register_hw(struct wl12xx *wl)
+static int wl1251_register_hw(struct wl1251 *wl)
{
int ret;
@@ -1137,22 +1156,22 @@ static int wl12xx_register_hw(struct wl12xx *wl)
ret = ieee80211_register_hw(wl->hw);
if (ret < 0) {
- wl12xx_error("unable to register mac80211 hw: %d", ret);
+ wl1251_error("unable to register mac80211 hw: %d", ret);
return ret;
}
wl->mac80211_registered = true;
- wl12xx_notice("loaded");
+ wl1251_notice("loaded");
return 0;
}
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+static int wl1251_init_ieee80211(struct wl1251 *wl)
{
/* The tx descriptor buffer and the TKIP space */
wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
- + WL12XX_TKIP_IV_SPACE;
+ + WL1251_TKIP_IV_SPACE;
/* unit us */
/* FIXME: find a proper value */
@@ -1163,31 +1182,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
- wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
+ wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
return 0;
}
-#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+#define WL1251_DEFAULT_CHANNEL 1
+static int __devinit wl1251_probe(struct spi_device *spi)
{
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
- struct wl12xx *wl;
+ struct wl1251 *wl;
int ret, i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
pdata = spi->dev.platform_data;
if (!pdata) {
- wl12xx_error("no platform data");
+ wl1251_error("no platform data");
return -ENODEV;
}
- hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
+ hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
if (!hw) {
- wl12xx_error("could not alloc ieee80211_hw");
+ wl1251_error("could not alloc ieee80211_hw");
return -ENOMEM;
}
@@ -1202,9 +1221,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->tx_work, wl12xx_tx_work);
- INIT_WORK(&wl->filter_work, wl12xx_filter_work);
- wl->channel = WL12XX_DEFAULT_CHANNEL;
+ INIT_WORK(&wl->filter_work, wl1251_filter_work);
+ wl->channel = WL1251_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
wl->listen_int = 1;
@@ -1212,17 +1230,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->rx_handled = 0;
wl->rx_current_buffer = 0;
wl->rx_last_id = 0;
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
wl->elp = false;
wl->psm = 0;
wl->psm_requested = false;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
/* We use the default power on sleep time until we know which chip
* we're using */
- wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP;
+ wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP;
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
wl->tx_frames[i] = NULL;
@@ -1236,37 +1254,46 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
+ wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+ if (!wl->rx_descriptor) {
+ wl1251_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;
ret = spi_setup(spi);
if (ret < 0) {
- wl12xx_error("spi_setup failed");
+ wl1251_error("spi_setup failed");
goto out_free;
}
wl->set_power = pdata->set_power;
if (!wl->set_power) {
- wl12xx_error("set power function missing in platform data");
- return -ENODEV;
+ wl1251_error("set power function missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
wl->irq = spi->irq;
if (wl->irq < 0) {
- wl12xx_error("irq missing in platform data");
- return -ENODEV;
+ wl1251_error("irq missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
- ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
+ ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
if (ret < 0) {
- wl12xx_error("request_irq() failed: %d", ret);
+ wl1251_error("request_irq() failed: %d", ret);
goto out_free;
}
@@ -1274,17 +1301,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
disable_irq(wl->irq);
- ret = wl12xx_init_ieee80211(wl);
+ ret = wl1251_init_ieee80211(wl);
if (ret)
goto out_irq;
- ret = wl12xx_register_hw(wl);
+ ret = wl1251_register_hw(wl);
if (ret)
goto out_irq;
- wl12xx_debugfs_init(wl);
+ wl1251_debugfs_init(wl);
- wl12xx_notice("initialized");
+ wl1251_notice("initialized");
return 0;
@@ -1292,18 +1319,21 @@ static int __devinit wl12xx_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;
}
-static int __devexit wl12xx_remove(struct spi_device *spi)
+static int __devexit wl1251_remove(struct spi_device *spi)
{
- struct wl12xx *wl = dev_get_drvdata(&spi->dev);
+ struct wl1251 *wl = dev_get_drvdata(&spi->dev);
ieee80211_unregister_hw(wl->hw);
- wl12xx_debugfs_exit(wl);
+ wl1251_debugfs_exit(wl);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
@@ -1312,30 +1342,35 @@ static int __devexit wl12xx_remove(struct spi_device *spi)
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
+
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
ieee80211_free_hw(wl->hw);
return 0;
}
-static struct spi_driver wl12xx_spi_driver = {
+static struct spi_driver wl1251_spi_driver = {
.driver = {
+ /* FIXME: use wl12xx name to not break the user space */
.name = "wl12xx",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
- .probe = wl12xx_probe,
- .remove = __devexit_p(wl12xx_remove),
+ .probe = wl1251_probe,
+ .remove = __devexit_p(wl1251_remove),
};
-static int __init wl12xx_init(void)
+static int __init wl1251_init(void)
{
int ret;
- ret = spi_register_driver(&wl12xx_spi_driver);
+ ret = spi_register_driver(&wl1251_spi_driver);
if (ret < 0) {
- wl12xx_error("failed to register spi driver: %d", ret);
+ wl1251_error("failed to register spi driver: %d", ret);
goto out;
}
@@ -1343,15 +1378,15 @@ out:
return ret;
}
-static void __exit wl12xx_exit(void)
+static void __exit wl1251_exit(void)
{
- spi_unregister_driver(&wl12xx_spi_driver);
+ spi_unregister_driver(&wl1251_spi_driver);
- wl12xx_notice("unloaded");
+ wl1251_notice("unloaded");
}
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
+module_init(wl1251_init);
+module_exit(wl1251_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, "
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
new file mode 100644
index 000000000000..ee36695e134e
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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 __WL1251_NETLINK_H__
+#define __WL1251_NETLINK_H__
+
+int wl1251_nl_register(void);
+void wl1251_nl_unregister(void);
+
+#endif /* __WL1251_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251_ops.c
index ce1561a41fa4..e7b9aab3682f 100644
--- a/drivers/net/wireless/wl12xx/wl1251.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -24,18 +24,18 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl1251.h"
+#include "wl1251_ops.h"
#include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-
-static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
+#include "wl1251_spi.h"
+#include "wl1251_boot.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+
+static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
@@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = {
[ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804)
};
-static int wl1251_upload_firmware(struct wl12xx *wl)
+static int wl1251_upload_firmware(struct wl1251 *wl)
{
- struct wl12xx_partition_set *p_table = wl->chip.p_table;
+ struct wl1251_partition_set *p_table = wl->chip.p_table;
int addr, chunk_num, partition_limit;
size_t fw_data_len;
u8 *p;
/* whal_FwCtrl_LoadFwImageSm() */
- wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
- wl12xx_reg_read32(wl, CHIP_ID_B));
+ wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
+ wl1251_reg_read32(wl, CHIP_ID_B));
/* 10.0 check firmware length and set partition */
fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
(wl->fw[6] << 8) | (wl->fw[7]);
- wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
+ wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
CHUNK_SIZE);
if ((fw_data_len % 4) != 0) {
- wl12xx_error("firmware length not multiple of four");
+ wl1251_error("firmware length not multiple of four");
return -EIO;
}
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
p_table[PART_DOWN].mem.start,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
p_table[PART_DOWN].mem.size;
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
addr,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.3 upload the chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE);
chunk_num++;
}
@@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.4 upload the last chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
return 0;
}
-static int wl1251_upload_nvs(struct wl12xx *wl)
+static int wl1251_upload_nvs(struct wl1251 *wl)
{
size_t nvs_len, nvs_bytes_written, burst_len;
int nvs_start, i;
@@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl12xx_mem_write32(wl, dest_addr, val);
+ wl1251_mem_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
nvs_len = ALIGN(nvs_len, 4);
/* Now we must set the partition correctly */
- wl12xx_set_partition(wl, nvs_start,
+ wl1251_set_partition(wl, nvs_start,
wl->chip.p_table[PART_DOWN].mem.size,
wl->chip.p_table[PART_DOWN].reg.start,
wl->chip.p_table[PART_DOWN].reg.size);
@@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = cpu_to_le32(val);
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs write table 0x%x: 0x%x",
nvs_start, val);
- wl12xx_mem_write32(wl, nvs_start, val);
+ wl1251_mem_write32(wl, nvs_start, val);
nvs_ptr += 4;
nvs_bytes_written += 4;
@@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
return 0;
}
-static int wl1251_boot(struct wl12xx *wl)
+static int wl1251_boot(struct wl1251 *wl)
{
int ret = 0, minor_minor_e2_ver;
u32 tmp, boot_data;
- ret = wl12xx_boot_soft_reset(wl);
+ ret = wl1251_boot_soft_reset(wl);
if (ret < 0)
goto out;
@@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl)
/* write firmware's last address (ie. it's length) to
* ACX_EEPROMLESS_IND_REG */
- wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+ wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
/* 6. read the EEPROM parameters */
- tmp = wl12xx_reg_read32(wl, SCR_PAD2);
+ tmp = wl1251_reg_read32(wl, SCR_PAD2);
/* 7. read bootdata */
wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
- tmp = wl12xx_reg_read32(wl, SCR_PAD3);
+ tmp = wl1251_reg_read32(wl, SCR_PAD3);
/* 8. check bootdata and call restart sequence */
wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
- wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
+ wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
"minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
wl->boot_attr.radio_type, wl->boot_attr.major,
wl->boot_attr.minor, minor_minor_e2_ver);
- ret = wl12xx_boot_init_seq(wl);
+ ret = wl1251_boot_init_seq(wl);
if (ret < 0)
goto out;
/* 9. NVS processing done */
- boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
- wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
+ wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
/* 10. check that ECPU_CONTROL_HALT bits are set in
* pWhalBus->uBootData and start uploading firmware
*/
if ((boot_data & ECPU_CONTROL_HALT) == 0) {
- wl12xx_error("boot failed, ECPU_CONTROL_HALT not set");
+ wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
ret = -EIO;
goto out;
}
@@ -284,62 +284,62 @@ static int wl1251_boot(struct wl12xx *wl)
goto out;
/* 10.5 start firmware */
- ret = wl12xx_boot_run_firmware(wl);
+ ret = wl1251_boot_run_firmware(wl);
if (ret < 0)
goto out;
- /* Get and save the firmware version */
- wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
-
out:
return ret;
}
-static int wl1251_mem_cfg(struct wl12xx *wl)
+static int wl1251_mem_cfg(struct wl1251 *wl)
{
- struct wl1251_acx_config_memory mem_conf;
+ struct wl1251_acx_config_memory *mem_conf;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg");
+ wl1251_debug(DEBUG_ACX, "wl1251 mem cfg");
+
+ mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+ if (!mem_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
/* memory config */
- mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
- mem_conf.mem_config.rx_mem_block_num = 35;
- mem_conf.mem_config.tx_min_mem_block_num = 64;
- mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES;
- mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING;
- mem_conf.mem_config.num_ssid_profiles = 1;
- mem_conf.mem_config.debug_buffer_size =
+ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->mem_config.rx_mem_block_num = 35;
+ mem_conf->mem_config.tx_min_mem_block_num = 64;
+ mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
+ mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
+ mem_conf->mem_config.num_ssid_profiles = 1;
+ mem_conf->mem_config.debug_buffer_size =
cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
/* RX queue config */
- mem_conf.rx_queue_config.dma_address = 0;
- mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF;
- mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
- mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE;
+ mem_conf->rx_queue_config.dma_address = 0;
+ mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
+ mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
+ mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
/* TX queue config */
for (i = 0; i < MAX_TX_QUEUES; i++) {
- mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
- mem_conf.tx_queue_config[i].attributes = i;
+ mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
+ mem_conf->tx_queue_config[i].attributes = i;
}
- mem_conf.header.id = ACX_MEM_CFG;
- mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) -
- sizeof(struct acx_header);
- mem_conf.header.len -=
- (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) *
- sizeof(struct wl1251_acx_tx_queue_config);
-
- ret = wl12xx_cmd_configure(wl, &mem_conf,
- sizeof(struct wl1251_acx_config_memory));
- if (ret < 0)
- wl12xx_warning("wl1251 mem config failed: %d", ret);
+ ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+ sizeof(*mem_conf));
+ if (ret < 0) {
+ wl1251_warning("wl1251 mem config failed: %d", ret);
+ goto out;
+ }
+out:
+ kfree(mem_conf);
return ret;
}
-static int wl1251_hw_init_mem_config(struct wl12xx *wl)
+static int wl1251_hw_init_mem_config(struct wl1251 *wl)
{
int ret;
@@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
GFP_KERNEL);
if (!wl->target_mem_map) {
- wl12xx_error("couldn't allocate target memory map");
+ wl1251_error("couldn't allocate target memory map");
return -ENOMEM;
}
/* we now ask for the firmware built memory map */
- ret = wl12xx_acx_mem_map(wl, wl->target_mem_map,
+ ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
sizeof(struct wl1251_acx_mem_map));
if (ret < 0) {
- wl12xx_error("couldn't retrieve firmware memory map");
+ wl1251_error("couldn't retrieve firmware memory map");
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
return ret;
@@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
return 0;
}
-static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag)
+static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
{
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl &= ~flag;
- wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
-static void wl1251_target_enable_interrupts(struct wl12xx *wl)
+static void wl1251_target_enable_interrupts(struct wl1251 *wl)
{
/* Enable target's interrupts */
wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
@@ -388,52 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl)
WL1251_ACX_INTR_EVENT_A |
WL1251_ACX_INTR_EVENT_B |
WL1251_ACX_INTR_INIT_COMPLETE;
- wl12xx_boot_target_enable_interrupts(wl);
+ wl1251_boot_target_enable_interrupts(wl);
+}
+
+static void wl1251_fw_version(struct wl1251 *wl)
+{
+ wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
}
static void wl1251_irq_work(struct work_struct *work)
{
u32 intr;
- struct wl12xx *wl =
- container_of(work, struct wl12xx, irq_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, irq_work);
+ int ret;
mutex_lock(&wl->mutex);
- wl12xx_debug(DEBUG_IRQ, "IRQ work");
+ wl1251_debug(DEBUG_IRQ, "IRQ work");
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
if (wl->data_path) {
- wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
- &wl->rx_counter, sizeof(u32));
+ wl->rx_counter =
+ wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
- /* We handle a frmware bug here */
+ /* We handle a firmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
case 0:
- wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync");
+ wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
intr &= ~WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 1:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +1");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +1");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 2:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +2");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +2");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr |= WL1251_ACX_INTR_RX1_DATA;
break;
default:
- wl12xx_warning("RX: FW and host out of sync: %d",
+ wl1251_warning("RX: FW and host out of sync: %d",
wl->rx_counter - wl->rx_handled);
break;
}
@@ -441,49 +449,50 @@ static void wl1251_irq_work(struct work_struct *work)
wl->rx_handled = wl->rx_counter;
- wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
+ wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
}
intr &= wl->intr_mask;
if (intr == 0) {
- wl12xx_debug(DEBUG_IRQ, "INTR is 0");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1251_debug(DEBUG_IRQ, "INTR is 0");
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
~(wl->intr_mask));
goto out_sleep;
}
if (intr & WL1251_ACX_INTR_RX0_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_RX1_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_TX_RESULT) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
- wl12xx_tx_complete(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+ wl1251_tx_complete(wl);
}
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
if (intr & WL1251_ACX_INTR_EVENT_A)
- wl12xx_event_handle(wl, 0);
+ wl1251_event_handle(wl, 0);
else
- wl12xx_event_handle(wl, 1);
+ wl1251_event_handle(wl, 1);
}
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
out_sleep:
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -520,40 +529,45 @@ static int wl1251_hw_init_txq_fill(u8 qid,
(QOS_TX_LOW_VO_DEF * num_blocks) / 100;
break;
default:
- wl12xx_error("Invalid TX queue id: %d", qid);
+ wl1251_error("Invalid TX queue id: %d", qid);
return -EINVAL;
}
return 0;
}
-static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl)
+static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
{
- struct acx_tx_queue_qos_config config;
+ struct acx_tx_queue_qos_config *config;
struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "acx tx queue config");
+ wl1251_debug(DEBUG_ACX, "acx tx queue config");
- config.header.id = ACX_TX_QUEUE_CFG;
- config.header.len = sizeof(struct acx_tx_queue_qos_config) -
- sizeof(struct acx_header);
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < MAX_NUM_OF_AC; i++) {
- ret = wl1251_hw_init_txq_fill(i, &config,
+ ret = wl1251_hw_init_txq_fill(i, config,
wl_mem_map->num_tx_mem_blocks);
if (ret < 0)
- return ret;
+ goto out;
- ret = wl12xx_cmd_configure(wl, &config, sizeof(config));
+ ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
+ config, sizeof(*config));
if (ret < 0)
- return ret;
+ goto out;
}
- return 0;
+out:
+ kfree(config);
+ return ret;
}
-static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
+static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
{
int ret;
@@ -561,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
GFP_KERNEL);
if (!wl->data_path) {
- wl12xx_error("Couldnt allocate data path parameters");
+ wl1251_error("Couldn't allocate data path parameters");
return -ENOMEM;
}
- ret = wl12xx_acx_data_path_params(wl, wl->data_path);
+ ret = wl1251_acx_data_path_params(wl, wl->data_path);
if (ret < 0) {
kfree(wl->data_path);
wl->data_path = NULL;
@@ -575,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
return 0;
}
-static int wl1251_hw_init(struct wl12xx *wl)
+static int wl1251_hw_init(struct wl1251 *wl)
{
struct wl1251_acx_mem_map *wl_mem_map;
int ret;
- ret = wl12xx_hw_init_hwenc_config(wl);
+ ret = wl1251_hw_init_hwenc_config(wl);
if (ret < 0)
return ret;
/* Template settings */
- ret = wl12xx_hw_init_templates_config(wl);
+ ret = wl1251_hw_init_templates_config(wl);
if (ret < 0)
return ret;
@@ -600,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_memmap;
/* RX config */
- ret = wl12xx_hw_init_rx_config(wl,
+ ret = wl1251_hw_init_rx_config(wl,
RX_CFG_PROMISCUOUS | RX_CFG_TSF,
RX_FILTER_OPTION_DEF);
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
@@ -614,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_data_path;
/* PHY layer config */
- ret = wl12xx_hw_init_phy_config(wl);
+ ret = wl1251_hw_init_phy_config(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacon filtering */
- ret = wl12xx_hw_init_beacon_filter(wl);
+ ret = wl1251_hw_init_beacon_filter(wl);
if (ret < 0)
goto out_free_data_path;
/* Bluetooth WLAN coexistence */
- ret = wl12xx_hw_init_pta(wl);
+ ret = wl1251_hw_init_pta(wl);
if (ret < 0)
goto out_free_data_path;
/* Energy detection */
- ret = wl12xx_hw_init_energy_detection(wl);
+ ret = wl1251_hw_init_energy_detection(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacons and boradcast settings */
- ret = wl12xx_hw_init_beacon_broadcast(wl);
+ ret = wl1251_hw_init_beacon_broadcast(wl);
if (ret < 0)
goto out_free_data_path;
/* Enable data path */
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
goto out_free_data_path;
/* Default power state */
- ret = wl12xx_hw_init_power_auth(wl);
+ ret = wl1251_hw_init_power_auth(wl);
if (ret < 0)
goto out_free_data_path;
wl_mem_map = wl->target_mem_map;
- wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
+ wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
wl_mem_map->num_tx_mem_blocks,
wl->data_path->tx_control_addr,
wl_mem_map->num_rx_mem_blocks,
@@ -666,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
return ret;
}
-static int wl1251_plt_init(struct wl12xx *wl)
+static int wl1251_plt_init(struct wl1251 *wl)
{
int ret;
@@ -674,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl)
if (ret < 0)
return ret;
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
return ret;
return 0;
}
-void wl1251_setup(struct wl12xx *wl)
+void wl1251_setup(struct wl1251 *wl)
{
/* FIXME: Is it better to use strncpy here or is this ok? */
wl->chip.fw_filename = WL1251_FW_NAME;
@@ -701,9 +715,14 @@ void wl1251_setup(struct wl12xx *wl)
wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts;
wl->chip.op_hw_init = wl1251_hw_init;
wl->chip.op_plt_init = wl1251_plt_init;
+ wl->chip.op_fw_version = wl1251_fw_version;
+ wl->chip.op_tx_flush = wl1251_tx_flush;
+ wl->chip.op_cmd_join = wl1251_cmd_join;
wl->chip.p_table = wl1251_part_table;
wl->chip.acx_reg_table = wl1251_acx_reg_table;
INIT_WORK(&wl->irq_work, wl1251_irq_work);
+ INIT_WORK(&wl->tx_work, wl1251_tx_work);
+
}
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h
new file mode 100644
index 000000000000..68183c472e43
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.h
@@ -0,0 +1,165 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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 __WL1251_OPS_H__
+#define __WL1251_OPS_H__
+
+#include <linux/bitops.h>
+
+#include "wl1251.h"
+#include "wl1251_acx.h"
+
+#define WL1251_FW_NAME "wl1251-fw.bin"
+#define WL1251_NVS_NAME "wl1251-nvs.bin"
+
+#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
+
+void wl1251_setup(struct wl1251 *wl);
+
+
+struct wl1251_acx_memory {
+ __le16 num_stations; /* number of STAs to be supported. */
+ u16 reserved_1;
+
+ /*
+ * Nmber of memory buffers for the RX mem pool.
+ * The actual number may be less if there are
+ * not enough blocks left for the minimum num
+ * of TX ones.
+ */
+ u8 rx_mem_block_num;
+ u8 reserved_2;
+ u8 num_tx_queues; /* From 1 to 16 */
+ u8 host_if_options; /* HOST_IF* */
+ u8 tx_min_mem_block_num;
+ u8 num_ssid_profiles;
+ __le16 debug_buffer_size;
+} __attribute__ ((packed));
+
+
+#define ACX_RX_DESC_MIN 1
+#define ACX_RX_DESC_MAX 127
+#define ACX_RX_DESC_DEF 32
+struct wl1251_acx_rx_queue_config {
+ u8 num_descs;
+ u8 pad;
+ u8 type;
+ u8 priority;
+ __le32 dma_address;
+} __attribute__ ((packed));
+
+#define ACX_TX_DESC_MIN 1
+#define ACX_TX_DESC_MAX 127
+#define ACX_TX_DESC_DEF 16
+struct wl1251_acx_tx_queue_config {
+ u8 num_descs;
+ u8 pad[2];
+ u8 attributes;
+} __attribute__ ((packed));
+
+#define MAX_TX_QUEUE_CONFIGS 5
+#define MAX_TX_QUEUES 4
+struct wl1251_acx_config_memory {
+ struct acx_header header;
+
+ struct wl1251_acx_memory mem_config;
+ struct wl1251_acx_rx_queue_config rx_queue_config;
+ struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
+} __attribute__ ((packed));
+
+struct wl1251_acx_mem_map {
+ struct acx_header header;
+
+ void *code_start;
+ void *code_end;
+
+ void *wep_defkey_start;
+ void *wep_defkey_end;
+
+ void *sta_table_start;
+ void *sta_table_end;
+
+ void *packet_template_start;
+ void *packet_template_end;
+
+ void *queue_memory_start;
+ void *queue_memory_end;
+
+ void *packet_memory_pool_start;
+ void *packet_memory_pool_end;
+
+ void *debug_buffer1_start;
+ void *debug_buffer1_end;
+
+ void *debug_buffer2_start;
+ void *debug_buffer2_end;
+
+ /* Number of blocks FW allocated for TX packets */
+ u32 num_tx_mem_blocks;
+
+ /* Number of blocks FW allocated for RX packets */
+ u32 num_rx_mem_blocks;
+} __attribute__ ((packed));
+
+/*************************************************************************
+
+ Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+
+/* RX packet is ready in Xfer buffer #0 */
+#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+
+/* TX result(s) are in the TX complete buffer */
+#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_TX_XFR BIT(2)
+
+/* RX packet is ready in Xfer buffer #1 */
+#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+
+/* Event was entered to Event MBOX #A */
+#define WL1251_ACX_INTR_EVENT_A BIT(4)
+
+/* Event was entered to Event MBOX #B */
+#define WL1251_ACX_INTR_EVENT_B BIT(5)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+
+/* Trace meassge on MBOX #A */
+#define WL1251_ACX_INTR_TRACE_A BIT(7)
+
+/* Trace meassge on MBOX #B */
+#define WL1251_ACX_INTR_TRACE_B BIT(8)
+
+/* Command processing completion */
+#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+
+/* Init sequence is done */
+#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+
+#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index 83a10117330b..68ff7f1900ed 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -22,25 +22,25 @@
*/
#include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_spi.h"
-#define WL12XX_WAKEUP_TIMEOUT 2000
+#define WL1251_WAKEUP_TIMEOUT 2000
/* Routines to toggle sleep mode while in ELP */
-void wl12xx_ps_elp_sleep(struct wl12xx *wl)
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
{
if (wl->elp || !wl->psm)
return;
- wl12xx_debug(DEBUG_PSM, "chip to elp");
+ wl1251_debug(DEBUG_PSM, "chip to elp");
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true;
}
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
unsigned long timeout;
u32 elp_reg;
@@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
if (!wl->elp)
return 0;
- wl12xx_debug(DEBUG_PSM, "waking up chip from elp");
+ wl1251_debug(DEBUG_PSM, "waking up chip from elp");
- timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT);
+ timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
/*
* FIXME: we should wait for irq from chip but, as a temporary
@@ -62,40 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
*/
while (!(elp_reg & ELPCTRL_WLAN_READY)) {
if (time_after(jiffies, timeout)) {
- wl12xx_error("elp wakeup timeout");
+ wl1251_error("elp wakeup timeout");
return -ETIMEDOUT;
}
msleep(1);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
}
- wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms",
+ wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT));
+ (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
wl->elp = false;
return 0;
}
-static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
{
int ret;
if (enable) {
- wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp");
+ wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
- /*
- * FIXME: we should PSM_ELP, but because of firmware wakeup
- * problems let's use only PSM_PS
- */
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
} else {
- wl12xx_debug(DEBUG_PSM, "sleep auth cam");
+ wl1251_debug(DEBUG_PSM, "sleep auth cam");
/*
* When the target is in ELP, we can only
@@ -104,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
* changing the power authorization.
*/
- wl12xx_ps_elp_wakeup(wl);
+ wl1251_ps_elp_wakeup(wl);
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
if (ret < 0)
return ret;
}
@@ -114,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
return 0;
}
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
{
int ret;
switch (mode) {
case STATION_POWER_SAVE_MODE:
- wl12xx_debug(DEBUG_PSM, "entering psm");
- ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ wl1251_debug(DEBUG_PSM, "entering psm");
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
- ret = wl12xx_ps_set_elp(wl, true);
+ ret = wl1251_ps_set_elp(wl, true);
if (ret < 0)
return ret;
@@ -133,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
break;
case STATION_ACTIVE_MODE:
default:
- wl12xx_debug(DEBUG_PSM, "leaving psm");
- ret = wl12xx_ps_set_elp(wl, false);
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1251_ps_set_elp(wl, false);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h
index 5d7c52553830..db036fe12f25 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.h
@@ -1,8 +1,8 @@
-#ifndef __WL12XX_PS_H__
-#define __WL12XX_PS_H__
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,12 +25,12 @@
*
*/
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode);
-void wl12xx_ps_elp_sleep(struct wl12xx *wl);
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+void wl1251_ps_elp_sleep(struct wl1251 *wl);
+int wl1251_ps_elp_wakeup(struct wl1251 *wl);
-#endif /* __WL12XX_PS_H__ */
+#endif /* __WL1251_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 981ea259eb89..0dbb483a0973 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,14 @@
#include <linux/skbuff.h>
#include <net/mac80211.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251_spi.h"
+#include "wl1251_rx.h"
+#include "wl1251_acx.h"
-static void wl12xx_rx_header(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_header(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
u32 rx_packet_ring_addr;
@@ -39,15 +40,17 @@ static void wl12xx_rx_header(struct wl12xx *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
- sizeof(struct wl12xx_rx_descriptor));
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
}
-static void wl12xx_rx_status(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc,
+static void wl1251_rx_status(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc,
struct ieee80211_rx_status *status,
u8 beacon)
{
+ u64 mactime;
+ int ret;
+
memset(status, 0, sizeof(struct ieee80211_rx_status));
status->band = IEEE80211_BAND_2GHZ;
@@ -62,32 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl,
* this one must be atomic, while our SPI routines can sleep.
*/
if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
- u64 mactime;
- int ret;
- struct wl12xx_command cmd;
- struct acx_tsf_info *tsf_info;
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO,
- sizeof(struct acx_tsf_info),
- &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return;
- }
-
- tsf_info = (struct acx_tsf_info *)&(cmd.parameters);
-
- mactime = tsf_info->current_tsf_lsb |
- (tsf_info->current_tsf_msb << 31);
-
- status->mactime = mactime;
+ ret = wl1251_acx_tsf_info(wl, &mactime);
+ if (ret == 0)
+ status->mactime = mactime;
}
status->signal = desc->rssi;
- status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 /
- (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI);
+ status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
+ (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
status->qual = min(status->qual, 100);
status->qual = max(status->qual, 0);
@@ -118,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl,
/* FIXME: set status->rate_idx */
}
-static void wl12xx_rx_body(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_body(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
struct sk_buff *skb;
struct ieee80211_rx_status status;
@@ -127,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl,
u16 length, *fc;
u32 curr_id, last_id_inc, rx_packet_ring_addr;
- length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
+ length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
if (last_id_inc != curr_id) {
- wl12xx_warning("curr ID:%d, last ID inc:%d",
+ wl1251_warning("curr ID:%d, last ID inc:%d",
curr_id, last_id_inc);
wl->rx_last_id = curr_id;
} else {
@@ -140,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl,
}
rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
- sizeof(struct wl12xx_rx_descriptor) + 20;
+ sizeof(struct wl1251_rx_descriptor) + 20;
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
skb = dev_alloc_skb(length);
if (!skb) {
- wl12xx_error("Couldn't allocate RX frame");
+ wl1251_error("Couldn't allocate RX frame");
return;
}
rx_buffer = skb_put(skb, length);
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual lenght doesn't include the target's alignment */
skb->len = desc->length - PLCP_HEADER_LENGTH;
@@ -161,15 +146,16 @@ static void wl12xx_rx_body(struct wl12xx *wl,
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- wl12xx_rx_status(wl, desc, &status, beacon);
+ wl1251_rx_status(wl, desc, &status, beacon);
- wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
beacon ? "beacon" : "");
- ieee80211_rx(wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(wl->hw, skb);
}
-static void wl12xx_rx_ack(struct wl12xx *wl)
+static void wl1251_rx_ack(struct wl1251 *wl)
{
u32 data, addr;
@@ -181,28 +167,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl)
data = INTR_TRIG_RX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Toggle buffer ring */
wl->rx_current_buffer = !wl->rx_current_buffer;
}
-void wl12xx_rx(struct wl12xx *wl)
+void wl1251_rx(struct wl1251 *wl)
{
- struct wl12xx_rx_descriptor rx_desc;
+ struct wl1251_rx_descriptor *rx_desc;
- if (wl->state != WL12XX_STATE_ON)
+ if (wl->state != WL1251_STATE_ON)
return;
+ rx_desc = wl->rx_descriptor;
+
/* We first read the frame's header */
- wl12xx_rx_header(wl, &rx_desc);
+ wl1251_rx_header(wl, rx_desc);
/* Now we can read the body */
- wl12xx_rx_body(wl, &rx_desc);
+ wl1251_rx_body(wl, rx_desc);
/* Finally, we need to ACK the RX */
- wl12xx_rx_ack(wl);
+ wl1251_rx_ack(wl);
return;
}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fdea5016..563a3fde40fb 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,13 @@
*
*/
-#ifndef __WL12XX_RX_H__
-#define __WL12XX_RX_H__
+#ifndef __WL1251_RX_H__
+#define __WL1251_RX_H__
#include <linux/bitops.h>
+#include "wl1251.h"
+
/*
* RX PATH
*
@@ -43,12 +45,12 @@
* 4) The target prepares the next RX packet.
*/
-#define WL12XX_RX_MAX_RSSI -30
-#define WL12XX_RX_MIN_RSSI -95
+#define WL1251_RX_MAX_RSSI -30
+#define WL1251_RX_MIN_RSSI -95
-#define WL12XX_RX_ALIGN_TO 4
-#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \
- ~(WL12XX_RX_ALIGN_TO - 1))
+#define WL1251_RX_ALIGN_TO 4
+#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \
+ ~(WL1251_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6)
@@ -72,7 +74,7 @@
#define RX_DESC_MIC_FAIL 0x2000
#define RX_DESC_DECRYPT_FAIL 0x4000
-struct wl12xx_rx_descriptor {
+struct wl1251_rx_descriptor {
u32 timestamp; /* In microseconds */
u16 length; /* Paylod length, including headers */
u16 flags;
@@ -86,7 +88,7 @@ struct wl12xx_rx_descriptor {
u8 type;
/*
- * Recevied Rate:
+ * Received Rate:
* 0x0A - 1MBPS
* 0x14 - 2MBPS
* 0x37 - 5_5MBPS
@@ -117,6 +119,6 @@ struct wl12xx_rx_descriptor {
u8 snr; /* in dB */
} __attribute__ ((packed));
-void wl12xx_rx(struct wl12xx *wl);
+void wl1251_rx(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index abdf171a47e7..c5da79dbc49c 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -25,13 +25,11 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr)
{
/* If the address is lower than REGISTERS_BASE, it means that this is
* a chip-specific register address, so look it up in the registers
@@ -39,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
if (addr < REGISTERS_BASE) {
/* Make sure we don't go over the table */
if (addr >= ACX_REG_TABLE_LEN) {
- wl12xx_error("address out of range (%d)", addr);
+ wl1251_error("address out of range (%d)", addr);
return -EINVAL;
}
addr = wl->chip.acx_reg_table[addr];
@@ -48,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
}
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr)
{
return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
}
-void wl12xx_spi_reset(struct wl12xx *wl)
+void wl1251_spi_reset(struct wl1251 *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -62,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi reset");
+ wl1251_error("could not allocate cmd for spi reset");
return;
}
@@ -77,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-void wl12xx_spi_init(struct wl12xx *wl)
+void wl1251_spi_init(struct wl1251 *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -88,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi init");
+ wl1251_error("could not allocate cmd for spi init");
return;
}
@@ -131,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
/* Set the SPI partitions to access the chip addresses
@@ -167,45 +165,47 @@ void wl12xx_spi_init(struct wl12xx *wl)
* | |
*
*/
-void wl12xx_set_partition(struct wl12xx *wl,
+int wl1251_set_partition(struct wl1251 *wl,
u32 mem_start, u32 mem_size,
u32 reg_start, u32 reg_size)
{
- u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
- struct wl12xx_partition *partition;
+ struct wl1251_partition *partition;
struct spi_transfer t;
struct spi_message m;
+ size_t len, cmd_len;
u32 *cmd;
- size_t len;
int addr;
+ cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition);
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
spi_message_init(&m);
memset(&t, 0, sizeof(t));
- memset(tx_buf, 0, sizeof(tx_buf));
- cmd = (u32 *) tx_buf;
- partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
+ partition = (struct wl1251_partition *) (cmd + 1);
addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl12xx_partition);
+ len = 2 * sizeof(struct wl1251_partition);
*cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_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) {
- wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
" address range. Truncating partition[0].");
mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -213,23 +213,23 @@ void wl12xx_set_partition(struct wl12xx *wl,
((mem_start + mem_size) > reg_start)) {
/* Guarantee that the memory partition doesn't overlap the
* registers partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+ wl1251_debug(DEBUG_SPI, "End of partition[0] is "
"overlapping partition[1]. Adjusted.");
mem_size = reg_start - mem_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_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 */
- wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+ wl1251_debug(DEBUG_SPI, "End of partition[1] is"
" overlapping partition[0]. Adjusted.");
reg_size = mem_start - reg_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -244,36 +244,46 @@ void wl12xx_set_partition(struct wl12xx *wl,
wl->virtual_mem_addr = 0;
wl->virtual_reg_addr = mem_size;
- t.tx_buf = tx_buf;
- t.len = sizeof(tx_buf);
+ t.tx_buf = cmd;
+ t.len = cmd_len;
spi_message_add_tail(&t, &m);
spi_sync(wl->spi, &m);
+
+ kfree(cmd);
+
+ return 0;
}
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- char busy_buf[TNETWIF_READ_OFFSET_BYTES];
- u32 cmd;
+ u8 *busy_buf;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
- cmd = 0;
- cmd |= WSPI_CMD_READ;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
+ t[0].tx_buf = cmd;
t[0].len = 4;
spi_message_add_tail(&t[0], &m);
/* Busy and non busy words read */
t[1].rx_buf = busy_buf;
- t[1].len = TNETWIF_READ_OFFSET_BYTES;
+ t[1].len = WL1251_BUSY_WORD_LEN;
spi_message_add_tail(&t[1], &m);
t[2].rx_buf = buf;
@@ -284,27 +294,32 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
/* FIXME: check busy words */
- wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
- u32 cmd;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
- cmd = 0;
- cmd |= WSPI_CMD_WRITE;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
- t[0].len = sizeof(cmd);
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(*cmd);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
@@ -313,46 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
- wl12xx_spi_read(wl, physical, buf, len);
+ wl1251_spi_read(wl, physical, buf, len, false);
}
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
+
+ wl1251_spi_write(wl, physical, buf, len, false);
+}
+
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
+
+ wl1251_spi_read(wl, physical, buf, len, fixed);
+}
+
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
- wl12xx_spi_write(wl, physical, buf, len);
+ wl1251_spi_write(wl, physical, buf, len, fixed);
}
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr));
}
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val);
}
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr));
}
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val);
}
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h
index fd3227e904a8..6e8daf4e1085 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,11 @@
*
*/
-#ifndef __WL12XX_SPI_H__
-#define __WL12XX_SPI_H__
+#ifndef __WL1251_SPI_H__
+#define __WL1251_SPI_H__
-#include "cmd.h"
-#include "acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
@@ -65,45 +65,51 @@
#define WSPI_INIT_CMD_LEN 8
-#define TNETWIF_READ_OFFSET_BYTES 8
#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
- ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32))
+ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
/* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr);
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val);
/* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr);
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val);
/* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
-void wl12xx_set_partition(struct wl12xx *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+void wl1251_spi_reset(struct wl1251 *wl);
+void wl1251_spi_init(struct wl1251 *wl);
+int wl1251_set_partition(struct wl1251 *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
{
- u32 response;
+ wl1251_spi_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
- return response;
+ return wl->buffer_32;
}
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+ wl->buffer_32 = val;
+ wl1251_spi_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
-#endif /* __WL12XX_SPI_H__ */
+#endif /* __WL1251_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index 62145e205a8c..2652a222383a 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "tx.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_tx.h"
+#include "wl1251_ps.h"
-static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
+static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
int used, data_in_count;
@@ -52,15 +52,15 @@ static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
return false;
}
-static int wl12xx_tx_path_status(struct wl12xx *wl)
+static int wl1251_tx_path_status(struct wl1251 *wl)
{
u32 status, addr, data_out_count;
bool busy;
addr = wl->data_path->tx_control_addr;
- status = wl12xx_mem_read32(wl, addr);
+ status = wl1251_mem_read32(wl, addr);
data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK;
- busy = wl12xx_tx_double_buffer_busy(wl, data_out_count);
+ busy = wl1251_tx_double_buffer_busy(wl, data_out_count);
if (busy)
return -EBUSY;
@@ -68,7 +68,7 @@ static int wl12xx_tx_path_status(struct wl12xx *wl)
return 0;
}
-static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb)
{
int i;
@@ -81,7 +81,7 @@ static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
return -EBUSY;
}
-static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
+static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
struct ieee80211_tx_info *control, u16 fc)
{
*(u16 *)&tx_hdr->control = 0;
@@ -109,7 +109,7 @@ static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \
WLAN_QOS_HDR_LEN)
#define HW_BLOCK_SIZE 252
-static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
+static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
{
u16 payload_len, frag_threshold, mem_blocks;
u16 num_mpdus, mem_blocks_per_frag;
@@ -142,7 +142,7 @@ static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
tx_hdr->num_mem_blocks = mem_blocks;
}
-static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -153,7 +153,7 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
if (!skb)
return -EINVAL;
- id = wl12xx_tx_id(wl, skb);
+ id = wl1251_tx_id(wl, skb);
if (id < 0)
return id;
@@ -170,14 +170,14 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
/* FIXME: how to get the correct queue id? */
tx_hdr->xmit_queue = 0;
- wl12xx_tx_control(tx_hdr, control, fc);
- wl12xx_tx_frag_block_num(tx_hdr);
+ wl1251_tx_control(tx_hdr, control, fc);
+ wl1251_tx_frag_block_num(tx_hdr);
return 0;
}
/* We copy the packet to the target */
-static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -196,12 +196,12 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
u8 *pos;
fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
- tx_hdr->length += WL12XX_TKIP_IV_SPACE;
+ tx_hdr->length += WL1251_TKIP_IV_SPACE;
hdrlen = ieee80211_hdrlen(fc);
- pos = skb_push(skb, WL12XX_TKIP_IV_SPACE);
- memmove(pos, pos + WL12XX_TKIP_IV_SPACE,
+ pos = skb_push(skb, WL1251_TKIP_IV_SPACE);
+ memmove(pos, pos + WL1251_TKIP_IV_SPACE,
sizeof(*tx_hdr) + hdrlen);
}
@@ -211,7 +211,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
*/
if (unlikely((long)skb->data & 0x03)) {
int offset = (4 - (long)skb->data) & 0x03;
- wl12xx_debug(DEBUG_TX, "skb offset %d", offset);
+ wl1251_debug(DEBUG_TX, "skb offset %d", offset);
/* check whether the current skb can be used */
if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
@@ -221,13 +221,13 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
} else {
- wl12xx_info("No handler, fixme!");
+ wl1251_info("No handler, fixme!");
return -EINVAL;
}
}
/* Our skb->data at this point includes the HW header */
- len = WL12XX_TX_ALIGN(skb->len);
+ len = WL1251_TX_ALIGN(skb->len);
if (wl->data_in_count & 0x1)
addr = wl->data_path->tx_packet_ring_addr +
@@ -235,15 +235,15 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
else
addr = wl->data_path->tx_packet_ring_addr;
- wl12xx_spi_mem_write(wl, addr, skb->data, len);
+ wl1251_spi_mem_write(wl, addr, skb->data, len);
- wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
+ wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
return 0;
}
-static void wl12xx_tx_trigger(struct wl12xx *wl)
+static void wl1251_tx_trigger(struct wl1251 *wl)
{
u32 data, addr;
@@ -255,7 +255,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
data = INTR_TRIG_TX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Bumping data in */
wl->data_in_count = (wl->data_in_count + 1) &
@@ -263,7 +263,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int ret = 0;
@@ -274,51 +274,53 @@ static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
if (info->control.hw_key) {
idx = info->control.hw_key->hw_key_idx;
if (unlikely(wl->default_key != idx)) {
- ret = wl12xx_acx_default_key(wl, idx);
+ ret = wl1251_acx_default_key(wl, idx);
if (ret < 0)
return ret;
}
}
- ret = wl12xx_tx_path_status(wl);
+ ret = wl1251_tx_path_status(wl);
if (ret < 0)
return ret;
- ret = wl12xx_tx_fill_hdr(wl, skb, info);
+ ret = wl1251_tx_fill_hdr(wl, skb, info);
if (ret < 0)
return ret;
- ret = wl12xx_tx_send_packet(wl, skb, info);
+ ret = wl1251_tx_send_packet(wl, skb, info);
if (ret < 0)
return ret;
- wl12xx_tx_trigger(wl);
+ wl1251_tx_trigger(wl);
return ret;
}
-void wl12xx_tx_work(struct work_struct *work)
+void wl1251_tx_work(struct work_struct *work)
{
- struct wl12xx *wl = container_of(work, struct wl12xx, tx_work);
+ struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
struct sk_buff *skb;
bool woken_up = false;
int ret;
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL12XX_STATE_OFF))
+ if (unlikely(wl->state == WL1251_STATE_OFF))
goto out;
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
woken_up = true;
}
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is full, stop queues */
- wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, "
+ wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
@@ -332,12 +334,12 @@ void wl12xx_tx_work(struct work_struct *work)
out:
if (woken_up)
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
}
-static const char *wl12xx_tx_parse_status(u8 status)
+static const char *wl1251_tx_parse_status(u8 status)
{
/* 8 bit status field, one character per bit plus null */
static char buf[9];
@@ -365,7 +367,7 @@ static const char *wl12xx_tx_parse_status(u8 status)
return buf;
}
-static void wl12xx_tx_packet_cb(struct wl12xx *wl,
+static void wl1251_tx_packet_cb(struct wl1251 *wl,
struct tx_result *result)
{
struct ieee80211_tx_info *info;
@@ -375,7 +377,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
skb = wl->tx_frames[result->id];
if (skb == NULL) {
- wl12xx_error("SKB for packet %d is NULL", result->id);
+ wl1251_error("SKB for packet %d is NULL", result->id);
return;
}
@@ -396,14 +398,14 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
if (info->control.hw_key &&
info->control.hw_key->alg == ALG_TKIP) {
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen);
- skb_pull(skb, WL12XX_TKIP_IV_SPACE);
+ memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
+ skb_pull(skb, WL1251_TKIP_IV_SPACE);
}
- wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x (%s)",
result->id, skb, result->ack_failures, result->rate,
- result->status, wl12xx_tx_parse_status(result->status));
+ result->status, wl1251_tx_parse_status(result->status));
ieee80211_tx_status(wl->hw, skb);
@@ -411,7 +413,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
wl->tx_frames[result->id] = NULL;
if (wl->tx_queue_stopped) {
- wl12xx_debug(DEBUG_TX, "cb: queue was stopped");
+ wl1251_debug(DEBUG_TX, "cb: queue was stopped");
skb = skb_dequeue(&wl->tx_queue);
@@ -420,10 +422,10 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
queue empty */
if (skb) {
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is still full */
- wl12xx_debug(DEBUG_TX, "cb: fw buffer "
+ wl1251_debug(DEBUG_TX, "cb: fw buffer "
"still full");
skb_queue_head(&wl->tx_queue, skb);
return;
@@ -433,23 +435,23 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
}
}
- wl12xx_debug(DEBUG_TX, "cb: waking queues");
+ wl1251_debug(DEBUG_TX, "cb: waking queues");
ieee80211_wake_queues(wl->hw);
wl->tx_queue_stopped = false;
}
}
/* Called upon reception of a TX complete interrupt */
-void wl12xx_tx_complete(struct wl12xx *wl)
+void wl1251_tx_complete(struct wl1251 *wl)
{
int i, result_index, num_complete = 0;
struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
- if (unlikely(wl->state != WL12XX_STATE_ON))
+ if (unlikely(wl->state != WL1251_STATE_ON))
return;
/* First we read the result */
- wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
+ wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr,
result, sizeof(result));
result_index = wl->next_tx_complete;
@@ -459,7 +461,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
if (result_ptr->done_1 == 1 &&
result_ptr->done_2 == 1) {
- wl12xx_tx_packet_cb(wl, result_ptr);
+ wl1251_tx_packet_cb(wl, result_ptr);
result_ptr->done_1 = 0;
result_ptr->done_2 = 0;
@@ -480,7 +482,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
*/
if (result_index > wl->next_tx_complete) {
/* Only 1 write is needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -491,7 +493,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else if (result_index < wl->next_tx_complete) {
/* 2 writes are needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -500,7 +502,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
wl->next_tx_complete) *
sizeof(struct tx_result));
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
(num_complete -
@@ -510,7 +512,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else {
/* We have to write the whole array */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
FW_TX_CMPLT_BLOCK_SIZE *
@@ -523,7 +525,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-void wl12xx_tx_flush(struct wl12xx *wl)
+void wl1251_tx_flush(struct wl1251 *wl)
{
int i;
struct sk_buff *skb;
@@ -535,7 +537,7 @@ void wl12xx_tx_flush(struct wl12xx *wl)
while ((skb = skb_dequeue(&wl->tx_queue))) {
info = IEEE80211_SKB_CB(skb);
- wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb);
if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
continue;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index dc82691f4c14..7c1c1665c810 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_TX_H__
-#define __WL12XX_TX_H__
+#ifndef __WL1251_TX_H__
+#define __WL1251_TX_H__
#include <linux/bitops.h>
@@ -73,10 +73,11 @@
#define TX_COMPLETE_REQUIRED_BIT 0x80
#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf
-#define WL12XX_TX_ALIGN_TO 4
-#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \
- ~(WL12XX_TX_ALIGN_TO - 1))
-#define WL12XX_TKIP_IV_SPACE 4
+
+#define WL1251_TX_ALIGN_TO 4
+#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \
+ ~(WL1251_TX_ALIGN_TO - 1))
+#define WL1251_TKIP_IV_SPACE 4
struct tx_control {
/* Rate Policy (class) index */
@@ -208,8 +209,8 @@ struct tx_result {
u8 done_2;
} __attribute__ ((packed));
-void wl12xx_tx_work(struct work_struct *work);
-void wl12xx_tx_complete(struct wl12xx *wl);
-void wl12xx_tx_flush(struct wl12xx *wl);
+void wl1251_tx_work(struct work_struct *work);
+void wl1251_tx_complete(struct wl1251 *wl);
+void wl1251_tx_flush(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
deleted file mode 100644
index 48641437414b..000000000000
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You 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 __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#define DRIVER_NAME "wl12xx"
-#define DRIVER_PREFIX DRIVER_NAME ": "
-
-enum {
- DEBUG_NONE = 0,
- DEBUG_IRQ = BIT(0),
- DEBUG_SPI = BIT(1),
- DEBUG_BOOT = BIT(2),
- DEBUG_MAILBOX = BIT(3),
- DEBUG_NETLINK = BIT(4),
- DEBUG_EVENT = BIT(5),
- DEBUG_TX = BIT(6),
- DEBUG_RX = BIT(7),
- DEBUG_SCAN = BIT(8),
- DEBUG_CRYPT = BIT(9),
- DEBUG_PSM = BIT(10),
- DEBUG_MAC80211 = BIT(11),
- DEBUG_CMD = BIT(12),
- DEBUG_ACX = BIT(13),
- DEBUG_ALL = ~0,
-};
-
-#define DEBUG_LEVEL (DEBUG_NONE)
-
-#define DEBUG_DUMP_LIMIT 1024
-
-#define wl12xx_error(fmt, arg...) \
- printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
-
-#define wl12xx_warning(fmt, arg...) \
- printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
-
-#define wl12xx_notice(fmt, arg...) \
- printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_info(fmt, arg...) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_debug(level, fmt, arg...) \
- do { \
- if (level & DEBUG_LEVEL) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
- } while (0)
-
-#define wl12xx_dump(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- 0); \
- } while (0)
-
-#define wl12xx_dump_ascii(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- true); \
- } while (0)
-
-#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN)
-
-#define WL12XX_DEFAULT_RX_FILTER (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)
-
-
-struct boot_attr {
- u32 radio_type;
- u8 mac_clock;
- u8 arm_clock;
- int firmware_debug;
- u32 minor;
- u32 major;
- u32 bugfix;
-};
-
-enum wl12xx_state {
- WL12XX_STATE_OFF,
- WL12XX_STATE_ON,
- WL12XX_STATE_PLT,
-};
-
-enum wl12xx_partition_type {
- PART_DOWN,
- PART_WORK,
- PART_DRPW,
-
- PART_TABLE_LEN
-};
-
-struct wl12xx_partition {
- u32 size;
- u32 start;
-};
-
-struct wl12xx_partition_set {
- struct wl12xx_partition mem;
- struct wl12xx_partition reg;
-};
-
-struct wl12xx;
-
-/* FIXME: I'm not sure about this structure name */
-struct wl12xx_chip {
- u32 id;
-
- const char *fw_filename;
- const char *nvs_filename;
-
- char fw_ver[21];
-
- unsigned int power_on_sleep;
- int intr_cmd_complete;
- int intr_init_complete;
-
- int (*op_upload_fw)(struct wl12xx *wl);
- int (*op_upload_nvs)(struct wl12xx *wl);
- int (*op_boot)(struct wl12xx *wl);
- void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag);
- void (*op_target_enable_interrupts)(struct wl12xx *wl);
- int (*op_hw_init)(struct wl12xx *wl);
- int (*op_plt_init)(struct wl12xx *wl);
-
- struct wl12xx_partition_set *p_table;
- enum wl12xx_acx_int_reg *acx_reg_table;
-};
-
-struct wl12xx_stats {
- struct acx_statistics *fw_stats;
- unsigned long fw_stats_update;
-
- unsigned int retry_count;
- unsigned int excessive_retries;
-};
-
-struct wl12xx_debugfs {
- struct dentry *rootdir;
- struct dentry *fw_statistics;
-
- struct dentry *tx_internal_desc_overflow;
-
- struct dentry *rx_out_of_mem;
- struct dentry *rx_hdr_overflow;
- struct dentry *rx_hw_stuck;
- struct dentry *rx_dropped;
- struct dentry *rx_fcs_err;
- struct dentry *rx_xfr_hint_trig;
- struct dentry *rx_path_reset;
- struct dentry *rx_reset_counter;
-
- struct dentry *dma_rx_requested;
- struct dentry *dma_rx_errors;
- struct dentry *dma_tx_requested;
- struct dentry *dma_tx_errors;
-
- struct dentry *isr_cmd_cmplt;
- struct dentry *isr_fiqs;
- struct dentry *isr_rx_headers;
- struct dentry *isr_rx_mem_overflow;
- struct dentry *isr_rx_rdys;
- struct dentry *isr_irqs;
- struct dentry *isr_tx_procs;
- struct dentry *isr_decrypt_done;
- struct dentry *isr_dma0_done;
- struct dentry *isr_dma1_done;
- struct dentry *isr_tx_exch_complete;
- struct dentry *isr_commands;
- struct dentry *isr_rx_procs;
- struct dentry *isr_hw_pm_mode_changes;
- struct dentry *isr_host_acknowledges;
- struct dentry *isr_pci_pm;
- struct dentry *isr_wakeups;
- struct dentry *isr_low_rssi;
-
- struct dentry *wep_addr_key_count;
- struct dentry *wep_default_key_count;
- /* skipping wep.reserved */
- struct dentry *wep_key_not_found;
- struct dentry *wep_decrypt_fail;
- struct dentry *wep_packets;
- struct dentry *wep_interrupt;
-
- struct dentry *pwr_ps_enter;
- struct dentry *pwr_elp_enter;
- struct dentry *pwr_missing_bcns;
- struct dentry *pwr_wake_on_host;
- struct dentry *pwr_wake_on_timer_exp;
- struct dentry *pwr_tx_with_ps;
- struct dentry *pwr_tx_without_ps;
- struct dentry *pwr_rcvd_beacons;
- struct dentry *pwr_power_save_off;
- struct dentry *pwr_enable_ps;
- struct dentry *pwr_disable_ps;
- struct dentry *pwr_fix_tsf_ps;
- /* skipping cont_miss_bcns_spread for now */
- struct dentry *pwr_rcvd_awake_beacons;
-
- struct dentry *mic_rx_pkts;
- struct dentry *mic_calc_failure;
-
- struct dentry *aes_encrypt_fail;
- struct dentry *aes_decrypt_fail;
- struct dentry *aes_encrypt_packets;
- struct dentry *aes_decrypt_packets;
- struct dentry *aes_encrypt_interrupt;
- struct dentry *aes_decrypt_interrupt;
-
- struct dentry *event_heart_beat;
- struct dentry *event_calibration;
- struct dentry *event_rx_mismatch;
- struct dentry *event_rx_mem_empty;
- struct dentry *event_rx_pool;
- struct dentry *event_oom_late;
- struct dentry *event_phy_transmit_error;
- struct dentry *event_tx_stuck;
-
- struct dentry *ps_pspoll_timeouts;
- struct dentry *ps_upsd_timeouts;
- struct dentry *ps_upsd_max_sptime;
- struct dentry *ps_upsd_max_apturn;
- struct dentry *ps_pspoll_max_apturn;
- struct dentry *ps_pspoll_utilization;
- struct dentry *ps_upsd_utilization;
-
- struct dentry *rxpipe_rx_prep_beacon_drop;
- struct dentry *rxpipe_descr_host_int_trig_rx_data;
- struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
- struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
- struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
-
- struct dentry *tx_queue_len;
-
- struct dentry *retry_count;
- struct dentry *excessive_retries;
-};
-
-struct wl12xx {
- struct ieee80211_hw *hw;
- bool mac80211_registered;
-
- struct spi_device *spi;
-
- void (*set_power)(bool enable);
- int irq;
-
- enum wl12xx_state state;
- struct mutex mutex;
-
- int physical_mem_addr;
- int physical_reg_addr;
- int virtual_mem_addr;
- int virtual_reg_addr;
-
- struct wl12xx_chip chip;
-
- int cmd_box_addr;
- int event_box_addr;
- struct boot_attr boot_attr;
-
- u8 *fw;
- size_t fw_len;
- u8 *nvs;
- size_t nvs_len;
-
- u8 bssid[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
- u8 bss_type;
- u8 listen_int;
- int channel;
-
- void *target_mem_map;
- struct acx_data_path_params_resp *data_path;
-
- /* Number of TX packets transferred to the FW, modulo 16 */
- u32 data_in_count;
-
- /* Frames scheduled for transmission, not handled yet */
- struct sk_buff_head tx_queue;
- bool tx_queue_stopped;
-
- struct work_struct tx_work;
- struct work_struct filter_work;
-
- /* Pending TX frames */
- struct sk_buff *tx_frames[16];
-
- /*
- * Index pointing to the next TX complete entry
- * in the cyclic XT complete array we get from
- * the FW.
- */
- u32 next_tx_complete;
-
- /* FW Rx counter */
- u32 rx_counter;
-
- /* Rx frames handled */
- u32 rx_handled;
-
- /* Current double buffer */
- u32 rx_current_buffer;
- u32 rx_last_id;
-
- /* The target interrupt mask */
- u32 intr_mask;
- struct work_struct irq_work;
-
- /* The mbox event mask */
- u32 event_mask;
-
- /* Mailbox pointers */
- u32 mbox_ptr[2];
-
- /* Are we currently scanning */
- bool scanning;
-
- /* Our association ID */
- u16 aid;
-
- /* Default key (for WEP) */
- u32 default_key;
-
- unsigned int tx_mgmt_frm_rate;
- unsigned int tx_mgmt_frm_mod;
-
- unsigned int rx_config;
- unsigned int rx_filter;
-
- /* is firmware in elp mode */
- bool elp;
-
- /* we can be in psm, but not in elp, we have to differentiate */
- bool psm;
-
- /* PSM mode requested */
- bool psm_requested;
-
- /* in dBm */
- int power_level;
-
- struct wl12xx_stats stats;
- struct wl12xx_debugfs debugfs;
-};
-
-int wl12xx_plt_start(struct wl12xx *wl);
-int wl12xx_plt_stop(struct wl12xx *wl);
-
-#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
-#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define WL12XX_DEFAULT_POWER_LEVEL 20
-
-#define WL12XX_TX_QUEUE_MAX_LENGTH 20
-
-/* Different chips need different sleep times after power on. WL1271 needs
- * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
- * know the chip ID, we change the sleep value in the wl12xx chip structure,
- * so in subsequent power ons, we don't waste more time then needed. */
-#define WL12XX_DEFAULT_POWER_ON_SLEEP 200
-
-#define CHIP_ID_1251_PG10 (0x7010101)
-#define CHIP_ID_1251_PG11 (0x7020101)
-#define CHIP_ID_1251_PG12 (0x7030101)
-#define CHIP_ID_1271_PG10 (0x4030101)
-
-#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3e96bb2c246..a83a5621ec44 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (rc) {
++dev->stats.tx_dropped;
netif_stop_queue(dev);
- rc = NETDEV_TX_OK;
} else {
++dev->stats.tx_packets;
dev->stats.tx_bytes += skb->len;
@@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&this->lock, flags);
- return rc;
+ return NETDEV_TX_OK;
}
static int wl3501_open(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4430b8d92e21..dae1bfb7655e 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!zd->mac_enabled || zd->monitor) {
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void zd1201_tx_timeout(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 2c813d87092c..1135dd9ee9ee 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -368,7 +368,7 @@ error:
return r;
}
-/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
+/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and
* CR_MAC_ADDR_P2 must be overwritten
*/
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 40b07b988224..9600b72495da 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
memcpy(skb_put(skb, length), buffer, length);
- ieee80211_rx_irqsafe(hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(hw, skb);
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 0e6e44689cc6..38688847d568 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -36,58 +36,60 @@
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
+ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
+ { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8d88daeed0c6..3700c49d76ca 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&np->tx_lock);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int xennet_close(struct net_device *dev)
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index 5a4ad156f63e..0c44135c0b1f 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -239,7 +239,7 @@ out:
* Actually probing is superfluous but we're paranoid.
*/
-int __init xtsonic_probe(struct platform_device *pdev)
+int __devinit xtsonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index a07580138e81..76764237cde6 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -830,7 +830,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, len)) {
yp->tx_skbuff[entry] = NULL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
}
}
@@ -884,7 +884,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
dev->name, yp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 0a6992d8611b..7f9e14131a5c 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The ZNET interrupt handler. */
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index aee967d7f760..bacaa536fd51 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -9,6 +9,10 @@
* out of the OpenFirmware device tree and using it to populate an mii_bus.
*/
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/err.h>
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
@@ -137,3 +141,41 @@ struct phy_device *of_phy_connect(struct net_device *dev,
return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect);
+
+/**
+ * of_phy_connect_fixed_link - Parse fixed-link property and return a dummy phy
+ * @dev: pointer to net_device claiming the phy
+ * @hndlr: Link state callback for the network device
+ * @iface: PHY data interface type
+ *
+ * This function is a temporary stop-gap and will be removed soon. It is
+ * only to support the fs_enet, ucc_geth and gianfar Ethernet drivers. Do
+ * not call this function from new drivers.
+ */
+struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
+ void (*hndlr)(struct net_device *),
+ phy_interface_t iface)
+{
+ struct device_node *net_np;
+ char bus_id[MII_BUS_ID_SIZE + 3];
+ struct phy_device *phy;
+ const u32 *phy_id;
+ int sz;
+
+ if (!dev->dev.parent)
+ return NULL;
+
+ net_np = dev_archdata_get_node(&dev->dev.parent->archdata);
+ if (!net_np)
+ return NULL;
+
+ phy_id = of_get_property(net_np, "fixed-link", &sz);
+ if (!phy_id || sz < sizeof(*phy_id))
+ return NULL;
+
+ sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]);
+
+ phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+ return IS_ERR(phy) ? NULL : phy;
+}
+EXPORT_SYMBOL(of_phy_connect_fixed_link);
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 8574622e36a5..c9e2ae90f195 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -154,9 +154,8 @@ int sync_start(void)
{
int err;
- if (!alloc_cpumask_var(&marked_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL))
return -ENOMEM;
- cpumask_clear(marked_cpus);
start_cpu_work();
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 242257b19441..a7aae24f2889 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -21,7 +21,6 @@
#include <linux/sched.h>
#include <linux/oprofile.h>
-#include <linux/vmalloc.h>
#include <linux/errno.h>
#include "event_buffer.h"
@@ -407,6 +406,21 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val)
return op_cpu_buffer_add_data(entry, val);
}
+int oprofile_add_data64(struct op_entry *entry, u64 val)
+{
+ if (!entry->event)
+ return 0;
+ if (op_cpu_buffer_get_size(entry) < 2)
+ /*
+ * the function returns 0 to indicate a too small
+ * buffer, even if there is some space left
+ */
+ return 0;
+ if (!op_cpu_buffer_add_data(entry, (u32)val))
+ return 0;
+ return op_cpu_buffer_add_data(entry, (u32)(val >> 32));
+}
+
int oprofile_write_commit(struct op_entry *entry)
{
if (!entry->event)
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index 3cffce90f82a..dc8a0428260d 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -12,6 +12,8 @@
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+#include <linux/time.h>
#include <asm/mutex.h>
#include "oprof.h"
@@ -87,6 +89,69 @@ out:
return err;
}
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+
+static void switch_worker(struct work_struct *work);
+static DECLARE_DELAYED_WORK(switch_work, switch_worker);
+
+static void start_switch_worker(void)
+{
+ if (oprofile_ops.switch_events)
+ schedule_delayed_work(&switch_work, oprofile_time_slice);
+}
+
+static void stop_switch_worker(void)
+{
+ cancel_delayed_work_sync(&switch_work);
+}
+
+static void switch_worker(struct work_struct *work)
+{
+ if (oprofile_ops.switch_events())
+ return;
+
+ atomic_inc(&oprofile_stats.multiplex_counter);
+ start_switch_worker();
+}
+
+/* User inputs in ms, converts to jiffies */
+int oprofile_set_timeout(unsigned long val_msec)
+{
+ int err = 0;
+ unsigned long time_slice;
+
+ mutex_lock(&start_mutex);
+
+ if (oprofile_started) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (!oprofile_ops.switch_events) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ time_slice = msecs_to_jiffies(val_msec);
+ if (time_slice == MAX_JIFFY_OFFSET) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ oprofile_time_slice = time_slice;
+
+out:
+ mutex_unlock(&start_mutex);
+ return err;
+
+}
+
+#else
+
+static inline void start_switch_worker(void) { }
+static inline void stop_switch_worker(void) { }
+
+#endif
/* Actually start profiling (echo 1>/dev/oprofile/enable) */
int oprofile_start(void)
@@ -108,6 +173,8 @@ int oprofile_start(void)
if ((err = oprofile_ops.start()))
goto out;
+ start_switch_worker();
+
oprofile_started = 1;
out:
mutex_unlock(&start_mutex);
@@ -123,6 +190,9 @@ void oprofile_stop(void)
goto out;
oprofile_ops.stop();
oprofile_started = 0;
+
+ stop_switch_worker();
+
/* wake up the daemon to read what remains */
wake_up_buffer_waiter();
out:
@@ -155,7 +225,6 @@ post_sync:
mutex_unlock(&start_mutex);
}
-
int oprofile_set_backtrace(unsigned long val)
{
int err = 0;
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index c288d3c24b50..cb92f5c98c1a 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -24,6 +24,8 @@ struct oprofile_operations;
extern unsigned long oprofile_buffer_size;
extern unsigned long oprofile_cpu_buffer_size;
extern unsigned long oprofile_buffer_watershed;
+extern unsigned long oprofile_time_slice;
+
extern struct oprofile_operations oprofile_ops;
extern unsigned long oprofile_started;
extern unsigned long oprofile_backtrace_depth;
@@ -35,5 +37,6 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root);
void oprofile_timer_init(struct oprofile_operations *ops);
int oprofile_set_backtrace(unsigned long depth);
+int oprofile_set_timeout(unsigned long time);
#endif /* OPROF_H */
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index 5d36ffc30dd5..bbd7516e0869 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -9,6 +9,7 @@
#include <linux/fs.h>
#include <linux/oprofile.h>
+#include <linux/jiffies.h>
#include "event_buffer.h"
#include "oprofile_stats.h"
@@ -17,10 +18,51 @@
#define BUFFER_SIZE_DEFAULT 131072
#define CPU_BUFFER_SIZE_DEFAULT 8192
#define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */
+#define TIME_SLICE_DEFAULT 1
unsigned long oprofile_buffer_size;
unsigned long oprofile_cpu_buffer_size;
unsigned long oprofile_buffer_watershed;
+unsigned long oprofile_time_slice;
+
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+
+static ssize_t timeout_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice),
+ buf, count, offset);
+}
+
+
+static ssize_t timeout_write(struct file *file, char const __user *buf,
+ size_t count, loff_t *offset)
+{
+ unsigned long val;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = oprofilefs_ulong_from_user(&val, buf, count);
+ if (retval)
+ return retval;
+
+ retval = oprofile_set_timeout(val);
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+
+static const struct file_operations timeout_fops = {
+ .read = timeout_read,
+ .write = timeout_write,
+};
+
+#endif
+
static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
@@ -129,6 +171,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root)
oprofile_buffer_size = BUFFER_SIZE_DEFAULT;
oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT;
oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT;
+ oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT);
oprofilefs_create_file(sb, root, "enable", &enable_fops);
oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
@@ -139,6 +182,9 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root)
oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+ oprofilefs_create_file(sb, root, "time_slice", &timeout_fops);
+#endif
oprofile_create_stats_files(sb, root);
if (oprofile_ops.create_files)
oprofile_ops.create_files(sb, root);
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index 3c2270a8300c..61689e814d46 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -34,6 +34,7 @@ void oprofile_reset_stats(void)
atomic_set(&oprofile_stats.sample_lost_no_mapping, 0);
atomic_set(&oprofile_stats.event_lost_overflow, 0);
atomic_set(&oprofile_stats.bt_lost_no_mapping, 0);
+ atomic_set(&oprofile_stats.multiplex_counter, 0);
}
@@ -76,4 +77,8 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root)
&oprofile_stats.event_lost_overflow);
oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping",
&oprofile_stats.bt_lost_no_mapping);
+#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
+ oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter",
+ &oprofile_stats.multiplex_counter);
+#endif
}
diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h
index 3da0d08dc1f9..0b54e46c3c14 100644
--- a/drivers/oprofile/oprofile_stats.h
+++ b/drivers/oprofile/oprofile_stats.h
@@ -17,6 +17,7 @@ struct oprofile_stat_struct {
atomic_t sample_lost_no_mapping;
atomic_t bt_lost_no_mapping;
atomic_t event_lost_overflow;
+ atomic_t multiplex_counter;
};
extern struct oprofile_stat_struct oprofile_stats;
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 1ebd6b4c743b..4a7f11d8f432 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -8,6 +8,9 @@ obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
+obj-$(CONFIG_PCI_LEGACY) += legacy.o
+CFLAGS_legacy.o += -Wno-deprecated-declarations
+
# Build PCI Express stuff if needed
obj-$(CONFIG_PCIEPORTBUS) += pcie/
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 0cb0f830a993..2e5f25969e11 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -62,6 +62,22 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static struct pci_bus *pci_bus_from_handle(acpi_handle handle)
+{
+ struct pci_bus *pbus;
+ struct acpi_pci_root *root;
+
+ root = acpi_pci_find_root(handle);
+ if (root)
+ pbus = root->bus;
+ else {
+ struct pci_dev *pdev = acpi_get_pci_dev(handle);
+ pbus = pdev->subordinate;
+ pci_dev_put(pdev);
+ }
+ return pbus;
+}
+
/* callback routine to check for the existence of a pci dock device */
static acpi_status
is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -1387,16 +1403,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
/* Program resources in newly inserted bridge */
static int acpiphp_configure_bridge (acpi_handle handle)
{
- struct pci_dev *dev;
- struct pci_bus *bus;
-
- dev = acpi_get_pci_dev(handle);
- if (!dev) {
- err("cannot get PCI domain and bus number for bridge\n");
- return -EINVAL;
- }
-
- bus = dev->bus;
+ struct pci_bus *bus = pci_bus_from_handle(handle);
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
@@ -1404,7 +1411,6 @@ static int acpiphp_configure_bridge (acpi_handle handle)
acpiphp_set_hpp_values(handle, bus);
pci_enable_bridges(bus);
acpiphp_configure_ioapics(handle);
- pci_dev_put(dev);
return 0;
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 5befa7e379b7..a9d926b7d805 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -398,23 +398,21 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
acpi_handle *phandle = (acpi_handle *)context;
acpi_status status;
struct acpi_device_info *info;
- struct acpi_buffer info_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
int retval = 0;
- status = acpi_get_object_info(handle, &info_buffer);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
err("%s: Failed to get device information status=0x%x\n",
__func__, status);
return retval;
}
- info = info_buffer.pointer;
- info->hardware_id.value[sizeof(info->hardware_id.value) - 1] = '\0';
+ info->hardware_id.string[sizeof(info->hardware_id.length) - 1] = '\0';
if (info->current_status && (info->valid & ACPI_VALID_HID) &&
- (!strcmp(info->hardware_id.value, IBM_HARDWARE_ID1) ||
- !strcmp(info->hardware_id.value, IBM_HARDWARE_ID2))) {
+ (!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) ||
+ !strcmp(info->hardware_id.string, IBM_HARDWARE_ID2))) {
dbg("found hardware: %s, handle: %p\n",
- info->hardware_id.value, handle);
+ info->hardware_id.string, handle);
*phandle = handle;
/* returning non-zero causes the search to stop
* and returns this value to the caller of
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index a4494d78e7c2..8aebe1e9d3d6 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -90,11 +90,10 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = {
static DEFINE_MUTEX(sn_hotplug_mutex);
-static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
- char *buf)
+static ssize_t path_show(struct pci_slot *pci_slot, char *buf)
{
int retval = -ENOENT;
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = pci_slot->hotplug->private;
if (!slot)
return retval;
@@ -103,7 +102,7 @@ static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
return retval;
}
-static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
+static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
{
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index ebc9b8dca881..bec29ed13e30 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1309,7 +1309,6 @@ static void iommu_detach_domain(struct dmar_domain *domain,
}
static struct iova_domain reserved_iova_list;
-static struct lock_class_key reserved_alloc_key;
static struct lock_class_key reserved_rbtree_key;
static void dmar_init_reserved_ranges(void)
@@ -1320,8 +1319,6 @@ static void dmar_init_reserved_ranges(void)
init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
- lockdep_set_class(&reserved_iova_list.iova_alloc_lock,
- &reserved_alloc_key);
lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
&reserved_rbtree_key);
@@ -2227,7 +2224,6 @@ int __init init_dmars(void)
deferred_flush = kzalloc(g_num_of_iommus *
sizeof(struct deferred_flush_tables), GFP_KERNEL);
if (!deferred_flush) {
- kfree(g_iommus);
ret = -ENOMEM;
goto error;
}
@@ -2455,8 +2451,7 @@ static struct iova *intel_alloc_iova(struct device *dev,
return iova;
}
-static struct dmar_domain *
-get_valid_domain_for_dev(struct pci_dev *pdev)
+static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
{
struct dmar_domain *domain;
int ret;
@@ -2484,6 +2479,18 @@ get_valid_domain_for_dev(struct pci_dev *pdev)
return domain;
}
+static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
+{
+ struct device_domain_info *info;
+
+ /* No lock here, assumes no domain exit in normal case */
+ info = dev->dev.archdata.iommu;
+ if (likely(info))
+ return info->domain;
+
+ return __get_valid_domain_for_dev(dev);
+}
+
static int iommu_dummy(struct pci_dev *pdev)
{
return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
@@ -2733,12 +2740,6 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
}
}
-static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
- int dir)
-{
- intel_unmap_page(dev, dev_addr, size, dir, NULL);
-}
-
static void *intel_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
{
@@ -2771,7 +2772,7 @@ static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
size = PAGE_ALIGN(size);
order = get_order(size);
- intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
+ intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
free_pages((unsigned long)vaddr, order);
}
@@ -2807,11 +2808,18 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
/* free page tables */
dma_pte_free_pagetable(domain, start_pfn, last_pfn);
- iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
- (last_pfn - start_pfn + 1));
-
- /* free iova */
- __free_iova(&domain->iovad, iova);
+ if (intel_iommu_strict) {
+ iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+ last_pfn - start_pfn + 1);
+ /* free iova */
+ __free_iova(&domain->iovad, iova);
+ } else {
+ add_unmap(domain, iova);
+ /*
+ * queue up the release of the unmap to save the 1/6th of the
+ * cpu used up by the iotlb flush operation...
+ */
+ }
}
static int intel_nontranslate_map_sg(struct device *hddev,
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index 46dd440e2315..7914951ef29a 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -22,7 +22,6 @@
void
init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
{
- spin_lock_init(&iovad->iova_alloc_lock);
spin_lock_init(&iovad->iova_rbtree_lock);
iovad->rbroot = RB_ROOT;
iovad->cached32_node = NULL;
@@ -205,7 +204,6 @@ alloc_iova(struct iova_domain *iovad, unsigned long size,
unsigned long limit_pfn,
bool size_aligned)
{
- unsigned long flags;
struct iova *new_iova;
int ret;
@@ -219,11 +217,9 @@ alloc_iova(struct iova_domain *iovad, unsigned long size,
if (size_aligned)
size = __roundup_pow_of_two(size);
- spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
ret = __alloc_and_insert_iova_range(iovad, size, limit_pfn,
new_iova, size_aligned);
- spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
if (ret) {
free_iova_mem(new_iova);
return NULL;
@@ -381,8 +377,7 @@ reserve_iova(struct iova_domain *iovad,
struct iova *iova;
unsigned int overlap = 0;
- spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
- spin_lock(&iovad->iova_rbtree_lock);
+ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) {
if (__is_range_overlap(node, pfn_lo, pfn_hi)) {
iova = container_of(node, struct iova, node);
@@ -402,8 +397,7 @@ reserve_iova(struct iova_domain *iovad,
iova = __insert_new_range(iovad, pfn_lo, pfn_hi);
finish:
- spin_unlock(&iovad->iova_rbtree_lock);
- spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
return iova;
}
@@ -420,8 +414,7 @@ copy_reserved_iova(struct iova_domain *from, struct iova_domain *to)
unsigned long flags;
struct rb_node *node;
- spin_lock_irqsave(&from->iova_alloc_lock, flags);
- spin_lock(&from->iova_rbtree_lock);
+ spin_lock_irqsave(&from->iova_rbtree_lock, flags);
for (node = rb_first(&from->rbroot); node; node = rb_next(node)) {
struct iova *iova = container_of(node, struct iova, node);
struct iova *new_iova;
@@ -430,6 +423,5 @@ copy_reserved_iova(struct iova_domain *from, struct iova_domain *to)
printk(KERN_ERR "Reserve iova range %lx@%lx failed\n",
iova->pfn_lo, iova->pfn_lo);
}
- spin_unlock(&from->iova_rbtree_lock);
- spin_unlock_irqrestore(&from->iova_alloc_lock, flags);
+ spin_unlock_irqrestore(&from->iova_rbtree_lock, flags);
}
diff --git a/drivers/pci/legacy.c b/drivers/pci/legacy.c
new file mode 100644
index 000000000000..871f65c15936
--- /dev/null
+++ b/drivers/pci/legacy.c
@@ -0,0 +1,34 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include "pci.h"
+
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is found
+ * with a matching @vendor and @device, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
+ *
+ * NOTE: Do not use this function any more; use pci_get_device() instead, as
+ * the PCI device returned by this function can disappear at any moment in
+ * time.
+ */
+struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
+ struct pci_dev *from)
+{
+ struct pci_dev *pdev;
+
+ pci_dev_get(from);
+ pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+ pci_dev_put(pdev);
+ return pdev;
+}
+EXPORT_SYMBOL(pci_find_device);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d76c4c85367e..0c2ea44ae5e1 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -575,7 +575,7 @@ static void pci_pm_complete(struct device *dev)
static int pci_pm_suspend(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_SUSPEND);
@@ -613,7 +613,7 @@ static int pci_pm_suspend(struct device *dev)
static int pci_pm_suspend_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
@@ -672,7 +672,7 @@ static int pci_pm_resume_noirq(struct device *dev)
static int pci_pm_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
/*
@@ -711,7 +711,7 @@ static int pci_pm_resume(struct device *dev)
static int pci_pm_freeze(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_FREEZE);
@@ -780,7 +780,7 @@ static int pci_pm_thaw_noirq(struct device *dev)
static int pci_pm_thaw(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
if (pci_has_legacy_pm_support(pci_dev))
@@ -799,7 +799,7 @@ static int pci_pm_thaw(struct device *dev)
static int pci_pm_poweroff(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_HIBERNATE);
@@ -872,7 +872,7 @@ static int pci_pm_restore_noirq(struct device *dev)
static int pci_pm_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
/*
@@ -910,7 +910,7 @@ static int pci_pm_restore(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
-struct dev_pm_ops pci_dev_pm_ops = {
+const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.complete = pci_pm_complete,
.suspend = pci_pm_suspend,
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 85ebd02a64a7..0f6382f090ee 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -916,6 +916,24 @@ int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
return 0;
}
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned long val;
+ ssize_t result = strict_strtoul(buf, 0, &val);
+
+ if (result < 0)
+ return result;
+
+ if (val != 1)
+ return -EINVAL;
+ return pci_reset_function(pdev);
+}
+
+static struct device_attribute reset_attr = __ATTR(reset, 0200, NULL, reset_store);
+
static int pci_create_capabilities_sysfs(struct pci_dev *dev)
{
int retval;
@@ -943,7 +961,22 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
/* Active State Power Management */
pcie_aspm_create_sysfs_dev_files(dev);
+ if (!pci_probe_reset_function(dev)) {
+ retval = device_create_file(&dev->dev, &reset_attr);
+ if (retval)
+ goto error;
+ dev->reset_fn = 1;
+ }
return 0;
+
+error:
+ pcie_aspm_remove_sysfs_dev_files(dev);
+ if (dev->vpd && dev->vpd->attr) {
+ sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr);
+ kfree(dev->vpd->attr);
+ }
+
+ return retval;
}
int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
@@ -1037,6 +1070,10 @@ static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
}
pcie_aspm_remove_sysfs_dev_files(dev);
+ if (dev->reset_fn) {
+ device_remove_file(&dev->dev, &reset_attr);
+ dev->reset_fn = 0;
+ }
}
/**
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index dbd0f947f497..f6d1c6c10d53 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2260,6 +2260,22 @@ int __pci_reset_function(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(__pci_reset_function);
/**
+ * pci_probe_reset_function - check whether the device can be safely reset
+ * @dev: PCI device to reset
+ *
+ * Some devices allow an individual function to be reset without affecting
+ * other functions in the same device. The PCI device must be responsive
+ * to PCI config space in order to use this function.
+ *
+ * Returns 0 if the device function can be reset or negative if the
+ * device doesn't support resetting a single function.
+ */
+int pci_probe_reset_function(struct pci_dev *dev)
+{
+ return pci_dev_reset(dev, 1);
+}
+
+/**
* pci_reset_function - quiesce and reset a PCI device function
* @dev: PCI device to reset
*
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f73bcbedf37c..60a381153e37 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -16,6 +16,7 @@ extern void pci_cleanup_rom(struct pci_dev *dev);
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
struct vm_area_struct *vma);
#endif
+int pci_probe_reset_function(struct pci_dev *dev);
/**
* struct pci_platform_pm_ops - Firmware PM callbacks
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 40e75f6a5056..b9d4e95aafba 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1061,8 +1061,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
if (dev && !dev->is_added) /* new device? */
nr++;
- if ((dev && dev->multifunction) ||
- (!dev && pcibios_scan_all_fns(bus, devfn))) {
+ if (dev && dev->multifunction) {
for (fn = 1; fn < 8; fn++) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 06b965623962..28d592de09ff 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1201,6 +1201,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
switch(dev->subsystem_device) {
case 0x00b8: /* Compaq Evo D510 CMT */
case 0x00b9: /* Compaq Evo D510 SFF */
+ case 0x00ba: /* Compaq Evo D510 USDT */
/* Motherboard doesn't have Host bridge
* subvendor/subdevice IDs and on-board VGA
* controller is disabled if an AGP card is
@@ -2382,8 +2383,10 @@ static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all);
static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
{
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index e8cb5051c311..ec415352d9ba 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -113,37 +113,6 @@ pci_find_next_bus(const struct pci_bus *from)
return b;
}
-#ifdef CONFIG_PCI_LEGACY
-/**
- * pci_find_device - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices. If a PCI device is found
- * with a matching @vendor and @device, a pointer to its device structure is
- * returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device
- * on the global list.
- *
- * NOTE: Do not use this function any more; use pci_get_device() instead, as
- * the PCI device returned by this function can disappear at any moment in
- * time.
- */
-struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
- struct pci_dev *from)
-{
- struct pci_dev *pdev;
-
- pci_dev_get(from);
- pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
- pci_dev_put(pdev);
- return pdev;
-}
-EXPORT_SYMBOL(pci_find_device);
-#endif /* CONFIG_PCI_LEGACY */
-
/**
* pci_get_slot - locate PCI device for a given PCI slot
* @bus: PCI bus on which desired PCI device resides
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index b711fb7181e2..55d20b989d5e 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -100,16 +100,16 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root;
- char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
int err;
root = pci_find_parent_resource(dev, res);
err = -EINVAL;
if (root != NULL)
- err = insert_resource(root, res);
+ err = request_resource(root, res);
if (err) {
+ const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
resource,
root ? "address space collision on" :
@@ -119,6 +119,7 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
return err;
}
+EXPORT_SYMBOL(pci_claim_resource);
#ifdef CONFIG_PCI_QUIRKS
void pci_disable_bridge_window(struct pci_dev *dev)
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index c49a7269f6d1..87e22ef8eb02 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -300,25 +300,29 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
return soc_common_drv_pcmcia_remove(&dev->dev);
}
-static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t state)
+static int pxa2xx_drv_pcmcia_suspend(struct device *dev)
{
- return pcmcia_socket_dev_suspend(&dev->dev, state);
+ return pcmcia_socket_dev_suspend(dev, PMSG_SUSPEND);
}
-static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev)
+static int pxa2xx_drv_pcmcia_resume(struct device *dev)
{
- pxa2xx_configure_sockets(&dev->dev);
- return pcmcia_socket_dev_resume(&dev->dev);
+ pxa2xx_configure_sockets(dev);
+ return pcmcia_socket_dev_resume(dev);
}
+static struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = {
+ .suspend = pxa2xx_drv_pcmcia_suspend,
+ .resume = pxa2xx_drv_pcmcia_resume,
+};
+
static struct platform_driver pxa2xx_pcmcia_driver = {
.probe = pxa2xx_drv_pcmcia_probe,
.remove = pxa2xx_drv_pcmcia_remove,
- .suspend = pxa2xx_drv_pcmcia_suspend,
- .resume = pxa2xx_drv_pcmcia_resume,
.driver = {
.name = "pxa2xx-pcmcia",
.owner = THIS_MODULE,
+ .pm = &pxa2xx_drv_pcmcia_pm_ops,
},
};
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 3ecd7c99d8eb..737fe5d87c40 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -622,11 +622,12 @@ static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end)
{
- struct resource *root, *res;
+ struct pci_dev *dev = socket->dev;
+ struct resource *res;
struct pci_bus_region region;
unsigned mask;
- res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
+ res = dev->resource + PCI_BRIDGE_RESOURCES + nr;
/* Already allocated? */
if (res->parent)
return 0;
@@ -636,17 +637,16 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
if (type & IORESOURCE_IO)
mask = ~3;
- res->name = socket->dev->subordinate->name;
+ res->name = dev->subordinate->name;
res->flags = type;
region.start = config_readl(socket, addr_start) & mask;
region.end = config_readl(socket, addr_end) | ~mask;
if (region.start && region.end > region.start && !override_bios) {
- pcibios_bus_to_resource(socket->dev, res, &region);
- root = pci_find_parent_resource(socket->dev, res);
- if (root && (request_resource(root, res) == 0))
+ pcibios_bus_to_resource(dev, res, &region);
+ if (pci_claim_resource(dev, PCI_BRIDGE_RESOURCES + nr) == 0)
return 0;
- dev_printk(KERN_INFO, &socket->dev->dev,
+ dev_printk(KERN_INFO, &dev->dev,
"Preassigned resource %d busy or not available, "
"reconfiguring...\n",
nr);
@@ -672,7 +672,7 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
return 1;
}
- dev_printk(KERN_INFO, &socket->dev->dev,
+ dev_printk(KERN_INFO, &dev->dev,
"no resource of type %x available, trying to continue...\n",
type);
res->start = res->end = res->flags = 0;
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 46dad12f952f..77c6097ced80 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -277,31 +277,6 @@ config THINKPAD_ACPI_UNSAFE_LEDS
Say N here, unless you are building a kernel for your own
use, and need to control the important firmware LEDs.
-config THINKPAD_ACPI_DOCK
- bool "Legacy Docking Station Support"
- depends on THINKPAD_ACPI
- depends on ACPI_DOCK=n
- default n
- ---help---
- Allows the thinkpad_acpi driver to handle docking station events.
- This support was made obsolete by the generic ACPI docking station
- support (CONFIG_ACPI_DOCK). It will allow locking and removing the
- laptop from the docking station, but will not properly connect PCI
- devices.
-
- If you are not sure, say N here.
-
-config THINKPAD_ACPI_BAY
- bool "Legacy Removable Bay Support"
- depends on THINKPAD_ACPI
- default y
- ---help---
- Allows the thinkpad_acpi driver to handle removable bays. It will
- electrically disable the device in the bay, and also generate
- notifications when the bay lever is ejected or inserted.
-
- If you are not sure, say Y here.
-
config THINKPAD_ACPI_VIDEO
bool "Video output control support"
depends on THINKPAD_ACPI
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index be2fd6f91639..fb45f5ee8df1 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -973,7 +973,7 @@ static int acer_rfkill_set(void *data, bool blocked)
{
acpi_status status;
u32 cap = (unsigned long)data;
- status = set_u32(!!blocked, cap);
+ status = set_u32(!blocked, cap);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index ec560f16d720..222ffb892f22 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -143,6 +143,7 @@ struct eeepc_hotk {
struct rfkill *bluetooth_rfkill;
struct rfkill *wwan3g_rfkill;
struct hotplug_slot *hotplug_slot;
+ struct work_struct hotplug_work;
};
/* The actual device the driver binds to */
@@ -660,7 +661,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-static void eeepc_rfkill_hotplug(void)
+static void eeepc_hotplug_work(struct work_struct *work)
{
struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1);
@@ -701,7 +702,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
- eeepc_rfkill_hotplug();
+ schedule_work(&ehotk->hotplug_work);
}
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -892,7 +893,7 @@ static int eeepc_hotk_resume(struct acpi_device *device)
rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
- eeepc_rfkill_hotplug();
+ schedule_work(&ehotk->hotplug_work);
}
if (ehotk->bluetooth_rfkill)
@@ -1093,6 +1094,8 @@ static int eeepc_rfkill_init(struct device *dev)
{
int result = 0;
+ INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work);
+
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index ca508564a181..af04f5b049db 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -53,7 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
static int __init hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device);
-static int hp_wmi_resume_handler(struct platform_device *device);
+static int hp_wmi_resume_handler(struct device *device);
struct bios_args {
u32 signature;
@@ -94,14 +94,19 @@ static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;
+static struct dev_pm_ops hp_wmi_pm_ops = {
+ .resume = hp_wmi_resume_handler,
+ .restore = hp_wmi_resume_handler,
+};
+
static struct platform_driver hp_wmi_driver = {
.driver = {
- .name = "hp-wmi",
- .owner = THIS_MODULE,
+ .name = "hp-wmi",
+ .owner = THIS_MODULE,
+ .pm = &hp_wmi_pm_ops,
},
.probe = hp_wmi_bios_setup,
.remove = hp_wmi_bios_remove,
- .resume = hp_wmi_resume_handler,
};
static int hp_wmi_perform_query(int query, int write, int value)
@@ -512,7 +517,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
return 0;
}
-static int hp_wmi_resume_handler(struct platform_device *device)
+static int hp_wmi_resume_handler(struct device *device)
{
/*
* Hardware state may have changed while suspended, so trigger
@@ -520,11 +525,13 @@ static int hp_wmi_resume_handler(struct platform_device *device)
* the input layer will only actually pass it on if the state
* changed.
*/
-
- input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
- input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
- hp_wmi_tablet_state());
- input_sync(hp_wmi_input_dev);
+ if (hp_wmi_input_dev) {
+ input_report_switch(hp_wmi_input_dev, SW_DOCK,
+ hp_wmi_dock_state());
+ input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+ hp_wmi_tablet_state());
+ input_sync(hp_wmi_input_dev);
+ }
return 0;
}
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index dafaa4a92df5..f9f68e0e7344 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -976,15 +976,12 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
void *context, void **return_value)
{
struct acpi_device_info *info;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-
- if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) {
- info = buffer.pointer;
+ if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
(char *)&info->name, info->param_count);
- kfree(buffer.pointer);
+ kfree(info);
}
return AE_OK;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a463fd72c495..e85600852502 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -239,12 +239,6 @@ struct ibm_init_struct {
};
static struct {
-#ifdef CONFIG_THINKPAD_ACPI_BAY
- u32 bay_status:1;
- u32 bay_eject:1;
- u32 bay_status2:1;
- u32 bay_eject2:1;
-#endif
u32 bluetooth:1;
u32 hotkey:1;
u32 hotkey_mask:1;
@@ -589,18 +583,6 @@ static int acpi_ec_write(int i, u8 v)
return 1;
}
-#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
-static int _sta(acpi_handle handle)
-{
- int status;
-
- if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
- status = 0;
-
- return status;
-}
-#endif
-
static int issue_thinkpad_cmos_command(int cmos_cmd)
{
if (!cmos_handle)
@@ -784,6 +766,8 @@ static int dispatch_procfs_write(struct file *file,
if (!ibm || !ibm->write)
return -EINVAL;
+ if (count > PAGE_SIZE - 2)
+ return -EINVAL;
kernbuf = kmalloc(count + 2, GFP_KERNEL);
if (!kernbuf)
@@ -4442,293 +4426,6 @@ static struct ibm_struct light_driver_data = {
};
/*************************************************************************
- * Dock subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-
-static void dock_notify(struct ibm_struct *ibm, u32 event);
-static int dock_read(char *p);
-static int dock_write(char *buf);
-
-TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
- "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
- "\\_SB.PCI0.PCI1.DOCK", /* all others */
- "\\_SB.PCI.ISA.SLCE", /* 570 */
- ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
-
-static const struct acpi_device_id ibm_pci_device_ids[] = {
- {PCI_ROOT_HID_STRING, 0},
- {"", 0},
-};
-
-static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
- {
- .notify = dock_notify,
- .handle = &dock_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
- {
- /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
- * We just use it to get notifications of dock hotplug
- * in very old thinkpads */
- .hid = ibm_pci_device_ids,
- .notify = dock_notify,
- .handle = &pci_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-};
-
-static struct ibm_struct dock_driver_data[2] = {
- {
- .name = "dock",
- .read = dock_read,
- .write = dock_write,
- .acpi = &ibm_dock_acpidriver[0],
- },
- {
- .name = "dock",
- .acpi = &ibm_dock_acpidriver[1],
- },
-};
-
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int __init dock_init(struct ibm_init_struct *iibm)
-{
- vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
-
- TPACPI_ACPIHANDLE_INIT(dock);
-
- vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
- str_supported(dock_handle != NULL));
-
- return (dock_handle)? 0 : 1;
-}
-
-static int __init dock_init2(struct ibm_init_struct *iibm)
-{
- int dock2_needed;
-
- vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
-
- if (dock_driver_data[0].flags.acpi_driver_registered &&
- dock_driver_data[0].flags.acpi_notify_installed) {
- TPACPI_ACPIHANDLE_INIT(pci);
- dock2_needed = (pci_handle != NULL);
- vdbg_printk(TPACPI_DBG_INIT,
- "dock PCI handler for the TP 570 is %s\n",
- str_supported(dock2_needed));
- } else {
- vdbg_printk(TPACPI_DBG_INIT,
- "dock subdriver part 2 not required\n");
- dock2_needed = 0;
- }
-
- return (dock2_needed)? 0 : 1;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
- int docked = dock_docked();
- int pci = ibm->acpi->hid && ibm->acpi->device &&
- acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
- int data;
-
- if (event == 1 && !pci) /* 570 */
- data = 1; /* button */
- else if (event == 1 && pci) /* 570 */
- data = 3; /* dock */
- else if (event == 3 && docked)
- data = 1; /* button */
- else if (event == 3 && !docked)
- data = 2; /* undock */
- else if (event == 0 && docked)
- data = 3; /* dock */
- else {
- printk(TPACPI_ERR "unknown dock event %d, status %d\n",
- event, _sta(dock_handle));
- data = 0; /* unknown */
- }
- acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- dev_name(&ibm->acpi->device->dev),
- event, data);
-}
-
-static int dock_read(char *p)
-{
- int len = 0;
- int docked = dock_docked();
-
- if (!dock_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!docked)
- len += sprintf(p + len, "status:\t\tundocked\n");
- else {
- len += sprintf(p + len, "status:\t\tdocked\n");
- len += sprintf(p + len, "commands:\tdock, undock\n");
- }
-
- return len;
-}
-
-static int dock_write(char *buf)
-{
- char *cmd;
-
- if (!dock_docked())
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "undock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
- !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "dock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-#endif /* CONFIG_THINKPAD_ACPI_DOCK */
-
-/*************************************************************************
- * Bay subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-
-TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
- "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
- "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
- ); /* A21e, R30, R31 */
-TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
- "_EJ0", /* all others */
- ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
- "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
- ); /* all others */
-TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
- "_EJ0", /* 770x */
- ); /* all others */
-
-static int __init bay_init(struct ibm_init_struct *iibm)
-{
- vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
-
- TPACPI_ACPIHANDLE_INIT(bay);
- if (bay_handle)
- TPACPI_ACPIHANDLE_INIT(bay_ej);
- TPACPI_ACPIHANDLE_INIT(bay2);
- if (bay2_handle)
- TPACPI_ACPIHANDLE_INIT(bay2_ej);
-
- tp_features.bay_status = bay_handle &&
- acpi_evalf(bay_handle, NULL, "_STA", "qv");
- tp_features.bay_status2 = bay2_handle &&
- acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
- tp_features.bay_eject = bay_handle && bay_ej_handle &&
- (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
- tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
- (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
- vdbg_printk(TPACPI_DBG_INIT,
- "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
- str_supported(tp_features.bay_status),
- str_supported(tp_features.bay_eject),
- str_supported(tp_features.bay_status2),
- str_supported(tp_features.bay_eject2));
-
- return (tp_features.bay_status || tp_features.bay_eject ||
- tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
- acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- dev_name(&ibm->acpi->device->dev),
- event, 0);
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
- int len = 0;
- int occupied = bay_occupied(bay);
- int occupied2 = bay_occupied(bay2);
- int eject, eject2;
-
- len += sprintf(p + len, "status:\t\t%s\n",
- tp_features.bay_status ?
- (occupied ? "occupied" : "unoccupied") :
- "not supported");
- if (tp_features.bay_status2)
- len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
- "occupied" : "unoccupied");
-
- eject = tp_features.bay_eject && occupied;
- eject2 = tp_features.bay_eject2 && occupied2;
-
- if (eject && eject2)
- len += sprintf(p + len, "commands:\teject, eject2\n");
- else if (eject)
- len += sprintf(p + len, "commands:\teject\n");
- else if (eject2)
- len += sprintf(p + len, "commands:\teject2\n");
-
- return len;
-}
-
-static int bay_write(char *buf)
-{
- char *cmd;
-
- if (!tp_features.bay_eject && !tp_features.bay_eject2)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
- if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else if (tp_features.bay_eject2 &&
- strlencmp(cmd, "eject2") == 0) {
- if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
- .notify = bay_notify,
- .handle = &bay_handle,
- .type = ACPI_SYSTEM_NOTIFY,
-};
-
-static struct ibm_struct bay_driver_data = {
- .name = "bay",
- .read = bay_read,
- .write = bay_write,
- .acpi = &ibm_bay_acpidriver,
-};
-
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
-
-/*************************************************************************
* CMOS subdriver
*/
@@ -5945,14 +5642,48 @@ static struct backlight_ops ibm_backlight_data = {
/* --------------------------------------------------------------------- */
+/*
+ * These are only useful for models that have only one possibility
+ * of GPU. If the BIOS model handles both ATI and Intel, don't use
+ * these quirks.
+ */
+#define TPACPI_BRGHT_Q_NOEC 0x0001 /* Must NOT use EC HBRV */
+#define TPACPI_BRGHT_Q_EC 0x0002 /* Should or must use EC HBRV */
+#define TPACPI_BRGHT_Q_ASK 0x8000 /* Ask for user report */
+
+static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
+ /* Models with ATI GPUs known to require ECNVRAM mode */
+ TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
+
+ /* Models with ATI GPUs (waiting confirmation) */
+ TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+ TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
+
+ /* Models with Intel Extreme Graphics 2 (waiting confirmation) */
+ TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+ TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+ TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
+
+ /* Models with Intel GMA900 */
+ TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */
+ TPACPI_Q_IBM('7', '4', TPACPI_BRGHT_Q_NOEC), /* X41 */
+ TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */
+};
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
+ unsigned long quirks;
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
mutex_init(&brightness_mutex);
+ quirks = tpacpi_check_quirks(brightness_quirk_table,
+ ARRAY_SIZE(brightness_quirk_table));
+
/*
* We always attempt to detect acpi support, so as to switch
* Lenovo Vista BIOS to ACPI brightness mode even if we are not
@@ -6009,23 +5740,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
/* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */
if (brightness_mode == TPACPI_BRGHT_MODE_AUTO ||
brightness_mode == TPACPI_BRGHT_MODE_MAX) {
- if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) {
- /*
- * IBM models that define HBRV probably have
- * EC-based backlight level control
- */
- if (acpi_evalf(ec_handle, NULL, "HBRV", "qd"))
- /* T40-T43, R50-R52, R50e, R51e, X31-X41 */
- brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM;
- else
- /* all other IBM ThinkPads */
- brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
- } else
- /* All Lenovo ThinkPads */
+ if (quirks & TPACPI_BRGHT_Q_EC)
+ brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM;
+ else
brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
dbg_printk(TPACPI_DBG_BRGHT,
- "selected brightness_mode=%d\n",
+ "driver auto-selected brightness_mode=%d\n",
brightness_mode);
}
@@ -6052,6 +5773,15 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
"brightness is supported\n");
+ if (quirks & TPACPI_BRGHT_Q_ASK) {
+ printk(TPACPI_NOTICE
+ "brightness: will use unverified default: "
+ "brightness_mode=%d\n", brightness_mode);
+ printk(TPACPI_NOTICE
+ "brightness: please report to %s whether it works well "
+ "or not on your ThinkPad\n", TPACPI_MAIL);
+ }
+
ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
@@ -7854,22 +7584,6 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = light_init,
.data = &light_driver_data,
},
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
- {
- .init = dock_init,
- .data = &dock_driver_data[0],
- },
- {
- .init = dock_init2,
- .data = &dock_driver_data[1],
- },
-#endif
-#ifdef CONFIG_THINKPAD_ACPI_BAY
- {
- .init = bay_init,
- .data = &bay_driver_data,
- },
-#endif
{
.init = cmos_init,
.data = &cmos_driver_data,
@@ -7968,12 +7682,6 @@ TPACPI_PARAM(hotkey);
TPACPI_PARAM(bluetooth);
TPACPI_PARAM(video);
TPACPI_PARAM(light);
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-TPACPI_PARAM(dock);
-#endif
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-TPACPI_PARAM(bay);
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
TPACPI_PARAM(cmos);
TPACPI_PARAM(led);
TPACPI_PARAM(beep);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 9496494f340e..c07fdb94d665 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -194,13 +194,13 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
pnpacpi_parse_resource_option_data(dev);
if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+ struct acpica_device_id_list *cid_list = device->pnp.cid_list;
int i;
for (i = 0; i < cid_list->count; i++) {
- if (!ispnpidacpi(cid_list->id[i].value))
+ if (!ispnpidacpi(cid_list->ids[i].string))
continue;
- pnp_add_id(dev, cid_list->id[i].value);
+ pnp_add_id(dev, cid_list->ids[i].string);
}
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7eda34838bfe..bdbc4f73fcdc 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -43,6 +43,13 @@ config BATTERY_DS2760
help
Say Y here to enable support for batteries with ds2760 chip.
+config BATTERY_DS2782
+ tristate "DS2782 standalone gas-gauge"
+ depends on I2C
+ help
+ Say Y here to enable support for the DS2782 standalone battery
+ gas-gauge.
+
config BATTERY_PMU
tristate "Apple PMU battery"
depends on PPC32 && ADB_PMU
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index daf3179689aa..380d17c9ae29 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_APM_POWER) += apm_power.o
obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
+obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index 520b5c49ff30..1bb8498f14be 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -56,6 +56,7 @@ struct ds2760_device_info {
struct device *w1_dev;
struct workqueue_struct *monitor_wqueue;
struct delayed_work monitor_work;
+ struct delayed_work set_charged_work;
};
static unsigned int cache_time = 1000;
@@ -66,6 +67,14 @@ static unsigned int pmod_enabled;
module_param(pmod_enabled, bool, 0644);
MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit");
+static unsigned int rated_capacity;
+module_param(rated_capacity, uint, 0644);
+MODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index");
+
+static unsigned int current_accum;
+module_param(current_accum, uint, 0644);
+MODULE_PARM_DESC(current_accum, "current accumulator value");
+
/* Some batteries have their rated capacity stored a N * 10 mAh, while
* others use an index into this table. */
static int rated_capacities[] = {
@@ -168,8 +177,13 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
di->raw[DS2760_ACTIVE_FULL + 1];
- scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
- di->raw[DS2760_ACTIVE_FULL + 1];
+ /* If the full_active_uAh value is not given, fall back to the rated
+ * capacity. This is likely to happen when chips are not part of the
+ * battery pack and is therefore not bootstrapped. */
+ if (di->full_active_uAh == 0)
+ di->full_active_uAh = di->rated_capacity / 1000L;
+
+ scale[0] = di->full_active_uAh;
for (i = 1; i < 5; i++)
scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
@@ -206,6 +220,22 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
return 0;
}
+static void ds2760_battery_set_current_accum(struct ds2760_device_info *di,
+ unsigned int acr_val)
+{
+ unsigned char acr[2];
+
+ /* acr is in units of 0.25 mAh */
+ acr_val *= 4L;
+ acr_val /= 1000;
+
+ acr[0] = acr_val >> 8;
+ acr[1] = acr_val & 0xff;
+
+ if (w1_ds2760_write(di->w1_dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2)
+ dev_warn(di->dev, "ACR write failed\n");
+}
+
static void ds2760_battery_update_status(struct ds2760_device_info *di)
{
int old_charge_status = di->charge_status;
@@ -237,21 +267,9 @@ static void ds2760_battery_update_status(struct ds2760_device_info *di)
if (di->full_counter < 2) {
di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
} else {
- unsigned char acr[2];
- int acr_val;
-
- /* acr is in units of 0.25 mAh */
- acr_val = di->full_active_uAh * 4L / 1000;
-
- acr[0] = acr_val >> 8;
- acr[1] = acr_val & 0xff;
-
- if (w1_ds2760_write(di->w1_dev, acr,
- DS2760_CURRENT_ACCUM_MSB, 2) < 2)
- dev_warn(di->dev,
- "ACR reset failed\n");
-
di->charge_status = POWER_SUPPLY_STATUS_FULL;
+ ds2760_battery_set_current_accum(di,
+ di->full_active_uAh);
}
}
} else {
@@ -274,6 +292,17 @@ static void ds2760_battery_write_status(struct ds2760_device_info *di,
w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
}
+static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di,
+ unsigned char rated_capacity)
+{
+ if (rated_capacity == di->raw[DS2760_RATED_CAPACITY])
+ return;
+
+ w1_ds2760_write(di->w1_dev, &rated_capacity, DS2760_RATED_CAPACITY, 1);
+ w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+ w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+}
+
static void ds2760_battery_work(struct work_struct *work)
{
struct ds2760_device_info *di = container_of(work,
@@ -299,6 +328,52 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy)
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
}
+
+static void ds2760_battery_set_charged_work(struct work_struct *work)
+{
+ char bias;
+ struct ds2760_device_info *di = container_of(work,
+ struct ds2760_device_info, set_charged_work.work);
+
+ dev_dbg(di->dev, "%s\n", __func__);
+
+ ds2760_battery_read_status(di);
+
+ /* When we get notified by external circuitry that the battery is
+ * considered fully charged now, we know that there is no current
+ * flow any more. However, the ds2760's internal current meter is
+ * too inaccurate to rely on - spec say something ~15% failure.
+ * Hence, we use the current offset bias register to compensate
+ * that error.
+ */
+
+ if (!power_supply_am_i_supplied(&di->bat))
+ return;
+
+ bias = (signed char) di->current_raw +
+ (signed char) di->raw[DS2760_CURRENT_OFFSET_BIAS];
+
+ dev_dbg(di->dev, "%s: bias = %d\n", __func__, bias);
+
+ w1_ds2760_write(di->w1_dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1);
+ w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+ w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
+
+ /* Write to the di->raw[] buffer directly - the CURRENT_OFFSET_BIAS
+ * value won't be read back by ds2760_battery_read_status() */
+ di->raw[DS2760_CURRENT_OFFSET_BIAS] = bias;
+}
+
+static void ds2760_battery_set_charged(struct power_supply *psy)
+{
+ struct ds2760_device_info *di = to_ds2760_device_info(psy);
+
+ /* postpone the actual work by 20 secs. This is for debouncing GPIO
+ * signals and to let the current value settle. See AN4188. */
+ cancel_delayed_work(&di->set_charged_work);
+ queue_delayed_work(di->monitor_wqueue, &di->set_charged_work, HZ * 20);
+}
+
static int ds2760_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -337,6 +412,12 @@ static int ds2760_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TEMP:
val->intval = di->temp_C;
break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ val->intval = di->life_sec;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = di->rem_capacity;
+ break;
default:
return -EINVAL;
}
@@ -353,6 +434,8 @@ static enum power_supply_property ds2760_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_EMPTY,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
};
static int ds2760_battery_probe(struct platform_device *pdev)
@@ -376,17 +459,12 @@ static int ds2760_battery_probe(struct platform_device *pdev)
di->bat.properties = ds2760_battery_props;
di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
di->bat.get_property = ds2760_battery_get_property;
+ di->bat.set_charged = ds2760_battery_set_charged;
di->bat.external_power_changed =
ds2760_battery_external_power_changed;
di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
- retval = power_supply_register(&pdev->dev, &di->bat);
- if (retval) {
- dev_err(di->dev, "failed to register battery\n");
- goto batt_failed;
- }
-
/* enable sleep mode feature */
ds2760_battery_read_status(di);
status = di->raw[DS2760_STATUS_REG];
@@ -397,7 +475,24 @@ static int ds2760_battery_probe(struct platform_device *pdev)
ds2760_battery_write_status(di, status);
+ /* set rated capacity from module param */
+ if (rated_capacity)
+ ds2760_battery_write_rated_capacity(di, rated_capacity);
+
+ /* set current accumulator if given as parameter.
+ * this should only be done for bootstrapping the value */
+ if (current_accum)
+ ds2760_battery_set_current_accum(di, current_accum);
+
+ retval = power_supply_register(&pdev->dev, &di->bat);
+ if (retval) {
+ dev_err(di->dev, "failed to register battery\n");
+ goto batt_failed;
+ }
+
INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
+ INIT_DELAYED_WORK(&di->set_charged_work,
+ ds2760_battery_set_charged_work);
di->monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
if (!di->monitor_wqueue) {
retval = -ESRCH;
@@ -422,6 +517,8 @@ static int ds2760_battery_remove(struct platform_device *pdev)
cancel_rearming_delayed_workqueue(di->monitor_wqueue,
&di->monitor_work);
+ cancel_rearming_delayed_workqueue(di->monitor_wqueue,
+ &di->set_charged_work);
destroy_workqueue(di->monitor_wqueue);
power_supply_unregister(&di->bat);
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
new file mode 100644
index 000000000000..da14f374cb60
--- /dev/null
+++ b/drivers/power/ds2782_battery.c
@@ -0,0 +1,330 @@
+/*
+ * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC
+ *
+ * Copyright (C) 2009 Bluewater Systems Ltd
+ *
+ * Author: Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/swab.h>
+#include <linux/i2c.h>
+#include <linux/idr.h>
+#include <linux/power_supply.h>
+
+#define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */
+
+#define DS2782_REG_VOLT_MSB 0x0c
+#define DS2782_REG_TEMP_MSB 0x0a
+#define DS2782_REG_CURRENT_MSB 0x0e
+
+/* EEPROM Block */
+#define DS2782_REG_RSNSP 0x69 /* Sense resistor value */
+
+/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
+#define DS2782_CURRENT_UNITS 1563
+
+#define to_ds2782_info(x) container_of(x, struct ds2782_info, battery)
+
+struct ds2782_info {
+ struct i2c_client *client;
+ struct power_supply battery;
+ int id;
+};
+
+static DEFINE_IDR(battery_id);
+static DEFINE_MUTEX(battery_lock);
+
+static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(info->client, reg);
+ if (ret < 0) {
+ dev_err(&info->client->dev, "register read failed\n");
+ return ret;
+ }
+
+ *val = ret;
+ return 0;
+}
+
+static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb,
+ s16 *val)
+{
+ int ret;
+
+ ret = swab16(i2c_smbus_read_word_data(info->client, reg_msb));
+ if (ret < 0) {
+ dev_err(&info->client->dev, "register read failed\n");
+ return ret;
+ }
+
+ *val = ret;
+ return 0;
+}
+
+static int ds2782_get_temp(struct ds2782_info *info, int *temp)
+{
+ s16 raw;
+ int err;
+
+ /*
+ * Temperature is measured in units of 0.125 degrees celcius, the
+ * power_supply class measures temperature in tenths of degrees
+ * celsius. The temperature value is stored as a 10 bit number, plus
+ * sign in the upper bits of a 16 bit register.
+ */
+ err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw);
+ if (err)
+ return err;
+ *temp = ((raw / 32) * 125) / 100;
+ return 0;
+}
+
+static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
+{
+ int sense_res;
+ int err;
+ u8 sense_res_raw;
+ s16 raw;
+
+ /*
+ * The units of measurement for current are dependent on the value of
+ * the sense resistor.
+ */
+ err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
+ if (err)
+ return err;
+ if (sense_res_raw == 0) {
+ dev_err(&info->client->dev, "sense resistor value is 0\n");
+ return -ENXIO;
+ }
+ sense_res = 1000 / sense_res_raw;
+
+ dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
+ sense_res);
+ err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw);
+ if (err)
+ return err;
+ *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
+ return 0;
+}
+
+static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA)
+{
+ s16 raw;
+ int err;
+
+ /*
+ * Voltage is measured in units of 4.88mV. The voltage is stored as
+ * a 10-bit number plus sign, in the upper bits of a 16-bit register
+ */
+ err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw);
+ if (err)
+ return err;
+ *voltage_uA = (raw / 32) * 4800;
+ return 0;
+}
+
+static int ds2782_get_capacity(struct ds2782_info *info, int *capacity)
+{
+ int err;
+ u8 raw;
+
+ err = ds2782_read_reg(info, DS2782_REG_RARC, &raw);
+ if (err)
+ return err;
+ *capacity = raw;
+ return raw;
+}
+
+static int ds2782_get_status(struct ds2782_info *info, int *status)
+{
+ int err;
+ int current_uA;
+ int capacity;
+
+ err = ds2782_get_current(info, &current_uA);
+ if (err)
+ return err;
+
+ err = ds2782_get_capacity(info, &capacity);
+ if (err)
+ return err;
+
+ if (capacity == 100)
+ *status = POWER_SUPPLY_STATUS_FULL;
+ else if (current_uA == 0)
+ *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else if (current_uA < 0)
+ *status = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ *status = POWER_SUPPLY_STATUS_CHARGING;
+
+ return 0;
+}
+
+static int ds2782_battery_get_property(struct power_supply *psy,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ struct ds2782_info *info = to_ds2782_info(psy);
+ int ret;
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = ds2782_get_status(info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CAPACITY:
+ ret = ds2782_get_capacity(info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = ds2782_get_voltage(info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = ds2782_get_current(info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_TEMP:
+ ret = ds2782_get_temp(info, &val->intval);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property ds2782_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static void ds2782_power_supply_init(struct power_supply *battery)
+{
+ battery->type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->properties = ds2782_battery_props;
+ battery->num_properties = ARRAY_SIZE(ds2782_battery_props);
+ battery->get_property = ds2782_battery_get_property;
+ battery->external_power_changed = NULL;
+}
+
+static int ds2782_battery_remove(struct i2c_client *client)
+{
+ struct ds2782_info *info = i2c_get_clientdata(client);
+
+ power_supply_unregister(&info->battery);
+ kfree(info->battery.name);
+
+ mutex_lock(&battery_lock);
+ idr_remove(&battery_id, info->id);
+ mutex_unlock(&battery_lock);
+
+ i2c_set_clientdata(client, info);
+
+ kfree(info);
+ return 0;
+}
+
+static int ds2782_battery_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ds2782_info *info;
+ int ret;
+ int num;
+
+ /* Get an ID for this battery */
+ ret = idr_pre_get(&battery_id, GFP_KERNEL);
+ if (ret == 0) {
+ ret = -ENOMEM;
+ goto fail_id;
+ }
+
+ mutex_lock(&battery_lock);
+ ret = idr_get_new(&battery_id, client, &num);
+ mutex_unlock(&battery_lock);
+ if (ret < 0)
+ goto fail_id;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto fail_info;
+ }
+
+ info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num);
+ if (!info->battery.name) {
+ ret = -ENOMEM;
+ goto fail_name;
+ }
+
+ i2c_set_clientdata(client, info);
+ info->client = client;
+ ds2782_power_supply_init(&info->battery);
+
+ ret = power_supply_register(&client->dev, &info->battery);
+ if (ret) {
+ dev_err(&client->dev, "failed to register battery\n");
+ goto fail_register;
+ }
+
+ return 0;
+
+fail_register:
+ kfree(info->battery.name);
+fail_name:
+ i2c_set_clientdata(client, info);
+ kfree(info);
+fail_info:
+ mutex_lock(&battery_lock);
+ idr_remove(&battery_id, num);
+ mutex_unlock(&battery_lock);
+fail_id:
+ return ret;
+}
+
+static const struct i2c_device_id ds2782_id[] = {
+ {"ds2782", 0},
+ {},
+};
+
+static struct i2c_driver ds2782_battery_driver = {
+ .driver = {
+ .name = "ds2782-battery",
+ },
+ .probe = ds2782_battery_probe,
+ .remove = ds2782_battery_remove,
+ .id_table = ds2782_id,
+};
+
+static int __init ds2782_init(void)
+{
+ return i2c_add_driver(&ds2782_battery_driver);
+}
+module_init(ds2782_init);
+
+static void __exit ds2782_exit(void)
+{
+ i2c_del_driver(&ds2782_battery_driver);
+}
+module_exit(ds2782_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5fbca2681baa..8fefe5a73558 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -8,8 +8,11 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/types.h>
#include <linux/err.h>
+#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/jiffies.h>
@@ -35,6 +38,7 @@
#define BAT_STAT_AC 0x10
#define BAT_STAT_CHARGING 0x20
#define BAT_STAT_DISCHARGING 0x40
+#define BAT_STAT_TRICKLE 0x80
#define BAT_ERR_INFOFAIL 0x02
#define BAT_ERR_OVERVOLTAGE 0x04
@@ -89,7 +93,7 @@ static char bat_serial[17]; /* Ick */
static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte)
{
if (olpc_platform_info.ecver > 0x44) {
- if (ec_byte & BAT_STAT_CHARGING)
+ if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE))
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (ec_byte & BAT_STAT_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -219,7 +223,8 @@ static int olpc_bat_get_property(struct power_supply *psy,
It doesn't matter though -- the EC will return the last-known
information, and it's as if we just ran that _little_ bit faster
and managed to read it out before the battery went away. */
- if (!(ec_byte & BAT_STAT_PRESENT) && psp != POWER_SUPPLY_PROP_PRESENT)
+ if (!(ec_byte & (BAT_STAT_PRESENT | BAT_STAT_TRICKLE)) &&
+ psp != POWER_SUPPLY_PROP_PRESENT)
return -ENODEV;
switch (psp) {
@@ -228,8 +233,17 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ if (ec_byte & BAT_STAT_TRICKLE)
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ else if (ec_byte & BAT_STAT_CHARGING)
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = !!(ec_byte & BAT_STAT_PRESENT);
+ val->intval = !!(ec_byte & (BAT_STAT_PRESENT |
+ BAT_STAT_TRICKLE));
break;
case POWER_SUPPLY_PROP_HEALTH:
@@ -272,6 +286,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
val->intval = ec_byte;
break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ if (ec_byte & BAT_STAT_FULL)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else if (ec_byte & BAT_STAT_LOW)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ else
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ break;
case POWER_SUPPLY_PROP_TEMP:
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
@@ -311,12 +333,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
static enum power_supply_property olpc_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_MANUFACTURER,
@@ -334,21 +358,21 @@ static ssize_t olpc_bat_eeprom_read(struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
uint8_t ec_byte;
- int ret, end;
+ int ret;
+ int i;
if (off >= EEPROM_SIZE)
return 0;
if (off + count > EEPROM_SIZE)
count = EEPROM_SIZE - off;
- end = EEPROM_START + off + count;
- for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) {
- ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1,
- &buf[ec_byte - EEPROM_START], 1);
+ for (i = 0; i < count; i++) {
+ ec_byte = EEPROM_START + off + i;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &buf[i], 1);
if (ret) {
- printk(KERN_ERR "olpc-battery: EC command "
- "EC_BAT_EEPROM @ 0x%x failed -"
- " %d!\n", ec_byte, ret);
+ pr_err("olpc-battery: "
+ "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",
+ ec_byte, ret);
return -EIO;
}
}
@@ -366,6 +390,29 @@ static struct bin_attribute olpc_bat_eeprom = {
.read = olpc_bat_eeprom_read,
};
+/* Allow userspace to see the specific error value pulled from the EC */
+
+static ssize_t olpc_bat_error_read(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t ec_byte;
+ ssize_t ret;
+
+ ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ec_byte);
+}
+
+static struct device_attribute olpc_bat_error = {
+ .attr = {
+ .name = "error",
+ .mode = S_IRUGO,
+ },
+ .show = olpc_bat_error_read,
+};
+
/*********************************************************************
* Initialisation
*********************************************************************/
@@ -429,8 +476,14 @@ static int __init olpc_bat_init(void)
if (ret)
goto eeprom_failed;
+ ret = device_create_file(olpc_bat.dev, &olpc_bat_error);
+ if (ret)
+ goto error_failed;
+
goto success;
+error_failed:
+ device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
eeprom_failed:
power_supply_unregister(&olpc_bat);
battery_failed:
@@ -443,6 +496,7 @@ success:
static void __exit olpc_bat_exit(void)
{
+ device_remove_file(olpc_bat.dev, &olpc_bat_error);
device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
power_supply_unregister(&olpc_bat);
power_supply_unregister(&olpc_ac);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 5520040449c4..cce75b40b435 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -18,7 +18,9 @@
#include <linux/power_supply.h>
#include "power_supply.h"
+/* exported for the APM Power driver, APM emulation */
struct class *power_supply_class;
+EXPORT_SYMBOL_GPL(power_supply_class);
static int __power_supply_changed_work(struct device *dev, void *data)
{
@@ -55,6 +57,7 @@ void power_supply_changed(struct power_supply *psy)
schedule_work(&psy->changed_work);
}
+EXPORT_SYMBOL_GPL(power_supply_changed);
static int __power_supply_am_i_supplied(struct device *dev, void *data)
{
@@ -86,6 +89,7 @@ int power_supply_am_i_supplied(struct power_supply *psy)
return error;
}
+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
static int __power_supply_is_system_supplied(struct device *dev, void *data)
{
@@ -110,6 +114,35 @@ int power_supply_is_system_supplied(void)
return error;
}
+EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
+
+int power_supply_set_battery_charged(struct power_supply *psy)
+{
+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) {
+ psy->set_charged(psy);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
+
+static int power_supply_match_device_by_name(struct device *dev, void *data)
+{
+ const char *name = data;
+ struct power_supply *psy = dev_get_drvdata(dev);
+
+ return strcmp(psy->name, name) == 0;
+}
+
+struct power_supply *power_supply_get_by_name(char *name)
+{
+ struct device *dev = class_find_device(power_supply_class, NULL, name,
+ power_supply_match_device_by_name);
+
+ return dev ? dev_get_drvdata(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(power_supply_get_by_name);
int power_supply_register(struct device *parent, struct power_supply *psy)
{
@@ -144,6 +177,7 @@ dev_create_failed:
success:
return rc;
}
+EXPORT_SYMBOL_GPL(power_supply_register);
void power_supply_unregister(struct power_supply *psy)
{
@@ -152,6 +186,7 @@ void power_supply_unregister(struct power_supply *psy)
power_supply_remove_attrs(psy);
device_unregister(psy->dev);
}
+EXPORT_SYMBOL_GPL(power_supply_unregister);
static int __init power_supply_class_init(void)
{
@@ -170,15 +205,6 @@ static void __exit power_supply_class_exit(void)
class_destroy(power_supply_class);
}
-EXPORT_SYMBOL_GPL(power_supply_changed);
-EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
-EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
-EXPORT_SYMBOL_GPL(power_supply_register);
-EXPORT_SYMBOL_GPL(power_supply_unregister);
-
-/* exported for the APM Power driver, APM emulation */
-EXPORT_SYMBOL_GPL(power_supply_class);
-
subsys_initcall(power_supply_class_init);
module_exit(power_supply_class_exit);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index da73591017f9..08144393d64b 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -43,6 +43,9 @@ static ssize_t power_supply_show_property(struct device *dev,
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
};
+ static char *charge_type[] = {
+ "Unknown", "N/A", "Trickle", "Fast"
+ };
static char *health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
"Unspecified failure", "Cold",
@@ -51,6 +54,9 @@ static ssize_t power_supply_show_property(struct device *dev,
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
"LiMn"
};
+ static char *capacity_level_text[] = {
+ "Unknown", "Critical", "Low", "Normal", "High", "Full"
+ };
ssize_t ret;
struct power_supply *psy = dev_get_drvdata(dev);
const ptrdiff_t off = attr - power_supply_attrs;
@@ -67,10 +73,14 @@ static ssize_t power_supply_show_property(struct device *dev,
if (off == POWER_SUPPLY_PROP_STATUS)
return sprintf(buf, "%s\n", status_text[value.intval]);
+ else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
+ return sprintf(buf, "%s\n", charge_type[value.intval]);
else if (off == POWER_SUPPLY_PROP_HEALTH)
return sprintf(buf, "%s\n", health_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
return sprintf(buf, "%s\n", technology_text[value.intval]);
+ else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
+ return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
return sprintf(buf, "%s\n", value.strval);
@@ -81,6 +91,7 @@ static ssize_t power_supply_show_property(struct device *dev,
static struct device_attribute power_supply_attrs[] = {
/* Properties of type `int' */
POWER_SUPPLY_ATTR(status),
+ POWER_SUPPLY_ATTR(charge_type),
POWER_SUPPLY_ATTR(health),
POWER_SUPPLY_ATTR(present),
POWER_SUPPLY_ATTR(online),
@@ -109,6 +120,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(energy_now),
POWER_SUPPLY_ATTR(energy_avg),
POWER_SUPPLY_ATTR(capacity),
+ POWER_SUPPLY_ATTR(capacity_level),
POWER_SUPPLY_ATTR(temp),
POWER_SUPPLY_ATTR(temp_ambient),
POWER_SUPPLY_ATTR(time_to_empty_now),
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
index 1b16bf343f2f..28b0299c0043 100644
--- a/drivers/power/wm8350_power.c
+++ b/drivers/power/wm8350_power.c
@@ -321,6 +321,24 @@ static int wm8350_bat_check_health(struct wm8350 *wm8350)
return POWER_SUPPLY_HEALTH_GOOD;
}
+static int wm8350_bat_get_charge_type(struct wm8350 *wm8350)
+{
+ int state;
+
+ state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
+ WM8350_CHG_STS_MASK;
+ switch (state) {
+ case WM8350_CHG_STS_OFF:
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ case WM8350_CHG_STS_TRICKLE:
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ case WM8350_CHG_STS_FAST:
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ default:
+ return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+}
+
static int wm8350_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -342,6 +360,9 @@ static int wm8350_bat_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_HEALTH:
val->intval = wm8350_bat_check_health(wm8350);
break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = wm8350_bat_get_charge_type(wm8350);
+ break;
default:
ret = -EINVAL;
break;
@@ -355,6 +376,7 @@ static enum power_supply_property wm8350_bat_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
};
/*********************************************************************
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f4317798e47c..da7483ef32b3 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -117,4 +117,11 @@ config REGULATOR_LP3971
Say Y here to support the voltage regulators and convertors
on National Semiconductors LP3971 PMIC
+config REGULATOR_PCAP
+ tristate "PCAP2 regulator driver"
+ depends on EZX_PCAP
+ help
+ This driver provides support for the voltage regulators of the
+ PCAP2 PMIC.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4d762c4cccfd..3a9748ff860b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 98c3a74e9949..e38db55600e0 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -37,7 +37,7 @@ static int has_full_constraints;
*/
struct regulator_map {
struct list_head list;
- struct device *dev;
+ const char *dev_name; /* The dev_name() for the consumer */
const char *supply;
struct regulator_dev *regulator;
};
@@ -857,23 +857,39 @@ out:
* set_consumer_device_supply: Bind a regulator to a symbolic supply
* @rdev: regulator source
* @consumer_dev: device the supply applies to
+ * @consumer_dev_name: dev_name() string for device supply applies to
* @supply: symbolic name for supply
*
* Allows platform initialisation code to map physical regulator
* sources to symbolic names for supplies for use by devices. Devices
* should use these symbolic names to request regulators, avoiding the
* need to provide board-specific regulator names as platform data.
+ *
+ * Only one of consumer_dev and consumer_dev_name may be specified.
*/
static int set_consumer_device_supply(struct regulator_dev *rdev,
- struct device *consumer_dev, const char *supply)
+ struct device *consumer_dev, const char *consumer_dev_name,
+ const char *supply)
{
struct regulator_map *node;
+ int has_dev;
+
+ if (consumer_dev && consumer_dev_name)
+ return -EINVAL;
+
+ if (!consumer_dev_name && consumer_dev)
+ consumer_dev_name = dev_name(consumer_dev);
if (supply == NULL)
return -EINVAL;
+ if (consumer_dev_name != NULL)
+ has_dev = 1;
+ else
+ has_dev = 0;
+
list_for_each_entry(node, &regulator_map_list, list) {
- if (consumer_dev != node->dev)
+ if (consumer_dev_name != node->dev_name)
continue;
if (strcmp(node->supply, supply) != 0)
continue;
@@ -886,30 +902,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
return -EBUSY;
}
- node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+ node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
if (node == NULL)
return -ENOMEM;
node->regulator = rdev;
- node->dev = consumer_dev;
node->supply = supply;
+ if (has_dev) {
+ node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+ if (node->dev_name == NULL) {
+ kfree(node);
+ return -ENOMEM;
+ }
+ }
+
list_add(&node->list, &regulator_map_list);
return 0;
}
static void unset_consumer_device_supply(struct regulator_dev *rdev,
- struct device *consumer_dev)
+ const char *consumer_dev_name, struct device *consumer_dev)
{
struct regulator_map *node, *n;
+ if (consumer_dev && !consumer_dev_name)
+ consumer_dev_name = dev_name(consumer_dev);
+
list_for_each_entry_safe(node, n, &regulator_map_list, list) {
- if (rdev == node->regulator &&
- consumer_dev == node->dev) {
- list_del(&node->list);
- kfree(node);
- return;
- }
+ if (rdev != node->regulator)
+ continue;
+
+ if (consumer_dev_name && node->dev_name &&
+ strcmp(consumer_dev_name, node->dev_name))
+ continue;
+
+ list_del(&node->list);
+ kfree(node->dev_name);
+ kfree(node);
+ return;
}
}
@@ -920,6 +951,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
list_for_each_entry_safe(node, n, &regulator_map_list, list) {
if (rdev == node->regulator) {
list_del(&node->list);
+ kfree(node->dev_name);
kfree(node);
return;
}
@@ -1001,35 +1033,33 @@ overflow_err:
return NULL;
}
-/**
- * regulator_get - lookup and obtain a reference to a regulator.
- * @dev: device for regulator "consumer"
- * @id: Supply name or regulator ID.
- *
- * Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno.
- *
- * Use of supply names configured via regulator_set_device_supply() is
- * strongly encouraged. It is recommended that the supply name used
- * should match the name used for the supply and/or the relevant
- * device pins in the datasheet.
- */
-struct regulator *regulator_get(struct device *dev, const char *id)
+/* Internal regulator request function */
+static struct regulator *_regulator_get(struct device *dev, const char *id,
+ int exclusive)
{
struct regulator_dev *rdev;
struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV);
+ const char *devname = NULL;
+ int ret;
if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n");
return regulator;
}
+ if (dev)
+ devname = dev_name(dev);
+
mutex_lock(&regulator_list_mutex);
list_for_each_entry(map, &regulator_map_list, list) {
- if (dev == map->dev &&
- strcmp(map->supply, id) == 0) {
+ /* If the mapping has a device set up it must match */
+ if (map->dev_name &&
+ (!devname || strcmp(map->dev_name, devname)))
+ continue;
+
+ if (strcmp(map->supply, id) == 0) {
rdev = map->regulator;
goto found;
}
@@ -1038,6 +1068,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator;
found:
+ if (rdev->exclusive) {
+ regulator = ERR_PTR(-EPERM);
+ goto out;
+ }
+
+ if (exclusive && rdev->open_count) {
+ regulator = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
if (!try_module_get(rdev->owner))
goto out;
@@ -1047,13 +1087,70 @@ found:
module_put(rdev->owner);
}
+ rdev->open_count++;
+ if (exclusive) {
+ rdev->exclusive = 1;
+
+ ret = _regulator_is_enabled(rdev);
+ if (ret > 0)
+ rdev->use_count = 1;
+ else
+ rdev->use_count = 0;
+ }
+
out:
mutex_unlock(&regulator_list_mutex);
+
return regulator;
}
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged. It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+ return _regulator_get(dev, id, 0);
+}
EXPORT_SYMBOL_GPL(regulator_get);
/**
+ * regulator_get_exclusive - obtain exclusive access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno. Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers which cannot tolerate shared
+ * use of the regulator such as those which need to force the
+ * regulator off for correct operation of the hardware they are
+ * controlling.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged. It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
+{
+ return _regulator_get(dev, id, 1);
+}
+EXPORT_SYMBOL_GPL(regulator_get_exclusive);
+
+/**
* regulator_put - "free" the regulator source
* @regulator: regulator source
*
@@ -1081,6 +1178,9 @@ void regulator_put(struct regulator *regulator)
list_del(&regulator->list);
kfree(regulator);
+ rdev->open_count--;
+ rdev->exclusive = 0;
+
module_put(rdev->owner);
mutex_unlock(&regulator_list_mutex);
}
@@ -1350,6 +1450,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
EXPORT_SYMBOL_GPL(regulator_list_voltage);
/**
+ * regulator_is_supported_voltage - check if a voltage range can be supported
+ *
+ * @regulator: Regulator to check.
+ * @min_uV: Minimum required voltage in uV.
+ * @max_uV: Maximum required voltage in uV.
+ *
+ * Returns a boolean or a negative error code.
+ */
+int regulator_is_supported_voltage(struct regulator *regulator,
+ int min_uV, int max_uV)
+{
+ int i, voltages, ret;
+
+ ret = regulator_count_voltages(regulator);
+ if (ret < 0)
+ return ret;
+ voltages = ret;
+
+ for (i = 0; i < voltages; i++) {
+ ret = regulator_list_voltage(regulator, i);
+
+ if (ret >= min_uV && ret <= max_uV)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
* @min_uV: Minimum required voltage in uV
@@ -1864,6 +1993,30 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
+/**
+ * regulator_mode_to_status - convert a regulator mode into a status
+ *
+ * @mode: Mode to convert
+ *
+ * Convert a regulator mode into a status.
+ */
+int regulator_mode_to_status(unsigned int mode)
+{
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ return REGULATOR_STATUS_FAST;
+ case REGULATOR_MODE_NORMAL:
+ return REGULATOR_STATUS_NORMAL;
+ case REGULATOR_MODE_IDLE:
+ return REGULATOR_STATUS_IDLE;
+ case REGULATOR_STATUS_STANDBY:
+ return REGULATOR_STATUS_STANDBY;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(regulator_mode_to_status);
+
/*
* To avoid cluttering sysfs (and memory) with useless state, only
* create attributes that can be meaningfully displayed.
@@ -2067,11 +2220,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
for (i = 0; i < init_data->num_consumer_supplies; i++) {
ret = set_consumer_device_supply(rdev,
init_data->consumer_supplies[i].dev,
+ init_data->consumer_supplies[i].dev_name,
init_data->consumer_supplies[i].supply);
if (ret < 0) {
for (--i; i >= 0; i--)
unset_consumer_device_supply(rdev,
- init_data->consumer_supplies[i].dev);
+ init_data->consumer_supplies[i].dev_name,
+ init_data->consumer_supplies[i].dev);
goto scrub;
}
}
@@ -2106,6 +2261,7 @@ void regulator_unregister(struct regulator_dev *rdev)
return;
mutex_lock(&regulator_list_mutex);
+ WARN_ON(rdev->open_count);
unset_regulator_supplies(rdev);
list_del(&rdev->list);
if (rdev->supply)
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index b8b89ef10a84..7d9c2506d215 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -64,6 +64,14 @@
#define DA9034_MDTV2 (0x33)
#define DA9034_MVRC (0x34)
+/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */
+#define DA9035_OVER3 (0x12)
+#define DA9035_VCC2 (0x1f)
+#define DA9035_3DTV1 (0x2c)
+#define DA9035_3DTV2 (0x2d)
+#define DA9035_3VRC (0x2e)
+#define DA9035_AUTOSKIP (0x2f)
+
struct da903x_regulator_info {
struct regulator_desc desc;
@@ -79,6 +87,10 @@ struct da903x_regulator_info {
int enable_bit;
};
+static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950,
+ 2000, 2050, 2700, 2750, 2800, 2850,
+ 2900, 2950, 3000, 3050 };
+
static inline struct device *to_da903x_dev(struct regulator_dev *rdev)
{
return rdev_get_dev(rdev)->parent->parent;
@@ -162,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
return !!(reg_val & (1 << info->enable_bit));
}
+static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = info->min_uV + info->step_uV * selector;
+ if (ret > info->max_uV)
+ return -EINVAL;
+ return ret;
+}
+
/* DA9030 specific operations */
static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
@@ -305,9 +328,18 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
return info->min_uV + info->step_uV * val;
}
+static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector > ARRAY_SIZE(da9034_ldo12_data))
+ return -EINVAL;
+ return da9034_ldo12_data[selector] * 1000;
+}
+
static struct regulator_ops da903x_regulator_ldo_ops = {
.set_voltage = da903x_set_ldo_voltage,
.get_voltage = da903x_get_voltage,
+ .list_voltage = da903x_list_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -317,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
static struct regulator_ops da9030_regulator_ldo14_ops = {
.set_voltage = da9030_set_ldo14_voltage,
.get_voltage = da9030_get_ldo14_voltage,
+ .list_voltage = da903x_list_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -326,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
static struct regulator_ops da9030_regulator_ldo1_15_ops = {
.set_voltage = da9030_set_ldo1_15_voltage,
.get_voltage = da903x_get_voltage,
+ .list_voltage = da903x_list_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -334,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
static struct regulator_ops da9034_regulator_dvc_ops = {
.set_voltage = da9034_set_dvc_voltage,
.get_voltage = da903x_get_voltage,
+ .list_voltage = da903x_list_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -343,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
static struct regulator_ops da9034_regulator_ldo12_ops = {
.set_voltage = da9034_set_ldo12_voltage,
.get_voltage = da9034_get_ldo12_voltage,
+ .list_voltage = da9034_list_ldo12_voltage,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -355,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.ops = &da903x_regulator_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.id = _pmic##_ID_LDO##_id, \
+ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
}, \
.min_uV = (min) * 1000, \
@@ -367,24 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.enable_bit = (ebit), \
}
-#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+#define DA903x_DVC(_pmic, _id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
{ \
.desc = { \
.name = #_id, \
.ops = &da9034_regulator_dvc_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = DA9034_ID_##_id, \
+ .id = _pmic##_ID_##_id, \
+ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \
}, \
.min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \
.step_uV = (step) * 1000, \
- .vol_reg = DA9034_##vreg, \
+ .vol_reg = _pmic##_##vreg, \
.vol_shift = (0), \
.vol_nbits = (nbits), \
- .update_reg = DA9034_##ureg, \
+ .update_reg = _pmic##_##ureg, \
.update_bit = (ubit), \
- .enable_reg = DA9034_##ereg, \
+ .enable_reg = _pmic##_##ereg, \
.enable_bit = (ebit), \
}
@@ -394,8 +432,22 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+ DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \
+ ereg, ebit)
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+ DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \
+ ereg, ebit)
+
+#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+ DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \
+ ereg, ebit)
+
static struct da903x_regulator_info da903x_regulator_info[] = {
/* DA9030 */
+ DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0),
+
DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1),
DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2),
DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3),
@@ -417,9 +469,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
/* DA9034 */
- DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
- DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
- DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
+ DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0),
+ DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1),
+ DA9034_DVC(LDO2, 725, 1500, 25, SDTV2, 5, VCC1, 4, OVER1, 2),
DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5),
@@ -435,6 +487,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+
+ /* DA9035 */
+ DA9035_DVC(BUCK3, 1800, 2200, 100, 3DTV1, 3, VCC2, 0, OVER3, 3),
};
static inline struct da903x_regulator_info *find_regulator_info(int id)
@@ -462,8 +517,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
}
/* Workaround for the weird LDO12 voltage setting */
- if (ri->desc.id == DA9034_ID_LDO12)
+ if (ri->desc.id == DA9034_ID_LDO12) {
ri->desc.ops = &da9034_regulator_ldo12_ops;
+ ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data);
+ }
if (ri->desc.id == DA9030_ID_LDO14)
ri->desc.ops = &da9030_regulator_ldo14_ops;
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
new file mode 100644
index 000000000000..fdb90940ef0f
--- /dev/null
+++ b/drivers/regulator/pcap-regulator.c
@@ -0,0 +1,318 @@
+/*
+ * PCAP2 Regulator Driver
+ *
+ * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ezx-pcap.h>
+
+static const u16 V1_table[] = {
+ 2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+};
+
+static const u16 V2_table[] = {
+ 2500, 2775,
+};
+
+static const u16 V3_table[] = {
+ 1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+};
+
+static const u16 V4_table[] = {
+ 1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+};
+
+static const u16 V5_table[] = {
+ 1875, 2275, 2475, 2775,
+};
+
+static const u16 V6_table[] = {
+ 2475, 2775,
+};
+
+static const u16 V7_table[] = {
+ 1875, 2775,
+};
+
+#define V8_table V4_table
+
+static const u16 V9_table[] = {
+ 1575, 1875, 2475, 2775,
+};
+
+static const u16 V10_table[] = {
+ 5000,
+};
+
+static const u16 VAUX1_table[] = {
+ 1875, 2475, 2775, 3000,
+};
+
+#define VAUX2_table VAUX1_table
+
+static const u16 VAUX3_table[] = {
+ 1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
+ 2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+};
+
+static const u16 VAUX4_table[] = {
+ 1800, 1800, 3000, 5000,
+};
+
+static const u16 VSIM_table[] = {
+ 1875, 3000,
+};
+
+static const u16 VSIM2_table[] = {
+ 1875,
+};
+
+static const u16 VVIB_table[] = {
+ 1300, 1800, 2000, 3000,
+};
+
+static const u16 SW1_table[] = {
+ 900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
+ 1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+};
+
+#define SW2_table SW1_table
+
+static const u16 SW3_table[] = {
+ 4000, 4500, 5000, 5500,
+};
+
+struct pcap_regulator {
+ const u8 reg;
+ const u8 en;
+ const u8 index;
+ const u8 stby;
+ const u8 lowpwr;
+ const u8 n_voltages;
+ const u16 *voltage_table;
+};
+
+#define NA 0xff
+
+#define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr) \
+ [_vreg] = { \
+ .reg = _reg, \
+ .en = _en, \
+ .index = _index, \
+ .stby = _stby, \
+ .lowpwr = _lowpwr, \
+ .n_voltages = ARRAY_SIZE(_vreg##_table), \
+ .voltage_table = _vreg##_table, \
+ }
+
+static struct pcap_regulator vreg_table[] = {
+ VREG_INFO(V1, PCAP_REG_VREG1, 1, 2, 18, 0),
+ VREG_INFO(V2, PCAP_REG_VREG1, 5, 6, 19, 22),
+ VREG_INFO(V3, PCAP_REG_VREG1, 7, 8, 20, 23),
+ VREG_INFO(V4, PCAP_REG_VREG1, 11, 12, 21, 24),
+ /* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */
+ VREG_INFO(V5, PCAP_REG_VREG1, 15, 16, 12, 19),
+
+ VREG_INFO(V6, PCAP_REG_VREG2, 1, 2, 14, 20),
+ VREG_INFO(V7, PCAP_REG_VREG2, 3, 4, 15, 21),
+ VREG_INFO(V8, PCAP_REG_VREG2, 5, 6, 16, 22),
+ VREG_INFO(V9, PCAP_REG_VREG2, 9, 10, 17, 23),
+ VREG_INFO(V10, PCAP_REG_VREG2, 10, NA, 18, 24),
+
+ VREG_INFO(VAUX1, PCAP_REG_AUXVREG, 1, 2, 22, 23),
+ /* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */
+ VREG_INFO(VAUX2, PCAP_REG_AUXVREG, 4, 5, 0, 1),
+ VREG_INFO(VAUX3, PCAP_REG_AUXVREG, 7, 8, 2, 3),
+ VREG_INFO(VAUX4, PCAP_REG_AUXVREG, 12, 13, 4, 5),
+ VREG_INFO(VSIM, PCAP_REG_AUXVREG, 17, 18, NA, 6),
+ VREG_INFO(VSIM2, PCAP_REG_AUXVREG, 16, NA, NA, 7),
+ VREG_INFO(VVIB, PCAP_REG_AUXVREG, 19, 20, NA, NA),
+
+ VREG_INFO(SW1, PCAP_REG_SWCTRL, 1, 2, NA, NA),
+ VREG_INFO(SW2, PCAP_REG_SWCTRL, 6, 7, NA, NA),
+ /* SW3 STBY is on PCAP_REG_AUXVREG */
+ VREG_INFO(SW3, PCAP_REG_SWCTRL, 11, 12, 24, NA),
+
+ /* SWxS used to control SWx voltage on standby */
+/* VREG_INFO(SW1S, PCAP_REG_LOWPWR, NA, 12, NA, NA),
+ VREG_INFO(SW2S, PCAP_REG_LOWPWR, NA, 20, NA, NA), */
+};
+
+static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+ void *pcap = rdev_get_drvdata(rdev);
+ int uV;
+ u8 i;
+
+ /* the regulator doesn't support voltage switching */
+ if (vreg->n_voltages == 1)
+ return -EINVAL;
+
+ for (i = 0; i < vreg->n_voltages; i++) {
+ /* For V1 the first is not the best match */
+ if (i == 0 && rdev_get_id(rdev) == V1)
+ i = 1;
+ else if (i + 1 == vreg->n_voltages && rdev_get_id(rdev) == V1)
+ i = 0;
+
+ uV = vreg->voltage_table[i] * 1000;
+ if (min_uV <= uV && uV <= max_uV)
+ return ezx_pcap_set_bits(pcap, vreg->reg,
+ (vreg->n_voltages - 1) << vreg->index,
+ i << vreg->index);
+
+ if (i == 0 && rdev_get_id(rdev) == V1)
+ i = vreg->n_voltages - 1;
+ }
+
+ /* the requested voltage range is not supported by this regulator */
+ return -EINVAL;
+}
+
+static int pcap_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+ void *pcap = rdev_get_drvdata(rdev);
+ u32 tmp;
+ int mV;
+
+ if (vreg->n_voltages == 1)
+ return vreg->voltage_table[0] * 1000;
+
+ ezx_pcap_read(pcap, vreg->reg, &tmp);
+ tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+ mV = vreg->voltage_table[tmp];
+
+ return mV * 1000;
+}
+
+static int pcap_regulator_enable(struct regulator_dev *rdev)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+ void *pcap = rdev_get_drvdata(rdev);
+
+ if (vreg->en == NA)
+ return -EINVAL;
+
+ return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 1 << vreg->en);
+}
+
+static int pcap_regulator_disable(struct regulator_dev *rdev)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+ void *pcap = rdev_get_drvdata(rdev);
+
+ if (vreg->en == NA)
+ return -EINVAL;
+
+ return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 0);
+}
+
+static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+ void *pcap = rdev_get_drvdata(rdev);
+ u32 tmp;
+
+ if (vreg->en == NA)
+ return -EINVAL;
+
+ ezx_pcap_read(pcap, vreg->reg, &tmp);
+ return (tmp >> vreg->en) & 1;
+}
+
+static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned int index)
+{
+ struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+
+ return vreg->voltage_table[index] * 1000;
+}
+
+static struct regulator_ops pcap_regulator_ops = {
+ .list_voltage = pcap_regulator_list_voltage,
+ .set_voltage = pcap_regulator_set_voltage,
+ .get_voltage = pcap_regulator_get_voltage,
+ .enable = pcap_regulator_enable,
+ .disable = pcap_regulator_disable,
+ .is_enabled = pcap_regulator_is_enabled,
+};
+
+#define VREG(_vreg) \
+ [_vreg] = { \
+ .name = #_vreg, \
+ .id = _vreg, \
+ .n_voltages = ARRAY_SIZE(_vreg##_table), \
+ .ops = &pcap_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+static struct regulator_desc pcap_regulators[] = {
+ VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7),
+ VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3),
+ VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2),
+};
+
+static int __devinit pcap_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ void *pcap = platform_get_drvdata(pdev);
+
+ rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
+ pdev->dev.platform_data, pcap);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ platform_set_drvdata(pdev, rdev);
+
+ return 0;
+}
+
+static int __devexit pcap_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver pcap_regulator_driver = {
+ .driver = {
+ .name = "pcap-regulator",
+ },
+ .probe = pcap_regulator_probe,
+ .remove = __devexit_p(pcap_regulator_remove),
+};
+
+static int __init pcap_regulator_init(void)
+{
+ return platform_driver_register(&pcap_regulator_driver);
+}
+
+static void __exit pcap_regulator_exit(void)
+{
+ platform_driver_unregister(&pcap_regulator_driver);
+}
+
+module_init(pcap_regulator_init);
+module_exit(pcap_regulator_exit);
+
+MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>");
+MODULE_DESCRIPTION("PCAP2 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 8e14900eb686..70ba77557650 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -155,7 +155,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
int regulator_id, millivolts, volt_bits;
u8 regnr;
- pcf = rdev_get_drvdata(rdev);;
+ pcf = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= PCF50633_NUM_REGULATORS)
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index e7db5664722e..addc032c84bf 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -27,71 +27,81 @@ struct virtual_consumer_data {
unsigned int mode;
};
-static void update_voltage_constraints(struct virtual_consumer_data *data)
+static void update_voltage_constraints(struct device *dev,
+ struct virtual_consumer_data *data)
{
int ret;
if (data->min_uV && data->max_uV
&& data->min_uV <= data->max_uV) {
+ dev_dbg(dev, "Requesting %d-%duV\n",
+ data->min_uV, data->max_uV);
ret = regulator_set_voltage(data->regulator,
- data->min_uV, data->max_uV);
+ data->min_uV, data->max_uV);
if (ret != 0) {
- printk(KERN_ERR "regulator_set_voltage() failed: %d\n",
- ret);
+ dev_err(dev,
+ "regulator_set_voltage() failed: %d\n", ret);
return;
}
}
if (data->min_uV && data->max_uV && !data->enabled) {
+ dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator);
if (ret == 0)
data->enabled = 1;
else
- printk(KERN_ERR "regulator_enable() failed: %d\n",
+ dev_err(dev, "regulator_enable() failed: %d\n",
ret);
}
if (!(data->min_uV && data->max_uV) && data->enabled) {
+ dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator);
if (ret == 0)
data->enabled = 0;
else
- printk(KERN_ERR "regulator_disable() failed: %d\n",
+ dev_err(dev, "regulator_disable() failed: %d\n",
ret);
}
}
-static void update_current_limit_constraints(struct virtual_consumer_data
- *data)
+static void update_current_limit_constraints(struct device *dev,
+ struct virtual_consumer_data *data)
{
int ret;
if (data->max_uA
&& data->min_uA <= data->max_uA) {
+ dev_dbg(dev, "Requesting %d-%duA\n",
+ data->min_uA, data->max_uA);
ret = regulator_set_current_limit(data->regulator,
data->min_uA, data->max_uA);
if (ret != 0) {
- pr_err("regulator_set_current_limit() failed: %d\n",
- ret);
+ dev_err(dev,
+ "regulator_set_current_limit() failed: %d\n",
+ ret);
return;
}
}
if (data->max_uA && !data->enabled) {
+ dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator);
if (ret == 0)
data->enabled = 1;
else
- printk(KERN_ERR "regulator_enable() failed: %d\n",
+ dev_err(dev, "regulator_enable() failed: %d\n",
ret);
}
if (!(data->min_uA && data->max_uA) && data->enabled) {
+ dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator);
if (ret == 0)
data->enabled = 0;
else
- printk(KERN_ERR "regulator_disable() failed: %d\n",
+ dev_err(dev, "regulator_disable() failed: %d\n",
ret);
}
}
@@ -115,7 +125,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock);
data->min_uV = val;
- update_voltage_constraints(data);
+ update_voltage_constraints(dev, data);
mutex_unlock(&data->lock);
@@ -141,7 +151,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock);
data->max_uV = val;
- update_voltage_constraints(data);
+ update_voltage_constraints(dev, data);
mutex_unlock(&data->lock);
@@ -167,7 +177,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock);
data->min_uA = val;
- update_current_limit_constraints(data);
+ update_current_limit_constraints(dev, data);
mutex_unlock(&data->lock);
@@ -193,7 +203,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock);
data->max_uA = val;
- update_current_limit_constraints(data);
+ update_current_limit_constraints(dev, data);
mutex_unlock(&data->lock);
@@ -276,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
if (drvdata == NULL) {
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
mutex_init(&drvdata->lock);
@@ -285,13 +294,18 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata->regulator = regulator_get(&pdev->dev, reg_id);
if (IS_ERR(drvdata->regulator)) {
ret = PTR_ERR(drvdata->regulator);
+ dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n",
+ reg_id, ret);
goto err;
}
for (i = 0; i < ARRAY_SIZE(attributes); i++) {
ret = device_create_file(&pdev->dev, attributes[i]);
- if (ret != 0)
- goto err;
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to create attr %d: %d\n",
+ i, ret);
+ goto err_regulator;
+ }
}
drvdata->mode = regulator_get_mode(drvdata->regulator);
@@ -300,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
return 0;
+err_regulator:
+ regulator_put(drvdata->regulator);
err:
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(&pdev->dev, attributes[i]);
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 17a00b0fafd1..768bd0e5b48b 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
{
struct platform_device *pdev;
int ret;
+ if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
+ return -EINVAL;
if (wm8350->pmic.pdev[reg])
return -EBUSY;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 81adbdbd5042..139b7834d6e3 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -500,6 +500,15 @@ config RTC_DRV_M48T59
This driver can also be built as a module, if so, the module
will be called "rtc-m48t59".
+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
@@ -509,6 +518,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 3c0f2b2ac927..2a565f8e06b7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.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_PCF8563) += rtc-pcf8563.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 23e10b6263d6..f7a4701bf863 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -1174,23 +1174,34 @@ static struct platform_driver cmos_platform_driver = {
}
};
+#ifdef CONFIG_PNP
+static bool pnp_driver_registered;
+#endif
+static bool platform_driver_registered;
+
static int __init cmos_init(void)
{
int retval = 0;
#ifdef CONFIG_PNP
- pnp_register_driver(&cmos_pnp_driver);
+ retval = pnp_register_driver(&cmos_pnp_driver);
+ if (retval == 0)
+ pnp_driver_registered = true;
#endif
- if (!cmos_rtc.dev)
+ if (!cmos_rtc.dev) {
retval = platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
+ if (retval == 0)
+ platform_driver_registered = true;
+ }
if (retval == 0)
return 0;
#ifdef CONFIG_PNP
- pnp_unregister_driver(&cmos_pnp_driver);
+ if (pnp_driver_registered)
+ pnp_unregister_driver(&cmos_pnp_driver);
#endif
return retval;
}
@@ -1199,9 +1210,11 @@ module_init(cmos_init);
static void __exit cmos_exit(void)
{
#ifdef CONFIG_PNP
- pnp_unregister_driver(&cmos_pnp_driver);
+ if (pnp_driver_registered)
+ pnp_unregister_driver(&cmos_pnp_driver);
#endif
- platform_driver_unregister(&cmos_platform_driver);
+ if (platform_driver_registered)
+ platform_driver_unregister(&cmos_platform_driver);
}
module_exit(cmos_exit);
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-pxa.c b/drivers/rtc/rtc-pxa.c
index bb8cc05605ac..747ca194fad4 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -438,34 +438,37 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int pxa_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int pxa_rtc_suspend(struct device *dev)
{
- struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
+ struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
enable_irq_wake(pxa_rtc->irq_Alrm);
return 0;
}
-static int pxa_rtc_resume(struct platform_device *pdev)
+static int pxa_rtc_resume(struct device *dev)
{
- struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
+ struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
disable_irq_wake(pxa_rtc->irq_Alrm);
return 0;
}
-#else
-#define pxa_rtc_suspend NULL
-#define pxa_rtc_resume NULL
+
+static struct dev_pm_ops pxa_rtc_pm_ops = {
+ .suspend = pxa_rtc_suspend,
+ .resume = pxa_rtc_resume,
+};
#endif
static struct platform_driver pxa_rtc_driver = {
.remove = __exit_p(pxa_rtc_remove),
- .suspend = pxa_rtc_suspend,
- .resume = pxa_rtc_resume,
.driver = {
- .name = "pxa-rtc",
+ .name = "pxa-rtc",
+#ifdef CONFIG_PM
+ .pm = &pxa_rtc_pm_ops,
+#endif
},
};
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
new file mode 100644
index 000000000000..e1313feb060f
--- /dev/null
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -0,0 +1,222 @@
+/*
+ * Ricoh RP5C01 RTC Driver
+ *
+ * Copyright 2009 Geert Uytterhoeven
+ *
+ * Based on the A3000 TOD code in arch/m68k/amiga/config.c
+ * Copyright (C) 1993 Hamish Macdonald
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+
+enum {
+ RP5C01_1_SECOND = 0x0, /* MODE 00 */
+ RP5C01_10_SECOND = 0x1, /* MODE 00 */
+ RP5C01_1_MINUTE = 0x2, /* MODE 00 and MODE 01 */
+ RP5C01_10_MINUTE = 0x3, /* MODE 00 and MODE 01 */
+ RP5C01_1_HOUR = 0x4, /* MODE 00 and MODE 01 */
+ RP5C01_10_HOUR = 0x5, /* MODE 00 and MODE 01 */
+ RP5C01_DAY_OF_WEEK = 0x6, /* MODE 00 and MODE 01 */
+ RP5C01_1_DAY = 0x7, /* MODE 00 and MODE 01 */
+ RP5C01_10_DAY = 0x8, /* MODE 00 and MODE 01 */
+ RP5C01_1_MONTH = 0x9, /* MODE 00 */
+ RP5C01_10_MONTH = 0xa, /* MODE 00 */
+ RP5C01_1_YEAR = 0xb, /* MODE 00 */
+ RP5C01_10_YEAR = 0xc, /* MODE 00 */
+
+ RP5C01_12_24_SELECT = 0xa, /* MODE 01 */
+ RP5C01_LEAP_YEAR = 0xb, /* MODE 01 */
+
+ RP5C01_MODE = 0xd, /* all modes */
+ RP5C01_TEST = 0xe, /* all modes */
+ RP5C01_RESET = 0xf, /* all modes */
+};
+
+#define RP5C01_12_24_SELECT_12 (0 << 0)
+#define RP5C01_12_24_SELECT_24 (1 << 0)
+
+#define RP5C01_10_HOUR_AM (0 << 1)
+#define RP5C01_10_HOUR_PM (1 << 1)
+
+#define RP5C01_MODE_TIMER_EN (1 << 3) /* timer enable */
+#define RP5C01_MODE_ALARM_EN (1 << 2) /* alarm enable */
+
+#define RP5C01_MODE_MODE_MASK (3 << 0)
+#define RP5C01_MODE_MODE00 (0 << 0) /* time */
+#define RP5C01_MODE_MODE01 (1 << 0) /* alarm, 12h/24h, leap year */
+#define RP5C01_MODE_RAM_BLOCK10 (2 << 0) /* RAM 4 bits x 13 */
+#define RP5C01_MODE_RAM_BLOCK11 (3 << 0) /* RAM 4 bits x 13 */
+
+#define RP5C01_RESET_1HZ_PULSE (1 << 3)
+#define RP5C01_RESET_16HZ_PULSE (1 << 2)
+#define RP5C01_RESET_SECOND (1 << 1) /* reset divider stages for */
+ /* seconds or smaller units */
+#define RP5C01_RESET_ALARM (1 << 0) /* reset all alarm registers */
+
+
+struct rp5c01_priv {
+ u32 __iomem *regs;
+ struct rtc_device *rtc;
+};
+
+static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
+ unsigned int reg)
+{
+ return __raw_readl(&priv->regs[reg]) & 0xf;
+}
+
+static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
+ unsigned int reg)
+{
+ return __raw_writel(val, &priv->regs[reg]);
+}
+
+static void rp5c01_lock(struct rp5c01_priv *priv)
+{
+ rp5c01_write(priv, RP5C01_MODE_MODE00, RP5C01_MODE);
+}
+
+static void rp5c01_unlock(struct rp5c01_priv *priv)
+{
+ rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01,
+ RP5C01_MODE);
+}
+
+static int rp5c01_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+ rp5c01_lock(priv);
+
+ tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 +
+ rp5c01_read(priv, RP5C01_1_SECOND);
+ tm->tm_min = rp5c01_read(priv, RP5C01_10_MINUTE) * 10 +
+ rp5c01_read(priv, RP5C01_1_MINUTE);
+ tm->tm_hour = rp5c01_read(priv, RP5C01_10_HOUR) * 10 +
+ rp5c01_read(priv, RP5C01_1_HOUR);
+ tm->tm_mday = rp5c01_read(priv, RP5C01_10_DAY) * 10 +
+ rp5c01_read(priv, RP5C01_1_DAY);
+ tm->tm_wday = rp5c01_read(priv, RP5C01_DAY_OF_WEEK);
+ tm->tm_mon = rp5c01_read(priv, RP5C01_10_MONTH) * 10 +
+ rp5c01_read(priv, RP5C01_1_MONTH) - 1;
+ tm->tm_year = rp5c01_read(priv, RP5C01_10_YEAR) * 10 +
+ rp5c01_read(priv, RP5C01_1_YEAR);
+ if (tm->tm_year <= 69)
+ tm->tm_year += 100;
+
+ rp5c01_unlock(priv);
+
+ return rtc_valid_tm(tm);
+}
+
+static int rp5c01_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+ rp5c01_lock(priv);
+
+ rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND);
+ rp5c01_write(priv, tm->tm_sec % 10, RP5C01_1_SECOND);
+ rp5c01_write(priv, tm->tm_min / 10, RP5C01_10_MINUTE);
+ rp5c01_write(priv, tm->tm_min % 10, RP5C01_1_MINUTE);
+ rp5c01_write(priv, tm->tm_hour / 10, RP5C01_10_HOUR);
+ rp5c01_write(priv, tm->tm_hour % 10, RP5C01_1_HOUR);
+ rp5c01_write(priv, tm->tm_mday / 10, RP5C01_10_DAY);
+ rp5c01_write(priv, tm->tm_mday % 10, RP5C01_1_DAY);
+ if (tm->tm_wday != -1)
+ rp5c01_write(priv, tm->tm_wday, RP5C01_DAY_OF_WEEK);
+ rp5c01_write(priv, (tm->tm_mon + 1) / 10, RP5C01_10_MONTH);
+ rp5c01_write(priv, (tm->tm_mon + 1) % 10, RP5C01_1_MONTH);
+ if (tm->tm_year >= 100)
+ tm->tm_year -= 100;
+ rp5c01_write(priv, tm->tm_year / 10, RP5C01_10_YEAR);
+ rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR);
+
+ rp5c01_unlock(priv);
+ return 0;
+}
+
+static const struct rtc_class_ops rp5c01_rtc_ops = {
+ .read_time = rp5c01_read_time,
+ .set_time = rp5c01_set_time,
+};
+
+static int __init rp5c01_rtc_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ struct rp5c01_priv *priv;
+ struct rtc_device *rtc;
+ int error;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = ioremap(res->start, resource_size(res));
+ if (!priv->regs) {
+ error = -ENOMEM;
+ goto out_free_priv;
+ }
+
+ rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ error = PTR_ERR(rtc);
+ goto out_unmap;
+ }
+
+ priv->rtc = rtc;
+ platform_set_drvdata(dev, priv);
+ return 0;
+
+out_unmap:
+ iounmap(priv->regs);
+out_free_priv:
+ kfree(priv);
+ return error;
+}
+
+static int __exit rp5c01_rtc_remove(struct platform_device *dev)
+{
+ struct rp5c01_priv *priv = platform_get_drvdata(dev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->regs);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver rp5c01_rtc_driver = {
+ .driver = {
+ .name = "rtc-rp5c01",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(rp5c01_rtc_remove),
+};
+
+static int __init rp5c01_rtc_init(void)
+{
+ return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe);
+}
+
+static void __exit rp5c01_rtc_fini(void)
+{
+ platform_driver_unregister(&rp5c01_rtc_driver);
+}
+
+module_init(rp5c01_rtc_init);
+module_exit(rp5c01_rtc_fini);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ricoh RP5C01 RTC driver");
+MODULE_ALIAS("platform:rtc-rp5c01");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 4f247e4dd3f9..dbd07c31042a 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -393,31 +393,34 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int sa1100_rtc_suspend(struct device *dev)
{
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
enable_irq_wake(IRQ_RTCAlrm);
return 0;
}
-static int sa1100_rtc_resume(struct platform_device *pdev)
+static int sa1100_rtc_resume(struct device *dev)
{
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
disable_irq_wake(IRQ_RTCAlrm);
return 0;
}
-#else
-#define sa1100_rtc_suspend NULL
-#define sa1100_rtc_resume NULL
+
+static struct dev_pm_ops sa1100_rtc_pm_ops = {
+ .suspend = sa1100_rtc_suspend,
+ .resume = sa1100_rtc_resume,
+};
#endif
static struct platform_driver sa1100_rtc_driver = {
.probe = sa1100_rtc_probe,
.remove = sa1100_rtc_remove,
- .suspend = sa1100_rtc_suspend,
- .resume = sa1100_rtc_resume,
.driver = {
- .name = "sa1100-rtc",
+ .name = "sa1100-rtc",
+#ifdef CONFIG_PM
+ .pm = &sa1100_rtc_pm_ops,
+#endif
},
};
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 749836668655..001af665add1 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -669,14 +669,14 @@ static void dasd_profile_end(struct dasd_block *block,
* memory and 2) dasd_smalloc_request uses the static ccw memory
* that gets allocated for each device.
*/
-struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
+struct dasd_ccw_req *dasd_kmalloc_request(int magic, int cplength,
int datasize,
struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
/* Sanity checks */
- BUG_ON( magic == NULL || datasize > PAGE_SIZE ||
+ BUG_ON(datasize > PAGE_SIZE ||
(cplength*sizeof(struct ccw1)) > PAGE_SIZE);
cqr = kzalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC);
@@ -700,14 +700,13 @@ struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
return ERR_PTR(-ENOMEM);
}
}
- strncpy((char *) &cqr->magic, magic, 4);
- ASCEBC((char *) &cqr->magic, 4);
+ cqr->magic = magic;
set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
dasd_get_device(device);
return cqr;
}
-struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
+struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength,
int datasize,
struct dasd_device *device)
{
@@ -717,7 +716,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
int size;
/* Sanity checks */
- BUG_ON( magic == NULL || datasize > PAGE_SIZE ||
+ BUG_ON(datasize > PAGE_SIZE ||
(cplength*sizeof(struct ccw1)) > PAGE_SIZE);
size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
@@ -744,8 +743,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
cqr->data = data;
memset(cqr->data, 0, datasize);
}
- strncpy((char *) &cqr->magic, magic, 4);
- ASCEBC((char *) &cqr->magic, 4);
+ cqr->magic = magic;
set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
dasd_get_device(device);
return cqr;
@@ -899,9 +897,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
switch (rc) {
case 0:
cqr->status = DASD_CQR_IN_IO;
- DBF_DEV_EVENT(DBF_DEBUG, device,
- "start_IO: request %p started successful",
- cqr);
break;
case -EBUSY:
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
@@ -1699,8 +1694,11 @@ static void __dasd_process_request_queue(struct dasd_block *block)
* for that. State DASD_STATE_ONLINE is normal block device
* operation.
*/
- if (basedev->state < DASD_STATE_READY)
+ if (basedev->state < DASD_STATE_READY) {
+ while ((req = blk_fetch_request(block->request_queue)))
+ __blk_end_request_all(req, -EIO);
return;
+ }
/* Now we try to fetch requests from the request queue */
while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) {
if (basedev->features & DASD_FEATURE_READONLY &&
@@ -2530,7 +2528,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_restore_device);
static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
void *rdc_buffer,
int rdc_buffer_size,
- char *magic)
+ int magic)
{
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
@@ -2561,7 +2559,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
}
-int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
+int dasd_generic_read_dev_chars(struct dasd_device *device, int magic,
void *rdc_buffer, int rdc_buffer_size)
{
int ret;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 27991b692056..e8ff7b0c961d 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -7,7 +7,7 @@
*
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-eckd"
#include <linux/timer.h>
#include <linux/slab.h>
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 5b7bbc87593b..70a008c00522 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -5,7 +5,7 @@
* Author(s): Stefan Weinhuber <wein@de.ibm.com>
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-eckd"
#include <linux/list.h>
#include <asm/ebcdic.h>
@@ -379,8 +379,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
int rc;
unsigned long flags;
- cqr = dasd_kmalloc_request("ECKD",
- 1 /* PSF */ + 1 /* RSSD */ ,
+ cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
(sizeof(struct dasd_psf_prssd_data)),
device);
if (IS_ERR(cqr))
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 644086ba2ede..4e49b4a6c880 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -8,7 +8,7 @@
*
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-diag"
#include <linux/stddef.h>
#include <linux/kernel.h>
@@ -523,8 +523,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
/* Build the request */
datasize = sizeof(struct dasd_diag_req) +
count*sizeof(struct dasd_diag_bio);
- cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
- datasize, memdev);
+ cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev);
if (IS_ERR(cqr))
return cqr;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index c11770f5b368..a1ce573648a2 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -10,7 +10,7 @@
* Author.........: Nigel Hislop <hislop_nigel@emc.com>
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-eckd"
#include <linux/stddef.h>
#include <linux/kernel.h>
@@ -730,7 +730,8 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
- cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count,
+ device);
if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
@@ -934,8 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
struct dasd_eckd_private *private;
private = (struct dasd_eckd_private *) device->private;
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1 /* PSF */ + 1 /* RSSD */ ,
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
(sizeof(struct dasd_psf_prssd_data) +
sizeof(struct dasd_rssd_features)),
device);
@@ -998,7 +998,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
struct dasd_psf_ssc_data *psf_ssc_data;
struct ccw1 *ccw;
- cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
sizeof(struct dasd_psf_ssc_data),
device);
@@ -1149,8 +1149,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
goto out_err3;
/* Read Device Characteristics */
- rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data,
- 64);
+ rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
+ &private->rdc_data, 64);
if (rc) {
DBF_EVENT(DBF_WARNING,
"Read device characteristics failed, rc=%d for "
@@ -1217,8 +1217,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
cplength = 8;
datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data);
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- cplength, datasize, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
@@ -1499,8 +1498,7 @@ dasd_eckd_format_device(struct dasd_device * device,
return ERR_PTR(-EINVAL);
}
/* Allocate the format ccw request. */
- fcp = dasd_smalloc_request(dasd_eckd_discipline.name,
- cplength, datasize, device);
+ fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
if (IS_ERR(fcp))
return fcp;
@@ -1783,8 +1781,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
datasize += count*sizeof(struct LO_eckd_data);
}
/* Allocate the ccw request. */
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- cplength, datasize, startdev);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
+ startdev);
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
@@ -1948,8 +1946,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
cidaw * sizeof(unsigned long long);
/* Allocate the ccw request. */
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- cplength, datasize, startdev);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
+ startdev);
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
@@ -2249,8 +2247,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
/* Allocate the ccw request. */
itcw_size = itcw_calc_size(0, ctidaw, 0);
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 0, itcw_size, startdev);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
if (IS_ERR(cqr))
return cqr;
@@ -2557,8 +2554,7 @@ dasd_eckd_release(struct dasd_device *device)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 32, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Could not allocate initialization request");
@@ -2600,8 +2596,7 @@ dasd_eckd_reserve(struct dasd_device *device)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 32, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Could not allocate initialization request");
@@ -2642,8 +2637,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 32, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Could not allocate initialization request");
@@ -2681,8 +2675,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
struct ccw1 *ccw;
int rc;
- cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1 /* PSF */ + 1 /* RSSD */ ,
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
(sizeof(struct dasd_psf_prssd_data) +
sizeof(struct dasd_rssd_perf_stats_t)),
device);
@@ -2828,7 +2821,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
}
/* setup CCWs for PSF + RSSD */
- cqr = dasd_smalloc_request("ECKD", 2 , 0, device);
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device);
if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Could not allocate initialization request");
@@ -3254,7 +3247,7 @@ int dasd_eckd_restore_device(struct dasd_device *device)
/* Read Device Characteristics */
memset(&private->rdc_data, 0, sizeof(private->rdc_data));
- rc = dasd_generic_read_dev_chars(device, "ECKD",
+ rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
&private->rdc_data, 64);
if (rc) {
DBF_EVENT(DBF_WARNING,
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index c24c8c30380d..d96039eae59b 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -6,7 +6,7 @@
* Author(s): Stefan Weinhuber <wein@de.ibm.com>
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-eckd"
#include <linux/init.h>
#include <linux/fs.h>
@@ -464,7 +464,7 @@ int dasd_eer_enable(struct dasd_device *device)
if (!device->discipline || strcmp(device->discipline->name, "ECKD"))
return -EPERM; /* FIXME: -EMEDIUMTYPE ? */
- cqr = dasd_kmalloc_request("ECKD", 1 /* SNSS */,
+ cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */,
SNSS_DATA_SIZE, device);
if (IS_ERR(cqr))
return -ENOMEM;
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index cb8f9cef7429..7656384a811d 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -99,8 +99,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
cqr->lpm = LPM_ANYPATH;
cqr->status = DASD_CQR_FILLED;
} else {
- dev_err(&device->cdev->dev,
- "default ERP has run out of retries and failed\n");
+ pr_err("%s: default ERP has run out of retries and failed\n",
+ dev_name(&device->cdev->dev));
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
}
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 31849ad5e59f..f245377e8e27 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -5,7 +5,7 @@
* Copyright IBM Corp. 1999, 2009
*/
-#define KMSG_COMPONENT "dasd"
+#define KMSG_COMPONENT "dasd-fba"
#include <linux/stddef.h>
#include <linux/kernel.h>
@@ -152,8 +152,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
block->base = device;
/* Read Device Characteristics */
- rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data,
- 32);
+ rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC,
+ &private->rdc_data, 32);
if (rc) {
DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
"error %d for device: %s",
@@ -305,8 +305,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
datasize += (count - 1)*sizeof(struct LO_fba_data);
}
/* Allocate the ccw request. */
- cqr = dasd_smalloc_request(dasd_fba_discipline.name,
- cplength, datasize, memdev);
+ cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev);
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index b699ca356ac5..5e47a1ee52b9 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -59,6 +59,11 @@
#include <asm/dasd.h>
#include <asm/idals.h>
+/* DASD discipline magic */
+#define DASD_ECKD_MAGIC 0xC5C3D2C4
+#define DASD_DIAG_MAGIC 0xC4C9C1C7
+#define DASD_FBA_MAGIC 0xC6C2C140
+
/*
* SECTION: Type definitions
*/
@@ -540,9 +545,9 @@ extern struct block_device_operations dasd_device_operations;
extern struct kmem_cache *dasd_page_cache;
struct dasd_ccw_req *
-dasd_kmalloc_request(char *, int, int, struct dasd_device *);
+dasd_kmalloc_request(int , int, int, struct dasd_device *);
struct dasd_ccw_req *
-dasd_smalloc_request(char *, int, int, struct dasd_device *);
+dasd_smalloc_request(int , int, int, struct dasd_device *);
void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *);
void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *);
@@ -587,7 +592,7 @@ void dasd_generic_handle_state_change(struct dasd_device *);
int dasd_generic_pm_freeze(struct ccw_device *);
int dasd_generic_restore_device(struct ccw_device *);
-int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
+int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
char *dasd_get_sense(struct irb *);
/* externals in dasd_devmap.c */
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index df918ef27965..f756a1b0c57a 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -98,8 +98,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)
if (!capable (CAP_SYS_ADMIN))
return -EACCES;
- dev_info(&base->cdev->dev, "The DASD has been put in the quiesce "
- "state\n");
+ pr_info("%s: The DASD has been put in the quiesce "
+ "state\n", dev_name(&base->cdev->dev));
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
base->stopped |= DASD_STOPPED_QUIESCE;
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
@@ -119,8 +119,8 @@ static int dasd_ioctl_resume(struct dasd_block *block)
if (!capable (CAP_SYS_ADMIN))
return -EACCES;
- dev_info(&base->cdev->dev, "I/O operations have been resumed "
- "on the DASD\n");
+ pr_info("%s: I/O operations have been resumed "
+ "on the DASD\n", dev_name(&base->cdev->dev));
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
base->stopped &= ~DASD_STOPPED_QUIESCE;
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
@@ -146,8 +146,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
return -EPERM;
if (base->state != DASD_STATE_BASIC) {
- dev_warn(&base->cdev->dev,
- "The DASD cannot be formatted while it is enabled\n");
+ pr_warning("%s: The DASD cannot be formatted while it is "
+ "enabled\n", dev_name(&base->cdev->dev));
return -EBUSY;
}
@@ -175,9 +175,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
dasd_sfree_request(cqr, cqr->memdev);
if (rc) {
if (rc != -ERESTARTSYS)
- dev_err(&base->cdev->dev,
- "Formatting unit %d failed with "
- "rc=%d\n", fdata->start_unit, rc);
+ pr_err("%s: Formatting unit %d failed with "
+ "rc=%d\n", dev_name(&base->cdev->dev),
+ fdata->start_unit, rc);
return rc;
}
fdata->start_unit++;
@@ -204,9 +204,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
return -EFAULT;
if (bdev != bdev->bd_contains) {
- dev_warn(&block->base->cdev->dev,
- "The specified DASD is a partition and cannot be "
- "formatted\n");
+ pr_warning("%s: The specified DASD is a partition and cannot "
+ "be formatted\n",
+ dev_name(&block->base->cdev->dev));
return -EINVAL;
}
return dasd_format(block, &fdata);
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 3234e90bd7f9..89ece1c235aa 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -581,7 +581,7 @@ static int __init mon_init(void)
monreader_device->release = (void (*)(struct device *))kfree;
rc = device_register(monreader_device);
if (rc) {
- kfree(monreader_device);
+ put_device(monreader_device);
goto out_driver;
}
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 1a9420ba518d..750354ad16e5 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -68,7 +68,7 @@ tape_std_assign(struct tape_device *device)
* to another host (actually this shouldn't happen but it does).
* So we set up a timeout for this call.
*/
- init_timer(&timeout);
+ init_timer_on_stack(&timeout);
timeout.function = tape_std_assign_timeout;
timeout.data = (unsigned long) request;
timeout.expires = jiffies + 2 * HZ;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c20a4fe6da51..d1a142fa3eb4 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -765,8 +765,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
} else
return -ENOMEM;
ret = device_register(dev);
- if (ret)
+ if (ret) {
+ put_device(dev);
return ret;
+ }
ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group);
if (ret) {
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index adb3dd301528..fa4c9662f65e 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,7 +2,7 @@
# Makefile for the S/390 common i/o drivers
#
-obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
+obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
fcx.o itcw.o crw.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 3e5f304ad88f..40002830d48a 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -417,7 +417,8 @@ int chp_new(struct chp_id chpid)
if (ret) {
CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",
chpid.cssid, chpid.id, ret);
- goto out_free;
+ put_device(&chp->dev);
+ goto out;
}
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
if (ret) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 425e8f89a6c5..37aa611d4ac5 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -37,29 +37,6 @@ struct channel_path_desc {
struct channel_path;
-struct css_general_char {
- u64 : 12;
- u32 dynio : 1; /* bit 12 */
- u32 : 28;
- u32 aif : 1; /* bit 41 */
- u32 : 3;
- u32 mcss : 1; /* bit 45 */
- u32 fcs : 1; /* bit 46 */
- u32 : 1;
- u32 ext_mb : 1; /* bit 48 */
- u32 : 7;
- u32 aif_tdd : 1; /* bit 56 */
- u32 : 1;
- u32 qebsm : 1; /* bit 58 */
- u32 : 8;
- u32 aif_osa : 1; /* bit 67 */
- u32 : 14;
- u32 cib : 1; /* bit 82 */
- u32 : 5;
- u32 fcx : 1; /* bit 88 */
- u32 : 7;
-}__attribute__((packed));
-
struct css_chsc_char {
u64 res;
u64 : 20;
@@ -72,7 +49,6 @@ struct css_chsc_char {
u32 : 19;
}__attribute__((packed));
-extern struct css_general_char css_general_characteristics;
extern struct css_chsc_char css_chsc_characteristics;
struct chsc_ssd_info {
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 85d43c6bcb66..de571b276649 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -152,24 +152,15 @@ css_alloc_subchannel(struct subchannel_id schid)
}
static void
-css_free_subchannel(struct subchannel *sch)
-{
- if (sch) {
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
- kfree(sch->lock);
- kfree(sch);
- }
-}
-
-static void
css_subchannel_release(struct device *dev)
{
struct subchannel *sch;
sch = to_subchannel(dev);
if (!cio_is_console(sch->schid)) {
+ /* Reset intparm to zeroes. */
+ sch->config.intparm = 0;
+ cio_commit_config(sch);
kfree(sch->lock);
kfree(sch);
}
@@ -327,7 +318,7 @@ int css_probe_device(struct subchannel_id schid)
return PTR_ERR(sch);
ret = css_register_subchannel(sch);
if (ret)
- css_free_subchannel(sch);
+ put_device(&sch->dev);
return ret;
}
@@ -644,7 +635,10 @@ __init_channel_subsystem(struct subchannel_id schid, void *data)
* not working) so we do it now. This is true e.g. for the
* console subchannel.
*/
- css_register_subchannel(sch);
+ if (css_register_subchannel(sch)) {
+ if (!cio_is_console(schid))
+ put_device(&sch->dev);
+ }
return 0;
}
@@ -920,8 +914,10 @@ init_channel_subsystem (void)
goto out_device;
}
ret = device_register(&css->pseudo_subchannel->dev);
- if (ret)
+ if (ret) {
+ put_device(&css->pseudo_subchannel->dev);
goto out_file;
+ }
}
ret = register_reboot_notifier(&css_reboot_notifier);
if (ret)
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 3c57c1a18bb8..007f8538695c 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1026,9 +1026,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
return;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
/* Release cdev reference for workqueue processing.*/
put_device(&cdev->dev);
/* Release subchannel reference for local processing. */
@@ -1212,9 +1209,6 @@ static void io_subchannel_do_unreg(struct work_struct *work)
sch = container_of(work, struct subchannel, work);
css_sch_device_unregister(sch);
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
put_device(&sch->dev);
}
@@ -1690,10 +1684,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow)
spin_unlock_irqrestore(sch->lock, flags);
css_sch_device_unregister(sch);
spin_lock_irqsave(sch->lock, flags);
-
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
break;
case REPROBE:
ccw_device_trigger_reprobe(cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 3db88c52d287..b8bdb0d75426 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -731,6 +731,17 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev,
}
/*
+ * Handle path verification event in offline state.
+ */
+static void ccw_device_offline_verify(struct ccw_device *cdev,
+ enum dev_event dev_event)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ css_schedule_eval(sch->schid);
+}
+
+/*
* Handle path verification event.
*/
static void
@@ -1149,7 +1160,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
- [DEV_EVENT_VERIFY] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_offline_verify,
},
[DEV_STATE_VERIFY] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index b1241f8fae88..ff7748a9199d 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -1,7 +1,7 @@
/*
* linux/drivers/s390/cio/qdio.h
*
- * Copyright 2000,2008 IBM Corp.
+ * Copyright 2000,2009 IBM Corp.
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Jan Glauber <jang@linux.vnet.ibm.com>
*/
@@ -246,6 +246,7 @@ struct qdio_q {
atomic_t nr_buf_used;
struct qdio_irq *irq_ptr;
+ struct dentry *debugfs_q;
struct tasklet_struct tasklet;
/* error condition during a data transfer */
@@ -267,6 +268,7 @@ struct qdio_irq {
struct qib qib;
u32 *dsci; /* address of device state change indicator */
struct ccw_device *cdev;
+ struct dentry *debugfs_dev;
unsigned long int_parm;
struct subchannel_id schid;
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index b8626d4df116..1b78f639ead3 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -1,14 +1,12 @@
/*
* drivers/s390/cio/qdio_debug.c
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* Author: Jan Glauber (jang@linux.vnet.ibm.com)
*/
-#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
-#include <asm/qdio.h>
#include <asm/debug.h>
#include "qdio_debug.h"
#include "qdio.h"
@@ -17,10 +15,7 @@ debug_info_t *qdio_dbf_setup;
debug_info_t *qdio_dbf_error;
static struct dentry *debugfs_root;
-#define MAX_DEBUGFS_QUEUES 32
-static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL };
-static DEFINE_MUTEX(debugfs_mutex);
-#define QDIO_DEBUGFS_NAME_LEN 40
+#define QDIO_DEBUGFS_NAME_LEN 10
void qdio_allocate_dbf(struct qdio_initialize *init_data,
struct qdio_irq *irq_ptr)
@@ -130,20 +125,6 @@ static int qstat_seq_open(struct inode *inode, struct file *filp)
filp->f_path.dentry->d_inode->i_private);
}
-static void remove_debugfs_entry(struct qdio_q *q)
-{
- int i;
-
- for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) {
- if (!debugfs_queues[i])
- continue;
- if (debugfs_queues[i]->d_inode->i_private == q) {
- debugfs_remove(debugfs_queues[i]);
- debugfs_queues[i] = NULL;
- }
- }
-}
-
static struct file_operations debugfs_fops = {
.owner = THIS_MODULE,
.open = qstat_seq_open,
@@ -155,22 +136,15 @@ static struct file_operations debugfs_fops = {
static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
{
- int i = 0;
char name[QDIO_DEBUGFS_NAME_LEN];
- while (debugfs_queues[i] != NULL) {
- i++;
- if (i >= MAX_DEBUGFS_QUEUES)
- return;
- }
- snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d",
- dev_name(&cdev->dev),
+ snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
q->is_input_q ? "input" : "output",
q->nr);
- debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
- debugfs_root, q, &debugfs_fops);
- if (IS_ERR(debugfs_queues[i]))
- debugfs_queues[i] = NULL;
+ q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
+ q->irq_ptr->debugfs_dev, q, &debugfs_fops);
+ if (IS_ERR(q->debugfs_q))
+ q->debugfs_q = NULL;
}
void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
@@ -178,12 +152,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
struct qdio_q *q;
int i;
- mutex_lock(&debugfs_mutex);
+ irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
+ debugfs_root);
+ if (IS_ERR(irq_ptr->debugfs_dev))
+ irq_ptr->debugfs_dev = NULL;
for_each_input_queue(irq_ptr, q, i)
setup_debugfs_entry(q, cdev);
for_each_output_queue(irq_ptr, q, i)
setup_debugfs_entry(q, cdev);
- mutex_unlock(&debugfs_mutex);
}
void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
@@ -191,17 +167,16 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd
struct qdio_q *q;
int i;
- mutex_lock(&debugfs_mutex);
for_each_input_queue(irq_ptr, q, i)
- remove_debugfs_entry(q);
+ debugfs_remove(q->debugfs_q);
for_each_output_queue(irq_ptr, q, i)
- remove_debugfs_entry(q);
- mutex_unlock(&debugfs_mutex);
+ debugfs_remove(q->debugfs_q);
+ debugfs_remove(irq_ptr->debugfs_dev);
}
int __init qdio_debug_init(void)
{
- debugfs_root = debugfs_create_dir("qdio_queues", NULL);
+ debugfs_root = debugfs_create_dir("qdio", NULL);
qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 0038750ad945..9aef402a5f1b 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -798,8 +798,10 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
if (!qdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
- if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
+ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
tasklet_schedule(&q->tasklet);
+ return;
+ }
}
qdio_stop_polling(q);
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 727a809636d8..ae9ab240c7f1 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1114,7 +1114,7 @@ static void ap_scan_bus(struct work_struct *unused)
ap_dev->device.release = ap_device_release;
rc = device_register(&ap_dev->device);
if (rc) {
- kfree(ap_dev);
+ put_device(&ap_dev->device);
continue;
}
/* Add device attributes. */
@@ -1145,12 +1145,17 @@ ap_config_timeout(unsigned long ptr)
*/
static inline void ap_schedule_poll_timer(void)
{
+ ktime_t hr_time;
if (ap_using_interrupts() || ap_suspend_flag)
return;
if (hrtimer_is_queued(&ap_poll_timer))
return;
- hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout),
- HRTIMER_MODE_ABS);
+ if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
+ hr_time = ktime_set(0, poll_timeout);
+ hrtimer_forward_now(&ap_poll_timer, hr_time);
+ hrtimer_restart(&ap_poll_timer);
+ }
+ return;
}
/**
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index f370f8d460a7..c63babefb698 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev)
CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc);
if (rc)
rc = NETDEV_TX_BUSY;
+ else
+ rc = NETDEV_TX_OK;
return rc;
} /* end of claw_tx */
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 222e47394437..38b5079f1599 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
"%s(%s): NULL sk_buff passed",
CTCM_FUNTAIL, dev->name);
priv->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
@@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2);
dev_kfree_skb(skb);
priv->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_dropped++;
priv->stats.tx_errors++;
priv->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (ctcm_test_and_set_busy(dev))
@@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0)
return NETDEV_TX_BUSY;
- return 0;
+ return NETDEV_TX_OK;
}
/* unmerged MPC variant of ctcm_tx */
@@ -1008,7 +1008,7 @@ done:
if (do_debug)
MPC_DBF_DEV_NAME(TRACE, dev, "exit");
- return 0; /* handle freeing of skb here */
+ return NETDEV_TX_OK; /* handle freeing of skb here */
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 8c675905448b..a70de9b4bf29 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
struct net_device *dev)
{
struct lcs_header *header;
- int rc = 0;
+ int rc = NETDEV_TX_OK;
LCS_DBF_TEXT(5, trace, "hardxmit");
if (skb == NULL) {
card->stats.tx_dropped++;
card->stats.tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (card->state != DEV_STATE_UP) {
dev_kfree_skb(skb);
card->stats.tx_dropped++;
card->stats.tx_errors++;
card->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->protocol == htons(ETH_P_IPV6)) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(card->dev);
spin_lock(&card->lock);
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 8c36eafcfbfe..3a1b3b1eed51 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");
privptr->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_headroom(skb) < NETIUCV_HDRLEN) {
IUCV_DBF_TEXT(data, 2,
"netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/**
@@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
privptr->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (netiucv_test_and_set_busy(dev)) {
@@ -2226,8 +2226,10 @@ static int __init netiucv_init(void)
netiucv_dev->release = (void (*)(struct device *))kfree;
netiucv_dev->driver = &netiucv_driver;
rc = device_register(netiucv_dev);
- if (rc)
+ if (rc) {
+ put_device(netiucv_dev);
goto out_driver;
+ }
netiucv_banner();
return rc;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 691cecd03b83..2cfc338c4625 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->stats.tx_bytes += tx_bytes;
if (new_skb != skb)
dev_kfree_skb_any(skb);
+ rc = NETDEV_TX_OK;
} else {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 54872406864e..048defaea81f 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.sg_frags_sent += nr_frags + 1;
}
}
+ rc = NETDEV_TX_OK;
} else {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index e76a320d373b..102000d1af6f 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -219,13 +219,13 @@ static int __init smsg_init(void)
smsg_dev->driver = &smsg_driver;
rc = device_register(smsg_dev);
if (rc)
- goto out_free_dev;
+ goto out_put;
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
return 0;
-out_free_dev:
- kfree(smsg_dev);
+out_put:
+ put_device(smsg_dev);
out_free_path:
iucv_path_free(smsg_path);
smsg_path = NULL;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 2ccbd185a5fb..84fd8cec7243 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -306,8 +306,10 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
}
read_unlock_irq(&zfcp_data.config_lock);
- if (device_register(&unit->sysfs_device))
- goto err_out_free;
+ if (device_register(&unit->sysfs_device)) {
+ put_device(&unit->sysfs_device);
+ return ERR_PTR(-EINVAL);
+ }
if (sysfs_create_group(&unit->sysfs_device.kobj,
&zfcp_sysfs_unit_attrs)) {
@@ -637,8 +639,10 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
}
read_unlock_irq(&zfcp_data.config_lock);
- if (device_register(&port->sysfs_device))
- goto err_out_free;
+ if (device_register(&port->sysfs_device)) {
+ put_device(&port->sysfs_device);
+ goto err_out;
+ }
retval = sysfs_create_group(&port->sysfs_device.kobj,
&zfcp_sysfs_port_attrs);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 8030e25152fb..c75d6f35cb5f 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -553,40 +553,35 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
_zfcp_erp_unit_reopen(unit, clear, id, ref);
}
-static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
+static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
{
- struct zfcp_adapter *adapter = act->adapter;
- struct zfcp_port *port = act->port;
- struct zfcp_unit *unit = act->unit;
- u32 status = act->status;
-
- /* initiate follow-up actions depending on success of finished action */
switch (act->action) {
-
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
+ _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
- else
- _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
+ _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_PORT:
- if (status == ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
- else
- _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
+ _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
break;
-
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (status != ZFCP_ERP_SUCCEEDED)
- _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
+ _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
+ break;
+ }
+}
+
+static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
+{
+ switch (act->action) {
+ case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+ _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+ _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+ break;
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
break;
}
}
@@ -801,7 +796,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
- if (status & ZFCP_STATUS_PORT_PHYS_OPEN)
+ if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
return ZFCP_ERP_SUCCEEDED;
}
return ZFCP_ERP_FAILED;
@@ -853,11 +848,17 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
gid_pn_work);
retval = zfcp_fc_ns_gid_pn(&port->erp_action);
- if (retval == -ENOMEM)
- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
- port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
- if (retval)
- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
+ if (!retval) {
+ port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
+ goto out;
+ }
+ if (retval == -ENOMEM) {
+ zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM);
+ goto out;
+ }
+ /* all other error condtions */
+ zfcp_erp_notify(&port->erp_action, 0);
+out:
zfcp_port_put(port);
}
@@ -1289,7 +1290,10 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
retval = zfcp_erp_strategy_statechange(erp_action, retval);
if (retval == ZFCP_ERP_EXIT)
goto unlock;
- zfcp_erp_strategy_followup_actions(erp_action);
+ if (retval == ZFCP_ERP_SUCCEEDED)
+ zfcp_erp_strategy_followup_success(erp_action);
+ if (retval == ZFCP_ERP_FAILED)
+ zfcp_erp_strategy_followup_failed(erp_action);
unlock:
write_unlock(&adapter->erp_lock);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 2f0705d76b72..47daebfa7e59 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -79,11 +79,9 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
mutex_unlock(&wka_port->mutex);
- wait_event_timeout(
- wka_port->completion_wq,
- wka_port->status == ZFCP_WKA_PORT_ONLINE ||
- wka_port->status == ZFCP_WKA_PORT_OFFLINE,
- HZ >> 1);
+ wait_event(wka_port->completion_wq,
+ wka_port->status == ZFCP_WKA_PORT_ONLINE ||
+ wka_port->status == ZFCP_WKA_PORT_OFFLINE);
if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
atomic_inc(&wka_port->refcount);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index c57658f3d34f..47795fbf081f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -670,8 +670,11 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
zfcp_fsf_sbal_check(adapter), 5 * HZ);
if (ret > 0)
return 0;
- if (!ret)
+ if (!ret) {
atomic_inc(&adapter->qdio_outb_full);
+ /* assume hanging outbound queue, try queue recovery */
+ zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
+ }
spin_lock_bh(&adapter->req_q_lock);
return -EIO;
@@ -722,7 +725,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
req = zfcp_fsf_alloc_qtcb(pool);
if (unlikely(!req))
- return ERR_PTR(-EIO);
+ return ERR_PTR(-ENOMEM);
if (adapter->req_no == 0)
adapter->req_no++;
@@ -1010,6 +1013,23 @@ skip_fsfstatus:
send_ct->handler(send_ct->handler_data);
}
+static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
+ struct scatterlist *sg_req,
+ struct scatterlist *sg_resp)
+{
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+ sbale[2].addr = sg_virt(sg_req);
+ sbale[2].length = sg_req->length;
+ sbale[3].addr = sg_virt(sg_resp);
+ sbale[3].length = sg_resp->length;
+ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+}
+
+static int zfcp_fsf_one_sbal(struct scatterlist *sg)
+{
+ return sg_is_last(sg) && sg->length <= PAGE_SIZE;
+}
+
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
@@ -1020,30 +1040,30 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
int bytes;
if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
- if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
- !sg_is_last(sg_req) || !sg_is_last(sg_resp))
+ if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
return -EOPNOTSUPP;
- sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
- sbale[2].addr = sg_virt(sg_req);
- sbale[2].length = sg_req->length;
- sbale[3].addr = sg_virt(sg_resp);
- sbale[3].length = sg_resp->length;
- sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+ return 0;
+ }
+
+ /* use single, unchained SBAL if it can hold the request */
+ if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
+ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
return 0;
}
bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_req, max_sbals);
if (bytes <= 0)
- return -ENOMEM;
+ return -EIO;
req->qtcb->bottom.support.req_buf_length = bytes;
req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_resp, max_sbals);
if (bytes <= 0)
- return -ENOMEM;
+ return -EIO;
req->qtcb->bottom.support.resp_buf_length = bytes;
return 0;
@@ -1607,10 +1627,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
case FSF_ACCESS_DENIED:
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
break;
- case FSF_PORT_ALREADY_OPEN:
- break;
case FSF_GOOD:
wka_port->handle = header->port_handle;
+ /* fall through */
+ case FSF_PORT_ALREADY_OPEN:
wka_port->status = ZFCP_WKA_PORT_ONLINE;
}
out:
@@ -1731,15 +1751,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
zfcp_fsf_access_denied_port(req, port);
break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(port, "fscpph2", req);
- req->status |= ZFCP_STATUS_FSFREQ_ERROR |
- ZFCP_STATUS_FSFREQ_RETRY;
/* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
list_for_each_entry(unit, &port->unit_list_head, list)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status);
+ zfcp_erp_port_boxed(port, "fscpph2", req);
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR |
+ ZFCP_STATUS_FSFREQ_RETRY;
+
break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]) {
@@ -2541,7 +2562,6 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
FSF_MAX_SBALS_PER_REQ);
if (bytes != ZFCP_CFDC_MAX_SIZE) {
- retval = -ENOMEM;
zfcp_fsf_req_free(req);
goto out;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 967ede73f4c5..6925a1784682 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -167,20 +167,21 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags;
- unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
+ unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS;
int retry = 3;
+ char *dbf_tag;
/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
spin_lock(&adapter->req_list_lock);
- old_req = zfcp_reqlist_find(adapter, old_req_id);
+ old_req = zfcp_reqlist_find(adapter, old_reqid);
spin_unlock(&adapter->req_list_lock);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
- old_req_id);
+ old_reqid);
return FAILED; /* completion could be in progress */
}
old_req->data = NULL;
@@ -189,7 +190,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
write_unlock_irqrestore(&adapter->abort_lock, flags);
while (retry--) {
- abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
+ abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
if (abrt_req)
break;
@@ -197,7 +198,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
- old_req_id);
+ old_reqid);
return SUCCESS;
}
}
@@ -208,13 +209,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
- zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "okay";
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
- zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "lte2";
else {
- zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
+ dbf_tag = "fail";
retval = FAILED;
}
+ zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid);
zfcp_fsf_req_free(abrt_req);
return retval;
}
@@ -534,6 +536,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
struct fc_rport_identifiers ids;
struct fc_rport *rport;
+ if (port->rport)
+ return;
+
ids.node_name = port->wwnn;
ids.port_name = port->wwpn;
ids.port_id = port->d_id;
@@ -557,8 +562,10 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
{
struct fc_rport *rport = port->rport;
- if (rport)
+ if (rport) {
fc_remote_port_delete(rport);
+ port->rport = NULL;
+ }
}
void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 3e51e64d1108..0fe5cce818cb 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -494,9 +494,14 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
struct Scsi_Host *scsi_host = class_to_shost(dev);
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
+ u64 util;
+
+ spin_lock_bh(&adapter->qdio_stat_lock);
+ util = adapter->req_q_util;
+ spin_unlock_bh(&adapter->qdio_stat_lock);
return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full),
- (unsigned long long)adapter->req_q_util);
+ (unsigned long long)util);
}
static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index ae4b2d588fd3..0c4210d48ee8 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -15,11 +15,10 @@
static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
-static int bnx2i_reg_device;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.0.1d"
-#define DRV_MODULE_RELDATE "Mar 25, 2009"
+#define DRV_MODULE_VERSION "2.0.1e"
+#define DRV_MODULE_RELDATE "June 22, 2009"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -31,7 +30,7 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
-static DEFINE_RWLOCK(bnx2i_dev_lock);
+static DEFINE_MUTEX(bnx2i_dev_lock);
unsigned int event_coal_div = 1;
module_param(event_coal_div, int, 0664);
@@ -100,14 +99,14 @@ struct bnx2i_hba *get_adapter_list_head(void)
if (!adapter_count)
goto hba_not_found;
- read_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
list_for_each_entry(tmp_hba, &adapter_list, link) {
if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) {
hba = tmp_hba;
break;
}
}
- read_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
hba_not_found:
return hba;
}
@@ -122,14 +121,14 @@ struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic)
{
struct bnx2i_hba *hba, *temp;
- read_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link) {
if (hba->cnic == cnic) {
- read_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
return hba;
}
}
- read_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
return NULL;
}
@@ -186,18 +185,17 @@ void bnx2i_stop(void *handle)
*/
void bnx2i_register_device(struct bnx2i_hba *hba)
{
+ int rc;
+
if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
return;
}
- hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
+ rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
- spin_lock(&hba->lock);
- bnx2i_reg_device++;
- spin_unlock(&hba->lock);
-
- set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+ if (!rc)
+ set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
}
@@ -211,10 +209,10 @@ void bnx2i_reg_dev_all(void)
{
struct bnx2i_hba *hba, *temp;
- read_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link)
bnx2i_register_device(hba);
- read_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
}
@@ -234,10 +232,6 @@ static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
- spin_lock(&hba->lock);
- bnx2i_reg_device--;
- spin_unlock(&hba->lock);
-
/* ep_disconnect could come before NETDEV_DOWN, driver won't
* see NETDEV_DOWN as it already unregistered itself.
*/
@@ -255,10 +249,10 @@ void bnx2i_unreg_dev_all(void)
{
struct bnx2i_hba *hba, *temp;
- read_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link)
bnx2i_unreg_one_device(hba);
- read_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
}
@@ -267,35 +261,34 @@ void bnx2i_unreg_dev_all(void)
* @hba: bnx2i adapter instance
* @cnic: cnic device handle
*
- * Global resource lock and host adapter lock is held during critical sections
- * below. This routine is called from cnic_register_driver() context and
- * work horse thread which does majority of device specific initialization
+ * Global resource lock is held during critical sections below. This routine is
+ * called from either cnic_register_driver() or device hot plug context and
+ * and does majority of device specific initialization
*/
static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
{
int rc;
- read_lock(&bnx2i_dev_lock);
- if (bnx2i_reg_device &&
- !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
- if (rc) /* duplicate registration */
- printk(KERN_ERR "bnx2i- dev reg failed\n");
-
- spin_lock(&hba->lock);
- bnx2i_reg_device++;
+ mutex_lock(&bnx2i_dev_lock);
+ rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
+ if (!rc) {
hba->age++;
- spin_unlock(&hba->lock);
-
set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
- }
- read_unlock(&bnx2i_dev_lock);
-
- write_lock(&bnx2i_dev_lock);
- list_add_tail(&hba->link, &adapter_list);
- adapter_count++;
- write_unlock(&bnx2i_dev_lock);
- return 0;
+ list_add_tail(&hba->link, &adapter_list);
+ adapter_count++;
+ } else if (rc == -EBUSY) /* duplicate registration */
+ printk(KERN_ALERT "bnx2i, duplicate registration"
+ "hba=%p, cnic=%p\n", hba, cnic);
+ else if (rc == -EAGAIN)
+ printk(KERN_ERR "bnx2i, driver not registered\n");
+ else if (rc == -EINVAL)
+ printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI);
+ else
+ printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
+
+ mutex_unlock(&bnx2i_dev_lock);
+
+ return rc;
}
@@ -343,19 +336,15 @@ void bnx2i_ulp_exit(struct cnic_dev *dev)
"found, dev 0x%p\n", dev);
return;
}
- write_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
list_del_init(&hba->link);
adapter_count--;
if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-
- spin_lock(&hba->lock);
- bnx2i_reg_device--;
- spin_unlock(&hba->lock);
}
- write_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
bnx2i_free_hba(hba);
}
@@ -377,6 +366,8 @@ static int __init bnx2i_mod_init(void)
if (!is_power_of_2(sq_size))
sq_size = roundup_pow_of_two(sq_size);
+ mutex_init(&bnx2i_dev_lock);
+
bnx2i_scsi_xport_template =
iscsi_register_transport(&bnx2i_iscsi_transport);
if (!bnx2i_scsi_xport_template) {
@@ -412,7 +403,7 @@ static void __exit bnx2i_mod_exit(void)
{
struct bnx2i_hba *hba;
- write_lock(&bnx2i_dev_lock);
+ mutex_lock(&bnx2i_dev_lock);
while (!list_empty(&adapter_list)) {
hba = list_entry(adapter_list.next, struct bnx2i_hba, link);
list_del(&hba->link);
@@ -421,14 +412,11 @@ static void __exit bnx2i_mod_exit(void)
if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
- bnx2i_reg_device--;
}
- write_unlock(&bnx2i_dev_lock);
bnx2i_free_hba(hba);
- write_lock(&bnx2i_dev_lock);
}
- write_unlock(&bnx2i_dev_lock);
+ mutex_unlock(&bnx2i_dev_lock);
iscsi_unregister_transport(&bnx2i_iscsi_transport);
cnic_unregister_driver(CNIC_ULP_ISCSI);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index f7412196f2f8..98148f3f3c63 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1653,15 +1653,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
struct iscsi_endpoint *ep;
int rc = 0;
- if (shost)
+ if (shost) {
/* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
- else
+ /* Register the device with cnic if not already done so */
+ bnx2i_register_device(hba);
+ } else
/*
* check if the given destination can be reached through
* a iscsi capable NetXtreme2 device
*/
hba = bnx2i_check_route(dst_addr);
+
if (!hba) {
rc = -ENOMEM;
goto check_busy;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index e79e18101f87..63abb06c4edb 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -4,8 +4,7 @@
* Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
- * Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
- * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702
+ * Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624
*/
#include <linux/blkdev.h>
@@ -56,9 +55,9 @@ static const char * cdb_byte0_names[] = {
"Read Buffer",
/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
/* 40-41 */ "Change Definition", "Write Same(10)",
-/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
- "Play audio(10)", "Get configuration", "Play audio msf",
- "Play audio track/index",
+/* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP",
+ "Read density support", "Play audio(10)", "Get configuration",
+ "Play audio msf", "Play audio track/index",
/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
@@ -71,12 +70,13 @@ static const char * cdb_byte0_names[] = {
/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
+/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB",
+ "Variable length",
/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
"Receive copy results",
/* 85-89 */ "ATA command pass through(16)", "Access control in",
"Access control out", "Read(16)", "Memory Export Out(16)",
-/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes",
+/* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes",
"Write and verify(16)", "Verify(16)",
/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
"Lock/unlock cache(16)", "Write same(16)", NULL,
@@ -107,22 +107,24 @@ struct value_name_pair {
};
static const struct value_name_pair maint_in_arr[] = {
- {0x5, "Report device identifier"},
+ {0x5, "Report identifying information"},
{0xa, "Report target port groups"},
{0xb, "Report aliases"},
{0xc, "Report supported operation codes"},
{0xd, "Report supported task management functions"},
{0xe, "Report priority"},
{0xf, "Report timestamp"},
+ {0x10, "Management protocol in"},
};
#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
static const struct value_name_pair maint_out_arr[] = {
- {0x6, "Set device identifier"},
+ {0x6, "Set identifying information"},
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
{0xe, "Set priority"},
- {0xe, "Set timestamp"},
+ {0xf, "Set timestamp"},
+ {0x10, "Management protocol out"},
};
#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
@@ -412,6 +414,7 @@ static const struct error_info additional[] =
{0x0004, "Beginning-of-partition/medium detected"},
{0x0005, "End-of-data detected"},
{0x0006, "I/O process terminated"},
+ {0x0007, "Programmable early warning detected"},
{0x0011, "Audio play operation in progress"},
{0x0012, "Audio play operation paused"},
{0x0013, "Audio play operation successfully completed"},
@@ -425,6 +428,7 @@ static const struct error_info additional[] =
{0x001B, "Set capacity operation in progress"},
{0x001C, "Verify operation in progress"},
{0x001D, "ATA pass through information available"},
+ {0x001E, "Conflicting SA creation request"},
{0x0100, "No index/sector signal"},
@@ -449,9 +453,12 @@ static const struct error_info additional[] =
{0x040B, "Logical unit not accessible, target port in standby state"},
{0x040C, "Logical unit not accessible, target port in unavailable "
"state"},
+ {0x040D, "Logical unit not ready, structure check required"},
{0x0410, "Logical unit not ready, auxiliary memory not accessible"},
{0x0411, "Logical unit not ready, notify (enable spinup) required"},
{0x0412, "Logical unit not ready, offline"},
+ {0x0413, "Logical unit not ready, SA creation in progress"},
+ {0x0414, "Logical unit not ready, space allocation in progress"},
{0x0500, "Logical unit does not respond to selection"},
@@ -479,6 +486,9 @@ static const struct error_info additional[] =
{0x0B03, "Warning - background self-test failed"},
{0x0B04, "Warning - background pre-scan detected medium error"},
{0x0B05, "Warning - background medium scan detected medium error"},
+ {0x0B06, "Warning - non-volatile cache now volatile"},
+ {0x0B07, "Warning - degraded power to non-volatile cache"},
+ {0x0B08, "Warning - power loss expected"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@@ -593,6 +603,7 @@ static const struct error_info additional[] =
{0x1C02, "Grown defect list not found"},
{0x1D00, "Miscompare during verify operation"},
+ {0x1D01, "Miscompare verify of unmapped LBA"},
{0x1E00, "Recovered id with ECC correction"},
@@ -626,6 +637,7 @@ static const struct error_info additional[] =
{0x2405, "Security working key frozen"},
{0x2406, "Nonce not unique"},
{0x2407, "Nonce timestamp out of range"},
+ {0x2408, "Invalid XCDB"},
{0x2500, "Logical unit not supported"},
@@ -656,10 +668,12 @@ static const struct error_info additional[] =
{0x2704, "Persistent write protect"},
{0x2705, "Permanent write protect"},
{0x2706, "Conditional write protect"},
+ {0x2707, "Space allocation failed write protect"},
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
{0x2802, "Format-layer may have changed"},
+ {0x2803, "Import/export element accessed, medium changed"},
{0x2900, "Power on, reset, or bus device reset occurred"},
{0x2901, "Power on occurred"},
@@ -680,11 +694,16 @@ static const struct error_info additional[] =
{0x2A07, "Implicit asymmetric access state transition failed"},
{0x2A08, "Priority changed"},
{0x2A09, "Capacity data has changed"},
+ {0x2A0A, "Error history I_T nexus cleared"},
+ {0x2A0B, "Error history snapshot released"},
+ {0x2A0C, "Error recovery attributes have changed"},
+ {0x2A0D, "Data encryption capabilities changed"},
{0x2A10, "Timestamp changed"},
{0x2A11, "Data encryption parameters changed by another i_t nexus"},
{0x2A12, "Data encryption parameters changed by vendor specific "
"event"},
{0x2A13, "Data encryption key instance counter has changed"},
+ {0x2A14, "SA creation capabilities data has changed"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@@ -723,6 +742,8 @@ static const struct error_info additional[] =
{0x300C, "WORM medium - overwrite attempted"},
{0x300D, "WORM medium - integrity check"},
{0x3010, "Medium not formatted"},
+ {0x3011, "Incompatible volume type"},
+ {0x3012, "Incompatible volume qualifier"},
{0x3100, "Medium format corrupted"},
{0x3101, "Format command failed"},
@@ -782,6 +803,10 @@ static const struct error_info additional[] =
{0x3B15, "Medium magazine unlocked"},
{0x3B16, "Mechanical positioning or changer error"},
{0x3B17, "Read past end of user object"},
+ {0x3B18, "Element disabled"},
+ {0x3B19, "Element enabled"},
+ {0x3B1A, "Data transfer device removed"},
+ {0x3B1B, "Data transfer device inserted"},
{0x3D00, "Invalid bits in identify message"},
@@ -882,6 +907,8 @@ static const struct error_info additional[] =
{0x5506, "Auxiliary memory out of space"},
{0x5507, "Quota error"},
{0x5508, "Maximum number of supplemental decryption keys exceeded"},
+ {0x5509, "Medium auxiliary memory not accessible"},
+ {0x550A, "Data currently unavailable"},
{0x5700, "Unable to recover table-of-contents"},
@@ -993,6 +1020,12 @@ static const struct error_info additional[] =
{0x5E02, "Standby condition activated by timer"},
{0x5E03, "Idle condition activated by command"},
{0x5E04, "Standby condition activated by command"},
+ {0x5E05, "Idle_b condition activated by timer"},
+ {0x5E06, "Idle_b condition activated by command"},
+ {0x5E07, "Idle_c condition activated by timer"},
+ {0x5E08, "Idle_c condition activated by command"},
+ {0x5E09, "Standby_y condition activated by timer"},
+ {0x5E0A, "Standby_y condition activated by command"},
{0x5E41, "Power state change to active"},
{0x5E42, "Power state change to idle"},
{0x5E43, "Power state change to standby"},
@@ -1091,7 +1124,28 @@ static const struct error_info additional[] =
{0x7403, "Incorrect data encryption key"},
{0x7404, "Cryptographic integrity validation failed"},
{0x7405, "Error decrypting data"},
+ {0x7406, "Unknown signature verification key"},
+ {0x7407, "Encryption parameters not useable"},
+ {0x7408, "Digital signature validation failure"},
+ {0x7409, "Encryption mode mismatch on read"},
+ {0x740A, "Encrypted block not raw read enabled"},
+ {0x740B, "Incorrect Encryption parameters"},
+ {0x740C, "Unable to decrypt parameter list"},
+ {0x740D, "Encryption algorithm disabled"},
+ {0x7410, "SA creation parameter value invalid"},
+ {0x7411, "SA creation parameter value rejected"},
+ {0x7412, "Invalid SA usage"},
+ {0x7421, "Data Encryption configuration prevented"},
+ {0x7430, "SA creation parameter not supported"},
+ {0x7440, "Authentication failed"},
+ {0x7461, "External data encryption key manager access error"},
+ {0x7462, "External data encryption key manager error"},
+ {0x7463, "External data encryption key not found"},
+ {0x7464, "External data encryption request not authorized"},
+ {0x746E, "External data encryption control timeout"},
+ {0x746F, "External data encryption control error"},
{0x7471, "Logical unit access not authorized"},
+ {0x7479, "Security conflict in translated device"},
{0, NULL}
};
@@ -1103,12 +1157,12 @@ struct error_info2 {
static const struct error_info2 additional2[] =
{
- {0x40,0x00,0x7f,"Ram failure (%x)"},
- {0x40,0x80,0xff,"Diagnostic failure on component (%x)"},
- {0x41,0x00,0xff,"Data path failure (%x)"},
- {0x42,0x00,0xff,"Power-on or self-test failure (%x)"},
- {0x4D,0x00,0xff,"Tagged overlapped commands (queue tag %x)"},
- {0x70,0x00,0xff,"Decompression exception short algorithm id of %x"},
+ {0x40, 0x00, 0x7f, "Ram failure (%x)"},
+ {0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"},
+ {0x41, 0x00, 0xff, "Data path failure (%x)"},
+ {0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"},
+ {0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"},
+ {0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"},
{0, 0, 0, NULL}
};
@@ -1157,14 +1211,15 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
int i;
unsigned short code = ((asc << 8) | ascq);
- for (i=0; additional[i].text; i++)
+ for (i = 0; additional[i].text; i++)
if (additional[i].code12 == code)
return additional[i].text;
- for (i=0; additional2[i].fmt; i++)
+ for (i = 0; additional2[i].fmt; i++) {
if (additional2[i].code1 == asc &&
- additional2[i].code2_min >= ascq &&
- additional2[i].code2_max <= ascq)
+ ascq >= additional2[i].code2_min &&
+ ascq <= additional2[i].code2_max)
return additional2[i].fmt;
+ }
#endif
return NULL;
}
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index a518f2eff19a..53a7385e1b4d 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
if (sdev->scsi_dh_data) {
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
err = -EBUSY;
- } else if (scsi_dh->attach)
+ else
+ kref_get(&sdev->scsi_dh_data->kref);
+ } else if (scsi_dh->attach) {
err = scsi_dh->attach(sdev);
-
+ if (!err) {
+ kref_init(&sdev->scsi_dh_data->kref);
+ sdev->scsi_dh_data->sdev = sdev;
+ }
+ }
return err;
}
+static void __detach_handler (struct kref *kref)
+{
+ struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
+ scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
+}
+
/*
* scsi_dh_handler_detach - Detach a device handler from a device
* @sdev - SCSI device the device handler should be detached from
@@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (scsi_dh && scsi_dh->detach)
- scsi_dh->detach(sdev);
+ kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
}
/*
@@ -474,7 +486,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
if (!err) {
err = scsi_dh_handler_attach(sdev, scsi_dh);
-
put_device(&sdev->sdev_gendev);
}
return err;
@@ -505,10 +516,8 @@ void scsi_dh_detach(struct request_queue *q)
return;
if (sdev->scsi_dh_data) {
- /* if sdev is not on internal list, detach */
scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (!device_handler_match(scsi_dh, sdev))
- scsi_dh_handler_detach(sdev, scsi_dh);
+ scsi_dh_handler_detach(sdev, scsi_dh);
}
put_device(&sdev->sdev_gendev);
}
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index dba154c8ff64..b5cdefaf2608 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev)
goto out;
}
- if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
+ if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
out:
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index f544340d318b..d6ed3f8255ad 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -1104,7 +1104,6 @@ static void fcoe_ctlr_timeout(unsigned long arg)
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
- DECLARE_MAC_BUF(buf);
u8 send_ctlr_ka;
u8 send_port_ka;
@@ -1128,9 +1127,8 @@ static void fcoe_ctlr_timeout(unsigned long arg)
fcf = sel; /* the old FCF may have been freed */
if (sel) {
printk(KERN_INFO "libfcoe: host%d: FIP selected "
- "Fibre-Channel Forwarder MAC %s\n",
- fip->lp->host->host_no,
- print_mac(buf, sel->fcf_mac));
+ "Fibre-Channel Forwarder MAC %pM\n",
+ fip->lp->host->host_no, sel->fcf_mac);
memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 2bc22be5f849..145ab9ba55ea 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -415,9 +415,9 @@ static void fc_exch_timeout(struct work_struct *work)
e_stat = ep->esb_stat;
if (e_stat & ESB_ST_COMPLETE) {
ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL;
+ spin_unlock_bh(&ep->ex_lock);
if (e_stat & ESB_ST_REC_QUAL)
fc_exch_rrq(ep);
- spin_unlock_bh(&ep->ex_lock);
goto done;
} else {
resp = ep->resp;
@@ -1624,14 +1624,14 @@ static void fc_exch_rrq(struct fc_exch *ep)
struct fc_lport *lp;
struct fc_els_rrq *rrq;
struct fc_frame *fp;
- struct fc_seq *rrq_sp;
u32 did;
lp = ep->lp;
fp = fc_frame_alloc(lp, sizeof(*rrq));
if (!fp)
- return;
+ goto retry;
+
rrq = fc_frame_payload_get(fp, sizeof(*rrq));
memset(rrq, 0, sizeof(*rrq));
rrq->rrq_cmd = ELS_RRQ;
@@ -1647,13 +1647,20 @@ static void fc_exch_rrq(struct fc_exch *ep)
fc_host_port_id(lp->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
- rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep,
- lp->e_d_tov);
- if (!rrq_sp) {
- ep->esb_stat |= ESB_ST_REC_QUAL;
- fc_exch_timer_set_locked(ep, ep->r_a_tov);
+ if (fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, lp->e_d_tov))
+ return;
+
+retry:
+ spin_lock_bh(&ep->ex_lock);
+ if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) {
+ spin_unlock_bh(&ep->ex_lock);
+ /* drop hold for rec qual */
+ fc_exch_release(ep);
return;
}
+ ep->esb_stat |= ESB_ST_REC_QUAL;
+ fc_exch_timer_set_locked(ep, ep->r_a_tov);
+ spin_unlock_bh(&ep->ex_lock);
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 716cc344c5df..a751f6230c22 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1974,10 +1974,10 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* good and have never sent us a successful tmf response
* then sent more data for the cmd.
*/
- spin_lock(&session->lock);
+ spin_lock_bh(&session->lock);
fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
- spin_unlock(&session->lock);
+ spin_unlock_bh(&session->lock);
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 54fa1e42dc4d..b3381959acce 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -766,6 +766,7 @@ static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr,
SAS_ADDR_SIZE) && ephy->port) {
sas_port_add_phy(ephy->port, phy->phy);
+ phy->port = ephy->port;
phy->phy_state = PHY_DEVICE_DISCOVERED;
return 0;
}
@@ -945,11 +946,21 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
if (ex->ex_phy[i].phy_state == PHY_VACANT ||
ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
continue;
-
+ /*
+ * Due to races, the phy might not get added to the
+ * wide port, so we add the phy to the wide port here.
+ */
if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
- SAS_ADDR(child->sas_addr))
+ SAS_ADDR(child->sas_addr)) {
ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+ res = sas_ex_join_wide_port(dev, i);
+ if (!res)
+ SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+ i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
+
+ }
}
+ res = 0;
}
return res;
@@ -1598,7 +1609,7 @@ static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
}
static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
- int from_phy)
+ int from_phy, bool update)
{
struct expander_device *ex = &dev->ex_dev;
int res = 0;
@@ -1611,7 +1622,9 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
if (res)
goto out;
else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
- ex->ex_phy[i].phy_change_count = phy_change_count;
+ if (update)
+ ex->ex_phy[i].phy_change_count =
+ phy_change_count;
*phy_id = i;
return 0;
}
@@ -1653,31 +1666,52 @@ out:
kfree(rg_req);
return res;
}
+/**
+ * sas_find_bcast_dev - find the device issue BROADCAST(CHANGE).
+ * @dev:domain device to be detect.
+ * @src_dev: the device which originated BROADCAST(CHANGE).
+ *
+ * Add self-configuration expander suport. Suppose two expander cascading,
+ * when the first level expander is self-configuring, hotplug the disks in
+ * second level expander, BROADCAST(CHANGE) will not only be originated
+ * in the second level expander, but also be originated in the first level
+ * expander (see SAS protocol SAS 2r-14, 7.11 for detail), it is to say,
+ * expander changed count in two level expanders will all increment at least
+ * once, but the phy which chang count has changed is the source device which
+ * we concerned.
+ */
static int sas_find_bcast_dev(struct domain_device *dev,
struct domain_device **src_dev)
{
struct expander_device *ex = &dev->ex_dev;
int ex_change_count = -1;
+ int phy_id = -1;
int res;
+ struct domain_device *ch;
res = sas_get_ex_change_count(dev, &ex_change_count);
if (res)
goto out;
- if (ex_change_count != -1 &&
- ex_change_count != ex->ex_change_count) {
- *src_dev = dev;
- ex->ex_change_count = ex_change_count;
- } else {
- struct domain_device *ch;
-
- list_for_each_entry(ch, &ex->children, siblings) {
- if (ch->dev_type == EDGE_DEV ||
- ch->dev_type == FANOUT_DEV) {
- res = sas_find_bcast_dev(ch, src_dev);
- if (src_dev)
- return res;
- }
+ if (ex_change_count != -1 && ex_change_count != ex->ex_change_count) {
+ /* Just detect if this expander phys phy change count changed,
+ * in order to determine if this expander originate BROADCAST,
+ * and do not update phy change count field in our structure.
+ */
+ res = sas_find_bcast_phy(dev, &phy_id, 0, false);
+ if (phy_id != -1) {
+ *src_dev = dev;
+ ex->ex_change_count = ex_change_count;
+ SAS_DPRINTK("Expander phy change count has changed\n");
+ return res;
+ } else
+ SAS_DPRINTK("Expander phys DID NOT change\n");
+ }
+ list_for_each_entry(ch, &ex->children, siblings) {
+ if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
+ res = sas_find_bcast_dev(ch, src_dev);
+ if (src_dev)
+ return res;
}
}
out:
@@ -1700,24 +1734,26 @@ static void sas_unregister_ex_tree(struct domain_device *dev)
}
static void sas_unregister_devs_sas_addr(struct domain_device *parent,
- int phy_id)
+ int phy_id, bool last)
{
struct expander_device *ex_dev = &parent->ex_dev;
struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
struct domain_device *child, *n;
-
- list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
- if (SAS_ADDR(child->sas_addr) ==
- SAS_ADDR(phy->attached_sas_addr)) {
- if (child->dev_type == EDGE_DEV ||
- child->dev_type == FANOUT_DEV)
- sas_unregister_ex_tree(child);
- else
- sas_unregister_dev(child);
- break;
+ if (last) {
+ list_for_each_entry_safe(child, n,
+ &ex_dev->children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ break;
+ }
}
+ sas_disable_routing(parent, phy->attached_sas_addr);
}
- sas_disable_routing(parent, phy->attached_sas_addr);
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
sas_port_delete_phy(phy->port, phy->phy);
if (phy->port->num_phys == 0)
@@ -1770,15 +1806,31 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
{
struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
struct domain_device *child;
- int res;
+ bool found = false;
+ int res, i;
SAS_DPRINTK("ex %016llx phy%d new device attached\n",
SAS_ADDR(dev->sas_addr), phy_id);
res = sas_ex_phy_discover(dev, phy_id);
if (res)
goto out;
+ /* to support the wide port inserted */
+ for (i = 0; i < dev->ex_dev.num_phys; i++) {
+ struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i];
+ if (i == phy_id)
+ continue;
+ if (SAS_ADDR(ex_phy_temp->attached_sas_addr) ==
+ SAS_ADDR(ex_phy->attached_sas_addr)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ sas_ex_join_wide_port(dev, phy_id);
+ return 0;
+ }
res = sas_ex_discover_devices(dev, phy_id);
- if (res)
+ if (!res)
goto out;
list_for_each_entry(child, &dev->ex_dev.children, siblings) {
if (SAS_ADDR(child->sas_addr) ==
@@ -1793,7 +1845,7 @@ out:
return res;
}
-static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
{
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id];
@@ -1804,11 +1856,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
switch (res) {
case SMP_RESP_NO_PHY:
phy->phy_state = PHY_NOT_PRESENT;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
goto out; break;
case SMP_RESP_PHY_VACANT:
phy->phy_state = PHY_VACANT;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
goto out; break;
case SMP_RESP_FUNC_ACC:
break;
@@ -1816,7 +1868,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
if (SAS_ADDR(attached_sas_addr) == 0) {
phy->phy_state = PHY_EMPTY;
- sas_unregister_devs_sas_addr(dev, phy_id);
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
} else if (SAS_ADDR(attached_sas_addr) ==
SAS_ADDR(phy->attached_sas_addr)) {
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
@@ -1828,12 +1880,27 @@ out:
return res;
}
+/**
+ * sas_rediscover - revalidate the domain.
+ * @dev:domain device to be detect.
+ * @phy_id: the phy id will be detected.
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.For plugging out, we un-register the device only when it is
+ * the last phy in the port, for other phys in this port, we just delete it
+ * from the port.For inserting, we do discovery when it is the
+ * first phy,for other phys in this port, we add it to the port to
+ * forming the wide-port.
+ */
static int sas_rediscover(struct domain_device *dev, const int phy_id)
{
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
int res = 0;
int i;
+ bool last = true; /* is this the last phy of the port */
SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
SAS_ADDR(dev->sas_addr), phy_id);
@@ -1848,13 +1915,13 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
SAS_ADDR(changed_phy->attached_sas_addr)) {
SAS_DPRINTK("phy%d part of wide port with "
"phy%d\n", phy_id, i);
- goto out;
+ last = false;
+ break;
}
}
- res = sas_rediscover_dev(dev, phy_id);
+ res = sas_rediscover_dev(dev, phy_id, last);
} else
res = sas_discover_new(dev, phy_id);
-out:
return res;
}
@@ -1881,7 +1948,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
do {
phy_id = -1;
- res = sas_find_bcast_phy(dev, &phy_id, i);
+ res = sas_find_bcast_phy(dev, &phy_id, i, true);
if (phy_id == -1)
break;
res = sas_rediscover(dev, phy_id);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index e6ac59c023f1..fe8b74c706d2 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -56,7 +56,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
}
}
- /* find a port */
+ /* see if the phy should be part of a wide port */
spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
for (i = 0; i < sas_ha->num_phys; i++) {
port = sas_ha->sas_port[i];
@@ -69,12 +69,23 @@ static void sas_form_port(struct asd_sas_phy *phy)
SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
port->id);
break;
- } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
- memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
- break;
}
spin_unlock(&port->phy_list_lock);
}
+ /* The phy does not match any existing port, create a new one */
+ if (i == sas_ha->num_phys) {
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ port = sas_ha->sas_port[i];
+ spin_lock(&port->phy_list_lock);
+ if (*(u64 *)port->sas_addr == 0
+ && port->num_phys == 0) {
+ memcpy(port->sas_addr, phy->sas_addr,
+ SAS_ADDR_SIZE);
+ break;
+ }
+ spin_unlock(&port->phy_list_lock);
+ }
+ }
if (i >= sas_ha->num_phys) {
printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
index 1c286707dd5f..ad05d6edb8f6 100644
--- a/drivers/scsi/lpfc/Makefile
+++ b/drivers/scsi/lpfc/Makefile
@@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \
lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
- lpfc_vport.o lpfc_debugfs.o
+ lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 1877d9811831..aa10f7951634 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -312,6 +312,7 @@ struct lpfc_vport {
#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
+#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */
uint32_t ct_flags;
#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
@@ -440,6 +441,12 @@ enum intr_type_t {
MSIX,
};
+struct unsol_rcv_ct_ctx {
+ uint32_t ctxt_id;
+ uint32_t SID;
+ uint32_t oxid;
+};
+
struct lpfc_hba {
/* SCSI interface function jump table entries */
int (*lpfc_new_scsi_buf)
@@ -525,6 +532,8 @@ struct lpfc_hba {
#define FCP_XRI_ABORT_EVENT 0x20
#define ELS_XRI_ABORT_EVENT 0x40
#define ASYNC_EVENT 0x80
+#define LINK_DISABLED 0x100 /* Link disabled by user */
+#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
struct lpfc_dmabuf slim2p;
MAILBOX_t *mbox;
@@ -616,6 +625,8 @@ struct lpfc_hba {
uint32_t hbq_count; /* Count of configured HBQs */
struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
+ uint32_t fcp_qidx; /* next work queue to post work to */
+
unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */
unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */
unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */
@@ -682,6 +693,7 @@ struct lpfc_hba {
struct pci_pool *lpfc_mbuf_pool;
struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */
struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */
+ struct pci_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */
struct lpfc_dma_pool lpfc_mbuf_safety_pool;
mempool_t *mbox_mem_pool;
@@ -763,11 +775,18 @@ struct lpfc_hba {
/* Maximum number of events that can be outstanding at any time*/
#define LPFC_MAX_EVT_COUNT 512
atomic_t fast_event_count;
+ uint32_t fcoe_eventtag;
+ uint32_t fcoe_eventtag_at_fcf_scan;
struct lpfc_fcf fcf;
uint8_t fc_map[3];
uint8_t valid_vlan;
uint16_t vlan_id;
struct list_head fcf_conn_rec_list;
+
+ struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */
+ struct list_head ct_ev_waiters;
+ struct unsol_rcv_ct_ctx ct_ctx[64];
+ uint32_t ctx_idx;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index fc07be5fbce9..e1a30a16a9fa 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -394,7 +394,12 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
case LPFC_HBA_ERROR:
- len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
+ if (phba->hba_flag & LINK_DISABLED)
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "Link Down - User disabled\n");
+ else
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "Link Down\n");
break;
case LPFC_LINK_UP:
case LPFC_CLEAR_LA:
@@ -4127,6 +4132,9 @@ struct fc_function_template lpfc_transport_functions = {
.vport_disable = lpfc_vport_disable,
.set_vport_symbolic_name = lpfc_set_vport_symbolic_name,
+
+ .bsg_request = lpfc_bsg_request,
+ .bsg_timeout = lpfc_bsg_timeout,
};
struct fc_function_template lpfc_vport_transport_functions = {
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
new file mode 100644
index 000000000000..da6bf5aac9dd
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -0,0 +1,904 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2009 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * 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. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#include <linux/interrupt.h>
+#include <linux/mempool.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_bsg_fc.h>
+
+#include "lpfc_hw4.h"
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_sli4.h"
+#include "lpfc_nl.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_version.h"
+
+/**
+ * lpfc_bsg_rport_ct - send a CT command from a bsg request
+ * @job: fc_bsg_job to handle
+ */
+static int
+lpfc_bsg_rport_ct(struct fc_bsg_job *job)
+{
+ struct Scsi_Host *shost = job->shost;
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_rport_data *rdata = job->rport->dd_data;
+ struct lpfc_nodelist *ndlp = rdata->pnode;
+ struct ulp_bde64 *bpl = NULL;
+ uint32_t timeout;
+ struct lpfc_iocbq *cmdiocbq = NULL;
+ struct lpfc_iocbq *rspiocbq = NULL;
+ IOCB_t *cmd;
+ IOCB_t *rsp;
+ struct lpfc_dmabuf *bmp = NULL;
+ int request_nseg;
+ int reply_nseg;
+ struct scatterlist *sgel = NULL;
+ int numbde;
+ dma_addr_t busaddr;
+ int rc = 0;
+
+ /* in case no data is transferred */
+ job->reply->reply_payload_rcv_len = 0;
+
+ if (!lpfc_nlp_get(ndlp)) {
+ job->reply->result = -ENODEV;
+ return 0;
+ }
+
+ if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
+ rc = -ENODEV;
+ goto free_ndlp_exit;
+ }
+
+ spin_lock_irq(shost->host_lock);
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ if (!cmdiocbq) {
+ rc = -ENOMEM;
+ spin_unlock_irq(shost->host_lock);
+ goto free_ndlp_exit;
+ }
+ cmd = &cmdiocbq->iocb;
+
+ rspiocbq = lpfc_sli_get_iocbq(phba);
+ if (!rspiocbq) {
+ rc = -ENOMEM;
+ goto free_cmdiocbq;
+ }
+ spin_unlock_irq(shost->host_lock);
+
+ rsp = &rspiocbq->iocb;
+
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!bmp) {
+ rc = -ENOMEM;
+ spin_lock_irq(shost->host_lock);
+ goto free_rspiocbq;
+ }
+
+ spin_lock_irq(shost->host_lock);
+ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+ if (!bmp->virt) {
+ rc = -ENOMEM;
+ goto free_bmp;
+ }
+ spin_unlock_irq(shost->host_lock);
+
+ INIT_LIST_HEAD(&bmp->list);
+ bpl = (struct ulp_bde64 *) bmp->virt;
+
+ request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
+ busaddr = sg_dma_address(sgel);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bpl->tus.f.bdeSize = sg_dma_len(sgel);
+ bpl->tus.w = cpu_to_le32(bpl->tus.w);
+ bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+ bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+ bpl++;
+ }
+
+ reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
+ busaddr = sg_dma_address(sgel);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ bpl->tus.f.bdeSize = sg_dma_len(sgel);
+ bpl->tus.w = cpu_to_le32(bpl->tus.w);
+ bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+ bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+ bpl++;
+ }
+
+ cmd->un.genreq64.bdl.ulpIoTag32 = 0;
+ cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
+ cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
+ cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+ cmd->un.genreq64.bdl.bdeSize =
+ (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
+ cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
+ cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
+ cmd->un.genreq64.w5.hcsw.Dfctl = 0;
+ cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
+ cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
+ cmd->ulpBdeCount = 1;
+ cmd->ulpLe = 1;
+ cmd->ulpClass = CLASS3;
+ cmd->ulpContext = ndlp->nlp_rpi;
+ cmd->ulpOwner = OWN_CHIP;
+ cmdiocbq->vport = phba->pport;
+ cmdiocbq->context1 = NULL;
+ cmdiocbq->context2 = NULL;
+ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+
+ timeout = phba->fc_ratov * 2;
+ job->dd_data = cmdiocbq;
+
+ rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq,
+ timeout + LPFC_DRVR_TIMEOUT);
+
+ if (rc != IOCB_TIMEDOUT) {
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ }
+
+ if (rc == IOCB_TIMEDOUT) {
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+ rc = -EACCES;
+ goto free_ndlp_exit;
+ }
+
+ if (rc != IOCB_SUCCESS) {
+ rc = -EACCES;
+ goto free_outdmp;
+ }
+
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & 0xff) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ goto free_outdmp;
+ }
+ } else
+ job->reply->reply_payload_rcv_len =
+ rsp->un.genreq64.bdl.bdeSize;
+
+free_outdmp:
+ spin_lock_irq(shost->host_lock);
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+free_bmp:
+ kfree(bmp);
+free_rspiocbq:
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+free_cmdiocbq:
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ spin_unlock_irq(shost->host_lock);
+free_ndlp_exit:
+ lpfc_nlp_put(ndlp);
+
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace */
+ job->job_done(job);
+
+ return 0;
+}
+
+/**
+ * lpfc_bsg_rport_els - send an ELS command from a bsg request
+ * @job: fc_bsg_job to handle
+ */
+static int
+lpfc_bsg_rport_els(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_rport_data *rdata = job->rport->dd_data;
+ struct lpfc_nodelist *ndlp = rdata->pnode;
+
+ uint32_t elscmd;
+ uint32_t cmdsize;
+ uint32_t rspsize;
+ struct lpfc_iocbq *rspiocbq;
+ struct lpfc_iocbq *cmdiocbq;
+ IOCB_t *rsp;
+ uint16_t rpi = 0;
+ struct lpfc_dmabuf *pcmd;
+ struct lpfc_dmabuf *prsp;
+ struct lpfc_dmabuf *pbuflist = NULL;
+ struct ulp_bde64 *bpl;
+ int iocb_status;
+ int request_nseg;
+ int reply_nseg;
+ struct scatterlist *sgel = NULL;
+ int numbde;
+ dma_addr_t busaddr;
+ int rc = 0;
+
+ /* in case no data is transferred */
+ job->reply->reply_payload_rcv_len = 0;
+
+ if (!lpfc_nlp_get(ndlp)) {
+ rc = -ENODEV;
+ goto out;
+ }
+
+ elscmd = job->request->rqst_data.r_els.els_code;
+ cmdsize = job->request_payload.payload_len;
+ rspsize = job->reply_payload.payload_len;
+ rspiocbq = lpfc_sli_get_iocbq(phba);
+ if (!rspiocbq) {
+ lpfc_nlp_put(ndlp);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rsp = &rspiocbq->iocb;
+ rpi = ndlp->nlp_rpi;
+
+ cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp,
+ ndlp->nlp_DID, elscmd);
+
+ if (!cmdiocbq) {
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+ return -EIO;
+ }
+
+ job->dd_data = cmdiocbq;
+ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2;
+ prsp = (struct lpfc_dmabuf *) pcmd->list.next;
+
+ lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+ kfree(pcmd);
+ lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
+ kfree(prsp);
+ cmdiocbq->context2 = NULL;
+
+ pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
+ bpl = (struct ulp_bde64 *) pbuflist->virt;
+
+ request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
+ busaddr = sg_dma_address(sgel);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bpl->tus.f.bdeSize = sg_dma_len(sgel);
+ bpl->tus.w = cpu_to_le32(bpl->tus.w);
+ bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+ bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+ bpl++;
+ }
+
+ reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
+ busaddr = sg_dma_address(sgel);
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ bpl->tus.f.bdeSize = sg_dma_len(sgel);
+ bpl->tus.w = cpu_to_le32(bpl->tus.w);
+ bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
+ bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
+ bpl++;
+ }
+
+ cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
+ (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
+ cmdiocbq->iocb.ulpContext = rpi;
+ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
+ cmdiocbq->context1 = NULL;
+ cmdiocbq->context2 = NULL;
+
+ iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
+ rspiocbq, (phba->fc_ratov * 2)
+ + LPFC_DRVR_TIMEOUT);
+
+ /* release the new ndlp once the iocb completes */
+ lpfc_nlp_put(ndlp);
+ if (iocb_status != IOCB_TIMEDOUT) {
+ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
+ job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ }
+
+ if (iocb_status == IOCB_SUCCESS) {
+ if (rsp->ulpStatus == IOSTAT_SUCCESS) {
+ job->reply->reply_payload_rcv_len =
+ rsp->un.elsreq64.bdl.bdeSize;
+ rc = 0;
+ } else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
+ struct fc_bsg_ctels_reply *els_reply;
+ /* LS_RJT data returned in word 4 */
+ uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
+
+ els_reply = &job->reply->reply_data.ctels_reply;
+ job->reply->result = 0;
+ els_reply->status = FC_CTELS_STATUS_REJECT;
+ els_reply->rjt_data.action = rjt_data[0];
+ els_reply->rjt_data.reason_code = rjt_data[1];
+ els_reply->rjt_data.reason_explanation = rjt_data[2];
+ els_reply->rjt_data.vendor_unique = rjt_data[3];
+ } else
+ rc = -EIO;
+ } else
+ rc = -EIO;
+
+ if (iocb_status != IOCB_TIMEDOUT)
+ lpfc_els_free_iocb(phba, cmdiocbq);
+
+ lpfc_sli_release_iocbq(phba, rspiocbq);
+
+out:
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace */
+ job->job_done(job);
+
+ return 0;
+}
+
+struct lpfc_ct_event {
+ struct list_head node;
+ int ref;
+ wait_queue_head_t wq;
+
+ /* Event type and waiter identifiers */
+ uint32_t type_mask;
+ uint32_t req_id;
+ uint32_t reg_id;
+
+ /* next two flags are here for the auto-delete logic */
+ unsigned long wait_time_stamp;
+ int waiting;
+
+ /* seen and not seen events */
+ struct list_head events_to_get;
+ struct list_head events_to_see;
+};
+
+struct event_data {
+ struct list_head node;
+ uint32_t type;
+ uint32_t immed_dat;
+ void *data;
+ uint32_t len;
+};
+
+static struct lpfc_ct_event *
+lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id)
+{
+ struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+ if (!evt)
+ return NULL;
+
+ INIT_LIST_HEAD(&evt->events_to_get);
+ INIT_LIST_HEAD(&evt->events_to_see);
+ evt->req_id = ev_req_id;
+ evt->reg_id = ev_reg_id;
+ evt->wait_time_stamp = jiffies;
+ init_waitqueue_head(&evt->wq);
+
+ return evt;
+}
+
+static void
+lpfc_ct_event_free(struct lpfc_ct_event *evt)
+{
+ struct event_data *ed;
+
+ list_del(&evt->node);
+
+ while (!list_empty(&evt->events_to_get)) {
+ ed = list_entry(evt->events_to_get.next, typeof(*ed), node);
+ list_del(&ed->node);
+ kfree(ed->data);
+ kfree(ed);
+ }
+
+ while (!list_empty(&evt->events_to_see)) {
+ ed = list_entry(evt->events_to_see.next, typeof(*ed), node);
+ list_del(&ed->node);
+ kfree(ed->data);
+ kfree(ed);
+ }
+
+ kfree(evt);
+}
+
+static inline void
+lpfc_ct_event_ref(struct lpfc_ct_event *evt)
+{
+ evt->ref++;
+}
+
+static inline void
+lpfc_ct_event_unref(struct lpfc_ct_event *evt)
+{
+ if (--evt->ref < 0)
+ lpfc_ct_event_free(evt);
+}
+
+#define SLI_CT_ELX_LOOPBACK 0x10
+
+enum ELX_LOOPBACK_CMD {
+ ELX_LOOPBACK_XRI_SETUP,
+ ELX_LOOPBACK_DATA,
+};
+
+/**
+ * lpfc_bsg_ct_unsol_event - process an unsolicited CT command
+ * @phba:
+ * @pring:
+ * @piocbq:
+ *
+ * This function is called when an unsolicited CT command is received. It
+ * forwards the event to any processes registerd to receive CT events.
+ */
+void
+lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocbq)
+{
+ uint32_t evt_req_id = 0;
+ uint32_t cmd;
+ uint32_t len;
+ struct lpfc_dmabuf *dmabuf = NULL;
+ struct lpfc_ct_event *evt;
+ struct event_data *evt_dat = NULL;
+ struct lpfc_iocbq *iocbq;
+ size_t offset = 0;
+ struct list_head head;
+ struct ulp_bde64 *bde;
+ dma_addr_t dma_addr;
+ int i;
+ struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
+ struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
+ struct lpfc_hbq_entry *hbqe;
+ struct lpfc_sli_ct_request *ct_req;
+
+ INIT_LIST_HEAD(&head);
+ list_add_tail(&head, &piocbq->list);
+
+ if (piocbq->iocb.ulpBdeCount == 0 ||
+ piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0)
+ goto error_ct_unsol_exit;
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+ dmabuf = bdeBuf1;
+ else {
+ dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh,
+ piocbq->iocb.un.cont64[0].addrLow);
+ dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr);
+ }
+
+ ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt;
+ evt_req_id = ct_req->FsType;
+ cmd = ct_req->CommandResponse.bits.CmdRsp;
+ len = ct_req->CommandResponse.bits.Size;
+ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+ lpfc_sli_ringpostbuf_put(phba, pring, dmabuf);
+
+ mutex_lock(&phba->ct_event_mutex);
+ list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
+ if (evt->req_id != evt_req_id)
+ continue;
+
+ lpfc_ct_event_ref(evt);
+
+ evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL);
+ if (!evt_dat) {
+ lpfc_ct_event_unref(evt);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2614 Memory allocation failed for "
+ "CT event\n");
+ break;
+ }
+
+ mutex_unlock(&phba->ct_event_mutex);
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ /* take accumulated byte count from the last iocbq */
+ iocbq = list_entry(head.prev, typeof(*iocbq), list);
+ evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len;
+ } else {
+ list_for_each_entry(iocbq, &head, list) {
+ for (i = 0; i < iocbq->iocb.ulpBdeCount; i++)
+ evt_dat->len +=
+ iocbq->iocb.un.cont64[i].tus.f.bdeSize;
+ }
+ }
+
+ evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL);
+ if (!evt_dat->data) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2615 Memory allocation failed for "
+ "CT event data, size %d\n",
+ evt_dat->len);
+ kfree(evt_dat);
+ mutex_lock(&phba->ct_event_mutex);
+ lpfc_ct_event_unref(evt);
+ mutex_unlock(&phba->ct_event_mutex);
+ goto error_ct_unsol_exit;
+ }
+
+ list_for_each_entry(iocbq, &head, list) {
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ bdeBuf1 = iocbq->context2;
+ bdeBuf2 = iocbq->context3;
+ }
+ for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) {
+ int size = 0;
+ if (phba->sli3_options &
+ LPFC_SLI3_HBQ_ENABLED) {
+ if (i == 0) {
+ hbqe = (struct lpfc_hbq_entry *)
+ &iocbq->iocb.un.ulpWord[0];
+ size = hbqe->bde.tus.f.bdeSize;
+ dmabuf = bdeBuf1;
+ } else if (i == 1) {
+ hbqe = (struct lpfc_hbq_entry *)
+ &iocbq->iocb.unsli3.
+ sli3Words[4];
+ size = hbqe->bde.tus.f.bdeSize;
+ dmabuf = bdeBuf2;
+ }
+ if ((offset + size) > evt_dat->len)
+ size = evt_dat->len - offset;
+ } else {
+ size = iocbq->iocb.un.cont64[i].
+ tus.f.bdeSize;
+ bde = &iocbq->iocb.un.cont64[i];
+ dma_addr = getPaddr(bde->addrHigh,
+ bde->addrLow);
+ dmabuf = lpfc_sli_ringpostbuf_get(phba,
+ pring, dma_addr);
+ }
+ if (!dmabuf) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_LIBDFC, "2616 No dmabuf "
+ "found for iocbq 0x%p\n",
+ iocbq);
+ kfree(evt_dat->data);
+ kfree(evt_dat);
+ mutex_lock(&phba->ct_event_mutex);
+ lpfc_ct_event_unref(evt);
+ mutex_unlock(&phba->ct_event_mutex);
+ goto error_ct_unsol_exit;
+ }
+ memcpy((char *)(evt_dat->data) + offset,
+ dmabuf->virt, size);
+ offset += size;
+ if (evt_req_id != SLI_CT_ELX_LOOPBACK &&
+ !(phba->sli3_options &
+ LPFC_SLI3_HBQ_ENABLED)) {
+ lpfc_sli_ringpostbuf_put(phba, pring,
+ dmabuf);
+ } else {
+ switch (cmd) {
+ case ELX_LOOPBACK_XRI_SETUP:
+ if (!(phba->sli3_options &
+ LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba,
+ pring,
+ 1);
+ else
+ lpfc_in_buf_free(phba,
+ dmabuf);
+ break;
+ default:
+ if (!(phba->sli3_options &
+ LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba,
+ pring,
+ 1);
+ break;
+ }
+ }
+ }
+ }
+
+ mutex_lock(&phba->ct_event_mutex);
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ evt_dat->immed_dat = phba->ctx_idx;
+ phba->ctx_idx = (phba->ctx_idx + 1) % 64;
+ phba->ct_ctx[evt_dat->immed_dat].oxid =
+ piocbq->iocb.ulpContext;
+ phba->ct_ctx[evt_dat->immed_dat].SID =
+ piocbq->iocb.un.rcvels.remoteID;
+ } else
+ evt_dat->immed_dat = piocbq->iocb.ulpContext;
+
+ evt_dat->type = FC_REG_CT_EVENT;
+ list_add(&evt_dat->node, &evt->events_to_see);
+ wake_up_interruptible(&evt->wq);
+ lpfc_ct_event_unref(evt);
+ if (evt_req_id == SLI_CT_ELX_LOOPBACK)
+ break;
+ }
+ mutex_unlock(&phba->ct_event_mutex);
+
+error_ct_unsol_exit:
+ if (!list_empty(&head))
+ list_del(&head);
+
+ return;
+}
+
+/**
+ * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command
+ * @job: SET_EVENT fc_bsg_job
+ */
+static int
+lpfc_bsg_set_event(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct set_ct_event *event_req;
+ struct lpfc_ct_event *evt;
+ int rc = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2612 Received SET_CT_EVENT below minimum "
+ "size\n");
+ return -EINVAL;
+ }
+
+ event_req = (struct set_ct_event *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+
+ mutex_lock(&phba->ct_event_mutex);
+ list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
+ if (evt->reg_id == event_req->ev_reg_id) {
+ lpfc_ct_event_ref(evt);
+ evt->wait_time_stamp = jiffies;
+ break;
+ }
+ }
+ mutex_unlock(&phba->ct_event_mutex);
+
+ if (&evt->node == &phba->ct_ev_waiters) {
+ /* no event waiting struct yet - first call */
+ evt = lpfc_ct_event_new(event_req->ev_reg_id,
+ event_req->ev_req_id);
+ if (!evt) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2617 Failed allocation of event "
+ "waiter\n");
+ return -ENOMEM;
+ }
+
+ mutex_lock(&phba->ct_event_mutex);
+ list_add(&evt->node, &phba->ct_ev_waiters);
+ lpfc_ct_event_ref(evt);
+ mutex_unlock(&phba->ct_event_mutex);
+ }
+
+ evt->waiting = 1;
+ if (wait_event_interruptible(evt->wq,
+ !list_empty(&evt->events_to_see))) {
+ mutex_lock(&phba->ct_event_mutex);
+ lpfc_ct_event_unref(evt); /* release ref */
+ lpfc_ct_event_unref(evt); /* delete */
+ mutex_unlock(&phba->ct_event_mutex);
+ rc = -EINTR;
+ goto set_event_out;
+ }
+
+ evt->wait_time_stamp = jiffies;
+ evt->waiting = 0;
+
+ mutex_lock(&phba->ct_event_mutex);
+ list_move(evt->events_to_see.prev, &evt->events_to_get);
+ lpfc_ct_event_unref(evt); /* release ref */
+ mutex_unlock(&phba->ct_event_mutex);
+
+set_event_out:
+ /* set_event carries no reply payload */
+ job->reply->reply_payload_rcv_len = 0;
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace */
+ job->job_done(job);
+
+ return 0;
+}
+
+/**
+ * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command
+ * @job: GET_EVENT fc_bsg_job
+ */
+static int
+lpfc_bsg_get_event(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct get_ct_event *event_req;
+ struct get_ct_event_reply *event_reply;
+ struct lpfc_ct_event *evt;
+ struct event_data *evt_dat = NULL;
+ int rc = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2613 Received GET_CT_EVENT request below "
+ "minimum size\n");
+ return -EINVAL;
+ }
+
+ event_req = (struct get_ct_event *)
+ job->request->rqst_data.h_vendor.vendor_cmd;
+
+ event_reply = (struct get_ct_event_reply *)
+ job->reply->reply_data.vendor_reply.vendor_rsp;
+
+ mutex_lock(&phba->ct_event_mutex);
+ list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
+ if (evt->reg_id == event_req->ev_reg_id) {
+ if (list_empty(&evt->events_to_get))
+ break;
+ lpfc_ct_event_ref(evt);
+ evt->wait_time_stamp = jiffies;
+ evt_dat = list_entry(evt->events_to_get.prev,
+ struct event_data, node);
+ list_del(&evt_dat->node);
+ break;
+ }
+ }
+ mutex_unlock(&phba->ct_event_mutex);
+
+ if (!evt_dat) {
+ job->reply->reply_payload_rcv_len = 0;
+ rc = -ENOENT;
+ goto error_get_event_exit;
+ }
+
+ if (evt_dat->len > job->reply_payload.payload_len) {
+ evt_dat->len = job->reply_payload.payload_len;
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2618 Truncated event data at %d "
+ "bytes\n",
+ job->reply_payload.payload_len);
+ }
+
+ event_reply->immed_data = evt_dat->immed_dat;
+
+ if (evt_dat->len > 0)
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ evt_dat->data, evt_dat->len);
+ else
+ job->reply->reply_payload_rcv_len = 0;
+ rc = 0;
+
+ if (evt_dat)
+ kfree(evt_dat->data);
+ kfree(evt_dat);
+ mutex_lock(&phba->ct_event_mutex);
+ lpfc_ct_event_unref(evt);
+ mutex_unlock(&phba->ct_event_mutex);
+
+error_get_event_exit:
+ /* make error code available to userspace */
+ job->reply->result = rc;
+ /* complete the job back to userspace */
+ job->job_done(job);
+
+ return rc;
+}
+
+/**
+ * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
+ * @job: fc_bsg_job to handle
+ */
+static int
+lpfc_bsg_hst_vendor(struct fc_bsg_job *job)
+{
+ int command = job->request->rqst_data.h_vendor.vendor_cmd[0];
+
+ switch (command) {
+ case LPFC_BSG_VENDOR_SET_CT_EVENT:
+ return lpfc_bsg_set_event(job);
+ break;
+
+ case LPFC_BSG_VENDOR_GET_CT_EVENT:
+ return lpfc_bsg_get_event(job);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * lpfc_bsg_request - handle a bsg request from the FC transport
+ * @job: fc_bsg_job to handle
+ */
+int
+lpfc_bsg_request(struct fc_bsg_job *job)
+{
+ uint32_t msgcode;
+ int rc = -EINVAL;
+
+ msgcode = job->request->msgcode;
+
+ switch (msgcode) {
+ case FC_BSG_HST_VENDOR:
+ rc = lpfc_bsg_hst_vendor(job);
+ break;
+ case FC_BSG_RPT_ELS:
+ rc = lpfc_bsg_rport_els(job);
+ break;
+ case FC_BSG_RPT_CT:
+ rc = lpfc_bsg_rport_ct(job);
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport
+ * @job: fc_bsg_job that has timed out
+ *
+ * This function just aborts the job's IOCB. The aborted IOCB will return to
+ * the waiting function which will handle passing the error back to userspace
+ */
+int
+lpfc_bsg_timeout(struct fc_bsg_job *job)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+
+ if (cmdiocb)
+ lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+
+ return 0;
+}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index d2a922997c0f..0830f37409a3 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -21,9 +21,11 @@
typedef int (*node_filter)(struct lpfc_nodelist *, void *);
struct fc_rport;
-void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli_read_link_ste(struct lpfc_hba *);
+void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t);
void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *);
-void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
@@ -135,6 +137,9 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long);
void lpfc_els_timeout_handler(struct lpfc_vport *);
+struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t,
+ uint8_t, struct lpfc_nodelist *,
+ uint32_t, uint32_t);
void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
@@ -182,11 +187,12 @@ int lpfc_mbox_dev_check(struct lpfc_hba *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
-void lpfc_init_vpi(struct lpfcMboxq *, uint16_t);
+void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t);
void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
+int lpfc_check_pending_fcoe_event(struct lpfc_hba *, uint8_t);
void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
uint32_t , LPFC_MBOXQ_t *);
@@ -234,6 +240,7 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
+void lpfc_sli_bemem_bcopy(void *, void *, uint32_t);
void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
void lpfc_sli_flush_fcp_rings(struct lpfc_hba *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
@@ -360,3 +367,8 @@ void lpfc_start_fdiscs(struct lpfc_hba *phba);
#define HBA_EVENT_LINK_UP 2
#define HBA_EVENT_LINK_DOWN 3
+/* functions to support SGIOv4/bsg interface */
+int lpfc_bsg_request(struct fc_bsg_job *);
+int lpfc_bsg_timeout(struct fc_bsg_job *);
+void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 0e532f072eb3..9df7ed38e1be 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -97,6 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct list_head head;
struct lpfc_dmabuf *bdeBuf;
+ lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
+
if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index f72fdf23bf1b..45337cd23feb 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -146,7 +146,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
* Pointer to the newly allocated/prepared els iocb data structure
* NULL - when els iocb data structure allocation/preparation failed
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
uint16_t cmdSize, uint8_t retry,
struct lpfc_nodelist *ndlp, uint32_t did,
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index ed46b24a3380..e6a47e25b218 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -61,6 +61,7 @@ static uint8_t lpfcAlpaArray[] = {
static void lpfc_disc_timeout_handler(struct lpfc_vport *);
static void lpfc_disc_flush_list(struct lpfc_vport *vport);
+static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void
lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -1009,9 +1010,15 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_lock_irqsave(&phba->hbalock, flags);
phba->fcf.fcf_flag |= FCF_REGISTERED;
spin_unlock_irqrestore(&phba->hbalock, flags);
+ /* If there is a pending FCoE event, restart FCF table scan. */
+ if (lpfc_check_pending_fcoe_event(phba, 1)) {
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return;
+ }
if (vport->port_state != LPFC_FLOGI) {
spin_lock_irqsave(&phba->hbalock, flags);
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
lpfc_initial_flogi(vport);
}
@@ -1054,6 +1061,39 @@ lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
}
/**
+ * lpfc_sw_name_match - Check if the fcf switch name match.
+ * @fab_name: pointer to fabric name.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine compare the fcf record's switch name with provided
+ * switch name. If the switch name are identical this function
+ * returns 1 else return 0.
+ **/
+static uint32_t
+lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record)
+{
+ if ((sw_name[0] ==
+ bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) &&
+ (sw_name[1] ==
+ bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) &&
+ (sw_name[2] ==
+ bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) &&
+ (sw_name[3] ==
+ bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) &&
+ (sw_name[4] ==
+ bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) &&
+ (sw_name[5] ==
+ bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) &&
+ (sw_name[6] ==
+ bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) &&
+ (sw_name[7] ==
+ bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record)))
+ return 1;
+ else
+ return 0;
+}
+
+/**
* lpfc_mac_addr_match - Check if the fcf mac address match.
* @phba: pointer to lpfc hba data structure.
* @new_fcf_record: pointer to fcf record.
@@ -1123,6 +1163,22 @@ lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
phba->fcf.priority = new_fcf_record->fip_priority;
+ phba->fcf.switch_name[0] =
+ bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record);
+ phba->fcf.switch_name[1] =
+ bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record);
+ phba->fcf.switch_name[2] =
+ bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record);
+ phba->fcf.switch_name[3] =
+ bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record);
+ phba->fcf.switch_name[4] =
+ bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record);
+ phba->fcf.switch_name[5] =
+ bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record);
+ phba->fcf.switch_name[6] =
+ bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record);
+ phba->fcf.switch_name[7] =
+ bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record);
}
/**
@@ -1150,6 +1206,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
/* The FCF is already registered, start discovery */
if (phba->fcf.fcf_flag & FCF_REGISTERED) {
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+ phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
if (phba->pport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(phba->pport);
@@ -1239,9 +1296,12 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) &&
!lpfc_fab_name_match(conn_entry->conn_rec.fabric_name,
- new_fcf_record))
+ new_fcf_record))
+ continue;
+ if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) &&
+ !lpfc_sw_name_match(conn_entry->conn_rec.switch_name,
+ new_fcf_record))
continue;
-
if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) {
/*
* If the vlan bit map does not have the bit set for the
@@ -1336,6 +1396,60 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
}
/**
+ * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event.
+ * @phba: pointer to lpfc hba data structure.
+ * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned.
+ *
+ * This function check if there is any fcoe event pending while driver
+ * scan FCF entries. If there is any pending event, it will restart the
+ * FCF saning and return 1 else return 0.
+ */
+int
+lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
+{
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+ /*
+ * If the Link is up and no FCoE events while in the
+ * FCF discovery, no need to restart FCF discovery.
+ */
+ if ((phba->link_state >= LPFC_LINK_UP) &&
+ (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
+ return 0;
+
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_AVAILABLE;
+ spin_unlock_irq(&phba->hbalock);
+
+ if (phba->link_state >= LPFC_LINK_UP)
+ lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+
+ if (unreg_fcf) {
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_REGISTERED;
+ spin_unlock_irq(&phba->hbalock);
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_DISCOVERY|LOG_MBOX,
+ "2610 UNREG_FCFI mbox allocation failed\n");
+ return 1;
+ }
+ lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
+ mbox->vport = phba->pport;
+ mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+ "2611 UNREG_FCFI issue mbox failed\n");
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+
+ return 1;
+}
+
+/**
* lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
@@ -1367,6 +1481,12 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
unsigned long flags;
uint16_t vlan_id;
+ /* If there is pending FCoE event restart FCF table scan */
+ if (lpfc_check_pending_fcoe_event(phba, 0)) {
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ return;
+ }
+
/* Get the first SGE entry from the non-embedded DMA memory. This
* routine only uses a single SGE.
*/
@@ -1424,7 +1544,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_lock_irqsave(&phba->hbalock, flags);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
if (lpfc_fab_name_match(phba->fcf.fabric_name,
- new_fcf_record) &&
+ new_fcf_record) &&
+ lpfc_sw_name_match(phba->fcf.switch_name,
+ new_fcf_record) &&
lpfc_mac_addr_match(phba, new_fcf_record)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -1464,9 +1586,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
* If there is a record with lower priority value for
* the current FCF, use that record.
*/
- if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record)
- && (new_fcf_record->fip_priority <
- phba->fcf.priority)) {
+ if (lpfc_fab_name_match(phba->fcf.fabric_name,
+ new_fcf_record) &&
+ (new_fcf_record->fip_priority < phba->fcf.priority)) {
/* Use this FCF record */
lpfc_copy_fcf_record(phba, new_fcf_record);
phba->fcf.addr_mode = addr_mode;
@@ -1512,6 +1634,39 @@ out:
}
/**
+ * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox data structure.
+ *
+ * This function handles completion of init vpi mailbox command.
+ */
+static void
+lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+ struct lpfc_vport *vport = mboxq->vport;
+ if (mboxq->u.mb.mbxStatus) {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_MBOX,
+ "2609 Init VPI mailbox failed 0x%x\n",
+ mboxq->u.mb.mbxStatus);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ return;
+ }
+ vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
+
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+ lpfc_initial_fdisc(vport);
+ else {
+ lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_ELS,
+ "2606 No NPIV Fabric support\n");
+ }
+ return;
+}
+
+/**
* lpfc_start_fdiscs - send fdiscs for each vports on this port.
* @phba: pointer to lpfc hba data structure.
*
@@ -1523,6 +1678,8 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
int i;
+ LPFC_MBOXQ_t *mboxq;
+ int rc;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL) {
@@ -1540,6 +1697,29 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
FC_VPORT_LINKDOWN);
continue;
}
+ if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
+ mboxq = mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mboxq) {
+ lpfc_printf_vlog(vports[i], KERN_ERR,
+ LOG_MBOX, "2607 Failed to allocate "
+ "init_vpi mailbox\n");
+ continue;
+ }
+ lpfc_init_vpi(phba, mboxq, vports[i]->vpi);
+ mboxq->vport = vports[i];
+ mboxq->mbox_cmpl = lpfc_init_vpi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mboxq,
+ MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vports[i], KERN_ERR,
+ LOG_MBOX, "2608 Failed to issue "
+ "init_vpi mailbox\n");
+ mempool_free(mboxq,
+ phba->mbox_mem_pool);
+ }
+ continue;
+ }
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
lpfc_initial_fdisc(vports[i]);
else {
@@ -1769,6 +1949,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
goto out;
}
} else {
+ vport->port_state = LPFC_VPORT_UNKNOWN;
/*
* Add the driver's default FCF record at FCF index 0 now. This
* is phase 1 implementation that support FCF index 0 and driver
@@ -1804,6 +1985,12 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
* The driver is expected to do FIP/FCF. Call the port
* and get the FCF Table.
*/
+ spin_lock_irq(&phba->hbalock);
+ if (phba->hba_flag & FCF_DISC_INPROGRESS) {
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli4_read_fcf_record(phba,
LPFC_FCOE_FCF_GET_FIRST);
if (rc)
@@ -2113,13 +2300,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
LPFC_MBOXQ_t *pmb = NULL;
MAILBOX_t *mb;
struct static_vport_info *vport_info;
- int rc, i;
+ int rc = 0, i;
struct fc_vport_identifiers vport_id;
struct fc_vport *new_fc_vport;
struct Scsi_Host *shost;
struct lpfc_vport *vport;
uint16_t offset = 0;
uint8_t *vport_buff;
+ struct lpfc_dmabuf *mp;
+ uint32_t byte_count = 0;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
@@ -2142,7 +2331,9 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
vport_buff = (uint8_t *) vport_info;
do {
- lpfc_dump_static_vport(phba, pmb, offset);
+ if (lpfc_dump_static_vport(phba, pmb, offset))
+ goto out;
+
pmb->vport = phba->pport;
rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO);
@@ -2155,17 +2346,30 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
goto out;
}
- if (mb->un.varDmp.word_cnt >
- sizeof(struct static_vport_info) - offset)
- mb->un.varDmp.word_cnt =
- sizeof(struct static_vport_info) - offset;
-
- lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
- vport_buff + offset,
- mb->un.varDmp.word_cnt);
- offset += mb->un.varDmp.word_cnt;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ byte_count = pmb->u.mqe.un.mb_words[5];
+ mp = (struct lpfc_dmabuf *) pmb->context2;
+ if (byte_count > sizeof(struct static_vport_info) -
+ offset)
+ byte_count = sizeof(struct static_vport_info)
+ - offset;
+ memcpy(vport_buff + offset, mp->virt, byte_count);
+ offset += byte_count;
+ } else {
+ if (mb->un.varDmp.word_cnt >
+ sizeof(struct static_vport_info) - offset)
+ mb->un.varDmp.word_cnt =
+ sizeof(struct static_vport_info)
+ - offset;
+ byte_count = mb->un.varDmp.word_cnt;
+ lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
+ vport_buff + offset,
+ byte_count);
+
+ offset += byte_count;
+ }
- } while (mb->un.varDmp.word_cnt &&
+ } while (byte_count &&
offset < sizeof(struct static_vport_info));
@@ -2198,7 +2402,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
if (!new_fc_vport) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"0546 lpfc_create_static_vport failed to"
- " create vport \n");
+ " create vport\n");
continue;
}
@@ -2207,16 +2411,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
}
out:
- /*
- * If this is timed out command, setting NULL to context2 tell SLI
- * layer not to use this buffer.
- */
- spin_lock_irq(&phba->hbalock);
- pmb->context2 = NULL;
- spin_unlock_irq(&phba->hbalock);
kfree(vport_info);
- if (rc != MBX_TIMEOUT)
+ if (rc != MBX_TIMEOUT) {
+ if (pmb->context2) {
+ mp = (struct lpfc_dmabuf *) pmb->context2;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
mempool_free(pmb, phba->mbox_mem_pool);
+ }
return;
}
@@ -4360,7 +4563,7 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba,
fcoe_param_hdr = (struct lpfc_fip_param_hdr *)
buff;
fcoe_param = (struct lpfc_fcoe_params *)
- buff + sizeof(struct lpfc_fip_param_hdr);
+ (buff + sizeof(struct lpfc_fip_param_hdr));
if ((fcoe_param_hdr->parm_version != FIPP_VERSION) ||
(fcoe_param_hdr->length != FCOE_PARAM_LENGTH))
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 8a3a026667e4..ccb26724dc53 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -2496,8 +2496,8 @@ typedef struct {
#define DMP_VPORT_REGION_SIZE 0x200
#define DMP_MBOX_OFFSET_WORD 0x5
-#define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */
-#define DMP_FCOEPARAM_RGN_SIZE 0x400
+#define DMP_REGION_23 0x17 /* fcoe param and port state region */
+#define DMP_RGN23_SIZE 0x400
#define WAKE_UP_PARMS_REGION_ID 4
#define WAKE_UP_PARMS_WORD_SIZE 15
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 2995d128f07f..3689eee04535 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -52,6 +52,31 @@ struct dma_address {
uint32_t addr_hi;
};
+#define LPFC_SLIREV_CONF_WORD 0x58
+struct lpfc_sli_intf {
+ uint32_t word0;
+#define lpfc_sli_intf_iftype_MASK 0x00000007
+#define lpfc_sli_intf_iftype_SHIFT 0
+#define lpfc_sli_intf_iftype_WORD word0
+#define lpfc_sli_intf_rev_MASK 0x0000000f
+#define lpfc_sli_intf_rev_SHIFT 4
+#define lpfc_sli_intf_rev_WORD word0
+#define LPFC_SLIREV_CONF_SLI4 4
+#define lpfc_sli_intf_family_MASK 0x000000ff
+#define lpfc_sli_intf_family_SHIFT 8
+#define lpfc_sli_intf_family_WORD word0
+#define lpfc_sli_intf_feat1_MASK 0x000000ff
+#define lpfc_sli_intf_feat1_SHIFT 16
+#define lpfc_sli_intf_feat1_WORD word0
+#define lpfc_sli_intf_feat2_MASK 0x0000001f
+#define lpfc_sli_intf_feat2_SHIFT 24
+#define lpfc_sli_intf_feat2_WORD word0
+#define lpfc_sli_intf_valid_MASK 0x00000007
+#define lpfc_sli_intf_valid_SHIFT 29
+#define lpfc_sli_intf_valid_WORD word0
+#define LPFC_SLI_INTF_VALID 6
+};
+
#define LPFC_SLI4_BAR0 1
#define LPFC_SLI4_BAR1 2
#define LPFC_SLI4_BAR2 4
@@ -1181,6 +1206,32 @@ struct fcf_record {
#define lpfc_fcf_record_fcf_state_MASK 0x0000FFFF
#define lpfc_fcf_record_fcf_state_WORD word8
uint8_t vlan_bitmap[512];
+ uint32_t word137;
+#define lpfc_fcf_record_switch_name_0_SHIFT 0
+#define lpfc_fcf_record_switch_name_0_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_0_WORD word137
+#define lpfc_fcf_record_switch_name_1_SHIFT 8
+#define lpfc_fcf_record_switch_name_1_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_1_WORD word137
+#define lpfc_fcf_record_switch_name_2_SHIFT 16
+#define lpfc_fcf_record_switch_name_2_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_2_WORD word137
+#define lpfc_fcf_record_switch_name_3_SHIFT 24
+#define lpfc_fcf_record_switch_name_3_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_3_WORD word137
+ uint32_t word138;
+#define lpfc_fcf_record_switch_name_4_SHIFT 0
+#define lpfc_fcf_record_switch_name_4_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_4_WORD word138
+#define lpfc_fcf_record_switch_name_5_SHIFT 8
+#define lpfc_fcf_record_switch_name_5_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_5_WORD word138
+#define lpfc_fcf_record_switch_name_6_SHIFT 16
+#define lpfc_fcf_record_switch_name_6_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_6_WORD word138
+#define lpfc_fcf_record_switch_name_7_SHIFT 24
+#define lpfc_fcf_record_switch_name_7_MASK 0x000000FF
+#define lpfc_fcf_record_switch_name_7_WORD word138
};
struct lpfc_mbx_read_fcf_tbl {
@@ -1385,20 +1436,17 @@ struct lpfc_mbx_unreg_vfi {
struct lpfc_mbx_resume_rpi {
uint32_t word1;
-#define lpfc_resume_rpi_rpi_SHIFT 0
-#define lpfc_resume_rpi_rpi_MASK 0x0000FFFF
-#define lpfc_resume_rpi_rpi_WORD word1
+#define lpfc_resume_rpi_index_SHIFT 0
+#define lpfc_resume_rpi_index_MASK 0x0000FFFF
+#define lpfc_resume_rpi_index_WORD word1
+#define lpfc_resume_rpi_ii_SHIFT 30
+#define lpfc_resume_rpi_ii_MASK 0x00000003
+#define lpfc_resume_rpi_ii_WORD word1
+#define RESUME_INDEX_RPI 0
+#define RESUME_INDEX_VPI 1
+#define RESUME_INDEX_VFI 2
+#define RESUME_INDEX_FCFI 3
uint32_t event_tag;
- uint32_t word3_rsvd;
- uint32_t word4_rsvd;
- uint32_t word5_rsvd;
- uint32_t word6;
-#define lpfc_resume_rpi_vpi_SHIFT 0
-#define lpfc_resume_rpi_vpi_MASK 0x0000FFFF
-#define lpfc_resume_rpi_vpi_WORD word6
-#define lpfc_resume_rpi_vfi_SHIFT 16
-#define lpfc_resume_rpi_vfi_MASK 0x0000FFFF
-#define lpfc_resume_rpi_vfi_WORD word6
};
#define REG_FCF_INVALID_QID 0xFFFF
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index fc67cc65c63b..562d8cee874b 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -211,7 +211,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
goto out_free_mbox;
do {
- lpfc_dump_mem(phba, pmb, offset);
+ lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
@@ -425,6 +425,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
return -EIO;
}
+ /* Check if the port is disabled */
+ lpfc_sli_read_link_ste(phba);
+
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))
phba->cfg_hba_queue_depth =
@@ -524,27 +527,46 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/* Set up error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
- lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- lpfc_set_loopback_flag(phba);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ if (phba->hba_flag & LINK_DISABLED) {
+ lpfc_printf_log(phba,
+ KERN_ERR, LOG_INIT,
+ "2598 Adapter Link is disabled.\n");
+ lpfc_down_link(phba, pmb);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
+ lpfc_printf_log(phba,
+ KERN_ERR, LOG_INIT,
+ "2599 Adapter failed to issue DOWN_LINK"
+ " mbox command rc 0x%x\n", rc);
+
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+ } else {
+ lpfc_init_link(phba, pmb, phba->cfg_topology,
+ phba->cfg_link_speed);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ lpfc_set_loopback_flag(phba);
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0454 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
- /* Clear all interrupt enable conditions */
- writel(0, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- /* Clear all pending interrupts */
- writel(0xffffffff, phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
+ /* Clear all interrupt enable conditions */
+ writel(0, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ /* Clear all pending interrupts */
+ writel(0xffffffff, phba->HAregaddr);
+ readl(phba->HAregaddr); /* flush */
- phba->link_state = LPFC_HBA_ERROR;
- if (rc != MBX_BUSY)
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
+ phba->link_state = LPFC_HBA_ERROR;
+ if (rc != MBX_BUSY)
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
}
/* MBOX buffer will be freed in mbox compl */
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -558,7 +580,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
KERN_ERR,
LOG_INIT,
"0456 Adapter failed to issue "
- "ASYNCEVT_ENABLE mbox status x%x \n.",
+ "ASYNCEVT_ENABLE mbox status x%x\n",
rc);
mempool_free(pmb, phba->mbox_mem_pool);
}
@@ -572,7 +594,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed "
- "to get Option ROM version status x%x\n.", rc);
+ "to get Option ROM version status x%x\n", rc);
mempool_free(pmb, phba->mbox_mem_pool);
}
@@ -2133,6 +2155,8 @@ lpfc_online(struct lpfc_hba *phba)
vports[i]->fc_flag &= ~FC_OFFLINE_MODE;
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -2807,6 +2831,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
return;
+ phba->fcoe_eventtag = acqe_link->event_tag;
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -2894,18 +2919,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
int rc;
+ phba->fcoe_eventtag = acqe_fcoe->event_tag;
switch (event_type) {
case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "2546 New FCF found index 0x%x tag 0x%x \n",
+ "2546 New FCF found index 0x%x tag 0x%x\n",
acqe_fcoe->fcf_index,
acqe_fcoe->event_tag);
/*
- * If the current FCF is in discovered state,
- * do nothing.
+ * If the current FCF is in discovered state, or
+ * FCF discovery is in progress do nothing.
*/
spin_lock_irq(&phba->hbalock);
- if (phba->fcf.fcf_flag & FCF_DISCOVERED) {
+ if ((phba->fcf.fcf_flag & FCF_DISCOVERED) ||
+ (phba->hba_flag & FCF_DISC_INPROGRESS)) {
spin_unlock_irq(&phba->hbalock);
break;
}
@@ -2922,7 +2949,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "2548 FCF Table full count 0x%x tag 0x%x \n",
+ "2548 FCF Table full count 0x%x tag 0x%x\n",
bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
acqe_fcoe->event_tag);
break;
@@ -2930,7 +2957,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
"2549 FCF disconnected fron network index 0x%x"
- " tag 0x%x \n", acqe_fcoe->fcf_index,
+ " tag 0x%x\n", acqe_fcoe->fcf_index,
acqe_fcoe->event_tag);
/* If the event is not for currently used fcf do nothing */
if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
@@ -4130,8 +4157,7 @@ lpfc_hba_alloc(struct pci_dev *pdev)
/* Allocate memory for HBA structure */
phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL);
if (!phba) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1417 Failed to allocate hba struct.\n");
+ dev_err(&pdev->dev, "failed to allocate hba struct\n");
return NULL;
}
@@ -4145,6 +4171,9 @@ lpfc_hba_alloc(struct pci_dev *pdev)
return NULL;
}
+ mutex_init(&phba->ct_event_mutex);
+ INIT_LIST_HEAD(&phba->ct_ev_waiters);
+
return phba;
}
@@ -4489,23 +4518,6 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
if (!phba->sli4_hba.STAregaddr)
return -ENODEV;
- /* With uncoverable error, log the error message and return error */
- onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
- onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
- if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
- uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
- uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
- if (uerrlo_reg.word0 || uerrhi_reg.word0) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1422 HBA Unrecoverable error: "
- "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
- "online0_reg=0x%x, online1_reg=0x%x\n",
- uerrlo_reg.word0, uerrhi_reg.word0,
- onlnreg0, onlnreg1);
- }
- return -ENODEV;
- }
-
/* Wait up to 30 seconds for the SLI Port POST done and ready */
for (i = 0; i < 3000; i++) {
sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
@@ -4545,6 +4557,23 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
+ /* With uncoverable error, log the error message and return error */
+ onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
+ onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
+ if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
+ uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
+ uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
+ if (uerrlo_reg.word0 || uerrhi_reg.word0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "1422 HBA Unrecoverable error: "
+ "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+ "online0_reg=0x%x, online1_reg=0x%x\n",
+ uerrlo_reg.word0, uerrhi_reg.word0,
+ onlnreg0, onlnreg1);
+ }
+ return -ENODEV;
+ }
+
return port_error;
}
@@ -7347,6 +7376,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Perform post initialization setup */
lpfc_post_init_setup(phba);
+ /* Check if there are static vports to be created. */
+ lpfc_create_static_vport(phba);
+
return 0;
out_disable_intr:
@@ -7636,19 +7668,17 @@ static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
{
int rc;
- uint16_t dev_id;
+ struct lpfc_sli_intf intf;
- if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id))
+ if (pci_read_config_dword(pdev, LPFC_SLIREV_CONF_WORD, &intf.word0))
return -ENODEV;
- switch (dev_id) {
- case PCI_DEVICE_ID_TIGERSHARK:
+ if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) &&
+ (bf_get(lpfc_sli_intf_rev, &intf) == LPFC_SLIREV_CONF_SLI4))
rc = lpfc_pci_probe_one_s4(pdev, pid);
- break;
- default:
+ else
rc = lpfc_pci_probe_one_s3(pdev, pid);
- break;
- }
+
return rc;
}
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 3423571dd1b3..1ab405902a18 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -52,48 +52,85 @@
* This routine prepares the mailbox command for dumping list of static
* vports to be created.
**/
-void
+int
lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
uint16_t offset)
{
MAILBOX_t *mb;
- void *ctx;
+ struct lpfc_dmabuf *mp;
mb = &pmb->u.mb;
- ctx = pmb->context2;
/* Setup to dump vport info region */
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb->mbxCommand = MBX_DUMP_MEMORY;
- mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.entry_index = offset;
mb->un.varDmp.region_id = DMP_REGION_VPORT;
- mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
- mb->un.varDmp.co = 0;
- mb->un.varDmp.resp_offset = 0;
- pmb->context2 = ctx;
mb->mbxOwner = OWN_HOST;
- return;
+ /* For SLI3 HBAs data is embedded in mailbox */
+ if (phba->sli_rev != LPFC_SLI_REV4) {
+ mb->un.varDmp.cv = 1;
+ mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
+ return 0;
+ }
+
+ /* For SLI4 HBAs driver need to allocate memory */
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (mp)
+ mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+
+ if (!mp || !mp->virt) {
+ kfree(mp);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "2605 lpfc_dump_static_vport: memory"
+ " allocation failed\n");
+ return 1;
+ }
+ memset(mp->virt, 0, LPFC_BPL_SIZE);
+ INIT_LIST_HEAD(&mp->list);
+ /* save address for completion */
+ pmb->context2 = (uint8_t *) mp;
+ mb->un.varWords[3] = putPaddrLow(mp->phys);
+ mb->un.varWords[4] = putPaddrHigh(mp->phys);
+ mb->un.varDmp.sli4_length = sizeof(struct static_vport_info);
+
+ return 0;
+}
+
+/**
+ * lpfc_down_link - Bring down HBAs link.
+ * @phba: pointer to lpfc hba data structure.
+ * @pmb: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine prepares a mailbox command to bring down HBA link.
+ **/
+void
+lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb;
+ memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+ mb = &pmb->u.mb;
+ mb->mbxCommand = MBX_DOWN_LINK;
+ mb->mbxOwner = OWN_HOST;
}
/**
- * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory
+ * lpfc_dump_mem - Prepare a mailbox command for reading a region.
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
- * @offset: offset for dumping VPD memory mailbox command.
+ * @offset: offset into the region.
+ * @region_id: config region id.
*
* The dump mailbox command provides a method for the device driver to obtain
* various types of information from the HBA device.
*
- * This routine prepares the mailbox command for dumping HBA Vital Product
- * Data (VPD) memory. This mailbox command is to be used for retrieving a
- * portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address
- * offset specified by the offset parameter.
+ * This routine prepares the mailbox command for dumping HBA's config region.
**/
void
-lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
+lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset,
+ uint16_t region_id)
{
MAILBOX_t *mb;
void *ctx;
@@ -107,7 +144,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.entry_index = offset;
- mb->un.varDmp.region_id = DMP_REGION_VPD;
+ mb->un.varDmp.region_id = region_id;
mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t));
mb->un.varDmp.co = 0;
mb->un.varDmp.resp_offset = 0;
@@ -1789,6 +1826,7 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
/**
* lpfc_init_vpi - Initialize the INIT_VPI mailbox command
+ * @phba: pointer to the hba structure to init the VPI for.
* @mbox: pointer to lpfc mbox command to initialize.
* @vpi: VPI to be initialized.
*
@@ -1799,11 +1837,14 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
* successful virtual NPort login.
**/
void
-lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi)
+lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi)
{
memset(mbox, 0, sizeof(*mbox));
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI);
- bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi);
+ bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi,
+ vpi + phba->vpi_base);
+ bf_set(lpfc_init_vpi_vfi, &mbox->u.mqe.un.init_vpi,
+ phba->pport->vfi + phba->vfi_base);
}
/**
@@ -1852,7 +1893,7 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba,
/* dump_fcoe_param failed to allocate memory */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"2569 lpfc_dump_fcoe_param: memory"
- " allocation failed \n");
+ " allocation failed\n");
return 1;
}
@@ -1864,8 +1905,8 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba,
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.type = DMP_NV_PARAMS;
- mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM;
- mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE;
+ mb->un.varDmp.region_id = DMP_REGION_23;
+ mb->un.varDmp.sli4_length = DMP_RGN23_SIZE;
mb->un.varWords[3] = putPaddrLow(mp->phys);
mb->un.varWords[4] = putPaddrHigh(mp->phys);
return 0;
@@ -1938,9 +1979,7 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
memset(mbox, 0, sizeof(*mbox));
resume_rpi = &mbox->u.mqe.un.resume_rpi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
- bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi);
- bf_set(lpfc_resume_rpi_vpi, resume_rpi,
- ndlp->vport->vpi + ndlp->vport->phba->vpi_base);
- bf_set(lpfc_resume_rpi_vfi, resume_rpi,
- ndlp->vport->vfi + ndlp->vport->phba->vfi_base);
+ bf_set(lpfc_resume_rpi_index, resume_rpi, ndlp->nlp_rpi);
+ bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI);
+ resume_rpi->event_tag = ndlp->phba->fc_eventTag;
}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index e198c917c13e..a1b6db6016da 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -110,17 +110,28 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
sizeof(struct lpfc_nodelist));
if (!phba->nlp_mem_pool)
goto fail_free_mbox_pool;
- phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
+
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
phba->pcidev,
LPFC_HDR_BUF_SIZE, align, 0);
- if (!phba->lpfc_hrb_pool)
- goto fail_free_nlp_mem_pool;
- phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
+ if (!phba->lpfc_hrb_pool)
+ goto fail_free_nlp_mem_pool;
+
+ phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
phba->pcidev,
LPFC_DATA_BUF_SIZE, align, 0);
- if (!phba->lpfc_drb_pool)
- goto fail_free_hbq_pool;
-
+ if (!phba->lpfc_drb_pool)
+ goto fail_free_hrb_pool;
+ phba->lpfc_hbq_pool = NULL;
+ } else {
+ phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",
+ phba->pcidev, LPFC_BPL_SIZE, align, 0);
+ if (!phba->lpfc_hbq_pool)
+ goto fail_free_nlp_mem_pool;
+ phba->lpfc_hrb_pool = NULL;
+ phba->lpfc_drb_pool = NULL;
+ }
/* vpi zero is reserved for the physical port so add 1 to max */
longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
@@ -132,7 +143,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
fail_free_dbq_pool:
pci_pool_destroy(phba->lpfc_drb_pool);
phba->lpfc_drb_pool = NULL;
- fail_free_hbq_pool:
+ fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
fail_free_nlp_mem_pool:
@@ -176,11 +187,17 @@ lpfc_mem_free(struct lpfc_hba *phba)
/* Free HBQ pools */
lpfc_sli_hbqbuf_free_all(phba);
- pci_pool_destroy(phba->lpfc_drb_pool);
+ if (phba->lpfc_drb_pool)
+ pci_pool_destroy(phba->lpfc_drb_pool);
phba->lpfc_drb_pool = NULL;
- pci_pool_destroy(phba->lpfc_hrb_pool);
+ if (phba->lpfc_hrb_pool)
+ pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
+ if (phba->lpfc_hbq_pool)
+ pci_pool_destroy(phba->lpfc_hbq_pool);
+ phba->lpfc_hbq_pool = NULL;
+
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
@@ -380,7 +397,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
if (!hbqbp)
return NULL;
- hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
+ hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
&hbqbp->dbuf.phys);
if (!hbqbp->dbuf.virt) {
kfree(hbqbp);
@@ -405,7 +422,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
void
lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
{
- pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+ pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
kfree(hbqbp);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h
index 27d1a88a98fe..d655ed3eebef 100644
--- a/drivers/scsi/lpfc/lpfc_nl.h
+++ b/drivers/scsi/lpfc/lpfc_nl.h
@@ -177,3 +177,23 @@ struct temp_event {
uint32_t data;
};
+/* bsg definitions */
+#define LPFC_BSG_VENDOR_SET_CT_EVENT 1
+#define LPFC_BSG_VENDOR_GET_CT_EVENT 2
+
+struct set_ct_event {
+ uint32_t command;
+ uint32_t ev_req_id;
+ uint32_t ev_reg_id;
+};
+
+struct get_ct_event {
+ uint32_t command;
+ uint32_t ev_reg_id;
+ uint32_t ev_req_id;
+};
+
+struct get_ct_event_reply {
+ uint32_t immed_data;
+ uint32_t type;
+};
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index da59c4f0168f..61d089703806 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -2142,7 +2142,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
} else if (resp_info & RESID_OVER) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"9028 FCP command x%x residual overrun error. "
- "Data: x%x x%x \n", cmnd->cmnd[0],
+ "Data: x%x x%x\n", cmnd->cmnd[0],
scsi_bufflen(cmnd), scsi_get_resid(cmnd));
host_status = DID_ERROR;
@@ -2843,7 +2843,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
dif_op_str[scsi_get_prot_op(cmnd)]);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9034 BLKGRD: CDB: %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x \n",
+ "%02x %02x %02x %02x %02x\n",
cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
@@ -2871,7 +2871,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
dif_op_str[scsi_get_prot_op(cmnd)]);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9039 BLKGRD: CDB: %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x \n",
+ "%02x %02x %02x %02x %02x\n",
cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
@@ -3584,6 +3584,7 @@ struct scsi_host_template lpfc_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
+ .vendor_id = LPFC_NL_VENDOR_ID,
};
struct scsi_host_template lpfc_vport_template = {
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index acc43b061ba1..43cbe336f1f8 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4139,7 +4139,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
return -EIO;
}
data_length = mqe->un.mb_words[5];
- if (data_length > DMP_FCOEPARAM_RGN_SIZE) {
+ if (data_length > DMP_RGN23_SIZE) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
return -EIO;
@@ -4304,7 +4304,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
*/
if (lpfc_sli4_read_fcoe_params(phba, mboxq))
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
- "2570 Failed to read FCoE parameters \n");
+ "2570 Failed to read FCoE parameters\n");
/* Issue READ_REV to collect vpd and FW information. */
vpd_size = PAGE_SIZE;
@@ -4522,12 +4522,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
lpfc_sli4_rb_setup(phba);
/* Start the ELS watchdog timer */
- /*
- * The driver for SLI4 is not yet ready to process timeouts
- * or interrupts. Once it is, the comment bars can be removed.
- */
- /* mod_timer(&vport->els_tmofunc,
- * jiffies + HZ * (phba->fc_ratov*2)); */
+ mod_timer(&vport->els_tmofunc,
+ jiffies + HZ * (phba->fc_ratov * 2));
/* Start heart beat timer */
mod_timer(&phba->hb_tmofunc,
@@ -4706,13 +4702,13 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
spin_lock_irqsave(&phba->hbalock, drvr_flag);
if (!pmbox) {
+ phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
/* processing mbox queue from intr_handler */
if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
return MBX_SUCCESS;
}
processing_queue = 1;
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
pmbox = lpfc_mbox_get(phba);
if (!pmbox) {
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
@@ -5279,6 +5275,18 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
unsigned long iflags;
int rc;
+ rc = lpfc_mbox_dev_check(phba);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "(%d):2544 Mailbox command x%x (x%x) "
+ "cannot issue Data: x%x x%x\n",
+ mboxq->vport ? mboxq->vport->vpi : 0,
+ mboxq->u.mb.mbxCommand,
+ lpfc_sli4_mbox_opcode_get(phba, mboxq),
+ psli->sli_flag, flag);
+ goto out_not_finished;
+ }
+
/* Detect polling mode and jump to a handler */
if (!phba->sli4_hba.intr_enable) {
if (flag == MBX_POLL)
@@ -5338,17 +5346,6 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
psli->sli_flag, flag);
goto out_not_finished;
}
- rc = lpfc_mbox_dev_check(phba);
- if (unlikely(rc)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "(%d):2544 Mailbox command x%x (x%x) "
- "cannot issue Data: x%x x%x\n",
- mboxq->vport ? mboxq->vport->vpi : 0,
- mboxq->u.mb.mbxCommand,
- lpfc_sli4_mbox_opcode_get(phba, mboxq),
- psli->sli_flag, flag);
- goto out_not_finished;
- }
/* Put the mailbox command to the driver internal FIFO */
psli->slistat.mbox_busy++;
@@ -5817,19 +5814,21 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
/**
* lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
* @phba: Pointer to HBA context object.
- * @piocb: Pointer to command iocb.
*
* This routine performs a round robin SCSI command to SLI4 FCP WQ index
- * distribution.
+ * distribution. This is called by __lpfc_sli_issue_iocb_s4() with the hbalock
+ * held.
*
* Return: index into SLI4 fast-path FCP queue index.
**/
static uint32_t
-lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
+lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba)
{
- static uint32_t fcp_qidx;
+ ++phba->fcp_qidx;
+ if (phba->fcp_qidx >= phba->cfg_fcp_wq_count)
+ phba->fcp_qidx = 0;
- return fcp_qidx++ % phba->cfg_fcp_wq_count;
+ return phba->fcp_qidx;
}
/**
@@ -6156,7 +6155,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if (piocb->iocb_flag & LPFC_IO_FCP) {
- fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb);
+ fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
return IOCB_ERROR;
} else {
@@ -6327,7 +6326,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
KERN_ERR,
LOG_SLI,
"0346 Ring %d handler: unexpected ASYNC_STATUS"
- " evt_code 0x%x \n"
+ " evt_code 0x%x\n"
"W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n"
"W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n"
"W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n"
@@ -6790,6 +6789,33 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
/**
+ * lpfc_sli_bemem_bcopy - SLI memory copy function
+ * @srcp: Source memory pointer.
+ * @destp: Destination memory pointer.
+ * @cnt: Number of words required to be copied.
+ *
+ * This function is used for copying data between a data structure
+ * with big endian representation to local endianness.
+ * This function can be called with or without lock.
+ **/
+void
+lpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt)
+{
+ uint32_t *src = srcp;
+ uint32_t *dest = destp;
+ uint32_t ldata;
+ int i;
+
+ for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) {
+ ldata = *src;
+ ldata = be32_to_cpu(ldata);
+ *dest = ldata;
+ src++;
+ dest++;
+ }
+}
+
+/**
* lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq
* @phba: Pointer to HBA context object.
* @pring: Pointer to driver SLI ring object.
@@ -7678,12 +7704,6 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
"online0_reg=0x%x, online1_reg=0x%x\n",
uerr_sta_lo, uerr_sta_hi,
onlnreg0, onlnreg1);
- /* TEMP: as the driver error recover logic is not
- * fully developed, we just log the error message
- * and the device error attention action is now
- * temporarily disabled.
- */
- return 0;
phba->work_status[0] = uerr_sta_lo;
phba->work_status[1] = uerr_sta_hi;
/* Set the driver HA work bitmap */
@@ -9499,8 +9519,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
eq->host_index = 0;
eq->hba_index = 0;
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@@ -9604,10 +9623,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
cq->host_index = 0;
cq->hba_index = 0;
-out:
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
+out:
+ mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@@ -9712,8 +9730,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
/* link the mq onto the parent cq child list */
list_add_tail(&mq->list, &cq->child_list);
out:
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@@ -9795,8 +9812,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
/* link the wq onto the parent cq child list */
list_add_tail(&wq->list, &cq->child_list);
out:
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@@ -9970,8 +9986,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
list_add_tail(&drq->list, &cq->child_list);
out:
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@@ -10026,8 +10041,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq)
/* Remove eq from any list */
list_del_init(&eq->list);
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, eq->phba->mbox_mem_pool);
+ mempool_free(mbox, eq->phba->mbox_mem_pool);
return status;
}
@@ -10080,8 +10094,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq)
}
/* Remove cq from any list */
list_del_init(&cq->list);
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, cq->phba->mbox_mem_pool);
+ mempool_free(mbox, cq->phba->mbox_mem_pool);
return status;
}
@@ -10134,8 +10147,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq)
}
/* Remove mq from any list */
list_del_init(&mq->list);
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, mq->phba->mbox_mem_pool);
+ mempool_free(mbox, mq->phba->mbox_mem_pool);
return status;
}
@@ -10187,8 +10199,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
}
/* Remove wq from any list */
list_del_init(&wq->list);
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, wq->phba->mbox_mem_pool);
+ mempool_free(mbox, wq->phba->mbox_mem_pool);
return status;
}
@@ -10258,8 +10269,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
}
list_del_init(&hrq->list);
list_del_init(&drq->list);
- if (rc != MBX_TIMEOUT)
- mempool_free(mbox, hrq->phba->mbox_mem_pool);
+ mempool_free(mbox, hrq->phba->mbox_mem_pool);
return status;
}
@@ -10933,6 +10943,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
first_iocbq = lpfc_sli_get_iocbq(vport->phba);
if (first_iocbq) {
/* Initialize the first IOCB. */
+ first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
@@ -10945,6 +10956,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.un.rcvels.remoteID = sid;
+ first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
+ bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
}
iocbq = first_iocbq;
/*
@@ -10961,6 +10974,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.ulpBdeCount++;
iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
+ first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
+ bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
} else {
iocbq = lpfc_sli_get_iocbq(vport->phba);
if (!iocbq) {
@@ -10978,6 +10993,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.ulpBdeCount = 1;
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
+ first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
+ bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
iocbq->iocb.un.rcvels.remoteID = sid;
list_add_tail(&iocbq->list, &first_iocbq->list);
}
@@ -11324,7 +11341,7 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq)
return -ENOMEM;
- lpfc_init_vpi(mboxq, vpi);
+ lpfc_init_vpi(phba, mboxq, vpi);
mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
if (rc != MBX_TIMEOUT)
@@ -11519,6 +11536,7 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
uint32_t alloc_len, req_len;
struct lpfc_mbx_read_fcf_tbl *read_fcf;
+ phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag;
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -11570,7 +11588,140 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
if (rc == MBX_NOT_FINISHED) {
lpfc_sli4_mbox_cmd_free(phba, mboxq);
error = -EIO;
- } else
+ } else {
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= FCF_DISC_INPROGRESS;
+ spin_unlock_irq(&phba->hbalock);
error = 0;
+ }
return error;
}
+
+/**
+ * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function read region 23 and parse TLV for port status to
+ * decide if the user disaled the port. If the TLV indicates the
+ * port is disabled, the hba_flag is set accordingly.
+ **/
+void
+lpfc_sli_read_link_ste(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *pmb = NULL;
+ MAILBOX_t *mb;
+ uint8_t *rgn23_data = NULL;
+ uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset;
+ int rc;
+
+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2600 lpfc_sli_read_serdes_param failed to"
+ " allocate mailbox memory\n");
+ goto out;
+ }
+ mb = &pmb->u.mb;
+
+ /* Get adapter Region 23 data */
+ rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL);
+ if (!rgn23_data)
+ goto out;
+
+ do {
+ lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23);
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2601 lpfc_sli_read_link_ste failed to"
+ " read config region 23 rc 0x%x Status 0x%x\n",
+ rc, mb->mbxStatus);
+ mb->un.varDmp.word_cnt = 0;
+ }
+ /*
+ * dump mem may return a zero when finished or we got a
+ * mailbox error, either way we are done.
+ */
+ if (mb->un.varDmp.word_cnt == 0)
+ break;
+ if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset)
+ mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset;
+
+ lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
+ rgn23_data + offset,
+ mb->un.varDmp.word_cnt);
+ offset += mb->un.varDmp.word_cnt;
+ } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE);
+
+ data_size = offset;
+ offset = 0;
+
+ if (!data_size)
+ goto out;
+
+ /* Check the region signature first */
+ if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2619 Config region 23 has bad signature\n");
+ goto out;
+ }
+ offset += 4;
+
+ /* Check the data structure version */
+ if (rgn23_data[offset] != LPFC_REGION23_VERSION) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2620 Config region 23 has bad version\n");
+ goto out;
+ }
+ offset += 4;
+
+ /* Parse TLV entries in the region */
+ while (offset < data_size) {
+ if (rgn23_data[offset] == LPFC_REGION23_LAST_REC)
+ break;
+ /*
+ * If the TLV is not driver specific TLV or driver id is
+ * not linux driver id, skip the record.
+ */
+ if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) ||
+ (rgn23_data[offset + 2] != LINUX_DRIVER_ID) ||
+ (rgn23_data[offset + 3] != 0)) {
+ offset += rgn23_data[offset + 1] * 4 + 4;
+ continue;
+ }
+
+ /* Driver found a driver specific TLV in the config region */
+ sub_tlv_len = rgn23_data[offset + 1] * 4;
+ offset += 4;
+ tlv_offset = 0;
+
+ /*
+ * Search for configured port state sub-TLV.
+ */
+ while ((offset < data_size) &&
+ (tlv_offset < sub_tlv_len)) {
+ if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) {
+ offset += 4;
+ tlv_offset += 4;
+ break;
+ }
+ if (rgn23_data[offset] != PORT_STE_TYPE) {
+ offset += rgn23_data[offset + 1] * 4 + 4;
+ tlv_offset += rgn23_data[offset + 1] * 4 + 4;
+ continue;
+ }
+
+ /* This HBA contains PORT_STE configured */
+ if (!rgn23_data[offset + 2])
+ phba->hba_flag |= LINK_DISABLED;
+
+ goto out;
+ }
+ }
+out:
+ if (pmb)
+ mempool_free(pmb, phba->mbox_mem_pool);
+ kfree(rgn23_data);
+ return;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 3b276b47d18f..b5f4ba1a5c27 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -132,6 +132,7 @@ struct lpfc_sli4_link {
struct lpfc_fcf {
uint8_t fabric_name[8];
+ uint8_t switch_name[8];
uint8_t mac_addr[6];
uint16_t fcf_indx;
uint16_t fcfi;
@@ -150,6 +151,10 @@ struct lpfc_fcf {
#define LPFC_REGION23_SIGNATURE "RG23"
#define LPFC_REGION23_VERSION 1
#define LPFC_REGION23_LAST_REC 0xff
+#define DRIVER_SPECIFIC_TYPE 0xA2
+#define LINUX_DRIVER_ID 0x20
+#define PORT_STE_TYPE 0x1
+
struct lpfc_fip_param_hdr {
uint8_t type;
#define FCOE_PARAM_TYPE 0xA0
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 41094e02304b..9ae20af4bdb7 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.3"
+#define LPFC_DRIVER_VERSION "8.3.4"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index e0b49922193e..606efa767548 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -313,22 +313,6 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
goto error_out;
}
- /*
- * In SLI4, the vpi must be activated before it can be used
- * by the port.
- */
- if (phba->sli_rev == LPFC_SLI_REV4) {
- rc = lpfc_sli4_init_vpi(phba, vpi);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "1838 Failed to INIT_VPI on vpi %d "
- "status %d\n", vpi, rc);
- rc = VPORT_NORESOURCES;
- lpfc_free_vpi(phba, vpi);
- goto error_out;
- }
- }
-
/* Assign an unused board number */
if ((instance = lpfc_get_instance()) < 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
@@ -367,12 +351,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
goto error_out;
}
- memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
- memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
- if (fc_vport->node_name != 0)
- u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
- if (fc_vport->port_name != 0)
- u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
+ u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
+ u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
@@ -404,7 +384,34 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
+ /*
+ * In SLI4, the vpi must be activated before it can be used
+ * by the port.
+ */
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (pport->vfi_state & LPFC_VFI_REGISTERED)) {
+ rc = lpfc_sli4_init_vpi(phba, vpi);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "1838 Failed to INIT_VPI on vpi %d "
+ "status %d\n", vpi, rc);
+ rc = VPORT_NORESOURCES;
+ lpfc_free_vpi(phba, vpi);
+ goto error_out;
+ }
+ } else if (phba->sli_rev == LPFC_SLI_REV4) {
+ /*
+ * Driver cannot INIT_VPI now. Set the flags to
+ * init_vpi when reg_vfi complete.
+ */
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ rc = VPORT_OK;
+ goto out;
+ }
+
if ((phba->link_state < LPFC_LINK_UP) ||
+ (pport->port_state < LPFC_FABRIC_CFG_LINK) ||
(phba->fc_topology == TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
@@ -661,7 +668,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
lpfc_printf_log(vport->phba, KERN_WARNING,
LOG_VPORT,
"1829 CT command failed to "
- "delete objects on fabric. \n");
+ "delete objects on fabric\n");
}
/* First look for the Fabric ndlp */
ndlp = lpfc_findnode_did(vport, Fabric_DID);
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 7dc3d1894b1a..a39addc3a596 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -718,7 +718,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
* megasas_build_ldio - Prepares IOs to logical devices
* @instance: Adapter soft state
* @scp: SCSI command
- * @cmd: Command to to be prepared
+ * @cmd: Command to be prepared
*
* Frames (and accompanying SGLs) for regular SCSI IOs use this function.
*/
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 286c185fa9e4..fa85253e2f67 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -434,7 +434,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @ioc_reset_in_progress: host reset in progress
* @ioc_reset_in_progress_lock:
* @ioc_link_reset_in_progress: phy/hard reset in progress
- * @ignore_loginfos: ignore loginfos during task managment
+ * @ignore_loginfos: ignore loginfos during task management
* @remove_host: flag for when driver unloads, to avoid sending dev resets
* @wait_for_port_enable_to_complete:
* @msix_enable: flag indicating msix is enabled
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 2a01a5f2a84d..e849fc7e834b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2633,7 +2633,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
return 0;
}
- /* see if we are busy with task managment stuff */
+ /* see if we are busy with task management stuff */
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (sas_target_priv_data->tm_busy ||
ioc->shost_recovery || ioc->ioc_link_reset_in_progress) {
@@ -5857,7 +5857,7 @@ _scsih_init(void)
/* queuecommand callback hander */
scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
- /* task managment callback handler */
+ /* task management callback handler */
tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
/* base internal commands callback handler */
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 00aa48d975a6..9fde8bfe7607 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1482,7 +1482,7 @@ typedef union {
uint8_t domain;
uint8_t area;
uint8_t al_pa;
-#elif __LITTLE_ENDIAN
+#elif defined(__LITTLE_ENDIAN)
uint8_t al_pa;
uint8_t area;
uint8_t domain;
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index fcc184cd066d..cbceb0ebabf7 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -15,19 +15,18 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
uint32_t cnt;
uint8_t *c = b;
- printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
+ printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
"Fh\n");
printk("------------------------------------------------------------"
"--\n");
- for (cnt = 0; cnt < size; cnt++, c++) {
- printk(KERN_DEBUG "%02x", *c);
- if (!(cnt % 16))
- printk(KERN_DEBUG "\n");
+ for (cnt = 0; cnt < size; c++) {
+ printk(KERN_INFO "%02x", *c);
+ if (!(++cnt % 16))
+ printk(KERN_INFO "\n");
else
- printk(KERN_DEBUG " ");
+ printk(KERN_INFO " ");
}
- if (cnt % 16)
- printk(KERN_DEBUG "\n");
+ printk(KERN_INFO "\n");
}
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index b586f27c3bd4..81b5f29254e2 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -100,7 +100,6 @@
#define MAX_SRBS MAX_CMDS_TO_RISC
#define MBOX_AEN_REG_COUNT 5
#define MAX_INIT_RETRIES 5
-#define IOCB_HIWAT_CUSHION 16
/*
* Buffer sizes
@@ -184,6 +183,11 @@ struct srb {
uint16_t cc_stat;
u_long r_start; /* Time we recieve a cmd from OS */
u_long u_start; /* Time when we handed the cmd to F/W */
+
+ /* Used for extended sense / status continuation */
+ uint8_t *req_sense_ptr;
+ uint16_t req_sense_len;
+ uint16_t reserved2;
};
/*
@@ -302,7 +306,6 @@ struct scsi_qla_host {
uint32_t tot_ddbs;
uint16_t iocb_cnt;
- uint16_t iocb_hiwat;
/* SRB cache. */
#define SRB_MIN_REQ 128
@@ -436,6 +439,8 @@ struct scsi_qla_host {
/* Map ddb_list entry by FW ddb index */
struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
+ /* Saved srb for status continuation entry processing */
+ struct srb *status_srb;
};
static inline int is_qla4010(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 1b667a70cffa..9cd7a608df38 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -572,6 +572,7 @@ struct conn_event_log_entry {
*************************************************************************/
#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
+#define IOCB_MAX_EXT_SENSEDATA_LEN 60 /* Bytes of extended sense data */
/* IOCB header structure */
struct qla4_header {
@@ -733,6 +734,12 @@ struct status_entry {
};
+/* Status Continuation entry */
+struct status_cont_entry {
+ struct qla4_header hdr; /* 00-03 */
+ uint8_t ext_sense_data[IOCB_MAX_EXT_SENSEDATA_LEN]; /* 04-63 */
+};
+
struct passthru0 {
struct qla4_header hdr; /* 00-03 */
uint32_t handle; /* 04-07 */
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 912a67494adf..e0c32159749c 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -10,9 +10,42 @@
#include "ql4_dbg.h"
#include "ql4_inline.h"
-
#include <scsi/scsi_tcq.h>
+static int
+qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt)
+{
+ uint16_t cnt;
+
+ /* Calculate number of free request entries. */
+ if ((req_cnt + 2) >= ha->req_q_count) {
+ cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+ if (ha->request_in < cnt)
+ ha->req_q_count = cnt - ha->request_in;
+ else
+ ha->req_q_count = REQUEST_QUEUE_DEPTH -
+ (ha->request_in - cnt);
+ }
+
+ /* Check if room for request in request ring. */
+ if ((req_cnt + 2) < ha->req_q_count)
+ return 1;
+ else
+ return 0;
+}
+
+static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha)
+{
+ /* Advance request queue pointer */
+ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ ha->request_in++;
+ ha->request_ptr++;
+ }
+}
+
/**
* qla4xxx_get_req_pkt - returns a valid entry in request queue.
* @ha: Pointer to host adapter structure.
@@ -26,35 +59,18 @@
static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
struct queue_entry **queue_entry)
{
- uint16_t request_in;
- uint8_t status = QLA_SUCCESS;
-
- *queue_entry = ha->request_ptr;
+ uint16_t req_cnt = 1;
- /* get the latest request_in and request_out index */
- request_in = ha->request_in;
- ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
-
- /* Advance request queue pointer and check for queue full */
- if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
- request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else {
- request_in++;
- ha->request_ptr++;
- }
-
- /* request queue is full, try again later */
- if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
- /* restore request pointer */
- ha->request_ptr = *queue_entry;
- status = QLA_ERROR;
- } else {
- ha->request_in = request_in;
+ if (qla4xxx_space_in_req_ring(ha, req_cnt)) {
+ *queue_entry = ha->request_ptr;
memset(*queue_entry, 0, sizeof(**queue_entry));
+
+ qla4xxx_advance_req_ring_ptr(ha);
+ ha->req_q_count -= req_cnt;
+ return QLA_SUCCESS;
}
- return status;
+ return QLA_ERROR;
}
/**
@@ -100,21 +116,14 @@ exit_send_marker:
return status;
}
-static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
- struct scsi_qla_host *ha)
+static struct continuation_t1_entry *
+qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha)
{
struct continuation_t1_entry *cont_entry;
cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
- /* Advance request queue pointer */
- if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
- ha->request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else {
- ha->request_in++;
- ha->request_ptr++;
- }
+ qla4xxx_advance_req_ring_ptr(ha);
/* Load packet defaults */
cont_entry->hdr.entryType = ET_CONTINUE;
@@ -197,13 +206,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
struct scsi_cmnd *cmd = srb->cmd;
struct ddb_entry *ddb_entry;
struct command_t3_entry *cmd_entry;
-
int nseg;
uint16_t tot_dsds;
uint16_t req_cnt;
-
unsigned long flags;
- uint16_t cnt;
uint32_t index;
char tag[2];
@@ -217,6 +223,19 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
index = (uint32_t)cmd->request->tag;
+ /*
+ * Check to see if adapter is online before placing request on
+ * request queue. If a reset occurs and a request is in the queue,
+ * the firmware will still attempt to process the request, retrieving
+ * garbage for pointers.
+ */
+ if (!test_bit(AF_ONLINE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
+ "Do not issue command.\n",
+ ha->host_no, __func__));
+ goto queuing_error;
+ }
+
/* Calculate the number of request entries needed. */
nseg = scsi_dma_map(cmd);
if (nseg < 0)
@@ -224,17 +243,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
tot_dsds = nseg;
req_cnt = qla4xxx_calc_request_entries(tot_dsds);
-
- if (ha->req_q_count < (req_cnt + 2)) {
- cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
- if (ha->request_in < cnt)
- ha->req_q_count = cnt - ha->request_in;
- else
- ha->req_q_count = REQUEST_QUEUE_DEPTH -
- (ha->request_in - cnt);
- }
-
- if (ha->req_q_count < (req_cnt + 2))
+ if (!qla4xxx_space_in_req_ring(ha, req_cnt))
goto queuing_error;
/* total iocbs active */
@@ -286,32 +295,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
break;
}
-
- /* Advance request queue pointer */
- ha->request_in++;
- if (ha->request_in == REQUEST_QUEUE_DEPTH) {
- ha->request_in = 0;
- ha->request_ptr = ha->request_ring;
- } else
- ha->request_ptr++;
-
-
+ qla4xxx_advance_req_ring_ptr(ha);
qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
wmb();
- /*
- * Check to see if adapter is online before placing request on
- * request queue. If a reset occurs and a request is in the queue,
- * the firmware will still attempt to process the request, retrieving
- * garbage for pointers.
- */
- if (!test_bit(AF_ONLINE, &ha->flags)) {
- DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
- "Do not issue command.\n",
- ha->host_no, __func__));
- goto queuing_error;
- }
-
srb->cmd->host_scribble = (unsigned char *)srb;
/* update counters */
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 799120fcb9be..8025ee16588e 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -11,6 +11,98 @@
#include "ql4_inline.h"
/**
+ * qla4xxx_copy_sense - copy sense data into cmd sense buffer
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ * @srb: Pointer to srb structure.
+ **/
+static void qla4xxx_copy_sense(struct scsi_qla_host *ha,
+ struct status_entry *sts_entry,
+ struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+ uint16_t sense_len;
+
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sense_len == 0)
+ return;
+
+ /* Save total available sense length,
+ * not to exceed cmd's sense buffer size */
+ sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);
+ srb->req_sense_ptr = cmd->sense_buffer;
+ srb->req_sense_len = sense_len;
+
+ /* Copy sense from sts_entry pkt */
+ sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN);
+ memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len);
+
+ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[7],
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+
+ DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len));
+ srb->flags |= SRB_GOT_SENSE;
+
+ /* Update srb, in case a sts_cont pkt follows */
+ srb->req_sense_ptr += sense_len;
+ srb->req_sense_len -= sense_len;
+ if (srb->req_sense_len != 0)
+ ha->status_srb = srb;
+ else
+ ha->status_srb = NULL;
+}
+
+/**
+ * qla4xxx_status_cont_entry - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @sts_cont: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
+ struct status_cont_entry *sts_cont)
+{
+ struct srb *srb = ha->status_srb;
+ struct scsi_cmnd *cmd;
+ uint8_t sense_len;
+
+ if (srb == NULL)
+ return;
+
+ cmd = srb->cmd;
+ if (cmd == NULL) {
+ DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned "
+ "back to OS srb=%p srb->state:%d\n", ha->host_no,
+ __func__, srb, srb->state));
+ ha->status_srb = NULL;
+ return;
+ }
+
+ /* Copy sense data. */
+ sense_len = min_t(uint16_t, srb->req_sense_len,
+ IOCB_MAX_EXT_SENSEDATA_LEN);
+ memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len);
+ DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len));
+
+ srb->req_sense_ptr += sense_len;
+ srb->req_sense_len -= sense_len;
+
+ /* Place command on done queue. */
+ if (srb->req_sense_len == 0) {
+ qla4xxx_srb_compl(ha, srb);
+ ha->status_srb = NULL;
+ }
+}
+
+/**
* qla4xxx_status_entry - processes status IOCBs
* @ha: Pointer to host adapter structure.
* @sts_entry: Pointer to status entry structure.
@@ -23,7 +115,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
struct srb *srb;
struct ddb_entry *ddb_entry;
uint32_t residual;
- uint16_t sensebytecnt;
srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
if (!srb) {
@@ -92,24 +183,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
/* Copy Sense Data into sense buffer. */
- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
- sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
- if (sensebytecnt == 0)
- break;
-
- memcpy(cmd->sense_buffer, sts_entry->senseData,
- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- "ASC/ASCQ = %02x/%02x\n", ha->host_no,
- cmd->device->channel, cmd->device->id,
- cmd->device->lun, __func__,
- sts_entry->senseData[2] & 0x0f,
- sts_entry->senseData[12],
- sts_entry->senseData[13]));
-
- srb->flags |= SRB_GOT_SENSE;
+ qla4xxx_copy_sense(ha, sts_entry, srb);
break;
case SCS_INCOMPLETE:
@@ -176,23 +250,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
/* Copy Sense Data into sense buffer. */
- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
- sensebytecnt =
- le16_to_cpu(sts_entry->senseDataByteCnt);
- if (sensebytecnt == 0)
- break;
-
- memcpy(cmd->sense_buffer, sts_entry->senseData,
- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
- "ASC/ASCQ = %02x/%02x\n", ha->host_no,
- cmd->device->channel, cmd->device->id,
- cmd->device->lun, __func__,
- sts_entry->senseData[2] & 0x0f,
- sts_entry->senseData[12],
- sts_entry->senseData[13]));
+ qla4xxx_copy_sense(ha, sts_entry, srb);
} else {
/*
* If RISC reports underrun and target does not
@@ -268,9 +326,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
status_entry_exit:
- /* complete the request */
+ /* complete the request, if not waiting for status_continuation pkt */
srb->cc_stat = sts_entry->completionStatus;
- qla4xxx_srb_compl(ha, srb);
+ if (ha->status_srb == NULL)
+ qla4xxx_srb_compl(ha, srb);
}
/**
@@ -305,10 +364,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
/* process entry */
switch (sts_entry->hdr.entryType) {
case ET_STATUS:
- /*
- * Common status - Single completion posted in single
- * IOSB.
- */
+ /* Common status */
qla4xxx_status_entry(ha, sts_entry);
break;
@@ -316,9 +372,8 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
break;
case ET_STATUS_CONTINUATION:
- /* Just throw away the status continuation entries */
- DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
- "- ignoring\n", ha->host_no, __func__));
+ qla4xxx_status_cont_entry(ha,
+ (struct status_cont_entry *) sts_entry);
break;
case ET_COMMAND:
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 051b0f5e8c8e..09d6d4b76f39 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -385,16 +385,6 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
mbox_sts[0]));
return QLA_ERROR;
}
-
- /* High-water mark of IOCBs */
- ha->iocb_hiwat = mbox_sts[2];
- if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
- ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
- else
- dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
- "firmware IOCBs available (%d).\n",
- IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
-
return QLA_SUCCESS;
}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index ec9da6ce8489..83c8b5e4fc8b 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -66,6 +66,7 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
static int qla4xxx_host_get_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf);
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
/*
* SCSI host template entry points
@@ -89,6 +90,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.eh_device_reset_handler = qla4xxx_eh_device_reset,
.eh_target_reset_handler = qla4xxx_eh_target_reset,
.eh_host_reset_handler = qla4xxx_eh_host_reset,
+ .eh_timed_out = qla4xxx_eh_cmd_timed_out,
.slave_configure = qla4xxx_slave_configure,
.slave_alloc = qla4xxx_slave_alloc,
@@ -124,6 +126,21 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
static struct scsi_transport_template *qla4xxx_scsi_transport;
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = starget_to_session(scsi_target(sc->device));
+ ddb_entry = session->dd_data;
+
+ /* if we are not logged in then the LLD is going to clean up the cmd */
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
+ return BLK_EH_RESET_TIMER;
+ else
+ return BLK_EH_NOT_HANDLED;
+}
+
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
{
struct ddb_entry *ddb_entry = session->dd_data;
@@ -904,18 +921,17 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
/* Flush any pending ddb changed AENs */
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ qla4xxx_flush_active_srbs(ha);
+
/* Reset the firmware. If successful, function
* returns with ISP interrupts enabled.
*/
- if (status == QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
- ha->host_no, __func__));
- qla4xxx_flush_active_srbs(ha);
- if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
- status = qla4xxx_soft_reset(ha);
- else
- status = QLA_ERROR;
- }
+ DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
+ ha->host_no, __func__));
+ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+ status = qla4xxx_soft_reset(ha);
+ else
+ status = QLA_ERROR;
/* Flush any pending ddb changed AENs */
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
@@ -1406,7 +1422,7 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev)
/**
* qla4xxx_del_from_active_array - returns an active srb
* @ha: Pointer to host adapter structure.
- * @index: index into to the active_array
+ * @index: index into the active_array
*
* This routine removes and returns the srb at the specified index
**/
@@ -1484,7 +1500,7 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
/**
* qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
- * @ha: pointer to to HBA
+ * @ha: pointer to HBA
* @t: target id
* @l: lun id
*
@@ -1527,11 +1543,9 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
struct ddb_entry *ddb_entry = cmd->device->hostdata;
- struct srb *sp;
int ret = FAILED, stat;
- sp = (struct srb *) cmd->SCp.ptr;
- if (!sp || !ddb_entry)
+ if (!ddb_entry)
return ret;
dev_info(&ha->pdev->dev,
@@ -1644,7 +1658,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
dev_info(&ha->pdev->dev,
- "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+ "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
cmd->device->channel, cmd->device->id, cmd->device->lun);
if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index ab984cb89cea..6980cb279c81 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,5 +5,5 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8"
+#define QLA4XXX_DRIVER_VERSION "5.01.00-k9"
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f3c40898fc7d..5987da857103 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -896,9 +896,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
+ scsi_print_command(cmd);
}
- blk_end_request_all(req, -EIO);
- scsi_next_command(cmd);
+ if (blk_end_request_err(req, -EIO))
+ scsi_requeue_command(q, cmd);
+ else
+ scsi_next_command(cmd);
break;
case ACTION_REPREP:
/* Unprep the request and put it back at the head of the queue.
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 292c02f810d0..b98885de6876 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -291,7 +291,7 @@ static void fc_scsi_scan_rport(struct work_struct *work);
#define FC_STARGET_NUM_ATTRS 3
#define FC_RPORT_NUM_ATTRS 10
#define FC_VPORT_NUM_ATTRS 9
-#define FC_HOST_NUM_ATTRS 21
+#define FC_HOST_NUM_ATTRS 22
struct fc_internal {
struct scsi_transport_template t;
@@ -3432,7 +3432,7 @@ fc_bsg_jobdone(struct fc_bsg_job *job)
/**
* fc_bsg_softirq_done - softirq done routine for destroying the bsg requests
- * @req: BSG request that holds the job to be destroyed
+ * @rq: BSG request that holds the job to be destroyed
*/
static void fc_bsg_softirq_done(struct request *rq)
{
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 783e33c65eb7..b47240ca4b19 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -990,7 +990,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
struct iscsi_uevent *ev;
int len = NLMSG_SPACE(sizeof(*ev) + data_size);
- skb = alloc_skb(len, GFP_NOIO);
+ skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
return -ENOMEM;
@@ -1012,7 +1012,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
memcpy((char *)ev + sizeof(*ev), data, data_size);
- return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_NOIO);
+ return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 0895d3c71b03..fd47cb1bee1b 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1692,10 +1692,6 @@ sas_attach_transport(struct sas_function_template *ft)
i->f = ft;
count = 0;
- SETUP_PORT_ATTRIBUTE(num_phys);
- i->host_attrs[count] = NULL;
-
- count = 0;
SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
SETUP_PHY_ATTRIBUTE(target_port_protocols);
SETUP_PHY_ATTRIBUTE(device_type);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5616cd780ff3..b7b9fec67a98 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1840,6 +1840,18 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
kfree(buffer);
}
+static int sd_try_extended_inquiry(struct scsi_device *sdp)
+{
+ /*
+ * Although VPD inquiries can go to SCSI-2 type devices,
+ * some USB ones crash on receiving them, and the pages
+ * we currently ask for are for SPC-3 and beyond
+ */
+ if (sdp->scsi_level > SCSI_SPC_2)
+ return 1;
+ return 0;
+}
+
/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
@@ -1877,8 +1889,12 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
if (sdkp->media_present) {
sd_read_capacity(sdkp, buffer);
- sd_read_block_limits(sdkp);
- sd_read_block_characteristics(sdkp);
+
+ if (sd_try_extended_inquiry(sdp)) {
+ sd_read_block_limits(sdkp);
+ sd_read_block_characteristics(sdkp);
+ }
+
sd_read_write_protect_flag(sdkp, buffer);
sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer);
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index bf82e28770a9..72ba0c6d3551 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -826,6 +826,28 @@ static int pl011_remove(struct amba_device *dev)
return 0;
}
+#ifdef CONFIG_PM
+static int pl011_suspend(struct amba_device *dev, pm_message_t state)
+{
+ struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+ if (!uap)
+ return -EINVAL;
+
+ return uart_suspend_port(&amba_reg, &uap->port);
+}
+
+static int pl011_resume(struct amba_device *dev)
+{
+ struct uart_amba_port *uap = amba_get_drvdata(dev);
+
+ if (!uap)
+ return -EINVAL;
+
+ return uart_resume_port(&amba_reg, &uap->port);
+}
+#endif
+
static struct amba_id pl011_ids[] __initdata = {
{
.id = 0x00041011,
@@ -847,6 +869,10 @@ static struct amba_driver pl011_driver = {
.id_table = pl011_ids,
.probe = pl011_probe,
.remove = pl011_remove,
+#ifdef CONFIG_PM
+ .suspend = pl011_suspend,
+ .resume = pl011_resume,
+#endif
};
static int __init pl011_init(void)
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 338b15c0a548..607d43a31048 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1551,6 +1551,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
if (ret)
goto err_add_port;
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
if (atmel_is_console_port(&port->uart)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
@@ -1559,6 +1560,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
*/
clk_disable(port->clk);
}
+#endif
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 141c0a3333ad..a9802e76b5fa 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -132,7 +132,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con) {
- mem_addr = alloc_bootmem(memsz);
+ mem_addr = kzalloc(memsz, GFP_NOWAIT);
dma_addr = virt_to_bus(mem_addr);
}
else
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index a48a8a13d87b..514971fb5bff 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -726,9 +726,10 @@ static struct uart_driver serial_pxa_reg = {
.cons = PXA_CONSOLE,
};
-static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM
+static int serial_pxa_suspend(struct device *dev)
{
- struct uart_pxa_port *sport = platform_get_drvdata(dev);
+ struct uart_pxa_port *sport = dev_get_drvdata(dev);
if (sport)
uart_suspend_port(&serial_pxa_reg, &sport->port);
@@ -736,9 +737,9 @@ static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state)
return 0;
}
-static int serial_pxa_resume(struct platform_device *dev)
+static int serial_pxa_resume(struct device *dev)
{
- struct uart_pxa_port *sport = platform_get_drvdata(dev);
+ struct uart_pxa_port *sport = dev_get_drvdata(dev);
if (sport)
uart_resume_port(&serial_pxa_reg, &sport->port);
@@ -746,6 +747,12 @@ static int serial_pxa_resume(struct platform_device *dev)
return 0;
}
+static struct dev_pm_ops serial_pxa_pm_ops = {
+ .suspend = serial_pxa_suspend,
+ .resume = serial_pxa_resume,
+};
+#endif
+
static int serial_pxa_probe(struct platform_device *dev)
{
struct uart_pxa_port *sport;
@@ -825,11 +832,12 @@ static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe,
.remove = serial_pxa_remove,
- .suspend = serial_pxa_suspend,
- .resume = serial_pxa_resume,
.driver = {
.name = "pxa2xx-uart",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &serial_pxa_pm_ops,
+#endif
},
};
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 8e2feb563347..4cbb87ad070a 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -662,10 +662,11 @@ static irqreturn_t sci_rx_interrupt(int irq, void *port)
static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ unsigned long flags;
- spin_lock_irq(&port->lock);
+ spin_lock_irqsave(&port->lock, flags);
sci_transmit_chars(port);
- spin_unlock_irq(&port->lock);
+ spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index da76797ce8b9..c0f950a7cbec 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -38,14 +38,12 @@
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
-#include <linux/delay.h>
/*
* This macro is used to define some register default values.
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index eee4b6e0af2c..9b80ad36dbba 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -59,6 +59,8 @@
/* per-register bitmasks: */
+#define OMAP2_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
+#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP (1 << 2)
#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE (1 << 0)
#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
@@ -90,6 +92,7 @@
#define OMAP2_MCSPI_CHCTRL_EN (1 << 0)
+#define OMAP2_MCSPI_WAKEUPENABLE_WKEN (1 << 0)
/* We have 2 DMA channels per CS, one for RX and one for TX */
struct omap2_mcspi_dma {
@@ -269,7 +272,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (rx != NULL) {
omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
- data_type, element_count, 1,
+ data_type, element_count - 1, 1,
OMAP_DMA_SYNC_ELEMENT,
mcspi_dma->dma_rx_sync_dev, 1);
@@ -300,6 +303,25 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (rx != NULL) {
wait_for_completion(&mcspi_dma->dma_rx_completion);
dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+ omap2_mcspi_set_enable(spi, 0);
+ if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
+ & OMAP2_MCSPI_CHSTAT_RXS)) {
+ u32 w;
+
+ w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
+ if (word_len <= 8)
+ ((u8 *)xfer->rx_buf)[element_count - 1] = w;
+ else if (word_len <= 16)
+ ((u16 *)xfer->rx_buf)[element_count - 1] = w;
+ else /* word_len <= 32 */
+ ((u32 *)xfer->rx_buf)[element_count - 1] = w;
+ } else {
+ dev_err(&spi->dev, "DMA RX last word empty");
+ count -= (word_len <= 8) ? 1 :
+ (word_len <= 16) ? 2 :
+ /* word_len <= 32 */ 4;
+ }
+ omap2_mcspi_set_enable(spi, 1);
}
return count;
}
@@ -873,8 +895,12 @@ static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
} while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
- /* (3 << 8) | (2 << 3) | */
- OMAP2_MCSPI_SYSCONFIG_AUTOIDLE);
+ OMAP2_MCSPI_SYSCONFIG_AUTOIDLE |
+ OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP |
+ OMAP2_MCSPI_SYSCONFIG_SMARTIDLE);
+
+ mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
+ OMAP2_MCSPI_WAKEUPENABLE_WKEN);
omap2_mcspi_set_master_mode(master);
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index d949dbf1141f..8a1fb608e8f1 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1668,10 +1668,9 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-
-static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int pxa2xx_spi_suspend(struct device *dev)
{
- struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct driver_data *drv_data = dev_get_drvdata(dev);
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
@@ -1684,9 +1683,9 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int pxa2xx_spi_resume(struct platform_device *pdev)
+static int pxa2xx_spi_resume(struct device *dev)
{
- struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct driver_data *drv_data = dev_get_drvdata(dev);
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
@@ -1703,26 +1702,29 @@ static int pxa2xx_spi_resume(struct platform_device *pdev)
/* Start the queue running */
status = start_queue(drv_data);
if (status != 0) {
- dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+ dev_err(dev, "problem starting queue (%d)\n", status);
return status;
}
return 0;
}
-#else
-#define pxa2xx_spi_suspend NULL
-#define pxa2xx_spi_resume NULL
-#endif /* CONFIG_PM */
+
+static struct dev_pm_ops pxa2xx_spi_pm_ops = {
+ .suspend = pxa2xx_spi_suspend,
+ .resume = pxa2xx_spi_resume,
+};
+#endif
static struct platform_driver driver = {
.driver = {
- .name = "pxa2xx-spi",
- .owner = THIS_MODULE,
+ .name = "pxa2xx-spi",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pxa2xx_spi_pm_ops,
+#endif
},
.remove = pxa2xx_spi_remove,
.shutdown = pxa2xx_spi_shutdown,
- .suspend = pxa2xx_spi_suspend,
- .resume = pxa2xx_spi_resume,
};
static int __init pxa2xx_spi_init(void)
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 348bf61a8fec..975ecddbce30 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -103,8 +103,6 @@ source "drivers/staging/pohmelfs/Kconfig"
source "drivers/staging/stlc45xx/Kconfig"
-source "drivers/staging/uc2322/Kconfig"
-
source "drivers/staging/b3dfg/Kconfig"
source "drivers/staging/phison/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 8d61d7b4debf..2241ae1b21ee 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_DST) += dst/
obj-$(CONFIG_POHMELFS) += pohmelfs/
obj-$(CONFIG_STLC45XX) += stlc45xx/
-obj-$(CONFIG_USB_SERIAL_ATEN2011) += uc2322/
obj-$(CONFIG_B3DFG) += b3dfg/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_PLAN9AUTH) += p9auth/
diff --git a/drivers/staging/agnx/xmit.c b/drivers/staging/agnx/xmit.c
index 0e034081f3a5..42db41070cf0 100644
--- a/drivers/staging/agnx/xmit.c
+++ b/drivers/staging/agnx/xmit.c
@@ -384,7 +384,8 @@ void handle_rx_irq(struct agnx_priv *priv)
/* dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */
} else
agnx_bug("Unknown packets type");
- ieee80211_rx_irqsafe(priv->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(priv->hw, skb);
rx_desc_reinit(priv, i);
} while (priv->rx.idx++);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index fe72240f5a9e..f934393f3959 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -96,19 +96,21 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
read_lock(&tasklist_lock);
for_each_process(p) {
+ struct mm_struct *mm;
int oom_adj;
task_lock(p);
- if (!p->mm) {
+ mm = p->mm;
+ if (!mm) {
task_unlock(p);
continue;
}
- oom_adj = p->oomkilladj;
+ oom_adj = mm->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
- tasksize = get_mm_rss(p->mm);
+ tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c
index 3f303ae97b43..7b8aa5edf42f 100644
--- a/drivers/staging/at76_usb/at76_usb.c
+++ b/drivers/staging/at76_usb/at76_usb.c
@@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
netdev->name, __func__);
/* skip this packet */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->tx_urb->status == -EINPROGRESS) {
@@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
netdev->name, __func__);
/* skip this packet */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->len < ETH_HLEN) {
printk(KERN_ERR "%s: %s: skb too short (%d)\n",
netdev->name, __func__, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
@@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
skb->data[ETH_HLEN + 1],
skb->data[ETH_HLEN + 2]);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
/* add RFC 1042 header in front */
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
index fad25b753042..ac8577358ba0 100644
--- a/drivers/staging/dst/dcore.c
+++ b/drivers/staging/dst/dcore.c
@@ -112,8 +112,9 @@ static int dst_request(struct request_queue *q, struct bio *bio)
* I worked with.
*
* Empty barriers are not allowed anyway, see 51fd77bd9f512
- * for example, although later it was changed to bio_discard()
- * only, which does not work in this case.
+ * for example, although later it was changed to
+ * bio_rw_flagged(bio, BIO_RW_DISCARD) only, which does not
+ * work in this case.
*/
//err = -EOPNOTSUPP;
err = 0;
@@ -846,10 +847,9 @@ static dst_command_func dst_commands[] = {
/*
* Configuration parser.
*/
-static void cn_dst_callback(void *data)
+static void cn_dst_callback(struct cn_msg *msg)
{
struct dst_ctl *ctl;
- struct cn_msg *msg = data;
int err;
struct dst_ctl_ack ack;
struct dst_node *n = NULL, *tmp;
diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c
index 077724a556cc..7b7cce1b36e8 100644
--- a/drivers/staging/epl/VirtualEthernetLinux.c
+++ b/drivers/staging/epl/VirtualEthernetLinux.c
@@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p)
}
Exit:
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c
index 540cbbb826f9..7cd87caa6812 100644
--- a/drivers/staging/otus/usbdrv.c
+++ b/drivers/staging/otus/usbdrv.c
@@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
@@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
if (vapId >= ZM_VAP_PORT_NUMBER)
{
dev_kfree_skb_irq(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#if 1
if (vap[vapId].openFlag == 0)
{
dev_kfree_skb_irq(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
@@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static const struct net_device_ops vap_netdev_ops = {
diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c
index 5db0004c8739..89a6b92f5972 100644
--- a/drivers/staging/otus/wrap_pkt.c
+++ b/drivers/staging/otus/wrap_pkt.c
@@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port)
switch(netif_rx(buf))
#endif
{
- case NET_RX_BAD:
case NET_RX_DROP:
- case NET_RX_CN_MOD:
- case NET_RX_CN_HIGH:
break;
default:
macp->drv_stats.net_stats.rx_packets++;
diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c
index f298b9bcec39..35c59d5aa99c 100644
--- a/drivers/staging/rt2860/rt_main_dev.c
+++ b/drivers/staging/rt2860/rt_main_dev.c
@@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
{
struct net_device *net_dev = skb->dev;
PRTMP_ADAPTER pAd = net_dev->ml_priv;
- int status = 0;
+ int status = NETDEV_TX_OK;
PNDIS_PACKET pPacket = (PNDIS_PACKET) skb;
{
@@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1);
- status = 0;
+ status = NETDEV_TX_OK;
done:
return status;
@@ -923,7 +923,7 @@ INT rt28xx_send_packets(
if (!(net_dev->flags & IFF_UP))
{
RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE);
- return 0;
+ return NETDEV_TX_OK;
}
NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15);
diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h
index 25c31998d071..a8da4f29e27e 100644
--- a/drivers/staging/rt2860/rtmp.h
+++ b/drivers/staging/rt2860/rtmp.h
@@ -2080,7 +2080,7 @@ typedef struct _STA_ADMIN_CONFIG {
BOOLEAN AdhocBGJoined; // Indicate Adhoc B/G Join.
BOOLEAN Adhoc20NJoined; // Indicate Adhoc 20MHz N Join.
#endif
- // New for WPA, windows want us to to keep association information and
+ // New for WPA, windows want us to keep association information and
// Fixed IEs from last association response
NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo;
USHORT ReqVarIELen; // Length of next VIE include EID & Length
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 1294e05fcf13..1b774601b4a3 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb,
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
stats->tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
}
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 7e2fecae813c..26a59118d34c 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
spin_unlock_irqrestore(&priv->tx_lock,flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
rtl8180_tx(dev, skb->data, skb->len, priority,
@@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
spin_unlock_irqrestore(&priv->tx_lock,flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
// longpre 144+48 shortpre 72+24
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index a9bd4106beb7..0fdf8c6dc648 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -360,18 +360,18 @@ static void qt_read_bulk_callback(struct urb *urb)
if (port_paranoia_check(port, __func__) != 0) {
dbg("%s - port_paranoia_check, exiting\n", __func__);
qt_port->ReadBulkStopped = 1;
- return;
+ goto exit;
}
if (!serial) {
dbg("%s - bad serial pointer, exiting\n", __func__);
- return;
+ goto exit;
}
if (qt_port->closePending == 1) {
/* Were closing , stop reading */
dbg("%s - (qt_port->closepending == 1\n", __func__);
qt_port->ReadBulkStopped = 1;
- return;
+ goto exit;
}
/*
@@ -381,7 +381,7 @@ static void qt_read_bulk_callback(struct urb *urb)
*/
if (qt_port->RxHolding == 1) {
qt_port->ReadBulkStopped = 1;
- return;
+ goto exit;
}
if (urb->status) {
@@ -389,7 +389,7 @@ static void qt_read_bulk_callback(struct urb *urb)
dbg("%s - nonzero read bulk status received: %d\n",
__func__, urb->status);
- return;
+ goto exit;
}
if (tty && RxCount) {
@@ -463,6 +463,8 @@ static void qt_read_bulk_callback(struct urb *urb)
}
schedule_work(&port->work);
+exit:
+ tty_kref_put(tty);
}
/*
@@ -736,6 +738,11 @@ static int qt_startup(struct usb_serial *serial)
if (!qt_port) {
dbg("%s: kmalloc for quatech_port (%d) failed!.",
__func__, i);
+ for(--i; i >= 0; i--) {
+ port = serial->port[i];
+ kfree(usb_get_serial_port_data(port));
+ usb_set_serial_port_data(port, NULL);
+ }
return -ENOMEM;
}
spin_lock_init(&qt_port->lock);
@@ -1041,7 +1048,7 @@ static void qt_block_until_empty(struct tty_struct *tty,
}
}
-static void qt_close( struct usb_serial_port *port)
+static void qt_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct quatech_port *qt_port;
@@ -1068,6 +1075,7 @@ static void qt_close( struct usb_serial_port *port)
/* wait up to for transmitter to empty */
if (serial->dev)
qt_block_until_empty(tty, qt_port);
+ tty_kref_put(tty);
/* Close uart channel */
status = qt_close_channel(serial, index);
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index ed47db5ce5ff..b01a2822a8ee 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
hcmd->paddrh, DONT_FLUSH);
}
xmit_done:
- return 0;
+ return NETDEV_TX_OK;
xmit_fail:
slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
goto xmit_done;
diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c
index a137c78fac09..12d414deaad6 100644
--- a/drivers/staging/stlc45xx/stlc45xx.c
+++ b/drivers/staging/stlc45xx/stlc45xx.c
@@ -1429,7 +1429,8 @@ static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
- ieee80211_rx(stlc->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(stlc->hw, skb);
return 0;
}
diff --git a/drivers/staging/uc2322/Kconfig b/drivers/staging/uc2322/Kconfig
deleted file mode 100644
index 2e0c6e79df2b..000000000000
--- a/drivers/staging/uc2322/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config USB_SERIAL_ATEN2011
- tristate "ATEN 2011 USB to serial device support"
- depends on USB_SERIAL
- default N
- ---help---
- Say Y here if you want to use a ATEN 2011 dual port USB to serial
- adapter.
-
- To compile this driver as a module, choose M here: the module will be
- called aten2011.
diff --git a/drivers/staging/uc2322/Makefile b/drivers/staging/uc2322/Makefile
deleted file mode 100644
index 49c18d6e579f..000000000000
--- a/drivers/staging/uc2322/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SERIAL_ATEN2011) += aten2011.o
diff --git a/drivers/staging/uc2322/TODO b/drivers/staging/uc2322/TODO
deleted file mode 100644
index c189a64c4185..000000000000
--- a/drivers/staging/uc2322/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-TODO:
- - checkpatch.pl cleanups
- - remove dead and useless code (auditing the tty ioctls to
- verify that they really are correct and needed.)
-
-Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-Russell Lang <gsview@ghostgum.com.au>.
diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c
deleted file mode 100644
index 39d0926d1a90..000000000000
--- a/drivers/staging/uc2322/aten2011.c
+++ /dev/null
@@ -1,2430 +0,0 @@
-/*
- * Aten 2011 USB serial driver for 4 port devices
- *
- * Copyright (C) 2000 Inside Out Networks
- * Copyright (C) 2001-2002, 2009 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2009 Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-
-#define ZLP_REG1 0x3A /* Zero_Flag_Reg1 58 */
-#define ZLP_REG2 0x3B /* Zero_Flag_Reg2 59 */
-#define ZLP_REG3 0x3C /* Zero_Flag_Reg3 60 */
-#define ZLP_REG4 0x3D /* Zero_Flag_Reg4 61 */
-#define ZLP_REG5 0x3E /* Zero_Flag_Reg5 62 */
-
-/* Interrupt Rotinue Defines */
-#define SERIAL_IIR_RLS 0x06
-#define SERIAL_IIR_RDA 0x04
-#define SERIAL_IIR_CTI 0x0c
-#define SERIAL_IIR_THR 0x02
-#define SERIAL_IIR_MS 0x00
-
-/* Emulation of the bit mask on the LINE STATUS REGISTER. */
-#define SERIAL_LSR_DR 0x0001
-#define SERIAL_LSR_OE 0x0002
-#define SERIAL_LSR_PE 0x0004
-#define SERIAL_LSR_FE 0x0008
-#define SERIAL_LSR_BI 0x0010
-#define SERIAL_LSR_THRE 0x0020
-#define SERIAL_LSR_TEMT 0x0040
-#define SERIAL_LSR_FIFOERR 0x0080
-
-/* MSR bit defines(place holders) */
-#define ATEN_MSR_DELTA_CTS 0x10
-#define ATEN_MSR_DELTA_DSR 0x20
-#define ATEN_MSR_DELTA_RI 0x40
-#define ATEN_MSR_DELTA_CD 0x80
-
-/* Serial Port register Address */
-#define RECEIVE_BUFFER_REGISTER ((__u16)(0x00))
-#define TRANSMIT_HOLDING_REGISTER ((__u16)(0x00))
-#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
-#define INTERRUPT_IDENT_REGISTER ((__u16)(0x02))
-#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
-#define LINE_CONTROL_REGISTER ((__u16)(0x03))
-#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
-#define LINE_STATUS_REGISTER ((__u16)(0x05))
-#define MODEM_STATUS_REGISTER ((__u16)(0x06))
-#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
-#define DIVISOR_LATCH_LSB ((__u16)(0x00))
-#define DIVISOR_LATCH_MSB ((__u16)(0x01))
-
-#define SP1_REGISTER ((__u16)(0x00))
-#define CONTROL1_REGISTER ((__u16)(0x01))
-#define CLK_MULTI_REGISTER ((__u16)(0x02))
-#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
-#define DCR1_REGISTER ((__u16)(0x04))
-#define GPIO_REGISTER ((__u16)(0x07))
-
-#define SERIAL_LCR_DLAB ((__u16)(0x0080))
-
-/*
- * URB POOL related defines
- */
-#define NUM_URBS 16 /* URB Count */
-#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
-
-#define USB_VENDOR_ID_ATENINTL 0x0557
-#define ATENINTL_DEVICE_ID_2011 0x2011
-#define ATENINTL_DEVICE_ID_7820 0x7820
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_2011) },
- { USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_7820) },
- { } /* terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-/* This structure holds all of the local port information */
-struct ATENINTL_port {
- int port_num; /*Actual port number in the device(1,2,etc)*/
- __u8 bulk_out_endpoint; /* the bulk out endpoint handle */
- unsigned char *bulk_out_buffer; /* buffer used for the bulk out endpoint */
- struct urb *write_urb; /* write URB for this port */
- __u8 bulk_in_endpoint; /* the bulk in endpoint handle */
- unsigned char *bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
- struct urb *read_urb; /* read URB for this port */
- __u8 shadowLCR; /* last LCR value received */
- __u8 shadowMCR; /* last MCR value received */
- char open;
- char chaseResponsePending;
- wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
- wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
- struct async_icount icount;
- struct usb_serial_port *port; /* loop back to the owner of this object */
- /*Offsets*/
- __u8 SpRegOffset;
- __u8 ControlRegOffset;
- __u8 DcrRegOffset;
- /* for processing control URBS in interrupt context */
- struct urb *control_urb;
- char *ctrl_buf;
- int MsrLsr;
-
- struct urb *write_urb_pool[NUM_URBS];
- /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
- struct ktermios tmp_termios; /* stores the old termios settings */
- spinlock_t lock; /* private lock */
-};
-
-/* This structure holds all of the individual serial device information */
-struct ATENINTL_serial {
- __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */
- unsigned char *interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */
- struct urb *interrupt_read_urb; /* our interrupt urb */
- __u8 bulk_in_endpoint; /* the bulk in endpoint handle */
- unsigned char *bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
- struct urb *read_urb; /* our bulk read urb */
- __u8 bulk_out_endpoint; /* the bulk out endpoint handle */
- struct usb_serial *serial; /* loop back to the owner of this object */
- int ATEN2011_spectrum_2or4ports; /* this says the number of ports in the device */
- /* Indicates about the no.of opened ports of an individual USB-serial adapater. */
- unsigned int NoOfOpenPorts;
- /* a flag for Status endpoint polling */
- unsigned char status_polling_started;
-};
-
-static void ATEN2011_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios);
-static void ATEN2011_change_port_settings(struct tty_struct *tty,
- struct ATENINTL_port *ATEN2011_port,
- struct ktermios *old_termios);
-
-/*************************************
- * Bit definitions for each register *
- *************************************/
-#define LCR_BITS_5 0x00 /* 5 bits/char */
-#define LCR_BITS_6 0x01 /* 6 bits/char */
-#define LCR_BITS_7 0x02 /* 7 bits/char */
-#define LCR_BITS_8 0x03 /* 8 bits/char */
-#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
-
-#define LCR_STOP_1 0x00 /* 1 stop bit */
-#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
-#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
-#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
-
-#define LCR_PAR_NONE 0x00 /* No parity */
-#define LCR_PAR_ODD 0x08 /* Odd parity */
-#define LCR_PAR_EVEN 0x18 /* Even parity */
-#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
-#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
-#define LCR_PAR_MASK 0x38 /* Mask for parity field */
-
-#define LCR_SET_BREAK 0x40 /* Set Break condition */
-#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
-
-#define MCR_DTR 0x01 /* Assert DTR */
-#define MCR_RTS 0x02 /* Assert RTS */
-#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
-#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
-#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
-#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
-
-#define ATEN2011_MSR_CTS 0x10 /* Current state of CTS */
-#define ATEN2011_MSR_DSR 0x20 /* Current state of DSR */
-#define ATEN2011_MSR_RI 0x40 /* Current state of RI */
-#define ATEN2011_MSR_CD 0x80 /* Current state of CD */
-
-
-static int debug;
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "2.0"
-#define DRIVER_DESC "ATENINTL 2011 USB Serial Adapter"
-
-/*
- * Defines used for sending commands to port
- */
-
-#define ATEN_WDR_TIMEOUT (50) /* default urb timeout */
-
-/* Requests */
-#define ATEN_RD_RTYPE 0xC0
-#define ATEN_WR_RTYPE 0x40
-#define ATEN_RDREQ 0x0D
-#define ATEN_WRREQ 0x0E
-#define ATEN_CTRL_TIMEOUT 500
-#define VENDOR_READ_LENGTH (0x01)
-
-/* set to 1 for RS485 mode and 0 for RS232 mode */
-/* FIXME make this somehow dynamic and not build time specific */
-static int RS485mode;
-
-static int set_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 val)
-{
- struct usb_device *dev = port->serial->dev;
- val = val & 0x00ff;
-
- dbg("%s: is %x, value %x", __func__, reg, val);
-
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
- ATEN_WR_RTYPE, val, reg, NULL, 0,
- ATEN_WDR_TIMEOUT);
-}
-
-static int get_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 *val)
-{
- struct usb_device *dev = port->serial->dev;
- int ret;
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
- ATEN_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
- ATEN_WDR_TIMEOUT);
- dbg("%s: offset is %x, return val %x", __func__, reg, *val);
- *val = (*val) & 0x00ff;
- return ret;
-}
-
-static int set_uart_reg(struct usb_serial_port *port, __u16 reg, __u16 val)
-{
- struct usb_device *dev = port->serial->dev;
- struct ATENINTL_serial *a_serial;
- __u16 minor;
-
- a_serial = usb_get_serial_data(port->serial);
- minor = port->serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
- val = val & 0x00ff;
-
- /*
- * For the UART control registers,
- * the application number need to be Or'ed
- */
- if (a_serial->ATEN2011_spectrum_2or4ports == 4)
- val |= (((__u16)port->number - minor) + 1) << 8;
- else {
- if (((__u16) port->number - minor) == 0)
- val |= (((__u16)port->number - minor) + 1) << 8;
- else
- val |= (((__u16)port->number - minor) + 2) << 8;
- }
- dbg("%s: application number is %x", __func__, val);
-
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
- ATEN_WR_RTYPE, val, reg, NULL, 0,
- ATEN_WDR_TIMEOUT);
-}
-
-static int get_uart_reg(struct usb_serial_port *port, __u16 reg, __u16 *val)
-{
- struct usb_device *dev = port->serial->dev;
- int ret = 0;
- __u16 wval;
- struct ATENINTL_serial *a_serial;
- __u16 minor = port->serial->minor;
-
- a_serial = usb_get_serial_data(port->serial);
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
-
- /* wval is same as application number */
- if (a_serial->ATEN2011_spectrum_2or4ports == 4)
- wval = (((__u16)port->number - minor) + 1) << 8;
- else {
- if (((__u16) port->number - minor) == 0)
- wval = (((__u16) port->number - minor) + 1) << 8;
- else
- wval = (((__u16) port->number - minor) + 2) << 8;
- }
- dbg("%s: application number is %x", __func__, wval);
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
- ATEN_RD_RTYPE, wval, reg, val, VENDOR_READ_LENGTH,
- ATEN_WDR_TIMEOUT);
- *val = (*val) & 0x00ff;
- return ret;
-}
-
-static int handle_newMsr(struct ATENINTL_port *port, __u8 newMsr)
-{
- struct ATENINTL_port *ATEN2011_port;
- struct async_icount *icount;
- ATEN2011_port = port;
- icount = &ATEN2011_port->icount;
- if (newMsr &
- (ATEN_MSR_DELTA_CTS | ATEN_MSR_DELTA_DSR | ATEN_MSR_DELTA_RI |
- ATEN_MSR_DELTA_CD)) {
- icount = &ATEN2011_port->icount;
-
- /* update input line counters */
- if (newMsr & ATEN_MSR_DELTA_CTS)
- icount->cts++;
- if (newMsr & ATEN_MSR_DELTA_DSR)
- icount->dsr++;
- if (newMsr & ATEN_MSR_DELTA_CD)
- icount->dcd++;
- if (newMsr & ATEN_MSR_DELTA_RI)
- icount->rng++;
- }
-
- return 0;
-}
-
-static int handle_newLsr(struct ATENINTL_port *port, __u8 newLsr)
-{
- struct async_icount *icount;
-
- dbg("%s - %02x", __func__, newLsr);
-
- if (newLsr & SERIAL_LSR_BI) {
- /*
- * Parity and Framing errors only count if they occur exclusive
- * of a break being received.
- */
- newLsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
- }
-
- /* update input line counters */
- icount = &port->icount;
- if (newLsr & SERIAL_LSR_BI)
- icount->brk++;
- if (newLsr & SERIAL_LSR_OE)
- icount->overrun++;
- if (newLsr & SERIAL_LSR_PE)
- icount->parity++;
- if (newLsr & SERIAL_LSR_FE)
- icount->frame++;
-
- return 0;
-}
-
-static void ATEN2011_control_callback(struct urb *urb)
-{
- unsigned char *data;
- struct ATENINTL_port *ATEN2011_port;
- __u8 regval = 0x0;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __func__,
- urb->status);
- goto exit;
- }
-
- ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
- dbg("%s urb buffer size is %d", __func__, urb->actual_length);
- dbg("%s ATEN2011_port->MsrLsr is %d port %d", __func__,
- ATEN2011_port->MsrLsr, ATEN2011_port->port_num);
- data = urb->transfer_buffer;
- regval = (__u8) data[0];
- dbg("%s data is %x", __func__, regval);
- if (ATEN2011_port->MsrLsr == 0)
- handle_newMsr(ATEN2011_port, regval);
- else if (ATEN2011_port->MsrLsr == 1)
- handle_newLsr(ATEN2011_port, regval);
-
-exit:
- return;
-}
-
-static int ATEN2011_get_reg(struct ATENINTL_port *ATEN, __u16 Wval, __u16 reg,
- __u16 *val)
-{
- struct usb_device *dev = ATEN->port->serial->dev;
- struct usb_ctrlrequest *dr = NULL;
- unsigned char *buffer = NULL;
- int ret = 0;
- buffer = (__u8 *) ATEN->ctrl_buf;
-
- dr = (void *)(buffer + 2);
- dr->bRequestType = ATEN_RD_RTYPE;
- dr->bRequest = ATEN_RDREQ;
- dr->wValue = cpu_to_le16(Wval);
- dr->wIndex = cpu_to_le16(reg);
- dr->wLength = cpu_to_le16(2);
-
- usb_fill_control_urb(ATEN->control_urb, dev, usb_rcvctrlpipe(dev, 0),
- (unsigned char *)dr, buffer, 2,
- ATEN2011_control_callback, ATEN);
- ATEN->control_urb->transfer_buffer_length = 2;
- ret = usb_submit_urb(ATEN->control_urb, GFP_ATOMIC);
- return ret;
-}
-
-static void ATEN2011_interrupt_callback(struct urb *urb)
-{
- int result;
- int length;
- struct ATENINTL_port *ATEN2011_port;
- struct ATENINTL_serial *ATEN2011_serial;
- struct usb_serial *serial;
- __u16 Data;
- unsigned char *data;
- __u8 sp[5], st;
- int i;
- __u16 wval;
- int minor;
-
- dbg("%s", " : Entering");
-
- ATEN2011_serial = (struct ATENINTL_serial *)urb->context;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __func__,
- urb->status);
- goto exit;
- }
- length = urb->actual_length;
- data = urb->transfer_buffer;
-
- serial = ATEN2011_serial->serial;
-
- /* ATENINTL get 5 bytes
- * Byte 1 IIR Port 1 (port.number is 0)
- * Byte 2 IIR Port 2 (port.number is 1)
- * Byte 3 IIR Port 3 (port.number is 2)
- * Byte 4 IIR Port 4 (port.number is 3)
- * Byte 5 FIFO status for both */
-
- if (length && length > 5) {
- dbg("%s", "Wrong data !!!");
- return;
- }
-
- /* MATRIX */
- if (ATEN2011_serial->ATEN2011_spectrum_2or4ports == 4) {
- sp[0] = (__u8) data[0];
- sp[1] = (__u8) data[1];
- sp[2] = (__u8) data[2];
- sp[3] = (__u8) data[3];
- st = (__u8) data[4];
- } else {
- sp[0] = (__u8) data[0];
- sp[1] = (__u8) data[2];
- /* sp[2]=(__u8)data[2]; */
- /* sp[3]=(__u8)data[3]; */
- st = (__u8) data[4];
-
- }
- for (i = 0; i < serial->num_ports; i++) {
- ATEN2011_port = usb_get_serial_port_data(serial->port[i]);
- minor = serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
- if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
- && (i != 0))
- wval =
- (((__u16) serial->port[i]->number -
- (__u16) (minor)) + 2) << 8;
- else
- wval =
- (((__u16) serial->port[i]->number -
- (__u16) (minor)) + 1) << 8;
- if (ATEN2011_port->open != 0) {
- if (sp[i] & 0x01) {
- dbg("SP%d No Interrupt !!!", i);
- } else {
- switch (sp[i] & 0x0f) {
- case SERIAL_IIR_RLS:
- dbg("Serial Port %d: Receiver status error or address bit detected in 9-bit mode", i);
- ATEN2011_port->MsrLsr = 1;
- ATEN2011_get_reg(ATEN2011_port, wval,
- LINE_STATUS_REGISTER,
- &Data);
- break;
- case SERIAL_IIR_MS:
- dbg("Serial Port %d: Modem status change", i);
- ATEN2011_port->MsrLsr = 0;
- ATEN2011_get_reg(ATEN2011_port, wval,
- MODEM_STATUS_REGISTER,
- &Data);
- break;
- }
- }
- }
-
- }
-exit:
- if (ATEN2011_serial->status_polling_started == 0)
- return;
-
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- dev_err(&urb->dev->dev,
- "%s - Error %d submitting interrupt urb\n",
- __func__, result);
- }
-
- return;
-}
-
-static void ATEN2011_bulk_in_callback(struct urb *urb)
-{
- int status;
- unsigned char *data;
- struct usb_serial *serial;
- struct usb_serial_port *port;
- struct ATENINTL_serial *ATEN2011_serial;
- struct ATENINTL_port *ATEN2011_port;
- struct tty_struct *tty;
-
- if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
- return;
- }
-
- ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
- port = (struct usb_serial_port *)ATEN2011_port->port;
- serial = port->serial;
-
- dbg("%s", "Entering...");
-
- data = urb->transfer_buffer;
- ATEN2011_serial = usb_get_serial_data(serial);
-
- if (urb->actual_length) {
- tty = tty_port_tty_get(&ATEN2011_port->port->port);
- if (tty) {
- tty_buffer_request_room(tty, urb->actual_length);
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
-
- ATEN2011_port->icount.rx += urb->actual_length;
- dbg("ATEN2011_port->icount.rx is %d:",
- ATEN2011_port->icount.rx);
- }
-
- if (!ATEN2011_port->read_urb) {
- dbg("%s", "URB KILLED !!!");
- return;
- }
-
- if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
- ATEN2011_port->read_urb->dev = serial->dev;
-
- status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
- if (status)
- dbg("usb_submit_urb(read bulk) failed, status = %d", status);
- }
-}
-
-static void ATEN2011_bulk_out_data_callback(struct urb *urb)
-{
- struct ATENINTL_port *ATEN2011_port;
- struct tty_struct *tty;
-
- if (urb->status) {
- dbg("nonzero write bulk status received:%d", urb->status);
- return;
- }
-
- ATEN2011_port = (struct ATENINTL_port *)urb->context;
-
- dbg("%s", "Entering .........");
-
- tty = tty_port_tty_get(&ATEN2011_port->port->port);
-
- if (tty && ATEN2011_port->open)
- /* tell the tty driver that something has changed */
- tty_wakeup(tty);
-
- /* schedule_work(&ATEN2011_port->port->work); */
- tty_kref_put(tty);
-
-}
-
-#ifdef ATENSerialProbe
-static int ATEN2011_serial_probe(struct usb_serial *serial,
- const struct usb_device_id *id)
-{
-
- /*need to implement the mode_reg reading and updating\
- structures usb_serial_ device_type\
- (i.e num_ports, num_bulkin,bulkout etc) */
- /* Also we can update the changes attach */
- return 1;
-}
-#endif
-
-static int ATEN2011_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
-{
- int response;
- int j;
- struct usb_serial *serial;
- struct urb *urb;
- __u16 Data;
- int status;
- struct ATENINTL_serial *ATEN2011_serial;
- struct ATENINTL_port *ATEN2011_port;
- struct ktermios tmp_termios;
- int minor;
-
- serial = port->serial;
-
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return -ENODEV;
-
- ATEN2011_serial = usb_get_serial_data(serial);
- if (ATEN2011_serial == NULL)
- return -ENODEV;
-
- /* increment the number of opened ports counter here */
- ATEN2011_serial->NoOfOpenPorts++;
-
- usb_clear_halt(serial->dev, port->write_urb->pipe);
- usb_clear_halt(serial->dev, port->read_urb->pipe);
-
- /* Initialising the write urb pool */
- for (j = 0; j < NUM_URBS; ++j) {
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- ATEN2011_port->write_urb_pool[j] = urb;
-
- if (urb == NULL) {
- err("No more urbs???");
- continue;
- }
-
- urb->transfer_buffer = NULL;
- urb->transfer_buffer =
- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
- if (!urb->transfer_buffer) {
- err("%s-out of memory for urb buffers.", __func__);
- continue;
- }
- }
-
-/*****************************************************************************
- * Initialize ATEN2011 -- Write Init values to corresponding Registers
- *
- * Register Index
- * 1 : IER
- * 2 : FCR
- * 3 : LCR
- * 4 : MCR
- *
- * 0x08 : SP1/2 Control Reg
- *****************************************************************************/
-
-/* NEED to check the fallowing Block */
-
- Data = 0x0;
- status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
- if (status < 0) {
- dbg("Reading Spreg failed");
- return -1;
- }
- Data |= 0x80;
- status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
- if (status < 0) {
- dbg("writing Spreg failed");
- return -1;
- }
-
- Data &= ~0x80;
- status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
- if (status < 0) {
- dbg("writing Spreg failed");
- return -1;
- }
-
-/* End of block to be checked */
-/**************************CHECK***************************/
-
- if (RS485mode == 0)
- Data = 0xC0;
- else
- Data = 0x00;
- status = set_uart_reg(port, SCRATCH_PAD_REGISTER, Data);
- if (status < 0) {
- dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", status);
- return -1;
- } else
- dbg("SCRATCH_PAD_REGISTER Writing success status%d", status);
-
-/**************************CHECK***************************/
-
- Data = 0x0;
- status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
- if (status < 0) {
- dbg("Reading Controlreg failed");
- return -1;
- }
- Data |= 0x08; /* Driver done bit */
- Data |= 0x20; /* rx_disable */
- status = 0;
- status =
- set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
- if (status < 0) {
- dbg("writing Controlreg failed");
- return -1;
- }
- /*
- * do register settings here
- * Set all regs to the device default values.
- * First Disable all interrupts.
- */
-
- Data = 0x00;
- status = set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
- if (status < 0) {
- dbg("disableing interrupts failed");
- return -1;
- }
- /* Set FIFO_CONTROL_REGISTER to the default value */
- Data = 0x00;
- status = set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
- if (status < 0) {
- dbg("Writing FIFO_CONTROL_REGISTER failed");
- return -1;
- }
-
- Data = 0xcf; /* chk */
- status = set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
- if (status < 0) {
- dbg("Writing FIFO_CONTROL_REGISTER failed");
- return -1;
- }
-
- Data = 0x03; /* LCR_BITS_8 */
- status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
- ATEN2011_port->shadowLCR = Data;
-
- Data = 0x0b; /* MCR_DTR|MCR_RTS|MCR_MASTER_IE */
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- ATEN2011_port->shadowMCR = Data;
-
-#ifdef Check
- Data = 0x00;
- status = get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
- ATEN2011_port->shadowLCR = Data;
-
- Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
- status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
- Data = 0x0c;
- status = set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
-
- Data = 0x0;
- status = set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
-
- Data = 0x00;
- status = get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
-
-/* Data = ATEN2011_port->shadowLCR; */ /* data latch disable */
- Data = Data & ~SERIAL_LCR_DLAB;
- status = set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
- ATEN2011_port->shadowLCR = Data;
-#endif
- /* clearing Bulkin and Bulkout Fifo */
- Data = 0x0;
- status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
-
- Data = Data | 0x0c;
- status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
-
- Data = Data & ~0x0c;
- status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
- /* Finally enable all interrupts */
- Data = 0x0;
- Data = 0x0c;
- status = set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
- /* clearing rx_disable */
- Data = 0x0;
- status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
- Data = Data & ~0x20;
- status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
-
- /* rx_negate */
- Data = 0x0;
- status = get_reg_sync(port, ATEN2011_port->ControlRegOffset, &Data);
- Data = Data | 0x10;
- status = 0;
- status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data);
-
- /*
- * Check to see if we've set up our endpoint info yet
- * (can't set it up in ATEN2011_startup as the structures
- * were not set up at that time.)
- */
- if (ATEN2011_serial->NoOfOpenPorts == 1) {
- /* start the status polling here */
- ATEN2011_serial->status_polling_started = 1;
- /* If not yet set, Set here */
- ATEN2011_serial->interrupt_in_buffer =
- serial->port[0]->interrupt_in_buffer;
- ATEN2011_serial->interrupt_in_endpoint =
- serial->port[0]->interrupt_in_endpointAddress;
- ATEN2011_serial->interrupt_read_urb =
- serial->port[0]->interrupt_in_urb;
-
- /* set up interrupt urb */
- usb_fill_int_urb(ATEN2011_serial->interrupt_read_urb,
- serial->dev,
- usb_rcvintpipe(serial->dev,
- ATEN2011_serial->
- interrupt_in_endpoint),
- ATEN2011_serial->interrupt_in_buffer,
- ATEN2011_serial->interrupt_read_urb->
- transfer_buffer_length,
- ATEN2011_interrupt_callback, ATEN2011_serial,
- ATEN2011_serial->interrupt_read_urb->interval);
-
- /* start interrupt read for ATEN2011 *
- * will continue as long as ATEN2011 is connected */
-
- response =
- usb_submit_urb(ATEN2011_serial->interrupt_read_urb,
- GFP_KERNEL);
- if (response) {
- dbg("%s - Error %d submitting interrupt urb",
- __func__, response);
- }
-
- }
-
- /*
- * See if we've set up our endpoint info yet
- * (can't set it up in ATEN2011_startup as the
- * structures were not set up at that time.)
- */
-
- dbg("port number is %d", port->number);
- dbg("serial number is %d", port->serial->minor);
- dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
- dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
- dbg("Interrupt endpoint is %d",
- port->interrupt_in_endpointAddress);
- dbg("port's number in the device is %d", ATEN2011_port->port_num);
- ATEN2011_port->bulk_in_buffer = port->bulk_in_buffer;
- ATEN2011_port->bulk_in_endpoint = port->bulk_in_endpointAddress;
- ATEN2011_port->read_urb = port->read_urb;
- ATEN2011_port->bulk_out_endpoint = port->bulk_out_endpointAddress;
-
- minor = port->serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
-
- /* set up our bulk in urb */
- if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
- && (((__u16) port->number - (__u16) (minor)) != 0)) {
- usb_fill_bulk_urb(ATEN2011_port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- (port->
- bulk_in_endpointAddress +
- 2)), port->bulk_in_buffer,
- ATEN2011_port->read_urb->
- transfer_buffer_length,
- ATEN2011_bulk_in_callback, ATEN2011_port);
- } else
- usb_fill_bulk_urb(ATEN2011_port->read_urb,
- serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->
- bulk_in_endpointAddress),
- port->bulk_in_buffer,
- ATEN2011_port->read_urb->
- transfer_buffer_length,
- ATEN2011_bulk_in_callback, ATEN2011_port);
-
- dbg("ATEN2011_open: bulkin endpoint is %d",
- port->bulk_in_endpointAddress);
- response = usb_submit_urb(ATEN2011_port->read_urb, GFP_KERNEL);
- if (response) {
- err("%s - Error %d submitting control urb", __func__,
- response);
- }
-
- /* initialize our wait queues */
- init_waitqueue_head(&ATEN2011_port->wait_chase);
- init_waitqueue_head(&ATEN2011_port->wait_command);
-
- /* initialize our icount structure */
- memset(&(ATEN2011_port->icount), 0x00, sizeof(ATEN2011_port->icount));
-
- /* initialize our port settings */
- ATEN2011_port->shadowMCR = MCR_MASTER_IE; /* Must set to enable ints! */
- ATEN2011_port->chaseResponsePending = 0;
- /* send a open port command */
- ATEN2011_port->open = 1;
- /* ATEN2011_change_port_settings(ATEN2011_port,old_termios); */
- /* Setup termios */
- ATEN2011_set_termios(tty, port, &tmp_termios);
- ATEN2011_port->icount.tx = 0;
- ATEN2011_port->icount.rx = 0;
-
- dbg("usb_serial serial:%x ATEN2011_port:%x\nATEN2011_serial:%x usb_serial_port port:%x",
- (unsigned int)serial, (unsigned int)ATEN2011_port,
- (unsigned int)ATEN2011_serial, (unsigned int)port);
-
- return 0;
-
-}
-
-static int ATEN2011_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- int i;
- int chars = 0;
- struct ATENINTL_port *ATEN2011_port;
-
- /* dbg("%s"," ATEN2011_chars_in_buffer:entering ..........."); */
-
- ATEN2011_port = usb_get_serial_port_data(port);
- if (ATEN2011_port == NULL) {
- dbg("%s", "ATEN2011_break:leaving ...........");
- return -1;
- }
-
- for (i = 0; i < NUM_URBS; ++i)
- if (ATEN2011_port->write_urb_pool[i]->status == -EINPROGRESS)
- chars += URB_TRANSFER_BUFFER_SIZE;
-
- dbg("%s - returns %d", __func__, chars);
- return chars;
-
-}
-
-static void ATEN2011_block_until_tx_empty(struct tty_struct *tty,
- struct ATENINTL_port *ATEN2011_port)
-{
- int timeout = HZ / 10;
- int wait = 30;
- int count;
-
- while (1) {
- count = ATEN2011_chars_in_buffer(tty);
-
- /* Check for Buffer status */
- if (count <= 0)
- return;
-
- /* Block the thread for a while */
- interruptible_sleep_on_timeout(&ATEN2011_port->wait_chase,
- timeout);
-
- /* No activity.. count down section */
- wait--;
- if (wait == 0) {
- dbg("%s - TIMEOUT", __func__);
- return;
- } else {
- /* Reset timout value back to seconds */
- wait = 30;
- }
- }
-}
-
-static void ATEN2011_close(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
-{
- struct usb_serial *serial;
- struct ATENINTL_serial *ATEN2011_serial;
- struct ATENINTL_port *ATEN2011_port;
- int no_urbs;
- __u16 Data;
-
- dbg("%s", "ATEN2011_close:entering...");
- serial = port->serial;
-
- /* take the Adpater and port's private data */
- ATEN2011_serial = usb_get_serial_data(serial);
- ATEN2011_port = usb_get_serial_port_data(port);
- if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
- return;
-
- if (serial->dev) {
- /* flush and block(wait) until tx is empty */
- ATEN2011_block_until_tx_empty(tty, ATEN2011_port);
- }
- /* kill the ports URB's */
- for (no_urbs = 0; no_urbs < NUM_URBS; no_urbs++)
- usb_kill_urb(ATEN2011_port->write_urb_pool[no_urbs]);
- /* Freeing Write URBs */
- for (no_urbs = 0; no_urbs < NUM_URBS; ++no_urbs) {
- kfree(ATEN2011_port->write_urb_pool[no_urbs]->transfer_buffer);
- usb_free_urb(ATEN2011_port->write_urb_pool[no_urbs]);
- }
- /* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- if (ATEN2011_port->write_urb) {
- dbg("%s", "Shutdown bulk write");
- usb_kill_urb(ATEN2011_port->write_urb);
- }
- if (ATEN2011_port->read_urb) {
- dbg("%s", "Shutdown bulk read");
- usb_kill_urb(ATEN2011_port->read_urb);
- }
- if ((&ATEN2011_port->control_urb)) {
- dbg("%s", "Shutdown control read");
- /* usb_kill_urb (ATEN2011_port->control_urb); */
-
- }
- }
- /* if(ATEN2011_port->ctrl_buf != NULL) */
- /* kfree(ATEN2011_port->ctrl_buf); */
- /* decrement the no.of open ports counter of an individual USB-serial adapter. */
- ATEN2011_serial->NoOfOpenPorts--;
- dbg("NoOfOpenPorts in close%d:in port%d",
- ATEN2011_serial->NoOfOpenPorts, port->number);
- if (ATEN2011_serial->NoOfOpenPorts == 0) {
- /* stop the stus polling here */
- ATEN2011_serial->status_polling_started = 0;
- if (ATEN2011_serial->interrupt_read_urb) {
- dbg("%s", "Shutdown interrupt_read_urb");
- /* ATEN2011_serial->interrupt_in_buffer=NULL; */
- /* usb_kill_urb (ATEN2011_serial->interrupt_read_urb); */
- }
- }
- if (ATEN2011_port->write_urb) {
- /* if this urb had a transfer buffer already (old tx) free it */
- kfree(ATEN2011_port->write_urb->transfer_buffer);
- usb_free_urb(ATEN2011_port->write_urb);
- }
-
- /* clear the MCR & IER */
- Data = 0x00;
- set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- Data = 0x00;
- set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
- ATEN2011_port->open = 0;
- dbg("%s", "Leaving ............");
-
-}
-
-static void ATEN2011_block_until_chase_response(struct tty_struct *tty,
- struct ATENINTL_port
- *ATEN2011_port)
-{
- int timeout = 1 * HZ;
- int wait = 10;
- int count;
-
- while (1) {
- count = ATEN2011_chars_in_buffer(tty);
-
- /* Check for Buffer status */
- if (count <= 0) {
- ATEN2011_port->chaseResponsePending = 0;
- return;
- }
-
- /* Block the thread for a while */
- interruptible_sleep_on_timeout(&ATEN2011_port->wait_chase,
- timeout);
- /* No activity.. count down section */
- wait--;
- if (wait == 0) {
- dbg("%s - TIMEOUT", __func__);
- return;
- } else {
- /* Reset timout value back to seconds */
- wait = 10;
- }
- }
-
-}
-
-static void ATEN2011_break(struct tty_struct *tty, int break_state)
-{
- struct usb_serial_port *port = tty->driver_data;
- unsigned char data;
- struct usb_serial *serial;
- struct ATENINTL_serial *ATEN2011_serial;
- struct ATENINTL_port *ATEN2011_port;
-
- dbg("%s", "Entering ...........");
- dbg("ATEN2011_break: Start");
-
- serial = port->serial;
-
- ATEN2011_serial = usb_get_serial_data(serial);
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
- return;
-
- /* flush and chase */
- ATEN2011_port->chaseResponsePending = 1;
-
- if (serial->dev) {
- /* flush and block until tx is empty */
- ATEN2011_block_until_chase_response(tty, ATEN2011_port);
- }
-
- if (break_state == -1)
- data = ATEN2011_port->shadowLCR | LCR_SET_BREAK;
- else
- data = ATEN2011_port->shadowLCR & ~LCR_SET_BREAK;
-
- ATEN2011_port->shadowLCR = data;
- dbg("ATEN2011_break ATEN2011_port->shadowLCR is %x",
- ATEN2011_port->shadowLCR);
- set_uart_reg(port, LINE_CONTROL_REGISTER, ATEN2011_port->shadowLCR);
-
- return;
-}
-
-static int ATEN2011_write_room(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- int i;
- int room = 0;
- struct ATENINTL_port *ATEN2011_port;
-
- ATEN2011_port = usb_get_serial_port_data(port);
- if (ATEN2011_port == NULL) {
- dbg("%s", "ATEN2011_break:leaving ...........");
- return -1;
- }
-
- for (i = 0; i < NUM_URBS; ++i)
- if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS)
- room += URB_TRANSFER_BUFFER_SIZE;
-
- dbg("%s - returns %d", __func__, room);
- return room;
-
-}
-
-static int ATEN2011_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *data, int count)
-{
- int status;
- int i;
- int bytes_sent = 0;
- int transfer_size;
- int minor;
-
- struct ATENINTL_port *ATEN2011_port;
- struct usb_serial *serial;
- struct ATENINTL_serial *ATEN2011_serial;
- struct urb *urb;
- const unsigned char *current_position = data;
- unsigned char *data1;
- dbg("%s", "entering ...........");
-
- serial = port->serial;
-
- ATEN2011_port = usb_get_serial_port_data(port);
- if (ATEN2011_port == NULL) {
- dbg("%s", "ATEN2011_port is NULL");
- return -1;
- }
-
- ATEN2011_serial = usb_get_serial_data(serial);
- if (ATEN2011_serial == NULL) {
- dbg("%s", "ATEN2011_serial is NULL");
- return -1;
- }
-
- /* try to find a free urb in the list */
- urb = NULL;
-
- for (i = 0; i < NUM_URBS; ++i) {
- if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS) {
- urb = ATEN2011_port->write_urb_pool[i];
- dbg("URB:%d", i);
- break;
- }
- }
-
- if (urb == NULL) {
- dbg("%s - no more free urbs", __func__);
- goto exit;
- }
-
- if (urb->transfer_buffer == NULL) {
- urb->transfer_buffer =
- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-
- if (urb->transfer_buffer == NULL) {
- err("%s no more kernel memory...", __func__);
- goto exit;
- }
- }
- transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
-
- memcpy(urb->transfer_buffer, current_position, transfer_size);
- /* usb_serial_debug_data (__FILE__, __func__, transfer_size, urb->transfer_buffer); */
-
- /* fill urb with data and submit */
- minor = port->serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
- if ((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)
- && (((__u16) port->number - (__u16) (minor)) != 0)) {
- usb_fill_bulk_urb(urb, ATEN2011_serial->serial->dev,
- usb_sndbulkpipe(ATEN2011_serial->serial->dev,
- (port->
- bulk_out_endpointAddress) +
- 2), urb->transfer_buffer,
- transfer_size,
- ATEN2011_bulk_out_data_callback,
- ATEN2011_port);
- } else
-
- usb_fill_bulk_urb(urb,
- ATEN2011_serial->serial->dev,
- usb_sndbulkpipe(ATEN2011_serial->serial->dev,
- port->
- bulk_out_endpointAddress),
- urb->transfer_buffer, transfer_size,
- ATEN2011_bulk_out_data_callback,
- ATEN2011_port);
-
- data1 = urb->transfer_buffer;
- dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
- /* for(i=0;i < urb->actual_length;i++) */
- /* dbg("Data is %c ",data1[i]); */
-
- /* send it down the pipe */
- status = usb_submit_urb(urb, GFP_ATOMIC);
-
- if (status) {
- err("%s - usb_submit_urb(write bulk) failed with status = %d",
- __func__, status);
- bytes_sent = status;
- goto exit;
- }
- bytes_sent = transfer_size;
- ATEN2011_port->icount.tx += transfer_size;
- dbg("ATEN2011_port->icount.tx is %d:", ATEN2011_port->icount.tx);
-
-exit:
- return bytes_sent;
-}
-
-static void ATEN2011_throttle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ATENINTL_port *ATEN2011_port;
- int status;
-
- dbg("- port %d", port->number);
-
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return;
-
- if (!ATEN2011_port->open) {
- dbg("%s", "port not opened");
- return;
- }
-
- dbg("%s", "Entering .......... ");
-
- if (!tty) {
- dbg("%s - no tty available", __func__);
- return;
- }
-
- /* if we are implementing XON/XOFF, send the stop character */
- if (I_IXOFF(tty)) {
- unsigned char stop_char = STOP_CHAR(tty);
- status = ATEN2011_write(tty, port, &stop_char, 1);
- if (status <= 0)
- return;
- }
-
- /* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
- ATEN2011_port->shadowMCR &= ~MCR_RTS;
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER,
- ATEN2011_port->shadowMCR);
- if (status < 0)
- return;
- }
-
- return;
-}
-
-static void ATEN2011_unthrottle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- int status;
- struct ATENINTL_port *ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return;
-
- if (!ATEN2011_port->open) {
- dbg("%s - port not opened", __func__);
- return;
- }
-
- dbg("%s", "Entering .......... ");
-
- if (!tty) {
- dbg("%s - no tty available", __func__);
- return;
- }
-
- /* if we are implementing XON/XOFF, send the start character */
- if (I_IXOFF(tty)) {
- unsigned char start_char = START_CHAR(tty);
- status = ATEN2011_write(tty, port, &start_char, 1);
- if (status <= 0)
- return;
- }
-
- /* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
- ATEN2011_port->shadowMCR |= MCR_RTS;
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER,
- ATEN2011_port->shadowMCR);
- if (status < 0)
- return;
- }
-
- return;
-}
-
-static int ATEN2011_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ATENINTL_port *ATEN2011_port;
- unsigned int result;
- __u16 msr;
- __u16 mcr;
- /* unsigned int mcr; */
- int status = 0;
- ATEN2011_port = usb_get_serial_port_data(port);
-
- dbg("%s - port %d", __func__, port->number);
-
- if (ATEN2011_port == NULL)
- return -ENODEV;
-
- status = get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
- status = get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
- /* mcr = ATEN2011_port->shadowMCR; */
- /* COMMENT2: the Fallowing three line are commented for updating only MSR values */
- result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
- | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
- | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
- | ((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS : 0)
- | ((msr & ATEN2011_MSR_CD) ? TIOCM_CAR : 0)
- | ((msr & ATEN2011_MSR_RI) ? TIOCM_RI : 0)
- | ((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR : 0);
-
- dbg("%s - 0x%04X", __func__, result);
-
- return result;
-}
-
-static int ATEN2011_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ATENINTL_port *ATEN2011_port;
- unsigned int mcr;
- unsigned int status;
-
- dbg("%s - port %d", __func__, port->number);
-
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return -ENODEV;
-
- mcr = ATEN2011_port->shadowMCR;
- if (clear & TIOCM_RTS)
- mcr &= ~MCR_RTS;
- if (clear & TIOCM_DTR)
- mcr &= ~MCR_DTR;
- if (clear & TIOCM_LOOP)
- mcr &= ~MCR_LOOPBACK;
-
- if (set & TIOCM_RTS)
- mcr |= MCR_RTS;
- if (set & TIOCM_DTR)
- mcr |= MCR_DTR;
- if (set & TIOCM_LOOP)
- mcr |= MCR_LOOPBACK;
-
- ATEN2011_port->shadowMCR = mcr;
-
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
- if (status < 0) {
- dbg("setting MODEM_CONTROL_REGISTER Failed");
- return -1;
- }
-
- return 0;
-}
-
-static void ATEN2011_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios)
-{
- int status;
- unsigned int cflag;
- struct usb_serial *serial;
- struct ATENINTL_port *ATEN2011_port;
-
- dbg("ATEN2011_set_termios: START");
-
- serial = port->serial;
-
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return;
-
- if (!ATEN2011_port->open) {
- dbg("%s - port not opened", __func__);
- return;
- }
-
- dbg("%s", "setting termios - ");
-
- cflag = tty->termios->c_cflag;
-
- dbg("%s - cflag %08x iflag %08x", __func__,
- tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
-
- if (old_termios) {
- dbg("%s - old clfag %08x old iflag %08x", __func__,
- old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
- }
-
- dbg("%s - port %d", __func__, port->number);
-
- /* change the port settings to the new ones specified */
-
- ATEN2011_change_port_settings(tty, ATEN2011_port, old_termios);
-
- if (!ATEN2011_port->read_urb) {
- dbg("%s", "URB KILLED !!!!!");
- return;
- }
-
- if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
- ATEN2011_port->read_urb->dev = serial->dev;
- status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
- if (status) {
- dbg
- (" usb_submit_urb(read bulk) failed, status = %d",
- status);
- }
- }
- return;
-}
-
-static int get_lsr_info(struct tty_struct *tty,
- struct ATENINTL_port *ATEN2011_port,
- unsigned int __user *value)
-{
- int count;
- unsigned int result = 0;
-
- count = ATEN2011_chars_in_buffer(tty);
- if (count == 0) {
- dbg("%s -- Empty", __func__);
- result = TIOCSER_TEMT;
- }
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-static int get_number_bytes_avail(struct tty_struct *tty,
- struct ATENINTL_port *ATEN2011_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
-
- if (!tty)
- return -ENOIOCTLCMD;
-
- result = tty->read_cnt;
-
- dbg("%s(%d) = %d", __func__, ATEN2011_port->port->number, result);
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
-
- return -ENOIOCTLCMD;
-}
-
-static int set_modem_info(struct ATENINTL_port *ATEN2011_port, unsigned int cmd,
- unsigned int __user *value)
-{
- unsigned int mcr;
- unsigned int arg;
- __u16 Data;
- int status;
- struct usb_serial_port *port;
-
- if (ATEN2011_port == NULL)
- return -1;
-
- port = (struct usb_serial_port *)ATEN2011_port->port;
-
- mcr = ATEN2011_port->shadowMCR;
-
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- mcr |= MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr |= MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr |= MCR_LOOPBACK;
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- mcr &= ~MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr &= ~MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr &= ~MCR_LOOPBACK;
- break;
-
- case TIOCMSET:
- /* turn off the RTS and DTR and LOOPBACK
- * and then only turn on what was asked to */
- mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
- mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
- mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
- mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
- break;
- }
-
- ATEN2011_port->shadowMCR = mcr;
-
- Data = ATEN2011_port->shadowMCR;
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- if (status < 0) {
- dbg("setting MODEM_CONTROL_REGISTER Failed");
- return -1;
- }
-
- return 0;
-}
-
-static int get_modem_info(struct ATENINTL_port *ATEN2011_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
- __u16 msr;
- unsigned int mcr = ATEN2011_port->shadowMCR;
- int status;
-
- status = get_uart_reg(ATEN2011_port->port, MODEM_STATUS_REGISTER, &msr);
- result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
- |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
- |((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
- |((msr & ATEN2011_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */
- |((msr & ATEN2011_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
- |((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
-
- dbg("%s -- %x", __func__, result);
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-static int get_serial_info(struct ATENINTL_port *ATEN2011_port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- if (ATEN2011_port == NULL)
- return -1;
-
- if (!retinfo)
- return -EFAULT;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = ATEN2011_port->port->serial->minor;
- if (tmp.line == SERIAL_TTY_NO_MINOR)
- tmp.line = 0;
- tmp.port = ATEN2011_port->port->number;
- tmp.irq = 0;
- tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
- tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- tmp.baud_base = 9600;
- tmp.close_delay = 5 * HZ;
- tmp.closing_wait = 30 * HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int ATEN2011_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ATENINTL_port *ATEN2011_port;
- struct async_icount cnow;
- struct async_icount cprev;
- struct serial_icounter_struct icount;
- int ATENret = 0;
- unsigned int __user *user_arg = (unsigned int __user *)arg;
-
- ATEN2011_port = usb_get_serial_port_data(port);
-
- if (ATEN2011_port == NULL)
- return -1;
-
- dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
-
- switch (cmd) {
- /* return number of bytes available */
-
- case TIOCINQ:
- dbg("%s (%d) TIOCINQ", __func__, port->number);
- return get_number_bytes_avail(tty, ATEN2011_port, user_arg);
- break;
-
- case TIOCOUTQ:
- dbg("%s (%d) TIOCOUTQ", __func__, port->number);
- return put_user(ATEN2011_chars_in_buffer(tty), user_arg);
- break;
-
- case TIOCSERGETLSR:
- dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
- return get_lsr_info(tty, ATEN2011_port, user_arg);
- return 0;
-
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
- port->number);
- ATENret = set_modem_info(ATEN2011_port, cmd, user_arg);
- return ATENret;
-
- case TIOCMGET:
- dbg("%s (%d) TIOCMGET", __func__, port->number);
- return get_modem_info(ATEN2011_port, user_arg);
-
- case TIOCGSERIAL:
- dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
- return get_serial_info(ATEN2011_port,
- (struct serial_struct __user *)arg);
-
- case TIOCSSERIAL:
- dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
- break;
-
- case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
- cprev = ATEN2011_port->icount;
- while (1) {
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = ATEN2011_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
- case TIOCGICOUNT:
- cnow = ATEN2011_port->icount;
- icount.cts = cnow.cts;
- icount.dsr = cnow.dsr;
- icount.rng = cnow.rng;
- icount.dcd = cnow.dcd;
- icount.rx = cnow.rx;
- icount.tx = cnow.tx;
- icount.frame = cnow.frame;
- icount.overrun = cnow.overrun;
- icount.parity = cnow.parity;
- icount.brk = cnow.brk;
- icount.buf_overrun = cnow.buf_overrun;
-
- dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
- port->number, icount.rx, icount.tx);
- if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
- return -EFAULT;
- return 0;
-
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
-static int ATEN2011_calc_baud_rate_divisor(int baudRate, int *divisor,
- __u16 *clk_sel_val)
-{
- dbg("%s - %d", __func__, baudRate);
-
- if (baudRate <= 115200) {
- *divisor = 115200 / baudRate;
- *clk_sel_val = 0x0;
- }
- if ((baudRate > 115200) && (baudRate <= 230400)) {
- *divisor = 230400 / baudRate;
- *clk_sel_val = 0x10;
- } else if ((baudRate > 230400) && (baudRate <= 403200)) {
- *divisor = 403200 / baudRate;
- *clk_sel_val = 0x20;
- } else if ((baudRate > 403200) && (baudRate <= 460800)) {
- *divisor = 460800 / baudRate;
- *clk_sel_val = 0x30;
- } else if ((baudRate > 460800) && (baudRate <= 806400)) {
- *divisor = 806400 / baudRate;
- *clk_sel_val = 0x40;
- } else if ((baudRate > 806400) && (baudRate <= 921600)) {
- *divisor = 921600 / baudRate;
- *clk_sel_val = 0x50;
- } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
- *divisor = 1572864 / baudRate;
- *clk_sel_val = 0x60;
- } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
- *divisor = 3145728 / baudRate;
- *clk_sel_val = 0x70;
- }
- return 0;
-}
-
-static int ATEN2011_send_cmd_write_baud_rate(struct ATENINTL_port
- *ATEN2011_port, int baudRate)
-{
- int divisor = 0;
- int status;
- __u16 Data;
- unsigned char number;
- __u16 clk_sel_val;
- struct usb_serial_port *port;
- int minor;
-
- if (ATEN2011_port == NULL)
- return -1;
-
- port = (struct usb_serial_port *)ATEN2011_port->port;
-
- dbg("%s", "Entering .......... ");
-
- minor = ATEN2011_port->port->serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
- number = ATEN2011_port->port->number - minor;
-
- dbg("%s - port = %d, baud = %d", __func__,
- ATEN2011_port->port->number, baudRate);
- /* reset clk_uart_sel in spregOffset */
- if (baudRate > 115200) {
-#ifdef HW_flow_control
- /*
- * NOTE: need to see the pther register to modify
- * setting h/w flow control bit to 1;
- */
- /* Data = ATEN2011_port->shadowMCR; */
- Data = 0x2b;
- ATEN2011_port->shadowMCR = Data;
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- if (status < 0) {
- dbg("Writing spreg failed in set_serial_baud");
- return -1;
- }
-#endif
-
- } else {
-#ifdef HW_flow_control
- /* setting h/w flow control bit to 0; */
- /* Data = ATEN2011_port->shadowMCR; */
- Data = 0xb;
- ATEN2011_port->shadowMCR = Data;
- status = set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- if (status < 0) {
- dbg("Writing spreg failed in set_serial_baud");
- return -1;
- }
-#endif
-
- }
-
- if (1) /* baudRate <= 115200) */ {
- clk_sel_val = 0x0;
- Data = 0x0;
- status =
- ATEN2011_calc_baud_rate_divisor(baudRate, &divisor,
- &clk_sel_val);
- status = get_reg_sync(port, ATEN2011_port->SpRegOffset, &Data);
- if (status < 0) {
- dbg("reading spreg failed in set_serial_baud");
- return -1;
- }
- Data = (Data & 0x8f) | clk_sel_val;
- status = set_reg_sync(port, ATEN2011_port->SpRegOffset, Data);
- if (status < 0) {
- dbg("Writing spreg failed in set_serial_baud");
- return -1;
- }
- /* Calculate the Divisor */
-
- if (status) {
- err("%s - bad baud rate", __func__);
- dbg("%s", "bad baud rate");
- return status;
- }
- /* Enable access to divisor latch */
- Data = ATEN2011_port->shadowLCR | SERIAL_LCR_DLAB;
- ATEN2011_port->shadowLCR = Data;
- set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
- /* Write the divisor */
- Data = (unsigned char)(divisor & 0xff);
- dbg("set_serial_baud Value to write DLL is %x", Data);
- set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
-
- Data = (unsigned char)((divisor & 0xff00) >> 8);
- dbg("set_serial_baud Value to write DLM is %x", Data);
- set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
-
- /* Disable access to divisor latch */
- Data = ATEN2011_port->shadowLCR & ~SERIAL_LCR_DLAB;
- ATEN2011_port->shadowLCR = Data;
- set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
- }
-
- return status;
-}
-
-static void ATEN2011_change_port_settings(struct tty_struct *tty,
- struct ATENINTL_port *ATEN2011_port,
- struct ktermios *old_termios)
-{
- int baud;
- unsigned cflag;
- unsigned iflag;
- __u8 lData;
- __u8 lParity;
- __u8 lStop;
- int status;
- __u16 Data;
- struct usb_serial_port *port;
- struct usb_serial *serial;
-
- if (ATEN2011_port == NULL)
- return;
-
- port = (struct usb_serial_port *)ATEN2011_port->port;
-
- serial = port->serial;
-
- dbg("%s - port %d", __func__, ATEN2011_port->port->number);
-
- if (!ATEN2011_port->open) {
- dbg("%s - port not opened", __func__);
- return;
- }
-
- if ((!tty) || (!tty->termios)) {
- dbg("%s - no tty structures", __func__);
- return;
- }
-
- dbg("%s", "Entering .......... ");
-
- lData = LCR_BITS_8;
- lStop = LCR_STOP_1;
- lParity = LCR_PAR_NONE;
-
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
-
- /* Change the number of bits */
-
- /* COMMENT1: the below Line"if(cflag & CSIZE)" is added for the errors we get for serial loop data test i.e serial_loopback.pl -v */
- /* if(cflag & CSIZE) */
- {
- switch (cflag & CSIZE) {
- case CS5:
- lData = LCR_BITS_5;
- break;
-
- case CS6:
- lData = LCR_BITS_6;
- break;
-
- case CS7:
- lData = LCR_BITS_7;
- break;
- default:
- case CS8:
- lData = LCR_BITS_8;
- break;
- }
- }
- /* Change the Parity bit */
- if (cflag & PARENB) {
- if (cflag & PARODD) {
- lParity = LCR_PAR_ODD;
- dbg("%s - parity = odd", __func__);
- } else {
- lParity = LCR_PAR_EVEN;
- dbg("%s - parity = even", __func__);
- }
-
- } else {
- dbg("%s - parity = none", __func__);
- }
-
- if (cflag & CMSPAR)
- lParity = lParity | 0x20;
-
- /* Change the Stop bit */
- if (cflag & CSTOPB) {
- lStop = LCR_STOP_2;
- dbg("%s - stop bits = 2", __func__);
- } else {
- lStop = LCR_STOP_1;
- dbg("%s - stop bits = 1", __func__);
- }
-
- /* Update the LCR with the correct value */
- ATEN2011_port->shadowLCR &=
- ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
- ATEN2011_port->shadowLCR |= (lData | lParity | lStop);
-
- dbg
- ("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is %x",
- ATEN2011_port->shadowLCR);
- /* Disable Interrupts */
- Data = 0x00;
- set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
- Data = 0x00;
- set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-
- Data = 0xcf;
- set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
-
- /* Send the updated LCR value to the ATEN2011 */
- Data = ATEN2011_port->shadowLCR;
-
- set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
- Data = 0x00b;
- ATEN2011_port->shadowMCR = Data;
- set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- Data = 0x00b;
- set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-
- /* set up the MCR register and send it to the ATEN2011 */
-
- ATEN2011_port->shadowMCR = MCR_MASTER_IE;
- if (cflag & CBAUD)
- ATEN2011_port->shadowMCR |= (MCR_DTR | MCR_RTS);
-
- if (cflag & CRTSCTS)
- ATEN2011_port->shadowMCR |= (MCR_XON_ANY);
- else
- ATEN2011_port->shadowMCR &= ~(MCR_XON_ANY);
-
- Data = ATEN2011_port->shadowMCR;
- set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
-
- /* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(tty);
-
- if (!baud) {
- /* pick a default, any default... */
- dbg("%s", "Picked default baud...");
- baud = 9600;
- }
-
- dbg("%s - baud rate = %d", __func__, baud);
- status = ATEN2011_send_cmd_write_baud_rate(ATEN2011_port, baud);
-
- /* Enable Interrupts */
- Data = 0x0c;
- set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
-
- if (ATEN2011_port->read_urb->status != -EINPROGRESS) {
- ATEN2011_port->read_urb->dev = serial->dev;
-
- status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
-
- if (status) {
- dbg
- (" usb_submit_urb(read bulk) failed, status = %d",
- status);
- }
- }
- dbg
- ("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is End %x",
- ATEN2011_port->shadowLCR);
-
- return;
-}
-
-static int ATEN2011_calc_num_ports(struct usb_serial *serial)
-{
-
- __u16 Data = 0x00;
- int ret = 0;
- int ATEN2011_2or4ports;
- ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- ATEN_RDREQ, ATEN_RD_RTYPE, 0, GPIO_REGISTER,
- &Data, VENDOR_READ_LENGTH, ATEN_WDR_TIMEOUT);
-
-/* ghostgum: here is where the problem appears to bet */
-/* Which of the following are needed? */
-/* Greg used the serial->type->num_ports=2 */
-/* But the code in the ATEN2011_open relies on serial->num_ports=2 */
- if ((Data & 0x01) == 0) {
- ATEN2011_2or4ports = 2;
- serial->type->num_ports = 2;
- serial->num_ports = 2;
- }
- /* else if(serial->interface->cur_altsetting->desc.bNumEndpoints == 9) */
- else {
- ATEN2011_2or4ports = 4;
- serial->type->num_ports = 4;
- serial->num_ports = 4;
-
- }
-
- return ATEN2011_2or4ports;
-}
-
-static int ATEN2011_startup(struct usb_serial *serial)
-{
- struct ATENINTL_serial *ATEN2011_serial;
- struct ATENINTL_port *ATEN2011_port;
- struct usb_device *dev;
- int i, status;
- int minor;
-
- __u16 Data;
- dbg("%s", " ATEN2011_startup :entering..........");
-
- if (!serial) {
- dbg("%s", "Invalid Handler");
- return -1;
- }
-
- dev = serial->dev;
-
- dbg("%s", "Entering...");
-
- /* create our private serial structure */
- ATEN2011_serial = kzalloc(sizeof(struct ATENINTL_serial), GFP_KERNEL);
- if (ATEN2011_serial == NULL) {
- err("%s - Out of memory", __func__);
- return -ENOMEM;
- }
-
- /* resetting the private structure field values to zero */
- memset(ATEN2011_serial, 0, sizeof(struct ATENINTL_serial));
-
- ATEN2011_serial->serial = serial;
- /* initilize status polling flag to 0 */
- ATEN2011_serial->status_polling_started = 0;
-
- usb_set_serial_data(serial, ATEN2011_serial);
- ATEN2011_serial->ATEN2011_spectrum_2or4ports =
- ATEN2011_calc_num_ports(serial);
- /* we set up the pointers to the endpoints in the ATEN2011_open *
- * function, as the structures aren't created yet. */
-
- /* set up port private structures */
- for (i = 0; i < serial->num_ports; ++i) {
- ATEN2011_port =
- kmalloc(sizeof(struct ATENINTL_port), GFP_KERNEL);
- if (ATEN2011_port == NULL) {
- err("%s - Out of memory", __func__);
- usb_set_serial_data(serial, NULL);
- kfree(ATEN2011_serial);
- return -ENOMEM;
- }
- memset(ATEN2011_port, 0, sizeof(struct ATENINTL_port));
-
- /*
- * Initialize all port interrupt end point to port 0
- * int endpoint. Our device has only one interrupt end point
- * comman to all port
- */
- /* serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; */
-
- ATEN2011_port->port = serial->port[i];
- usb_set_serial_port_data(serial->port[i], ATEN2011_port);
-
- minor = serial->port[i]->serial->minor;
- if (minor == SERIAL_TTY_NO_MINOR)
- minor = 0;
- ATEN2011_port->port_num =
- ((serial->port[i]->number - minor) + 1);
-
- if (ATEN2011_port->port_num == 1) {
- ATEN2011_port->SpRegOffset = 0x0;
- ATEN2011_port->ControlRegOffset = 0x1;
- ATEN2011_port->DcrRegOffset = 0x4;
- } else if ((ATEN2011_port->port_num == 2)
- && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
- 4)) {
- ATEN2011_port->SpRegOffset = 0x8;
- ATEN2011_port->ControlRegOffset = 0x9;
- ATEN2011_port->DcrRegOffset = 0x16;
- } else if ((ATEN2011_port->port_num == 2)
- && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
- 2)) {
- ATEN2011_port->SpRegOffset = 0xa;
- ATEN2011_port->ControlRegOffset = 0xb;
- ATEN2011_port->DcrRegOffset = 0x19;
- } else if ((ATEN2011_port->port_num == 3)
- && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
- 4)) {
- ATEN2011_port->SpRegOffset = 0xa;
- ATEN2011_port->ControlRegOffset = 0xb;
- ATEN2011_port->DcrRegOffset = 0x19;
- } else if ((ATEN2011_port->port_num == 4)
- && (ATEN2011_serial->ATEN2011_spectrum_2or4ports ==
- 4)) {
- ATEN2011_port->SpRegOffset = 0xc;
- ATEN2011_port->ControlRegOffset = 0xd;
- ATEN2011_port->DcrRegOffset = 0x1c;
- }
-
- usb_set_serial_port_data(serial->port[i], ATEN2011_port);
-
- /* enable rx_disable bit in control register */
-
- status = get_reg_sync(serial->port[i],
- ATEN2011_port->ControlRegOffset, &Data);
- if (status < 0) {
- dbg("Reading ControlReg failed status-0x%x",
- status);
- break;
- } else
- dbg
- ("ControlReg Reading success val is %x, status%d",
- Data, status);
- Data |= 0x08; /* setting driver done bit */
- Data |= 0x04; /* sp1_bit to have cts change reflect in modem status reg */
-
- /* Data |= 0x20; */ /* rx_disable bit */
- status = set_reg_sync(serial->port[i],
- ATEN2011_port->ControlRegOffset, Data);
- if (status < 0) {
- dbg
- ("Writing ControlReg failed(rx_disable) status-0x%x",
- status);
- break;
- } else
- dbg
- ("ControlReg Writing success(rx_disable) status%d",
- status);
-
- /*
- * Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
- * and 0x24 in DCR3
- */
- Data = 0x01;
- status = set_reg_sync(serial->port[i],
- (__u16)(ATEN2011_port->DcrRegOffset + 0),
- Data);
- if (status < 0) {
- dbg("Writing DCR0 failed status-0x%x", status);
- break;
- } else
- dbg("DCR0 Writing success status%d", status);
-
- Data = 0x05;
- status = set_reg_sync(serial->port[i],
- (__u16)(ATEN2011_port->DcrRegOffset + 1),
- Data);
- if (status < 0) {
- dbg("Writing DCR1 failed status-0x%x", status);
- break;
- } else
- dbg("DCR1 Writing success status%d", status);
-
- Data = 0x24;
- status = set_reg_sync(serial->port[i],
- (__u16)(ATEN2011_port->DcrRegOffset + 2),
- Data);
- if (status < 0) {
- dbg("Writing DCR2 failed status-0x%x", status);
- break;
- } else
- dbg("DCR2 Writing success status%d", status);
-
- /* write values in clkstart0x0 and clkmulti 0x20 */
- Data = 0x0;
- status = set_reg_sync(serial->port[i], CLK_START_VALUE_REGISTER,
- Data);
- if (status < 0) {
- dbg
- ("Writing CLK_START_VALUE_REGISTER failed status-0x%x",
- status);
- break;
- } else
- dbg
- ("CLK_START_VALUE_REGISTER Writing success status%d",
- status);
-
- Data = 0x20;
- status = set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
- Data);
- if (status < 0) {
- dbg
- ("Writing CLK_MULTI_REGISTER failed status-0x%x",
- status);
- break;
- } else
- dbg("CLK_MULTI_REGISTER Writing success status%d",
- status);
-
- /* Zero Length flag register */
- if ((ATEN2011_port->port_num != 1)
- && (ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2)) {
-
- Data = 0xff;
- status = set_reg_sync(serial->port[i],
- (__u16)(ZLP_REG1 + ((__u16)ATEN2011_port->port_num)),
- Data);
- dbg("ZLIP offset%x",
- (__u16) (ZLP_REG1 +
- ((__u16) ATEN2011_port->port_num)));
- if (status < 0) {
- dbg
- ("Writing ZLP_REG%d failed status-0x%x",
- i + 2, status);
- break;
- } else
- dbg("ZLP_REG%d Writing success status%d",
- i + 2, status);
- } else {
- Data = 0xff;
- status = set_reg_sync(serial->port[i],
- (__u16)(ZLP_REG1 + ((__u16)ATEN2011_port->port_num) - 0x1),
- Data);
- dbg("ZLIP offset%x",
- (__u16) (ZLP_REG1 +
- ((__u16) ATEN2011_port->port_num) -
- 0x1));
- if (status < 0) {
- dbg
- ("Writing ZLP_REG%d failed status-0x%x",
- i + 1, status);
- break;
- } else
- dbg("ZLP_REG%d Writing success status%d",
- i + 1, status);
-
- }
- ATEN2011_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC);
- ATEN2011_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
-
- }
-
- /* Zero Length flag enable */
- Data = 0x0f;
- status = set_reg_sync(serial->port[0], ZLP_REG5, Data);
- if (status < 0) {
- dbg("Writing ZLP_REG5 failed status-0x%x", status);
- return -1;
- } else
- dbg("ZLP_REG5 Writing success status%d", status);
-
- /* setting configuration feature to one */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
- return 0;
-}
-
-static void ATEN2011_release(struct usb_serial *serial)
-{
- int i;
- struct ATENINTL_port *ATEN2011_port;
-
- /* check for the ports to be closed,close the ports and disconnect */
-
- /* free private structure allocated for serial port *
- * stop reads and writes on all ports */
-
- for (i = 0; i < serial->num_ports; ++i) {
- ATEN2011_port = usb_get_serial_port_data(serial->port[i]);
- kfree(ATEN2011_port->ctrl_buf);
- usb_kill_urb(ATEN2011_port->control_urb);
- kfree(ATEN2011_port);
- usb_set_serial_port_data(serial->port[i], NULL);
- }
-
- /* free private structure allocated for serial device */
-
- kfree(usb_get_serial_data(serial));
- usb_set_serial_data(serial, NULL);
-}
-
-static struct usb_serial_driver aten_serial_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "aten2011",
- },
- .description = DRIVER_DESC,
- .id_table = id_table,
- .open = ATEN2011_open,
- .close = ATEN2011_close,
- .write = ATEN2011_write,
- .write_room = ATEN2011_write_room,
- .chars_in_buffer = ATEN2011_chars_in_buffer,
- .throttle = ATEN2011_throttle,
- .unthrottle = ATEN2011_unthrottle,
- .calc_num_ports = ATEN2011_calc_num_ports,
-
- .ioctl = ATEN2011_ioctl,
- .set_termios = ATEN2011_set_termios,
- .break_ctl = ATEN2011_break,
- .tiocmget = ATEN2011_tiocmget,
- .tiocmset = ATEN2011_tiocmset,
- .attach = ATEN2011_startup,
- .release = ATEN2011_release,
- .read_bulk_callback = ATEN2011_bulk_in_callback,
- .read_int_callback = ATEN2011_interrupt_callback,
-};
-
-static struct usb_driver aten_driver = {
- .name = "aten2011",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-static int __init aten_init(void)
-{
- int retval;
-
- /* Register with the usb serial */
- retval = usb_serial_register(&aten_serial_driver);
- if (retval)
- return retval;
-
- printk(KERN_INFO KBUILD_MODNAME ":"
- DRIVER_DESC " " DRIVER_VERSION "\n");
-
- /* Register with the usb */
- retval = usb_register(&aten_driver);
- if (retval)
- usb_serial_deregister(&aten_serial_driver);
-
- return retval;
-}
-
-static void __exit aten_exit(void)
-{
- usb_deregister(&aten_driver);
- usb_serial_deregister(&aten_serial_driver);
-}
-
-module_init(aten_init);
-module_exit(aten_exit);
-
-/* Module information */
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
index 0ab9d15f3439..f5416af1e902 100644
--- a/drivers/staging/udlfb/udlfb.c
+++ b/drivers/staging/udlfb/udlfb.c
@@ -21,6 +21,7 @@
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/mutex.h>
+#include <linux/vmalloc.h>
#include "udlfb.h"
diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c
index 3e8cf08b87e6..b905e7b43a19 100644
--- a/drivers/staging/winbond/wb35rx.c
+++ b/drivers/staging/winbond/wb35rx.c
@@ -40,7 +40,8 @@ static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int Pac
rx_status.phymode = MODE_IEEE80211B;
*/
- ieee80211_rx_irqsafe(hw, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(hw, skb);
}
static void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 90f499e00dc5..c273c034a830 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
p80211_metawep_t p80211_wep;
if (skb == NULL)
- return 0;
+ return NETDEV_TX_OK;
if (wlandev->state != WLAN_DEVICE_OPEN) {
result = 1;
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 24dfb33f90cb..a16c538d0132 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -80,38 +80,18 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int max_tx;
int i;
- /* Allocate space for the SS endpoint companion descriptor */
- ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
- GFP_KERNEL);
- if (!ep->ss_ep_comp)
- return -ENOMEM;
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
" interface %d altsetting %d ep %d: "
"using minimum values\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
- ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
- ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
- ep->ss_ep_comp->desc.bMaxBurst = 0;
- /*
- * Leave bmAttributes as zero, which will mean no streams for
- * bulk, and isoc won't support multiple bursts of packets.
- * With bursts of only one packet, and a Mult of 1, the max
- * amount of data moved per endpoint service interval is one
- * packet.
- */
- if (usb_endpoint_xfer_isoc(&ep->desc) ||
- usb_endpoint_xfer_int(&ep->desc))
- ep->ss_ep_comp->desc.wBytesPerInterval =
- ep->desc.wMaxPacketSize;
/*
* The next descriptor is for an Endpoint or Interface,
* no extra descriptors to copy into the companion structure,
* and we didn't eat up any of the buffer.
*/
- retval = 0;
- goto valid;
+ return 0;
}
memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
desc = &ep->ss_ep_comp->desc;
@@ -320,6 +300,28 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
buffer += i;
size -= i;
+ /* Allocate space for the SS endpoint companion descriptor */
+ endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
+ GFP_KERNEL);
+ if (!endpoint->ss_ep_comp)
+ return -ENOMEM;
+
+ /* Fill in some default values (may be overwritten later) */
+ endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
+ endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
+ endpoint->ss_ep_comp->desc.bMaxBurst = 0;
+ /*
+ * Leave bmAttributes as zero, which will mean no streams for
+ * bulk, and isoc won't support multiple bursts of packets.
+ * With bursts of only one packet, and a Mult of 1, the max
+ * amount of data moved per endpoint service interval is one
+ * packet.
+ */
+ if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
+ usb_endpoint_xfer_int(&endpoint->desc))
+ endpoint->ss_ep_comp->desc.wBytesPerInterval =
+ endpoint->desc.wMaxPacketSize;
+
if (size > 0) {
retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, num_ep, buffer,
@@ -329,6 +331,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
retval = buffer - buffer0;
}
} else {
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "endpoint 0x%X has no "
+ "SuperSpeed companion descriptor\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
retval = buffer - buffer0;
}
} else {
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 38b8bce782d6..4247eccf858c 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -595,7 +595,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
if (!ps)
goto out;
- ret = -ENOENT;
+ ret = -ENODEV;
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
@@ -1321,7 +1321,8 @@ static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
{
__u32 uptr;
- if (get_user(kurb->type, &uurb->type) ||
+ if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) ||
+ __get_user(kurb->type, &uurb->type) ||
__get_user(kurb->endpoint, &uurb->endpoint) ||
__get_user(kurb->status, &uurb->status) ||
__get_user(kurb->flags, &uurb->flags) ||
@@ -1536,8 +1537,9 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
u32 udata;
uioc = compat_ptr((long)arg);
- if (get_user(ctrl.ifno, &uioc->ifno) ||
- get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
+ if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) ||
+ __get_user(ctrl.ifno, &uioc->ifno) ||
+ __get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
__get_user(udata, &uioc->data))
return -EFAULT;
ctrl.data = compat_ptr(udata);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7f8e83a954ac..b7f10bc25c2c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -360,16 +360,6 @@ config USB_M66592
default USB_GADGET
select USB_GADGET_SELECTED
-config SUPERH_BUILT_IN_M66592
- boolean "Enable SuperH built-in USB like the M66592"
- depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
- help
- SH7722 has USB like the M66592.
-
- The transfer rate is very slow when use "Ethernet Gadget".
- However, this problem is improved if change a value of
- NET_IP_ALIGN to 4.
-
#
# Controllers available only in discrete form (and all PCI controllers)
#
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 96fb118355b0..d17f1082df96 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -256,7 +256,7 @@ out:
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
}
- return 0;
+ return NETDEV_TX_OK;
}
static int pn_net_mtu(struct net_device *dev, int new_mtu)
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 43dcf9e1af6b..a61c70caff12 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -31,38 +31,12 @@
#include "m66592-udc.h"
-
MODULE_DESCRIPTION("M66592 USB gadget driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:m66592_udc");
-#define DRIVER_VERSION "18 Oct 2007"
-
-/* module parameters */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-static unsigned short endian = M66592_LITTLE;
-module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
-#else
-static unsigned short clock = M66592_XTAL24;
-module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
- "(default=16384)");
-
-static unsigned short vif = M66592_LDRV;
-module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
-
-static unsigned short endian;
-module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
-
-static unsigned short irq_sense = M66592_INTL;
-module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
- "(default=2)");
-#endif
+#define DRIVER_VERSION "21 July 2009"
static const char udc_name[] = "m66592_udc";
static const char *m66592_ep_name[] = {
@@ -244,6 +218,7 @@ static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
{
struct m66592_ep *ep = m66592->pipenum2ep[pipenum];
+ unsigned short mbw;
if (ep->use_dma)
return;
@@ -252,7 +227,12 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
ndelay(450);
- m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ if (m66592->pdata->on_chip)
+ mbw = M66592_MBW_32;
+ else
+ mbw = M66592_MBW_16;
+
+ m66592_bset(m66592, mbw, ep->fifosel);
}
static int pipe_buffer_setting(struct m66592 *m66592,
@@ -276,24 +256,27 @@ static int pipe_buffer_setting(struct m66592 *m66592,
buf_bsize = 0;
break;
case M66592_BULK:
- bufnum = m66592->bi_bufnum +
- (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
- m66592->bi_bufnum += 16;
+ /* isochronous pipes may be used as bulk pipes */
+ if (info->pipe > M66592_BASE_PIPENUM_BULK)
+ bufnum = info->pipe - M66592_BASE_PIPENUM_BULK;
+ else
+ bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC;
+
+ bufnum = M66592_BASE_BUFNUM + (bufnum * 16);
buf_bsize = 7;
pipecfg |= M66592_DBLB;
if (!info->dir_in)
pipecfg |= M66592_SHTNAK;
break;
case M66592_ISO:
- bufnum = m66592->bi_bufnum +
+ bufnum = M66592_BASE_BUFNUM +
(info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
- m66592->bi_bufnum += 16;
buf_bsize = 7;
break;
}
- if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
- pr_err("m66592 pipe memory is insufficient(%d)\n",
- m66592->bi_bufnum);
+
+ if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) {
+ pr_err("m66592 pipe memory is insufficient\n");
return -ENOMEM;
}
@@ -313,17 +296,6 @@ static void pipe_buffer_release(struct m66592 *m66592,
if (info->pipe == 0)
return;
- switch (info->type) {
- case M66592_BULK:
- if (is_bulk_pipe(info->pipe))
- m66592->bi_bufnum -= 16;
- break;
- case M66592_ISO:
- if (is_isoc_pipe(info->pipe))
- m66592->bi_bufnum -= 16;
- break;
- }
-
if (is_bulk_pipe(info->pipe)) {
m66592->bulk--;
} else if (is_interrupt_pipe(info->pipe))
@@ -340,6 +312,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
static void pipe_initialize(struct m66592_ep *ep)
{
struct m66592 *m66592 = ep->m66592;
+ unsigned short mbw;
m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel);
@@ -351,7 +324,12 @@ static void pipe_initialize(struct m66592_ep *ep)
ndelay(450);
- m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ if (m66592->pdata->on_chip)
+ mbw = M66592_MBW_32;
+ else
+ mbw = M66592_MBW_16;
+
+ m66592_bset(m66592, mbw, ep->fifosel);
}
}
@@ -367,15 +345,13 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
ep->fifosel = M66592_D0FIFOSEL;
ep->fifoctr = M66592_D0FIFOCTR;
ep->fifotrn = M66592_D0FIFOTRN;
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
- } else if (m66592->num_dma == 1) {
+ } else if (!m66592->pdata->on_chip && m66592->num_dma == 1) {
m66592->num_dma++;
ep->use_dma = 1;
ep->fifoaddr = M66592_D1FIFO;
ep->fifosel = M66592_D1FIFOSEL;
ep->fifoctr = M66592_D1FIFOCTR;
ep->fifotrn = M66592_D1FIFOTRN;
-#endif
} else {
ep->use_dma = 0;
ep->fifoaddr = M66592_CFIFO;
@@ -620,76 +596,120 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
}
}
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
static void init_controller(struct m66592 *m66592)
{
- m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
- m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
- m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+ unsigned int endian;
- /* This is a workaound for SH7722 2nd cut */
- m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
- m66592_bset(m66592, 0x1000, M66592_TESTMODE);
- m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
+ if (m66592->pdata->on_chip) {
+ if (m66592->pdata->endian)
+ endian = 0; /* big endian */
+ else
+ endian = M66592_LITTLE; /* little endian */
- m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_write(m66592, 0, M66592_CFBCFG);
- m66592_write(m66592, 0, M66592_D0FBCFG);
- m66592_bset(m66592, endian, M66592_CFBCFG);
- m66592_bset(m66592, endian, M66592_D0FBCFG);
-}
-#else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
-static void init_controller(struct m66592 *m66592)
-{
- m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
- M66592_PINCFG);
- m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
- m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
+ /* This is a workaound for SH7722 2nd cut */
+ m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
+ m66592_bset(m66592, 0x1000, M66592_TESTMODE);
+ m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
- m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
- m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
- m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+ m66592_write(m66592, 0, M66592_CFBCFG);
+ m66592_write(m66592, 0, M66592_D0FBCFG);
+ m66592_bset(m66592, endian, M66592_CFBCFG);
+ m66592_bset(m66592, endian, M66592_D0FBCFG);
+ } else {
+ unsigned int clock, vif, irq_sense;
- msleep(3);
+ if (m66592->pdata->endian)
+ endian = M66592_BIGEND; /* big endian */
+ else
+ endian = 0; /* little endian */
- m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+ if (m66592->pdata->vif)
+ vif = M66592_LDRV; /* 3.3v */
+ else
+ vif = 0; /* 1.5v */
- msleep(1);
+ switch (m66592->pdata->xtal) {
+ case M66592_PLATDATA_XTAL_12MHZ:
+ clock = M66592_XTAL12;
+ break;
+ case M66592_PLATDATA_XTAL_24MHZ:
+ clock = M66592_XTAL24;
+ break;
+ case M66592_PLATDATA_XTAL_48MHZ:
+ clock = M66592_XTAL48;
+ break;
+ default:
+ pr_warning("m66592-udc: xtal configuration error\n");
+ clock = 0;
+ }
- m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+ switch (m66592->irq_trigger) {
+ case IRQF_TRIGGER_LOW:
+ irq_sense = M66592_INTL;
+ break;
+ case IRQF_TRIGGER_FALLING:
+ irq_sense = 0;
+ break;
+ default:
+ pr_warning("m66592-udc: irq trigger config error\n");
+ irq_sense = 0;
+ }
+
+ m66592_bset(m66592,
+ (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+ M66592_PINCFG);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL,
+ M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+
+ msleep(3);
- m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
- m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
- M66592_DMA0CFG);
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+
+ msleep(1);
+
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+
+ m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
+ m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+ M66592_DMA0CFG);
+ }
}
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
static void disable_controller(struct m66592 *m66592)
{
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
- m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
-#endif
+ if (!m66592->pdata->on_chip) {
+ m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+ }
}
static void m66592_start_xclock(struct m66592 *m66592)
{
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
u16 tmp;
- tmp = m66592_read(m66592, M66592_SYSCFG);
- if (!(tmp & M66592_XCKE))
- m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
-#endif
+ if (!m66592->pdata->on_chip) {
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_XCKE))
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+ }
}
/*-------------------------------------------------------------------------*/
@@ -1177,8 +1197,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- if (!intsts0 && !intenb0) {
+ if (m66592->pdata->on_chip && !intsts0 && !intenb0) {
/*
* When USB clock stops, it cannot read register. Even if a
* clock stops, the interrupt occurs. So this driver turn on
@@ -1188,7 +1207,6 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
}
-#endif
savepipe = m66592_read(m66592, M66592_CFIFOSEL);
@@ -1534,9 +1552,11 @@ static int __exit m66592_remove(struct platform_device *pdev)
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- clk_disable(m66592->clk);
- clk_put(m66592->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ clk_disable(m66592->clk);
+ clk_put(m66592->clk);
+ }
#endif
kfree(m66592);
return 0;
@@ -1548,11 +1568,10 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r)
static int __init m66592_probe(struct platform_device *pdev)
{
- struct resource *res;
- int irq;
+ struct resource *res, *ires;
void __iomem *reg = NULL;
struct m66592 *m66592 = NULL;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
char clk_name[8];
#endif
int ret = 0;
@@ -1565,10 +1584,11 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!ires) {
ret = -ENODEV;
- pr_err("platform_get_irq error.\n");
+ dev_err(&pdev->dev,
+ "platform_get_resource IORESOURCE_IRQ error.\n");
goto clean_up;
}
@@ -1579,6 +1599,12 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ ret = -ENODEV;
+ goto clean_up;
+ }
+
/* initialize ucd */
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
if (m66592 == NULL) {
@@ -1586,6 +1612,9 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
+ m66592->pdata = pdev->dev.platform_data;
+ m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
+
spin_lock_init(&m66592->lock);
dev_set_drvdata(&pdev->dev, m66592);
@@ -1603,24 +1632,25 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->timer.data = (unsigned long)m66592;
m66592->reg = reg;
- m66592->bi_bufnum = M66592_BASE_BUFNUM;
-
- ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(ires->start, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
udc_name, m66592);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
goto clean_up;
}
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
- m66592->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(m66592->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(m66592->clk);
- goto clean_up2;
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
+ m66592->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(m66592->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+ clk_name);
+ ret = PTR_ERR(m66592->clk);
+ goto clean_up2;
+ }
+ clk_enable(m66592->clk);
}
- clk_enable(m66592->clk);
#endif
INIT_LIST_HEAD(&m66592->gadget.ep_list);
m66592->gadget.ep0 = &m66592->ep[0].ep;
@@ -1662,12 +1692,14 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0;
clean_up3:
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- clk_disable(m66592->clk);
- clk_put(m66592->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ clk_disable(m66592->clk);
+ clk_put(m66592->clk);
+ }
clean_up2:
#endif
- free_irq(irq, m66592);
+ free_irq(ires->start, m66592);
clean_up:
if (m66592) {
if (m66592->ep0_req)
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 286ce07e7960..8b960deed680 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -23,10 +23,12 @@
#ifndef __M66592_UDC_H__
#define __M66592_UDC_H__
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
#include <linux/clk.h>
#endif
+#include <linux/usb/m66592.h>
+
#define M66592_SYSCFG 0x00
#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
#define M66592_XTAL48 0x8000 /* 48MHz */
@@ -76,11 +78,11 @@
#define M66592_P_TST_J 0x0001 /* PERI TEST J */
#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+/* built-in registers */
#define M66592_CFBCFG 0x0A
#define M66592_D0FBCFG 0x0C
#define M66592_LITTLE 0x0100 /* b8: Little endian mode */
-#else
+/* external chip case */
#define M66592_PINCFG 0x0A
#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
@@ -100,8 +102,8 @@
#define M66592_PKTM 0x0020 /* b5: Packet mode */
#define M66592_DENDE 0x0010 /* b4: Dend enable */
#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+/* common case */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
#define M66592_D1FIFO 0x18
@@ -113,13 +115,9 @@
#define M66592_REW 0x4000 /* b14: Buffer rewind */
#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-#define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */
-#else
-#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
-#define M66592_MBW_8 0x0000 /* 8bit */
-#define M66592_MBW_16 0x0400 /* 16bit */
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#define M66592_MBW_32 0x0800 /* 32bit */
#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
@@ -480,9 +478,11 @@ struct m66592_ep {
struct m66592 {
spinlock_t lock;
void __iomem *reg;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
+ struct m66592_platdata *pdata;
+ unsigned long irq_trigger;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
@@ -506,7 +506,6 @@ struct m66592 {
int interrupt;
int isochronous;
int num_dma;
- int bi_bufnum; /* bulk and isochronous's bufnum */
};
#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
@@ -547,13 +546,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592,
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- len = (len + 3) / 4;
- insl(fifoaddr, buf, len);
-#else
- len = (len + 1) / 2;
- insw(fifoaddr, buf, len);
-#endif
+ if (m66592->pdata->on_chip) {
+ len = (len + 3) / 4;
+ insl(fifoaddr, buf, len);
+ } else {
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
+ }
}
static inline void m66592_write(struct m66592 *m66592, u16 val,
@@ -567,33 +566,34 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- unsigned long count;
- unsigned char *pb;
- int i;
-
- count = len / 4;
- outsl(fifoaddr, buf, count);
-
- if (len & 0x00000003) {
- pb = buf + count * 4;
- for (i = 0; i < (len & 0x00000003); i++) {
- if (m66592_read(m66592, M66592_CFBCFG)) /* little */
- outb(pb[i], fifoaddr + (3 - i));
- else
- outb(pb[i], fifoaddr + i);
+
+ if (m66592->pdata->on_chip) {
+ unsigned long count;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (m66592_read(m66592, M66592_CFBCFG)) /* le */
+ outb(pb[i], fifoaddr + (3 - i));
+ else
+ outb(pb[i], fifoaddr + i);
+ }
+ }
+ } else {
+ unsigned long odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (odd) {
+ unsigned char *p = buf + len*2;
+ outb(*p, fifoaddr);
}
}
-#else
- unsigned long odd = len & 0x0001;
-
- len = len / 2;
- outsw(fifoaddr, buf, len);
- if (odd) {
- unsigned char *p = buf + len*2;
- outb(*p, fifoaddr);
- }
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 016f63b39028..aac69b591aeb 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
if (!in) {
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* apply outgoing CDC or RNDIS filters */
@@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
if (!(cdc_filter & type)) {
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
@@ -586,7 +586,7 @@ drop:
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a920c70b5a1..f21ca7d27a43 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -336,13 +336,6 @@ config USB_R8A66597_HCD
To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd.
-config SUPERH_ON_CHIP_R8A66597
- boolean "Enable SuperH on-chip R8A66597 USB"
- depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)
- help
- This driver enables support for the on-chip R8A66597 in the
- SH7366, SH7723 and SH7724 processors.
-
config USB_WHCI_HCD
tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
depends on EXPERIMENTAL
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7d03549c3339..11c627ce6022 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* already started */
break;
case QH_STATE_IDLE:
- WARN_ON(1);
+ /* QH might be waiting for a Clear-TT-Buffer */
+ qh_completions(ehci, qh);
break;
}
break;
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index dc2ac613a9d1..1d283e1b2b8d 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -105,6 +105,7 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
+ ehci_reset(ehci);
retval = ehci_halt(ehci);
if (retval)
return retval;
@@ -118,7 +119,6 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
hcd->has_tt = 1;
- ehci_reset(ehci);
ehci_port_power(ehci, 0);
return retval;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index c2f1b7df918c..b5b83c43898a 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -242,7 +242,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
* System suspend currently expects to be able to suspend the entire
* device tree, device-at-a-time. If we failed selective suspend
* reports, system suspend would fail; so the root hub code must claim
- * success. That's lying to usbcore, and it matters for for runtime
+ * success. That's lying to usbcore, and it matters for runtime
* PM scenarios with selective suspend and remote wakeup...
*/
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 9a1384747f3b..7673554fa64d 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -375,12 +375,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
*/
if ((token & QTD_STS_XACT) &&
QTD_CERR(token) == 0 &&
- --qh->xacterrs > 0 &&
+ ++qh->xacterrs < QH_XACTERR_MAX &&
!urb->unlinked) {
ehci_dbg(ehci,
"detected XactErr len %zu/%zu retry %d\n",
- qtd->length - QTD_LENGTH(token), qtd->length,
- QH_XACTERR_MAX - qh->xacterrs);
+ qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
/* reset the token in the qtd and the
* qh overlay (which still contains
@@ -494,7 +493,7 @@ halt:
last = qtd;
/* reinit the xacterr counter for the next qtd */
- qh->xacterrs = QH_XACTERR_MAX;
+ qh->xacterrs = 0;
}
/* last urb's completion might still need calling */
@@ -940,7 +939,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh;
head->hw_next = dma;
- qh->xacterrs = QH_XACTERR_MAX;
+ qh_get(qh);
+ qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */
}
@@ -1080,7 +1080,7 @@ submit_async (
* the HC and TT handle it when the TT has a buffer ready.
*/
if (likely (qh->qh_state == QH_STATE_IDLE))
- qh_link_async (ehci, qh_get (qh));
+ qh_link_async(ehci, qh);
done:
spin_unlock_irqrestore (&ehci->lock, flags);
if (unlikely (qh == NULL))
@@ -1115,8 +1115,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
qh_link_async (ehci, qh);
else {
- qh_put (qh); // refcount from async list
-
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
*/
@@ -1124,6 +1122,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& ehci->async->qh_next.qh == NULL)
timer_action (ehci, TIMER_ASYNC_OFF);
}
+ qh_put(qh); /* refcount from async list */
if (next) {
ehci->reclaim = NULL;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 74f7f83b29ad..edd61ee90323 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -542,6 +542,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
qh->qh_state = QH_STATE_LINKED;
+ qh->xacterrs = 0;
qh_get (qh);
/* update per-qh bandwidth for usbfs */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2bfff30f4704..48b9e889a18b 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -37,7 +37,7 @@ typedef __u16 __bitwise __hc16;
#define __hc16 __le16
#endif
-/* statistics can be kept for for tuning/monitoring */
+/* statistics can be kept for tuning/monitoring */
struct ehci_stats {
/* irq usage */
unsigned long normal;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index f3aaba35e912..83cbecd2a1ed 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -282,6 +282,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
static void ohci_omap_stop(struct usb_hcd *hcd)
{
dev_dbg(hcd->self.controller, "stopping USB Controller\n");
+ ohci_stop(hcd);
omap_ohci_clock_power(0);
}
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e44dc2cbca24..61800742fc07 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -477,25 +477,25 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM
+static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
if (time_before(jiffies, ohci->ohci.next_statechange))
msleep(5);
ohci->ohci.next_statechange = jiffies;
- pxa27x_stop_hc(ohci, &pdev->dev);
+ pxa27x_stop_hc(ohci, dev);
hcd->state = HC_STATE_SUSPENDED;
return 0;
}
-static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_pxa27x_drv_resume(struct device *dev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
int status;
@@ -503,12 +503,17 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
msleep(5);
ohci->ohci.next_statechange = jiffies;
- if ((status = pxa27x_start_hc(ohci, &pdev->dev)) < 0)
+ if ((status = pxa27x_start_hc(ohci, dev)) < 0)
return status;
ohci_finish_controller_resume(hcd);
return 0;
}
+
+static struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {
+ .suspend = ohci_hcd_pxa27x_drv_suspend,
+ .resume = ohci_hcd_pxa27x_drv_resume,
+};
#endif
/* work with hotplug and coldplug */
@@ -518,13 +523,12 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
-#ifdef CONFIG_PM
- .suspend = ohci_hcd_pxa27x_drv_suspend,
- .resume = ohci_hcd_pxa27x_drv_resume,
-#endif
.driver = {
.name = "pxa27x-ohci",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ohci_hcd_pxa27x_pm_ops,
+#endif
},
};
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index c2d80f80448b..16fecb8ecc39 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -418,7 +418,7 @@ static struct ed *ed_get (
is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN);
/* FIXME usbcore changes dev->devnum before SET_ADDRESS
- * suceeds ... otherwise we wouldn't need "pipe".
+ * succeeds ... otherwise we wouldn't need "pipe".
*/
info = usb_pipedevice (pipe);
ed->type = usb_pipetype(pipe);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index e18f74946e68..749b53742828 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -91,43 +91,43 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
u16 tmp;
int i = 0;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
- clk_enable(r8a66597->clk);
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ clk_enable(r8a66597->clk);
#endif
- do {
- r8a66597_write(r8a66597, SCKE, SYSCFG0);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 1000) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & SCKE) != SCKE);
- r8a66597_write(r8a66597, 0x04, 0x02);
-#else
- do {
- r8a66597_write(r8a66597, USBE, SYSCFG0);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 1000) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & USBE) != USBE);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
- r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
- SYSCFG0);
+ do {
+ r8a66597_write(r8a66597, SCKE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+ } else {
+ do {
+ r8a66597_write(r8a66597, USBE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & USBE) != USBE);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata),
+ XTAL, SYSCFG0);
- i = 0;
- r8a66597_bset(r8a66597, XCKE, SYSCFG0);
- do {
- msleep(1);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 500) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & SCKE) != SCKE);
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+ i = 0;
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ do {
+ msleep(1);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 500) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ }
return 0;
}
@@ -136,15 +136,16 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
{
r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
udelay(1);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
- clk_disable(r8a66597->clk);
-#endif
-#else
- r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
- r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ clk_disable(r8a66597->clk);
#endif
+ } else {
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ }
}
static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
@@ -205,7 +206,7 @@ static int enable_controller(struct r8a66597 *r8a66597)
r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_enable_port(r8a66597, port);
return 0;
@@ -218,7 +219,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
r8a66597_write(r8a66597, 0, INTENB0);
r8a66597_write(r8a66597, 0, INTSTS0);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_disable_port(r8a66597, port);
r8a66597_clock_disable(r8a66597);
@@ -249,11 +250,12 @@ static int is_hub_limit(char *devpath)
return ((strlen(devpath) >= 4) ? 1 : 0);
}
-static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
+static void get_port_number(struct r8a66597 *r8a66597,
+ char *devpath, u16 *root_port, u16 *hub_port)
{
if (root_port) {
*root_port = (devpath[0] & 0x0F) - 1;
- if (*root_port >= R8A66597_MAX_ROOT_HUB)
+ if (*root_port >= r8a66597->max_root_hub)
printk(KERN_ERR "r8a66597: Illegal root port number.\n");
}
if (hub_port)
@@ -355,7 +357,8 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
INIT_LIST_HEAD(&dev->device_list);
list_add_tail(&dev->device_list, &r8a66597->child_device);
- get_port_number(urb->dev->devpath, &dev->root_port, &dev->hub_port);
+ get_port_number(r8a66597, urb->dev->devpath,
+ &dev->root_port, &dev->hub_port);
if (!is_child_device(urb->dev->devpath))
r8a66597->root_hub[dev->root_port].dev = dev;
@@ -420,7 +423,7 @@ static void free_usb_address(struct r8a66597 *r8a66597,
list_del(&dev->device_list);
kfree(dev);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
if (r8a66597->root_hub[port].dev == dev) {
r8a66597->root_hub[port].dev = NULL;
break;
@@ -495,10 +498,20 @@ static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
}
+static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
+{
+ if (r8a66597->pdata->on_chip)
+ return MBW_32;
+ else
+ return MBW_16;
+}
+
/* this function must be called with interrupt disabled */
static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
{
- r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+ unsigned short mbw = mbw_value(r8a66597);
+
+ r8a66597_mdfy(r8a66597, mbw | pipenum, mbw | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
}
@@ -506,11 +519,13 @@ static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe)
{
+ unsigned short mbw = mbw_value(r8a66597);
+
cfifo_change(r8a66597, 0);
- r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D0FIFOSEL);
- r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D1FIFOSEL);
+ r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D0FIFOSEL);
+ r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D1FIFOSEL);
- r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE,
+ r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, mbw | CURPIPE,
pipe->fifosel);
r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
}
@@ -742,9 +757,13 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe,
struct urb *urb)
{
-#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
int i;
struct r8a66597_pipe_info *info = &pipe->info;
+ unsigned short mbw = mbw_value(r8a66597);
+
+ /* pipe dma is only for external controlles */
+ if (r8a66597->pdata->on_chip)
+ return;
if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
@@ -763,8 +782,8 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
set_pipe_reg_addr(pipe, i);
cfifo_change(r8a66597, 0);
- r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,
- MBW | CURPIPE, pipe->fifosel);
+ r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum,
+ mbw | CURPIPE, pipe->fifosel);
r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
pipe->info.pipenum);
@@ -772,7 +791,6 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
break;
}
}
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
}
/* this function must be called with interrupt disabled */
@@ -1769,7 +1787,7 @@ static void r8a66597_timer(unsigned long _r8a66597)
spin_lock_irqsave(&r8a66597->lock, flags);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_root_hub_control(r8a66597, port);
spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -1807,7 +1825,7 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
u16 root_port, hub_port;
if (usb_address == 0) {
- get_port_number(urb->dev->devpath,
+ get_port_number(r8a66597, urb->dev->devpath,
&root_port, &hub_port);
set_devadd_reg(r8a66597, 0,
get_r8a66597_usb_speed(urb->dev->speed),
@@ -2082,7 +2100,7 @@ static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
*buf = 0; /* initialize (no change) */
- for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) {
+ for (i = 0; i < r8a66597->max_root_hub; i++) {
if (r8a66597->root_hub[i].port & 0xffff0000)
*buf |= 1 << (i + 1);
}
@@ -2097,11 +2115,11 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
{
desc->bDescriptorType = 0x29;
desc->bHubContrCurrent = 0;
- desc->bNbrPorts = R8A66597_MAX_ROOT_HUB;
+ desc->bNbrPorts = r8a66597->max_root_hub;
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
desc->wHubCharacteristics = cpu_to_le16(0x0011);
- desc->bitmap[0] = ((1 << R8A66597_MAX_ROOT_HUB) - 1) << 1;
+ desc->bitmap[0] = ((1 << r8a66597->max_root_hub) - 1) << 1;
desc->bitmap[1] = ~0;
}
@@ -2129,7 +2147,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
break;
case ClearPortFeature:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
if (wLength != 0)
goto error;
@@ -2162,12 +2180,12 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*buf = 0x00;
break;
case GetPortStatus:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
*(__le32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
if (wLength != 0)
goto error;
@@ -2216,7 +2234,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
dbg("%s", __func__);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);
@@ -2247,7 +2265,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
dbg("%s", __func__);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);
@@ -2305,16 +2323,16 @@ static struct hc_driver r8a66597_hc_driver = {
};
#if defined(CONFIG_PM)
-static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
+static int r8a66597_suspend(struct device *dev)
{
- struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
int port;
dbg("%s", __func__);
disable_controller(r8a66597);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
rh->port = 0x00000000;
@@ -2323,9 +2341,9 @@ static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int r8a66597_resume(struct platform_device *pdev)
+static int r8a66597_resume(struct device *dev)
{
- struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
dbg("%s", __func__);
@@ -2335,9 +2353,17 @@ static int r8a66597_resume(struct platform_device *pdev)
return 0;
}
+
+static struct dev_pm_ops r8a66597_dev_pm_ops = {
+ .suspend = r8a66597_suspend,
+ .resume = r8a66597_resume,
+ .poweroff = r8a66597_suspend,
+ .restore = r8a66597_resume,
+};
+
+#define R8A66597_DEV_PM_OPS (&r8a66597_dev_pm_ops)
#else /* if defined(CONFIG_PM) */
-#define r8a66597_suspend NULL
-#define r8a66597_resume NULL
+#define R8A66597_DEV_PM_OPS NULL
#endif
static int __init_or_module r8a66597_remove(struct platform_device *pdev)
@@ -2348,8 +2374,9 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
del_timer_sync(&r8a66597->rh_timer);
usb_remove_hcd(hcd);
iounmap((void *)r8a66597->reg);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip)
+ clk_put(r8a66597->clk);
#endif
usb_put_hcd(hcd);
return 0;
@@ -2357,7 +2384,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
static int __devinit r8a66597_probe(struct platform_device *pdev)
{
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
char clk_name[8];
#endif
struct resource *res = NULL, *ires;
@@ -2419,15 +2446,20 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
r8a66597->pdata = pdev->dev.platform_data;
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
- r8a66597->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(r8a66597->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(r8a66597->clk);
- goto clean_up2;
- }
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
+ r8a66597->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(r8a66597->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+ clk_name);
+ ret = PTR_ERR(r8a66597->clk);
+ goto clean_up2;
+ }
#endif
+ r8a66597->max_root_hub = 1;
+ } else
+ r8a66597->max_root_hub = 2;
spin_lock_init(&r8a66597->lock);
init_timer(&r8a66597->rh_timer);
@@ -2457,8 +2489,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
return 0;
clean_up3:
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip)
+ clk_put(r8a66597->clk);
clean_up2:
#endif
usb_put_hcd(hcd);
@@ -2473,11 +2506,10 @@ clean_up:
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
.remove = r8a66597_remove,
- .suspend = r8a66597_suspend,
- .resume = r8a66597_resume,
.driver = {
.name = (char *) hcd_name,
.owner = THIS_MODULE,
+ .pm = R8A66597_DEV_PM_OPS,
},
};
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index d72680b433f9..228e3fb23854 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -26,390 +26,16 @@
#ifndef __R8A66597_H__
#define __R8A66597_H__
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
#include <linux/clk.h>
#endif
#include <linux/usb/r8a66597.h>
-#define SYSCFG0 0x00
-#define SYSCFG1 0x02
-#define SYSSTS0 0x04
-#define SYSSTS1 0x06
-#define DVSTCTR0 0x08
-#define DVSTCTR1 0x0A
-#define TESTMODE 0x0C
-#define PINCFG 0x0E
-#define DMA0CFG 0x10
-#define DMA1CFG 0x12
-#define CFIFO 0x14
-#define D0FIFO 0x18
-#define D1FIFO 0x1C
-#define CFIFOSEL 0x20
-#define CFIFOCTR 0x22
-#define CFIFOSIE 0x24
-#define D0FIFOSEL 0x28
-#define D0FIFOCTR 0x2A
-#define D1FIFOSEL 0x2C
-#define D1FIFOCTR 0x2E
-#define INTENB0 0x30
-#define INTENB1 0x32
-#define INTENB2 0x34
-#define BRDYENB 0x36
-#define NRDYENB 0x38
-#define BEMPENB 0x3A
-#define SOFCFG 0x3C
-#define INTSTS0 0x40
-#define INTSTS1 0x42
-#define INTSTS2 0x44
-#define BRDYSTS 0x46
-#define NRDYSTS 0x48
-#define BEMPSTS 0x4A
-#define FRMNUM 0x4C
-#define UFRMNUM 0x4E
-#define USBADDR 0x50
-#define USBREQ 0x54
-#define USBVAL 0x56
-#define USBINDX 0x58
-#define USBLENG 0x5A
-#define DCPCFG 0x5C
-#define DCPMAXP 0x5E
-#define DCPCTR 0x60
-#define PIPESEL 0x64
-#define PIPECFG 0x68
-#define PIPEBUF 0x6A
-#define PIPEMAXP 0x6C
-#define PIPEPERI 0x6E
-#define PIPE1CTR 0x70
-#define PIPE2CTR 0x72
-#define PIPE3CTR 0x74
-#define PIPE4CTR 0x76
-#define PIPE5CTR 0x78
-#define PIPE6CTR 0x7A
-#define PIPE7CTR 0x7C
-#define PIPE8CTR 0x7E
-#define PIPE9CTR 0x80
-#define PIPE1TRE 0x90
-#define PIPE1TRN 0x92
-#define PIPE2TRE 0x94
-#define PIPE2TRN 0x96
-#define PIPE3TRE 0x98
-#define PIPE3TRN 0x9A
-#define PIPE4TRE 0x9C
-#define PIPE4TRN 0x9E
-#define PIPE5TRE 0xA0
-#define PIPE5TRN 0xA2
-#define DEVADD0 0xD0
-#define DEVADD1 0xD2
-#define DEVADD2 0xD4
-#define DEVADD3 0xD6
-#define DEVADD4 0xD8
-#define DEVADD5 0xDA
-#define DEVADD6 0xDC
-#define DEVADD7 0xDE
-#define DEVADD8 0xE0
-#define DEVADD9 0xE2
-#define DEVADDA 0xE4
-
-/* System Configuration Control Register */
-#define XTAL 0xC000 /* b15-14: Crystal selection */
-#define XTAL48 0x8000 /* 48MHz */
-#define XTAL24 0x4000 /* 24MHz */
-#define XTAL12 0x0000 /* 12MHz */
-#define XCKE 0x2000 /* b13: External clock enable */
-#define PLLC 0x0800 /* b11: PLL control */
-#define SCKE 0x0400 /* b10: USB clock enable */
-#define PCSDIS 0x0200 /* b9: not CS wakeup */
-#define LPSME 0x0100 /* b8: Low power sleep mode */
-#define HSE 0x0080 /* b7: Hi-speed enable */
-#define DCFM 0x0040 /* b6: Controller function select */
-#define DRPD 0x0020 /* b5: D+/- pull down control */
-#define DPRPU 0x0010 /* b4: D+ pull up control */
-#define USBE 0x0001 /* b0: USB module operation enable */
-
-/* System Configuration Status Register */
-#define OVCBIT 0x8000 /* b15-14: Over-current bit */
-#define OVCMON 0xC000 /* b15-14: Over-current monitor */
-#define SOFEA 0x0020 /* b5: SOF monitor */
-#define IDMON 0x0004 /* b3: ID-pin monitor */
-#define LNST 0x0003 /* b1-0: D+, D- line status */
-#define SE1 0x0003 /* SE1 */
-#define FS_KSTS 0x0002 /* Full-Speed K State */
-#define FS_JSTS 0x0001 /* Full-Speed J State */
-#define LS_JSTS 0x0002 /* Low-Speed J State */
-#define LS_KSTS 0x0001 /* Low-Speed K State */
-#define SE0 0x0000 /* SE0 */
-
-/* Device State Control Register */
-#define EXTLP0 0x0400 /* b10: External port */
-#define VBOUT 0x0200 /* b9: VBUS output */
-#define WKUP 0x0100 /* b8: Remote wakeup */
-#define RWUPE 0x0080 /* b7: Remote wakeup sense */
-#define USBRST 0x0040 /* b6: USB reset enable */
-#define RESUME 0x0020 /* b5: Resume enable */
-#define UACT 0x0010 /* b4: USB bus enable */
-#define RHST 0x0007 /* b1-0: Reset handshake status */
-#define HSPROC 0x0004 /* HS handshake is processing */
-#define HSMODE 0x0003 /* Hi-Speed mode */
-#define FSMODE 0x0002 /* Full-Speed mode */
-#define LSMODE 0x0001 /* Low-Speed mode */
-#define UNDECID 0x0000 /* Undecided */
-
-/* Test Mode Register */
-#define UTST 0x000F /* b3-0: Test select */
-#define H_TST_PACKET 0x000C /* HOST TEST Packet */
-#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
-#define H_TST_K 0x000A /* HOST TEST K */
-#define H_TST_J 0x0009 /* HOST TEST J */
-#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
-#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
-#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
-#define P_TST_K 0x0002 /* PERI TEST K */
-#define P_TST_J 0x0001 /* PERI TEST J */
-#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
-
-/* Data Pin Configuration Register */
-#define LDRV 0x8000 /* b15: Drive Current Adjust */
-#define VIF1 0x0000 /* VIF = 1.8V */
-#define VIF3 0x8000 /* VIF = 3.3V */
-#define INTA 0x0001 /* b1: USB INT-pin active */
-
-/* DMAx Pin Configuration Register */
-#define DREQA 0x4000 /* b14: Dreq active select */
-#define BURST 0x2000 /* b13: Burst mode */
-#define DACKA 0x0400 /* b10: Dack active select */
-#define DFORM 0x0380 /* b9-7: DMA mode select */
-#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
-#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
-#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
-#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
-#define DENDA 0x0040 /* b6: Dend active select */
-#define PKTM 0x0020 /* b5: Packet mode */
-#define DENDE 0x0010 /* b4: Dend enable */
-#define OBUS 0x0004 /* b2: OUTbus mode */
-
-/* CFIFO/DxFIFO Port Select Register */
-#define RCNT 0x8000 /* b15: Read count mode */
-#define REW 0x4000 /* b14: Buffer rewind */
-#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
-#define DREQE 0x1000 /* b12: DREQ output enable */
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define MBW 0x0800
-#else
-#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
-#endif
-#define MBW_8 0x0000 /* 8bit */
-#define MBW_16 0x0400 /* 16bit */
-#define BIGEND 0x0100 /* b8: Big endian mode */
-#define BYTE_LITTLE 0x0000 /* little dendian */
-#define BYTE_BIG 0x0100 /* big endifan */
-#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
-#define CURPIPE 0x000F /* b2-0: PIPE select */
-
-/* CFIFO/DxFIFO Port Control Register */
-#define BVAL 0x8000 /* b15: Buffer valid flag */
-#define BCLR 0x4000 /* b14: Buffer clear */
-#define FRDY 0x2000 /* b13: FIFO ready */
-#define DTLN 0x0FFF /* b11-0: FIFO received data length */
-
-/* Interrupt Enable Register 0 */
-#define VBSE 0x8000 /* b15: VBUS interrupt */
-#define RSME 0x4000 /* b14: Resume interrupt */
-#define SOFE 0x2000 /* b13: Frame update interrupt */
-#define DVSE 0x1000 /* b12: Device state transition interrupt */
-#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
-
-/* Interrupt Enable Register 1 */
-#define OVRCRE 0x8000 /* b15: Over-current interrupt */
-#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
-#define DTCHE 0x1000 /* b12: Detach sense interrupt */
-#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
-#define EOFERRE 0x0040 /* b6: EOF error interrupt */
-#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
-#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
-
-/* BRDY Interrupt Enable/Status Register */
-#define BRDY9 0x0200 /* b9: PIPE9 */
-#define BRDY8 0x0100 /* b8: PIPE8 */
-#define BRDY7 0x0080 /* b7: PIPE7 */
-#define BRDY6 0x0040 /* b6: PIPE6 */
-#define BRDY5 0x0020 /* b5: PIPE5 */
-#define BRDY4 0x0010 /* b4: PIPE4 */
-#define BRDY3 0x0008 /* b3: PIPE3 */
-#define BRDY2 0x0004 /* b2: PIPE2 */
-#define BRDY1 0x0002 /* b1: PIPE1 */
-#define BRDY0 0x0001 /* b1: PIPE0 */
-
-/* NRDY Interrupt Enable/Status Register */
-#define NRDY9 0x0200 /* b9: PIPE9 */
-#define NRDY8 0x0100 /* b8: PIPE8 */
-#define NRDY7 0x0080 /* b7: PIPE7 */
-#define NRDY6 0x0040 /* b6: PIPE6 */
-#define NRDY5 0x0020 /* b5: PIPE5 */
-#define NRDY4 0x0010 /* b4: PIPE4 */
-#define NRDY3 0x0008 /* b3: PIPE3 */
-#define NRDY2 0x0004 /* b2: PIPE2 */
-#define NRDY1 0x0002 /* b1: PIPE1 */
-#define NRDY0 0x0001 /* b1: PIPE0 */
-
-/* BEMP Interrupt Enable/Status Register */
-#define BEMP9 0x0200 /* b9: PIPE9 */
-#define BEMP8 0x0100 /* b8: PIPE8 */
-#define BEMP7 0x0080 /* b7: PIPE7 */
-#define BEMP6 0x0040 /* b6: PIPE6 */
-#define BEMP5 0x0020 /* b5: PIPE5 */
-#define BEMP4 0x0010 /* b4: PIPE4 */
-#define BEMP3 0x0008 /* b3: PIPE3 */
-#define BEMP2 0x0004 /* b2: PIPE2 */
-#define BEMP1 0x0002 /* b1: PIPE1 */
-#define BEMP0 0x0001 /* b0: PIPE0 */
-
-/* SOF Pin Configuration Register */
-#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
-#define BRDYM 0x0040 /* b6: BRDY clear timing */
-#define INTL 0x0020 /* b5: Interrupt sense select */
-#define EDGESTS 0x0010 /* b4: */
-#define SOFMODE 0x000C /* b3-2: SOF pin select */
-#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
-#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
-#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
-
-/* Interrupt Status Register 0 */
-#define VBINT 0x8000 /* b15: VBUS interrupt */
-#define RESM 0x4000 /* b14: Resume interrupt */
-#define SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define DVST 0x1000 /* b12: Device state transition interrupt */
-#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define VBSTS 0x0080 /* b7: VBUS input port */
-#define DVSQ 0x0070 /* b6-4: Device state */
-#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
-#define DS_SPD_ADDR 0x0060 /* Suspend Address */
-#define DS_SPD_DFLT 0x0050 /* Suspend Default */
-#define DS_SPD_POWR 0x0040 /* Suspend Powered */
-#define DS_SUSP 0x0040 /* Suspend */
-#define DS_CNFG 0x0030 /* Configured */
-#define DS_ADDS 0x0020 /* Address */
-#define DS_DFLT 0x0010 /* Default */
-#define DS_POWR 0x0000 /* Powered */
-#define DVSQS 0x0030 /* b5-4: Device state */
-#define VALID 0x0008 /* b3: Setup packet detected flag */
-#define CTSQ 0x0007 /* b2-0: Control transfer stage */
-#define CS_SQER 0x0006 /* Sequence error */
-#define CS_WRND 0x0005 /* Control write nodata status stage */
-#define CS_WRSS 0x0004 /* Control write status stage */
-#define CS_WRDS 0x0003 /* Control write data stage */
-#define CS_RDSS 0x0002 /* Control read status stage */
-#define CS_RDDS 0x0001 /* Control read data stage */
-#define CS_IDST 0x0000 /* Idle or setup stage */
-
-/* Interrupt Status Register 1 */
-#define OVRCR 0x8000 /* b15: Over-current interrupt */
-#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
-#define DTCH 0x1000 /* b12: Detach sense interrupt */
-#define ATTCH 0x0800 /* b11: Attach sense interrupt */
-#define EOFERR 0x0040 /* b6: EOF-error interrupt */
-#define SIGN 0x0020 /* b5: Setup ignore interrupt */
-#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
-
-/* Frame Number Register */
-#define OVRN 0x8000 /* b15: Overrun error */
-#define CRCE 0x4000 /* b14: Received data error */
-#define FRNM 0x07FF /* b10-0: Frame number */
-
-/* Micro Frame Number Register */
-#define UFRNM 0x0007 /* b2-0: Micro frame number */
-
-/* Default Control Pipe Maxpacket Size Register */
-/* Pipe Maxpacket Size Register */
-#define DEVSEL 0xF000 /* b15-14: Device address select */
-#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
-
-/* Default Control Pipe Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define SUREQ 0x4000 /* b14: Send USB request */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define SUREQCLR 0x0800 /* b11: stop setup request */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PINGE 0x0010 /* b4: ping enable */
-#define CCPL 0x0004 /* b2: Enable control transfer complete */
-#define PID 0x0003 /* b1-0: Response PID */
-#define PID_STALL11 0x0003 /* STALL */
-#define PID_STALL 0x0002 /* STALL */
-#define PID_BUF 0x0001 /* BUF */
-#define PID_NAK 0x0000 /* NAK */
-
-/* Pipe Window Select Register */
-#define PIPENM 0x0007 /* b2-0: Pipe select */
-
-/* Pipe Configuration Register */
-#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
-#define R8A66597_ISO 0xC000 /* Isochronous */
-#define R8A66597_INT 0x8000 /* Interrupt */
-#define R8A66597_BULK 0x4000 /* Bulk */
-#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
-#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
-#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
-#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
-#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
-
-/* Pipe Buffer Configuration Register */
-#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
-#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
-#define PIPE0BUF 256
-#define PIPExBUF 64
-
-/* Pipe Maxpacket Size Register */
-#define MXPS 0x07FF /* b10-0: Maxpacket size */
-
-/* Pipe Cycle Configuration Register */
-#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define IITV 0x0007 /* b2-0: Isochronous interval */
-
-/* Pipex Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define ATREPM 0x0400 /* b10: Auto repeat mode */
-#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PID 0x0003 /* b1-0: Response PID */
-
-/* PIPExTRE */
-#define TRENB 0x0200 /* b9: Transaction counter enable */
-#define TRCLR 0x0100 /* b8: Transaction counter clear */
-
-/* PIPExTRN */
-#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
-
-/* DEVADDx */
-#define UPPHUB 0x7800
-#define HUBPORT 0x0700
-#define USBSPD 0x00C0
-#define RTPORT 0x0001
-
#define R8A66597_MAX_NUM_PIPE 10
#define R8A66597_BUF_BSIZE 8
#define R8A66597_MAX_DEVICE 10
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define R8A66597_MAX_ROOT_HUB 1
-#else
#define R8A66597_MAX_ROOT_HUB 2
-#endif
#define R8A66597_MAX_SAMPLING 5
#define R8A66597_RH_POLL_TIME 10
#define R8A66597_MAX_DMA_CHANNEL 2
@@ -487,7 +113,7 @@ struct r8a66597_root_hub {
struct r8a66597 {
spinlock_t lock;
unsigned long reg;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
struct r8a66597_platdata *pdata;
@@ -504,6 +130,7 @@ struct r8a66597 {
unsigned short interval_map;
unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
unsigned char dma_map;
+ unsigned int max_root_hub;
struct list_head child_device;
unsigned long child_connect_map[4];
@@ -550,21 +177,22 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long fifoaddr = r8a66597->reg + offset;
unsigned long count;
- count = len / 4;
- insl(fifoaddr, buf, count);
+ if (r8a66597->pdata->on_chip) {
+ count = len / 4;
+ insl(fifoaddr, buf, count);
- if (len & 0x00000003) {
- unsigned long tmp = inl(fifoaddr);
- memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+ if (len & 0x00000003) {
+ unsigned long tmp = inl(fifoaddr);
+ memcpy((unsigned char *)buf + count * 4, &tmp,
+ len & 0x03);
+ }
+ } else {
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
}
-#else
- len = (len + 1) / 2;
- insw(r8a66597->reg + offset, buf, len);
-#endif
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
@@ -578,33 +206,33 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
int len)
{
unsigned long fifoaddr = r8a66597->reg + offset;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long count;
unsigned char *pb;
int i;
- count = len / 4;
- outsl(fifoaddr, buf, count);
+ if (r8a66597->pdata->on_chip) {
+ 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);
+ }
+ }
+ } else {
+ int odd = len & 0x0001;
- 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);
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (unlikely(odd)) {
+ buf = &buf[len];
+ outb((unsigned char)*buf, fifoaddr);
}
}
-#else
- int odd = len & 0x0001;
-
- len = len / 2;
- outsw(fifoaddr, buf, len);
- if (unlikely(odd)) {
- buf = &buf[len];
- outb((unsigned char)*buf, fifoaddr);
- }
-#endif
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 2501c571f855..705e34324156 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -173,6 +173,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int
{
void *addr;
u32 temp;
+ u64 temp_64;
addr = &ir_set->irq_pending;
temp = xhci_readl(xhci, addr);
@@ -200,25 +201,15 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int
xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n",
addr, (unsigned int)temp);
- addr = &ir_set->erst_base[0];
- temp = xhci_readl(xhci, addr);
- xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n",
- addr, (unsigned int) temp);
-
- addr = &ir_set->erst_base[1];
- temp = xhci_readl(xhci, addr);
- xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n",
- addr, (unsigned int) temp);
+ addr = &ir_set->erst_base;
+ temp_64 = xhci_read_64(xhci, addr);
+ xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n",
+ addr, temp_64);
- addr = &ir_set->erst_dequeue[0];
- temp = xhci_readl(xhci, addr);
- xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n",
- addr, (unsigned int) temp);
-
- addr = &ir_set->erst_dequeue[1];
- temp = xhci_readl(xhci, addr);
- xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n",
- addr, (unsigned int) temp);
+ addr = &ir_set->erst_dequeue;
+ temp_64 = xhci_read_64(xhci, addr);
+ xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n",
+ addr, temp_64);
}
void xhci_print_run_regs(struct xhci_hcd *xhci)
@@ -268,8 +259,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
xhci_dbg(xhci, "Link TRB:\n");
xhci_print_trb_offsets(xhci, trb);
- address = trb->link.segment_ptr[0] +
- (((u64) trb->link.segment_ptr[1]) << 32);
+ address = trb->link.segment_ptr;
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
@@ -282,8 +272,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
(unsigned int) (trb->link.control & TRB_NO_SNOOP));
break;
case TRB_TYPE(TRB_TRANSFER):
- address = trb->trans_event.buffer[0] +
- (((u64) trb->trans_event.buffer[1]) << 32);
+ address = trb->trans_event.buffer;
/*
* FIXME: look at flags to figure out if it's an address or if
* the data is directly in the buffer field.
@@ -291,8 +280,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
break;
case TRB_TYPE(TRB_COMPLETION):
- address = trb->event_cmd.cmd_trb[0] +
- (((u64) trb->event_cmd.cmd_trb[1]) << 32);
+ address = trb->event_cmd.cmd_trb;
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
xhci_dbg(xhci, "Completion status = %u\n",
(unsigned int) GET_COMP_CODE(trb->event_cmd.status));
@@ -328,8 +316,8 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
trb = &seg->trbs[i];
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
- (unsigned int) trb->link.segment_ptr[0],
- (unsigned int) trb->link.segment_ptr[1],
+ lower_32_bits(trb->link.segment_ptr),
+ upper_32_bits(trb->link.segment_ptr),
(unsigned int) trb->link.intr_target,
(unsigned int) trb->link.control);
addr += sizeof(*trb);
@@ -386,8 +374,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
entry = &erst->entries[i];
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
(unsigned int) addr,
- (unsigned int) entry->seg_addr[0],
- (unsigned int) entry->seg_addr[1],
+ lower_32_bits(entry->seg_addr),
+ upper_32_bits(entry->seg_addr),
(unsigned int) entry->seg_size,
(unsigned int) entry->rsvd);
addr += sizeof(*entry);
@@ -396,90 +384,147 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
{
- u32 val;
+ u64 val;
- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
- xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
- xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
+ val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n",
+ lower_32_bits(val));
+ xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n",
+ upper_32_bits(val));
}
-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
+/* Print the last 32 bytes for 64-byte contexts */
+static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
+{
+ int i;
+ for (i = 0; i < 4; ++i) {
+ xhci_dbg(xhci, "@%p (virt) @%08llx "
+ "(dma) %#08llx - rsvd64[%d]\n",
+ &ctx[4 + i], (unsigned long long)dma,
+ ctx[4 + i], i);
+ dma += 8;
+ }
+}
+
+void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
{
- int i, j;
- int last_ep_ctx = 31;
/* Fields are 32 bits wide, DMA addresses are in bytes */
int field_size = 32 / 8;
+ int i;
- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
- &ctx->drop_flags, (unsigned long long)dma,
- ctx->drop_flags);
- dma += field_size;
- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
- &ctx->add_flags, (unsigned long long)dma,
- ctx->add_flags);
- dma += field_size;
- for (i = 0; i > 6; ++i) {
- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
- &ctx->rsvd[i], (unsigned long long)dma,
- ctx->rsvd[i], i);
- dma += field_size;
- }
+ struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+ dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx);
+ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
xhci_dbg(xhci, "Slot Context:\n");
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
- &ctx->slot.dev_info,
- (unsigned long long)dma, ctx->slot.dev_info);
+ &slot_ctx->dev_info,
+ (unsigned long long)dma, slot_ctx->dev_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
- &ctx->slot.dev_info2,
- (unsigned long long)dma, ctx->slot.dev_info2);
+ &slot_ctx->dev_info2,
+ (unsigned long long)dma, slot_ctx->dev_info2);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
- &ctx->slot.tt_info,
- (unsigned long long)dma, ctx->slot.tt_info);
+ &slot_ctx->tt_info,
+ (unsigned long long)dma, slot_ctx->tt_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
- &ctx->slot.dev_state,
- (unsigned long long)dma, ctx->slot.dev_state);
+ &slot_ctx->dev_state,
+ (unsigned long long)dma, slot_ctx->dev_state);
dma += field_size;
- for (i = 0; i > 4; ++i) {
+ for (i = 0; i < 4; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
- &ctx->slot.reserved[i], (unsigned long long)dma,
- ctx->slot.reserved[i], i);
+ &slot_ctx->reserved[i], (unsigned long long)dma,
+ slot_ctx->reserved[i], i);
dma += field_size;
}
+ if (csz)
+ dbg_rsvd64(xhci, (u64 *)slot_ctx, dma);
+}
+
+void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx,
+ unsigned int last_ep)
+{
+ int i, j;
+ int last_ep_ctx = 31;
+ /* Fields are 32 bits wide, DMA addresses are in bytes */
+ int field_size = 32 / 8;
+ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+
if (last_ep < 31)
last_ep_ctx = last_ep + 1;
for (i = 0; i < last_ep_ctx; ++i) {
+ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
+ dma_addr_t dma = ctx->dma +
+ ((unsigned long)ep_ctx - (unsigned long)ctx);
+
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
- &ctx->ep[i].ep_info,
- (unsigned long long)dma, ctx->ep[i].ep_info);
+ &ep_ctx->ep_info,
+ (unsigned long long)dma, ep_ctx->ep_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
- &ctx->ep[i].ep_info2,
- (unsigned long long)dma, ctx->ep[i].ep_info2);
- dma += field_size;
- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n",
- &ctx->ep[i].deq[0],
- (unsigned long long)dma, ctx->ep[i].deq[0]);
- dma += field_size;
- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n",
- &ctx->ep[i].deq[1],
- (unsigned long long)dma, ctx->ep[i].deq[1]);
+ &ep_ctx->ep_info2,
+ (unsigned long long)dma, ep_ctx->ep_info2);
dma += field_size;
+ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n",
+ &ep_ctx->deq,
+ (unsigned long long)dma, ep_ctx->deq);
+ dma += 2*field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
- &ctx->ep[i].tx_info,
- (unsigned long long)dma, ctx->ep[i].tx_info);
+ &ep_ctx->tx_info,
+ (unsigned long long)dma, ep_ctx->tx_info);
dma += field_size;
for (j = 0; j < 3; ++j) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
- &ctx->ep[i].reserved[j],
+ &ep_ctx->reserved[j],
(unsigned long long)dma,
- ctx->ep[i].reserved[j], j);
+ ep_ctx->reserved[j], j);
+ dma += field_size;
+ }
+
+ if (csz)
+ dbg_rsvd64(xhci, (u64 *)ep_ctx, dma);
+ }
+}
+
+void xhci_dbg_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx,
+ unsigned int last_ep)
+{
+ int i;
+ /* Fields are 32 bits wide, DMA addresses are in bytes */
+ int field_size = 32 / 8;
+ struct xhci_slot_ctx *slot_ctx;
+ dma_addr_t dma = ctx->dma;
+ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+
+ if (ctx->type == XHCI_CTX_TYPE_INPUT) {
+ struct xhci_input_control_ctx *ctrl_ctx =
+ xhci_get_input_control_ctx(xhci, ctx);
+ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
+ &ctrl_ctx->drop_flags, (unsigned long long)dma,
+ ctrl_ctx->drop_flags);
+ dma += field_size;
+ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
+ &ctrl_ctx->add_flags, (unsigned long long)dma,
+ ctrl_ctx->add_flags);
+ dma += field_size;
+ for (i = 0; i < 6; ++i) {
+ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n",
+ &ctrl_ctx->rsvd2[i], (unsigned long long)dma,
+ ctrl_ctx->rsvd2[i], i);
dma += field_size;
}
+
+ if (csz)
+ dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma);
}
+
+ slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+ xhci_dbg_slot_ctx(xhci, ctx);
+ xhci_dbg_ep_ctx(xhci, ctx, last_ep);
}
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index dba3e07ccd09..816c39caca1c 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -103,7 +103,10 @@ int xhci_reset(struct xhci_hcd *xhci)
u32 state;
state = xhci_readl(xhci, &xhci->op_regs->status);
- BUG_ON((state & STS_HALT) == 0);
+ if ((state & STS_HALT) == 0) {
+ xhci_warn(xhci, "Host controller not halted, aborting reset.\n");
+ return 0;
+ }
xhci_dbg(xhci, "// Reset the HC\n");
command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -226,6 +229,7 @@ int xhci_init(struct usb_hcd *hcd)
static void xhci_work(struct xhci_hcd *xhci)
{
u32 temp;
+ u64 temp_64;
/*
* Clear the op reg interrupt status first,
@@ -248,9 +252,9 @@ static void xhci_work(struct xhci_hcd *xhci)
/* FIXME this should be a delayed service routine that clears the EHB */
xhci_handle_event(xhci);
- /* Clear the event handler busy flag; the event ring should be empty. */
- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
- xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]);
+ /* Clear the event handler busy flag (RW1C); the event ring should be empty. */
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
/* Flush posted writes -- FIXME is this necessary? */
xhci_readl(xhci, &xhci->ir_set->irq_pending);
}
@@ -266,19 +270,34 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
u32 temp, temp2;
+ union xhci_trb *trb;
spin_lock(&xhci->lock);
+ trb = xhci->event_ring->dequeue;
/* Check if the xHC generated the interrupt, or the irq is shared */
temp = xhci_readl(xhci, &xhci->op_regs->status);
temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ if (temp == 0xffffffff && temp2 == 0xffffffff)
+ goto hw_died;
+
if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
spin_unlock(&xhci->lock);
return IRQ_NONE;
}
+ xhci_dbg(xhci, "op reg status = %08x\n", temp);
+ xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
+ xhci_dbg(xhci, "Event ring dequeue ptr:\n");
+ xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
+ (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
+ lower_32_bits(trb->link.segment_ptr),
+ upper_32_bits(trb->link.segment_ptr),
+ (unsigned int) trb->link.intr_target,
+ (unsigned int) trb->link.control);
if (temp & STS_FATAL) {
xhci_warn(xhci, "WARNING: Host System Error\n");
xhci_halt(xhci);
+hw_died:
xhci_to_hcd(xhci)->state = HC_STATE_HALT;
spin_unlock(&xhci->lock);
return -ESHUTDOWN;
@@ -295,6 +314,7 @@ void xhci_event_ring_work(unsigned long arg)
{
unsigned long flags;
int temp;
+ u64 temp_64;
struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
int i, j;
@@ -311,9 +331,9 @@ void xhci_event_ring_work(unsigned long arg)
xhci_dbg(xhci, "Event ring:\n");
xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
- temp &= ERST_PTR_MASK;
- xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp_64 &= ~ERST_PTR_MASK;
+ xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
xhci_dbg(xhci, "Command ring:\n");
xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
@@ -356,6 +376,7 @@ void xhci_event_ring_work(unsigned long arg)
int xhci_run(struct usb_hcd *hcd)
{
u32 temp;
+ u64 temp_64;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
void (*doorbell)(struct xhci_hcd *) = NULL;
@@ -382,6 +403,20 @@ int xhci_run(struct usb_hcd *hcd)
add_timer(&xhci->event_ring_timer);
#endif
+ xhci_dbg(xhci, "Command ring memory map follows:\n");
+ xhci_debug_ring(xhci, xhci->cmd_ring);
+ xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
+ xhci_dbg_cmd_ptrs(xhci);
+
+ xhci_dbg(xhci, "ERST memory map follows:\n");
+ xhci_dbg_erst(xhci, &xhci->erst);
+ xhci_dbg(xhci, "Event ring:\n");
+ xhci_debug_ring(xhci, xhci->event_ring);
+ xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp_64 &= ~ERST_PTR_MASK;
+ xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
+
xhci_dbg(xhci, "// Set the interrupt modulation register\n");
temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
@@ -406,22 +441,6 @@ int xhci_run(struct usb_hcd *hcd)
if (NUM_TEST_NOOPS > 0)
doorbell = xhci_setup_one_noop(xhci);
- xhci_dbg(xhci, "Command ring memory map follows:\n");
- xhci_debug_ring(xhci, xhci->cmd_ring);
- xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
- xhci_dbg_cmd_ptrs(xhci);
-
- xhci_dbg(xhci, "ERST memory map follows:\n");
- xhci_dbg_erst(xhci, &xhci->erst);
- xhci_dbg(xhci, "Event ring:\n");
- xhci_debug_ring(xhci, xhci->event_ring);
- xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
- temp &= ERST_PTR_MASK;
- xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]);
- xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp);
-
temp = xhci_readl(xhci, &xhci->op_regs->command);
temp |= (CMD_RUN);
xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
@@ -601,10 +620,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
goto exit;
}
if (usb_endpoint_xfer_control(&urb->ep->desc))
- ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb,
+ /* We have a spinlock and interrupts disabled, so we must pass
+ * atomic context to this function, which may allocate memory.
+ */
+ ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
else if (usb_endpoint_xfer_bulk(&urb->ep->desc))
- ret = xhci_queue_bulk_tx(xhci, mem_flags, urb,
+ ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
else
ret = -EINVAL;
@@ -661,8 +683,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
xhci_dbg(xhci, "Cancel URB %p\n", urb);
+ xhci_dbg(xhci, "Event ring:\n");
+ xhci_debug_ring(xhci, xhci->event_ring);
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index];
+ xhci_dbg(xhci, "Endpoint ring:\n");
+ xhci_debug_ring(xhci, ep_ring);
td = (struct xhci_td *) urb->hcpriv;
ep_ring->cancels_pending++;
@@ -696,7 +722,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
- struct xhci_device_control *in_ctx;
+ struct xhci_container_ctx *in_ctx, *out_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_slot_ctx *slot_ctx;
unsigned int last_ctx;
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
@@ -724,31 +752,34 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
}
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+ out_ctx = xhci->devs[udev->slot_id]->out_ctx;
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
ep_index = xhci_get_endpoint_index(&ep->desc);
- ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+ ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
/* If the HC already knows the endpoint is disabled,
* or the HCD has noted it is disabled, ignore this request
*/
if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED ||
- in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
+ ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
__func__, ep);
return 0;
}
- in_ctx->drop_flags |= drop_flag;
- new_drop_flags = in_ctx->drop_flags;
+ ctrl_ctx->drop_flags |= drop_flag;
+ new_drop_flags = ctrl_ctx->drop_flags;
- in_ctx->add_flags = ~drop_flag;
- new_add_flags = in_ctx->add_flags;
+ ctrl_ctx->add_flags = ~drop_flag;
+ new_add_flags = ctrl_ctx->add_flags;
- last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags);
+ last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
+ slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
/* Update the last valid endpoint context, if we deleted the last one */
- if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
- in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
- in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+ if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
+ slot_ctx->dev_info &= ~LAST_CTX_MASK;
+ slot_ctx->dev_info |= LAST_CTX(last_ctx);
}
- new_slot_info = in_ctx->slot.dev_info;
+ new_slot_info = slot_ctx->dev_info;
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
@@ -778,17 +809,22 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
- struct xhci_device_control *in_ctx;
+ struct xhci_container_ctx *in_ctx, *out_ctx;
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
u32 added_ctxs;
unsigned int last_ctx;
u32 new_add_flags, new_drop_flags, new_slot_info;
int ret = 0;
ret = xhci_check_args(hcd, udev, ep, 1, __func__);
- if (ret <= 0)
+ if (ret <= 0) {
+ /* So we won't queue a reset ep command for a root hub */
+ ep->hcpriv = NULL;
return ret;
+ }
xhci = hcd_to_xhci(hcd);
added_ctxs = xhci_get_endpoint_flag(&ep->desc);
@@ -810,12 +846,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
}
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+ out_ctx = xhci->devs[udev->slot_id]->out_ctx;
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
ep_index = xhci_get_endpoint_index(&ep->desc);
- ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+ ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
/* If the HCD has already noted the endpoint is enabled,
* ignore this request.
*/
- if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
+ if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
__func__, ep);
return 0;
@@ -833,8 +871,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return -ENOMEM;
}
- in_ctx->add_flags |= added_ctxs;
- new_add_flags = in_ctx->add_flags;
+ ctrl_ctx->add_flags |= added_ctxs;
+ new_add_flags = ctrl_ctx->add_flags;
/* If xhci_endpoint_disable() was called for this endpoint, but the
* xHC hasn't been notified yet through the check_bandwidth() call,
@@ -842,14 +880,18 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* descriptors. We must drop and re-add this endpoint, so we leave the
* drop flags alone.
*/
- new_drop_flags = in_ctx->drop_flags;
+ new_drop_flags = ctrl_ctx->drop_flags;
+ slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
/* Update the last valid endpoint context, if we just added one past */
- if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
- in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
- in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+ if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
+ slot_ctx->dev_info &= ~LAST_CTX_MASK;
+ slot_ctx->dev_info |= LAST_CTX(last_ctx);
}
- new_slot_info = in_ctx->slot.dev_info;
+ new_slot_info = slot_ctx->dev_info;
+
+ /* Store the usb_device pointer for later use */
+ ep->hcpriv = udev;
xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
@@ -860,9 +902,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return 0;
}
-static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)
+static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev)
{
+ struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_ep_ctx *ep_ctx;
+ struct xhci_slot_ctx *slot_ctx;
int i;
/* When a device's add flag and drop flag are zero, any subsequent
@@ -870,17 +914,18 @@ static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)
* untouched. Make sure we don't leave any old state in the input
* endpoint contexts.
*/
- virt_dev->in_ctx->drop_flags = 0;
- virt_dev->in_ctx->add_flags = 0;
- virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx->drop_flags = 0;
+ ctrl_ctx->add_flags = 0;
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ slot_ctx->dev_info &= ~LAST_CTX_MASK;
/* Endpoint 0 is always valid */
- virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+ slot_ctx->dev_info |= LAST_CTX(1);
for (i = 1; i < 31; ++i) {
- ep_ctx = &virt_dev->in_ctx->ep[i];
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i);
ep_ctx->ep_info = 0;
ep_ctx->ep_info2 = 0;
- ep_ctx->deq[0] = 0;
- ep_ctx->deq[1] = 0;
+ ep_ctx->deq = 0;
ep_ctx->tx_info = 0;
}
}
@@ -903,6 +948,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
unsigned long flags;
struct xhci_hcd *xhci;
struct xhci_virt_device *virt_dev;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_slot_ctx *slot_ctx;
ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
if (ret <= 0)
@@ -918,16 +965,18 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
virt_dev = xhci->devs[udev->slot_id];
/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
- virt_dev->in_ctx->add_flags |= SLOT_FLAG;
- virt_dev->in_ctx->add_flags &= ~EP0_FLAG;
- virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG;
- virt_dev->in_ctx->drop_flags &= ~EP0_FLAG;
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx->add_flags |= SLOT_FLAG;
+ ctrl_ctx->add_flags &= ~EP0_FLAG;
+ ctrl_ctx->drop_flags &= ~SLOT_FLAG;
+ ctrl_ctx->drop_flags &= ~EP0_FLAG;
xhci_dbg(xhci, "New Input Control Context:\n");
- xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma,
- LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ xhci_dbg_ctx(xhci, virt_dev->in_ctx,
+ LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
spin_lock_irqsave(&xhci->lock, flags);
- ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma,
+ ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
udev->slot_id);
if (ret < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -982,10 +1031,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
}
xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
- xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma,
- LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx,
+ LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
- xhci_zero_in_ctx(virt_dev);
+ xhci_zero_in_ctx(xhci, virt_dev);
/* Free any old rings */
for (i = 1; i < 31; ++i) {
if (virt_dev->new_ep_rings[i]) {
@@ -1023,7 +1072,67 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
virt_dev->new_ep_rings[i] = NULL;
}
}
- xhci_zero_in_ctx(virt_dev);
+ xhci_zero_in_ctx(xhci, virt_dev);
+}
+
+/* Deal with stalled endpoints. The core should have sent the control message
+ * to clear the halt condition. However, we need to make the xHCI hardware
+ * reset its sequence number, since a device will expect a sequence number of
+ * zero after the halt condition is cleared.
+ * Context: in_interrupt
+ */
+void xhci_endpoint_reset(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd *xhci;
+ struct usb_device *udev;
+ unsigned int ep_index;
+ unsigned long flags;
+ int ret;
+ struct xhci_dequeue_state deq_state;
+ struct xhci_ring *ep_ring;
+
+ xhci = hcd_to_xhci(hcd);
+ udev = (struct usb_device *) ep->hcpriv;
+ /* Called with a root hub endpoint (or an endpoint that wasn't added
+ * with xhci_add_endpoint()
+ */
+ if (!ep->hcpriv)
+ return;
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+ ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index];
+ if (!ep_ring->stopped_td) {
+ xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
+ ep->desc.bEndpointAddress);
+ return;
+ }
+
+ xhci_dbg(xhci, "Queueing reset endpoint command\n");
+ spin_lock_irqsave(&xhci->lock, flags);
+ ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
+ /*
+ * Can't change the ring dequeue pointer until it's transitioned to the
+ * stopped state, which is only upon a successful reset endpoint
+ * command. Better hope that last command worked!
+ */
+ if (!ret) {
+ xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+ /* We need to move the HW's dequeue pointer past this TD,
+ * or it will attempt to resend it on the next doorbell ring.
+ */
+ xhci_find_new_dequeue_state(xhci, udev->slot_id,
+ ep_index, ep_ring->stopped_td, &deq_state);
+ xhci_dbg(xhci, "Queueing new dequeue state\n");
+ xhci_queue_new_dequeue_state(xhci, ep_ring,
+ udev->slot_id,
+ ep_index, &deq_state);
+ kfree(ep_ring->stopped_td);
+ xhci_ring_cmd_db(xhci);
+ }
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ if (ret)
+ xhci_warn(xhci, "FIXME allocate a new ring segment\n");
}
/*
@@ -1120,7 +1229,9 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
struct xhci_virt_device *virt_dev;
int ret = 0;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- u32 temp;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ u64 temp_64;
if (!udev->slot_id) {
xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
@@ -1133,10 +1244,12 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
if (!udev->config)
xhci_setup_addressable_virt_dev(xhci, udev);
/* Otherwise, assume the core has the device configured how it wants */
+ xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
spin_lock_irqsave(&xhci->lock, flags);
- ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma,
- udev->slot_id);
+ ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
+ udev->slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
@@ -1176,41 +1289,37 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", virt_dev->cmd_status);
+ xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
ret = -EINVAL;
break;
}
if (ret) {
return ret;
}
- temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]);
- xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp);
- temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]);
- xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp);
- xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n",
- udev->slot_id,
- &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id],
- xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]);
- xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n",
+ temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
+ xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
+ xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
udev->slot_id,
- &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1],
- xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]);
+ &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+ (unsigned long long)
+ xhci->dcbaa->dev_context_ptrs[udev->slot_id]);
xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
- (unsigned long long)virt_dev->out_ctx_dma);
+ (unsigned long long)virt_dev->out_ctx->dma);
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
- xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2);
+ xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
- xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2);
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
/*
* USB core uses address 1 for the roothubs, so we add one to the
* address given back to us by the HC.
*/
- udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1;
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+ udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
/* Zero the input context control for later use */
- virt_dev->in_ctx->add_flags = 0;
- virt_dev->in_ctx->drop_flags = 0;
- /* Mirror flags in the output context for future ep enable/disable */
- virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
- virt_dev->out_ctx->drop_flags = 0;
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx->add_flags = 0;
+ ctrl_ctx->drop_flags = 0;
xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
/* XXX Meh, not sure if anyone else but choose_address uses this. */
@@ -1252,7 +1361,6 @@ static int __init xhci_hcd_init(void)
/* xhci_device_control has eight fields, and also
* embeds one xhci_slot_ctx and 31 xhci_ep_ctx
*/
- BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8);
BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index c8a72de1c508..e6b9a1c6002d 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -88,7 +88,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
return;
prev->next = next;
if (link_trbs) {
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma;
+ prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma;
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
@@ -189,6 +189,63 @@ fail:
return 0;
}
+#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
+
+struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+ int type, gfp_t flags)
+{
+ struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags);
+ if (!ctx)
+ return NULL;
+
+ BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
+ ctx->type = type;
+ ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+ if (type == XHCI_CTX_TYPE_INPUT)
+ ctx->size += CTX_SIZE(xhci->hcc_params);
+
+ ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma);
+ memset(ctx->bytes, 0, ctx->size);
+ return ctx;
+}
+
+void xhci_free_container_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma);
+ kfree(ctx);
+}
+
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT);
+ return (struct xhci_input_control_ctx *)ctx->bytes;
+}
+
+struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ if (ctx->type == XHCI_CTX_TYPE_DEVICE)
+ return (struct xhci_slot_ctx *)ctx->bytes;
+
+ return (struct xhci_slot_ctx *)
+ (ctx->bytes + CTX_SIZE(xhci->hcc_params));
+}
+
+struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx,
+ unsigned int ep_index)
+{
+ /* increment ep index by offset of start of ep ctx array */
+ ep_index++;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ ep_index++;
+
+ return (struct xhci_ep_ctx *)
+ (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params)));
+}
+
/* All the xhci_tds in the ring's TD list should be freed at this point */
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
{
@@ -200,8 +257,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
return;
dev = xhci->devs[slot_id];
- xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0;
- xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+ xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
if (!dev)
return;
@@ -210,11 +266,10 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
xhci_ring_free(xhci, dev->ep_rings[i]);
if (dev->in_ctx)
- dma_pool_free(xhci->device_pool,
- dev->in_ctx, dev->in_ctx_dma);
+ xhci_free_container_ctx(xhci, dev->in_ctx);
if (dev->out_ctx)
- dma_pool_free(xhci->device_pool,
- dev->out_ctx, dev->out_ctx_dma);
+ xhci_free_container_ctx(xhci, dev->out_ctx);
+
kfree(xhci->devs[slot_id]);
xhci->devs[slot_id] = 0;
}
@@ -222,7 +277,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
struct usb_device *udev, gfp_t flags)
{
- dma_addr_t dma;
struct xhci_virt_device *dev;
/* Slot ID 0 is reserved */
@@ -236,23 +290,21 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
return 0;
dev = xhci->devs[slot_id];
- /* Allocate the (output) device context that will be used in the HC */
- dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+ /* Allocate the (output) device context that will be used in the HC. */
+ dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
if (!dev->out_ctx)
goto fail;
- dev->out_ctx_dma = dma;
+
xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
- (unsigned long long)dma);
- memset(dev->out_ctx, 0, sizeof(*dev->out_ctx));
+ (unsigned long long)dev->out_ctx->dma);
/* Allocate the (input) device context for address device command */
- dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags);
if (!dev->in_ctx)
goto fail;
- dev->in_ctx_dma = dma;
+
xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
- (unsigned long long)dma);
- memset(dev->in_ctx, 0, sizeof(*dev->in_ctx));
+ (unsigned long long)dev->in_ctx->dma);
/* Allocate endpoint 0 ring */
dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags);
@@ -261,17 +313,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
init_completion(&dev->cmd_completion);
- /*
- * Point to output device context in dcbaa; skip the output control
- * context, which is eight 32 bit fields (or 32 bytes long)
- */
- xhci->dcbaa->dev_context_ptrs[2*slot_id] =
- (u32) dev->out_ctx_dma + (32);
+ /* Point to output device context in dcbaa. */
+ xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
slot_id,
- &xhci->dcbaa->dev_context_ptrs[2*slot_id],
- (unsigned long long)dev->out_ctx_dma);
- xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+ &xhci->dcbaa->dev_context_ptrs[slot_id],
+ (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]);
return 1;
fail:
@@ -285,6 +332,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
struct xhci_virt_device *dev;
struct xhci_ep_ctx *ep0_ctx;
struct usb_device *top_dev;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_input_control_ctx *ctrl_ctx;
dev = xhci->devs[udev->slot_id];
/* Slot ID 0 is reserved */
@@ -293,27 +342,29 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
udev->slot_id);
return -EINVAL;
}
- ep0_ctx = &dev->in_ctx->ep[0];
+ ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0);
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx);
+ slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx);
/* 2) New slot context and endpoint 0 context are valid*/
- dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+ ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
/* 3) Only the control endpoint is valid - one endpoint context */
- dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+ slot_ctx->dev_info |= LAST_CTX(1);
switch (udev->speed) {
case USB_SPEED_SUPER:
- dev->in_ctx->slot.dev_info |= (u32) udev->route;
- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS;
+ slot_ctx->dev_info |= (u32) udev->route;
+ slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
break;
case USB_SPEED_HIGH:
- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS;
+ slot_ctx->dev_info |= (u32) SLOT_SPEED_HS;
break;
case USB_SPEED_FULL:
- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS;
+ slot_ctx->dev_info |= (u32) SLOT_SPEED_FS;
break;
case USB_SPEED_LOW:
- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS;
+ slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
break;
case USB_SPEED_VARIABLE:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -327,7 +378,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
- dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
+ slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
/* Is this a LS/FS device under a HS hub? */
@@ -337,8 +388,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
*/
if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
udev->tt) {
- dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id;
- dev->in_ctx->slot.tt_info |= udev->ttport << 8;
+ slot_ctx->tt_info = udev->tt->hub->slot_id;
+ slot_ctx->tt_info |= udev->ttport << 8;
}
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
@@ -360,10 +411,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
ep0_ctx->ep_info2 |= MAX_BURST(0);
ep0_ctx->ep_info2 |= ERROR_COUNT(3);
- ep0_ctx->deq[0] =
+ ep0_ctx->deq =
dev->ep_rings[0]->first_seg->dma;
- ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state;
- ep0_ctx->deq[1] = 0;
+ ep0_ctx->deq |= dev->ep_rings[0]->cycle_state;
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
@@ -470,25 +520,26 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
unsigned int max_burst;
ep_index = xhci_get_endpoint_index(&ep->desc);
- ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
/* Set up the endpoint ring */
virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);
if (!virt_dev->new_ep_rings[ep_index])
return -ENOMEM;
ep_ring = virt_dev->new_ep_rings[ep_index];
- ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state;
- ep_ctx->deq[1] = 0;
+ ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
/* FIXME dig Mult and streams info out of ep companion desc */
- /* Allow 3 retries for everything but isoc */
+ /* Allow 3 retries for everything but isoc;
+ * error count = 0 means infinite retries.
+ */
if (!usb_endpoint_xfer_isoc(&ep->desc))
ep_ctx->ep_info2 = ERROR_COUNT(3);
else
- ep_ctx->ep_info2 = ERROR_COUNT(0);
+ ep_ctx->ep_info2 = ERROR_COUNT(1);
ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
@@ -498,7 +549,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
max_packet = ep->desc.wMaxPacketSize;
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
/* dig out max burst from ep companion desc */
- max_packet = ep->ss_ep_comp->desc.bMaxBurst;
+ if (!ep->ss_ep_comp) {
+ xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n");
+ max_packet = 0;
+ } else {
+ max_packet = ep->ss_ep_comp->desc.bMaxBurst;
+ }
ep_ctx->ep_info2 |= MAX_BURST(max_packet);
break;
case USB_SPEED_HIGH:
@@ -531,18 +587,114 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
struct xhci_ep_ctx *ep_ctx;
ep_index = xhci_get_endpoint_index(&ep->desc);
- ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
ep_ctx->ep_info = 0;
ep_ctx->ep_info2 = 0;
- ep_ctx->deq[0] = 0;
- ep_ctx->deq[1] = 0;
+ ep_ctx->deq = 0;
ep_ctx->tx_info = 0;
/* Don't free the endpoint ring until the set interface or configuration
* request succeeds.
*/
}
+/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
+static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
+{
+ int i;
+ struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+
+ xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp);
+
+ if (!num_sp)
+ return 0;
+
+ xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags);
+ if (!xhci->scratchpad)
+ goto fail_sp;
+
+ xhci->scratchpad->sp_array =
+ pci_alloc_consistent(to_pci_dev(dev),
+ num_sp * sizeof(u64),
+ &xhci->scratchpad->sp_dma);
+ if (!xhci->scratchpad->sp_array)
+ goto fail_sp2;
+
+ xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags);
+ if (!xhci->scratchpad->sp_buffers)
+ goto fail_sp3;
+
+ xhci->scratchpad->sp_dma_buffers =
+ kzalloc(sizeof(dma_addr_t) * num_sp, flags);
+
+ if (!xhci->scratchpad->sp_dma_buffers)
+ goto fail_sp4;
+
+ xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma;
+ for (i = 0; i < num_sp; i++) {
+ dma_addr_t dma;
+ void *buf = pci_alloc_consistent(to_pci_dev(dev),
+ xhci->page_size, &dma);
+ if (!buf)
+ goto fail_sp5;
+
+ xhci->scratchpad->sp_array[i] = dma;
+ xhci->scratchpad->sp_buffers[i] = buf;
+ xhci->scratchpad->sp_dma_buffers[i] = dma;
+ }
+
+ return 0;
+
+ fail_sp5:
+ for (i = i - 1; i >= 0; i--) {
+ pci_free_consistent(to_pci_dev(dev), xhci->page_size,
+ xhci->scratchpad->sp_buffers[i],
+ xhci->scratchpad->sp_dma_buffers[i]);
+ }
+ kfree(xhci->scratchpad->sp_dma_buffers);
+
+ fail_sp4:
+ kfree(xhci->scratchpad->sp_buffers);
+
+ fail_sp3:
+ pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64),
+ xhci->scratchpad->sp_array,
+ xhci->scratchpad->sp_dma);
+
+ fail_sp2:
+ kfree(xhci->scratchpad);
+ xhci->scratchpad = NULL;
+
+ fail_sp:
+ return -ENOMEM;
+}
+
+static void scratchpad_free(struct xhci_hcd *xhci)
+{
+ int num_sp;
+ int i;
+ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+ if (!xhci->scratchpad)
+ return;
+
+ num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+
+ for (i = 0; i < num_sp; i++) {
+ pci_free_consistent(pdev, xhci->page_size,
+ xhci->scratchpad->sp_buffers[i],
+ xhci->scratchpad->sp_dma_buffers[i]);
+ }
+ kfree(xhci->scratchpad->sp_dma_buffers);
+ kfree(xhci->scratchpad->sp_buffers);
+ pci_free_consistent(pdev, num_sp * sizeof(u64),
+ xhci->scratchpad->sp_array,
+ xhci->scratchpad->sp_dma);
+ kfree(xhci->scratchpad);
+ xhci->scratchpad = NULL;
+}
+
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
@@ -551,10 +703,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
/* Free the Event Ring Segment Table and the actual Event Ring */
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]);
- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]);
- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
+ xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
pci_free_consistent(pdev, size,
@@ -566,8 +716,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
- xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]);
- xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]);
+ xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -586,8 +735,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->device_pool = NULL;
xhci_dbg(xhci, "Freed device context pool\n");
- xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]);
- xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]);
+ xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
if (xhci->dcbaa)
pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
xhci->dcbaa, xhci->dcbaa->dma);
@@ -595,6 +743,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->page_size = 0;
xhci->page_shift = 0;
+ scratchpad_free(xhci);
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
@@ -602,6 +751,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
dma_addr_t dma;
struct device *dev = xhci_to_hcd(xhci)->self.controller;
unsigned int val, val2;
+ u64 val_64;
struct xhci_segment *seg;
u32 page_size;
int i;
@@ -647,8 +797,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci->dcbaa->dma = dma;
xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
- xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]);
- xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]);
+ xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
/*
* Initialize the ring segment pool. The ring must be a contiguous
@@ -658,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
*/
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
SEGMENT_SIZE, 64, xhci->page_size);
+
/* See Table 46 and Note on Figure 55 */
- /* FIXME support 64-byte contexts */
xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
- sizeof(struct xhci_device_control),
- 64, xhci->page_size);
+ 2112, 64, xhci->page_size);
if (!xhci->segment_pool || !xhci->device_pool)
goto fail;
@@ -675,14 +823,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
(unsigned long long)xhci->cmd_ring->first_seg->dma);
/* Set the address in the Command Ring Control register */
- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
- val = (val & ~CMD_RING_ADDR_MASK) |
- (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) |
+ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+ (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val);
- xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]);
- xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n");
- xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]);
+ xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val);
+ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
@@ -722,8 +868,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* set ring base address and size for each segment table entry */
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
- entry->seg_addr[0] = seg->dma;
- entry->seg_addr[1] = 0;
+ entry->seg_addr = seg->dma;
entry->seg_size = TRBS_PER_SEGMENT;
entry->rsvd = 0;
seg = seg->next;
@@ -741,11 +886,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* set the segment table base address */
xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
(unsigned long long)xhci->erst.erst_dma_addr);
- val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]);
- val &= ERST_PTR_MASK;
- val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK);
- xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]);
- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
+ val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+ val_64 &= ERST_PTR_MASK;
+ val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
+ xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
/* Set the event ring dequeue address */
xhci_set_hc_event_deq(xhci);
@@ -761,7 +905,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
for (i = 0; i < MAX_HC_SLOTS; ++i)
xhci->devs[i] = 0;
+ if (scratchpad_alloc(xhci, flags))
+ goto fail;
+
return 0;
+
fail:
xhci_warn(xhci, "Couldn't initialize memory\n");
xhci_mem_cleanup(xhci);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 1462709e26c0..592fe7e623f7 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -117,6 +117,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
.free_dev = xhci_free_dev,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
+ .endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 02d81985c454..aa88a067148b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -135,6 +135,7 @@ static void next_trb(struct xhci_hcd *xhci,
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
{
union xhci_trb *next = ++(ring->dequeue);
+ unsigned long long addr;
ring->deq_updates++;
/* Update the dequeue pointer further if that was a link TRB or we're at
@@ -152,6 +153,13 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
ring->dequeue = ring->deq_seg->trbs;
next = ring->dequeue;
}
+ addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
+ if (ring == xhci->event_ring)
+ xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr);
+ else if (ring == xhci->cmd_ring)
+ xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr);
+ else
+ xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr);
}
/*
@@ -171,6 +179,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
{
u32 chain;
union xhci_trb *next;
+ unsigned long long addr;
chain = ring->enqueue->generic.field[3] & TRB_CHAIN;
next = ++(ring->enqueue);
@@ -204,6 +213,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
}
+ addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
+ if (ring == xhci->event_ring)
+ xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr);
+ else if (ring == xhci->cmd_ring)
+ xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr);
+ else
+ xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr);
}
/*
@@ -237,7 +253,7 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
{
- u32 temp;
+ u64 temp;
dma_addr_t deq;
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
@@ -246,13 +262,15 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
xhci_warn(xhci, "WARN something wrong with SW event ring "
"dequeue ptr.\n");
/* Update HC event ring dequeue pointer */
- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+ temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
temp &= ERST_PTR_MASK;
- if (!in_interrupt())
- xhci_dbg(xhci, "// Write event ring dequeue pointer\n");
- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
- xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp,
- &xhci->ir_set->erst_dequeue[0]);
+ /* Don't clear the EHB bit (which is RW1C) because
+ * there might be more events to service.
+ */
+ temp &= ~ERST_EHB;
+ xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n");
+ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+ &xhci->ir_set->erst_dequeue);
}
/* Ring the host controller doorbell after placing a command on the ring */
@@ -279,7 +297,8 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci,
/* Don't ring the doorbell for this endpoint if there are pending
* cancellations because the we don't want to interrupt processing.
*/
- if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) {
+ if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)
+ && !(ep_ring->state & EP_HALTED)) {
field = xhci_readl(xhci, db_addr) & DB_MASK;
xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
/* Flush PCI posted writes - FIXME Matthew Wilcox says this
@@ -316,12 +335,6 @@ static struct xhci_segment *find_trb_seg(
return cur_seg;
}
-struct dequeue_state {
- struct xhci_segment *new_deq_seg;
- union xhci_trb *new_deq_ptr;
- int new_cycle_state;
-};
-
/*
* Move the xHC's endpoint ring dequeue pointer past cur_td.
* Record the new state of the xHC's endpoint ring dequeue segment,
@@ -336,24 +349,30 @@ struct dequeue_state {
* - Finally we move the dequeue state one TRB further, toggling the cycle bit
* if we've moved it past a link TRB with the toggle cycle bit set.
*/
-static void find_new_dequeue_state(struct xhci_hcd *xhci,
+void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
- struct xhci_td *cur_td, struct dequeue_state *state)
+ struct xhci_td *cur_td, struct xhci_dequeue_state *state)
{
struct xhci_virt_device *dev = xhci->devs[slot_id];
struct xhci_ring *ep_ring = dev->ep_rings[ep_index];
struct xhci_generic_trb *trb;
+ struct xhci_ep_ctx *ep_ctx;
+ dma_addr_t addr;
state->new_cycle_state = 0;
+ xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
state->new_deq_seg = find_trb_seg(cur_td->start_seg,
ep_ring->stopped_trb,
&state->new_cycle_state);
if (!state->new_deq_seg)
BUG();
/* Dig out the cycle state saved by the xHC during the stop ep cmd */
- state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0];
+ xhci_dbg(xhci, "Finding endpoint context\n");
+ ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+ state->new_cycle_state = 0x1 & ep_ctx->deq;
state->new_deq_ptr = cur_td->last_trb;
+ xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
state->new_deq_seg = find_trb_seg(state->new_deq_seg,
state->new_deq_ptr,
&state->new_cycle_state);
@@ -367,6 +386,12 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci,
next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
/* Don't update the ring cycle state for the producer (us). */
+ xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n",
+ state->new_deq_seg);
+ addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr);
+ xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n",
+ (unsigned long long) addr);
+ xhci_dbg(xhci, "Setting dequeue pointer in internal ring state.\n");
ep_ring->dequeue = state->new_deq_ptr;
ep_ring->deq_seg = state->new_deq_seg;
}
@@ -416,6 +441,30 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index, struct xhci_segment *deq_seg,
union xhci_trb *deq_ptr, u32 cycle_state);
+void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
+ struct xhci_ring *ep_ring, unsigned int slot_id,
+ unsigned int ep_index, struct xhci_dequeue_state *deq_state)
+{
+ xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+ "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+ deq_state->new_deq_seg,
+ (unsigned long long)deq_state->new_deq_seg->dma,
+ deq_state->new_deq_ptr,
+ (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr),
+ deq_state->new_cycle_state);
+ queue_set_tr_deq(xhci, slot_id, ep_index,
+ deq_state->new_deq_seg,
+ deq_state->new_deq_ptr,
+ (u32) deq_state->new_cycle_state);
+ /* Stop the TD queueing code from ringing the doorbell until
+ * this command completes. The HC won't set the dequeue pointer
+ * if the ring is running, and ringing the doorbell starts the
+ * ring running.
+ */
+ ep_ring->state |= SET_DEQ_PENDING;
+ xhci_ring_cmd_db(xhci);
+}
+
/*
* When we get a command completion for a Stop Endpoint Command, we need to
* unlink any cancelled TDs from the ring. There are two ways to do that:
@@ -436,7 +485,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
struct xhci_td *cur_td = 0;
struct xhci_td *last_unlinked_td;
- struct dequeue_state deq_state;
+ struct xhci_dequeue_state deq_state;
#ifdef CONFIG_USB_HCD_STAT
ktime_t stop_time = ktime_get();
#endif
@@ -464,7 +513,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* move the xHC endpoint ring dequeue pointer past this TD.
*/
if (cur_td == ep_ring->stopped_td)
- find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
+ xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
&deq_state);
else
td_to_noop(xhci, ep_ring, cur_td);
@@ -480,24 +529,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
- xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
- "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
- deq_state.new_deq_seg,
- (unsigned long long)deq_state.new_deq_seg->dma,
- deq_state.new_deq_ptr,
- (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr),
- deq_state.new_cycle_state);
- queue_set_tr_deq(xhci, slot_id, ep_index,
- deq_state.new_deq_seg,
- deq_state.new_deq_ptr,
- (u32) deq_state.new_cycle_state);
- /* Stop the TD queueing code from ringing the doorbell until
- * this command completes. The HC won't set the dequeue pointer
- * if the ring is running, and ringing the doorbell starts the
- * ring running.
- */
- ep_ring->state |= SET_DEQ_PENDING;
- xhci_ring_cmd_db(xhci);
+ xhci_queue_new_dequeue_state(xhci, ep_ring,
+ slot_id, ep_index, &deq_state);
} else {
/* Otherwise just ring the doorbell to restart the ring */
ring_ep_doorbell(xhci, slot_id, ep_index);
@@ -551,11 +584,15 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
unsigned int ep_index;
struct xhci_ring *ep_ring;
struct xhci_virt_device *dev;
+ struct xhci_ep_ctx *ep_ctx;
+ struct xhci_slot_ctx *slot_ctx;
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
dev = xhci->devs[slot_id];
ep_ring = dev->ep_rings[ep_index];
+ ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+ slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
if (GET_COMP_CODE(event->status) != COMP_SUCCESS) {
unsigned int ep_state;
@@ -569,9 +606,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
case COMP_CTX_STATE:
xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "
"to incorrect slot or ep state.\n");
- ep_state = dev->out_ctx->ep[ep_index].ep_info;
+ ep_state = ep_ctx->ep_info;
ep_state &= EP_STATE_MASK;
- slot_state = dev->out_ctx->slot.dev_state;
+ slot_state = slot_ctx->dev_state;
slot_state = GET_SLOT_STATE(slot_state);
xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
slot_state, ep_state);
@@ -593,16 +630,33 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
* cancelling URBs, which might not be an error...
*/
} else {
- xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, "
- "deq[1] = 0x%x.\n",
- dev->out_ctx->ep[ep_index].deq[0],
- dev->out_ctx->ep[ep_index].deq[1]);
+ xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
+ ep_ctx->deq);
}
ep_ring->state &= ~SET_DEQ_PENDING;
ring_ep_doorbell(xhci, slot_id, ep_index);
}
+static void handle_reset_ep_completion(struct xhci_hcd *xhci,
+ struct xhci_event_cmd *event,
+ union xhci_trb *trb)
+{
+ int slot_id;
+ unsigned int ep_index;
+
+ slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
+ ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+ /* This command will only fail if the endpoint wasn't halted,
+ * but we don't care.
+ */
+ xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
+ (unsigned int) GET_COMP_CODE(event->status));
+
+ /* Clear our internal halted state and restart the ring */
+ xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED;
+ ring_ep_doorbell(xhci, slot_id, ep_index);
+}
static void handle_cmd_completion(struct xhci_hcd *xhci,
struct xhci_event_cmd *event)
@@ -611,7 +665,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
u64 cmd_dma;
dma_addr_t cmd_dequeue_dma;
- cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0];
+ cmd_dma = event->cmd_trb;
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
xhci->cmd_ring->dequeue);
/* Is the command ring deq ptr out of sync with the deq seg ptr? */
@@ -653,6 +707,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
case TRB_TYPE(TRB_CMD_NOOP):
++xhci->noops_handled;
break;
+ case TRB_TYPE(TRB_RESET_EP):
+ handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue);
+ break;
default:
/* Skip over unknown commands on the event ring */
xhci->error_bitmask |= 1 << 6;
@@ -756,7 +813,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
union xhci_trb *event_trb;
struct urb *urb = 0;
int status = -EINPROGRESS;
+ struct xhci_ep_ctx *ep_ctx;
+ xhci_dbg(xhci, "In %s\n", __func__);
xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
if (!xdev) {
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
@@ -765,17 +824,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Endpoint ID is 1 based, our index is zero based */
ep_index = TRB_TO_EP_ID(event->flags) - 1;
+ xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
ep_ring = xdev->ep_rings[ep_index];
- if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
+ ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
+ if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");
return -ENODEV;
}
- event_dma = event->buffer[0];
- if (event->buffer[1] != 0)
- xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n");
-
+ event_dma = event->buffer;
/* This TRB should be in the TD at the head of this ring's TD list */
+ xhci_dbg(xhci, "%s - checking for list empty\n", __func__);
if (list_empty(&ep_ring->td_list)) {
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
TRB_TO_SLOT_ID(event->flags), ep_index);
@@ -785,11 +844,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
urb = NULL;
goto cleanup;
}
+ xhci_dbg(xhci, "%s - getting list entry\n", __func__);
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
/* Is this a TRB in the currently executing TD? */
+ xhci_dbg(xhci, "%s - looking for TD\n", __func__);
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
td->last_trb, event_dma);
+ xhci_dbg(xhci, "%s - found event_seg = %p\n", __func__, event_seg);
if (!event_seg) {
/* HC is busted, give up! */
xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n");
@@ -798,10 +860,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)];
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
- xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n",
- (unsigned int) event->buffer[0]);
- xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n",
- (unsigned int) event->buffer[1]);
+ xhci_dbg(xhci, "Offset 0x00 (buffer lo) = 0x%x\n",
+ lower_32_bits(event->buffer));
+ xhci_dbg(xhci, "Offset 0x04 (buffer hi) = 0x%x\n",
+ upper_32_bits(event->buffer));
xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n",
(unsigned int) event->transfer_len);
xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n",
@@ -823,6 +885,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
break;
case COMP_STALL:
xhci_warn(xhci, "WARN: Stalled endpoint\n");
+ ep_ring->state |= EP_HALTED;
status = -EPIPE;
break;
case COMP_TRB_ERR:
@@ -833,6 +896,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_warn(xhci, "WARN: transfer error on endpoint\n");
status = -EPROTO;
break;
+ case COMP_BABBLE:
+ xhci_warn(xhci, "WARN: babble error on endpoint\n");
+ status = -EOVERFLOW;
+ break;
case COMP_DB_ERR:
xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n");
status = -ENOSR;
@@ -874,15 +941,26 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (event_trb != ep_ring->dequeue) {
/* The event was for the status stage */
if (event_trb == td->last_trb) {
- td->urb->actual_length =
- td->urb->transfer_buffer_length;
+ if (td->urb->actual_length != 0) {
+ /* Don't overwrite a previously set error code */
+ if (status == -EINPROGRESS || status == 0)
+ /* Did we already see a short data stage? */
+ status = -EREMOTEIO;
+ } else {
+ td->urb->actual_length =
+ td->urb->transfer_buffer_length;
+ }
} else {
/* Maybe the event was for the data stage? */
- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
+ if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {
/* We didn't stop on a link TRB in the middle */
td->urb->actual_length =
td->urb->transfer_buffer_length -
TRB_LEN(event->transfer_len);
+ xhci_dbg(xhci, "Waiting for status stage event\n");
+ urb = NULL;
+ goto cleanup;
+ }
}
}
} else {
@@ -929,16 +1007,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
TRB_LEN(event->transfer_len));
td->urb->actual_length = 0;
}
- if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
- status = -EREMOTEIO;
- else
- status = 0;
+ /* Don't overwrite a previously set error code */
+ if (status == -EINPROGRESS) {
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+ status = -EREMOTEIO;
+ else
+ status = 0;
+ }
} else {
td->urb->actual_length = td->urb->transfer_buffer_length;
/* Ignore a short packet completion if the
* untransferred length was zero.
*/
- status = 0;
+ if (status == -EREMOTEIO)
+ status = 0;
}
} else {
/* Slow path - walk the list, starting from the dequeue
@@ -965,19 +1047,30 @@ static int handle_tx_event(struct xhci_hcd *xhci,
TRB_LEN(event->transfer_len);
}
}
- /* The Endpoint Stop Command completion will take care of
- * any stopped TDs. A stopped TD may be restarted, so don't update the
- * ring dequeue pointer or take this TD off any lists yet.
- */
if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||
GET_COMP_CODE(event->transfer_len) == COMP_STOP) {
+ /* The Endpoint Stop Command completion will take care of any
+ * stopped TDs. A stopped TD may be restarted, so don't update
+ * the ring dequeue pointer or take this TD off any lists yet.
+ */
ep_ring->stopped_td = td;
ep_ring->stopped_trb = event_trb;
} else {
- /* Update ring dequeue pointer */
- while (ep_ring->dequeue != td->last_trb)
+ if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) {
+ /* The transfer is completed from the driver's
+ * perspective, but we need to issue a set dequeue
+ * command for this stalled endpoint to move the dequeue
+ * pointer past the TD. We can't do that here because
+ * the halt condition must be cleared first.
+ */
+ ep_ring->stopped_td = td;
+ ep_ring->stopped_trb = event_trb;
+ } else {
+ /* Update ring dequeue pointer */
+ while (ep_ring->dequeue != td->last_trb)
+ inc_deq(xhci, ep_ring, false);
inc_deq(xhci, ep_ring, false);
- inc_deq(xhci, ep_ring, false);
+ }
/* Clean up the endpoint's TD list */
urb = td->urb;
@@ -987,7 +1080,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
list_del(&td->cancelled_td_list);
ep_ring->cancels_pending--;
}
- kfree(td);
+ /* Leave the TD around for the reset endpoint function to use */
+ if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) {
+ kfree(td);
+ }
urb->hcpriv = NULL;
}
cleanup:
@@ -997,6 +1093,8 @@ cleanup:
/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
if (urb) {
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
+ xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
+ urb, td->urb->actual_length, status);
spin_unlock(&xhci->lock);
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
spin_lock(&xhci->lock);
@@ -1014,6 +1112,7 @@ void xhci_handle_event(struct xhci_hcd *xhci)
int update_ptrs = 1;
int ret;
+ xhci_dbg(xhci, "In %s\n", __func__);
if (!xhci->event_ring || !xhci->event_ring->dequeue) {
xhci->error_bitmask |= 1 << 1;
return;
@@ -1026,18 +1125,25 @@ void xhci_handle_event(struct xhci_hcd *xhci)
xhci->error_bitmask |= 1 << 2;
return;
}
+ xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
/* FIXME: Handle more event types. */
switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {
case TRB_TYPE(TRB_COMPLETION):
+ xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);
handle_cmd_completion(xhci, &event->event_cmd);
+ xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__);
break;
case TRB_TYPE(TRB_PORT_STATUS):
+ xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);
handle_port_status(xhci, event);
+ xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);
update_ptrs = 0;
break;
case TRB_TYPE(TRB_TRANSFER):
+ xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);
ret = handle_tx_event(xhci, &event->trans_event);
+ xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__);
if (ret < 0)
xhci->error_bitmask |= 1 << 9;
else
@@ -1093,13 +1199,13 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
*/
xhci_warn(xhci, "WARN urb submitted to disabled ep\n");
return -ENOENT;
- case EP_STATE_HALTED:
case EP_STATE_ERROR:
- xhci_warn(xhci, "WARN waiting for halt or error on ep "
- "to be cleared\n");
+ xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n");
/* FIXME event handling code for error needs to clear it */
/* XXX not sure if this should be -ENOENT or not */
return -EINVAL;
+ case EP_STATE_HALTED:
+ xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");
case EP_STATE_STOPPED:
case EP_STATE_RUNNING:
break;
@@ -1128,9 +1234,9 @@ static int prepare_transfer(struct xhci_hcd *xhci,
gfp_t mem_flags)
{
int ret;
-
+ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
ret = prepare_ring(xhci, xdev->ep_rings[ep_index],
- xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK,
+ ep_ctx->ep_info & EP_STATE_MASK,
num_trbs, mem_flags);
if (ret)
return ret;
@@ -1285,6 +1391,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Queue the first TRB, even if it's zero-length */
do {
u32 field = 0;
+ u32 length_field = 0;
/* Don't change the cycle bit of the first TRB until later */
if (first_trb)
@@ -1314,10 +1421,13 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
(unsigned int) addr + trb_buff_len);
}
+ length_field = TRB_LEN(trb_buff_len) |
+ TD_REMAINDER(urb->transfer_buffer_length - running_total) |
+ TRB_INTR_TARGET(0);
queue_trb(xhci, ep_ring, false,
- (u32) addr,
- (u32) ((u64) addr >> 32),
- TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+ lower_32_bits(addr),
+ upper_32_bits(addr),
+ length_field,
/* We always want to know if the TRB was short,
* or we won't get an event when it completes.
* (Unless we use event data TRBs, which are a
@@ -1365,7 +1475,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_generic_trb *start_trb;
bool first_trb;
int start_cycle;
- u32 field;
+ u32 field, length_field;
int running_total, trb_buff_len, ret;
u64 addr;
@@ -1443,10 +1553,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
}
+ length_field = TRB_LEN(trb_buff_len) |
+ TD_REMAINDER(urb->transfer_buffer_length - running_total) |
+ TRB_INTR_TARGET(0);
queue_trb(xhci, ep_ring, false,
- (u32) addr,
- (u32) ((u64) addr >> 32),
- TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+ lower_32_bits(addr),
+ upper_32_bits(addr),
+ length_field,
/* We always want to know if the TRB was short,
* or we won't get an event when it completes.
* (Unless we use event data TRBs, which are a
@@ -1478,7 +1591,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct usb_ctrlrequest *setup;
struct xhci_generic_trb *start_trb;
int start_cycle;
- u32 field;
+ u32 field, length_field;
struct xhci_td *td;
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
@@ -1528,13 +1641,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* If there's data, queue data TRBs */
field = 0;
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+ TD_REMAINDER(urb->transfer_buffer_length) |
+ TRB_INTR_TARGET(0);
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
queue_trb(xhci, ep_ring, false,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
- TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0),
+ length_field,
/* Event on short tx */
field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);
}
@@ -1603,7 +1719,8 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id)
{
- return queue_command(xhci, in_ctx_ptr, 0, 0,
+ return queue_command(xhci, lower_32_bits(in_ctx_ptr),
+ upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id));
}
@@ -1611,7 +1728,8 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id)
{
- return queue_command(xhci, in_ctx_ptr, 0, 0,
+ return queue_command(xhci, lower_32_bits(in_ctx_ptr),
+ upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));
}
@@ -1639,10 +1757,23 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
u32 type = TRB_TYPE(TRB_SET_DEQ);
addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr);
- if (addr == 0)
+ if (addr == 0) {
xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");
xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n",
deq_seg, deq_ptr);
- return queue_command(xhci, (u32) addr | cycle_state, 0, 0,
+ return 0;
+ }
+ return queue_command(xhci, lower_32_bits(addr) | cycle_state,
+ upper_32_bits(addr), 0,
trb_slot_id | trb_ep_index | type);
}
+
+int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
+ unsigned int ep_index)
+{
+ u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
+ u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+ u32 type = TRB_TYPE(TRB_RESET_EP);
+
+ return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type);
+}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 8936eeb5588b..ffe1625d4e1b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -25,6 +25,7 @@
#include <linux/usb.h>
#include <linux/timer.h>
+#include <linux/kernel.h>
#include "../core/hcd.h"
/* Code sharing between pci-quirks and xhci hcd */
@@ -42,14 +43,6 @@
* xHCI register interface.
* This corresponds to the eXtensible Host Controller Interface (xHCI)
* Revision 0.95 specification
- *
- * Registers should always be accessed with double word or quad word accesses.
- *
- * Some xHCI implementations may support 64-bit address pointers. Registers
- * with 64-bit address pointers should be written to with dword accesses by
- * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
- * xHCI implementations that do not support 64-bit address pointers will ignore
- * the high dword, and write order is irrelevant.
*/
/**
@@ -96,6 +89,7 @@ struct xhci_cap_regs {
#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf)
/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f)
/* HCSPARAMS3 - hcs_params3 - bitmasks */
/* bits 0:7, Max U1 to U0 latency for the roothub ports */
@@ -166,10 +160,10 @@ struct xhci_op_regs {
u32 reserved1;
u32 reserved2;
u32 dev_notification;
- u32 cmd_ring[2];
+ u64 cmd_ring;
/* rsvd: offset 0x20-2F */
u32 reserved3[4];
- u32 dcbaa_ptr[2];
+ u64 dcbaa_ptr;
u32 config_reg;
/* rsvd: offset 0x3C-3FF */
u32 reserved4[241];
@@ -254,7 +248,7 @@ struct xhci_op_regs {
#define CMD_RING_RUNNING (1 << 3)
/* bits 4:5 reserved and should be preserved */
/* Command Ring pointer - bit mask for the lower 32 bits. */
-#define CMD_RING_ADDR_MASK (0xffffffc0)
+#define CMD_RING_RSVD_BITS (0x3f)
/* CONFIG - Configure Register - config_reg bitmasks */
/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
@@ -382,8 +376,8 @@ struct xhci_intr_reg {
u32 irq_control;
u32 erst_size;
u32 rsvd;
- u32 erst_base[2];
- u32 erst_dequeue[2];
+ u64 erst_base;
+ u64 erst_dequeue;
};
/* irq_pending bitmasks */
@@ -453,6 +447,27 @@ struct xhci_doorbell_array {
/**
+ * struct xhci_container_ctx
+ * @type: Type of context. Used to calculated offsets to contained contexts.
+ * @size: Size of the context data
+ * @bytes: The raw context data given to HW
+ * @dma: dma address of the bytes
+ *
+ * Represents either a Device or Input context. Holds a pointer to the raw
+ * memory used for the context (bytes) and dma address of it (dma).
+ */
+struct xhci_container_ctx {
+ unsigned type;
+#define XHCI_CTX_TYPE_DEVICE 0x1
+#define XHCI_CTX_TYPE_INPUT 0x2
+
+ int size;
+
+ u8 *bytes;
+ dma_addr_t dma;
+};
+
+/**
* struct xhci_slot_ctx
* @dev_info: Route string, device speed, hub info, and last valid endpoint
* @dev_info2: Max exit latency for device number, root hub port number
@@ -538,7 +553,7 @@ struct xhci_slot_ctx {
struct xhci_ep_ctx {
u32 ep_info;
u32 ep_info2;
- u32 deq[2];
+ u64 deq;
u32 tx_info;
/* offset 0x14 - 0x1f reserved for HC internal use */
u32 reserved[3];
@@ -589,18 +604,16 @@ struct xhci_ep_ctx {
/**
- * struct xhci_device_control
- * Input/Output context; see section 6.2.5.
+ * struct xhci_input_control_context
+ * Input control context; see section 6.2.5.
*
* @drop_context: set the bit of the endpoint context you want to disable
* @add_context: set the bit of the endpoint context you want to enable
*/
-struct xhci_device_control {
+struct xhci_input_control_ctx {
u32 drop_flags;
u32 add_flags;
- u32 rsvd[6];
- struct xhci_slot_ctx slot;
- struct xhci_ep_ctx ep[31];
+ u32 rsvd2[6];
};
/* drop context bitmasks */
@@ -608,7 +621,6 @@ struct xhci_device_control {
/* add context bitmasks */
#define ADD_EP(x) (0x1 << x)
-
struct xhci_virt_device {
/*
* Commands to the hardware are passed an "input context" that
@@ -618,11 +630,10 @@ struct xhci_virt_device {
* track of input and output contexts separately because
* these commands might fail and we don't trust the hardware.
*/
- struct xhci_device_control *out_ctx;
- dma_addr_t out_ctx_dma;
+ struct xhci_container_ctx *out_ctx;
/* Used for addressing devices and configuration changes */
- struct xhci_device_control *in_ctx;
- dma_addr_t in_ctx_dma;
+ struct xhci_container_ctx *in_ctx;
+
/* FIXME when stream support is added */
struct xhci_ring *ep_rings[31];
/* Temporary storage in case the configure endpoint command fails and we
@@ -641,7 +652,7 @@ struct xhci_virt_device {
*/
struct xhci_device_context_array {
/* 64-bit device addresses; we only write 32-bit addresses */
- u32 dev_context_ptrs[2*MAX_HC_SLOTS];
+ u64 dev_context_ptrs[MAX_HC_SLOTS];
/* private xHCD pointers */
dma_addr_t dma;
};
@@ -654,7 +665,7 @@ struct xhci_device_context_array {
struct xhci_stream_ctx {
/* 64-bit stream ring address, cycle state, and stream type */
- u32 stream_ring[2];
+ u64 stream_ring;
/* offset 0x14 - 0x1f reserved for HC internal use */
u32 reserved[2];
};
@@ -662,7 +673,7 @@ struct xhci_stream_ctx {
struct xhci_transfer_event {
/* 64-bit buffer address, or immediate data */
- u32 buffer[2];
+ u64 buffer;
u32 transfer_len;
/* This field is interpreted differently based on the type of TRB */
u32 flags;
@@ -744,7 +755,7 @@ struct xhci_transfer_event {
struct xhci_link_trb {
/* 64-bit segment pointer*/
- u32 segment_ptr[2];
+ u64 segment_ptr;
u32 intr_target;
u32 control;
};
@@ -755,7 +766,7 @@ struct xhci_link_trb {
/* Command completion event TRB */
struct xhci_event_cmd {
/* Pointer to command TRB, or the value passed by the event data trb */
- u32 cmd_trb[2];
+ u64 cmd_trb;
u32 status;
u32 flags;
};
@@ -848,8 +859,8 @@ union xhci_trb {
#define TRB_CONFIG_EP 12
/* Evaluate Context Command */
#define TRB_EVAL_CONTEXT 13
-/* Reset Transfer Ring Command */
-#define TRB_RESET_RING 14
+/* Reset Endpoint Command */
+#define TRB_RESET_EP 14
/* Stop Transfer Ring Command */
#define TRB_STOP_RING 15
/* Set Transfer Ring Dequeue Pointer Command */
@@ -929,6 +940,7 @@ struct xhci_ring {
unsigned int cancels_pending;
unsigned int state;
#define SET_DEQ_PENDING (1 << 0)
+#define EP_HALTED (1 << 1)
/* The TRB that was last reported in a stopped endpoint ring */
union xhci_trb *stopped_trb;
struct xhci_td *stopped_td;
@@ -940,9 +952,15 @@ struct xhci_ring {
u32 cycle_state;
};
+struct xhci_dequeue_state {
+ struct xhci_segment *new_deq_seg;
+ union xhci_trb *new_deq_ptr;
+ int new_cycle_state;
+};
+
struct xhci_erst_entry {
/* 64-bit event ring segment address */
- u32 seg_addr[2];
+ u64 seg_addr;
u32 seg_size;
/* Set to zero */
u32 rsvd;
@@ -957,6 +975,13 @@ struct xhci_erst {
unsigned int erst_size;
};
+struct xhci_scratchpad {
+ u64 *sp_array;
+ dma_addr_t sp_dma;
+ void **sp_buffers;
+ dma_addr_t *sp_dma_buffers;
+};
+
/*
* Each segment table entry is 4*32bits long. 1K seems like an ok size:
* (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
@@ -1011,6 +1036,9 @@ struct xhci_hcd {
struct xhci_ring *cmd_ring;
struct xhci_ring *event_ring;
struct xhci_erst erst;
+ /* Scratchpad */
+ struct xhci_scratchpad *scratchpad;
+
/* slot enabling and address device helpers */
struct completion addr_dev;
int slot_id;
@@ -1071,13 +1099,43 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
static inline void xhci_writel(struct xhci_hcd *xhci,
const unsigned int val, __u32 __iomem *regs)
{
- if (!in_interrupt())
- xhci_dbg(xhci,
- "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
- regs, val);
+ xhci_dbg(xhci,
+ "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
+ regs, val);
writel(val, regs);
}
+/*
+ * Registers should always be accessed with double word or quad word accesses.
+ *
+ * Some xHCI implementations may support 64-bit address pointers. Registers
+ * with 64-bit address pointers should be written to with dword accesses by
+ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
+ * xHCI implementations that do not support 64-bit address pointers will ignore
+ * the high dword, and write order is irrelevant.
+ */
+static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
+ __u64 __iomem *regs)
+{
+ __u32 __iomem *ptr = (__u32 __iomem *) regs;
+ u64 val_lo = readl(ptr);
+ u64 val_hi = readl(ptr + 1);
+ return val_lo + (val_hi << 32);
+}
+static inline void xhci_write_64(struct xhci_hcd *xhci,
+ const u64 val, __u64 __iomem *regs)
+{
+ __u32 __iomem *ptr = (__u32 __iomem *) regs;
+ u32 val_lo = lower_32_bits(val);
+ u32 val_hi = upper_32_bits(val);
+
+ xhci_dbg(xhci,
+ "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n",
+ regs, (long unsigned int) val);
+ writel(val_lo, ptr);
+ writel(val_hi, ptr + 1);
+}
+
/* xHCI debugging */
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
void xhci_print_registers(struct xhci_hcd *xhci);
@@ -1090,9 +1148,9 @@ void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep);
+void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
-/* xHCI memory managment */
+/* xHCI memory management */
void xhci_mem_cleanup(struct xhci_hcd *xhci);
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags);
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
@@ -1128,6 +1186,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
+void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
@@ -1148,10 +1207,23 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
+int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
+ unsigned int ep_index);
+void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
+ unsigned int slot_id, unsigned int ep_index,
+ struct xhci_td *cur_td, struct xhci_dequeue_state *state);
+void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
+ struct xhci_ring *ep_ring, unsigned int slot_id,
+ unsigned int ep_index, struct xhci_dequeue_state *deq_state);
/* xHCI roothub code */
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+/* xHCI contexts */
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+
#endif /* __LINUX_XHCI_HCD_H */
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a68d91a11bee..abe3aa67ed00 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -220,7 +220,7 @@ config USB_IOWARRIOR
config USB_TEST
tristate "USB testing driver"
- depends on USB && USB_DEVICEFS
+ depends on USB
help
This driver is for testing host controller software. It is used
with specialized device firmware for regression and stress testing,
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 70073b157f0a..803adcb5ac1d 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -12,6 +12,7 @@ config USB_MUSB_HDRC
depends on !SUPERH
select NOP_USB_XCEIV if ARCH_DAVINCI
select TWL4030_USB if MACH_OMAP_3430SDP
+ select NOP_USB_XCEIV if MACH_OMAP3EVM
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 554a414f65d1..1d26beddf2ca 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1326,7 +1326,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
int i;
/* log core options (read using indexed model) */
- musb_ep_select(mbase, 0);
reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
@@ -1990,7 +1989,7 @@ bad_config:
if (status < 0)
goto fail2;
-#ifdef CONFIG_USB_OTG
+#ifdef CONFIG_USB_MUSB_OTG
setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
#endif
@@ -2168,8 +2167,9 @@ static int __devexit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
-static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+static int musb_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev);
@@ -2196,8 +2196,9 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
return 0;
}
-static int musb_resume_early(struct platform_device *pdev)
+static int musb_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock)
@@ -2215,9 +2216,14 @@ static int musb_resume_early(struct platform_device *pdev)
return 0;
}
+static struct dev_pm_ops musb_dev_pm_ops = {
+ .suspend = musb_suspend,
+ .resume_noirq = musb_resume_noirq,
+};
+
+#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
#else
-#define musb_suspend NULL
-#define musb_resume_early NULL
+#define MUSB_DEV_PM_OPS NULL
#endif
static struct platform_driver musb_driver = {
@@ -2225,11 +2231,10 @@ static struct platform_driver musb_driver = {
.name = (char *)musb_driver_name,
.bus = &platform_bus_type,
.owner = THIS_MODULE,
+ .pm = MUSB_DEV_PM_OPS,
},
.remove = __devexit_p(musb_remove),
.shutdown = musb_shutdown,
- .suspend = musb_suspend,
- .resume_early = musb_resume_early,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 40ed50ecedff..7a6778675ad3 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -407,7 +407,7 @@ stall:
csr |= MUSB_RXCSR_P_SENDSTALL
| MUSB_RXCSR_FLUSHFIFO
| MUSB_RXCSR_CLRDATATOG
- | MUSB_TXCSR_P_WZC_BITS;
+ | MUSB_RXCSR_P_WZC_BITS;
musb_writew(regs, MUSB_RXCSR,
csr);
}
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index de3b2f18db44..fbfd3fd9ce1f 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -323,6 +323,7 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
static inline u8 musb_read_configdata(void __iomem *mbase)
{
+ musb_writeb(mbase, MUSB_INDEX, 0);
return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index e9a40b820fd4..985cbcf48bda 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -80,6 +80,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
+ { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
@@ -96,7 +97,9 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
+ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
index e772b01ac3ac..1fd360e04065 100644
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -57,7 +57,7 @@
#define UART_RI 0x10 /* ring indicator - modem - device to host */
#define UART_CD 0x40 /* carrier detect - modem - device to host */
#define CYP_ERROR 0x08 /* received from input report - device to host */
-/* Note - the below has nothing to to with the "feature report" reset */
+/* Note - the below has nothing to do with the "feature report" reset */
#define CONTROL_RESET 0x08 /* sent with output report - host to device */
/* End of RS-232 protocol definitions */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 60c64cc5be2a..b574878c78b2 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -698,6 +698,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
+ { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index c9fbd7415092..24dbd99e87d7 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -947,6 +947,13 @@
#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
/*
+ * GN Otometrics (http://www.otometrics.com)
+ * Submitted by Ville Sundberg.
+ */
+#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */
+#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 0191693625d6..0b4d32ea1521 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2542,7 +2542,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor)
/*****************************************************************************
* send_cmd_write_uart_register
- * this function builds up a uart register message and sends to to the device.
+ * this function builds up a uart register message and sends to the device.
*****************************************************************************/
static int send_cmd_write_uart_register(struct edgeport_port *edge_port,
__u8 regNum, __u8 regValue)
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 0f44bb8e8d4f..e83346c79fdc 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -38,7 +38,7 @@
* 0.3a - implemented pools of write URBs
* 0.3 - alpha version for public testing
* 0.2 - TIOCMGET works, so autopilot(1) can be used!
- * 0.1 - can be used to to pilot-xfer -p /dev/ttyUSB0 -l
+ * 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l
*
* The driver skeleton is mainly based on mct_u232.c and various other
* pieces of code shamelessly copied from the drivers/usb/serial/ directory.
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c31940a307f8..270009afdf77 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -124,10 +124,13 @@
#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44
#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42
-/* This driver also supports the ATEN UC2324 device since it is mos7840 based
- * - if I knew the device id it would also support the ATEN UC2322 */
+/* This driver also supports
+ * ATEN UC2324 device using Moschip MCS7840
+ * ATEN UC2322 device using Moschip MCS7820
+ */
#define USB_VENDOR_ID_ATENINTL 0x0557
#define ATENINTL_DEVICE_ID_UC2324 0x2011
+#define ATENINTL_DEVICE_ID_UC2322 0x7820
/* Interrupt Routine Defines */
@@ -177,6 +180,7 @@ static struct usb_device_id moschip_port_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
+ {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
};
@@ -186,6 +190,7 @@ static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
+ {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
};
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 98262dd552bb..c784ddbe7b61 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -66,8 +66,10 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file);
static int option_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static int option_send_setup(struct usb_serial_port *port);
+#ifdef CONFIG_PM
static int option_suspend(struct usb_serial *serial, pm_message_t message);
static int option_resume(struct usb_serial *serial);
+#endif
/* Vendor and product IDs */
#define OPTION_VENDOR_ID 0x0AF0
@@ -205,6 +207,7 @@ static int option_resume(struct usb_serial *serial);
#define NOVATELWIRELESS_PRODUCT_MC727 0x4100
#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400
#define NOVATELWIRELESS_PRODUCT_U727 0x5010
+#define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100
#define NOVATELWIRELESS_PRODUCT_MC760 0x6000
#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002
@@ -259,11 +262,6 @@ static int option_resume(struct usb_serial *serial);
#define AXESSTEL_VENDOR_ID 0x1726
#define AXESSTEL_PRODUCT_MV110H 0x1000
-#define ONDA_VENDOR_ID 0x19d2
-#define ONDA_PRODUCT_MSA501HS 0x0001
-#define ONDA_PRODUCT_ET502HS 0x0002
-#define ONDA_PRODUCT_MT503HS 0x2000
-
#define BANDRICH_VENDOR_ID 0x1A8D
#define BANDRICH_PRODUCT_C100_1 0x1002
#define BANDRICH_PRODUCT_C100_2 0x1003
@@ -301,6 +299,7 @@ static int option_resume(struct usb_serial *serial);
#define ZTE_PRODUCT_MF628 0x0015
#define ZTE_PRODUCT_MF626 0x0031
#define ZTE_PRODUCT_CDMA_TECH 0xfffe
+#define ZTE_PRODUCT_AC8710 0xfff1
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
@@ -322,6 +321,11 @@ static int option_resume(struct usb_serial *serial);
#define ALINK_VENDOR_ID 0x1e0e
#define ALINK_PRODUCT_3GU 0x9200
+/* ALCATEL PRODUCTS */
+#define ALCATEL_VENDOR_ID 0x1bbb
+#define ALCATEL_PRODUCT_X060S 0x0000
+
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -438,6 +442,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727_NEW) }, /* Novatel MC727/U727/USB727 refresh */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */
@@ -474,42 +479,6 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0003) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0004) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0005) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0006) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0007) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0008) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0009) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000a) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000b) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000c) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000d) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000e) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x000f) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0010) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0011) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0012) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0013) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0014) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0015) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0016) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0017) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0018) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0019) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0020) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0021) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0022) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0023) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0024) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0025) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0026) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0027) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0028) },
- { USB_DEVICE(ONDA_VENDOR_ID, 0x0029) },
- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) },
{ USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
@@ -534,10 +503,75 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
- { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622) },
- { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
- { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
- { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000b, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000c, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000d, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000e, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0082, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
@@ -547,6 +581,7 @@ static struct usb_device_id option_ids[] = {
{ 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) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -555,8 +590,10 @@ static struct usb_driver option_driver = {
.name = "option",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
+#ifdef CONFIG_PM
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
+#endif
.id_table = option_ids,
.no_dynamic_id = 1,
};
@@ -588,8 +625,10 @@ static struct usb_serial_driver option_1port_device = {
.disconnect = option_disconnect,
.release = option_release,
.read_int_callback = option_instat_callback,
+#ifdef CONFIG_PM
.suspend = option_suspend,
.resume = option_resume,
+#endif
};
static int debug;
@@ -831,7 +870,6 @@ static void option_instat_callback(struct urb *urb)
int status = urb->status;
struct usb_serial_port *port = urb->context;
struct option_port_private *portdata = usb_get_serial_port_data(port);
- struct usb_serial *serial = port->serial;
dbg("%s", __func__);
dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
@@ -927,7 +965,6 @@ static int option_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
struct option_port_private *portdata;
- struct usb_serial *serial = port->serial;
int i, err;
struct urb *urb;
@@ -1187,6 +1224,7 @@ static void option_release(struct usb_serial *serial)
}
}
+#ifdef CONFIG_PM
static int option_suspend(struct usb_serial *serial, pm_message_t message)
{
dbg("%s entered", __func__);
@@ -1245,6 +1283,7 @@ static int option_resume(struct usb_serial *serial)
}
return 0;
}
+#endif
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 7d15bfa7c2db..3e86815b2705 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
+ { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 12aac7d2462d..ee9505e1dd92 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -126,3 +126,7 @@
/* Cressi Edy (diving computer) PC interface */
#define CRESSI_VENDOR_ID 0x04b8
#define CRESSI_EDY_PRODUCT_ID 0x0521
+
+/* Sony, USB data cable for CMD-Jxx mobile phones */
+#define SONY_VENDOR_ID 0x054c
+#define SONY_QN3USB_PRODUCT_ID 0x0437
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index bd7581b3a48a..99188c92068b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -32,6 +32,7 @@
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/uaccess.h>
+#include <linux/serial.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include "pl2303.h"
@@ -184,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
struct usb_serial_port *port;
unsigned int portNumber;
int retval = 0;
+ int first = 0;
dbg("%s", __func__);
@@ -223,7 +225,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
/* If the console is attached, the device is already open */
if (port->port.count == 1 && !port->console) {
-
+ first = 1;
/* lock this module before we call it
* this may fail, which means we must bail out,
* safe because we are called with BKL held */
@@ -246,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
if (retval)
goto bailout_interface_put;
mutex_unlock(&serial->disc_mutex);
+ set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
mutex_unlock(&port->mutex);
/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
- if (retval == 0)
+ if (retval == 0) {
+ if (!first)
+ usb_serial_put(serial);
return 0;
-
+ }
+ mutex_lock(&port->mutex);
+ if (first == 0)
+ goto bailout_mutex_unlock;
+ /* Undo the initial port actions */
+ mutex_lock(&serial->disc_mutex);
bailout_interface_put:
usb_autopm_put_interface(serial->interface);
bailout_module_put:
@@ -340,6 +350,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
dbg("%s - port %d", __func__, port->number);
+ /* FIXME:
+ This leaves a very narrow race. Really we should do the
+ serial_do_free() on tty->shutdown(), but tty->shutdown can
+ be called from IRQ context and serial_do_free can sleep.
+
+ The right fix is probably to make the tty free (which is rare)
+ and thus tty->shutdown() occur via a work queue and simplify all
+ the drivers that use it.
+ */
+ if (tty_hung_up_p(filp)) {
+ /* serial_hangup already called serial_down at this point.
+ Another user may have already reopened the port but
+ serial_do_free is refcounted */
+ serial_do_free(port);
+ return;
+ }
if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
@@ -355,7 +381,8 @@ static void serial_hangup(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
serial_do_down(port);
tty_port_hangup(&port->port);
- serial_do_free(port);
+ /* We must not free port yet - the USB serial layer depends on it's
+ continued existence */
}
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@@ -394,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
dbg("%s = port %d", __func__, port->number);
- WARN_ON(!port->port.count);
/* if the device was unplugged then any remaining characters
fell out of the connector ;) */
if (port->serial->disconnected)
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index fcb320217218..e20dc525d177 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -961,7 +961,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
US_BULK_GET_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
- 0, us->ifnum, us->iobuf, 1, HZ);
+ 0, us->ifnum, us->iobuf, 1, 10*HZ);
US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
result, us->iobuf[0]);
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
index 586d350cdb4d..d6bea3e0b54a 100644
--- a/drivers/usb/wusbcore/wa-hc.h
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -47,7 +47,7 @@
* to an endpoint on a WUSB device that is connected to a
* HWA RC.
*
- * xfer Transfer managment -- this is all the code that gets a
+ * xfer Transfer management -- this is all the code that gets a
* buffer and pushes it to a device (or viceversa). *
*
* Some day a lot of this code will be shared between this driver and
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3b54b3940178..49f2c4bdf904 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -935,7 +935,7 @@ config FB_S1D13XXX
config FB_ATMEL
tristate "AT91/AT32 LCD Controller support"
- depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32)
+ depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9G10 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -951,7 +951,7 @@ config FB_INTSRAM
config FB_ATMEL_STN
bool "Use a STN display with AT91/AT32 LCD Controller"
- depends on FB_ATMEL && MACH_AT91SAM9261EK
+ depends on FB_ATMEL && (MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK)
default n
help
Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
@@ -1867,7 +1867,7 @@ config FB_W100
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
- depends on FB && SUPERH
+ depends on FB && SUPERH && HAVE_CLK
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index da05f0801bb7..2830ffd72976 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -182,7 +182,8 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
{
unsigned long value;
- if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+ || cpu_is_at32ap7000()))
return xres;
value = xres;
@@ -824,7 +825,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
info->fix = atmel_lcdfb_fix;
/* Enable LCDC Clocks */
- if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+ if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+ || cpu_is_at32ap7000()) {
sinfo->bus_clk = clk_get(dev, "hck1");
if (IS_ERR(sinfo->bus_clk)) {
ret = PTR_ERR(sinfo->bus_clk);
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index f9d19be05540..90861cd93165 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -110,7 +110,7 @@ config BACKLIGHT_CLASS_DEVICE
config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control"
depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
- default y if MACH_SAM9261EK || MACH_SAM9263EK
+ default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
help
This provides a backlight control internal to the Atmel LCDC
driver. If the LCD "contrast control" on your board is wired
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index 93bb4340cc64..701a1081e199 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -154,34 +154,38 @@ static int da903x_backlight_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int da903x_backlight_suspend(struct platform_device *pdev,
- pm_message_t state)
+static int da903x_backlight_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct backlight_device *bl = platform_get_drvdata(pdev);
return da903x_backlight_set(bl, 0);
}
-static int da903x_backlight_resume(struct platform_device *pdev)
+static int da903x_backlight_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct backlight_device *bl = platform_get_drvdata(pdev);
backlight_update_status(bl);
return 0;
}
-#else
-#define da903x_backlight_suspend NULL
-#define da903x_backlight_resume NULL
+
+static struct dev_pm_ops da903x_backlight_pm_ops = {
+ .suspend = da903x_backlight_suspend,
+ .resume = da903x_backlight_resume,
+};
#endif
static struct platform_driver da903x_backlight_driver = {
.driver = {
.name = "da903x-backlight",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &da903x_backlight_pm_ops,
+#endif
},
.probe = da903x_backlight_probe,
.remove = da903x_backlight_remove,
- .suspend = da903x_backlight_suspend,
- .resume = da903x_backlight_resume,
};
static int __init da903x_backlight_init(void)
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index c3ebb6b41ce1..7aed2565c1bd 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -72,7 +72,7 @@ static int jornada_bl_update_status(struct backlight_device *bd)
if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
printk(KERN_INFO "bl : failed to set brightness\n");
ret = -ETIMEDOUT;
- goto out
+ goto out;
}
/* at this point we expect that the mcu has accepted
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index 2486237ebba5..417ae5efa8bb 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -124,12 +124,12 @@ struct platform_driver h3_panel_driver = {
},
};
-static int h3_panel_drv_init(void)
+static int __init h3_panel_drv_init(void)
{
return platform_driver_register(&h3_panel_driver);
}
-static void h3_panel_drv_cleanup(void)
+static void __exit h3_panel_drv_cleanup(void)
{
platform_driver_unregister(&h3_panel_driver);
}
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
index 6ff56430341b..0c398bda7601 100644
--- a/drivers/video/omap/lcd_h4.c
+++ b/drivers/video/omap/lcd_h4.c
@@ -102,12 +102,12 @@ static struct platform_driver h4_panel_driver = {
},
};
-static int h4_panel_drv_init(void)
+static int __init h4_panel_drv_init(void)
{
return platform_driver_register(&h4_panel_driver);
}
-static void h4_panel_drv_cleanup(void)
+static void __exit h4_panel_drv_cleanup(void)
{
platform_driver_unregister(&h4_panel_driver);
}
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
index 6953ed4b5820..cdbd8bb607be 100644
--- a/drivers/video/omap/lcd_inn1510.c
+++ b/drivers/video/omap/lcd_inn1510.c
@@ -109,12 +109,12 @@ struct platform_driver innovator1510_panel_driver = {
},
};
-static int innovator1510_panel_drv_init(void)
+static int __init innovator1510_panel_drv_init(void)
{
return platform_driver_register(&innovator1510_panel_driver);
}
-static void innovator1510_panel_drv_cleanup(void)
+static void __exit innovator1510_panel_drv_cleanup(void)
{
platform_driver_unregister(&innovator1510_panel_driver);
}
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 4c4f7ee6d733..268f7f808a4e 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -133,12 +133,12 @@ struct platform_driver innovator1610_panel_driver = {
},
};
-static int innovator1610_panel_drv_init(void)
+static int __init innovator1610_panel_drv_init(void)
{
return platform_driver_register(&innovator1610_panel_driver);
}
-static void innovator1610_panel_drv_cleanup(void)
+static void __exit innovator1610_panel_drv_cleanup(void)
{
platform_driver_unregister(&innovator1610_panel_driver);
}
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index 379c96d36da5..b3fa88bc6269 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -127,12 +127,12 @@ struct platform_driver osk_panel_driver = {
},
};
-static int osk_panel_drv_init(void)
+static int __init osk_panel_drv_init(void)
{
return platform_driver_register(&osk_panel_driver);
}
-static void osk_panel_drv_cleanup(void)
+static void __exit osk_panel_drv_cleanup(void)
{
platform_driver_unregister(&osk_panel_driver);
}
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
index 218317366e6e..4bf3c79f3cc7 100644
--- a/drivers/video/omap/lcd_palmte.c
+++ b/drivers/video/omap/lcd_palmte.c
@@ -108,12 +108,12 @@ struct platform_driver palmte_panel_driver = {
},
};
-static int palmte_panel_drv_init(void)
+static int __init palmte_panel_drv_init(void)
{
return platform_driver_register(&palmte_panel_driver);
}
-static void palmte_panel_drv_cleanup(void)
+static void __exit palmte_panel_drv_cleanup(void)
{
platform_driver_unregister(&palmte_panel_driver);
}
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
index 57b0f6cf6a5a..48ea1f9f2cbf 100644
--- a/drivers/video/omap/lcd_palmtt.c
+++ b/drivers/video/omap/lcd_palmtt.c
@@ -113,12 +113,12 @@ struct platform_driver palmtt_panel_driver = {
},
};
-static int palmtt_panel_drv_init(void)
+static int __init palmtt_panel_drv_init(void)
{
return platform_driver_register(&palmtt_panel_driver);
}
-static void palmtt_panel_drv_cleanup(void)
+static void __exit palmtt_panel_drv_cleanup(void)
{
platform_driver_unregister(&palmtt_panel_driver);
}
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
index d33d78b11723..0697d29b4d3b 100644
--- a/drivers/video/omap/lcd_palmz71.c
+++ b/drivers/video/omap/lcd_palmz71.c
@@ -109,12 +109,12 @@ struct platform_driver palmz71_panel_driver = {
},
};
-static int palmz71_panel_drv_init(void)
+static int __init palmz71_panel_drv_init(void)
{
return platform_driver_register(&palmz71_panel_driver);
}
-static void palmz71_panel_drv_cleanup(void)
+static void __exit palmz71_panel_drv_cleanup(void)
{
platform_driver_unregister(&palmz71_panel_driver);
}
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 6506117c134b..3a002a634ecf 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1638,24 +1638,26 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
* Power management hooks. Note that we won't be called from IRQ context,
* unlike the blank functions above, so we may sleep.
*/
-static int pxafb_suspend(struct platform_device *dev, pm_message_t state)
+static int pxafb_suspend(struct device *dev)
{
- struct pxafb_info *fbi = platform_get_drvdata(dev);
+ struct pxafb_info *fbi = dev_get_drvdata(dev);
set_ctrlr_state(fbi, C_DISABLE_PM);
return 0;
}
-static int pxafb_resume(struct platform_device *dev)
+static int pxafb_resume(struct device *dev)
{
- struct pxafb_info *fbi = platform_get_drvdata(dev);
+ struct pxafb_info *fbi = dev_get_drvdata(dev);
set_ctrlr_state(fbi, C_ENABLE_PM);
return 0;
}
-#else
-#define pxafb_suspend NULL
-#define pxafb_resume NULL
+
+static struct dev_pm_ops pxafb_pm_ops = {
+ .suspend = pxafb_suspend,
+ .resume = pxafb_resume,
+};
#endif
static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi)
@@ -2091,14 +2093,14 @@ static int __devinit pxafb_probe(struct platform_device *dev)
goto failed_fbi;
}
- r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
+ r = request_mem_region(r->start, resource_size(r), dev->name);
if (r == NULL) {
dev_err(&dev->dev, "failed to request I/O memory\n");
ret = -EBUSY;
goto failed_fbi;
}
- fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ fbi->mmio_base = ioremap(r->start, resource_size(r));
if (fbi->mmio_base == NULL) {
dev_err(&dev->dev, "failed to map I/O memory\n");
ret = -EBUSY;
@@ -2197,7 +2199,7 @@ failed_free_dma:
failed_free_io:
iounmap(fbi->mmio_base);
failed_free_res:
- release_mem_region(r->start, r->end - r->start + 1);
+ release_mem_region(r->start, resource_size(r));
failed_fbi:
clk_put(fbi->clk);
platform_set_drvdata(dev, NULL);
@@ -2237,7 +2239,7 @@ static int __devexit pxafb_remove(struct platform_device *dev)
iounmap(fbi->mmio_base);
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, r->end - r->start + 1);
+ release_mem_region(r->start, resource_size(r));
clk_put(fbi->clk);
kfree(fbi);
@@ -2248,11 +2250,12 @@ static int __devexit pxafb_remove(struct platform_device *dev)
static struct platform_driver pxafb_driver = {
.probe = pxafb_probe,
.remove = __devexit_p(pxafb_remove),
- .suspend = pxafb_suspend,
- .resume = pxafb_resume,
.driver = {
.owner = THIS_MODULE,
.name = "pxa2xx-fb",
+#ifdef CONFIG_PM
+ .pm = &pxafb_pm_ops,
+#endif
},
};
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index bb63c07e13de..5a72083dc67c 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -964,7 +964,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
int win;
- for (win = 0; win <= S3C_FB_MAX_WIN; win++)
+ for (win = 0; win < S3C_FB_MAX_WIN; win++)
if (sfb->windows[win])
s3c_fb_release_win(sfb, sfb->windows[win]);
@@ -988,7 +988,7 @@ static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
struct s3c_fb_win *win;
int win_no;
- for (win_no = S3C_FB_MAX_WIN; win_no >= 0; win_no--) {
+ for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
win = sfb->windows[win_no];
if (!win)
continue;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 8f24564f77b0..98fb82f11611 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -42,11 +42,9 @@ struct sh_mobile_lcdc_chan {
struct sh_mobile_lcdc_priv {
void __iomem *base;
int irq;
-#ifdef CONFIG_HAVE_CLK
atomic_t clk_usecnt;
struct clk *dot_clk;
struct clk *clk;
-#endif
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
int started;
@@ -185,7 +183,6 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
lcdc_sys_read_data,
};
-#ifdef CONFIG_HAVE_CLK
static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_inc_and_test(&priv->clk_usecnt)) {
@@ -203,10 +200,6 @@ static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
clk_disable(priv->clk);
}
}
-#else
-static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
-static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
-#endif
static int sh_mobile_lcdc_sginit(struct fb_info *info,
struct list_head *pagelist)
@@ -515,7 +508,6 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
board_cfg = &ch->cfg.board_cfg;
if (board_cfg->display_off)
board_cfg->display_off(board_cfg->board_data);
-
}
/* stop the lcdc */
@@ -574,9 +566,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
int clock_source,
struct sh_mobile_lcdc_priv *priv)
{
-#ifdef CONFIG_HAVE_CLK
char clk_name[8];
-#endif
char *str;
int icksel;
@@ -590,7 +580,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
priv->lddckr = icksel << 16;
-#ifdef CONFIG_HAVE_CLK
atomic_set(&priv->clk_usecnt, -1);
snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id);
priv->clk = clk_get(&pdev->dev, clk_name);
@@ -598,7 +587,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
return PTR_ERR(priv->clk);
}
-
+
if (str) {
priv->dot_clk = clk_get(&pdev->dev, str);
if (IS_ERR(priv->dot_clk)) {
@@ -607,7 +596,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
return PTR_ERR(priv->dot_clk);
}
}
-#endif
return 0;
}
@@ -942,11 +930,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
framebuffer_release(info);
}
-#ifdef CONFIG_HAVE_CLK
if (priv->dot_clk)
clk_put(priv->dot_clk);
clk_put(priv->clk);
-#endif
if (priv->base)
iounmap(priv->base);
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index ca5b4643a401..e98baf6916b8 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock);
* find the kernel part of the task struct, copy the registers and
* the buffer contents and then complete the task.
*/
-static void uvesafb_cn_callback(void *data)
+static void uvesafb_cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct uvesafb_task *utask;
struct uvesafb_ktask *task;
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index bcec78ffc765..50d78f68a52f 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -52,8 +52,10 @@ struct virtio_pci_device
char (*msix_names)[256];
/* Number of available vectors */
unsigned msix_vectors;
- /* Vectors allocated */
+ /* Vectors allocated, excluding per-vq vectors if any */
unsigned msix_used_vectors;
+ /* Whether we have vector per vq */
+ bool per_vq_vectors;
};
/* Constants for MSI-X */
@@ -258,7 +260,6 @@ static void vp_free_vectors(struct virtio_device *vdev)
for (i = 0; i < vp_dev->msix_used_vectors; ++i)
free_irq(vp_dev->msix_entries[i].vector, vp_dev);
- vp_dev->msix_used_vectors = 0;
if (vp_dev->msix_enabled) {
/* Disable the vector used for configuration */
@@ -267,80 +268,67 @@ static void vp_free_vectors(struct virtio_device *vdev)
/* Flush the write out to device */
ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- vp_dev->msix_enabled = 0;
pci_disable_msix(vp_dev->pci_dev);
+ vp_dev->msix_enabled = 0;
+ vp_dev->msix_vectors = 0;
}
-}
-static int vp_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
- int *options, int noptions)
-{
- int i;
- for (i = 0; i < noptions; ++i)
- if (!pci_enable_msix(dev, entries, options[i]))
- return options[i];
- return -EBUSY;
+ vp_dev->msix_used_vectors = 0;
+ kfree(vp_dev->msix_names);
+ vp_dev->msix_names = NULL;
+ kfree(vp_dev->msix_entries);
+ vp_dev->msix_entries = NULL;
}
-static int vp_request_vectors(struct virtio_device *vdev, unsigned max_vqs)
+static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
+ bool per_vq_vectors)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
const char *name = dev_name(&vp_dev->vdev.dev);
unsigned i, v;
int err = -ENOMEM;
- /* We want at most one vector per queue and one for config changes.
- * Fallback to separate vectors for config and a shared for queues.
- * Finally fall back to regular interrupts. */
- int options[] = { max_vqs + 1, 2 };
- int nvectors = max(options[0], options[1]);
vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
GFP_KERNEL);
if (!vp_dev->msix_entries)
- goto error_entries;
+ goto error;
vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
GFP_KERNEL);
if (!vp_dev->msix_names)
- goto error_names;
+ goto error;
for (i = 0; i < nvectors; ++i)
vp_dev->msix_entries[i].entry = i;
- err = vp_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries,
- options, ARRAY_SIZE(options));
- if (err < 0) {
- /* Can't allocate enough MSI-X vectors, use regular interrupt */
- vp_dev->msix_vectors = 0;
- err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
- IRQF_SHARED, name, vp_dev);
- if (err)
- goto error_irq;
- vp_dev->intx_enabled = 1;
- } else {
- vp_dev->msix_vectors = err;
- vp_dev->msix_enabled = 1;
-
- /* Set the vector used for configuration */
- v = vp_dev->msix_used_vectors;
- snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
- "%s-config", name);
- err = request_irq(vp_dev->msix_entries[v].vector,
- vp_config_changed, 0, vp_dev->msix_names[v],
- vp_dev);
- if (err)
- goto error_irq;
- ++vp_dev->msix_used_vectors;
-
- iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- /* Verify we had enough resources to assign the vector */
- v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- if (v == VIRTIO_MSI_NO_VECTOR) {
- err = -EBUSY;
- goto error_irq;
- }
+ /* pci_enable_msix returns positive if we can't get this many. */
+ err = pci_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries, nvectors);
+ if (err > 0)
+ err = -ENOSPC;
+ if (err)
+ goto error;
+ vp_dev->msix_vectors = nvectors;
+ vp_dev->msix_enabled = 1;
+
+ /* Set the vector used for configuration */
+ v = vp_dev->msix_used_vectors;
+ snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+ "%s-config", name);
+ err = request_irq(vp_dev->msix_entries[v].vector,
+ vp_config_changed, 0, vp_dev->msix_names[v],
+ vp_dev);
+ if (err)
+ goto error;
+ ++vp_dev->msix_used_vectors;
+
+ iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+ /* Verify we had enough resources to assign the vector */
+ v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+ if (v == VIRTIO_MSI_NO_VECTOR) {
+ err = -EBUSY;
+ goto error;
}
- if (vp_dev->msix_vectors && vp_dev->msix_vectors != max_vqs + 1) {
+ if (!per_vq_vectors) {
/* Shared vector for all VQs */
v = vp_dev->msix_used_vectors;
snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
@@ -349,28 +337,25 @@ static int vp_request_vectors(struct virtio_device *vdev, unsigned max_vqs)
vp_vring_interrupt, 0, vp_dev->msix_names[v],
vp_dev);
if (err)
- goto error_irq;
+ goto error;
++vp_dev->msix_used_vectors;
}
return 0;
-error_irq:
+error:
vp_free_vectors(vdev);
- kfree(vp_dev->msix_names);
-error_names:
- kfree(vp_dev->msix_entries);
-error_entries:
return err;
}
-static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
- void (*callback)(struct virtqueue *vq),
- const char *name)
+static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name,
+ u16 vector)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtio_pci_vq_info *info;
struct virtqueue *vq;
unsigned long flags, size;
- u16 num, vector;
+ u16 num;
int err;
/* Select the queue we're interested in */
@@ -389,7 +374,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
info->queue_index = index;
info->num = num;
- info->vector = VIRTIO_MSI_NO_VECTOR;
+ info->vector = vector;
size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
@@ -413,22 +398,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
vq->priv = info;
info->vq = vq;
- /* allocate per-vq vector if available and necessary */
- if (callback && vp_dev->msix_used_vectors < vp_dev->msix_vectors) {
- vector = vp_dev->msix_used_vectors;
- snprintf(vp_dev->msix_names[vector], sizeof *vp_dev->msix_names,
- "%s-%s", dev_name(&vp_dev->vdev.dev), name);
- err = request_irq(vp_dev->msix_entries[vector].vector,
- vring_interrupt, 0,
- vp_dev->msix_names[vector], vq);
- if (err)
- goto out_request_irq;
- info->vector = vector;
- ++vp_dev->msix_used_vectors;
- } else
- vector = VP_MSIX_VQ_VECTOR;
-
- if (callback && vp_dev->msix_enabled) {
+ if (vector != VIRTIO_MSI_NO_VECTOR) {
iowrite16(vector, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
vector = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
if (vector == VIRTIO_MSI_NO_VECTOR) {
@@ -444,11 +414,6 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
return vq;
out_assign:
- if (info->vector != VIRTIO_MSI_NO_VECTOR) {
- free_irq(vp_dev->msix_entries[info->vector].vector, vq);
- --vp_dev->msix_used_vectors;
- }
-out_request_irq:
vring_del_virtqueue(vq);
out_activate_queue:
iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
@@ -462,12 +427,13 @@ static void vp_del_vq(struct virtqueue *vq)
{
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
struct virtio_pci_vq_info *info = vq->priv;
- unsigned long size;
+ unsigned long flags, size;
- iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+ spin_lock_irqsave(&vp_dev->lock, flags);
+ list_del(&info->node);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
- if (info->vector != VIRTIO_MSI_NO_VECTOR)
- free_irq(vp_dev->msix_entries[info->vector].vector, vq);
+ iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
if (vp_dev->msix_enabled) {
iowrite16(VIRTIO_MSI_NO_VECTOR,
@@ -489,36 +455,86 @@ static void vp_del_vq(struct virtqueue *vq)
/* the config->del_vqs() implementation */
static void vp_del_vqs(struct virtio_device *vdev)
{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtqueue *vq, *n;
+ struct virtio_pci_vq_info *info;
- list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+ list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+ info = vq->priv;
+ if (vp_dev->per_vq_vectors)
+ free_irq(vp_dev->msix_entries[info->vector].vector, vq);
vp_del_vq(vq);
+ }
+ vp_dev->per_vq_vectors = false;
vp_free_vectors(vdev);
}
-/* the config->find_vqs() implementation */
-static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char *names[])
+static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[],
+ bool use_msix,
+ bool per_vq_vectors)
{
- int vectors = 0;
- int i, err;
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ u16 vector;
+ int i, err, nvectors, allocated_vectors;
+
+ if (!use_msix) {
+ /* Old style: one normal interrupt for change and all vqs. */
+ vp_dev->msix_vectors = 0;
+ vp_dev->per_vq_vectors = false;
+ err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
+ IRQF_SHARED, dev_name(&vdev->dev), vp_dev);
+ if (!err)
+ vp_dev->intx_enabled = 1;
+ return err;
+ }
- /* How many vectors would we like? */
- for (i = 0; i < nvqs; ++i)
- if (callbacks[i])
- ++vectors;
+ if (per_vq_vectors) {
+ /* Best option: one for change interrupt, one per vq. */
+ nvectors = 1;
+ for (i = 0; i < nvqs; ++i)
+ if (callbacks[i])
+ ++nvectors;
+ } else {
+ /* Second best: one for change, shared one for all vqs. */
+ nvectors = 2;
+ }
- err = vp_request_vectors(vdev, vectors);
+ err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors);
if (err)
goto error_request;
+ vp_dev->per_vq_vectors = per_vq_vectors;
+ allocated_vectors = vp_dev->msix_used_vectors;
for (i = 0; i < nvqs; ++i) {
- vqs[i] = vp_find_vq(vdev, i, callbacks[i], names[i]);
- if (IS_ERR(vqs[i]))
+ if (!callbacks[i] || !vp_dev->msix_enabled)
+ vector = VIRTIO_MSI_NO_VECTOR;
+ else if (vp_dev->per_vq_vectors)
+ vector = allocated_vectors++;
+ else
+ vector = VP_MSIX_VQ_VECTOR;
+ vqs[i] = setup_vq(vdev, i, callbacks[i], names[i], vector);
+ if (IS_ERR(vqs[i])) {
+ err = PTR_ERR(vqs[i]);
goto error_find;
+ }
+ /* allocate per-vq irq if available and necessary */
+ if (vp_dev->per_vq_vectors && vector != VIRTIO_MSI_NO_VECTOR) {
+ snprintf(vp_dev->msix_names[vector],
+ sizeof *vp_dev->msix_names,
+ "%s-%s",
+ dev_name(&vp_dev->vdev.dev), names[i]);
+ err = request_irq(vp_dev->msix_entries[vector].vector,
+ vring_interrupt, 0,
+ vp_dev->msix_names[vector], vqs[i]);
+ if (err) {
+ vp_del_vq(vqs[i]);
+ goto error_find;
+ }
+ }
}
return 0;
@@ -526,7 +542,29 @@ error_find:
vp_del_vqs(vdev);
error_request:
- return PTR_ERR(vqs[i]);
+ return err;
+}
+
+/* the config->find_vqs() implementation */
+static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[])
+{
+ int err;
+
+ /* Try MSI-X with one vector per queue. */
+ err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, true, true);
+ if (!err)
+ return 0;
+ /* Fallback: MSI-X with one vector for config, one shared for queues. */
+ err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
+ true, false);
+ if (!err)
+ return 0;
+ /* Finally fall back to regular interrupts. */
+ return vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
+ false, false);
}
static struct virtio_config_ops virtio_pci_config_ops = {
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index fdf72851c574..52ccb3d3a963 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -306,9 +306,8 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
return error;
}
-static void w1_cn_callback(void *data)
+static void w1_cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
struct w1_netlink_cmd *cmd;
struct w1_slave *sl;
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index fecb307d28e9..aec7cefdef21 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -18,6 +18,7 @@
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#define DRV_NAME "WDOG COH 901 327"
@@ -92,6 +93,8 @@ static struct clk *clk;
static void coh901327_enable(u16 timeout)
{
u16 val;
+ unsigned long freq;
+ unsigned long delay_ns;
clk_enable(clk);
/* Restart timer if it is disabled */
@@ -102,6 +105,14 @@ static void coh901327_enable(u16 timeout)
/* Acknowledge any pending interrupt so it doesn't just fire off */
writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
virtbase + U300_WDOG_IER);
+ /*
+ * The interrupt is cleared in the 32 kHz clock domain.
+ * Wait 3 32 kHz cycles for it to take effect
+ */
+ freq = clk_get_rate(clk);
+ delay_ns = (1000000000 + freq - 1) / freq; /* Freq to ns and round up */
+ delay_ns = 3 * delay_ns; /* Wait 3 cycles */
+ ndelay(delay_ns);
/* Enable the watchdog interrupt */
writew(U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE, virtbase + U300_WDOG_IMR);
/* Activate the watchdog timer */
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index abad71b1632b..2f57276e87a2 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -47,10 +47,10 @@
static DEFINE_SPINLOCK(irq_mapping_update_lock);
/* IRQ <-> VIRQ mapping. */
-static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1};
/* IRQ <-> IPI mapping */
-static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1};
/* Interrupt types. */
enum xen_irq_type {
@@ -602,6 +602,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static DEFINE_PER_CPU(unsigned, xed_nesting_count);
+
/*
* Search the CPUs pending events bitmasks. For each one found, map
* the event number to an irq, and feed it into do_IRQ() for
@@ -617,7 +619,6 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
struct pt_regs *old_regs = set_irq_regs(regs);
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
- static DEFINE_PER_CPU(unsigned, nesting_count);
unsigned count;
exit_idle();
@@ -628,7 +629,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
vcpu_info->evtchn_upcall_pending = 0;
- if (__get_cpu_var(nesting_count)++)
+ if (__get_cpu_var(xed_nesting_count)++)
goto out;
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
@@ -653,8 +654,8 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
BUG_ON(!irqs_disabled());
- count = __get_cpu_var(nesting_count);
- __get_cpu_var(nesting_count) = 0;
+ count = __get_cpu_var(xed_nesting_count);
+ __get_cpu_var(xed_nesting_count) = 0;
} while(count != 1);
out:
diff --git a/firmware/Makefile b/firmware/Makefile
index 621de8e952f7..44313b25580f 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -41,7 +41,10 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
cxgb3/t3c_psram-1.1.0.bin \
- cxgb3/t3fw-7.4.0.bin
+ cxgb3/t3fw-7.4.0.bin \
+ cxgb3/ael2005_opt_edc.bin \
+ cxgb3/ael2005_twx_edc.bin \
+ cxgb3/ael2020_twx_edc.bin
fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin
fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
diff --git a/firmware/WHENCE b/firmware/WHENCE
index 0f5649a08c0c..d9e3a94cb4df 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -418,6 +418,23 @@ License: GPLv2 or OpenIB.org BSD license, no source visible
--------------------------------------------------------------------------
+Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter
+
+File: cxgb3/ael2005_opt_edc.bin.ihex
+File: cxgb3/ael2005_twx_edc.bin.ihex
+File: cxgb3/ael2020_twx_edc.bin.ihex
+
+Licence:
+ * Copyright (c) 2007-2009 NetLogic Microsystems, Inc.
+ *
+ * Permission is hereby granted for the distribution of this firmware
+ * data in hexadecimal or equivalent format, provided this copyright
+ * notice is accompanying it.
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
+
Driver: e100 -- Intel PRO/100 Ethernet NIC
File: e100/d101m_ucode.bin
diff --git a/firmware/cxgb3/ael2005_opt_edc.bin.ihex b/firmware/cxgb3/ael2005_opt_edc.bin.ihex
new file mode 100644
index 000000000000..c1d6e5d3bea7
--- /dev/null
+++ b/firmware/cxgb3/ael2005_opt_edc.bin.ihex
@@ -0,0 +1,69 @@
+:10000000CC002FF4CC013CD4CC022015CC0331051C
+:10001000CC046524CC0527FFCC06300FCC072C8BF5
+:10002000CC08300BCC094009CC0A400ECC0B2F7207
+:10003000CC0C3002CC0D1002CC0E2172CC0F301241
+:10004000CC101002CC1125D2CC123012CC131002DD
+:10005000CC14D01ECC1527D2CC163012CC171002DF
+:10006000CC182004CC193C84CC1A6436CC1B200755
+:10007000CC1C3F87CC1D8676CC1E40B7CC1FA74634
+:10008000CC204047CC215673CC222982CC2330028D
+:10009000CC2413D2CC258BBDCC262862CC273012A1
+:1000A000CC281002CC292092CC2A3012CC2B100262
+:1000B000CC2C5CC3CC2D0314CC2E2942CC2F300287
+:1000C000CC301002CC31D019CC322032CC333012AB
+:1000D000CC341002CC352A04CC363C74CC37643591
+:1000E000CC382FA4CC393CD4CC3A6624CC3B5563D5
+:1000F000CC3C2D42CC3D3002CC3E13D2CC3F464DC1
+:10010000CC402862CC413012CC421002CC43203289
+:10011000CC443012CC451002CC462FB4CC473CD452
+:10012000CC486624CC495563CC4A2D42CC4B300296
+:10013000CC4C13D2CC4D2ED2CC4E3002CC4F100230
+:10014000CC502FD2CC513002CC521002CC530004F0
+:10015000CC542942CC553002CC561002CC572092B8
+:10016000CC583012CC591002CC5A5CC3CC5B03176C
+:10017000CC5C2F72CC5D3002CC5E1002CC5F294289
+:10018000CC603002CC611002CC6222CDCC63301D39
+:10019000CC642862CC653012CC661002CC672ED2BB
+:1001A000CC683002CC691002CC6A2D72CC6B300264
+:1001B000CC6C1002CC6D628FCC6E2112CC6F3012E1
+:1001C000CC701002CC715AA3CC722DC2CC73300209
+:1001D000CC741312CC756F72CC761002CC772807D2
+:1001E000CC7831A7CC7920C4CC7A3C24CC7B672452
+:1001F000CC7C1002CC7D2807CC7E3187CC7F20C4FC
+:10020000CC803C24CC816724CC821002CC83251482
+:10021000CC843C64CC856436CC86DFF4CC876436F1
+:10022000CC881002CC8940A4CC8A643CCC8B40168C
+:10023000CC8C8C6CCC8D2B24CC8E3C24CC8F643518
+:10024000CC901002CC912B24CC923C24CC93643AD9
+:10025000CC944025CC958A5ACC961002CC97273165
+:10026000CC983011CC991001CC9AC7A0CC9B01003E
+:10027000CC9CC502CC9D53ACCC9EC503CC9FD5D5A0
+:10028000CCA0C600CCA12A6DCCA2C601CCA32A4C1E
+:10029000CCA4C602CCA50111CCA6C60CCCA7590093
+:1002A000CCA8C710CCA90700CCAAC718CCAB0700B4
+:1002B000CCACC720CCAD4700CCAEC801CCAF7F5092
+:1002C000CCB0C802CCB17760CCB2C803CCB37FCE7F
+:1002D000CCB4C804CCB55700CCB6C805CCB75F11B8
+:1002E000CCB8C806CCB94751CCBAC807CCBB57E18B
+:1002F000CCBCC808CCBD2700CCBEC809CCBF000010
+:10030000CCC0C821CCC10002CCC2C822CCC30014CE
+:10031000CCC4C832CCC51186CCC6C847CCC71E02D7
+:10032000CCC8C013CCC9F341CCCAC01ACCCB04464C
+:10033000CCCCC024CCCD1000CCCEC025CCCF0A0074
+:10034000CCD0C026CCD10C0CCCD2C027CCD30C0C3A
+:10035000CCD4C029CCD500A0CCD6C030CCD70A0094
+:10036000CCD8C03CCCD9001CCCDAC005CCDB7A069A
+:10037000CCDC0000CCDD2731CCDE3011CCDF10012D
+:10038000CCE0C620CCE10000CCE2C621CCE3003FAB
+:10039000CCE4C622CCE50000CCE6C623CCE70000C6
+:1003A000CCE8C624CCE90000CCEAC625CCEB0000A2
+:1003B000CCECC627CCED0000CCEEC628CCEF00007C
+:1003C000CCF0C62CCCF10000CCF20000CCF3280617
+:1003D000CCF43CB6CCF5C161CCF66134CCF76135D8
+:1003E000CCF85443CCF90303CCFA6524CCFB000BC6
+:1003F000CCFC1002CCFD2104CCFE3C24CCFF21051A
+:10040000CD003805CD016524CD02DFF4CD034005D4
+:10041000CD046524CD051002CD065DD3CD070306BE
+:10042000CD082FF7CD0938F7CD0A60B7CD0BDFFD2A
+:10043000CD0C000ACD0D1002CD0E00007CC7AE59C8
+:00000001FF
diff --git a/firmware/cxgb3/ael2005_twx_edc.bin.ihex b/firmware/cxgb3/ael2005_twx_edc.bin.ihex
new file mode 100644
index 000000000000..9b5e9e51fcb7
--- /dev/null
+++ b/firmware/cxgb3/ael2005_twx_edc.bin.ihex
@@ -0,0 +1,93 @@
+:10000000CC004009CC0127FFCC02300FCC0340AA22
+:10001000CC04401CCC05401ECC062FF4CC073CD4AD
+:10002000CC082035CC093145CC0A6524CC0B26A25E
+:10003000CC0C3012CC0D1002CC0E29C2CC0F3002E9
+:10004000CC101002CC112072CC123012CC13100242
+:10005000CC1422CDCC15301DCC162E52CC1730121C
+:10006000CC181002CC1928E2CC1A3002CC1B10029A
+:10007000CC1C628FCC1D2AC2CC1E3012CC1F1002A9
+:10008000CC205553CC212AE2CC223002CC231302BF
+:10009000CC24401ECC252BE2CC263012CC271002DB
+:1000A000CC282DA2CC293012CC2A1002CC2B2BA28A
+:1000B000CC2C3002CC2D1002CC2E5EE3CC2F0305CD
+:1000C000CC30400ECC312BC2CC323002CC331002BB
+:1000D000CC342B82CC353012CC361002CC37566360
+:1000E000CC380302CC39401ECC3A6F72CC3B1002A4
+:1000F000CC3C628FCC3D2BE2CC3E3012CC3F100288
+:10010000CC4022CDCC41301DCC422E52CC433012BB
+:10011000CC441002CC452522CC463012CC471002EC
+:10012000CC482DA2CC493012CC4A1002CC4B2CA288
+:10013000CC4C3012CC4D1002CC4E2FA4CC4F3CD422
+:10014000CC506624CC51410BCC5256B3CC5303C493
+:10015000CC542FB2CC553002CC561002CC57220BC7
+:10016000CC58303BCC5956B3CC5A03C3CC5B866BCE
+:10017000CC5C400CCC5D23A2CC5E3012CC5F100274
+:10018000CC602DA2CC613012CC621002CC632CA2C8
+:10019000CC643012CC651002CC662FB4CC673CD452
+:1001A000CC686624CC6956B3CC6A03C3CC6B866B2F
+:1001B000CC6C401CCC6D2205CC6E3035CC6F5B53C3
+:1001C000CC702C52CC713002CC7213C2CC735CC395
+:1001D000CC740317CC752522CC763012CC77100264
+:1001E000CC782DA2CC793012CC7A1002CC7B2B8229
+:1001F000CC7C3012CC7D1002CC7E5663CC7F0303C6
+:10020000CC80401ECC810004CC822C42CC833012A6
+:10021000CC841002CC856F72CC861002CC87628FA2
+:10022000CC882304CC893C84CC8A6436CC8BDFF424
+:10023000CC8C6436CC8D2FF5CC8E3005CC8F865689
+:10024000CC90DFBACC9156A3CC92D05ACC9321C299
+:10025000CC943012CC951392CC96D05ACC9756A30E
+:10026000CC98DFBACC990383CC9A6F72CC9B1002E6
+:10027000CC9C28C5CC9D3005CC9E4178CC9F565354
+:10028000CCA00384CCA122B2CCA23012CCA3100209
+:10029000CCA42BE5CCA53005CCA641E8CCA7565381
+:1002A000CCA80382CCA90002CCAA4258CCAB2474BF
+:1002B000CCAC3C84CCAD6437CCAEDFF4CCAF64378F
+:1002C000CCB02FF5CCB13C05CCB28757CCB3B888B5
+:1002D000CCB49787CCB5DFF4CCB66724CCB7866AAC
+:1002E000CCB86F72CCB91002CCBA2D01CCBB301196
+:1002F000CCBC1001CCBDC620CCBE14E5CCBFC62101
+:10030000CCC0C53DCCC1C622CCC23CBECCC3C623EA
+:10031000CCC44452CCC5C624CCC6C5C5CCC7C625A2
+:10032000CCC8E01ECCC9C627CCCA0000CCCBC6289E
+:10033000CCCC0000CCCDC62BCCCE0000CCCFC62C74
+:10034000CCD00000CCD10000CCD22D01CCD33011C8
+:10035000CCD41001CCD5C620CCD60000CCD7C62139
+:10036000CCD80000CCD9C622CCDA00CECCDBC62358
+:10037000CCDC007FCCDDC624CCDE0032CCDFC62551
+:10038000CCE00000CCE1C627CCE20000CCE3C628DC
+:10039000CCE40000CCE5C62BCCE60000CCE7C62CB4
+:1003A000CCE80000CCE90000CCEA2D01CCEB301108
+:1003B000CCEC1001CCEDC502CCEE609FCCEFC600BA
+:1003C000CCF02A6ECCF1C601CCF22A2CCCF3C60CB0
+:1003D000CCF45400CCF5C710CCF60700CCF7C71806
+:1003E000CCF80700CCF9C720CCFA4700CCFBC728D3
+:1003F000CCFC0700CCFDC729CCFE1207CCFFC801FE
+:10040000CD007F50CD01C802CD027760CD03C80377
+:10041000CD047FCECD05C804CD06520ECD07C8054C
+:10042000CD085C11CD09C806CD0A3C51CD0BC807DB
+:10043000CD0C4061CD0DC808CD0E49C1CD0FC80906
+:10044000CD103840CD11C80ACD120000CD13C821FF
+:10045000CD140002CD15C822CD160046CD17C844D4
+:10046000CD18182FCD19C013CD1AF341CD1BC01ACA
+:10047000CD1C0446CD1DC024CD1E1000CD1FC025AF
+:10048000CD200A00CD21C026CD220C0CCD23C027C3
+:10049000CD240C0CCD25C029CD2600A0CD27C03001
+:1004A000CD280A00CD29C03CCD2A001CCD2B000050
+:1004B000CD2C2B84CD2D3C74CD2E6435CD2FDFF487
+:1004C000CD306435CD312806CD323006CD3385654B
+:1004D000CD342B24CD353C24CD366436CD371002B7
+:1004E000CD382B24CD393C24CD3A6436CD3B404524
+:1004F000CD3C8656CD3D1002CD3E2807CD3F31A7DD
+:10050000CD4020C4CD413C24CD426724CD431002D0
+:10051000CD442807CD453187CD4620C4CD473C2466
+:10052000CD486724CD491002CD4A2514CD4B3C64FB
+:10053000CD4C6436CD4DDFF4CD4E6436CD4F100238
+:10054000CD502806CD513CB6CD52C161CD5361345A
+:10055000CD546135CD555443CD560303CD57652455
+:10056000CD58000BCD591002CD5AD019CD5B2104C6
+:10057000CD5C3C24CD5D2105CD5E3805CD5F652485
+:10058000CD60DFF4CD614005CD626524CD632E8D55
+:10059000CD64303DCD655DD3CD660306CD672FF7C5
+:1005A000CD6838F7CD6960B7CD6ADFFDCD6B000A45
+:0C05B000CD6C1002CD6D000052A76B0E48
+:00000001FF
diff --git a/firmware/cxgb3/ael2020_twx_edc.bin.ihex b/firmware/cxgb3/ael2020_twx_edc.bin.ihex
new file mode 100644
index 000000000000..8b1337f4c329
--- /dev/null
+++ b/firmware/cxgb3/ael2020_twx_edc.bin.ihex
@@ -0,0 +1,100 @@
+:10000000D8004009D8012FFFD802300FD80340AAEA
+:10001000D804401CD805401ED8062FF4D8073DC48C
+:10002000D8082035D8093035D80A6524D80B2CB229
+:10003000D80C3012D80D1002D80E26E2D80F30227C
+:10004000D8101002D81127D2D8123022D81310029B
+:10005000D8142822D8153012D8161002D817249296
+:10006000D8183022D8191002D81A2772D81B30128B
+:10007000D81C1002D81D23D2D81E3022D81F10023F
+:10008000D82022CDD821301DD82227F2D8233022E3
+:10009000D8241002D8255553D8260307D82725225F
+:1000A000D8283022D8291002D82A2142D82B301241
+:1000B000D82C1002D82D4016D82E5E63D82F0344BA
+:1000C000D8302142D8313012D8321002D833400E05
+:1000D000D8342522D8353022D8361002D8372B52C2
+:1000E000D8383012D8391002D83A2742D83B3022BB
+:1000F000D83C1002D83D25E2D83E3022D83F10022D
+:10010000D8402FA4D8413DC4D8426624D843414B9F
+:10011000D84456B3D84503C6D846866BD847400C5A
+:10012000D8482712D8493012D84A1002D84B2C4B45
+:10013000D84C309BD84D56B3D84E03C3D84F866B9E
+:10014000D850400CD8512272D8523022D8531002C5
+:10015000D8542742D8553022D8561002D85725E215
+:10016000D8583022D8591002D85A2FB4D85B3DC481
+:10017000D85C6624D85D56B3D85E03C3D85F866B5F
+:10018000D860401CD8612C45D8623095D8635B5349
+:10019000D8642372D8653012D86613C2D8675CC39E
+:1001A000D8682712D8693012D86A1312D86B2B522C
+:1001B000D86C3012D86D1002D86E2742D86F30221A
+:1001C000D8701002D8712582D8723022D8731002EC
+:1001D000D8742142D8753012D8761002D877628F41
+:1001E000D8782985D87933A5D87A25E2D87B3022EA
+:1001F000D87C1002D87D5653D87E03D2D87F401EBB
+:10020000D8806F72D8811002D882628FD88323047D
+:10021000D8843C84D8856436D886DFF4D8876436A1
+:10022000D8882FF5D8893005D88A8656D88BDFBA7A
+:10023000D88C56A3D88DD05AD88E2972D88F301228
+:10024000D8901392D891D05AD89256A3D893DFBAA7
+:10025000D8940383D8956F72D8961002D8972B45FF
+:10026000D8983005D8994178D89A5653D89B0384AA
+:10027000D89C2A62D89D3012D89E1002D89F2F0594
+:10028000D8A03005D8A141C8D8A25653D8A303821C
+:10029000D8A40002D8A54218D8A62474D8A73C84B4
+:1002A000D8A86437D8A9DFF4D8AA6437D8AB2FF51B
+:1002B000D8AC3C05D8AD8757D8AEB888D8AF9787AB
+:1002C000D8B0DFF4D8B16724D8B2866AD8B36F72D9
+:1002D000D8B41002D8B52641D8B63021D8B710010D
+:1002E000D8B8C620D8B90000D8BAC621D8BB0000FB
+:1002F000D8BCC622D8BD00CED8BEC623D8BF007F8A
+:10030000D8C0C624D8C10032D8C2C625D8C3000080
+:10031000D8C4C627D8C50000D8C6C628D8C700008C
+:10032000D8C8C62CD8C90000D8CA0000D8CB2641EE
+:10033000D8CC3021D8CD1001D8CEC502D8CF53ACFF
+:10034000D8D0C503D8D12CD3D8D2C600D8D32A6EE2
+:10035000D8D4C601D8D52A2CD8D6C605D8D7555753
+:10036000D8D8C60CD8D95400D8DAC710D8DB0700C3
+:10037000D8DCC711D8DD0F06D8DEC718D8DF0700D4
+:10038000D8E0C719D8E10F06D8E2C720D8E3470064
+:10039000D8E4C721D8E50F06D8E6C728D8E7070074
+:1003A000D8E8C729D8E91207D8EAC801D8EB7F50A6
+:1003B000D8ECC802D8ED7760D8EEC803D8EF7FCE6E
+:1003C000D8F0C804D8F1520ED8F2C805D8F35C11A1
+:1003D000D8F4C806D8F53C51D8F6C807D8F740611C
+:1003E000D8F8C808D8F949C1D8FAC809D8FB3840A4
+:1003F000D8FCC80AD8FD0000D8FEC821D8FF0002EA
+:10040000D900C822D9010046D902C844D903182FFF
+:10041000D904C013D905F341D906C084D9070030E7
+:10042000D908C904D9091401D90ACB0CD90B000485
+:10043000D90CCB0ED90DA00AD90ECB0FD90FC0C045
+:10044000D910CB10D911C0C0D912CB11D91300A02B
+:10045000D914CB12D9150007D916C241D917A0005B
+:10046000D918C243D9197FE0D91AC604D91B000E86
+:10047000D91CC609D91D00F5D91EC611D91F000EF9
+:10048000D920C660D9219600D922C687D923000475
+:10049000D924C60AD92504F5D9260000D927264132
+:1004A000D9283021D9291001D92AC620D92B14E501
+:1004B000D92CC621D92DC53DD92EC622D92F3CBE57
+:1004C000D930C623D9314452D932C624D933C5C50F
+:1004D000D934C625D935E01ED936C627D93700000C
+:1004E000D938C628D9390000D93AC62CD93B0000E2
+:1004F000D93C0000D93D2B84D93E3C74D93F6435AA
+:10050000D940DFF4D9416435D9422806D9433006B1
+:10051000D9448565D9452B24D9463C24D94764362E
+:10052000D9481002D9492B24D94A3C24D94B6436E6
+:10053000D94C4045D94D8656D94E5663D94F030202
+:10054000D950401ED9511002D9522807D95331A78A
+:10055000D95420C4D9553C24D9566724D957100200
+:10056000D9582807D9593187D95A20C4D95B3C2496
+:10057000D95C6724D95D1002D95E24F4D95F3C644C
+:10058000D9606436D961DFF4D9626436D963100268
+:10059000D9642006D9653D76D966C161D9676134D1
+:1005A000D9686135D9695443D96A0303D96B652485
+:1005B000D96C00FBD96D1002D96E20D4D96F3C24C0
+:1005C000D9702025D9713005D9726524D9731002EC
+:1005D000D974D019D9752104D9763C24D97721054D
+:1005E000D9783805D9796524D97ADFF4D97B4005E3
+:1005F000D97C6524D97D2E8DD97E303DD97F2408C4
+:10060000D98035D8D9815DD3D9820307D98388872A
+:10061000D98463A7D9858887D98663A7D987DFFD61
+:10062000D98800F9D9891002D98A0000878C30D97D
+:00000001FF
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 81f8bbf12f9f..fac30d21851f 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -171,7 +171,6 @@ int v9fs_uflags2omode(int uflags, int extended)
/**
* v9fs_blank_wstat - helper function to setup a 9P stat structure
- * @v9ses: 9P session info (for determining extended mode)
* @wstat: structure to initialize
*
*/
@@ -207,65 +206,72 @@ v9fs_blank_wstat(struct p9_wstat *wstat)
struct inode *v9fs_get_inode(struct super_block *sb, int mode)
{
+ int err;
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
inode = new_inode(sb);
- if (inode) {
- inode->i_mode = mode;
- inode->i_uid = current_fsuid();
- inode->i_gid = current_fsgid();
- inode->i_blocks = 0;
- inode->i_rdev = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_mapping->a_ops = &v9fs_addr_operations;
-
- switch (mode & S_IFMT) {
- case S_IFIFO:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFSOCK:
- if (!v9fs_extended(v9ses)) {
- P9_DPRINTK(P9_DEBUG_ERROR,
- "special files without extended mode\n");
- return ERR_PTR(-EINVAL);
- }
- init_special_inode(inode, inode->i_mode,
- inode->i_rdev);
- break;
- case S_IFREG:
- inode->i_op = &v9fs_file_inode_operations;
- inode->i_fop = &v9fs_file_operations;
- break;
- case S_IFLNK:
- if (!v9fs_extended(v9ses)) {
- P9_DPRINTK(P9_DEBUG_ERROR,
- "extended modes used w/o 9P2000.u\n");
- return ERR_PTR(-EINVAL);
- }
- inode->i_op = &v9fs_symlink_inode_operations;
- break;
- case S_IFDIR:
- inc_nlink(inode);
- if (v9fs_extended(v9ses))
- inode->i_op = &v9fs_dir_inode_operations_ext;
- else
- inode->i_op = &v9fs_dir_inode_operations;
- inode->i_fop = &v9fs_dir_operations;
- break;
- default:
+ if (!inode) {
+ P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
+ return -ENOMEM;
+ }
+
+ inode->i_mode = mode;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
+ inode->i_blocks = 0;
+ inode->i_rdev = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mapping->a_ops = &v9fs_addr_operations;
+
+ switch (mode & S_IFMT) {
+ case S_IFIFO:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFSOCK:
+ if (!v9fs_extended(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR,
- "BAD mode 0x%x S_IFMT 0x%x\n",
- mode, mode & S_IFMT);
- return ERR_PTR(-EINVAL);
+ "special files without extended mode\n");
+ err = -EINVAL;
+ goto error;
}
- } else {
- P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
- return ERR_PTR(-ENOMEM);
+ init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ break;
+ case S_IFREG:
+ inode->i_op = &v9fs_file_inode_operations;
+ inode->i_fop = &v9fs_file_operations;
+ break;
+ case S_IFLNK:
+ if (!v9fs_extended(v9ses)) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "extended modes used w/o 9P2000.u\n");
+ err = -EINVAL;
+ goto error;
+ }
+ inode->i_op = &v9fs_symlink_inode_operations;
+ break;
+ case S_IFDIR:
+ inc_nlink(inode);
+ if (v9fs_extended(v9ses))
+ inode->i_op = &v9fs_dir_inode_operations_ext;
+ else
+ inode->i_op = &v9fs_dir_inode_operations;
+ inode->i_fop = &v9fs_dir_operations;
+ break;
+ default:
+ P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
+ mode, mode & S_IFMT);
+ err = -EINVAL;
+ goto error;
}
+
return inode;
+
+error:
+ iput(inode);
+ return ERR_PTR(err);
}
/*
@@ -338,30 +344,25 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
ret = NULL;
st = p9_client_stat(fid);
- if (IS_ERR(st)) {
- err = PTR_ERR(st);
- st = NULL;
- goto error;
- }
+ if (IS_ERR(st))
+ return ERR_CAST(st);
umode = p9mode2unixmode(v9ses, st->mode);
ret = v9fs_get_inode(sb, umode);
if (IS_ERR(ret)) {
err = PTR_ERR(ret);
- ret = NULL;
goto error;
}
v9fs_stat2inode(st, ret, sb);
ret->i_ino = v9fs_qid2ino(&st->qid);
+ p9stat_free(st);
kfree(st);
return ret;
error:
+ p9stat_free(st);
kfree(st);
- if (ret)
- iput(ret);
-
return ERR_PTR(err);
}
@@ -403,9 +404,9 @@ v9fs_open_created(struct inode *inode, struct file *file)
* @v9ses: session information
* @dir: directory that dentry is being created in
* @dentry: dentry that is being created
+ * @extension: 9p2000.u extension string to support devices, etc.
* @perm: create permissions
* @mode: open mode
- * @extension: 9p2000.u extension string to support devices, etc.
*
*/
static struct p9_fid *
@@ -470,7 +471,10 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
dentry->d_op = &v9fs_dentry_operations;
d_instantiate(dentry, inode);
- v9fs_fid_add(dentry, fid);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ goto error;
+
return ofid;
error:
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 38d695d66a0b..072dce094477 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -113,14 +113,11 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct v9fs_session_info *v9ses = NULL;
struct p9_wstat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
- uid_t uid = current_fsuid();
- gid_t gid = current_fsgid();
struct p9_fid *fid;
int retval = 0;
P9_DPRINTK(P9_DEBUG_VFS, " \n");
- st = NULL;
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses)
return -ENOMEM;
@@ -150,9 +147,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
goto release_sb;
}
- inode->i_uid = uid;
- inode->i_gid = gid;
-
root = d_alloc_root(inode);
if (!root) {
iput(inode);
@@ -173,10 +167,8 @@ P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
simple_set_mnt(mnt, sb);
return 0;
-release_sb:
- deactivate_locked_super(sb);
-
free_stat:
+ p9stat_free(st);
kfree(st);
clunk_fid:
@@ -185,7 +177,12 @@ clunk_fid:
close_session:
v9fs_session_close(v9ses);
kfree(v9ses);
+ return retval;
+release_sb:
+ p9stat_free(st);
+ kfree(st);
+ deactivate_locked_super(sb);
return retval;
}
@@ -207,6 +204,7 @@ static void v9fs_kill_super(struct super_block *s)
v9fs_session_close(v9ses);
kfree(v9ses);
+ s->s_fs_info = NULL;
P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
}
@@ -220,8 +218,8 @@ static void v9fs_kill_super(struct super_block *s)
static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
{
struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
-
- seq_printf(m, "%s", v9ses->options);
+ if (v9ses->options != NULL)
+ seq_printf(m, ",%s", v9ses->options);
return 0;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 3a6d4fb2a329..94dfda24c06e 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -564,6 +564,16 @@ struct block_device *bdget(dev_t dev)
EXPORT_SYMBOL(bdget);
+/**
+ * bdgrab -- Grab a reference to an already referenced block device
+ * @bdev: Block device to grab a reference to.
+ */
+struct block_device *bdgrab(struct block_device *bdev)
+{
+ atomic_inc(&bdev->bd_inode->i_count);
+ return bdev;
+}
+
long nr_blockdev_pages(void)
{
struct block_device *bdev;
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index 6e4f6c50a120..019e8af449ab 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -424,11 +424,11 @@ int btrfs_requeue_work(struct btrfs_work *work)
* list
*/
if (worker->idle) {
- spin_lock_irqsave(&worker->workers->lock, flags);
+ spin_lock(&worker->workers->lock);
worker->idle = 0;
list_move_tail(&worker->worker_list,
&worker->workers->worker_list);
- spin_unlock_irqrestore(&worker->workers->lock, flags);
+ spin_unlock(&worker->workers->lock);
}
if (!worker->working) {
wake = 1;
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 60a45f3a4e91..3fdcc0512d3a 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -557,19 +557,7 @@ static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
btrfs_disk_key_to_cpu(&k1, disk);
- if (k1.objectid > k2->objectid)
- return 1;
- if (k1.objectid < k2->objectid)
- return -1;
- if (k1.type > k2->type)
- return 1;
- if (k1.type < k2->type)
- return -1;
- if (k1.offset > k2->offset)
- return 1;
- if (k1.offset < k2->offset)
- return -1;
- return 0;
+ return btrfs_comp_cpu_keys(&k1, k2);
}
/*
@@ -1052,9 +1040,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
return 0;
- if (btrfs_header_nritems(mid) > 2)
- return 0;
-
if (btrfs_header_nritems(mid) < 2)
err_on_enospc = 1;
@@ -1701,6 +1686,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
struct extent_buffer *b;
int slot;
int ret;
+ int err;
int level;
int lowest_unlock = 1;
u8 lowest_level = 0;
@@ -1737,8 +1723,6 @@ again:
p->locks[level] = 1;
if (cow) {
- int wret;
-
/*
* if we don't really need to cow this block
* then we don't want to set the path blocking,
@@ -1749,12 +1733,12 @@ again:
btrfs_set_path_blocking(p);
- wret = btrfs_cow_block(trans, root, b,
- p->nodes[level + 1],
- p->slots[level + 1], &b);
- if (wret) {
+ err = btrfs_cow_block(trans, root, b,
+ p->nodes[level + 1],
+ p->slots[level + 1], &b);
+ if (err) {
free_extent_buffer(b);
- ret = wret;
+ ret = err;
goto done;
}
}
@@ -1793,41 +1777,45 @@ cow_done:
ret = bin_search(b, key, level, &slot);
if (level != 0) {
- if (ret && slot > 0)
+ int dec = 0;
+ if (ret && slot > 0) {
+ dec = 1;
slot -= 1;
+ }
p->slots[level] = slot;
- ret = setup_nodes_for_search(trans, root, p, b, level,
+ err = setup_nodes_for_search(trans, root, p, b, level,
ins_len);
- if (ret == -EAGAIN)
+ if (err == -EAGAIN)
goto again;
- else if (ret)
+ if (err) {
+ ret = err;
goto done;
+ }
b = p->nodes[level];
slot = p->slots[level];
unlock_up(p, level, lowest_unlock);
- /* this is only true while dropping a snapshot */
if (level == lowest_level) {
- ret = 0;
+ if (dec)
+ p->slots[level]++;
goto done;
}
- ret = read_block_for_search(trans, root, p,
+ err = read_block_for_search(trans, root, p,
&b, level, slot, key);
- if (ret == -EAGAIN)
+ if (err == -EAGAIN)
goto again;
-
- if (ret == -EIO)
+ if (err) {
+ ret = err;
goto done;
+ }
if (!p->skip_locking) {
- int lret;
-
btrfs_clear_path_blocking(p, NULL);
- lret = btrfs_try_spin_lock(b);
+ err = btrfs_try_spin_lock(b);
- if (!lret) {
+ if (!err) {
btrfs_set_path_blocking(p);
btrfs_tree_lock(b);
btrfs_clear_path_blocking(p, b);
@@ -1837,16 +1825,14 @@ cow_done:
p->slots[level] = slot;
if (ins_len > 0 &&
btrfs_leaf_free_space(root, b) < ins_len) {
- int sret;
-
btrfs_set_path_blocking(p);
- sret = split_leaf(trans, root, key,
- p, ins_len, ret == 0);
+ err = split_leaf(trans, root, key,
+ p, ins_len, ret == 0);
btrfs_clear_path_blocking(p, NULL);
- BUG_ON(sret > 0);
- if (sret) {
- ret = sret;
+ BUG_ON(err > 0);
+ if (err) {
+ ret = err;
goto done;
}
}
@@ -3807,7 +3793,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
/* delete the leaf if it is mostly empty */
- if (used < BTRFS_LEAF_DATA_SIZE(root) / 2) {
+ if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) {
/* push_leaf_left fixes the path.
* make sure the path still points to our leaf
* for possible call to del_ptr below
@@ -4042,10 +4028,9 @@ out:
* calling this function.
*/
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
- struct btrfs_key *key, int lowest_level,
+ struct btrfs_key *key, int level,
int cache_only, u64 min_trans)
{
- int level = lowest_level;
int slot;
struct extent_buffer *c;
@@ -4058,11 +4043,40 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
c = path->nodes[level];
next:
if (slot >= btrfs_header_nritems(c)) {
- level++;
- if (level == BTRFS_MAX_LEVEL)
+ int ret;
+ int orig_lowest;
+ struct btrfs_key cur_key;
+ if (level + 1 >= BTRFS_MAX_LEVEL ||
+ !path->nodes[level + 1])
return 1;
- continue;
+
+ if (path->locks[level + 1]) {
+ level++;
+ continue;
+ }
+
+ slot = btrfs_header_nritems(c) - 1;
+ if (level == 0)
+ btrfs_item_key_to_cpu(c, &cur_key, slot);
+ else
+ btrfs_node_key_to_cpu(c, &cur_key, slot);
+
+ orig_lowest = path->lowest_level;
+ btrfs_release_path(root, path);
+ path->lowest_level = level;
+ ret = btrfs_search_slot(NULL, root, &cur_key, path,
+ 0, 0);
+ path->lowest_level = orig_lowest;
+ if (ret < 0)
+ return ret;
+
+ c = path->nodes[level];
+ slot = path->slots[level];
+ if (ret == 0)
+ slot++;
+ goto next;
}
+
if (level == 0)
btrfs_item_key_to_cpu(c, key, slot);
else {
@@ -4146,7 +4160,8 @@ again:
* advance the path if there are now more items available.
*/
if (nritems > 0 && path->slots[0] < nritems - 1) {
- path->slots[0]++;
+ if (ret == 0)
+ path->slots[0]++;
ret = 0;
goto done;
}
@@ -4278,10 +4293,10 @@ int btrfs_previous_item(struct btrfs_root *root,
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
- if (found_key.type == type)
- return 0;
if (found_key.objectid < min_objectid)
break;
+ if (found_key.type == type)
+ return 0;
if (found_key.objectid == min_objectid &&
found_key.type < type)
break;
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 98a873838717..837435ce84ca 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -481,7 +481,7 @@ struct btrfs_shared_data_ref {
struct btrfs_extent_inline_ref {
u8 type;
- u64 offset;
+ __le64 offset;
} __attribute__ ((__packed__));
/* old style backrefs item */
@@ -689,6 +689,7 @@ struct btrfs_space_info {
struct list_head block_groups;
spinlock_t lock;
struct rw_semaphore groups_sem;
+ atomic_t caching_threads;
};
/*
@@ -707,6 +708,9 @@ struct btrfs_free_cluster {
/* first extent starting offset */
u64 window_start;
+ /* if this cluster simply points at a bitmap in the block group */
+ bool points_to_bitmap;
+
struct btrfs_block_group_cache *block_group;
/*
* when a cluster is allocated from a block group, we put the
@@ -716,24 +720,37 @@ struct btrfs_free_cluster {
struct list_head block_group_list;
};
+enum btrfs_caching_type {
+ BTRFS_CACHE_NO = 0,
+ BTRFS_CACHE_STARTED = 1,
+ BTRFS_CACHE_FINISHED = 2,
+};
+
struct btrfs_block_group_cache {
struct btrfs_key key;
struct btrfs_block_group_item item;
+ struct btrfs_fs_info *fs_info;
spinlock_t lock;
- struct mutex cache_mutex;
u64 pinned;
u64 reserved;
u64 flags;
- int cached;
+ u64 sectorsize;
+ int extents_thresh;
+ int free_extents;
+ int total_bitmaps;
int ro;
int dirty;
+ /* cache tracking stuff */
+ wait_queue_head_t caching_q;
+ int cached;
+
struct btrfs_space_info *space_info;
/* free space cache stuff */
spinlock_t tree_lock;
- struct rb_root free_space_bytes;
struct rb_root free_space_offset;
+ u64 free_space;
/* block group cache stuff */
struct rb_node cache_node;
@@ -808,6 +825,7 @@ struct btrfs_fs_info {
struct mutex drop_mutex;
struct mutex volume_mutex;
struct mutex tree_reloc_mutex;
+ struct rw_semaphore extent_commit_sem;
/*
* this protects the ordered operations list only while we are
@@ -1988,6 +2006,7 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
u64 bytes);
void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
u64 bytes);
+void btrfs_free_pinned_extents(struct btrfs_fs_info *info);
/* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index d28d29c95f7c..15831d5c7367 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1352,6 +1352,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
{
int err;
+ bdi->name = "btrfs";
bdi->capabilities = BDI_CAP_MAP_COPY;
err = bdi_init(bdi);
if (err)
@@ -1639,6 +1640,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
mutex_init(&fs_info->cleaner_mutex);
mutex_init(&fs_info->volume_mutex);
mutex_init(&fs_info->tree_reloc_mutex);
+ init_rwsem(&fs_info->extent_commit_sem);
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
@@ -1799,6 +1801,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
btrfs_super_chunk_root(disk_super),
blocksize, generation);
BUG_ON(!chunk_root->node);
+ if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
+ printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
+ sb->s_id);
+ goto fail_chunk_root;
+ }
btrfs_set_root_node(&chunk_root->root_item, chunk_root->node);
chunk_root->commit_root = btrfs_root_node(chunk_root);
@@ -1826,6 +1833,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
blocksize, generation);
if (!tree_root->node)
goto fail_chunk_root;
+ if (!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) {
+ printk(KERN_WARNING "btrfs: failed to read tree root on %s\n",
+ sb->s_id);
+ goto fail_tree_root;
+ }
btrfs_set_root_node(&tree_root->root_item, tree_root->node);
tree_root->commit_root = btrfs_root_node(tree_root);
@@ -2322,6 +2334,9 @@ int close_ctree(struct btrfs_root *root)
printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
}
+ fs_info->closing = 2;
+ smp_mb();
+
if (fs_info->delalloc_bytes) {
printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
(unsigned long long)fs_info->delalloc_bytes);
@@ -2343,6 +2358,7 @@ int close_ctree(struct btrfs_root *root)
free_extent_buffer(root->fs_info->csum_root->commit_root);
btrfs_free_block_groups(root->fs_info);
+ btrfs_free_pinned_extents(root->fs_info);
del_fs_roots(fs_info);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index a5aca3997d42..dc84daee6bc4 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -21,6 +21,7 @@
#include <linux/blkdev.h>
#include <linux/sort.h>
#include <linux/rcupdate.h>
+#include <linux/kthread.h>
#include "compat.h"
#include "hash.h"
#include "ctree.h"
@@ -61,6 +62,13 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root, u64 alloc_bytes,
u64 flags, int force);
+static noinline int
+block_group_cache_done(struct btrfs_block_group_cache *cache)
+{
+ smp_mb();
+ return cache->cached == BTRFS_CACHE_FINISHED;
+}
+
static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
{
return (cache->flags & bits) == bits;
@@ -146,20 +154,70 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr,
}
/*
+ * We always set EXTENT_LOCKED for the super mirror extents so we don't
+ * overwrite them, so those bits need to be unset. Also, if we are unmounting
+ * with pinned extents still sitting there because we had a block group caching,
+ * we need to clear those now, since we are done.
+ */
+void btrfs_free_pinned_extents(struct btrfs_fs_info *info)
+{
+ u64 start, end, last = 0;
+ int ret;
+
+ while (1) {
+ ret = find_first_extent_bit(&info->pinned_extents, last,
+ &start, &end,
+ EXTENT_LOCKED|EXTENT_DIRTY);
+ if (ret)
+ break;
+
+ clear_extent_bits(&info->pinned_extents, start, end,
+ EXTENT_LOCKED|EXTENT_DIRTY, GFP_NOFS);
+ last = end+1;
+ }
+}
+
+static int remove_sb_from_cache(struct btrfs_root *root,
+ struct btrfs_block_group_cache *cache)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ u64 bytenr;
+ u64 *logical;
+ int stripe_len;
+ int i, nr, ret;
+
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ bytenr = btrfs_sb_offset(i);
+ ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
+ cache->key.objectid, bytenr,
+ 0, &logical, &nr, &stripe_len);
+ BUG_ON(ret);
+ while (nr--) {
+ try_lock_extent(&fs_info->pinned_extents,
+ logical[nr],
+ logical[nr] + stripe_len - 1, GFP_NOFS);
+ }
+ kfree(logical);
+ }
+
+ return 0;
+}
+
+/*
* this is only called by cache_block_group, since we could have freed extents
* we need to check the pinned_extents for any extents that can't be used yet
* since their free space will be released as soon as the transaction commits.
*/
-static int add_new_free_space(struct btrfs_block_group_cache *block_group,
+static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
struct btrfs_fs_info *info, u64 start, u64 end)
{
- u64 extent_start, extent_end, size;
+ u64 extent_start, extent_end, size, total_added = 0;
int ret;
while (start < end) {
ret = find_first_extent_bit(&info->pinned_extents, start,
&extent_start, &extent_end,
- EXTENT_DIRTY);
+ EXTENT_DIRTY|EXTENT_LOCKED);
if (ret)
break;
@@ -167,6 +225,7 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
start = extent_end + 1;
} else if (extent_start > start && extent_start < end) {
size = extent_start - start;
+ total_added += size;
ret = btrfs_add_free_space(block_group, start,
size);
BUG_ON(ret);
@@ -178,84 +237,80 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group,
if (start < end) {
size = end - start;
+ total_added += size;
ret = btrfs_add_free_space(block_group, start, size);
BUG_ON(ret);
}
- return 0;
+ return total_added;
}
-static int remove_sb_from_cache(struct btrfs_root *root,
- struct btrfs_block_group_cache *cache)
-{
- u64 bytenr;
- u64 *logical;
- int stripe_len;
- int i, nr, ret;
-
- for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
- bytenr = btrfs_sb_offset(i);
- ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
- cache->key.objectid, bytenr, 0,
- &logical, &nr, &stripe_len);
- BUG_ON(ret);
- while (nr--) {
- btrfs_remove_free_space(cache, logical[nr],
- stripe_len);
- }
- kfree(logical);
- }
- return 0;
-}
-
-static int cache_block_group(struct btrfs_root *root,
- struct btrfs_block_group_cache *block_group)
+static int caching_kthread(void *data)
{
+ struct btrfs_block_group_cache *block_group = data;
+ struct btrfs_fs_info *fs_info = block_group->fs_info;
+ u64 last = 0;
struct btrfs_path *path;
int ret = 0;
struct btrfs_key key;
struct extent_buffer *leaf;
int slot;
- u64 last;
-
- if (!block_group)
- return 0;
+ u64 total_found = 0;
- root = root->fs_info->extent_root;
-
- if (block_group->cached)
- return 0;
+ BUG_ON(!fs_info);
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 2;
+ atomic_inc(&block_group->space_info->caching_threads);
+ last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
+again:
+ /* need to make sure the commit_root doesn't disappear */
+ down_read(&fs_info->extent_commit_sem);
+
/*
- * we get into deadlocks with paths held by callers of this function.
- * since the alloc_mutex is protecting things right now, just
- * skip the locking here
+ * We don't want to deadlock with somebody trying to allocate a new
+ * extent for the extent root while also trying to search the extent
+ * root to add free space. So we skip locking and search the commit
+ * root, since its read-only
*/
path->skip_locking = 1;
- last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
+ path->search_commit_root = 1;
+ path->reada = 2;
+
key.objectid = last;
key.offset = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
- ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
if (ret < 0)
goto err;
while (1) {
+ smp_mb();
+ if (block_group->fs_info->closing > 1) {
+ last = (u64)-1;
+ break;
+ }
+
leaf = path->nodes[0];
slot = path->slots[0];
if (slot >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(root, path);
+ ret = btrfs_next_leaf(fs_info->extent_root, path);
if (ret < 0)
goto err;
- if (ret == 0)
- continue;
- else
+ else if (ret)
break;
+
+ if (need_resched() ||
+ btrfs_transaction_in_commit(fs_info)) {
+ btrfs_release_path(fs_info->extent_root, path);
+ up_read(&fs_info->extent_commit_sem);
+ schedule_timeout(1);
+ goto again;
+ }
+
+ continue;
}
btrfs_item_key_to_cpu(leaf, &key, slot);
if (key.objectid < block_group->key.objectid)
@@ -266,24 +321,59 @@ static int cache_block_group(struct btrfs_root *root,
break;
if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
- add_new_free_space(block_group, root->fs_info, last,
- key.objectid);
-
+ total_found += add_new_free_space(block_group,
+ fs_info, last,
+ key.objectid);
last = key.objectid + key.offset;
}
+
+ if (total_found > (1024 * 1024 * 2)) {
+ total_found = 0;
+ wake_up(&block_group->caching_q);
+ }
next:
path->slots[0]++;
}
+ ret = 0;
- add_new_free_space(block_group, root->fs_info, last,
- block_group->key.objectid +
- block_group->key.offset);
+ total_found += add_new_free_space(block_group, fs_info, last,
+ block_group->key.objectid +
+ block_group->key.offset);
+
+ spin_lock(&block_group->lock);
+ block_group->cached = BTRFS_CACHE_FINISHED;
+ spin_unlock(&block_group->lock);
- block_group->cached = 1;
- remove_sb_from_cache(root, block_group);
- ret = 0;
err:
btrfs_free_path(path);
+ up_read(&fs_info->extent_commit_sem);
+ atomic_dec(&block_group->space_info->caching_threads);
+ wake_up(&block_group->caching_q);
+
+ return 0;
+}
+
+static int cache_block_group(struct btrfs_block_group_cache *cache)
+{
+ struct task_struct *tsk;
+ int ret = 0;
+
+ spin_lock(&cache->lock);
+ if (cache->cached != BTRFS_CACHE_NO) {
+ spin_unlock(&cache->lock);
+ return ret;
+ }
+ cache->cached = BTRFS_CACHE_STARTED;
+ spin_unlock(&cache->lock);
+
+ tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n",
+ cache->key.objectid);
+ if (IS_ERR(tsk)) {
+ ret = PTR_ERR(tsk);
+ printk(KERN_ERR "error running thread %d\n", ret);
+ BUG();
+ }
+
return ret;
}
@@ -2387,13 +2477,29 @@ fail:
}
+static struct btrfs_block_group_cache *
+next_block_group(struct btrfs_root *root,
+ struct btrfs_block_group_cache *cache)
+{
+ struct rb_node *node;
+ spin_lock(&root->fs_info->block_group_cache_lock);
+ node = rb_next(&cache->cache_node);
+ btrfs_put_block_group(cache);
+ if (node) {
+ cache = rb_entry(node, struct btrfs_block_group_cache,
+ cache_node);
+ atomic_inc(&cache->count);
+ } else
+ cache = NULL;
+ spin_unlock(&root->fs_info->block_group_cache_lock);
+ return cache;
+}
+
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
- struct btrfs_block_group_cache *cache, *entry;
- struct rb_node *n;
+ struct btrfs_block_group_cache *cache;
int err = 0;
- int werr = 0;
struct btrfs_path *path;
u64 last = 0;
@@ -2402,39 +2508,35 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
return -ENOMEM;
while (1) {
- cache = NULL;
- spin_lock(&root->fs_info->block_group_cache_lock);
- for (n = rb_first(&root->fs_info->block_group_cache_tree);
- n; n = rb_next(n)) {
- entry = rb_entry(n, struct btrfs_block_group_cache,
- cache_node);
- if (entry->dirty) {
- cache = entry;
- break;
- }
+ if (last == 0) {
+ err = btrfs_run_delayed_refs(trans, root,
+ (unsigned long)-1);
+ BUG_ON(err);
}
- spin_unlock(&root->fs_info->block_group_cache_lock);
- if (!cache)
- break;
+ cache = btrfs_lookup_first_block_group(root->fs_info, last);
+ while (cache) {
+ if (cache->dirty)
+ break;
+ cache = next_block_group(root, cache);
+ }
+ if (!cache) {
+ if (last == 0)
+ break;
+ last = 0;
+ continue;
+ }
cache->dirty = 0;
- last += cache->key.offset;
+ last = cache->key.objectid + cache->key.offset;
- err = write_one_cache_group(trans, root,
- path, cache);
- /*
- * if we fail to write the cache group, we want
- * to keep it marked dirty in hopes that a later
- * write will work
- */
- if (err) {
- werr = err;
- continue;
- }
+ err = write_one_cache_group(trans, root, path, cache);
+ BUG_ON(err);
+ btrfs_put_block_group(cache);
}
+
btrfs_free_path(path);
- return werr;
+ return 0;
}
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
@@ -2484,6 +2586,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
found->force_alloc = 0;
*space_info = found;
list_add_rcu(&found->list, &info->space_info);
+ atomic_set(&found->caching_threads, 0);
return 0;
}
@@ -2947,13 +3050,9 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *fs_info = root->fs_info;
- if (pin) {
+ if (pin)
set_extent_dirty(&fs_info->pinned_extents,
bytenr, bytenr + num - 1, GFP_NOFS);
- } else {
- clear_extent_dirty(&fs_info->pinned_extents,
- bytenr, bytenr + num - 1, GFP_NOFS);
- }
while (num > 0) {
cache = btrfs_lookup_block_group(fs_info, bytenr);
@@ -2969,14 +3068,34 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
spin_unlock(&cache->space_info->lock);
fs_info->total_pinned += len;
} else {
+ int unpin = 0;
+
+ /*
+ * in order to not race with the block group caching, we
+ * only want to unpin the extent if we are cached. If
+ * we aren't cached, we want to start async caching this
+ * block group so we can free the extent the next time
+ * around.
+ */
spin_lock(&cache->space_info->lock);
spin_lock(&cache->lock);
- cache->pinned -= len;
- cache->space_info->bytes_pinned -= len;
+ unpin = (cache->cached == BTRFS_CACHE_FINISHED);
+ if (likely(unpin)) {
+ cache->pinned -= len;
+ cache->space_info->bytes_pinned -= len;
+ fs_info->total_pinned -= len;
+ }
spin_unlock(&cache->lock);
spin_unlock(&cache->space_info->lock);
- fs_info->total_pinned -= len;
- if (cache->cached)
+
+ if (likely(unpin))
+ clear_extent_dirty(&fs_info->pinned_extents,
+ bytenr, bytenr + len -1,
+ GFP_NOFS);
+ else
+ cache_block_group(cache);
+
+ if (unpin)
btrfs_add_free_space(cache, bytenr, len);
}
btrfs_put_block_group(cache);
@@ -3030,6 +3149,7 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy)
&start, &end, EXTENT_DIRTY);
if (ret)
break;
+
set_extent_dirty(copy, start, end, GFP_NOFS);
last = end + 1;
}
@@ -3058,6 +3178,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
cond_resched();
}
+
return ret;
}
@@ -3436,6 +3557,45 @@ static u64 stripe_align(struct btrfs_root *root, u64 val)
}
/*
+ * when we wait for progress in the block group caching, its because
+ * our allocation attempt failed at least once. So, we must sleep
+ * and let some progress happen before we try again.
+ *
+ * This function will sleep at least once waiting for new free space to
+ * show up, and then it will check the block group free space numbers
+ * for our min num_bytes. Another option is to have it go ahead
+ * and look in the rbtree for a free extent of a given size, but this
+ * is a good start.
+ */
+static noinline int
+wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
+ u64 num_bytes)
+{
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(&cache->caching_q, &wait, TASK_UNINTERRUPTIBLE);
+
+ if (block_group_cache_done(cache)) {
+ finish_wait(&cache->caching_q, &wait);
+ return 0;
+ }
+ schedule();
+ finish_wait(&cache->caching_q, &wait);
+
+ wait_event(cache->caching_q, block_group_cache_done(cache) ||
+ (cache->free_space >= num_bytes));
+ return 0;
+}
+
+enum btrfs_loop_type {
+ LOOP_CACHED_ONLY = 0,
+ LOOP_CACHING_NOWAIT = 1,
+ LOOP_CACHING_WAIT = 2,
+ LOOP_ALLOC_CHUNK = 3,
+ LOOP_NO_EMPTY_SIZE = 4,
+};
+
+/*
* walks the btree of allocated extents and find a hole of a given size.
* The key ins is changed to record the hole:
* ins->objectid == block start
@@ -3460,6 +3620,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_space_info *space_info;
int last_ptr_loop = 0;
int loop = 0;
+ bool found_uncached_bg = false;
WARN_ON(num_bytes < root->sectorsize);
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -3491,15 +3652,18 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
search_start = max(search_start, first_logical_byte(root, 0));
search_start = max(search_start, hint_byte);
- if (!last_ptr) {
+ if (!last_ptr)
empty_cluster = 0;
- loop = 1;
- }
if (search_start == hint_byte) {
block_group = btrfs_lookup_block_group(root->fs_info,
search_start);
- if (block_group && block_group_bits(block_group, data)) {
+ /*
+ * we don't want to use the block group if it doesn't match our
+ * allocation bits, or if its not cached.
+ */
+ if (block_group && block_group_bits(block_group, data) &&
+ block_group_cache_done(block_group)) {
down_read(&space_info->groups_sem);
if (list_empty(&block_group->list) ||
block_group->ro) {
@@ -3522,21 +3686,35 @@ search:
down_read(&space_info->groups_sem);
list_for_each_entry(block_group, &space_info->block_groups, list) {
u64 offset;
+ int cached;
atomic_inc(&block_group->count);
search_start = block_group->key.objectid;
have_block_group:
- if (unlikely(!block_group->cached)) {
- mutex_lock(&block_group->cache_mutex);
- ret = cache_block_group(root, block_group);
- mutex_unlock(&block_group->cache_mutex);
- if (ret) {
- btrfs_put_block_group(block_group);
- break;
+ if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
+ /*
+ * we want to start caching kthreads, but not too many
+ * right off the bat so we don't overwhelm the system,
+ * so only start them if there are less than 2 and we're
+ * in the initial allocation phase.
+ */
+ if (loop > LOOP_CACHING_NOWAIT ||
+ atomic_read(&space_info->caching_threads) < 2) {
+ ret = cache_block_group(block_group);
+ BUG_ON(ret);
}
}
+ cached = block_group_cache_done(block_group);
+ if (unlikely(!cached)) {
+ found_uncached_bg = true;
+
+ /* if we only want cached bgs, loop */
+ if (loop == LOOP_CACHED_ONLY)
+ goto loop;
+ }
+
if (unlikely(block_group->ro))
goto loop;
@@ -3615,14 +3793,21 @@ refill_cluster:
spin_unlock(&last_ptr->refill_lock);
goto checks;
}
+ } else if (!cached && loop > LOOP_CACHING_NOWAIT) {
+ spin_unlock(&last_ptr->refill_lock);
+
+ wait_block_group_cache_progress(block_group,
+ num_bytes + empty_cluster + empty_size);
+ goto have_block_group;
}
+
/*
* at this point we either didn't find a cluster
* or we weren't able to allocate a block from our
* cluster. Free the cluster we've been trying
* to use, and go to the next block group
*/
- if (loop < 2) {
+ if (loop < LOOP_NO_EMPTY_SIZE) {
btrfs_return_cluster_to_free_space(NULL,
last_ptr);
spin_unlock(&last_ptr->refill_lock);
@@ -3633,11 +3818,17 @@ refill_cluster:
offset = btrfs_find_space_for_alloc(block_group, search_start,
num_bytes, empty_size);
- if (!offset)
+ if (!offset && (cached || (!cached &&
+ loop == LOOP_CACHING_NOWAIT))) {
goto loop;
+ } else if (!offset && (!cached &&
+ loop > LOOP_CACHING_NOWAIT)) {
+ wait_block_group_cache_progress(block_group,
+ num_bytes + empty_size);
+ goto have_block_group;
+ }
checks:
search_start = stripe_align(root, offset);
-
/* move on to the next group */
if (search_start + num_bytes >= search_end) {
btrfs_add_free_space(block_group, offset, num_bytes);
@@ -3683,13 +3874,26 @@ loop:
}
up_read(&space_info->groups_sem);
- /* loop == 0, try to find a clustered alloc in every block group
- * loop == 1, try again after forcing a chunk allocation
- * loop == 2, set empty_size and empty_cluster to 0 and try again
+ /* LOOP_CACHED_ONLY, only search fully cached block groups
+ * LOOP_CACHING_NOWAIT, search partially cached block groups, but
+ * dont wait foR them to finish caching
+ * LOOP_CACHING_WAIT, search everything, and wait if our bg is caching
+ * LOOP_ALLOC_CHUNK, force a chunk allocation and try again
+ * LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try
+ * again
*/
- if (!ins->objectid && loop < 3 &&
- (empty_size || empty_cluster || allowed_chunk_alloc)) {
- if (loop >= 2) {
+ if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE &&
+ (found_uncached_bg || empty_size || empty_cluster ||
+ allowed_chunk_alloc)) {
+ if (found_uncached_bg) {
+ found_uncached_bg = false;
+ if (loop < LOOP_CACHING_WAIT) {
+ loop++;
+ goto search;
+ }
+ }
+
+ if (loop == LOOP_ALLOC_CHUNK) {
empty_size = 0;
empty_cluster = 0;
}
@@ -3702,7 +3906,7 @@ loop:
space_info->force_alloc = 1;
}
- if (loop < 3) {
+ if (loop < LOOP_NO_EMPTY_SIZE) {
loop++;
goto search;
}
@@ -3798,7 +4002,7 @@ again:
num_bytes, data, 1);
goto again;
}
- if (ret) {
+ if (ret == -ENOSPC) {
struct btrfs_space_info *sinfo;
sinfo = __find_space_info(root->fs_info, data);
@@ -3806,7 +4010,6 @@ again:
"wanted %llu\n", (unsigned long long)data,
(unsigned long long)num_bytes);
dump_space_info(sinfo, num_bytes);
- BUG();
}
return ret;
@@ -3844,7 +4047,9 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
ret = __btrfs_reserve_extent(trans, root, num_bytes, min_alloc_size,
empty_size, hint_byte, search_end, ins,
data);
- update_reserved_extents(root, ins->objectid, ins->offset, 1);
+ if (!ret)
+ update_reserved_extents(root, ins->objectid, ins->offset, 1);
+
return ret;
}
@@ -4006,9 +4211,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *block_group;
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
- mutex_lock(&block_group->cache_mutex);
- cache_block_group(root, block_group);
- mutex_unlock(&block_group->cache_mutex);
+ cache_block_group(block_group);
+ wait_event(block_group->caching_q,
+ block_group_cache_done(block_group));
ret = btrfs_remove_free_space(block_group, ins->objectid,
ins->offset);
@@ -4039,7 +4244,8 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
ret = __btrfs_reserve_extent(trans, root, num_bytes, num_bytes,
empty_size, hint_byte, search_end,
ins, 0);
- BUG_ON(ret);
+ if (ret)
+ return ret;
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
if (parent == 0)
@@ -6955,11 +7161,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
&info->block_group_cache_tree);
spin_unlock(&info->block_group_cache_lock);
- btrfs_remove_free_space_cache(block_group);
down_write(&block_group->space_info->groups_sem);
list_del(&block_group->list);
up_write(&block_group->space_info->groups_sem);
+ if (block_group->cached == BTRFS_CACHE_STARTED)
+ wait_event(block_group->caching_q,
+ block_group_cache_done(block_group));
+
+ btrfs_remove_free_space_cache(block_group);
+
WARN_ON(atomic_read(&block_group->count) != 1);
kfree(block_group);
@@ -7025,9 +7236,19 @@ int btrfs_read_block_groups(struct btrfs_root *root)
atomic_set(&cache->count, 1);
spin_lock_init(&cache->lock);
spin_lock_init(&cache->tree_lock);
- mutex_init(&cache->cache_mutex);
+ cache->fs_info = info;
+ init_waitqueue_head(&cache->caching_q);
INIT_LIST_HEAD(&cache->list);
INIT_LIST_HEAD(&cache->cluster_list);
+
+ /*
+ * we only want to have 32k of ram per block group for keeping
+ * track of free space, and if we pass 1/2 of that we want to
+ * start converting things over to using bitmaps
+ */
+ cache->extents_thresh = ((1024 * 32) / 2) /
+ sizeof(struct btrfs_free_space);
+
read_extent_buffer(leaf, &cache->item,
btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(cache->item));
@@ -7036,6 +7257,26 @@ int btrfs_read_block_groups(struct btrfs_root *root)
key.objectid = found_key.objectid + found_key.offset;
btrfs_release_path(root, path);
cache->flags = btrfs_block_group_flags(&cache->item);
+ cache->sectorsize = root->sectorsize;
+
+ remove_sb_from_cache(root, cache);
+
+ /*
+ * check for two cases, either we are full, and therefore
+ * don't need to bother with the caching work since we won't
+ * find any space, or we are empty, and we can just add all
+ * the space in and be done with it. This saves us _alot_ of
+ * time, particularly in the full case.
+ */
+ if (found_key.offset == btrfs_block_group_used(&cache->item)) {
+ cache->cached = BTRFS_CACHE_FINISHED;
+ } else if (btrfs_block_group_used(&cache->item) == 0) {
+ cache->cached = BTRFS_CACHE_FINISHED;
+ add_new_free_space(cache, root->fs_info,
+ found_key.objectid,
+ found_key.objectid +
+ found_key.offset);
+ }
ret = update_space_info(info, cache->flags, found_key.offset,
btrfs_block_group_used(&cache->item),
@@ -7079,10 +7320,19 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
cache->key.objectid = chunk_offset;
cache->key.offset = size;
cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+ cache->sectorsize = root->sectorsize;
+
+ /*
+ * we only want to have 32k of ram per block group for keeping track
+ * of free space, and if we pass 1/2 of that we want to start
+ * converting things over to using bitmaps
+ */
+ cache->extents_thresh = ((1024 * 32) / 2) /
+ sizeof(struct btrfs_free_space);
atomic_set(&cache->count, 1);
spin_lock_init(&cache->lock);
spin_lock_init(&cache->tree_lock);
- mutex_init(&cache->cache_mutex);
+ init_waitqueue_head(&cache->caching_q);
INIT_LIST_HEAD(&cache->list);
INIT_LIST_HEAD(&cache->cluster_list);
@@ -7091,6 +7341,12 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
cache->flags = type;
btrfs_set_block_group_flags(&cache->item, type);
+ cache->cached = BTRFS_CACHE_FINISHED;
+ remove_sb_from_cache(root, cache);
+
+ add_new_free_space(cache, root->fs_info, chunk_offset,
+ chunk_offset + size);
+
ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
&cache->space_info);
BUG_ON(ret);
@@ -7149,7 +7405,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
rb_erase(&block_group->cache_node,
&root->fs_info->block_group_cache_tree);
spin_unlock(&root->fs_info->block_group_cache_lock);
- btrfs_remove_free_space_cache(block_group);
+
down_write(&block_group->space_info->groups_sem);
/*
* we must use list_del_init so people can check to see if they
@@ -7158,11 +7414,18 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
list_del_init(&block_group->list);
up_write(&block_group->space_info->groups_sem);
+ if (block_group->cached == BTRFS_CACHE_STARTED)
+ wait_event(block_group->caching_q,
+ block_group_cache_done(block_group));
+
+ btrfs_remove_free_space_cache(block_group);
+
spin_lock(&block_group->space_info->lock);
block_group->space_info->total_bytes -= block_group->key.offset;
block_group->space_info->bytes_readonly -= block_group->key.offset;
spin_unlock(&block_group->space_info->lock);
- block_group->space_info->full = 0;
+
+ btrfs_clear_space_info_full(root->fs_info);
btrfs_put_block_group(block_group);
btrfs_put_block_group(block_group);
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 4538e48581a5..af99b78b288e 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -16,45 +16,46 @@
* Boston, MA 021110-1307, USA.
*/
+#include <linux/pagemap.h>
#include <linux/sched.h>
+#include <linux/math64.h>
#include "ctree.h"
#include "free-space-cache.h"
#include "transaction.h"
-struct btrfs_free_space {
- struct rb_node bytes_index;
- struct rb_node offset_index;
- u64 offset;
- u64 bytes;
-};
+#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
+#define MAX_CACHE_BYTES_PER_GIG (32 * 1024)
-static int tree_insert_offset(struct rb_root *root, u64 offset,
- struct rb_node *node)
+static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize,
+ u64 offset)
{
- struct rb_node **p = &root->rb_node;
- struct rb_node *parent = NULL;
- struct btrfs_free_space *info;
+ BUG_ON(offset < bitmap_start);
+ offset -= bitmap_start;
+ return (unsigned long)(div64_u64(offset, sectorsize));
+}
- while (*p) {
- parent = *p;
- info = rb_entry(parent, struct btrfs_free_space, offset_index);
+static inline unsigned long bytes_to_bits(u64 bytes, u64 sectorsize)
+{
+ return (unsigned long)(div64_u64(bytes, sectorsize));
+}
- if (offset < info->offset)
- p = &(*p)->rb_left;
- else if (offset > info->offset)
- p = &(*p)->rb_right;
- else
- return -EEXIST;
- }
+static inline u64 offset_to_bitmap(struct btrfs_block_group_cache *block_group,
+ u64 offset)
+{
+ u64 bitmap_start;
+ u64 bytes_per_bitmap;
- rb_link_node(node, parent, p);
- rb_insert_color(node, root);
+ bytes_per_bitmap = BITS_PER_BITMAP * block_group->sectorsize;
+ bitmap_start = offset - block_group->key.objectid;
+ bitmap_start = div64_u64(bitmap_start, bytes_per_bitmap);
+ bitmap_start *= bytes_per_bitmap;
+ bitmap_start += block_group->key.objectid;
- return 0;
+ return bitmap_start;
}
-static int tree_insert_bytes(struct rb_root *root, u64 bytes,
- struct rb_node *node)
+static int tree_insert_offset(struct rb_root *root, u64 offset,
+ struct rb_node *node, int bitmap)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -62,12 +63,34 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
while (*p) {
parent = *p;
- info = rb_entry(parent, struct btrfs_free_space, bytes_index);
+ info = rb_entry(parent, struct btrfs_free_space, offset_index);
- if (bytes < info->bytes)
+ if (offset < info->offset) {
p = &(*p)->rb_left;
- else
+ } else if (offset > info->offset) {
p = &(*p)->rb_right;
+ } else {
+ /*
+ * we could have a bitmap entry and an extent entry
+ * share the same offset. If this is the case, we want
+ * the extent entry to always be found first if we do a
+ * linear search through the tree, since we want to have
+ * the quickest allocation time, and allocating from an
+ * extent is faster than allocating from a bitmap. So
+ * if we're inserting a bitmap and we find an entry at
+ * this offset, we want to go right, or after this entry
+ * logically. If we are inserting an extent and we've
+ * found a bitmap, we want to go left, or before
+ * logically.
+ */
+ if (bitmap) {
+ WARN_ON(info->bitmap);
+ p = &(*p)->rb_right;
+ } else {
+ WARN_ON(!info->bitmap);
+ p = &(*p)->rb_left;
+ }
+ }
}
rb_link_node(node, parent, p);
@@ -79,110 +102,143 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
/*
* searches the tree for the given offset.
*
- * fuzzy == 1: this is used for allocations where we are given a hint of where
- * to look for free space. Because the hint may not be completely on an offset
- * mark, or the hint may no longer point to free space we need to fudge our
- * results a bit. So we look for free space starting at or after offset with at
- * least bytes size. We prefer to find as close to the given offset as we can.
- * Also if the offset is within a free space range, then we will return the free
- * space that contains the given offset, which means we can return a free space
- * chunk with an offset before the provided offset.
- *
- * fuzzy == 0: this is just a normal tree search. Give us the free space that
- * starts at the given offset which is at least bytes size, and if its not there
- * return NULL.
+ * fuzzy - If this is set, then we are trying to make an allocation, and we just
+ * want a section that has at least bytes size and comes at or after the given
+ * offset.
*/
-static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
- u64 offset, u64 bytes,
- int fuzzy)
+static struct btrfs_free_space *
+tree_search_offset(struct btrfs_block_group_cache *block_group,
+ u64 offset, int bitmap_only, int fuzzy)
{
- struct rb_node *n = root->rb_node;
- struct btrfs_free_space *entry, *ret = NULL;
+ struct rb_node *n = block_group->free_space_offset.rb_node;
+ struct btrfs_free_space *entry, *prev = NULL;
+
+ /* find entry that is closest to the 'offset' */
+ while (1) {
+ if (!n) {
+ entry = NULL;
+ break;
+ }
- while (n) {
entry = rb_entry(n, struct btrfs_free_space, offset_index);
+ prev = entry;
- if (offset < entry->offset) {
- if (fuzzy &&
- (!ret || entry->offset < ret->offset) &&
- (bytes <= entry->bytes))
- ret = entry;
+ if (offset < entry->offset)
n = n->rb_left;
- } else if (offset > entry->offset) {
- if (fuzzy &&
- (entry->offset + entry->bytes - 1) >= offset &&
- bytes <= entry->bytes) {
- ret = entry;
- break;
- }
+ else if (offset > entry->offset)
n = n->rb_right;
- } else {
- if (bytes > entry->bytes) {
- n = n->rb_right;
- continue;
- }
- ret = entry;
+ else
break;
- }
}
- return ret;
-}
-
-/*
- * return a chunk at least bytes size, as close to offset that we can get.
- */
-static struct btrfs_free_space *tree_search_bytes(struct rb_root *root,
- u64 offset, u64 bytes)
-{
- struct rb_node *n = root->rb_node;
- struct btrfs_free_space *entry, *ret = NULL;
+ if (bitmap_only) {
+ if (!entry)
+ return NULL;
+ if (entry->bitmap)
+ return entry;
- while (n) {
- entry = rb_entry(n, struct btrfs_free_space, bytes_index);
+ /*
+ * bitmap entry and extent entry may share same offset,
+ * in that case, bitmap entry comes after extent entry.
+ */
+ n = rb_next(n);
+ if (!n)
+ return NULL;
+ entry = rb_entry(n, struct btrfs_free_space, offset_index);
+ if (entry->offset != offset)
+ return NULL;
- if (bytes < entry->bytes) {
+ WARN_ON(!entry->bitmap);
+ return entry;
+ } else if (entry) {
+ if (entry->bitmap) {
/*
- * We prefer to get a hole size as close to the size we
- * are asking for so we don't take small slivers out of
- * huge holes, but we also want to get as close to the
- * offset as possible so we don't have a whole lot of
- * fragmentation.
+ * if previous extent entry covers the offset,
+ * we should return it instead of the bitmap entry
*/
- if (offset <= entry->offset) {
- if (!ret)
- ret = entry;
- else if (entry->bytes < ret->bytes)
- ret = entry;
- else if (entry->offset < ret->offset)
- ret = entry;
+ n = &entry->offset_index;
+ while (1) {
+ n = rb_prev(n);
+ if (!n)
+ break;
+ prev = rb_entry(n, struct btrfs_free_space,
+ offset_index);
+ if (!prev->bitmap) {
+ if (prev->offset + prev->bytes > offset)
+ entry = prev;
+ break;
+ }
}
- n = n->rb_left;
- } else if (bytes > entry->bytes) {
- n = n->rb_right;
+ }
+ return entry;
+ }
+
+ if (!prev)
+ return NULL;
+
+ /* find last entry before the 'offset' */
+ entry = prev;
+ if (entry->offset > offset) {
+ n = rb_prev(&entry->offset_index);
+ if (n) {
+ entry = rb_entry(n, struct btrfs_free_space,
+ offset_index);
+ BUG_ON(entry->offset > offset);
} else {
- /*
- * Ok we may have multiple chunks of the wanted size,
- * so we don't want to take the first one we find, we
- * want to take the one closest to our given offset, so
- * keep searching just in case theres a better match.
- */
- n = n->rb_right;
- if (offset > entry->offset)
- continue;
- else if (!ret || entry->offset < ret->offset)
- ret = entry;
+ if (fuzzy)
+ return entry;
+ else
+ return NULL;
}
}
- return ret;
+ if (entry->bitmap) {
+ n = &entry->offset_index;
+ while (1) {
+ n = rb_prev(n);
+ if (!n)
+ break;
+ prev = rb_entry(n, struct btrfs_free_space,
+ offset_index);
+ if (!prev->bitmap) {
+ if (prev->offset + prev->bytes > offset)
+ return prev;
+ break;
+ }
+ }
+ if (entry->offset + BITS_PER_BITMAP *
+ block_group->sectorsize > offset)
+ return entry;
+ } else if (entry->offset + entry->bytes > offset)
+ return entry;
+
+ if (!fuzzy)
+ return NULL;
+
+ while (1) {
+ if (entry->bitmap) {
+ if (entry->offset + BITS_PER_BITMAP *
+ block_group->sectorsize > offset)
+ break;
+ } else {
+ if (entry->offset + entry->bytes > offset)
+ break;
+ }
+
+ n = rb_next(&entry->offset_index);
+ if (!n)
+ return NULL;
+ entry = rb_entry(n, struct btrfs_free_space, offset_index);
+ }
+ return entry;
}
static void unlink_free_space(struct btrfs_block_group_cache *block_group,
struct btrfs_free_space *info)
{
rb_erase(&info->offset_index, &block_group->free_space_offset);
- rb_erase(&info->bytes_index, &block_group->free_space_bytes);
+ block_group->free_extents--;
+ block_group->free_space -= info->bytes;
}
static int link_free_space(struct btrfs_block_group_cache *block_group,
@@ -190,17 +246,314 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
{
int ret = 0;
-
- BUG_ON(!info->bytes);
+ BUG_ON(!info->bitmap && !info->bytes);
ret = tree_insert_offset(&block_group->free_space_offset, info->offset,
- &info->offset_index);
+ &info->offset_index, (info->bitmap != NULL));
if (ret)
return ret;
- ret = tree_insert_bytes(&block_group->free_space_bytes, info->bytes,
- &info->bytes_index);
- if (ret)
- return ret;
+ block_group->free_space += info->bytes;
+ block_group->free_extents++;
+ return ret;
+}
+
+static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
+{
+ u64 max_bytes, possible_bytes;
+
+ /*
+ * The goal is to keep the total amount of memory used per 1gb of space
+ * at or below 32k, so we need to adjust how much memory we allow to be
+ * used by extent based free space tracking
+ */
+ max_bytes = MAX_CACHE_BYTES_PER_GIG *
+ (div64_u64(block_group->key.offset, 1024 * 1024 * 1024));
+
+ possible_bytes = (block_group->total_bitmaps * PAGE_CACHE_SIZE) +
+ (sizeof(struct btrfs_free_space) *
+ block_group->extents_thresh);
+
+ if (possible_bytes > max_bytes) {
+ int extent_bytes = max_bytes -
+ (block_group->total_bitmaps * PAGE_CACHE_SIZE);
+
+ if (extent_bytes <= 0) {
+ block_group->extents_thresh = 0;
+ return;
+ }
+
+ block_group->extents_thresh = extent_bytes /
+ (sizeof(struct btrfs_free_space));
+ }
+}
+
+static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *info, u64 offset,
+ u64 bytes)
+{
+ unsigned long start, end;
+ unsigned long i;
+
+ start = offset_to_bit(info->offset, block_group->sectorsize, offset);
+ end = start + bytes_to_bits(bytes, block_group->sectorsize);
+ BUG_ON(end > BITS_PER_BITMAP);
+
+ for (i = start; i < end; i++)
+ clear_bit(i, info->bitmap);
+
+ info->bytes -= bytes;
+ block_group->free_space -= bytes;
+}
+
+static void bitmap_set_bits(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *info, u64 offset,
+ u64 bytes)
+{
+ unsigned long start, end;
+ unsigned long i;
+
+ start = offset_to_bit(info->offset, block_group->sectorsize, offset);
+ end = start + bytes_to_bits(bytes, block_group->sectorsize);
+ BUG_ON(end > BITS_PER_BITMAP);
+
+ for (i = start; i < end; i++)
+ set_bit(i, info->bitmap);
+
+ info->bytes += bytes;
+ block_group->free_space += bytes;
+}
+
+static int search_bitmap(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *bitmap_info, u64 *offset,
+ u64 *bytes)
+{
+ unsigned long found_bits = 0;
+ unsigned long bits, i;
+ unsigned long next_zero;
+
+ i = offset_to_bit(bitmap_info->offset, block_group->sectorsize,
+ max_t(u64, *offset, bitmap_info->offset));
+ bits = bytes_to_bits(*bytes, block_group->sectorsize);
+
+ for (i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i);
+ i < BITS_PER_BITMAP;
+ i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i + 1)) {
+ next_zero = find_next_zero_bit(bitmap_info->bitmap,
+ BITS_PER_BITMAP, i);
+ if ((next_zero - i) >= bits) {
+ found_bits = next_zero - i;
+ break;
+ }
+ i = next_zero;
+ }
+
+ if (found_bits) {
+ *offset = (u64)(i * block_group->sectorsize) +
+ bitmap_info->offset;
+ *bytes = (u64)(found_bits) * block_group->sectorsize;
+ return 0;
+ }
+
+ return -1;
+}
+
+static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache
+ *block_group, u64 *offset,
+ u64 *bytes, int debug)
+{
+ struct btrfs_free_space *entry;
+ struct rb_node *node;
+ int ret;
+
+ if (!block_group->free_space_offset.rb_node)
+ return NULL;
+
+ entry = tree_search_offset(block_group,
+ offset_to_bitmap(block_group, *offset),
+ 0, 1);
+ if (!entry)
+ return NULL;
+
+ for (node = &entry->offset_index; node; node = rb_next(node)) {
+ entry = rb_entry(node, struct btrfs_free_space, offset_index);
+ if (entry->bytes < *bytes)
+ continue;
+
+ if (entry->bitmap) {
+ ret = search_bitmap(block_group, entry, offset, bytes);
+ if (!ret)
+ return entry;
+ continue;
+ }
+
+ *offset = entry->offset;
+ *bytes = entry->bytes;
+ return entry;
+ }
+
+ return NULL;
+}
+
+static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *info, u64 offset)
+{
+ u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize;
+ int max_bitmaps = (int)div64_u64(block_group->key.offset +
+ bytes_per_bg - 1, bytes_per_bg);
+ BUG_ON(block_group->total_bitmaps >= max_bitmaps);
+
+ info->offset = offset_to_bitmap(block_group, offset);
+ link_free_space(block_group, info);
+ block_group->total_bitmaps++;
+
+ recalculate_thresholds(block_group);
+}
+
+static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *bitmap_info,
+ u64 *offset, u64 *bytes)
+{
+ u64 end;
+
+again:
+ end = bitmap_info->offset +
+ (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1;
+
+ if (*offset > bitmap_info->offset && *offset + *bytes > end) {
+ bitmap_clear_bits(block_group, bitmap_info, *offset,
+ end - *offset + 1);
+ *bytes -= end - *offset + 1;
+ *offset = end + 1;
+ } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
+ bitmap_clear_bits(block_group, bitmap_info, *offset, *bytes);
+ *bytes = 0;
+ }
+
+ if (*bytes) {
+ if (!bitmap_info->bytes) {
+ unlink_free_space(block_group, bitmap_info);
+ kfree(bitmap_info->bitmap);
+ kfree(bitmap_info);
+ block_group->total_bitmaps--;
+ recalculate_thresholds(block_group);
+ }
+
+ bitmap_info = tree_search_offset(block_group,
+ offset_to_bitmap(block_group,
+ *offset),
+ 1, 0);
+ if (!bitmap_info)
+ return -EINVAL;
+
+ if (!bitmap_info->bitmap)
+ return -EAGAIN;
+
+ goto again;
+ } else if (!bitmap_info->bytes) {
+ unlink_free_space(block_group, bitmap_info);
+ kfree(bitmap_info->bitmap);
+ kfree(bitmap_info);
+ block_group->total_bitmaps--;
+ recalculate_thresholds(block_group);
+ }
+
+ return 0;
+}
+
+static int insert_into_bitmap(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *info)
+{
+ struct btrfs_free_space *bitmap_info;
+ int added = 0;
+ u64 bytes, offset, end;
+ int ret;
+
+ /*
+ * If we are below the extents threshold then we can add this as an
+ * extent, and don't have to deal with the bitmap
+ */
+ if (block_group->free_extents < block_group->extents_thresh &&
+ info->bytes > block_group->sectorsize * 4)
+ return 0;
+
+ /*
+ * some block groups are so tiny they can't be enveloped by a bitmap, so
+ * don't even bother to create a bitmap for this
+ */
+ if (BITS_PER_BITMAP * block_group->sectorsize >
+ block_group->key.offset)
+ return 0;
+
+ bytes = info->bytes;
+ offset = info->offset;
+
+again:
+ bitmap_info = tree_search_offset(block_group,
+ offset_to_bitmap(block_group, offset),
+ 1, 0);
+ if (!bitmap_info) {
+ BUG_ON(added);
+ goto new_bitmap;
+ }
+
+ end = bitmap_info->offset +
+ (u64)(BITS_PER_BITMAP * block_group->sectorsize);
+
+ if (offset >= bitmap_info->offset && offset + bytes > end) {
+ bitmap_set_bits(block_group, bitmap_info, offset,
+ end - offset);
+ bytes -= end - offset;
+ offset = end;
+ added = 0;
+ } else if (offset >= bitmap_info->offset && offset + bytes <= end) {
+ bitmap_set_bits(block_group, bitmap_info, offset, bytes);
+ bytes = 0;
+ } else {
+ BUG();
+ }
+
+ if (!bytes) {
+ ret = 1;
+ goto out;
+ } else
+ goto again;
+
+new_bitmap:
+ if (info && info->bitmap) {
+ add_new_bitmap(block_group, info, offset);
+ added = 1;
+ info = NULL;
+ goto again;
+ } else {
+ spin_unlock(&block_group->tree_lock);
+
+ /* no pre-allocated info, allocate a new one */
+ if (!info) {
+ info = kzalloc(sizeof(struct btrfs_free_space),
+ GFP_NOFS);
+ if (!info) {
+ spin_lock(&block_group->tree_lock);
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ /* allocate the bitmap */
+ info->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
+ spin_lock(&block_group->tree_lock);
+ if (!info->bitmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ goto again;
+ }
+
+out:
+ if (info) {
+ if (info->bitmap)
+ kfree(info->bitmap);
+ kfree(info);
+ }
return ret;
}
@@ -208,8 +561,8 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
u64 offset, u64 bytes)
{
- struct btrfs_free_space *right_info;
- struct btrfs_free_space *left_info;
+ struct btrfs_free_space *right_info = NULL;
+ struct btrfs_free_space *left_info = NULL;
struct btrfs_free_space *info = NULL;
int ret = 0;
@@ -227,18 +580,38 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
* are adding, if there is remove that struct and add a new one to
* cover the entire range
*/
- right_info = tree_search_offset(&block_group->free_space_offset,
- offset+bytes, 0, 0);
- left_info = tree_search_offset(&block_group->free_space_offset,
- offset-1, 0, 1);
+ right_info = tree_search_offset(block_group, offset + bytes, 0, 0);
+ if (right_info && rb_prev(&right_info->offset_index))
+ left_info = rb_entry(rb_prev(&right_info->offset_index),
+ struct btrfs_free_space, offset_index);
+ else
+ left_info = tree_search_offset(block_group, offset - 1, 0, 0);
- if (right_info) {
+ /*
+ * If there was no extent directly to the left or right of this new
+ * extent then we know we're going to have to allocate a new extent, so
+ * before we do that see if we need to drop this into a bitmap
+ */
+ if ((!left_info || left_info->bitmap) &&
+ (!right_info || right_info->bitmap)) {
+ ret = insert_into_bitmap(block_group, info);
+
+ if (ret < 0) {
+ goto out;
+ } else if (ret) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ if (right_info && !right_info->bitmap) {
unlink_free_space(block_group, right_info);
info->bytes += right_info->bytes;
kfree(right_info);
}
- if (left_info && left_info->offset + left_info->bytes == offset) {
+ if (left_info && !left_info->bitmap &&
+ left_info->offset + left_info->bytes == offset) {
unlink_free_space(block_group, left_info);
info->offset = left_info->offset;
info->bytes += left_info->bytes;
@@ -248,11 +621,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
ret = link_free_space(block_group, info);
if (ret)
kfree(info);
-
+out:
spin_unlock(&block_group->tree_lock);
if (ret) {
- printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret);
+ printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret);
BUG_ON(ret == -EEXIST);
}
@@ -263,40 +636,65 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
u64 offset, u64 bytes)
{
struct btrfs_free_space *info;
+ struct btrfs_free_space *next_info = NULL;
int ret = 0;
spin_lock(&block_group->tree_lock);
- info = tree_search_offset(&block_group->free_space_offset, offset, 0,
- 1);
- if (info && info->offset == offset) {
- if (info->bytes < bytes) {
- printk(KERN_ERR "Found free space at %llu, size %llu,"
- "trying to use %llu\n",
- (unsigned long long)info->offset,
- (unsigned long long)info->bytes,
- (unsigned long long)bytes);
+again:
+ info = tree_search_offset(block_group, offset, 0, 0);
+ if (!info) {
+ WARN_ON(1);
+ goto out_lock;
+ }
+
+ if (info->bytes < bytes && rb_next(&info->offset_index)) {
+ u64 end;
+ next_info = rb_entry(rb_next(&info->offset_index),
+ struct btrfs_free_space,
+ offset_index);
+
+ if (next_info->bitmap)
+ end = next_info->offset + BITS_PER_BITMAP *
+ block_group->sectorsize - 1;
+ else
+ end = next_info->offset + next_info->bytes;
+
+ if (next_info->bytes < bytes ||
+ next_info->offset > offset || offset > end) {
+ printk(KERN_CRIT "Found free space at %llu, size %llu,"
+ " trying to use %llu\n",
+ (unsigned long long)info->offset,
+ (unsigned long long)info->bytes,
+ (unsigned long long)bytes);
WARN_ON(1);
ret = -EINVAL;
- spin_unlock(&block_group->tree_lock);
- goto out;
+ goto out_lock;
}
- unlink_free_space(block_group, info);
- if (info->bytes == bytes) {
- kfree(info);
- spin_unlock(&block_group->tree_lock);
- goto out;
+ info = next_info;
+ }
+
+ if (info->bytes == bytes) {
+ unlink_free_space(block_group, info);
+ if (info->bitmap) {
+ kfree(info->bitmap);
+ block_group->total_bitmaps--;
}
+ kfree(info);
+ goto out_lock;
+ }
+ if (!info->bitmap && info->offset == offset) {
+ unlink_free_space(block_group, info);
info->offset += bytes;
info->bytes -= bytes;
+ link_free_space(block_group, info);
+ goto out_lock;
+ }
- ret = link_free_space(block_group, info);
- spin_unlock(&block_group->tree_lock);
- BUG_ON(ret);
- } else if (info && info->offset < offset &&
- info->offset + info->bytes >= offset + bytes) {
+ if (!info->bitmap && info->offset <= offset &&
+ info->offset + info->bytes >= offset + bytes) {
u64 old_start = info->offset;
/*
* we're freeing space in the middle of the info,
@@ -312,7 +710,9 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
info->offset = offset + bytes;
info->bytes = old_end - info->offset;
ret = link_free_space(block_group, info);
- BUG_ON(ret);
+ WARN_ON(ret);
+ if (ret)
+ goto out_lock;
} else {
/* the hole we're creating ends at the end
* of the info struct, just free the info
@@ -320,32 +720,22 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
kfree(info);
}
spin_unlock(&block_group->tree_lock);
- /* step two, insert a new info struct to cover anything
- * before the hole
+
+ /* step two, insert a new info struct to cover
+ * anything before the hole
*/
ret = btrfs_add_free_space(block_group, old_start,
offset - old_start);
- BUG_ON(ret);
- } else {
- spin_unlock(&block_group->tree_lock);
- if (!info) {
- printk(KERN_ERR "couldn't find space %llu to free\n",
- (unsigned long long)offset);
- printk(KERN_ERR "cached is %d, offset %llu bytes %llu\n",
- block_group->cached,
- (unsigned long long)block_group->key.objectid,
- (unsigned long long)block_group->key.offset);
- btrfs_dump_free_space(block_group, bytes);
- } else if (info) {
- printk(KERN_ERR "hmm, found offset=%llu bytes=%llu, "
- "but wanted offset=%llu bytes=%llu\n",
- (unsigned long long)info->offset,
- (unsigned long long)info->bytes,
- (unsigned long long)offset,
- (unsigned long long)bytes);
- }
- WARN_ON(1);
+ WARN_ON(ret);
+ goto out;
}
+
+ ret = remove_from_bitmap(block_group, info, &offset, &bytes);
+ if (ret == -EAGAIN)
+ goto again;
+ BUG_ON(ret);
+out_lock:
+ spin_unlock(&block_group->tree_lock);
out:
return ret;
}
@@ -361,10 +751,13 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
info = rb_entry(n, struct btrfs_free_space, offset_index);
if (info->bytes >= bytes)
count++;
- printk(KERN_ERR "entry offset %llu, bytes %llu\n",
+ printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n",
(unsigned long long)info->offset,
- (unsigned long long)info->bytes);
+ (unsigned long long)info->bytes,
+ (info->bitmap) ? "yes" : "no");
}
+ printk(KERN_INFO "block group has cluster?: %s\n",
+ list_empty(&block_group->cluster_list) ? "no" : "yes");
printk(KERN_INFO "%d blocks of free space at or bigger than bytes is"
"\n", count);
}
@@ -397,26 +790,35 @@ __btrfs_return_cluster_to_free_space(
{
struct btrfs_free_space *entry;
struct rb_node *node;
+ bool bitmap;
spin_lock(&cluster->lock);
if (cluster->block_group != block_group)
goto out;
+ bitmap = cluster->points_to_bitmap;
+ cluster->block_group = NULL;
cluster->window_start = 0;
+ list_del_init(&cluster->block_group_list);
+ cluster->points_to_bitmap = false;
+
+ if (bitmap)
+ goto out;
+
node = rb_first(&cluster->root);
- while(node) {
+ while (node) {
entry = rb_entry(node, struct btrfs_free_space, offset_index);
node = rb_next(&entry->offset_index);
rb_erase(&entry->offset_index, &cluster->root);
- link_free_space(block_group, entry);
+ BUG_ON(entry->bitmap);
+ tree_insert_offset(&block_group->free_space_offset,
+ entry->offset, &entry->offset_index, 0);
}
- list_del_init(&cluster->block_group_list);
-
- btrfs_put_block_group(cluster->block_group);
- cluster->block_group = NULL;
cluster->root.rb_node = NULL;
+
out:
spin_unlock(&cluster->lock);
+ btrfs_put_block_group(block_group);
return 0;
}
@@ -425,20 +827,28 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
struct btrfs_free_space *info;
struct rb_node *node;
struct btrfs_free_cluster *cluster;
- struct btrfs_free_cluster *safe;
+ struct list_head *head;
spin_lock(&block_group->tree_lock);
-
- list_for_each_entry_safe(cluster, safe, &block_group->cluster_list,
- block_group_list) {
+ while ((head = block_group->cluster_list.next) !=
+ &block_group->cluster_list) {
+ cluster = list_entry(head, struct btrfs_free_cluster,
+ block_group_list);
WARN_ON(cluster->block_group != block_group);
__btrfs_return_cluster_to_free_space(block_group, cluster);
+ if (need_resched()) {
+ spin_unlock(&block_group->tree_lock);
+ cond_resched();
+ spin_lock(&block_group->tree_lock);
+ }
}
- while ((node = rb_last(&block_group->free_space_bytes)) != NULL) {
- info = rb_entry(node, struct btrfs_free_space, bytes_index);
+ while ((node = rb_last(&block_group->free_space_offset)) != NULL) {
+ info = rb_entry(node, struct btrfs_free_space, offset_index);
unlink_free_space(block_group, info);
+ if (info->bitmap)
+ kfree(info->bitmap);
kfree(info);
if (need_resched()) {
spin_unlock(&block_group->tree_lock);
@@ -446,6 +856,7 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
spin_lock(&block_group->tree_lock);
}
}
+
spin_unlock(&block_group->tree_lock);
}
@@ -453,25 +864,35 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
u64 offset, u64 bytes, u64 empty_size)
{
struct btrfs_free_space *entry = NULL;
+ u64 bytes_search = bytes + empty_size;
u64 ret = 0;
spin_lock(&block_group->tree_lock);
- entry = tree_search_offset(&block_group->free_space_offset, offset,
- bytes + empty_size, 1);
+ entry = find_free_space(block_group, &offset, &bytes_search, 0);
if (!entry)
- entry = tree_search_bytes(&block_group->free_space_bytes,
- offset, bytes + empty_size);
- if (entry) {
+ goto out;
+
+ ret = offset;
+ if (entry->bitmap) {
+ bitmap_clear_bits(block_group, entry, offset, bytes);
+ if (!entry->bytes) {
+ unlink_free_space(block_group, entry);
+ kfree(entry->bitmap);
+ kfree(entry);
+ block_group->total_bitmaps--;
+ recalculate_thresholds(block_group);
+ }
+ } else {
unlink_free_space(block_group, entry);
- ret = entry->offset;
entry->offset += bytes;
entry->bytes -= bytes;
-
if (!entry->bytes)
kfree(entry);
else
link_free_space(block_group, entry);
}
+
+out:
spin_unlock(&block_group->tree_lock);
return ret;
@@ -517,6 +938,47 @@ int btrfs_return_cluster_to_free_space(
return ret;
}
+static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_cluster *cluster,
+ u64 bytes, u64 min_start)
+{
+ struct btrfs_free_space *entry;
+ int err;
+ u64 search_start = cluster->window_start;
+ u64 search_bytes = bytes;
+ u64 ret = 0;
+
+ spin_lock(&block_group->tree_lock);
+ spin_lock(&cluster->lock);
+
+ if (!cluster->points_to_bitmap)
+ goto out;
+
+ if (cluster->block_group != block_group)
+ goto out;
+
+ entry = tree_search_offset(block_group, search_start, 0, 0);
+
+ if (!entry || !entry->bitmap)
+ goto out;
+
+ search_start = min_start;
+ search_bytes = bytes;
+
+ err = search_bitmap(block_group, entry, &search_start,
+ &search_bytes);
+ if (err)
+ goto out;
+
+ ret = search_start;
+ bitmap_clear_bits(block_group, entry, ret, bytes);
+out:
+ spin_unlock(&cluster->lock);
+ spin_unlock(&block_group->tree_lock);
+
+ return ret;
+}
+
/*
* given a cluster, try to allocate 'bytes' from it, returns 0
* if it couldn't find anything suitably large, or a logical disk offset
@@ -530,6 +992,10 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
struct rb_node *node;
u64 ret = 0;
+ if (cluster->points_to_bitmap)
+ return btrfs_alloc_from_bitmap(block_group, cluster, bytes,
+ min_start);
+
spin_lock(&cluster->lock);
if (bytes > cluster->max_size)
goto out;
@@ -567,9 +1033,73 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
}
out:
spin_unlock(&cluster->lock);
+
return ret;
}
+static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
+ struct btrfs_free_space *entry,
+ struct btrfs_free_cluster *cluster,
+ u64 offset, u64 bytes, u64 min_bytes)
+{
+ unsigned long next_zero;
+ unsigned long i;
+ unsigned long search_bits;
+ unsigned long total_bits;
+ unsigned long found_bits;
+ unsigned long start = 0;
+ unsigned long total_found = 0;
+ bool found = false;
+
+ i = offset_to_bit(entry->offset, block_group->sectorsize,
+ max_t(u64, offset, entry->offset));
+ search_bits = bytes_to_bits(min_bytes, block_group->sectorsize);
+ total_bits = bytes_to_bits(bytes, block_group->sectorsize);
+
+again:
+ found_bits = 0;
+ for (i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i);
+ i < BITS_PER_BITMAP;
+ i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) {
+ next_zero = find_next_zero_bit(entry->bitmap,
+ BITS_PER_BITMAP, i);
+ if (next_zero - i >= search_bits) {
+ found_bits = next_zero - i;
+ break;
+ }
+ i = next_zero;
+ }
+
+ if (!found_bits)
+ return -1;
+
+ if (!found) {
+ start = i;
+ found = true;
+ }
+
+ total_found += found_bits;
+
+ if (cluster->max_size < found_bits * block_group->sectorsize)
+ cluster->max_size = found_bits * block_group->sectorsize;
+
+ if (total_found < total_bits) {
+ i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, next_zero);
+ if (i - start > total_bits * 2) {
+ total_found = 0;
+ cluster->max_size = 0;
+ found = false;
+ }
+ goto again;
+ }
+
+ cluster->window_start = start * block_group->sectorsize +
+ entry->offset;
+ cluster->points_to_bitmap = true;
+
+ return 0;
+}
+
/*
* here we try to find a cluster of blocks in a block group. The goal
* is to find at least bytes free and up to empty_size + bytes free.
@@ -587,12 +1117,12 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
struct btrfs_free_space *entry = NULL;
struct rb_node *node;
struct btrfs_free_space *next;
- struct btrfs_free_space *last;
+ struct btrfs_free_space *last = NULL;
u64 min_bytes;
u64 window_start;
u64 window_free;
u64 max_extent = 0;
- int total_retries = 0;
+ bool found_bitmap = false;
int ret;
/* for metadata, allow allocates with more holes */
@@ -620,31 +1150,80 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
goto out;
}
again:
- min_bytes = min(min_bytes, bytes + empty_size);
- entry = tree_search_bytes(&block_group->free_space_bytes,
- offset, min_bytes);
+ entry = tree_search_offset(block_group, offset, found_bitmap, 1);
if (!entry) {
ret = -ENOSPC;
goto out;
}
+
+ /*
+ * If found_bitmap is true, we exhausted our search for extent entries,
+ * and we just want to search all of the bitmaps that we can find, and
+ * ignore any extent entries we find.
+ */
+ while (entry->bitmap || found_bitmap ||
+ (!entry->bitmap && entry->bytes < min_bytes)) {
+ struct rb_node *node = rb_next(&entry->offset_index);
+
+ if (entry->bitmap && entry->bytes > bytes + empty_size) {
+ ret = btrfs_bitmap_cluster(block_group, entry, cluster,
+ offset, bytes + empty_size,
+ min_bytes);
+ if (!ret)
+ goto got_it;
+ }
+
+ if (!node) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ entry = rb_entry(node, struct btrfs_free_space, offset_index);
+ }
+
+ /*
+ * We already searched all the extent entries from the passed in offset
+ * to the end and didn't find enough space for the cluster, and we also
+ * didn't find any bitmaps that met our criteria, just go ahead and exit
+ */
+ if (found_bitmap) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ cluster->points_to_bitmap = false;
window_start = entry->offset;
window_free = entry->bytes;
last = entry;
max_extent = entry->bytes;
- while(1) {
+ while (1) {
/* out window is just right, lets fill it */
if (window_free >= bytes + empty_size)
break;
node = rb_next(&last->offset_index);
if (!node) {
+ if (found_bitmap)
+ goto again;
ret = -ENOSPC;
goto out;
}
next = rb_entry(node, struct btrfs_free_space, offset_index);
/*
+ * we found a bitmap, so if this search doesn't result in a
+ * cluster, we know to go and search again for the bitmaps and
+ * start looking for space there
+ */
+ if (next->bitmap) {
+ if (!found_bitmap)
+ offset = next->offset;
+ found_bitmap = true;
+ last = next;
+ continue;
+ }
+
+ /*
* we haven't filled the empty size and the window is
* very large. reset and try again
*/
@@ -655,19 +1234,6 @@ again:
window_free = entry->bytes;
last = entry;
max_extent = 0;
- total_retries++;
- if (total_retries % 64 == 0) {
- if (min_bytes >= (bytes + empty_size)) {
- ret = -ENOSPC;
- goto out;
- }
- /*
- * grow our allocation a bit, we're not having
- * much luck
- */
- min_bytes *= 2;
- goto again;
- }
} else {
last = next;
window_free += next->bytes;
@@ -685,11 +1251,19 @@ again:
* The cluster includes an rbtree, but only uses the offset index
* of each free space cache entry.
*/
- while(1) {
+ while (1) {
node = rb_next(&entry->offset_index);
- unlink_free_space(block_group, entry);
+ if (entry->bitmap && node) {
+ entry = rb_entry(node, struct btrfs_free_space,
+ offset_index);
+ continue;
+ } else if (entry->bitmap && !node) {
+ break;
+ }
+
+ rb_erase(&entry->offset_index, &block_group->free_space_offset);
ret = tree_insert_offset(&cluster->root, entry->offset,
- &entry->offset_index);
+ &entry->offset_index, 0);
BUG_ON(ret);
if (!node || entry == last)
@@ -697,8 +1271,10 @@ again:
entry = rb_entry(node, struct btrfs_free_space, offset_index);
}
- ret = 0;
+
cluster->max_size = max_extent;
+got_it:
+ ret = 0;
atomic_inc(&block_group->count);
list_add_tail(&cluster->block_group_list, &block_group->cluster_list);
cluster->block_group = block_group;
@@ -718,6 +1294,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
spin_lock_init(&cluster->refill_lock);
cluster->root.rb_node = NULL;
cluster->max_size = 0;
+ cluster->points_to_bitmap = false;
INIT_LIST_HEAD(&cluster->block_group_list);
cluster->block_group = NULL;
}
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index 266fb8764054..890a8e79011b 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -19,6 +19,14 @@
#ifndef __BTRFS_FREE_SPACE_CACHE
#define __BTRFS_FREE_SPACE_CACHE
+struct btrfs_free_space {
+ struct rb_node offset_index;
+ u64 offset;
+ u64 bytes;
+ unsigned long *bitmap;
+ struct list_head list;
+};
+
int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
u64 bytenr, u64 size);
int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 791eab19e330..56fe83fa60c4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2603,8 +2603,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
if (root->ref_cows)
btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
path = btrfs_alloc_path();
- path->reada = -1;
BUG_ON(!path);
+ path->reada = -1;
/* FIXME, add redo link to tree so we don't leak on crash */
key.objectid = inode->i_ino;
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index 6d6523da0a30..0d126be22b63 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -309,7 +309,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
}
printk(KERN_INFO "node %llu level %d total ptrs %d free spc %u\n",
(unsigned long long)btrfs_header_bytenr(c),
- btrfs_header_level(c), nr,
+ level, nr,
(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr);
for (i = 0; i < nr; i++) {
btrfs_node_key_to_cpu(c, &key, i);
@@ -326,10 +326,10 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
btrfs_level_size(root, level - 1),
btrfs_node_ptr_generation(c, i));
if (btrfs_is_leaf(next) &&
- btrfs_header_level(c) != 1)
+ level != 1)
BUG();
if (btrfs_header_level(next) !=
- btrfs_header_level(c) - 1)
+ level - 1)
BUG();
btrfs_print_tree(root, next);
free_extent_buffer(next);
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 008397934778..e71264d1c2c9 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -670,6 +670,8 @@ again:
err = ret;
goto out;
}
+ if (ret > 0 && path2->slots[level] > 0)
+ path2->slots[level]--;
eb = path2->nodes[level];
WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) !=
@@ -1609,6 +1611,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
BUG_ON(level == 0);
path->lowest_level = level;
ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0);
+ path->lowest_level = 0;
if (ret < 0) {
btrfs_free_path(path);
return ret;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 2dbf1c1f56ee..cdbb5022da52 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -40,6 +40,12 @@ static noinline void put_transaction(struct btrfs_transaction *transaction)
}
}
+static noinline void switch_commit_root(struct btrfs_root *root)
+{
+ free_extent_buffer(root->commit_root);
+ root->commit_root = btrfs_root_node(root);
+}
+
/*
* either allocate a new transaction or hop into the existing one
*/
@@ -444,9 +450,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
btrfs_write_dirty_block_groups(trans, root);
- ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
- BUG_ON(ret);
-
while (1) {
old_root_bytenr = btrfs_root_bytenr(&root->root_item);
if (old_root_bytenr == root->node->start)
@@ -457,13 +460,14 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
&root->root_key,
&root->root_item);
BUG_ON(ret);
- btrfs_write_dirty_block_groups(trans, root);
- ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+ ret = btrfs_write_dirty_block_groups(trans, root);
BUG_ON(ret);
}
- free_extent_buffer(root->commit_root);
- root->commit_root = btrfs_root_node(root);
+
+ if (root != root->fs_info->extent_root)
+ switch_commit_root(root);
+
return 0;
}
@@ -495,10 +499,12 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
root = list_entry(next, struct btrfs_root, dirty_list);
update_cowonly_root(trans, root);
-
- ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
- BUG_ON(ret);
}
+
+ down_write(&fs_info->extent_commit_sem);
+ switch_commit_root(fs_info->extent_root);
+ up_write(&fs_info->extent_commit_sem);
+
return 0;
}
@@ -544,8 +550,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
btrfs_update_reloc_root(trans, root);
if (root->commit_root != root->node) {
- free_extent_buffer(root->commit_root);
- root->commit_root = btrfs_root_node(root);
+ switch_commit_root(root);
btrfs_set_root_node(&root->root_item,
root->node);
}
@@ -852,6 +857,16 @@ static void update_super_roots(struct btrfs_root *root)
super->root_level = root_item->level;
}
+int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
+{
+ int ret = 0;
+ spin_lock(&info->new_trans_lock);
+ if (info->running_transaction)
+ ret = info->running_transaction->in_commit;
+ spin_unlock(&info->new_trans_lock);
+ return ret;
+}
+
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
@@ -943,9 +958,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_unlock(&root->fs_info->trans_mutex);
- if (flush_on_commit || snap_pending) {
- if (flush_on_commit)
- btrfs_start_delalloc_inodes(root);
+ if (flush_on_commit) {
+ btrfs_start_delalloc_inodes(root);
+ ret = btrfs_wait_ordered_extents(root, 0);
+ BUG_ON(ret);
+ } else if (snap_pending) {
ret = btrfs_wait_ordered_extents(root, 1);
BUG_ON(ret);
}
@@ -1009,15 +1026,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
btrfs_set_root_node(&root->fs_info->tree_root->root_item,
root->fs_info->tree_root->node);
- free_extent_buffer(root->fs_info->tree_root->commit_root);
- root->fs_info->tree_root->commit_root =
- btrfs_root_node(root->fs_info->tree_root);
+ switch_commit_root(root->fs_info->tree_root);
btrfs_set_root_node(&root->fs_info->chunk_root->root_item,
root->fs_info->chunk_root->node);
- free_extent_buffer(root->fs_info->chunk_root->commit_root);
- root->fs_info->chunk_root->commit_root =
- btrfs_root_node(root->fs_info->chunk_root);
+ switch_commit_root(root->fs_info->chunk_root);
update_super_roots(root);
@@ -1057,6 +1070,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
cur_trans->commit_done = 1;
root->fs_info->last_trans_committed = cur_trans->transid;
+
wake_up(&cur_trans->commit_wait);
put_transaction(cur_trans);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 961c3ee5a2e1..663c67404918 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -107,4 +107,5 @@ 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_transaction_in_commit(struct btrfs_fs_info *info);
#endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index c13922206d1b..d91b0de7c502 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -797,7 +797,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
return -ENOENT;
inode = read_one_inode(root, key->objectid);
- BUG_ON(!dir);
+ BUG_ON(!inode);
ref_ptr = btrfs_item_ptr_offset(eb, slot);
ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 3ab80e9cd767..5cf405b0828d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -260,7 +260,7 @@ loop_lock:
num_run++;
batch_run++;
- if (bio_sync(cur))
+ if (bio_rw_flagged(cur, BIO_RW_SYNCIO))
num_sync_run++;
if (need_resched()) {
@@ -721,7 +721,8 @@ error:
*/
static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
- u64 num_bytes, u64 *start)
+ u64 num_bytes, u64 *start,
+ u64 *max_avail)
{
struct btrfs_key key;
struct btrfs_root *root = device->dev_root;
@@ -758,9 +759,13 @@ static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
if (ret < 0)
goto error;
- ret = btrfs_previous_item(root, path, 0, key.type);
- if (ret < 0)
- goto error;
+ if (ret > 0) {
+ ret = btrfs_previous_item(root, path, key.objectid, key.type);
+ if (ret < 0)
+ goto error;
+ if (ret > 0)
+ start_found = 1;
+ }
l = path->nodes[0];
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
while (1) {
@@ -803,6 +808,10 @@ no_more_items:
if (last_byte < search_start)
last_byte = search_start;
hole_size = key.offset - last_byte;
+
+ if (hole_size > *max_avail)
+ *max_avail = hole_size;
+
if (key.offset > last_byte &&
hole_size >= num_bytes) {
*start = last_byte;
@@ -1621,6 +1630,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
device->fs_devices->total_rw_bytes += diff;
device->total_bytes = new_size;
+ device->disk_total_bytes = new_size;
btrfs_clear_space_info_full(device->dev_root->fs_info);
return btrfs_update_device(trans, device);
@@ -2007,7 +2017,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
goto done;
if (ret) {
ret = 0;
- goto done;
+ break;
}
l = path->nodes[0];
@@ -2015,7 +2025,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
if (key.objectid != device->devid)
- goto done;
+ break;
dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
length = btrfs_dev_extent_length(l, dev_extent);
@@ -2171,6 +2181,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_chunk_size);
again:
+ max_avail = 0;
if (!map || map->num_stripes != num_stripes) {
kfree(map);
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
@@ -2219,7 +2230,8 @@ again:
if (device->in_fs_metadata && avail >= min_free) {
ret = find_free_dev_extent(trans, device,
- min_free, &dev_offset);
+ min_free, &dev_offset,
+ &max_avail);
if (ret == 0) {
list_move_tail(&device->dev_alloc_list,
&private_devs);
@@ -2795,26 +2807,6 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
}
}
- for (i = 0; i > nr; i++) {
- struct btrfs_multi_bio *multi;
- struct btrfs_bio_stripe *stripe;
- int ret;
-
- length = 1;
- ret = btrfs_map_block(map_tree, WRITE, buf[i],
- &length, &multi, 0);
- BUG_ON(ret);
-
- stripe = multi->stripes;
- for (j = 0; j < multi->num_stripes; j++) {
- if (stripe->physical >= physical &&
- physical < stripe->physical + length)
- break;
- }
- BUG_ON(j >= multi->num_stripes);
- kfree(multi);
- }
-
*logical = buf;
*naddrs = nr;
*stripe_len = map->stripe_len;
@@ -2911,7 +2903,7 @@ static noinline int schedule_bio(struct btrfs_root *root,
bio->bi_rw |= rw;
spin_lock(&device->io_lock);
- if (bio_sync(bio))
+ if (bio_rw_flagged(bio, BIO_RW_SYNCIO))
pending_bios = &device->pending_sync_bios;
else
pending_bios = &device->pending_bios;
diff --git a/fs/buffer.c b/fs/buffer.c
index a3ef091a45bd..2a01b2bc27ba 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -281,7 +281,7 @@ static void free_more_memory(void)
struct zone *zone;
int nid;
- wakeup_pdflush(1024);
+ wakeup_flusher_threads(1024);
yield();
for_each_online_node(nid) {
diff --git a/fs/char_dev.c b/fs/char_dev.c
index a173551e19d7..7c27a8ebef6a 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -31,6 +31,7 @@
* - no readahead or I/O queue unplugging required
*/
struct backing_dev_info directly_mappable_cdev_bdi = {
+ .name = "char",
.capabilities = (
#ifdef CONFIG_MMU
/* permit private copies of the data to be taken */
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 92888aa90749..651cefde385b 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.60
+-------------
+Fix memory leak in reconnect. Fix oops in DFS mount error path.
+Set s_maxbytes to smaller (the max that vfs can handle) so that
+sendfile will now work over cifs mounts again.
+
Version 1.59
------------
Client uses server inode numbers (which are persistent) rather than
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 3bb11be8b6a8..606912d8f2a8 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -55,7 +55,7 @@ void cifs_dfs_release_automount_timer(void)
* i.e. strips from UNC trailing path that is not part of share
* name and fixup missing '\' in the begining of DFS node refferal
* if neccessary.
- * Returns pointer to share name on success or NULL on error.
+ * Returns pointer to share name on success or ERR_PTR on error.
* Caller is responsible for freeing returned string.
*/
static char *cifs_get_share_name(const char *node_name)
@@ -68,7 +68,7 @@ static char *cifs_get_share_name(const char *node_name)
UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
GFP_KERNEL);
if (!UNC)
- return NULL;
+ return ERR_PTR(-ENOMEM);
/* get share name and server name */
if (node_name[1] != '\\') {
@@ -87,7 +87,7 @@ static char *cifs_get_share_name(const char *node_name)
cERROR(1, ("%s: no server name end in node name: %s",
__func__, node_name));
kfree(UNC);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
/* find sharename end */
@@ -133,6 +133,12 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
return ERR_PTR(-EINVAL);
*devname = cifs_get_share_name(ref->node_name);
+ if (IS_ERR(*devname)) {
+ rc = PTR_ERR(*devname);
+ *devname = NULL;
+ goto compose_mount_options_err;
+ }
+
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
if (rc != 0) {
cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 9bb5c8750736..1f3345d7fa79 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -803,6 +803,10 @@ cifs_parse_mount_options(char *options, const char *devname,
char *data;
unsigned int temp_len, i, j;
char separator[2];
+ short int override_uid = -1;
+ short int override_gid = -1;
+ bool uid_specified = false;
+ bool gid_specified = false;
separator[0] = ',';
separator[1] = 0;
@@ -1093,18 +1097,20 @@ cifs_parse_mount_options(char *options, const char *devname,
"too long.\n");
return 1;
}
- } else if (strnicmp(data, "uid", 3) == 0) {
- if (value && *value)
- vol->linux_uid =
- simple_strtoul(value, &value, 0);
- } else if (strnicmp(data, "forceuid", 8) == 0) {
- vol->override_uid = 1;
- } else if (strnicmp(data, "gid", 3) == 0) {
- if (value && *value)
- vol->linux_gid =
- simple_strtoul(value, &value, 0);
- } else if (strnicmp(data, "forcegid", 8) == 0) {
- vol->override_gid = 1;
+ } else if (!strnicmp(data, "uid", 3) && value && *value) {
+ vol->linux_uid = simple_strtoul(value, &value, 0);
+ uid_specified = true;
+ } else if (!strnicmp(data, "forceuid", 8)) {
+ override_uid = 1;
+ } else if (!strnicmp(data, "noforceuid", 10)) {
+ override_uid = 0;
+ } else if (!strnicmp(data, "gid", 3) && value && *value) {
+ vol->linux_gid = simple_strtoul(value, &value, 0);
+ gid_specified = true;
+ } else if (!strnicmp(data, "forcegid", 8)) {
+ override_gid = 1;
+ } else if (!strnicmp(data, "noforcegid", 10)) {
+ override_gid = 0;
} else if (strnicmp(data, "file_mode", 4) == 0) {
if (value && *value) {
vol->file_mode =
@@ -1355,6 +1361,18 @@ cifs_parse_mount_options(char *options, const char *devname,
if (vol->UNCip == NULL)
vol->UNCip = &vol->UNC[2];
+ if (uid_specified)
+ vol->override_uid = override_uid;
+ else if (override_uid == 1)
+ printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
+ "specified with no uid= option.\n");
+
+ if (gid_specified)
+ vol->override_gid = override_gid;
+ else if (override_gid == 1)
+ printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
+ "specified with no gid= option.\n");
+
return 0;
}
@@ -2452,10 +2470,10 @@ try_mount_again:
tcon->local_lease = volume_info->local_lease;
}
if (pSesInfo) {
- if (pSesInfo->capabilities & CAP_LARGE_FILES) {
- sb->s_maxbytes = (u64) 1 << 63;
- } else
- sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
+ if (pSesInfo->capabilities & CAP_LARGE_FILES)
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+ else
+ sb->s_maxbytes = MAX_NON_LFS;
}
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
@@ -2544,11 +2562,20 @@ remote_path_check:
if (mount_data != mount_data_global)
kfree(mount_data);
+
mount_data = cifs_compose_mount_options(
cifs_sb->mountdata, full_path + 1,
referrals, &fake_devname);
- kfree(fake_devname);
+
free_dfs_info_array(referrals, num_referrals);
+ kfree(fake_devname);
+ kfree(full_path);
+
+ if (IS_ERR(mount_data)) {
+ rc = PTR_ERR(mount_data);
+ mount_data = NULL;
+ goto mount_fail_check;
+ }
if (tcon)
cifs_put_tcon(tcon);
@@ -2556,8 +2583,6 @@ remote_path_check:
cifs_put_smb_ses(pSesInfo);
cleanup_volume_info(&volume_info);
- FreeXid(xid);
- kfree(full_path);
referral_walks_count++;
goto try_mount_again;
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 18afe57b2461..82d83839655e 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -212,7 +212,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
* junction to the new submount (ie to setup the fake directory
* which represents a DFS referral).
*/
-void
+static void
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -388,7 +388,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
}
/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
-void
+static void
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
struct cifs_sb_info *cifs_sb, bool adjust_tz)
{
@@ -513,9 +513,12 @@ int cifs_get_inode_info(struct inode **pinode,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc1) {
- /* BB EOPNOSUPP disable SERVER_INUM? */
cFYI(1, ("GetSrvInodeNum rc %d", rc1));
fattr.cf_uniqueid = iunique(sb, ROOT_I);
+ /* disable serverino if call not supported */
+ if (rc1 == -EINVAL)
+ cifs_sb->mnt_cifs_flags &=
+ ~CIFS_MOUNT_SERVER_INUM;
}
} else {
fattr.cf_uniqueid = iunique(sb, ROOT_I);
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 4921e7426d95..a2f746066c5d 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -51,6 +51,7 @@ static const struct address_space_operations configfs_aops = {
};
static struct backing_dev_info configfs_backing_dev_info = {
+ .name = "configfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index ccc9d62c462d..55ea369f43a9 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb)
return rv;
}
- return genlmsg_unicast(skb, listener_nlpid);
+ return genlmsg_unicast(&init_net, skb, listener_nlpid);
}
static int user_cmd(struct sk_buff *skb, struct genl_info *info)
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index b91851f1cda3..520783b205a1 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -245,13 +245,11 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
crypto_free_blkcipher(crypt_stat->tfm);
if (crypt_stat->hash_tfm)
crypto_free_hash(crypt_stat->hash_tfm);
- mutex_lock(&crypt_stat->keysig_list_mutex);
list_for_each_entry_safe(key_sig, key_sig_tmp,
&crypt_stat->keysig_list, crypt_stat_list) {
list_del(&key_sig->crypt_stat_list);
kmem_cache_free(ecryptfs_key_sig_cache, key_sig);
}
- mutex_unlock(&crypt_stat->keysig_list_mutex);
memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
}
@@ -925,7 +923,9 @@ static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs(
struct ecryptfs_global_auth_tok *global_auth_tok;
int rc = 0;
+ mutex_lock(&crypt_stat->keysig_list_mutex);
mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
+
list_for_each_entry(global_auth_tok,
&mount_crypt_stat->global_auth_tok_list,
mount_crypt_stat_list) {
@@ -934,13 +934,13 @@ static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs(
rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig);
if (rc) {
printk(KERN_ERR "Error adding keysig; rc = [%d]\n", rc);
- mutex_unlock(
- &mount_crypt_stat->global_auth_tok_list_mutex);
goto out;
}
}
- mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
+
out:
+ mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
+ mutex_unlock(&crypt_stat->keysig_list_mutex);
return rc;
}
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index af737bb56cb7..f9965139c430 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -1303,6 +1303,13 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
}
(*new_auth_tok)->session_key.encrypted_key_size =
(body_size - (ECRYPTFS_SALT_SIZE + 5));
+ if ((*new_auth_tok)->session_key.encrypted_key_size
+ > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
+ printk(KERN_WARNING "Tag 3 packet contains key larger "
+ "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
+ rc = -EINVAL;
+ goto out_free;
+ }
if (unlikely(data[(*packet_size)++] != 0x04)) {
printk(KERN_WARNING "Unknown version number [%d]\n",
data[(*packet_size) - 1]);
@@ -1449,6 +1456,12 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
rc = -EINVAL;
goto out;
}
+ if (unlikely((*tag_11_contents_size) > max_contents_bytes)) {
+ printk(KERN_ERR "Literal data section in tag 11 packet exceeds "
+ "expected size\n");
+ rc = -EINVAL;
+ goto out;
+ }
if (data[(*packet_size)++] != 0x62) {
printk(KERN_WARNING "Unrecognizable packet\n");
rc = -EINVAL;
@@ -2353,21 +2366,18 @@ struct kmem_cache *ecryptfs_key_sig_cache;
int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig)
{
struct ecryptfs_key_sig *new_key_sig;
- int rc = 0;
new_key_sig = kmem_cache_alloc(ecryptfs_key_sig_cache, GFP_KERNEL);
if (!new_key_sig) {
- rc = -ENOMEM;
printk(KERN_ERR
"Error allocating from ecryptfs_key_sig_cache\n");
- goto out;
+ return -ENOMEM;
}
memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX);
- mutex_lock(&crypt_stat->keysig_list_mutex);
+ /* Caller must hold keysig_list_mutex */
list_add(&new_key_sig->crypt_stat_list, &crypt_stat->keysig_list);
- mutex_unlock(&crypt_stat->keysig_list_mutex);
-out:
- return rc;
+
+ return 0;
}
struct kmem_cache *ecryptfs_global_auth_tok_cache;
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index 12d649602d3a..b15a43a80ab7 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -77,7 +77,6 @@ static void ecryptfs_destroy_inode(struct inode *inode)
struct ecryptfs_inode_info *inode_info;
inode_info = ecryptfs_inode_to_private(inode);
- mutex_lock(&inode_info->lower_file_mutex);
if (inode_info->lower_file) {
struct dentry *lower_dentry =
inode_info->lower_file->f_dentry;
@@ -89,7 +88,6 @@ static void ecryptfs_destroy_inode(struct inode *inode)
d_drop(lower_dentry);
}
}
- mutex_unlock(&inode_info->lower_file_mutex);
ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
}
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 3d724a95882f..373fa90c796a 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -130,8 +130,7 @@ static int ext3_readdir(struct file * filp,
struct buffer_head *bh = NULL;
map_bh.b_state = 0;
- err = ext3_get_blocks_handle(NULL, inode, blk, 1,
- &map_bh, 0, 0);
+ err = ext3_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0);
if (err > 0) {
pgoff_t index = map_bh.b_blocknr >>
(PAGE_CACHE_SHIFT - inode->i_blkbits);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 5f51fed5c750..b49908a167ae 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -788,7 +788,7 @@ err_out:
int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
sector_t iblock, unsigned long maxblocks,
struct buffer_head *bh_result,
- int create, int extend_disksize)
+ int create)
{
int err = -EIO;
int offsets[4];
@@ -911,13 +911,6 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
if (!err)
err = ext3_splice_branch(handle, inode, iblock,
partial, indirect_blks, count);
- /*
- * i_disksize growing is protected by truncate_mutex. Don't forget to
- * protect it if you're about to implement concurrent
- * ext3_get_block() -bzzz
- */
- if (!err && extend_disksize && inode->i_size > ei->i_disksize)
- ei->i_disksize = inode->i_size;
mutex_unlock(&ei->truncate_mutex);
if (err)
goto cleanup;
@@ -972,7 +965,7 @@ static int ext3_get_block(struct inode *inode, sector_t iblock,
}
ret = ext3_get_blocks_handle(handle, inode, iblock,
- max_blocks, bh_result, create, 0);
+ max_blocks, bh_result, create);
if (ret > 0) {
bh_result->b_size = (ret << inode->i_blkbits);
ret = 0;
@@ -1005,7 +998,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode,
dummy.b_blocknr = -1000;
buffer_trace_init(&dummy.b_history);
err = ext3_get_blocks_handle(handle, inode, block, 1,
- &dummy, create, 1);
+ &dummy, create);
/*
* ext3_get_blocks_handle() returns number of blocks
* mapped. 0 in case of a HOLE.
@@ -1193,15 +1186,16 @@ write_begin_failed:
* i_size_read because we hold i_mutex.
*
* Add inode to orphan list in case we crash before truncate
- * finishes.
+ * finishes. Do this only if ext3_can_truncate() agrees so
+ * that orphan processing code is happy.
*/
- if (pos + len > inode->i_size)
+ if (pos + len > inode->i_size && ext3_can_truncate(inode))
ext3_orphan_add(handle, inode);
ext3_journal_stop(handle);
unlock_page(page);
page_cache_release(page);
if (pos + len > inode->i_size)
- vmtruncate(inode, inode->i_size);
+ ext3_truncate(inode);
}
if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@@ -1287,7 +1281,7 @@ static int ext3_ordered_write_end(struct file *file,
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
- if (pos + len > inode->i_size)
+ if (pos + len > inode->i_size && ext3_can_truncate(inode))
ext3_orphan_add(handle, inode);
ret2 = ext3_journal_stop(handle);
if (!ret)
@@ -1296,7 +1290,7 @@ static int ext3_ordered_write_end(struct file *file,
page_cache_release(page);
if (pos + len > inode->i_size)
- vmtruncate(inode, inode->i_size);
+ ext3_truncate(inode);
return ret ? ret : copied;
}
@@ -1315,14 +1309,14 @@ static int ext3_writeback_write_end(struct file *file,
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
- if (pos + len > inode->i_size)
+ if (pos + len > inode->i_size && ext3_can_truncate(inode))
ext3_orphan_add(handle, inode);
ret = ext3_journal_stop(handle);
unlock_page(page);
page_cache_release(page);
if (pos + len > inode->i_size)
- vmtruncate(inode, inode->i_size);
+ ext3_truncate(inode);
return ret ? ret : copied;
}
@@ -1358,7 +1352,7 @@ static int ext3_journalled_write_end(struct file *file,
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
- if (pos + len > inode->i_size)
+ if (pos + len > inode->i_size && ext3_can_truncate(inode))
ext3_orphan_add(handle, inode);
EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
if (inode->i_size > EXT3_I(inode)->i_disksize) {
@@ -1375,7 +1369,7 @@ static int ext3_journalled_write_end(struct file *file,
page_cache_release(page);
if (pos + len > inode->i_size)
- vmtruncate(inode, inode->i_size);
+ ext3_truncate(inode);
return ret ? ret : copied;
}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f9c642b22efa..6bd719b6b1b1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2329,7 +2329,7 @@ static int __mpage_da_writepage(struct page *page,
/*
* Rest of the page in the page_vec
* redirty then and skip then. We will
- * try to to write them again after
+ * try to write them again after
* starting a new transaction
*/
redirty_page_for_writepage(wbc, page);
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index cd258463e2a9..9d08b780880a 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -1851,7 +1851,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
struct inode *inode = sbi->s_buddy_cache;
struct page *page = NULL, *bitmap_page = NULL;
- mb_debug("init group %lu\n", group);
+ mb_debug("init group %u\n", group);
blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
this_grp = ext4_get_group_info(sb, group);
/*
@@ -2532,7 +2532,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list);
init_rwsem(&meta_group_info[i]->alloc_sem);
- meta_group_info[i]->bb_free_root.rb_node = NULL;;
+ meta_group_info[i]->bb_free_root.rb_node = NULL;
#ifdef DOUBLE_CHECK
{
@@ -4139,14 +4139,14 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
ext4_get_group_no_and_offset(sb, pa->pa_pstart,
NULL, &start);
spin_unlock(&pa->pa_lock);
- printk(KERN_ERR "PA:%lu:%d:%u \n", i,
- start, pa->pa_len);
+ printk(KERN_ERR "PA:%u:%d:%u \n", i,
+ start, pa->pa_len);
}
ext4_unlock_group(sb, i);
if (grp->bb_free == 0)
continue;
- printk(KERN_ERR "%lu: %d/%d \n",
+ printk(KERN_ERR "%u: %d/%d \n",
i, grp->bb_free, grp->bb_fragments);
}
printk(KERN_ERR "\n");
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 8970d8c49bb0..63a5c1a4ee60 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -820,7 +820,7 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
seq_puts(m, ",shortname=mixed");
break;
case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95:
- /* seq_puts(m, ",shortname=lower"); */
+ seq_puts(m, ",shortname=lower");
break;
default:
seq_puts(m, ",shortname=unknown");
@@ -971,7 +971,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
opts->codepage = fat_default_codepage;
opts->iocharset = fat_default_iocharset;
if (is_vfat) {
- opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95;
+ opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
opts->rodir = 0;
} else {
opts->shortname = 0;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index cb6e83557112..f565f24019b5 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -499,17 +499,10 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
int charlen;
if (utf8) {
- int name_len = strlen(name);
-
- *outlen = utf8s_to_utf16s(name, PATH_MAX, (wchar_t *) outname);
-
- /*
- * We stripped '.'s before and set len appropriately,
- * but utf8s_to_utf16s doesn't care about len
- */
- *outlen -= (name_len - len);
-
- if (*outlen > 255)
+ *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
+ if (*outlen < 0)
+ return *outlen;
+ else if (*outlen > 255)
return -ENAMETOOLONG;
op = &outname[*outlen * sizeof(wchar_t)];
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index c54226be5294..e657d57e605f 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -19,49 +19,516 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
#include "internal.h"
+#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
-/**
- * writeback_acquire - attempt to get exclusive writeback access to a device
- * @bdi: the device's backing_dev_info structure
- *
- * It is a waste of resources to have more than one pdflush thread blocked on
- * a single request queue. Exclusion at the request_queue level is obtained
- * via a flag in the request_queue's backing_dev_info.state.
- *
- * Non-request_queue-backed address_spaces will share default_backing_dev_info,
- * unless they implement their own. Which is somewhat inefficient, as this
- * may prevent concurrent writeback against multiple devices.
+static void generic_sync_wb_inodes(struct bdi_writeback *wb,
+ struct super_block *sb,
+ struct writeback_control *wbc);
+
+/*
+ * We don't actually have pdflush, but this one is exported though /proc...
*/
-static int writeback_acquire(struct backing_dev_info *bdi)
+int nr_pdflush_threads;
+
+static void generic_sync_wb_inodes(struct bdi_writeback *wb,
+ struct super_block *sb,
+ struct writeback_control *wbc);
+
+/*
+ * Work items for the bdi_writeback threads
+ */
+struct bdi_work {
+ struct list_head list;
+ struct list_head wait_list;
+ struct rcu_head rcu_head;
+
+ unsigned long seen;
+ atomic_t pending;
+
+ unsigned long sb_data;
+ unsigned long nr_pages;
+ enum writeback_sync_modes sync_mode;
+
+ unsigned long state;
+};
+
+static struct super_block *bdi_work_sb(struct bdi_work *work)
+{
+ return (struct super_block *) (work->sb_data & ~1UL);
+}
+
+static inline bool bdi_work_on_stack(struct bdi_work *work)
+{
+ return work->sb_data & 1UL;
+}
+
+static inline void bdi_work_init(struct bdi_work *work, struct super_block *sb,
+ unsigned long nr_pages,
+ enum writeback_sync_modes sync_mode)
{
- return !test_and_set_bit(BDI_pdflush, &bdi->state);
+ INIT_RCU_HEAD(&work->rcu_head);
+ work->sb_data = (unsigned long) sb;
+ work->nr_pages = nr_pages;
+ work->sync_mode = sync_mode;
+ work->state = 1;
+}
+
+static inline void bdi_work_init_on_stack(struct bdi_work *work,
+ struct super_block *sb,
+ unsigned long nr_pages,
+ enum writeback_sync_modes sync_mode)
+{
+ bdi_work_init(work, sb, nr_pages, sync_mode);
+ work->sb_data |= 1UL;
}
/**
* writeback_in_progress - determine whether there is writeback in progress
* @bdi: the device's backing_dev_info structure.
*
- * Determine whether there is writeback in progress against a backing device.
+ * Determine whether there is writeback waiting to be handled against a
+ * backing device.
*/
int writeback_in_progress(struct backing_dev_info *bdi)
{
- return test_bit(BDI_pdflush, &bdi->state);
+ return !list_empty(&bdi->work_list);
}
-/**
- * writeback_release - relinquish exclusive writeback access against a device.
- * @bdi: the device's backing_dev_info structure
+static void bdi_work_clear(struct bdi_work *work)
+{
+ clear_bit(0, &work->state);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&work->state, 0);
+}
+
+static void bdi_work_free(struct rcu_head *head)
+{
+ struct bdi_work *work = container_of(head, struct bdi_work, rcu_head);
+
+ if (!bdi_work_on_stack(work))
+ kfree(work);
+ else
+ bdi_work_clear(work);
+}
+
+static void wb_work_complete(struct bdi_work *work)
+{
+ const enum writeback_sync_modes sync_mode = work->sync_mode;
+
+ /*
+ * For allocated work, we can clear the done/seen bit right here.
+ * For on-stack work, we need to postpone both the clear and free
+ * to after the RCU grace period, since the stack could be invalidated
+ * as soon as bdi_work_clear() has done the wakeup.
+ */
+ if (!bdi_work_on_stack(work))
+ bdi_work_clear(work);
+ if (sync_mode == WB_SYNC_NONE || bdi_work_on_stack(work))
+ call_rcu(&work->rcu_head, bdi_work_free);
+}
+
+static void wb_clear_pending(struct bdi_writeback *wb, struct bdi_work *work)
+{
+ /*
+ * The caller has retrieved the work arguments from this work,
+ * drop our reference. If this is the last ref, delete and free it
+ */
+ if (atomic_dec_and_test(&work->pending)) {
+ struct backing_dev_info *bdi = wb->bdi;
+
+ spin_lock(&bdi->wb_lock);
+ list_del_rcu(&work->list);
+ spin_unlock(&bdi->wb_lock);
+
+ wb_work_complete(work);
+ }
+}
+
+static void wb_start_writeback(struct bdi_writeback *wb, struct bdi_work *work)
+{
+ /*
+ * If we failed allocating the bdi work item, wake up the wb thread
+ * always. As a safety precaution, it'll flush out everything
+ */
+ if (!wb_has_dirty_io(wb) && work)
+ wb_clear_pending(wb, work);
+ else if (wb->task)
+ wake_up_process(wb->task);
+}
+
+static void bdi_sched_work(struct backing_dev_info *bdi, struct bdi_work *work)
+{
+ if (!bdi_wblist_needs_lock(bdi))
+ wb_start_writeback(&bdi->wb, work);
+ else {
+ struct bdi_writeback *wb;
+ int idx;
+
+ idx = srcu_read_lock(&bdi->srcu);
+
+ list_for_each_entry_rcu(wb, &bdi->wb_list, list)
+ wb_start_writeback(wb, work);
+
+ srcu_read_unlock(&bdi->srcu, idx);
+ }
+}
+
+static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)
+{
+ if (work) {
+ work->seen = bdi->wb_mask;
+ BUG_ON(!work->seen);
+ atomic_set(&work->pending, bdi->wb_cnt);
+ BUG_ON(!bdi->wb_cnt);
+
+ /*
+ * Make sure stores are seen before it appears on the list
+ */
+ smp_mb();
+
+ spin_lock(&bdi->wb_lock);
+ list_add_tail_rcu(&work->list, &bdi->work_list);
+ spin_unlock(&bdi->wb_lock);
+ }
+
+ /*
+ * If the default thread isn't there, make sure we add it. When
+ * it gets created and wakes up, we'll run this work.
+ */
+ if (unlikely(list_empty_careful(&bdi->wb_list)))
+ wake_up_process(default_backing_dev_info.wb.task);
+ else
+ bdi_sched_work(bdi, work);
+}
+
+/*
+ * Used for on-stack allocated work items. The caller needs to wait until
+ * the wb threads have acked the work before it's safe to continue.
*/
-static void writeback_release(struct backing_dev_info *bdi)
+static void bdi_wait_on_work_clear(struct bdi_work *work)
{
- BUG_ON(!writeback_in_progress(bdi));
- clear_bit(BDI_pdflush, &bdi->state);
+ wait_on_bit(&work->state, 0, bdi_sched_wait, TASK_UNINTERRUPTIBLE);
+}
+
+static struct bdi_work *bdi_alloc_work(struct super_block *sb, long nr_pages,
+ enum writeback_sync_modes sync_mode)
+{
+ struct bdi_work *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (work)
+ bdi_work_init(work, sb, nr_pages, sync_mode);
+
+ return work;
+}
+
+void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
+ long nr_pages, enum writeback_sync_modes sync_mode)
+{
+ const bool must_wait = sync_mode == WB_SYNC_ALL;
+ struct bdi_work work_stack, *work = NULL;
+
+ if (!must_wait)
+ work = bdi_alloc_work(sb, nr_pages, sync_mode);
+
+ if (!work) {
+ work = &work_stack;
+ bdi_work_init_on_stack(work, sb, nr_pages, sync_mode);
+ }
+
+ bdi_queue_work(bdi, work);
+
+ /*
+ * If the sync mode is WB_SYNC_ALL, block waiting for the work to
+ * complete. If not, we only need to wait for the work to be started,
+ * if we allocated it on-stack. We use the same mechanism, if the
+ * wait bit is set in the bdi_work struct, then threads will not
+ * clear pending until after they are done.
+ *
+ * Note that work == &work_stack if must_wait is true, so we don't
+ * need to do call_rcu() here ever, since the completion path will
+ * have done that for us.
+ */
+ if (must_wait || work == &work_stack) {
+ bdi_wait_on_work_clear(work);
+ if (work != &work_stack)
+ call_rcu(&work->rcu_head, bdi_work_free);
+ }
+}
+
+/*
+ * The maximum number of pages to writeout in a single bdi flush/kupdate
+ * operation. We do this so we don't hold I_SYNC against an inode for
+ * enormous amounts of time, which would block a userspace task which has
+ * been forced to throttle against that inode. Also, the code reevaluates
+ * the dirty each time it has written this many pages.
+ */
+#define MAX_WRITEBACK_PAGES 1024
+
+static inline bool over_bground_thresh(void)
+{
+ unsigned long background_thresh, dirty_thresh;
+
+ get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);
+
+ return (global_page_state(NR_FILE_DIRTY) +
+ global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
+}
+
+/*
+ * Explicit flushing or periodic writeback of "old" data.
+ *
+ * Define "old": the first time one of an inode's pages is dirtied, we mark the
+ * dirtying-time in the inode's address_space. So this periodic writeback code
+ * just walks the superblock inode list, writing back any inodes which are
+ * older than a specific point in time.
+ *
+ * Try to run once per dirty_writeback_interval. But if a writeback event
+ * takes longer than a dirty_writeback_interval interval, then leave a
+ * one-second gap.
+ *
+ * older_than_this takes precedence over nr_to_write. So we'll only write back
+ * all dirty pages if they are all attached to "old" mappings.
+ */
+static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
+ struct super_block *sb,
+ enum writeback_sync_modes sync_mode, int for_kupdate)
+{
+ struct writeback_control wbc = {
+ .bdi = wb->bdi,
+ .sync_mode = sync_mode,
+ .older_than_this = NULL,
+ .for_kupdate = for_kupdate,
+ .range_cyclic = 1,
+ };
+ unsigned long oldest_jif;
+ long wrote = 0;
+
+ if (wbc.for_kupdate) {
+ wbc.older_than_this = &oldest_jif;
+ oldest_jif = jiffies -
+ msecs_to_jiffies(dirty_expire_interval * 10);
+ }
+
+ for (;;) {
+ if (sync_mode == WB_SYNC_NONE && nr_pages <= 0 &&
+ !over_bground_thresh())
+ break;
+
+ wbc.more_io = 0;
+ wbc.encountered_congestion = 0;
+ wbc.nr_to_write = MAX_WRITEBACK_PAGES;
+ wbc.pages_skipped = 0;
+ generic_sync_wb_inodes(wb, sb, &wbc);
+ nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+ wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+ /*
+ * If we ran out of stuff to write, bail unless more_io got set
+ */
+ if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
+ if (wbc.more_io && !wbc.for_kupdate)
+ continue;
+ break;
+ }
+ }
+
+ return wrote;
+}
+
+/*
+ * Return the next bdi_work struct that hasn't been processed by this
+ * wb thread yet
+ */
+static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi,
+ struct bdi_writeback *wb)
+{
+ struct bdi_work *work, *ret = NULL;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(work, &bdi->work_list, list) {
+ if (!test_and_clear_bit(wb->nr, &work->seen))
+ continue;
+
+ ret = work;
+ break;
+ }
+
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Retrieve work items and do the writeback they describe
+ */
+long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
+{
+ struct backing_dev_info *bdi = wb->bdi;
+ struct bdi_work *work;
+ long nr_pages, wrote = 0;
+
+ while ((work = get_next_work_item(bdi, wb)) != NULL) {
+ struct super_block *sb = bdi_work_sb(work);
+ enum writeback_sync_modes sync_mode;
+
+ nr_pages = work->nr_pages;
+
+ /*
+ * Override sync mode, in case we must wait for completion
+ */
+ if (force_wait)
+ work->sync_mode = sync_mode = WB_SYNC_ALL;
+ else
+ sync_mode = work->sync_mode;
+
+ /*
+ * If this isn't a data integrity operation, just notify
+ * that we have seen this work and we are now starting it.
+ */
+ if (sync_mode == WB_SYNC_NONE)
+ wb_clear_pending(wb, work);
+
+ wrote += wb_writeback(wb, nr_pages, sb, sync_mode, 0);
+
+ /*
+ * This is a data integrity writeback, so only do the
+ * notification when we have completed the work.
+ */
+ if (sync_mode == WB_SYNC_ALL)
+ wb_clear_pending(wb, work);
+ }
+
+ /*
+ * Check for periodic writeback, kupdated() style
+ */
+ if (!wrote) {
+ nr_pages = global_page_state(NR_FILE_DIRTY) +
+ global_page_state(NR_UNSTABLE_NFS) +
+ (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+
+ wrote = wb_writeback(wb, nr_pages, NULL, WB_SYNC_NONE, 1);
+ }
+
+ return wrote;
+}
+
+/*
+ * Handle writeback of dirty data for the device backed by this bdi. Also
+ * wakes up periodically and does kupdated style flushing.
+ */
+int bdi_writeback_task(struct bdi_writeback *wb)
+{
+ unsigned long last_active = jiffies;
+ unsigned long wait_jiffies = -1UL;
+ long pages_written;
+
+ while (!kthread_should_stop()) {
+ pages_written = wb_do_writeback(wb, 0);
+
+ if (pages_written)
+ last_active = jiffies;
+ else if (wait_jiffies != -1UL) {
+ unsigned long max_idle;
+
+ /*
+ * Longest period of inactivity that we tolerate. If we
+ * see dirty data again later, the task will get
+ * recreated automatically.
+ */
+ max_idle = max(5UL * 60 * HZ, wait_jiffies);
+ if (time_after(jiffies, max_idle + last_active) &&
+ wb_is_default_task(wb))
+ break;
+ }
+
+ wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(wait_jiffies);
+ try_to_freeze();
+ }
+
+ return 0;
+}
+
+/*
+ * Schedule writeback for all backing devices. Expensive! If this is a data
+ * integrity operation, writeback will be complete when this returns. If
+ * we are simply called for WB_SYNC_NONE, then writeback will merely be
+ * scheduled to run.
+ */
+void bdi_writeback_all(struct super_block *sb, struct writeback_control *wbc)
+{
+ const bool must_wait = wbc->sync_mode == WB_SYNC_ALL;
+ struct backing_dev_info *bdi;
+ struct bdi_work *work;
+ LIST_HEAD(list);
+
+ /*
+ * If this isn't a data integrity writeback, just drop it if
+ * someone is already holding the bdi_lock
+ */
+ if (!spin_trylock(&bdi_lock)) {
+ if (!must_wait)
+ return;
+ spin_lock(&bdi_lock);
+ }
+
+restart:
+ list_for_each_entry(bdi, &bdi_list, bdi_list) {
+ struct bdi_work *work;
+
+ if (!bdi_has_dirty_io(bdi))
+ continue;
+
+ /*
+ * If work allocation fails, do the writes inline. We drop
+ * the lock and restart the list writeout. This should be OK,
+ * since this happens rarely and because the writeout should
+ * eventually make more free memory available.
+ */
+ work = bdi_alloc_work(sb, wbc->nr_to_write, wbc->sync_mode);
+ if (!work) {
+ struct writeback_control __wbc = *wbc;
+
+ /*
+ * Not a data integrity writeout, just continue
+ */
+ if (!must_wait)
+ continue;
+
+ spin_unlock(&bdi_lock);
+ __wbc = *wbc;
+ __wbc.bdi = bdi;
+ generic_sync_bdi_inodes(sb, &__wbc);
+ spin_lock(&bdi_lock);
+ goto restart;
+ }
+ if (must_wait)
+ list_add_tail(&work->wait_list, &list);
+
+ bdi_queue_work(bdi, work);
+ }
+
+ spin_unlock(&bdi_lock);
+
+ /*
+ * If this is for WB_SYNC_ALL, wait for pending work to complete
+ * before returning.
+ */
+ while (!list_empty(&list)) {
+ work = list_entry(list.next, struct bdi_work, wait_list);
+ list_del(&work->wait_list);
+ bdi_wait_on_work_clear(work);
+ call_rcu(&work->rcu_head, bdi_work_free);
+ }
}
static noinline void block_dump___mark_inode_dirty(struct inode *inode)
@@ -86,6 +553,21 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode)
}
}
+/*
+ * If the filesystem didn't provide a way to map an inode to a dedicated
+ * flusher thread, it doesn't support more than 1 thread. So we know it's
+ * the default thread, return that.
+ */
+static inline struct bdi_writeback *inode_get_wb(struct inode *inode)
+{
+ const struct super_operations *sop = inode->i_sb->s_op;
+
+ if (!sop->inode_get_wb)
+ return &inode_to_bdi(inode)->wb;
+
+ return sop->inode_get_wb(inode);
+}
+
/**
* __mark_inode_dirty - internal function
* @inode: inode to mark
@@ -165,12 +647,21 @@ void __mark_inode_dirty(struct inode *inode, int flags)
goto out;
/*
- * If the inode was already on s_dirty/s_io/s_more_io, don't
- * reposition it (that would break s_dirty time-ordering).
+ * If the inode was already on b_dirty/b_io/b_more_io, don't
+ * reposition it (that would break b_dirty time-ordering).
*/
if (!was_dirty) {
+ struct bdi_writeback *wb = inode_get_wb(inode);
+ struct backing_dev_info *bdi = wb->bdi;
+
+ if (bdi_cap_writeback_dirty(bdi) &&
+ !test_bit(BDI_registered, &bdi->state)) {
+ WARN_ON(1);
+ printk("bdi-%s not registered\n", bdi->name);
+ }
+
inode->dirtied_when = jiffies;
- list_move(&inode->i_list, &sb->s_dirty);
+ list_move(&inode->i_list, &wb->b_dirty);
}
}
out:
@@ -191,31 +682,32 @@ static int write_inode(struct inode *inode, int sync)
* furthest end of its superblock's dirty-inode list.
*
* Before stamping the inode's ->dirtied_when, we check to see whether it is
- * already the most-recently-dirtied inode on the s_dirty list. If that is
+ * already the most-recently-dirtied inode on the b_dirty list. If that is
* the case then the inode must have been redirtied while it was being written
* out and we don't reset its dirtied_when.
*/
static void redirty_tail(struct inode *inode)
{
- struct super_block *sb = inode->i_sb;
+ struct bdi_writeback *wb = inode_get_wb(inode);
- if (!list_empty(&sb->s_dirty)) {
- struct inode *tail_inode;
+ if (!list_empty(&wb->b_dirty)) {
+ struct inode *tail;
- tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list);
- if (time_before(inode->dirtied_when,
- tail_inode->dirtied_when))
+ tail = list_entry(wb->b_dirty.next, struct inode, i_list);
+ if (time_before(inode->dirtied_when, tail->dirtied_when))
inode->dirtied_when = jiffies;
}
- list_move(&inode->i_list, &sb->s_dirty);
+ list_move(&inode->i_list, &wb->b_dirty);
}
/*
- * requeue inode for re-scanning after sb->s_io list is exhausted.
+ * requeue inode for re-scanning after bdi->b_io list is exhausted.
*/
static void requeue_io(struct inode *inode)
{
- list_move(&inode->i_list, &inode->i_sb->s_more_io);
+ struct bdi_writeback *wb = inode_get_wb(inode);
+
+ list_move(&inode->i_list, &wb->b_more_io);
}
static void inode_sync_complete(struct inode *inode)
@@ -262,21 +754,12 @@ static void move_expired_inodes(struct list_head *delaying_queue,
/*
* Queue all expired dirty inodes for io, eldest first.
*/
-static void queue_io(struct super_block *sb,
- unsigned long *older_than_this)
+static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this)
{
- list_splice_init(&sb->s_more_io, sb->s_io.prev);
- move_expired_inodes(&sb->s_dirty, &sb->s_io, older_than_this);
+ list_splice_init(&wb->b_more_io, wb->b_io.prev);
+ move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
}
-int sb_has_dirty_inodes(struct super_block *sb)
-{
- return !list_empty(&sb->s_dirty) ||
- !list_empty(&sb->s_io) ||
- !list_empty(&sb->s_more_io);
-}
-EXPORT_SYMBOL(sb_has_dirty_inodes);
-
/*
* Wait for writeback on an inode to complete.
*/
@@ -322,11 +805,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
if (inode->i_state & I_SYNC) {
/*
* If this inode is locked for writeback and we are not doing
- * writeback-for-data-integrity, move it to s_more_io so that
+ * writeback-for-data-integrity, move it to b_more_io so that
* writeback can proceed with the other inodes on s_io.
*
* We'll have another go at writing back this inode when we
- * completed a full scan of s_io.
+ * completed a full scan of b_io.
*/
if (!wait) {
requeue_io(inode);
@@ -371,11 +854,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
/*
* We didn't write back all the pages. nfs_writepages()
* sometimes bales out without doing anything. Redirty
- * the inode; Move it from s_io onto s_more_io/s_dirty.
+ * the inode; Move it from b_io onto b_more_io/b_dirty.
*/
/*
* akpm: if the caller was the kupdate function we put
- * this inode at the head of s_dirty so it gets first
+ * this inode at the head of b_dirty so it gets first
* consideration. Otherwise, move it to the tail, for
* the reasons described there. I'm not really sure
* how much sense this makes. Presumably I had a good
@@ -385,7 +868,7 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
if (wbc->for_kupdate) {
/*
* For the kupdate function we move the inode
- * to s_more_io so it will get more writeout as
+ * to b_more_io so it will get more writeout as
* soon as the queue becomes uncongested.
*/
inode->i_state |= I_DIRTY_PAGES;
@@ -433,51 +916,34 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
return ret;
}
-/*
- * Write out a superblock's list of dirty inodes. A wait will be performed
- * upon no inodes, all inodes or the final one, depending upon sync_mode.
- *
- * If older_than_this is non-NULL, then only write out inodes which
- * had their first dirtying at a time earlier than *older_than_this.
- *
- * If we're a pdflush thread, then implement pdflush collision avoidance
- * against the entire list.
- *
- * If `bdi' is non-zero then we're being asked to writeback a specific queue.
- * This function assumes that the blockdev superblock's inodes are backed by
- * a variety of queues, so all inodes are searched. For other superblocks,
- * assume that all inodes are backed by the same queue.
- *
- * FIXME: this linear search could get expensive with many fileystems. But
- * how to fix? We need to go from an address_space to all inodes which share
- * a queue with that address_space. (Easy: have a global "dirty superblocks"
- * list).
- *
- * The inodes to be written are parked on sb->s_io. They are moved back onto
- * sb->s_dirty as they are selected for writing. This way, none can be missed
- * on the writer throttling path, and we get decent balancing between many
- * throttled threads: we don't want them all piling up on inode_sync_wait.
- */
-void generic_sync_sb_inodes(struct super_block *sb,
- struct writeback_control *wbc)
+static void generic_sync_wb_inodes(struct bdi_writeback *wb,
+ struct super_block *sb,
+ struct writeback_control *wbc)
{
+ const int is_blkdev_sb = sb_is_blkdev_sb(sb);
const unsigned long start = jiffies; /* livelock avoidance */
- int sync = wbc->sync_mode == WB_SYNC_ALL;
spin_lock(&inode_lock);
- if (!wbc->for_kupdate || list_empty(&sb->s_io))
- queue_io(sb, wbc->older_than_this);
- while (!list_empty(&sb->s_io)) {
- struct inode *inode = list_entry(sb->s_io.prev,
+ if (!wbc->for_kupdate || list_empty(&wb->b_io))
+ queue_io(wb, wbc->older_than_this);
+
+ while (!list_empty(&wb->b_io)) {
+ struct inode *inode = list_entry(wb->b_io.prev,
struct inode, i_list);
- struct address_space *mapping = inode->i_mapping;
- struct backing_dev_info *bdi = mapping->backing_dev_info;
long pages_skipped;
- if (!bdi_cap_writeback_dirty(bdi)) {
+ /*
+ * super block given and doesn't match, skip this inode
+ */
+ if (sb && sb != inode->i_sb) {
redirty_tail(inode);
- if (sb_is_blkdev_sb(sb)) {
+ continue;
+ }
+
+ if (!bdi_cap_writeback_dirty(wb->bdi)) {
+ redirty_tail(inode);
+ if (is_blkdev_sb) {
/*
* Dirty memory-backed blockdev: the ramdisk
* driver does this. Skip just this inode
@@ -497,21 +963,14 @@ void generic_sync_sb_inodes(struct super_block *sb,
continue;
}
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
+ if (wbc->nonblocking && bdi_write_congested(wb->bdi)) {
wbc->encountered_congestion = 1;
- if (!sb_is_blkdev_sb(sb))
+ if (!is_blkdev_sb)
break; /* Skip a congested fs */
requeue_io(inode);
continue; /* Skip a congested blockdev */
}
- if (wbc->bdi && bdi != wbc->bdi) {
- if (!sb_is_blkdev_sb(sb))
- break; /* fs has the wrong queue */
- requeue_io(inode);
- continue; /* blockdev has wrong queue */
- }
-
/*
* Was this inode dirtied after sync_sb_inodes was called?
* This keeps sync from extra jobs and livelock.
@@ -519,16 +978,10 @@ void generic_sync_sb_inodes(struct super_block *sb,
if (inode_dirtied_after(inode, start))
break;
- /* Is another pdflush already flushing this queue? */
- if (current_is_pdflush() && !writeback_acquire(bdi))
- break;
-
BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
__iget(inode);
pages_skipped = wbc->pages_skipped;
writeback_single_inode(inode, wbc);
- if (current_is_pdflush())
- writeback_release(bdi);
if (wbc->pages_skipped != pages_skipped) {
/*
* writeback is not making progress due to locked
@@ -544,13 +997,71 @@ void generic_sync_sb_inodes(struct super_block *sb,
wbc->more_io = 1;
break;
}
- if (!list_empty(&sb->s_more_io))
+ if (!list_empty(&wb->b_more_io))
wbc->more_io = 1;
}
- if (sync) {
+ spin_unlock(&inode_lock);
+ /* Leave any unwritten inodes on b_io */
+}
+
+void generic_sync_bdi_inodes(struct super_block *sb,
+ struct writeback_control *wbc)
+{
+ struct backing_dev_info *bdi = wbc->bdi;
+ struct bdi_writeback *wb;
+
+ /*
+ * Common case is just a single wb thread and that is embedded in
+ * the bdi, so it doesn't need locking
+ */
+ if (!bdi_wblist_needs_lock(bdi))
+ generic_sync_wb_inodes(&bdi->wb, sb, wbc);
+ else {
+ int idx;
+
+ idx = srcu_read_lock(&bdi->srcu);
+
+ list_for_each_entry_rcu(wb, &bdi->wb_list, list)
+ generic_sync_wb_inodes(wb, sb, wbc);
+
+ srcu_read_unlock(&bdi->srcu, idx);
+ }
+}
+
+/*
+ * Write out a superblock's list of dirty inodes. A wait will be performed
+ * upon no inodes, all inodes or the final one, depending upon sync_mode.
+ *
+ * If older_than_this is non-NULL, then only write out inodes which
+ * had their first dirtying at a time earlier than *older_than_this.
+ *
+ * If we're a pdlfush thread, then implement pdflush collision avoidance
+ * against the entire list.
+ *
+ * If `bdi' is non-zero then we're being asked to writeback a specific queue.
+ * This function assumes that the blockdev superblock's inodes are backed by
+ * a variety of queues, so all inodes are searched. For other superblocks,
+ * assume that all inodes are backed by the same queue.
+ *
+ * The inodes to be written are parked on bdi->b_io. They are moved back onto
+ * bdi->b_dirty as they are selected for writing. This way, none can be missed
+ * on the writer throttling path, and we get decent balancing between many
+ * throttled threads: we don't want them all piling up on inode_sync_wait.
+ */
+void generic_sync_sb_inodes(struct super_block *sb,
+ struct writeback_control *wbc)
+{
+ if (wbc->bdi)
+ bdi_start_writeback(wbc->bdi, sb, wbc->nr_to_write, wbc->sync_mode);
+ else
+ bdi_writeback_all(sb, wbc);
+
+ if (wbc->sync_mode == WB_SYNC_ALL) {
struct inode *inode, *old_inode = NULL;
+ spin_lock(&inode_lock);
+
/*
* Data integrity sync. Must wait for all pages under writeback,
* because there may have been pages dirtied before our sync
@@ -588,10 +1099,8 @@ void generic_sync_sb_inodes(struct super_block *sb,
}
spin_unlock(&inode_lock);
iput(old_inode);
- } else
- spin_unlock(&inode_lock);
+ }
- return; /* Leave any unwritten inodes on s_io */
}
EXPORT_SYMBOL_GPL(generic_sync_sb_inodes);
@@ -602,58 +1111,6 @@ static void sync_sb_inodes(struct super_block *sb,
}
/*
- * Start writeback of dirty pagecache data against all unlocked inodes.
- *
- * Note:
- * We don't need to grab a reference to superblock here. If it has non-empty
- * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
- * past sync_inodes_sb() until the ->s_dirty/s_io/s_more_io lists are all
- * empty. Since __sync_single_inode() regains inode_lock before it finally moves
- * inode from superblock lists we are OK.
- *
- * If `older_than_this' is non-zero then only flush inodes which have a
- * flushtime older than *older_than_this.
- *
- * If `bdi' is non-zero then we will scan the first inode against each
- * superblock until we find the matching ones. One group will be the dirty
- * inodes against a filesystem. Then when we hit the dummy blockdev superblock,
- * sync_sb_inodes will seekout the blockdev which matches `bdi'. Maybe not
- * super-efficient but we're about to do a ton of I/O...
- */
-void
-writeback_inodes(struct writeback_control *wbc)
-{
- struct super_block *sb;
-
- might_sleep();
- spin_lock(&sb_lock);
-restart:
- list_for_each_entry_reverse(sb, &super_blocks, s_list) {
- if (sb_has_dirty_inodes(sb)) {
- /* we're making our own get_super here */
- sb->s_count++;
- spin_unlock(&sb_lock);
- /*
- * If we can't get the readlock, there's no sense in
- * waiting around, most of the time the FS is going to
- * be unmounted by the time it is released.
- */
- if (down_read_trylock(&sb->s_umount)) {
- if (sb->s_root)
- sync_sb_inodes(sb, wbc);
- up_read(&sb->s_umount);
- }
- spin_lock(&sb_lock);
- if (__put_super_and_need_restart(sb))
- goto restart;
- }
- if (wbc->nr_to_write <= 0)
- break;
- }
- spin_unlock(&sb_lock);
-}
-
-/*
* writeback and wait upon the filesystem's dirty inodes. The caller will
* do this in two passes - one to write, and one to wait.
*
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 6484eb75acd6..51d9e33d634f 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -250,7 +250,7 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
static void flush_bg_queue(struct fuse_conn *fc)
{
- while (fc->active_background < FUSE_MAX_BACKGROUND &&
+ while (fc->active_background < fc->max_background &&
!list_empty(&fc->bg_queue)) {
struct fuse_req *req;
@@ -280,11 +280,11 @@ __releases(&fc->lock)
list_del(&req->intr_entry);
req->state = FUSE_REQ_FINISHED;
if (req->background) {
- if (fc->num_background == FUSE_MAX_BACKGROUND) {
+ if (fc->num_background == fc->max_background) {
fc->blocked = 0;
wake_up_all(&fc->blocked_waitq);
}
- if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+ if (fc->num_background == fc->congestion_threshold &&
fc->connected && fc->bdi_initialized) {
clear_bdi_congested(&fc->bdi, BLK_RW_SYNC);
clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
@@ -410,9 +410,9 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
{
req->background = 1;
fc->num_background++;
- if (fc->num_background == FUSE_MAX_BACKGROUND)
+ if (fc->num_background == fc->max_background)
fc->blocked = 1;
- if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+ if (fc->num_background == fc->congestion_threshold &&
fc->bdi_initialized) {
set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 52b641fc0faf..6bcfab04396f 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -25,12 +25,6 @@
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
-/** Maximum number of outstanding background requests */
-#define FUSE_MAX_BACKGROUND 12
-
-/** Congestion starts at 75% of maximum */
-#define FUSE_CONGESTION_THRESHOLD (FUSE_MAX_BACKGROUND * 75 / 100)
-
/** Bias for fi->writectr, meaning new writepages must not be sent */
#define FUSE_NOWRITE INT_MIN
@@ -349,6 +343,12 @@ struct fuse_conn {
/** rbtree of fuse_files waiting for poll events indexed by ph */
struct rb_root polled_files;
+ /** Maximum number of outstanding background requests */
+ unsigned max_background;
+
+ /** Number of background requests at which congestion starts */
+ unsigned congestion_threshold;
+
/** Number of requests currently in the background */
unsigned num_background;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index f91ccc4a189d..a9a9cfff30ca 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -32,6 +32,12 @@ DEFINE_MUTEX(fuse_mutex);
#define FUSE_DEFAULT_BLKSIZE 512
+/** Maximum number of outstanding background requests */
+#define FUSE_DEFAULT_MAX_BACKGROUND 12
+
+/** Congestion starts at 75% of maximum */
+#define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4)
+
struct fuse_mount_data {
int fd;
unsigned rootmode;
@@ -517,6 +523,8 @@ void fuse_conn_init(struct fuse_conn *fc)
INIT_LIST_HEAD(&fc->bg_queue);
INIT_LIST_HEAD(&fc->entry);
atomic_set(&fc->num_waiting, 0);
+ fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
+ fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
fc->khctr = 0;
fc->polled_files = RB_ROOT;
fc->reqctr = 0;
@@ -736,6 +744,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
else {
unsigned long ra_pages;
+ if (arg->minor >= 13) {
+ if (arg->max_background)
+ fc->max_background = arg->max_background;
+ if (arg->congestion_threshold)
+ fc->congestion_threshold = arg->congestion_threshold;
+ }
if (arg->minor >= 6) {
ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
if (arg->flags & FUSE_ASYNC_READ)
@@ -801,6 +815,7 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
{
int err;
+ fc->bdi.name = "fuse";
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
/* fuse does it's own writeback accounting */
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 03ebb439ace0..7ebae9a4ecc0 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -624,6 +624,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
{
struct gfs2_inode *ip = GFS2_I(mapping->host);
struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
int alloc_required;
int error = 0;
@@ -637,6 +638,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
error = gfs2_glock_nq(&ip->i_gh);
if (unlikely(error))
goto out_uninit;
+ if (&ip->i_inode == sdp->sd_rindex) {
+ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE,
+ GL_NOCACHE, &m_ip->i_gh);
+ if (unlikely(error)) {
+ gfs2_glock_dq(&ip->i_gh);
+ goto out_uninit;
+ }
+ }
error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
if (error)
@@ -667,6 +676,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
rblocks += data_blocks ? data_blocks : 1;
if (ind_blocks || data_blocks)
rblocks += RES_STATFS + RES_QUOTA;
+ if (&ip->i_inode == sdp->sd_rindex)
+ rblocks += 2 * RES_STATFS;
error = gfs2_trans_begin(sdp, rblocks,
PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -712,6 +723,10 @@ out_alloc_put:
gfs2_alloc_put(ip);
}
out_unlock:
+ if (&ip->i_inode == sdp->sd_rindex) {
+ gfs2_glock_dq(&m_ip->i_gh);
+ gfs2_holder_uninit(&m_ip->i_gh);
+ }
gfs2_glock_dq(&ip->i_gh);
out_uninit:
gfs2_holder_uninit(&ip->i_gh);
@@ -725,14 +740,21 @@ out_uninit:
static void adjust_fs_space(struct inode *inode)
{
struct gfs2_sbd *sdp = inode->i_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;
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+ struct buffer_head *m_bh, *l_bh;
u64 fs_total, new_free;
/* Total up the file system space, according to the latest rindex. */
fs_total = gfs2_ri_total(sdp);
+ if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0)
+ return;
spin_lock(&sdp->sd_statfs_spin);
+ gfs2_statfs_change_in(m_sc, m_bh->b_data +
+ sizeof(struct gfs2_dinode));
if (fs_total > (m_sc->sc_total + l_sc->sc_total))
new_free = fs_total - (m_sc->sc_total + l_sc->sc_total);
else
@@ -741,6 +763,13 @@ static void adjust_fs_space(struct inode *inode)
fs_warn(sdp, "File system extended by %llu blocks.\n",
(unsigned long long)new_free);
gfs2_statfs_change(sdp, new_free, new_free, 0);
+
+ if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0)
+ goto out;
+ update_statfs(sdp, m_bh, l_bh);
+ brelse(l_bh);
+out:
+ brelse(m_bh);
}
/**
@@ -763,6 +792,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
u64 to = pos + copied;
void *kaddr;
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
@@ -794,6 +824,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
brelse(dibh);
gfs2_trans_end(sdp);
+ if (inode == sdp->sd_rindex) {
+ gfs2_glock_dq(&m_ip->i_gh);
+ gfs2_holder_uninit(&m_ip->i_gh);
+ }
gfs2_glock_dq(&ip->i_gh);
gfs2_holder_uninit(&ip->i_gh);
return copied;
@@ -823,6 +857,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
struct buffer_head *dibh;
struct gfs2_alloc *al = ip->i_alloc;
unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
@@ -865,6 +900,10 @@ failed:
gfs2_quota_unlock(ip);
gfs2_alloc_put(ip);
}
+ if (inode == sdp->sd_rindex) {
+ gfs2_glock_dq(&m_ip->i_gh);
+ gfs2_holder_uninit(&m_ip->i_gh);
+ }
gfs2_glock_dq(&ip->i_gh);
gfs2_holder_uninit(&ip->i_gh);
return ret;
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 297421c0427a..8b674b1f3a55 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -63,6 +63,7 @@ static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int
static DECLARE_RWSEM(gfs2_umount_flush_sem);
static struct dentry *gfs2_root;
static struct workqueue_struct *glock_workqueue;
+struct workqueue_struct *gfs2_delete_workqueue;
static LIST_HEAD(lru_list);
static atomic_t lru_count = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(lru_lock);
@@ -167,13 +168,33 @@ static void glock_free(struct gfs2_glock *gl)
*
*/
-static void gfs2_glock_hold(struct gfs2_glock *gl)
+void gfs2_glock_hold(struct gfs2_glock *gl)
{
GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0);
atomic_inc(&gl->gl_ref);
}
/**
+ * demote_ok - Check to see if it's ok to unlock a glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int demote_ok(const struct gfs2_glock *gl)
+{
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ if (gl->gl_state == LM_ST_UNLOCKED)
+ return 0;
+ if (!list_empty(&gl->gl_holders))
+ return 0;
+ if (glops->go_demote_ok)
+ return glops->go_demote_ok(gl);
+ return 1;
+}
+
+/**
* gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
* @gl: the glock
*
@@ -181,8 +202,13 @@ static void gfs2_glock_hold(struct gfs2_glock *gl)
static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
{
+ int may_reclaim;
+ may_reclaim = (demote_ok(gl) &&
+ (atomic_read(&gl->gl_ref) == 1 ||
+ (gl->gl_name.ln_type == LM_TYPE_INODE &&
+ atomic_read(&gl->gl_ref) <= 2)));
spin_lock(&lru_lock);
- if (list_empty(&gl->gl_lru) && gl->gl_state != LM_ST_UNLOCKED) {
+ if (list_empty(&gl->gl_lru) && may_reclaim) {
list_add_tail(&gl->gl_lru, &lru_list);
atomic_inc(&lru_count);
}
@@ -190,6 +216,21 @@ static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
}
/**
+ * gfs2_glock_put_nolock() - Decrement reference count on glock
+ * @gl: The glock to put
+ *
+ * This function should only be used if the caller has its own reference
+ * to the glock, in addition to the one it is dropping.
+ */
+
+void gfs2_glock_put_nolock(struct gfs2_glock *gl)
+{
+ if (atomic_dec_and_test(&gl->gl_ref))
+ GLOCK_BUG_ON(gl, 1);
+ gfs2_glock_schedule_for_reclaim(gl);
+}
+
+/**
* gfs2_glock_put() - Decrement reference count on glock
* @gl: The glock to put
*
@@ -214,9 +255,9 @@ int gfs2_glock_put(struct gfs2_glock *gl)
rv = 1;
goto out;
}
- /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */
- if (atomic_read(&gl->gl_ref) == 2)
- gfs2_glock_schedule_for_reclaim(gl);
+ spin_lock(&gl->gl_spin);
+ gfs2_glock_schedule_for_reclaim(gl);
+ spin_unlock(&gl->gl_spin);
write_unlock(gl_lock_addr(gl->gl_hash));
out:
return rv;
@@ -398,7 +439,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
if (held2)
gfs2_glock_hold(gl);
else
- gfs2_glock_put(gl);
+ gfs2_glock_put_nolock(gl);
}
gl->gl_state = new_state;
@@ -633,12 +674,35 @@ out:
out_sched:
gfs2_glock_hold(gl);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
- gfs2_glock_put(gl);
+ gfs2_glock_put_nolock(gl);
out_unlock:
clear_bit(GLF_LOCK, &gl->gl_flags);
goto out;
}
+static void delete_work_func(struct work_struct *work)
+{
+ struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct gfs2_inode *ip = NULL;
+ struct inode *inode;
+ u64 no_addr = 0;
+
+ spin_lock(&gl->gl_spin);
+ ip = (struct gfs2_inode *)gl->gl_object;
+ if (ip)
+ no_addr = ip->i_no_addr;
+ spin_unlock(&gl->gl_spin);
+ if (ip) {
+ inode = gfs2_ilookup(sdp->sd_vfs, no_addr);
+ if (inode) {
+ d_prune_aliases(inode);
+ iput(inode);
+ }
+ }
+ gfs2_glock_put(gl);
+}
+
static void glock_work_func(struct work_struct *work)
{
unsigned long delay = 0;
@@ -717,6 +781,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_sbd = sdp;
gl->gl_aspace = NULL;
INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
+ INIT_WORK(&gl->gl_delete, delete_work_func);
/* If this glock protects actual on-disk data or metadata blocks,
create a VFS inode to manage the pages/buffers holding them. */
@@ -858,6 +923,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
gl->gl_demote_state != state) {
gl->gl_demote_state = LM_ST_UNLOCKED;
}
+ if (gl->gl_ops->go_callback)
+ gl->gl_ops->go_callback(gl);
trace_gfs2_demote_rq(gl);
}
@@ -1274,33 +1341,12 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
gfs2_glock_put(gl);
}
-/**
- * demote_ok - Check to see if it's ok to unlock a glock
- * @gl: the glock
- *
- * Returns: 1 if it's ok
- */
-
-static int demote_ok(const struct gfs2_glock *gl)
-{
- const struct gfs2_glock_operations *glops = gl->gl_ops;
-
- if (gl->gl_state == LM_ST_UNLOCKED)
- return 0;
- if (!list_empty(&gl->gl_holders))
- return 0;
- if (glops->go_demote_ok)
- return glops->go_demote_ok(gl);
- return 1;
-}
-
static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask)
{
struct gfs2_glock *gl;
int may_demote;
int nr_skipped = 0;
- int got_ref = 0;
LIST_HEAD(skipped);
if (nr == 0)
@@ -1315,37 +1361,29 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask)
list_del_init(&gl->gl_lru);
atomic_dec(&lru_count);
+ /* Check if glock is about to be freed */
+ if (atomic_read(&gl->gl_ref) == 0)
+ continue;
+
/* Test for being demotable */
if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
gfs2_glock_hold(gl);
- got_ref = 1;
spin_unlock(&lru_lock);
spin_lock(&gl->gl_spin);
may_demote = demote_ok(gl);
- spin_unlock(&gl->gl_spin);
- clear_bit(GLF_LOCK, &gl->gl_flags);
if (may_demote) {
handle_callback(gl, LM_ST_UNLOCKED, 0);
nr--;
- if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
- gfs2_glock_put(gl);
- got_ref = 0;
}
+ 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);
- if (may_demote)
- continue;
- }
- if (list_empty(&gl->gl_lru) &&
- (atomic_read(&gl->gl_ref) <= (2 + got_ref))) {
- nr_skipped++;
- list_add(&gl->gl_lru, &skipped);
- }
- if (got_ref) {
- spin_unlock(&lru_lock);
- gfs2_glock_put(gl);
- spin_lock(&lru_lock);
- got_ref = 0;
+ continue;
}
+ nr_skipped++;
+ list_add(&gl->gl_lru, &skipped);
}
list_splice(&skipped, &lru_list);
atomic_add(nr_skipped, &lru_count);
@@ -1727,6 +1765,11 @@ int __init gfs2_glock_init(void)
glock_workqueue = create_workqueue("glock_workqueue");
if (IS_ERR(glock_workqueue))
return PTR_ERR(glock_workqueue);
+ gfs2_delete_workqueue = create_workqueue("delete_workqueue");
+ if (IS_ERR(gfs2_delete_workqueue)) {
+ destroy_workqueue(glock_workqueue);
+ return PTR_ERR(gfs2_delete_workqueue);
+ }
register_shrinker(&glock_shrinker);
@@ -1737,6 +1780,7 @@ void gfs2_glock_exit(void)
{
unregister_shrinker(&glock_shrinker);
destroy_workqueue(glock_workqueue);
+ destroy_workqueue(gfs2_delete_workqueue);
}
static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index a602a28f6f08..c609894ec0d0 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -143,6 +143,7 @@ struct lm_lockops {
#define GLR_TRYFAILED 13
+extern struct workqueue_struct *gfs2_delete_workqueue;
static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
{
struct gfs2_holder *gh;
@@ -191,6 +192,8 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
int gfs2_glock_get(struct gfs2_sbd *sdp,
u64 number, const struct gfs2_glock_operations *glops,
int create, struct gfs2_glock **glp);
+void gfs2_glock_hold(struct gfs2_glock *gl);
+void gfs2_glock_put_nolock(struct gfs2_glock *gl);
int gfs2_glock_put(struct gfs2_glock *gl);
void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
struct gfs2_holder *gh);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index d5e4ab155ca0..6985eef06c39 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -323,6 +323,7 @@ static void trans_go_sync(struct gfs2_glock *gl)
if (gl->gl_state != LM_ST_UNLOCKED &&
test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+ flush_workqueue(gfs2_delete_workqueue);
gfs2_meta_syncfs(sdp);
gfs2_log_shutdown(sdp);
}
@@ -372,6 +373,25 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl)
return 0;
}
+/**
+ * iopen_go_callback - schedule the dcache entry for the inode to be deleted
+ * @gl: the glock
+ *
+ * gl_spin lock is held while calling this
+ */
+static void iopen_go_callback(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;
+
+ if (gl->gl_demote_state == LM_ST_UNLOCKED &&
+ gl->gl_state == LM_ST_SHARED &&
+ ip && test_bit(GIF_USER, &ip->i_flags)) {
+ gfs2_glock_hold(gl);
+ if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+ gfs2_glock_put_nolock(gl);
+ }
+}
+
const struct gfs2_glock_operations gfs2_meta_glops = {
.go_type = LM_TYPE_META,
};
@@ -406,6 +426,7 @@ const struct gfs2_glock_operations gfs2_trans_glops = {
const struct gfs2_glock_operations gfs2_iopen_glops = {
.go_type = LM_TYPE_IOPEN,
+ .go_callback = iopen_go_callback,
};
const struct gfs2_glock_operations gfs2_flock_glops = {
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 225347fbff3c..61801ada36f0 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -159,6 +159,7 @@ struct gfs2_glock_operations {
int (*go_lock) (struct gfs2_holder *gh);
void (*go_unlock) (struct gfs2_holder *gh);
int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl);
+ void (*go_callback) (struct gfs2_glock *gl);
const int go_type;
const unsigned long go_min_hold_time;
};
@@ -228,6 +229,7 @@ struct gfs2_glock {
struct list_head gl_ail_list;
atomic_t gl_ail_count;
struct delayed_work gl_work;
+ struct work_struct gl_delete;
};
#define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 2f94bd723698..f9b4fe886540 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -731,7 +731,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
if (error)
goto out_ipreserv;
- *no_addr = gfs2_alloc_di(dip, generation);
+ error = gfs2_alloc_di(dip, no_addr, generation);
gfs2_trans_end(sdp);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 7bc3c45cd676..39021c020176 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1133,6 +1133,17 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp)
lm->lm_unmount(sdp);
}
+void gfs2_online_uevent(struct gfs2_sbd *sdp)
+{
+ struct super_block *sb = sdp->sd_vfs;
+ char ro[20];
+ char spectator[20];
+ char *envp[] = { ro, spectator, NULL };
+ sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
+ sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
+ kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp);
+}
+
/**
* fill_super - Read in superblock
* @sb: The VFS superblock
@@ -1236,7 +1247,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
}
gfs2_glock_dq_uninit(&mount_gh);
-
+ gfs2_online_uevent(sdp);
return 0;
fail_threads:
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index daa4ae341a29..16193d834746 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -179,7 +179,7 @@ static inline u64 gfs2_bit_search(const __le64 *ptr, u64 mask, u8 state)
* always aligned to a 64 bit boundary.
*
* The size of the buffer is in bytes, but is it assumed that it is
- * always ok to to read a complete multiple of 64 bits at the end
+ * always ok to read a complete multiple of 64 bits at the end
* of the block in case the end is no aligned to a natural boundary.
*
* Return: the block number (bitmap buffer scope) that was found
@@ -285,27 +285,19 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd)
}
tmp = rgd->rd_data - rgd->rd_free - rgd->rd_dinodes;
- if (count[1] + count[2] != tmp) {
+ if (count[1] != tmp) {
if (gfs2_consist_rgrpd(rgd))
fs_err(sdp, "used data mismatch: %u != %u\n",
count[1], tmp);
return;
}
- if (count[3] != rgd->rd_dinodes) {
+ if (count[2] + count[3] != rgd->rd_dinodes) {
if (gfs2_consist_rgrpd(rgd))
fs_err(sdp, "used metadata mismatch: %u != %u\n",
- count[3], rgd->rd_dinodes);
+ count[2] + count[3], rgd->rd_dinodes);
return;
}
-
- if (count[2] > count[3]) {
- if (gfs2_consist_rgrpd(rgd))
- fs_err(sdp, "unlinked inodes > inodes: %u\n",
- count[2]);
- return;
- }
-
}
static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
@@ -961,7 +953,8 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
* Returns: The inode, if one has been found
*/
-static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
+static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
+ u64 skip)
{
struct inode *inode;
u32 goal = 0, block;
@@ -985,6 +978,8 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
goal++;
if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
continue;
+ if (no_addr == skip)
+ continue;
*last_unlinked = no_addr;
inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,
no_addr, -1, 1);
@@ -1104,7 +1099,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
- inode = try_rgrp_unlink(rgd, last_unlinked);
+ inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
@@ -1138,7 +1133,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
- inode = try_rgrp_unlink(rgd, last_unlinked);
+ inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (inode)
@@ -1464,6 +1459,16 @@ int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl)
return 0;
}
+static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n",
+ (unsigned long long)rgd->rd_addr);
+ fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n");
+ gfs2_rgrp_dump(NULL, rgd->rd_gl);
+ rgd->rd_flags |= GFS2_RDF_ERROR;
+}
+
/**
* gfs2_alloc_block - Allocate one or more blocks
* @ip: the inode to allocate the block for
@@ -1525,22 +1530,20 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
return 0;
rgrp_error:
- fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n",
- (unsigned long long)rgd->rd_addr);
- fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n");
- gfs2_rgrp_dump(NULL, rgd->rd_gl);
- rgd->rd_flags |= GFS2_RDF_ERROR;
+ gfs2_rgrp_error(rgd);
return -EIO;
}
/**
* gfs2_alloc_di - Allocate a dinode
* @dip: the directory that the inode is going in
+ * @bn: the block number which is allocated
+ * @generation: the generation number of the inode
*
- * Returns: the block allocated
+ * Returns: 0 on success or error
*/
-u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
+int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc *al = dip->i_alloc;
@@ -1551,12 +1554,13 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
blk = rgblk_search(rgd, rgd->rd_last_alloc,
GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n);
- BUG_ON(blk == BFITNOENT);
- rgd->rd_last_alloc = blk;
+ /* Since all blocks are reserved in advance, this shouldn't happen */
+ if (blk == BFITNOENT)
+ goto rgrp_error;
+ rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk;
-
gfs2_assert_withdraw(sdp, rgd->rd_free);
rgd->rd_free--;
rgd->rd_dinodes++;
@@ -1573,7 +1577,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
rgd->rd_free_clone--;
spin_unlock(&sdp->sd_rindex_spin);
trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
- return block;
+ *bn = block;
+ return 0;
+
+rgrp_error:
+ gfs2_rgrp_error(rgd);
+ return -EIO;
}
/**
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index 1e76ff0f3e00..a8dedd78245b 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -47,7 +47,7 @@ extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
-extern u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
+extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 0a6801336470..85bd2bc8c1de 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -353,7 +353,7 @@ fail:
return error;
}
-static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
+void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
{
const struct gfs2_statfs_change *str = buf;
@@ -441,6 +441,29 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
brelse(l_bh);
}
+void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
+ struct buffer_head *l_bh)
+{
+ 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;
+ struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+
+ gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+
+ spin_lock(&sdp->sd_statfs_spin);
+ m_sc->sc_total += l_sc->sc_total;
+ m_sc->sc_free += l_sc->sc_free;
+ m_sc->sc_dinodes += l_sc->sc_dinodes;
+ memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
+ memset(l_bh->b_data + sizeof(struct gfs2_dinode),
+ 0, sizeof(struct gfs2_statfs_change));
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+ gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+}
+
int gfs2_statfs_sync(struct gfs2_sbd *sdp)
{
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
@@ -477,19 +500,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
if (error)
goto out_bh2;
- gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
-
- spin_lock(&sdp->sd_statfs_spin);
- m_sc->sc_total += l_sc->sc_total;
- m_sc->sc_free += l_sc->sc_free;
- m_sc->sc_dinodes += l_sc->sc_dinodes;
- memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
- memset(l_bh->b_data + sizeof(struct gfs2_dinode),
- 0, sizeof(struct gfs2_statfs_change));
- spin_unlock(&sdp->sd_statfs_spin);
-
- gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
- gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+ update_statfs(sdp, m_bh, l_bh);
gfs2_trans_end(sdp);
@@ -680,6 +691,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
struct gfs2_holder t_gh;
int error;
+ flush_workqueue(gfs2_delete_workqueue);
gfs2_quota_sync(sdp);
gfs2_statfs_sync(sdp);
@@ -1072,6 +1084,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
gt->gt_log_flush_secs = args.ar_commit;
spin_unlock(&gt->gt_spin);
+ gfs2_online_uevent(sdp);
return 0;
}
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index b56413e3e40d..911c954cefbd 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -25,7 +25,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
return x;
}
-void gfs2_jindex_free(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);
@@ -36,10 +36,14 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
struct gfs2_inode **ipp);
extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
-
+extern void gfs2_online_uevent(struct gfs2_sbd *sdp);
extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
s64 dinodes);
+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_freeze_fs(struct gfs2_sbd *sdp);
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 23419dc3027b..f520480e0423 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -519,7 +519,14 @@ static struct attribute_group lock_module_group = {
int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
{
+ struct super_block *sb = sdp->sd_vfs;
int error;
+ char ro[20];
+ char spectator[20];
+ char *envp[] = { ro, spectator, NULL };
+
+ sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
+ sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
sdp->sd_kobj.kset = gfs2_kset;
error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
@@ -535,7 +542,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
if (error)
goto fail_tune;
- kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
+ kobject_uevent_env(&sdp->sd_kobj, KOBJ_ADD, envp);
return 0;
fail_tune:
@@ -554,7 +561,6 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
kobject_put(&sdp->sd_kobj);
}
-
static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
@@ -563,6 +569,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
+ if (!sdp->sd_args.ar_spectator)
+ add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid);
if (gfs2_uuid_valid(uuid)) {
add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-"
"%02X%02X-%02X%02X%02X%02X%02X%02X",
@@ -578,7 +586,6 @@ static struct kset_uevent_ops gfs2_uevent_ops = {
.uevent = gfs2_uevent,
};
-
int gfs2_sys_init(void)
{
gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 941c8425c10b..2d8abaf3b8a8 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -44,6 +44,7 @@ static const struct inode_operations hugetlbfs_dir_inode_operations;
static const struct inode_operations hugetlbfs_inode_operations;
static struct backing_dev_info hugetlbfs_backing_dev_info = {
+ .name = "hugetlbfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 737f7246a4b5..f96f85092d1c 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -287,6 +287,7 @@ int journal_write_metadata_buffer(transaction_t *transaction,
struct page *new_page;
unsigned int new_offset;
struct buffer_head *bh_in = jh2bh(jh_in);
+ journal_t *journal = transaction->t_journal;
/*
* The buffer really shouldn't be locked: only the current committing
@@ -300,6 +301,11 @@ int journal_write_metadata_buffer(transaction_t *transaction,
J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+ /* keep subsequent assertions sane */
+ new_bh->b_state = 0;
+ init_buffer(new_bh, NULL, NULL);
+ atomic_set(&new_bh->b_count, 1);
+ new_jh = journal_add_journal_head(new_bh); /* This sleeps */
/*
* If a new transaction has already done a buffer copy-out, then
@@ -361,14 +367,6 @@ repeat:
kunmap_atomic(mapped_data, KM_USER0);
}
- /* keep subsequent assertions sane */
- new_bh->b_state = 0;
- init_buffer(new_bh, NULL, NULL);
- atomic_set(&new_bh->b_count, 1);
- jbd_unlock_bh_state(bh_in);
-
- new_jh = journal_add_journal_head(new_bh); /* This sleeps */
-
set_bh_page(new_bh, new_page, new_offset);
new_jh->b_transaction = NULL;
new_bh->b_size = jh2bh(jh_in)->b_size;
@@ -385,7 +383,11 @@ repeat:
* copying is moved to the transaction's shadow queue.
*/
JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
- journal_file_buffer(jh_in, transaction, BJ_Shadow);
+ spin_lock(&journal->j_list_lock);
+ __journal_file_buffer(jh_in, transaction, BJ_Shadow);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh_in);
+
JBUFFER_TRACE(new_jh, "file as BJ_IO");
journal_file_buffer(new_jh, transaction, BJ_IO);
@@ -848,6 +850,12 @@ static int journal_reset(journal_t *journal)
first = be32_to_cpu(sb->s_first);
last = be32_to_cpu(sb->s_maxlen);
+ if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) {
+ printk(KERN_ERR "JBD: Journal too short (blocks %lu-%lu).\n",
+ first, last);
+ journal_fail_superblock(journal);
+ return -EINVAL;
+ }
journal->j_first = first;
journal->j_last = last;
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 73242ba7c7b1..c03ac11f74be 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -489,34 +489,15 @@ void journal_unlock_updates (journal_t *journal)
wake_up(&journal->j_wait_transaction_locked);
}
-/*
- * Report any unexpected dirty buffers which turn up. Normally those
- * indicate an error, but they can occur if the user is running (say)
- * tune2fs to modify the live filesystem, so we need the option of
- * continuing as gracefully as possible. #
- *
- * The caller should already hold the journal lock and
- * j_list_lock spinlock: most callers will need those anyway
- * in order to probe the buffer's journaling state safely.
- */
-static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+static void warn_dirty_buffer(struct buffer_head *bh)
{
- int jlist;
-
- /* If this buffer is one which might reasonably be dirty
- * --- ie. data, or not part of this journal --- then
- * we're OK to leave it alone, but otherwise we need to
- * move the dirty bit to the journal's own internal
- * JBDDirty bit. */
- jlist = jh->b_jlist;
+ char b[BDEVNAME_SIZE];
- if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
- jlist == BJ_Shadow || jlist == BJ_Forget) {
- struct buffer_head *bh = jh2bh(jh);
-
- if (test_clear_buffer_dirty(bh))
- set_buffer_jbddirty(bh);
- }
+ printk(KERN_WARNING
+ "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+ "There's a risk of filesystem corruption in case of system "
+ "crash.\n",
+ bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
}
/*
@@ -583,14 +564,16 @@ repeat:
if (jh->b_next_transaction)
J_ASSERT_JH(jh, jh->b_next_transaction ==
transaction);
+ warn_dirty_buffer(bh);
}
/*
* In any case we need to clean the dirty flag and we must
* do it under the buffer lock to be sure we don't race
* with running write-out.
*/
- JBUFFER_TRACE(jh, "Unexpected dirty buffer");
- jbd_unexpected_dirty_buffer(jh);
+ JBUFFER_TRACE(jh, "Journalling dirty buffer");
+ clear_buffer_dirty(bh);
+ set_buffer_jbddirty(bh);
}
unlock_buffer(bh);
@@ -826,6 +809,15 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
if (jh->b_transaction == NULL) {
+ /*
+ * Previous journal_forget() could have left the buffer
+ * with jbddirty bit set because it was being committed. When
+ * the commit finished, we've filed the buffer for
+ * checkpointing and marked it dirty. Now we are reallocating
+ * the buffer so the transaction freeing it must have
+ * committed and so it's safe to clear the dirty bit.
+ */
+ clear_buffer_dirty(jh2bh(jh));
jh->b_transaction = transaction;
/* first access by this transaction */
@@ -1782,8 +1774,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
if (jh->b_cp_transaction) {
JBUFFER_TRACE(jh, "on running+cp transaction");
+ /*
+ * We don't want to write the buffer anymore, clear the
+ * bit so that we don't confuse checks in
+ * __journal_file_buffer
+ */
+ clear_buffer_dirty(bh);
__journal_file_buffer(jh, transaction, BJ_Forget);
- clear_buffer_jbddirty(bh);
may_free = 0;
} else {
JBUFFER_TRACE(jh, "on running transaction");
@@ -2041,12 +2038,17 @@ void __journal_file_buffer(struct journal_head *jh,
if (jh->b_transaction && jh->b_jlist == jlist)
return;
- /* The following list of buffer states needs to be consistent
- * with __jbd_unexpected_dirty_buffer()'s handling of dirty
- * state. */
-
if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
jlist == BJ_Shadow || jlist == BJ_Forget) {
+ /*
+ * For metadata buffers, we track dirty bit in buffer_jbddirty
+ * instead of buffer_dirty. We should not see a dirty bit set
+ * here because we clear it in do_get_write_access but e.g.
+ * tune2fs can modify the sb and set the dirty bit at any time
+ * so we try to gracefully handle that.
+ */
+ if (buffer_dirty(bh))
+ warn_dirty_buffer(bh);
if (test_clear_buffer_dirty(bh) ||
test_clear_buffer_jbddirty(bh))
was_dirty = 1;
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 91fa3ad6e8c2..a29c7c3e3fb8 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -67,10 +67,8 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
acl = posix_acl_from_xattr(value, size);
}
kfree(value);
- if (!IS_ERR(acl)) {
+ if (!IS_ERR(acl))
set_cached_acl(inode, type, acl);
- posix_acl_release(acl);
- }
return acl;
}
diff --git a/fs/locks.c b/fs/locks.c
index b6440f52178f..52366e877d76 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
if (can_sleep)
lock->fl_flags |= FL_SLEEP;
- error = security_file_lock(filp, cmd);
+ error = security_file_lock(filp, lock->fl_type);
if (error)
goto out_free;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 8d25ccb2d51d..c6be84a161f6 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -879,6 +879,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
server->rsize = NFS_MAX_FILE_IO_SIZE;
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ server->backing_dev_info.name = "nfs";
server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
if (server->wsize > max_rpc_payload)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7c8801769a3c..6fde431df9ee 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -123,6 +123,35 @@ nfsd4_check_open_attributes(struct svc_rqst *rqstp,
return status;
}
+static int
+is_create_with_attrs(struct nfsd4_open *open)
+{
+ return open->op_create == NFS4_OPEN_CREATE
+ && (open->op_createmode == NFS4_CREATE_UNCHECKED
+ || open->op_createmode == NFS4_CREATE_GUARDED
+ || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
+}
+
+/*
+ * if error occurs when setting the acl, just clear the acl bit
+ * in the returned attr bitmap.
+ */
+static void
+do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_acl *acl, u32 *bmval)
+{
+ __be32 status;
+
+ status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
+ if (status)
+ /*
+ * We should probably fail the whole open at this point,
+ * but we've already created the file, so it's too late;
+ * So this seems the least of evils:
+ */
+ bmval[0] &= ~FATTR4_WORD0_ACL;
+}
+
static inline void
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
{
@@ -206,6 +235,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
if (status)
goto out;
+ if (is_create_with_attrs(open) && open->op_acl != NULL)
+ do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
+
set_change_info(&open->op_cinfo, current_fh);
fh_dup2(current_fh, &resfh);
@@ -536,12 +568,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_badtype;
}
- if (!status) {
- fh_unlock(&cstate->current_fh);
- set_change_info(&create->cr_cinfo, &cstate->current_fh);
- fh_dup2(&cstate->current_fh, &resfh);
- }
+ if (status)
+ goto out;
+ if (create->cr_acl != NULL)
+ do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
+ create->cr_bmval);
+
+ fh_unlock(&cstate->current_fh);
+ set_change_info(&create->cr_cinfo, &cstate->current_fh);
+ fh_dup2(&cstate->current_fh, &resfh);
+out:
fh_put(&resfh);
return status;
}
@@ -947,34 +984,6 @@ static struct nfsd4_operation nfsd4_ops[];
static const char *nfsd4_op_name(unsigned opnum);
/*
- * This is a replay of a compound for which no cache entry pages
- * were used. Encode the sequence operation, and if cachethis is FALSE
- * encode the uncache rep error on the next operation.
- */
-static __be32
-nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
- struct nfsd4_compoundres *resp)
-{
- struct nfsd4_op *op;
-
- dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
- resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
-
- /* Encode the replayed sequence operation */
- BUG_ON(resp->opcnt != 1);
- op = &args->ops[resp->opcnt - 1];
- nfsd4_encode_operation(resp, op);
-
- /*return nfserr_retry_uncached_rep in next operation. */
- if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
- op = &args->ops[resp->opcnt++];
- op->status = nfserr_retry_uncached_rep;
- nfsd4_encode_operation(resp, op);
- }
- return op->status;
-}
-
-/*
* Enforce NFSv4.1 COMPOUND ordering rules.
*
* TODO:
@@ -1083,13 +1092,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
BUG_ON(op->status == nfs_ok);
encode_op:
- /* Only from SEQUENCE or CREATE_SESSION */
+ /* Only from SEQUENCE */
if (resp->cstate.status == nfserr_replay_cache) {
dprintk("%s NFS4.1 replay from cache\n", __func__);
- if (nfsd4_not_cached(resp))
- status = nfsd4_enc_uncached_replay(args, resp);
- else
- status = op->status;
+ status = op->status;
goto out;
}
if (op->status == nfserr_replay_me) {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 980a216a48c8..9295c4b56bce 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -414,35 +414,34 @@ gen_sessionid(struct nfsd4_session *ses)
/*
* Give the client the number of slots it requests bound by
- * NFSD_MAX_SLOTS_PER_SESSION and by sv_drc_max_pages.
+ * NFSD_MAX_SLOTS_PER_SESSION and by nfsd_drc_max_mem.
*
- * If we run out of pages (sv_drc_pages_used == sv_drc_max_pages) we
- * should (up to a point) re-negotiate active sessions and reduce their
- * slot usage to make rooom for new connections. For now we just fail the
- * create session.
+ * If we run out of reserved DRC memory we should (up to a point) re-negotiate
+ * active sessions and reduce their slot usage to make rooom for new
+ * connections. For now we just fail the create session.
*/
static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan)
{
- int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT;
+ int mem;
if (fchan->maxreqs < 1)
return nfserr_inval;
else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
- spin_lock(&nfsd_serv->sv_lock);
- if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages)
- np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used;
- nfsd_serv->sv_drc_pages_used += np;
- spin_unlock(&nfsd_serv->sv_lock);
+ mem = fchan->maxreqs * NFSD_SLOT_CACHE_SIZE;
- if (np <= 0) {
- status = nfserr_resource;
- fchan->maxreqs = 0;
- } else
- fchan->maxreqs = np / NFSD_PAGES_PER_SLOT;
+ spin_lock(&nfsd_drc_lock);
+ if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem)
+ mem = ((nfsd_drc_max_mem - nfsd_drc_mem_used) /
+ NFSD_SLOT_CACHE_SIZE) * NFSD_SLOT_CACHE_SIZE;
+ nfsd_drc_mem_used += mem;
+ spin_unlock(&nfsd_drc_lock);
- return status;
+ fchan->maxreqs = mem / NFSD_SLOT_CACHE_SIZE;
+ if (fchan->maxreqs == 0)
+ return nfserr_resource;
+ return 0;
}
/*
@@ -466,9 +465,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp,
fchan->maxresp_sz = maxcount;
session_fchan->maxresp_sz = fchan->maxresp_sz;
- /* Set the max response cached size our default which is
- * a multiple of PAGE_SIZE and small */
- session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE;
+ session_fchan->maxresp_cached = NFSD_SLOT_CACHE_SIZE;
fchan->maxresp_cached = session_fchan->maxresp_cached;
/* Use the client's maxops if possible */
@@ -476,10 +473,6 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp,
fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
session_fchan->maxops = fchan->maxops;
- /* try to use the client requested number of slots */
- if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
- fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
-
/* FIXME: Error means no more DRC pages so the server should
* recover pages from existing sessions. For now fail session
* creation.
@@ -585,6 +578,9 @@ free_session(struct kref *kref)
struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry;
nfsd4_release_respages(e->ce_respages, e->ce_resused);
}
+ spin_lock(&nfsd_drc_lock);
+ nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE;
+ spin_unlock(&nfsd_drc_lock);
kfree(ses);
}
@@ -657,8 +653,6 @@ static inline void
free_client(struct nfs4_client *clp)
{
shutdown_callback_client(clp);
- nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages,
- clp->cl_slot.sl_cache_entry.ce_resused);
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
kfree(clp->cl_principal);
@@ -1115,6 +1109,36 @@ nfsd41_copy_replay_data(struct nfsd4_compoundres *resp,
}
/*
+ * Encode the replay sequence operation from the slot values.
+ * If cachethis is FALSE encode the uncached rep error on the next
+ * operation which sets resp->p and increments resp->opcnt for
+ * nfs4svc_encode_compoundres.
+ *
+ */
+static __be32
+nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
+ struct nfsd4_compoundres *resp)
+{
+ struct nfsd4_op *op;
+ struct nfsd4_slot *slot = resp->cstate.slot;
+
+ dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__,
+ resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
+
+ /* Encode the replayed sequence operation */
+ op = &args->ops[resp->opcnt - 1];
+ nfsd4_encode_operation(resp, op);
+
+ /* Return nfserr_retry_uncached_rep in next operation. */
+ if (args->opcnt > 1 && slot->sl_cache_entry.ce_cachethis == 0) {
+ op = &args->ops[resp->opcnt++];
+ op->status = nfserr_retry_uncached_rep;
+ nfsd4_encode_operation(resp, op);
+ }
+ return op->status;
+}
+
+/*
* Keep the first page of the replay. Copy the NFSv4.1 data from the first
* cached page. Replace any futher replay pages from the cache.
*/
@@ -1137,10 +1161,12 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
* session inactivity timer fires and a solo sequence operation
* is sent (lease renewal).
*/
- if (seq && nfsd4_not_cached(resp)) {
- seq->maxslots = resp->cstate.session->se_fchannel.maxreqs;
- return nfs_ok;
- }
+ seq->maxslots = resp->cstate.session->se_fchannel.maxreqs;
+
+ /* Either returns 0 or nfserr_retry_uncached */
+ status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
+ if (status == nfserr_retry_uncached_rep)
+ return status;
if (!nfsd41_copy_replay_data(resp, entry)) {
/*
@@ -1297,12 +1323,11 @@ out_copy:
exid->clientid.cl_boot = new->cl_clientid.cl_boot;
exid->clientid.cl_id = new->cl_clientid.cl_id;
- new->cl_slot.sl_seqid = 0;
exid->seqid = 1;
nfsd4_set_ex_flags(new, exid);
dprintk("nfsd4_exchange_id seqid %d flags %x\n",
- new->cl_slot.sl_seqid, new->cl_exchange_flags);
+ new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
status = nfs_ok;
out:
@@ -1313,40 +1338,60 @@ error:
}
static int
-check_slot_seqid(u32 seqid, struct nfsd4_slot *slot)
+check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
{
- dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid,
- slot->sl_seqid);
+ dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
+ slot_seqid);
/* The slot is in use, and no response has been sent. */
- if (slot->sl_inuse) {
- if (seqid == slot->sl_seqid)
+ if (slot_inuse) {
+ if (seqid == slot_seqid)
return nfserr_jukebox;
else
return nfserr_seq_misordered;
}
/* Normal */
- if (likely(seqid == slot->sl_seqid + 1))
+ if (likely(seqid == slot_seqid + 1))
return nfs_ok;
/* Replay */
- if (seqid == slot->sl_seqid)
+ if (seqid == slot_seqid)
return nfserr_replay_cache;
/* Wraparound */
- if (seqid == 1 && (slot->sl_seqid + 1) == 0)
+ if (seqid == 1 && (slot_seqid + 1) == 0)
return nfs_ok;
/* Misordered replay or misordered new request */
return nfserr_seq_misordered;
}
+/*
+ * Cache the create session result into the create session single DRC
+ * slot cache by saving the xdr structure. sl_seqid has been set.
+ * Do this for solo or embedded create session operations.
+ */
+static void
+nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
+ struct nfsd4_clid_slot *slot, int nfserr)
+{
+ slot->sl_status = nfserr;
+ memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
+}
+
+static __be32
+nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
+ struct nfsd4_clid_slot *slot)
+{
+ memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
+ return slot->sl_status;
+}
+
__be32
nfsd4_create_session(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
struct nfsd4_create_session *cr_ses)
{
u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr;
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct nfs4_client *conf, *unconf;
- struct nfsd4_slot *slot = NULL;
+ struct nfsd4_clid_slot *cs_slot = NULL;
int status = 0;
nfs4_lock_state();
@@ -1354,24 +1399,22 @@ nfsd4_create_session(struct svc_rqst *rqstp,
conf = find_confirmed_client(&cr_ses->clientid);
if (conf) {
- slot = &conf->cl_slot;
- status = check_slot_seqid(cr_ses->seqid, slot);
+ cs_slot = &conf->cl_cs_slot;
+ status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
if (status == nfserr_replay_cache) {
dprintk("Got a create_session replay! seqid= %d\n",
- slot->sl_seqid);
- cstate->slot = slot;
- cstate->status = status;
+ cs_slot->sl_seqid);
/* Return the cached reply status */
- status = nfsd4_replay_cache_entry(resp, NULL);
+ status = nfsd4_replay_create_session(cr_ses, cs_slot);
goto out;
- } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) {
+ } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
status = nfserr_seq_misordered;
dprintk("Sequence misordered!\n");
dprintk("Expected seqid= %d but got seqid= %d\n",
- slot->sl_seqid, cr_ses->seqid);
+ cs_slot->sl_seqid, cr_ses->seqid);
goto out;
}
- conf->cl_slot.sl_seqid++;
+ cs_slot->sl_seqid++;
} else if (unconf) {
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
(ip_addr != unconf->cl_addr)) {
@@ -1379,15 +1422,15 @@ nfsd4_create_session(struct svc_rqst *rqstp,
goto out;
}
- slot = &unconf->cl_slot;
- status = check_slot_seqid(cr_ses->seqid, slot);
+ cs_slot = &unconf->cl_cs_slot;
+ status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
if (status) {
/* an unconfirmed replay returns misordered */
status = nfserr_seq_misordered;
- goto out;
+ goto out_cache;
}
- slot->sl_seqid++; /* from 0 to 1 */
+ cs_slot->sl_seqid++; /* from 0 to 1 */
move_to_confirmed(unconf);
/*
@@ -1408,12 +1451,11 @@ nfsd4_create_session(struct svc_rqst *rqstp,
memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data,
NFS4_MAX_SESSIONID_LEN);
- cr_ses->seqid = slot->sl_seqid;
+ cr_ses->seqid = cs_slot->sl_seqid;
- slot->sl_inuse = true;
- cstate->slot = slot;
- /* Ensure a page is used for the cache */
- slot->sl_cache_entry.ce_cachethis = 1;
+out_cache:
+ /* cache solo and embedded create sessions under the state lock */
+ nfsd4_cache_create_session(cr_ses, cs_slot, status);
out:
nfs4_unlock_state();
dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1481,7 +1523,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
slot = &session->se_slots[seq->slotid];
dprintk("%s: slotid %d\n", __func__, seq->slotid);
- status = check_slot_seqid(seq->seqid, slot);
+ status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
if (status == nfserr_replay_cache) {
cstate->slot = slot;
cstate->session = session;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2dcc7feaa6ff..fdf632bf1cfe 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3313,8 +3313,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
resp->cstate.slot->sl_inuse = 0;
}
- if (resp->cstate.session)
- nfsd4_put_session(resp->cstate.session);
+ nfsd4_put_session(resp->cstate.session);
}
return 1;
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 6d0847562d87..54cfa8f4a318 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -783,10 +783,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
size -= len;
mesg += len;
}
-
- mutex_unlock(&nfsd_mutex);
- return (mesg-buf);
-
+ rv = mesg - buf;
out_free:
kfree(nthreads);
mutex_unlock(&nfsd_mutex);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 492c79b7800b..d68cd056b281 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -66,6 +66,16 @@ struct timeval nfssvc_boot;
DEFINE_MUTEX(nfsd_mutex);
struct svc_serv *nfsd_serv;
+/*
+ * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
+ * nfsd_drc_max_pages limits the total amount of memory available for
+ * version 4.1 DRC caches.
+ * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
+ */
+spinlock_t nfsd_drc_lock;
+unsigned int nfsd_drc_max_mem;
+unsigned int nfsd_drc_mem_used;
+
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static struct svc_stat nfsd_acl_svcstats;
static struct svc_version * nfsd_acl_version[] = {
@@ -235,13 +245,12 @@ void nfsd_reset_versions(void)
*/
static void set_max_drc(void)
{
- /* The percent of nr_free_buffer_pages used by the V4.1 server DRC */
- #define NFSD_DRC_SIZE_SHIFT 7
- nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages()
- >> NFSD_DRC_SIZE_SHIFT;
- nfsd_serv->sv_drc_pages_used = 0;
- dprintk("%s svc_drc_max_pages %u\n", __func__,
- nfsd_serv->sv_drc_max_pages);
+ #define NFSD_DRC_SIZE_SHIFT 10
+ nfsd_drc_max_mem = (nr_free_buffer_pages()
+ >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
+ nfsd_drc_mem_used = 0;
+ spin_lock_init(&nfsd_drc_lock);
+ dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
}
int nfsd_create_serv(void)
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index 3d3ddb3f5177..2dfd47714ae5 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -412,8 +412,10 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc)
return 0; /* Do not request flush for shadow page cache */
if (!sb) {
writer = nilfs_get_writer(NILFS_MDT(inode)->mi_nilfs);
- if (!writer)
+ if (!writer) {
+ nilfs_put_writer(NILFS_MDT(inode)->mi_nilfs);
return -EROFS;
+ }
sb = writer->s_super;
}
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index 8b5e4778cf28..683df89dbae5 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1859,12 +1859,26 @@ static void nilfs_end_page_io(struct page *page, int err)
if (!page)
return;
- if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page))
+ if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page)) {
/*
* For b-tree node pages, this function may be called twice
* or more because they might be split in a segment.
*/
+ if (PageDirty(page)) {
+ /*
+ * For pages holding split b-tree node buffers, dirty
+ * flag on the buffers may be cleared discretely.
+ * In that case, the page is once redirtied for
+ * remaining buffers, and it must be cancelled if
+ * all the buffers get cleaned later.
+ */
+ lock_page(page);
+ if (nilfs_page_buffers_clean(page))
+ __nilfs_clear_page_dirty(page);
+ unlock_page(page);
+ }
return;
+ }
__nilfs_end_page_io(page, err);
}
@@ -2487,7 +2501,8 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci,
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
nilfs_discontinued(nilfs)) {
down_write(&nilfs->ns_sem);
- req->sb_err = nilfs_commit_super(sbi, 0);
+ req->sb_err = nilfs_commit_super(sbi,
+ nilfs_altsb_need_update(nilfs));
up_write(&nilfs->ns_sem);
}
}
@@ -2675,6 +2690,7 @@ static int nilfs_segctor_thread(void *arg)
} else {
DEFINE_WAIT(wait);
int should_sleep = 1;
+ struct the_nilfs *nilfs;
prepare_to_wait(&sci->sc_wait_daemon, &wait,
TASK_INTERRUPTIBLE);
@@ -2695,6 +2711,9 @@ static int nilfs_segctor_thread(void *arg)
finish_wait(&sci->sc_wait_daemon, &wait);
timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
time_after_eq(jiffies, sci->sc_timer->expires));
+ nilfs = sci->sc_sbi->s_nilfs;
+ if (sci->sc_super->s_dirt && nilfs_sb_need_update(nilfs))
+ set_nilfs_discontinued(nilfs);
}
goto loop;
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 8e2ec43b18f4..0c8af26d3763 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -50,6 +50,8 @@
#include <linux/writeback.h>
#include <linux/kobject.h>
#include <linux/exportfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
#include "nilfs.h"
#include "mdt.h"
#include "alloc.h"
@@ -65,7 +67,6 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem "
"(NILFS)");
MODULE_LICENSE("GPL");
-static void nilfs_write_super(struct super_block *sb);
static int nilfs_remount(struct super_block *sb, int *flags, char *data);
/**
@@ -311,9 +312,6 @@ static void nilfs_put_super(struct super_block *sb)
lock_kernel();
- if (sb->s_dirt)
- nilfs_write_super(sb);
-
nilfs_detach_segment_constructor(sbi);
if (!(sb->s_flags & MS_RDONLY)) {
@@ -336,63 +334,21 @@ static void nilfs_put_super(struct super_block *sb)
unlock_kernel();
}
-/**
- * nilfs_write_super - write super block(s) of NILFS
- * @sb: super_block
- *
- * nilfs_write_super() gets a fs-dependent lock, writes super block(s), and
- * clears s_dirt. This function is called in the section protected by
- * lock_super().
- *
- * The s_dirt flag is managed by each filesystem and we protect it by ns_sem
- * of the struct the_nilfs. Lock order must be as follows:
- *
- * 1. lock_super()
- * 2. down_write(&nilfs->ns_sem)
- *
- * Inside NILFS, locking ns_sem is enough to protect s_dirt and the buffer
- * of the super block (nilfs->ns_sbp[]).
- *
- * In most cases, VFS functions call lock_super() before calling these
- * methods. So we must be careful not to bring on deadlocks when using
- * lock_super(); see generic_shutdown_super(), write_super(), and so on.
- *
- * Note that order of lock_kernel() and lock_super() depends on contexts
- * of VFS. We should also note that lock_kernel() can be used in its
- * protective section and only the outermost one has an effect.
- */
-static void nilfs_write_super(struct super_block *sb)
+static int nilfs_sync_fs(struct super_block *sb, int wait)
{
struct nilfs_sb_info *sbi = NILFS_SB(sb);
struct the_nilfs *nilfs = sbi->s_nilfs;
-
- down_write(&nilfs->ns_sem);
- if (!(sb->s_flags & MS_RDONLY)) {
- struct nilfs_super_block **sbp = nilfs->ns_sbp;
- u64 t = get_seconds();
- int dupsb;
-
- if (!nilfs_discontinued(nilfs) && t >= nilfs->ns_sbwtime[0] &&
- t < nilfs->ns_sbwtime[0] + NILFS_SB_FREQ) {
- up_write(&nilfs->ns_sem);
- return;
- }
- dupsb = sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
- nilfs_commit_super(sbi, dupsb);
- }
- sb->s_dirt = 0;
- up_write(&nilfs->ns_sem);
-}
-
-static int nilfs_sync_fs(struct super_block *sb, int wait)
-{
int err = 0;
- nilfs_write_super(sb);
-
/* This function is called when super block should be written back */
if (wait)
err = nilfs_construct_segment(sb);
+
+ down_write(&nilfs->ns_sem);
+ if (sb->s_dirt)
+ nilfs_commit_super(sbi, 1);
+ up_write(&nilfs->ns_sem);
+
return err;
}
@@ -527,6 +483,26 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
+static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct super_block *sb = vfs->mnt_sb;
+ struct nilfs_sb_info *sbi = NILFS_SB(sb);
+
+ if (!nilfs_test_opt(sbi, BARRIER))
+ seq_printf(seq, ",barrier=off");
+ if (nilfs_test_opt(sbi, SNAPSHOT))
+ seq_printf(seq, ",cp=%llu",
+ (unsigned long long int)sbi->s_snapshot_cno);
+ if (nilfs_test_opt(sbi, ERRORS_RO))
+ seq_printf(seq, ",errors=remount-ro");
+ if (nilfs_test_opt(sbi, ERRORS_PANIC))
+ seq_printf(seq, ",errors=panic");
+ if (nilfs_test_opt(sbi, STRICT_ORDER))
+ seq_printf(seq, ",order=strict");
+
+ return 0;
+}
+
static struct super_operations nilfs_sops = {
.alloc_inode = nilfs_alloc_inode,
.destroy_inode = nilfs_destroy_inode,
@@ -536,7 +512,7 @@ static struct super_operations nilfs_sops = {
/* .drop_inode = nilfs_drop_inode, */
.delete_inode = nilfs_delete_inode,
.put_super = nilfs_put_super,
- .write_super = nilfs_write_super,
+ /* .write_super = nilfs_write_super, */
.sync_fs = nilfs_sync_fs,
/* .write_super_lockfs */
/* .unlockfs */
@@ -544,7 +520,7 @@ static struct super_operations nilfs_sops = {
.remount_fs = nilfs_remount,
.clear_inode = nilfs_clear_inode,
/* .umount_begin */
- /* .show_options */
+ .show_options = nilfs_show_options
};
static struct inode *
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index e8adbffc626f..37f9f355e3e1 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -202,6 +202,20 @@ THE_NILFS_FNS(DISCONTINUED, discontinued)
#define NILFS_SB_FREQ 10
#define NILFS_ALTSB_FREQ 60 /* spare superblock */
+static inline int nilfs_sb_need_update(struct the_nilfs *nilfs)
+{
+ u64 t = get_seconds();
+ return t < nilfs->ns_sbwtime[0] ||
+ t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ;
+}
+
+static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs)
+{
+ u64 t = get_seconds();
+ struct nilfs_super_block **sbp = nilfs->ns_sbp;
+ return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
+}
+
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
struct the_nilfs *find_or_create_nilfs(struct block_device *);
void put_nilfs(struct the_nilfs *);
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 477d37d83b31..b25c218671b3 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -124,10 +124,10 @@ int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
while (*s && len > 0) {
if (*s & 0x80) {
size = utf8_to_utf32(s, len, &u);
- if (size < 0) {
- /* Ignore character and move on */
- size = 1;
- } else if (u >= PLANE_SIZE) {
+ if (size < 0)
+ return -EINVAL;
+
+ if (u >= PLANE_SIZE) {
u -= PLANE_SIZE;
*op++ = (wchar_t) (SURROGATE_PAIR |
((u >> 10) & SURROGATE_BITS));
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
index 31dac7e3b0f1..dffbb0911d02 100644
--- a/fs/notify/Kconfig
+++ b/fs/notify/Kconfig
@@ -1,15 +1,5 @@
config FSNOTIFY
- bool "Filesystem notification backend"
- default y
- ---help---
- fsnotify is a backend for filesystem notification. fsnotify does
- not provide any userspace interface but does provide the basis
- needed for other notification schemes such as dnotify, inotify,
- and fanotify.
-
- Say Y here to enable fsnotify suport.
-
- If unsure, say Y.
+ def_bool n
source "fs/notify/dnotify/Kconfig"
source "fs/notify/inotify/Kconfig"
diff --git a/fs/notify/dnotify/Kconfig b/fs/notify/dnotify/Kconfig
index 904ff8d5405a..f9c1ca139d8f 100644
--- a/fs/notify/dnotify/Kconfig
+++ b/fs/notify/dnotify/Kconfig
@@ -1,6 +1,6 @@
config DNOTIFY
bool "Dnotify support"
- depends on FSNOTIFY
+ select FSNOTIFY
default y
help
Dnotify is a directory-based per-fd file change notification system
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 828a889be909..6b71be963699 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -361,7 +361,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry);
spin_lock(&entry->lock);
} else {
- fsnotify_add_mark(new_entry, dnotify_group, inode);
+ fsnotify_add_mark(new_entry, dnotify_group, inode, 0);
spin_lock(&new_entry->lock);
entry = new_entry;
dnentry = new_dnentry;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index ec2f7bd76818..037e878e03fc 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -159,7 +159,9 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
if (!group->ops->should_send_event(group, to_tell, mask))
continue;
if (!event) {
- event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie);
+ event = fsnotify_create_event(to_tell, mask, data,
+ data_is, file_name, cookie,
+ GFP_KERNEL);
/* shit, we OOM'd and now we can't tell, maybe
* someday someone else will want to do something
* here */
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index c8a07c65482b..3f3261b11295 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -283,12 +283,20 @@ struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *grou
return NULL;
}
+void fsnotify_duplicate_mark(struct fsnotify_mark_entry *new, struct fsnotify_mark_entry *old)
+{
+ assert_spin_locked(&old->lock);
+ new->inode = old->inode;
+ new->group = old->group;
+ new->mask = old->mask;
+ new->free_mark = old->free_mark;
+}
+
/*
* Nothing fancy, just initialize lists and locks and counters.
*/
void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
void (*free_mark)(struct fsnotify_mark_entry *entry))
-
{
spin_lock_init(&entry->lock);
atomic_set(&entry->refcnt, 1);
@@ -305,9 +313,10 @@ void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
* event types should be delivered to which group and for which inodes.
*/
int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
- struct fsnotify_group *group, struct inode *inode)
+ struct fsnotify_group *group, struct inode *inode,
+ int allow_dups)
{
- struct fsnotify_mark_entry *lentry;
+ struct fsnotify_mark_entry *lentry = NULL;
int ret = 0;
inode = igrab(inode);
@@ -327,7 +336,8 @@ int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
entry->group = group;
entry->inode = inode;
- lentry = fsnotify_find_mark_entry(group, inode);
+ if (!allow_dups)
+ lentry = fsnotify_find_mark_entry(group, inode);
if (!lentry) {
hlist_add_head(&entry->i_list, &inode->i_fsnotify_mark_entries);
list_add(&entry->g_list, &group->mark_entries);
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
index 5356884289a1..3e56dbffe729 100644
--- a/fs/notify/inotify/Kconfig
+++ b/fs/notify/inotify/Kconfig
@@ -15,7 +15,7 @@ config INOTIFY
config INOTIFY_USER
bool "Inotify support for userspace"
- depends on FSNOTIFY
+ select FSNOTIFY
default y
---help---
Say Y here to enable inotify support for userspace, including the
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index ff27a2965844..c17d5a3eabf6 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -57,7 +57,6 @@ int inotify_max_user_watches __read_mostly;
static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
struct kmem_cache *event_priv_cachep __read_mostly;
-static struct fsnotify_event *inotify_ignored_event;
/*
* When inotify registers a new group it increments this and uses that
@@ -365,6 +364,17 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
return error;
}
+static void inotify_remove_from_idr(struct fsnotify_group *group,
+ struct inotify_inode_mark_entry *ientry)
+{
+ struct idr *idr;
+
+ spin_lock(&group->inotify_data.idr_lock);
+ idr = &group->inotify_data.idr;
+ idr_remove(idr, ientry->wd);
+ spin_unlock(&group->inotify_data.idr_lock);
+ ientry->wd = -1;
+}
/*
* Send IN_IGNORED for this wd, remove this wd from the idr, and drop the
* internal reference help on the mark because it is in the idr.
@@ -373,13 +383,19 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
struct fsnotify_group *group)
{
struct inotify_inode_mark_entry *ientry;
+ struct fsnotify_event *ignored_event;
struct inotify_event_private_data *event_priv;
struct fsnotify_event_private_data *fsn_event_priv;
- struct idr *idr;
+
+ ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
+ FSNOTIFY_EVENT_NONE, NULL, 0,
+ GFP_NOFS);
+ if (!ignored_event)
+ return;
ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
- event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL);
+ event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
if (unlikely(!event_priv))
goto skip_send_ignore;
@@ -388,7 +404,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
fsn_event_priv->group = group;
event_priv->wd = ientry->wd;
- fsnotify_add_notify_event(group, inotify_ignored_event, fsn_event_priv);
+ fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
/* did the private data get added? */
if (list_empty(&fsn_event_priv->event_list))
@@ -396,14 +412,16 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
skip_send_ignore:
+ /* matches the reference taken when the event was created */
+ fsnotify_put_event(ignored_event);
+
/* remove this entry from the idr */
- spin_lock(&group->inotify_data.idr_lock);
- idr = &group->inotify_data.idr;
- idr_remove(idr, ientry->wd);
- spin_unlock(&group->inotify_data.idr_lock);
+ inotify_remove_from_idr(group, ientry);
/* removed from idr, drop that reference */
fsnotify_put_mark(entry);
+
+ atomic_dec(&group->inotify_data.user->inotify_watches);
}
/* ding dong the mark is dead */
@@ -418,6 +436,7 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
{
struct fsnotify_mark_entry *entry = NULL;
struct inotify_inode_mark_entry *ientry;
+ struct inotify_inode_mark_entry *tmp_ientry;
int ret = 0;
int add = (arg & IN_MASK_ADD);
__u32 mask;
@@ -428,54 +447,66 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
if (unlikely(!mask))
return -EINVAL;
- ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
- if (unlikely(!ientry))
+ tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
+ if (unlikely(!tmp_ientry))
return -ENOMEM;
/* we set the mask at the end after attaching it */
- fsnotify_init_mark(&ientry->fsn_entry, inotify_free_mark);
- ientry->wd = 0;
+ fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
+ tmp_ientry->wd = -1;
find_entry:
spin_lock(&inode->i_lock);
entry = fsnotify_find_mark_entry(group, inode);
spin_unlock(&inode->i_lock);
if (entry) {
- kmem_cache_free(inotify_inode_mark_cachep, ientry);
ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
} else {
- if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) {
- ret = -ENOSPC;
- goto out_err;
- }
-
- ret = fsnotify_add_mark(&ientry->fsn_entry, group, inode);
- if (ret == -EEXIST)
- goto find_entry;
- else if (ret)
+ ret = -ENOSPC;
+ if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
goto out_err;
-
- entry = &ientry->fsn_entry;
retry:
ret = -ENOMEM;
if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
goto out_err;
spin_lock(&group->inotify_data.idr_lock);
- /* if entry is added to the idr we keep the reference obtained
- * through fsnotify_mark_add. remember to drop this reference
- * when entry is removed from idr */
- ret = idr_get_new_above(&group->inotify_data.idr, entry,
- ++group->inotify_data.last_wd,
- &ientry->wd);
+ ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
+ group->inotify_data.last_wd,
+ &tmp_ientry->wd);
spin_unlock(&group->inotify_data.idr_lock);
if (ret) {
if (ret == -EAGAIN)
goto retry;
goto out_err;
}
+
+ ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode, 0);
+ if (ret) {
+ inotify_remove_from_idr(group, tmp_ientry);
+ if (ret == -EEXIST)
+ goto find_entry;
+ goto out_err;
+ }
+
+ /* tmp_ientry has been added to the inode, so we are all set up.
+ * now we just need to make sure tmp_ientry doesn't get freed and
+ * we need to set up entry and ientry so the generic code can
+ * do its thing. */
+ ientry = tmp_ientry;
+ entry = &ientry->fsn_entry;
+ tmp_ientry = NULL;
+
atomic_inc(&group->inotify_data.user->inotify_watches);
+
+ /* update the idr hint */
+ group->inotify_data.last_wd = ientry->wd;
+
+ /* we put the mark on the idr, take a reference */
+ fsnotify_get_mark(entry);
}
+ ret = ientry->wd;
+
spin_lock(&entry->lock);
old_mask = entry->mask;
@@ -506,14 +537,19 @@ retry:
fsnotify_recalc_group_mask(group);
}
- return ientry->wd;
+ /* this either matches fsnotify_find_mark_entry, or init_mark_entry
+ * depending on which path we took... */
+ fsnotify_put_mark(entry);
out_err:
- /* see this isn't supposed to happen, just kill the watch */
- if (entry) {
- fsnotify_destroy_mark_by_entry(entry);
- fsnotify_put_mark(entry);
+ /* could be an error, could be that we found an existing mark */
+ if (tmp_ientry) {
+ /* on the idr but didn't make it on the inode */
+ if (tmp_ientry->wd != -1)
+ inotify_remove_from_idr(group, tmp_ientry);
+ kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
}
+
return ret;
}
@@ -721,9 +757,6 @@ static int __init inotify_user_setup(void)
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC);
event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);
- inotify_ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
- if (!inotify_ignored_event)
- panic("unable to allocate the inotify ignored event\n");
inotify_max_queued_events = 16384;
inotify_max_user_instances = 128;
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 959b73e756fd..521368574e97 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -136,18 +136,24 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
{
if ((old->mask == new->mask) &&
(old->to_tell == new->to_tell) &&
- (old->data_type == new->data_type)) {
+ (old->data_type == new->data_type) &&
+ (old->name_len == new->name_len)) {
switch (old->data_type) {
case (FSNOTIFY_EVENT_INODE):
- if (old->inode == new->inode)
+ /* remember, after old was put on the wait_q we aren't
+ * allowed to look at the inode any more, only thing
+ * left to check was if the file_name is the same */
+ if (old->name_len &&
+ !strcmp(old->file_name, new->file_name))
return true;
break;
case (FSNOTIFY_EVENT_PATH):
if ((old->path.mnt == new->path.mnt) &&
(old->path.dentry == new->path.dentry))
return true;
+ break;
case (FSNOTIFY_EVENT_NONE):
- return true;
+ return false;
};
}
return false;
@@ -339,18 +345,19 @@ static void initialize_event(struct fsnotify_event *event)
* @name the filename, if available
*/
struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
- int data_type, const char *name, u32 cookie)
+ int data_type, const char *name, u32 cookie,
+ gfp_t gfp)
{
struct fsnotify_event *event;
- event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+ event = kmem_cache_alloc(fsnotify_event_cachep, gfp);
if (!event)
return NULL;
initialize_event(event);
if (name) {
- event->file_name = kstrdup(name, GFP_KERNEL);
+ event->file_name = kstrdup(name, gfp);
if (!event->file_name) {
kmem_cache_free(fsnotify_event_cachep, event);
return NULL;
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
index 50931b1ce4b9..8b2549f672bf 100644
--- a/fs/ntfs/layout.h
+++ b/fs/ntfs/layout.h
@@ -829,7 +829,7 @@ enum {
/* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
- is used to to obtain all flags that are valid for setting. */
+ is used to obtain all flags that are valid for setting. */
/*
* The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
* FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 9edcde4974aa..f9a3e8942669 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -1914,7 +1914,8 @@ static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec,
* immediately to their right.
*/
left_clusters = le32_to_cpu(right_child_el->l_recs[0].e_cpos);
- if (ocfs2_is_empty_extent(&right_child_el->l_recs[0])) {
+ if (!ocfs2_rec_clusters(right_child_el, &right_child_el->l_recs[0])) {
+ BUG_ON(right_child_el->l_tree_depth);
BUG_ON(le16_to_cpu(right_child_el->l_next_free_rec) <= 1);
left_clusters = le32_to_cpu(right_child_el->l_recs[1].e_cpos);
}
@@ -2476,15 +2477,37 @@ out_ret_path:
return ret;
}
-static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle,
- struct ocfs2_path *path)
+static int ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle,
+ int subtree_index, struct ocfs2_path *path)
{
- int i, idx;
+ int i, idx, ret;
struct ocfs2_extent_rec *rec;
struct ocfs2_extent_list *el;
struct ocfs2_extent_block *eb;
u32 range;
+ /*
+ * In normal tree rotation process, we will never touch the
+ * tree branch above subtree_index and ocfs2_extend_rotate_transaction
+ * doesn't reserve the credits for them either.
+ *
+ * But we do have a special case here which will update the rightmost
+ * records for all the bh in the path.
+ * So we have to allocate extra credits and access them.
+ */
+ ret = ocfs2_extend_trans(handle,
+ handle->h_buffer_credits + subtree_index);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access_path(inode, handle, path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
/* Path should always be rightmost. */
eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data;
BUG_ON(eb->h_next_leaf_blk != 0ULL);
@@ -2505,6 +2528,8 @@ static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle,
ocfs2_journal_dirty(handle, path->p_node[i].bh);
}
+out:
+ return ret;
}
static void ocfs2_unlink_path(struct inode *inode, handle_t *handle,
@@ -2717,7 +2742,12 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
if (del_right_subtree) {
ocfs2_unlink_subtree(inode, handle, left_path, right_path,
subtree_index, dealloc);
- ocfs2_update_edge_lengths(inode, handle, left_path);
+ ret = ocfs2_update_edge_lengths(inode, handle, subtree_index,
+ left_path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
@@ -3034,7 +3064,12 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
ocfs2_unlink_subtree(inode, handle, left_path, path,
subtree_index, dealloc);
- ocfs2_update_edge_lengths(inode, handle, left_path);
+ ret = ocfs2_update_edge_lengths(inode, handle, subtree_index,
+ left_path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index b2c52b3a1484..e511df101451 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -193,6 +193,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
(unsigned long long)OCFS2_I(inode)->ip_blkno);
mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters);
dump_stack();
+ goto bail;
}
past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
@@ -1301,7 +1302,7 @@ static int ocfs2_write_cluster(struct address_space *mapping,
if (tmpret) {
mlog_errno(tmpret);
if (ret == 0)
- tmpret = ret;
+ ret = tmpret;
}
}
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index b574431a031d..2f28b7de2c8d 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -310,22 +310,19 @@ out_attach:
return ret;
}
-static DEFINE_SPINLOCK(dentry_list_lock);
+DEFINE_SPINLOCK(dentry_list_lock);
/* We limit the number of dentry locks to drop in one go. We have
* this limit so that we don't starve other users of ocfs2_wq. */
#define DL_INODE_DROP_COUNT 64
/* Drop inode references from dentry locks */
-void ocfs2_drop_dl_inodes(struct work_struct *work)
+static void __ocfs2_drop_dl_inodes(struct ocfs2_super *osb, int drop_count)
{
- struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
- dentry_lock_work);
struct ocfs2_dentry_lock *dl;
- int drop_count = DL_INODE_DROP_COUNT;
spin_lock(&dentry_list_lock);
- while (osb->dentry_lock_list && drop_count--) {
+ while (osb->dentry_lock_list && (drop_count < 0 || drop_count--)) {
dl = osb->dentry_lock_list;
osb->dentry_lock_list = dl->dl_next;
spin_unlock(&dentry_list_lock);
@@ -333,11 +330,32 @@ void ocfs2_drop_dl_inodes(struct work_struct *work)
kfree(dl);
spin_lock(&dentry_list_lock);
}
- if (osb->dentry_lock_list)
+ spin_unlock(&dentry_list_lock);
+}
+
+void ocfs2_drop_dl_inodes(struct work_struct *work)
+{
+ struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
+ dentry_lock_work);
+
+ __ocfs2_drop_dl_inodes(osb, DL_INODE_DROP_COUNT);
+ /*
+ * Don't queue dropping if umount is in progress. We flush the
+ * list in ocfs2_dismount_volume
+ */
+ spin_lock(&dentry_list_lock);
+ if (osb->dentry_lock_list &&
+ !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
queue_work(ocfs2_wq, &osb->dentry_lock_work);
spin_unlock(&dentry_list_lock);
}
+/* Flush the whole work queue */
+void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb)
+{
+ __ocfs2_drop_dl_inodes(osb, -1);
+}
+
/*
* ocfs2_dentry_iput() and friends.
*
@@ -368,7 +386,8 @@ static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb,
/* We leave dropping of inode reference to ocfs2_wq as that can
* possibly lead to inode deletion which gets tricky */
spin_lock(&dentry_list_lock);
- if (!osb->dentry_lock_list)
+ if (!osb->dentry_lock_list &&
+ !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED))
queue_work(ocfs2_wq, &osb->dentry_lock_work);
dl->dl_next = osb->dentry_lock_list;
osb->dentry_lock_list = dl;
diff --git a/fs/ocfs2/dcache.h b/fs/ocfs2/dcache.h
index faa12e75f98d..f5dd1789acf1 100644
--- a/fs/ocfs2/dcache.h
+++ b/fs/ocfs2/dcache.h
@@ -49,10 +49,13 @@ struct ocfs2_dentry_lock {
int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode,
u64 parent_blkno);
+extern spinlock_t dentry_list_lock;
+
void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
struct ocfs2_dentry_lock *dl);
void ocfs2_drop_dl_inodes(struct work_struct *work);
+void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb);
struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno,
int skip_unhashed);
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index d07ddbe4b283..81eff8e58322 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -103,7 +103,6 @@ static void __dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
lock->ast_pending, lock->ml.type);
BUG();
}
- BUG_ON(!list_empty(&lock->ast_list));
if (lock->ast_pending)
mlog(0, "lock has an ast getting flushed right now\n");
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 1c9efb406a96..02bf17808bdc 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -325,6 +325,7 @@ clear_fields:
}
static struct backing_dev_info dlmfs_backing_dev_info = {
+ .name = "ocfs2-dlmfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index bcb9260c3735..43e6e3280569 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1118,7 +1118,7 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm,
mlog(0, "%s:%.*s: sending mig lockres (%s) to %u\n",
dlm->name, res->lockname.len, res->lockname.name,
- orig_flags & DLM_MRES_MIGRATION ? "migrate" : "recovery",
+ orig_flags & DLM_MRES_MIGRATION ? "migration" : "recovery",
send_to);
/* send it */
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 62442e413a00..aa501d3f93f1 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1851,6 +1851,7 @@ relock:
if (ret)
goto out_dio;
+ count = ocount;
ret = generic_write_checks(file, ppos, &count,
S_ISBLK(inode->i_mode));
if (ret)
@@ -1918,8 +1919,10 @@ out_sems:
mutex_unlock(&inode->i_mutex);
+ if (written)
+ ret = written;
mlog_exit(ret);
- return written ? written : ret;
+ return ret;
}
static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index f033760ecbea..c48b93ac6b65 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -1954,10 +1954,16 @@ void ocfs2_orphan_scan_init(struct ocfs2_super *osb)
os->os_osb = osb;
os->os_count = 0;
os->os_seqno = 0;
- os->os_scantime = CURRENT_TIME;
mutex_init(&os->os_lock);
INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work);
+}
+void ocfs2_orphan_scan_start(struct ocfs2_super *osb)
+{
+ struct ocfs2_orphan_scan *os;
+
+ os = &osb->osb_orphan_scan;
+ os->os_scantime = CURRENT_TIME;
if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb))
atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
else {
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 5432c7f79cc6..4a4d3b55fd22 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -145,6 +145,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
/* Exported only for the journal struct init code in super.c. Do not call. */
void ocfs2_orphan_scan_init(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_start(struct ocfs2_super *osb);
void ocfs2_orphan_scan_stop(struct ocfs2_super *osb);
void ocfs2_orphan_scan_exit(struct ocfs2_super *osb);
@@ -329,20 +330,27 @@ int ocfs2_journal_dirty(handle_t *handle,
/* extended attribute block update */
#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1
+/* Update of a single quota block */
+#define OCFS2_QUOTA_BLOCK_UPDATE_CREDITS 1
+
/* global quotafile inode update, data block */
-#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
+#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + \
+ OCFS2_QUOTA_BLOCK_UPDATE_CREDITS)
+#define OCFS2_LOCAL_QINFO_WRITE_CREDITS OCFS2_QUOTA_BLOCK_UPDATE_CREDITS
/*
* The two writes below can accidentally see global info dirty due
* to set_info() quotactl so make them prepared for the writes.
*/
/* quota data block, global info */
/* Write to local quota file */
-#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1)
+#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + \
+ OCFS2_QUOTA_BLOCK_UPDATE_CREDITS)
/* global quota data block, local quota data block, global quota inode,
* global quota info */
-#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3)
+#define OCFS2_QSYNC_CREDITS (OCFS2_QINFO_WRITE_CREDITS + \
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS)
static inline int ocfs2_quota_trans_credits(struct super_block *sb)
{
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index c9345ebb8493..39e1d5a39505 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -224,10 +224,12 @@ enum ocfs2_mount_options
OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */
};
-#define OCFS2_OSB_SOFT_RO 0x0001
-#define OCFS2_OSB_HARD_RO 0x0002
-#define OCFS2_OSB_ERROR_FS 0x0004
-#define OCFS2_DEFAULT_ATIME_QUANTUM 60
+#define OCFS2_OSB_SOFT_RO 0x0001
+#define OCFS2_OSB_HARD_RO 0x0002
+#define OCFS2_OSB_ERROR_FS 0x0004
+#define OCFS2_OSB_DROP_DENTRY_LOCK_IMMED 0x0008
+
+#define OCFS2_DEFAULT_ATIME_QUANTUM 60
struct ocfs2_journal;
struct ocfs2_slot_info;
@@ -490,6 +492,18 @@ static inline void ocfs2_set_osb_flag(struct ocfs2_super *osb,
spin_unlock(&osb->osb_lock);
}
+
+static inline unsigned long ocfs2_test_osb_flag(struct ocfs2_super *osb,
+ unsigned long flag)
+{
+ unsigned long ret;
+
+ spin_lock(&osb->osb_lock);
+ ret = osb->osb_flags & flag;
+ spin_unlock(&osb->osb_lock);
+ return ret;
+}
+
static inline void ocfs2_set_ro_flag(struct ocfs2_super *osb,
int hard)
{
diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h
index 7365e2e08706..3fb96fcd4c81 100644
--- a/fs/ocfs2/quota.h
+++ b/fs/ocfs2/quota.h
@@ -50,7 +50,6 @@ struct ocfs2_mem_dqinfo {
unsigned int dqi_chunks; /* Number of chunks in local quota file */
unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */
unsigned int dqi_syncms; /* How often should we sync with other nodes */
- unsigned int dqi_syncjiff; /* Precomputed dqi_syncms in jiffies */
struct list_head dqi_chunk; /* List of chunks */
struct inode *dqi_gqinode; /* Global quota file inode */
struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index edfa60cd155c..d604a6aa0a22 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -69,6 +69,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
d->dqb_itime = cpu_to_le64(m->dqb_itime);
+ d->dqb_pad1 = d->dqb_pad2 = 0;
}
static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
@@ -211,14 +212,17 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA);
if (gqinode->i_size < off + len) {
+ loff_t rounded_end =
+ ocfs2_align_bytes_to_blocks(sb, off + len);
+
down_write(&OCFS2_I(gqinode)->ip_alloc_sem);
- err = ocfs2_extend_no_holes(gqinode, off + len, off);
+ err = ocfs2_extend_no_holes(gqinode, rounded_end, off);
up_write(&OCFS2_I(gqinode)->ip_alloc_sem);
if (err < 0)
goto out;
err = ocfs2_simple_size_update(gqinode,
oinfo->dqi_gqi_bh,
- off + len);
+ rounded_end);
if (err < 0)
goto out;
new = 1;
@@ -234,7 +238,7 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
}
if (err) {
mlog_errno(err);
- return err;
+ goto out;
}
lock_buffer(bh);
if (new)
@@ -342,7 +346,6 @@ int ocfs2_global_read_info(struct super_block *sb, int type)
info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms);
- oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms);
oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
@@ -352,7 +355,7 @@ int ocfs2_global_read_info(struct super_block *sb, int type)
oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
INIT_DELAYED_WORK(&oinfo->dqi_sync_work, qsync_work_fn);
queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
- oinfo->dqi_syncjiff);
+ msecs_to_jiffies(oinfo->dqi_syncms));
out_err:
mlog_exit(status);
@@ -607,7 +610,7 @@ static void qsync_work_fn(struct work_struct *work)
dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
- oinfo->dqi_syncjiff);
+ msecs_to_jiffies(oinfo->dqi_syncms));
}
/*
@@ -645,10 +648,15 @@ int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
return 0;
oinfo = sb_dqinfo(sb, type)->dqi_priv;
- /* We modify tree, leaf block, global info, local chunk header,
- * global and local inode */
- return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 +
- 2 * OCFS2_INODE_UPDATE_CREDITS;
+ /*
+ * We modify tree, leaf block, global info, local chunk header,
+ * global and local inode; OCFS2_QINFO_WRITE_CREDITS already
+ * accounts for inode update
+ */
+ return oinfo->dqi_gi.dqi_qtree_depth +
+ OCFS2_QINFO_WRITE_CREDITS +
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS +
+ OCFS2_INODE_UPDATE_CREDITS;
}
static int ocfs2_release_dquot(struct dquot *dquot)
@@ -698,7 +706,10 @@ int ocfs2_calc_qinit_credits(struct super_block *sb, int type)
* global file we can modify info, tree and leaf block */
return ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) +
ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) +
- 3 + oinfo->dqi_gi.dqi_qtree_depth + 2;
+ OCFS2_LOCAL_QINFO_WRITE_CREDITS +
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS +
+ oinfo->dqi_gi.dqi_qtree_depth +
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS;
}
static int ocfs2_acquire_dquot(struct dquot *dquot)
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index 5a460fa82553..bdb09cb6e1fe 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -20,6 +20,7 @@
#include "sysfile.h"
#include "dlmglue.h"
#include "quota.h"
+#include "uptodate.h"
/* Number of local quota structures per block */
static inline unsigned int ol_quota_entries_per_block(struct super_block *sb)
@@ -100,7 +101,8 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
handle_t *handle;
int status;
- handle = ocfs2_start_trans(OCFS2_SB(sb), 1);
+ handle = ocfs2_start_trans(OCFS2_SB(sb),
+ OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
@@ -610,7 +612,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
goto out_bh;
/* Mark quota file as clean if we are recovering quota file of
* some other node. */
- handle = ocfs2_start_trans(osb, 1);
+ handle = ocfs2_start_trans(osb,
+ OCFS2_LOCAL_QINFO_WRITE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
@@ -940,7 +943,7 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
struct ocfs2_local_disk_chunk *dchunk;
int status;
handle_t *handle;
- struct buffer_head *bh = NULL;
+ struct buffer_head *bh = NULL, *dbh = NULL;
u64 p_blkno;
/* We are protected by dqio_sem so no locking needed */
@@ -964,32 +967,35 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
mlog_errno(status);
goto out;
}
+ /* Local quota info and two new blocks we initialize */
+ handle = ocfs2_start_trans(OCFS2_SB(sb),
+ OCFS2_LOCAL_QINFO_WRITE_CREDITS +
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ mlog_errno(status);
+ goto out;
+ }
+ /* Initialize chunk header */
down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
&p_blkno, NULL, NULL);
up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
if (status < 0) {
mlog_errno(status);
- goto out;
+ goto out_trans;
}
bh = sb_getblk(sb, p_blkno);
if (!bh) {
status = -ENOMEM;
mlog_errno(status);
- goto out;
+ goto out_trans;
}
dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
-
- handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
- if (IS_ERR(handle)) {
- status = PTR_ERR(handle);
- mlog_errno(status);
- goto out;
- }
-
+ ocfs2_set_new_buffer_uptodate(lqinode, bh);
status = ocfs2_journal_access_dq(handle, lqinode, bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
+ OCFS2_JOURNAL_ACCESS_CREATE);
if (status < 0) {
mlog_errno(status);
goto out_trans;
@@ -999,7 +1005,6 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
memset(dchunk->dqc_bitmap, 0,
sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
OCFS2_QBLK_RESERVED_SPACE);
- set_buffer_uptodate(bh);
unlock_buffer(bh);
status = ocfs2_journal_dirty(handle, bh);
if (status < 0) {
@@ -1007,6 +1012,38 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
goto out_trans;
}
+ /* Initialize new block with structures */
+ down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+ status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks + 1,
+ &p_blkno, NULL, NULL);
+ up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out_trans;
+ }
+ dbh = sb_getblk(sb, p_blkno);
+ if (!dbh) {
+ status = -ENOMEM;
+ mlog_errno(status);
+ goto out_trans;
+ }
+ ocfs2_set_new_buffer_uptodate(lqinode, dbh);
+ status = ocfs2_journal_access_dq(handle, lqinode, dbh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out_trans;
+ }
+ lock_buffer(dbh);
+ memset(dbh->b_data, 0, sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE);
+ unlock_buffer(dbh);
+ status = ocfs2_journal_dirty(handle, dbh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out_trans;
+ }
+
+ /* Update local quotafile info */
oinfo->dqi_blocks += 2;
oinfo->dqi_chunks++;
status = ocfs2_local_write_info(sb, type);
@@ -1031,6 +1068,7 @@ out_trans:
ocfs2_commit_trans(OCFS2_SB(sb), handle);
out:
brelse(bh);
+ brelse(dbh);
kmem_cache_free(ocfs2_qf_chunk_cachep, chunk);
return ERR_PTR(status);
}
@@ -1048,6 +1086,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
struct ocfs2_local_disk_chunk *dchunk;
int epb = ol_quota_entries_per_block(sb);
unsigned int chunk_blocks;
+ struct buffer_head *bh;
+ u64 p_blkno;
int status;
handle_t *handle;
@@ -1075,12 +1115,49 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
mlog_errno(status);
goto out;
}
- handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
+
+ /* Get buffer from the just added block */
+ down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+ status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
+ &p_blkno, NULL, NULL);
+ up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out;
+ }
+ bh = sb_getblk(sb, p_blkno);
+ if (!bh) {
+ status = -ENOMEM;
+ mlog_errno(status);
+ goto out;
+ }
+ ocfs2_set_new_buffer_uptodate(lqinode, bh);
+
+ /* Local quota info, chunk header and the new block we initialize */
+ handle = ocfs2_start_trans(OCFS2_SB(sb),
+ OCFS2_LOCAL_QINFO_WRITE_CREDITS +
+ 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
goto out;
}
+ /* Zero created block */
+ status = ocfs2_journal_access_dq(handle, lqinode, bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out_trans;
+ }
+ lock_buffer(bh);
+ memset(bh->b_data, 0, sb->s_blocksize);
+ unlock_buffer(bh);
+ status = ocfs2_journal_dirty(handle, bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto out_trans;
+ }
+ /* Update chunk header */
status = ocfs2_journal_access_dq(handle, lqinode, chunk->qc_headerbh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
@@ -1097,6 +1174,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
mlog_errno(status);
goto out_trans;
}
+ /* Update file header */
oinfo->dqi_blocks++;
status = ocfs2_local_write_info(sb, type);
if (status < 0) {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 7efb349fb9bd..b0ee0fdf799a 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -777,6 +777,7 @@ static int ocfs2_sb_probe(struct super_block *sb,
}
di = (struct ocfs2_dinode *) (*bh)->b_data;
memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
+ spin_lock_init(&stats->b_lock);
status = ocfs2_verify_volume(di, *bh, blksize, stats);
if (status >= 0)
goto bail;
@@ -1182,7 +1183,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
wake_up(&osb->osb_mount_event);
/* Start this when the mount is almost sure of being successful */
- ocfs2_orphan_scan_init(osb);
+ ocfs2_orphan_scan_start(osb);
mlog_exit(status);
return status;
@@ -1213,14 +1214,27 @@ static int ocfs2_get_sb(struct file_system_type *fs_type,
mnt);
}
+static void ocfs2_kill_sb(struct super_block *sb)
+{
+ struct ocfs2_super *osb = OCFS2_SB(sb);
+
+ /* Prevent further queueing of inode drop events */
+ spin_lock(&dentry_list_lock);
+ ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED);
+ spin_unlock(&dentry_list_lock);
+ /* Wait for work to finish and/or remove it */
+ cancel_work_sync(&osb->dentry_lock_work);
+
+ kill_block_super(sb);
+}
+
static struct file_system_type ocfs2_fs_type = {
.owner = THIS_MODULE,
.name = "ocfs2",
.get_sb = ocfs2_get_sb, /* is this called when we mount
* the fs? */
- .kill_sb = kill_block_super, /* set to the generic one
- * right now, but do we
- * need to change that? */
+ .kill_sb = ocfs2_kill_sb,
+
.fs_flags = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
.next = NULL
};
@@ -1819,6 +1833,12 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
debugfs_remove(osb->osb_ctxt);
+ /*
+ * Flush inode dropping work queue so that deletes are
+ * performed while the filesystem is still working
+ */
+ ocfs2_drop_all_dl_inodes(osb);
+
/* Orphan scan should be stopped as early as possible */
ocfs2_orphan_scan_stop(osb);
@@ -1981,6 +2001,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
+ ocfs2_orphan_scan_init(osb);
+
status = ocfs2_recovery_init(osb);
if (status) {
mlog(ML_ERROR, "Unable to initialize recovery state\n");
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index ba320e250747..d1a27cda984f 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -1052,7 +1052,8 @@ static int ocfs2_xattr_block_get(struct inode *inode,
struct ocfs2_xattr_block *xb;
struct ocfs2_xattr_value_root *xv;
size_t size;
- int ret = -ENODATA, name_offset, name_len, block_off, i;
+ int ret = -ENODATA, name_offset, name_len, i;
+ int uninitialized_var(block_off);
xs->bucket = ocfs2_xattr_bucket_new(inode);
if (!xs->bucket) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3ce5ae9e3d2d..917f338a6739 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -237,20 +237,19 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
struct mm_struct *mm = get_task_mm(task);
if (!mm)
return NULL;
+ if (mm != current->mm) {
+ /*
+ * task->mm can be changed before security check,
+ * in that case we must notice the change after.
+ */
+ if (!ptrace_may_access(task, PTRACE_MODE_READ) ||
+ mm != task->mm) {
+ mmput(mm);
+ return NULL;
+ }
+ }
down_read(&mm->mmap_sem);
- task_lock(task);
- if (task->mm != mm)
- goto out;
- if (task->mm != current->mm &&
- __ptrace_may_access(task, PTRACE_MODE_READ) < 0)
- goto out;
- task_unlock(task);
return mm;
-out:
- task_unlock(task);
- up_read(&mm->mmap_sem);
- mmput(mm);
- return NULL;
}
static int proc_pid_cmdline(struct task_struct *task, char * buffer)
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
index 0c10a0b3f146..766b1d456050 100644
--- a/fs/proc/uptime.c
+++ b/fs/proc/uptime.c
@@ -4,13 +4,18 @@
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/time.h>
+#include <linux/kernel_stat.h>
#include <asm/cputime.h>
static int uptime_proc_show(struct seq_file *m, void *v)
{
struct timespec uptime;
struct timespec idle;
- cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
+ int i;
+ cputime_t idletime = cputime_zero;
+
+ for_each_possible_cpu(i)
+ idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle);
do_posix_clock_monotonic_gettime(&uptime);
monotonic_to_bootbased(&uptime);
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 70f36c043d62..38f7bd559f35 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2043,7 +2043,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
invalidate_bdev(sb->s_bdev);
}
mutex_lock(&dqopt->dqonoff_mutex);
- mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
if (sb_has_quota_loaded(sb, type)) {
error = -EBUSY;
goto out_lock;
@@ -2054,9 +2053,11 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
* possible) Also nobody should write to the file - we use
* special IO operations which ignore the immutable bit. */
down_write(&dqopt->dqptr_sem);
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE |
S_NOQUOTA);
inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
+ mutex_unlock(&inode->i_mutex);
up_write(&dqopt->dqptr_sem);
sb->dq_op->drop(inode);
}
@@ -2080,7 +2081,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
goto out_file_init;
}
mutex_unlock(&dqopt->dqio_mutex);
- mutex_unlock(&inode->i_mutex);
spin_lock(&dq_state_lock);
dqopt->flags |= dquot_state_flag(flags, type);
spin_unlock(&dq_state_lock);
@@ -2096,13 +2096,14 @@ out_file_init:
out_lock:
if (oldflags != -1) {
down_write(&dqopt->dqptr_sem);
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
/* Set the flags back (in the case of accidental quotaon()
* on a wrong file we don't want to mess up the flags) */
inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
inode->i_flags |= oldflags;
+ mutex_unlock(&inode->i_mutex);
up_write(&dqopt->dqptr_sem);
}
- mutex_unlock(&inode->i_mutex);
mutex_unlock(&dqopt->dqonoff_mutex);
out_fmt:
put_quota_format(fmt);
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index ebb2c417912c..11f0c06316de 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -20,6 +20,7 @@
#include <linux/ramfs.h>
#include <linux/pagevec.h>
#include <linux/mman.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
#include "internal.h"
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 0ff7566c767c..a7f0110fca4c 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -46,6 +46,7 @@ static const struct super_operations ramfs_ops;
static const struct inode_operations ramfs_dir_inode_operations;
static struct backing_dev_info ramfs_backing_dev_info = {
+ .name = "ramfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |
BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
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..d6fb8d3f52be 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -51,6 +51,46 @@ static inline bool is_privroot_deh(struct dentry *dir,
deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid);
}
+/*
+ * The first entry will be the first one to be copied in the user buffer,
+ * hence the first time it is touched by reiserfs_readdir_dentry(). We assume
+ * the buffer has chances to be swapped out at this time and not after,
+ * unless we switch to another page in further entry.
+ * This assumption lead us to:
+ *
+ * - while the page is swapped in, we want the filesystem to be available
+ * for others, we then relax the write lock.
+ * - because we relax the lock, the entry from which we have read the name
+ * may have moved somewhere else, we then copy the name in a temporary buffer
+ */
+static int
+fill_first_entry(void * dirent, const char *d_name, int d_reclen, loff_t d_off,
+ u64 d_ino, filldir_t filldir, struct super_block *sb)
+{
+ int ret;
+ char *local_buf;
+ char small_buf[32]; /* avoid kmalloc if we can */
+
+ if (d_reclen <= 32) {
+ local_buf = small_buf;
+ } else {
+ local_buf = kmalloc(d_reclen, GFP_NOFS);
+ if (!local_buf)
+ return -ENOMEM;
+ }
+
+ memcpy(local_buf, d_name, d_reclen);
+
+ reiserfs_write_unlock(sb);
+ ret = filldir(dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN);
+ reiserfs_write_lock(sb);
+
+ if (local_buf != small_buf)
+ kfree(local_buf);
+
+ return ret;
+}
+
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
filldir_t filldir, loff_t *pos)
{
@@ -62,9 +102,7 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
const struct reiserfs_key *rkey;
struct item_head *ih, tmp_ih;
int search_res;
- char *local_buf;
loff_t next_pos;
- char small_buf[32]; /* avoid kmalloc if we can */
struct reiserfs_dir_entry de;
int ret = 0;
@@ -79,6 +117,8 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
path_to_entry.reada = PATH_READA;
while (1) {
+ bool first_entry = true;
+
research:
/* search the directory item, containing entry with specified key */
search_res =
@@ -154,43 +194,38 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
d_off = deh_offset(deh);
*pos = d_off;
d_ino = deh_objectid(deh);
- if (d_reclen <= 32) {
- local_buf = small_buf;
- } else {
- local_buf = kmalloc(d_reclen,
- GFP_NOFS);
- if (!local_buf) {
+
+ /*
+ * next entry should be looked for with such
+ * offset
+ */
+ next_pos = deh_offset(deh) + 1;
+
+ if (first_entry) {
+ int fillret;
+
+ fillret = fill_first_entry(dirent,
+ d_name,
+ d_reclen,
+ d_off, d_ino,
+ filldir,
+ inode->i_sb);
+ if (fillret == -ENOMEM) {
pathrelse(&path_to_entry);
ret = -ENOMEM;
goto out;
}
- if (item_moved(&tmp_ih, &path_to_entry)) {
- kfree(local_buf);
- goto research;
- }
- }
- // Note, that we copy name to user space via temporary
- // buffer (local_buf) because filldir will block if
- // user space buffer is swapped out. At that time
- // entry can move to somewhere else
- memcpy(local_buf, d_name, d_reclen);
- if (filldir
- (dirent, local_buf, d_reclen, d_off, d_ino,
- DT_UNKNOWN) < 0) {
- if (local_buf != small_buf) {
- kfree(local_buf);
- }
- goto end;
- }
- if (local_buf != small_buf) {
- kfree(local_buf);
- }
- // next entry should be looked for with such offset
- next_pos = deh_offset(deh) + 1;
+ if (fillret < 0)
+ goto end;
+ first_entry = false;
- if (item_moved(&tmp_ih, &path_to_entry)) {
- goto research;
+ if (item_moved(&tmp_ih, &path_to_entry))
+ goto research;
+ continue;
}
+ if (filldir(dirent, d_name, d_reclen, d_off,
+ d_ino, DT_UNKNOWN) < 0)
+ goto end;
} /* for */
}
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/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..853f4f6fe920 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -489,10 +489,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 +605,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 +621,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 +637,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 +755,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 +1001,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 +1045,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 +2082,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 +2153,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 +2622,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 +2681,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 +2709,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 +2724,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 +2738,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 +2780,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;
}
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 0ccc3fdda7bf..5e40b0cd4c3d 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -141,9 +141,11 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
+
+ reiserfs_write_lock(inode->i_sb);
ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
+ reiserfs_write_unlock(inode->i_sb);
+
return ret;
}
#endif
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 90622200b39c..d23d6d7a45a6 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! "
@@ -2964,8 +3000,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 +3021,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 +3074,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 +3549,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 +4084,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 +4199,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 +4248,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..cb1bba3802dd
--- /dev/null
+++ b/fs/reiserfs/lock.c
@@ -0,0 +1,89 @@
+#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 could even raise a BUG() if we don't
+ * want the data become corrupted
+ */
+ WARN_ONCE(sb_i->lock_owner != current,
+ "Superblock write lock imbalance");
+
+ 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..b3973c9f0bf1 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);
}
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 7adea74d6a8a..58727b5b4351 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..59870a4751cc 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)) {
@@ -1011,7 +1011,7 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
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/super.c b/fs/super.c
index 2761d3e22ed9..0d22ce3be4aa 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -62,9 +62,6 @@ static struct super_block *alloc_super(struct file_system_type *type)
s = NULL;
goto out;
}
- INIT_LIST_HEAD(&s->s_dirty);
- INIT_LIST_HEAD(&s->s_io);
- INIT_LIST_HEAD(&s->s_more_io);
INIT_LIST_HEAD(&s->s_files);
INIT_LIST_HEAD(&s->s_instances);
INIT_HLIST_HEAD(&s->s_anon);
diff --git a/fs/sync.c b/fs/sync.c
index 3422ba61d86d..bf03fc75b392 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -118,7 +118,7 @@ restart:
*/
SYSCALL_DEFINE0(sync)
{
- wakeup_pdflush(0);
+ wakeup_flusher_threads(0);
sync_filesystems(0);
sync_filesystems(1);
if (unlikely(laptop_mode))
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index d88d0fac9fa5..14f2d71ea3ce 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -939,8 +939,10 @@ again:
/* Remove from old parent's list and insert into new parent's list. */
sysfs_unlink_sibling(sd);
sysfs_get(new_parent_sd);
+ drop_nlink(old_parent->d_inode);
sysfs_put(sd->s_parent);
sd->s_parent = new_parent_sd;
+ inc_nlink(new_parent->d_inode);
sysfs_link_sibling(sd);
out_unlock:
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 555f0ff988df..e57f98e54fce 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -29,6 +29,7 @@ static const struct address_space_operations sysfs_aops = {
};
static struct backing_dev_info sysfs_backing_dev_info = {
+ .name = "sysfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index f3a7945527fb..4775af401167 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -510,7 +510,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt;
int first = 1, iip;
struct ubifs_debug_info *d = c->dbg;
- union ubifs_key lower_key, upper_key, l_key, u_key;
+ union ubifs_key uninitialized_var(lower_key), upper_key, l_key, u_key;
unsigned long long uninitialized_var(last_sqnum);
struct ubifs_idx_node *idx;
struct list_head list;
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index 5fa27ea031ba..919af84b9e17 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -229,23 +229,6 @@ static inline void xent_key_init(const struct ubifs_info *c,
}
/**
- * xent_key_init_hash - initialize extended attribute entry key without
- * re-calculating hash function.
- * @c: UBIFS file-system description object
- * @key: key to initialize
- * @inum: host inode number
- * @hash: extended attribute entry name hash
- */
-static inline void xent_key_init_hash(const struct ubifs_info *c,
- union ubifs_key *key, ino_t inum,
- uint32_t hash)
-{
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
- key->u32[0] = inum;
- key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
-}
-
-/**
* xent_key_init_flash - initialize on-flash extended attribute entry key.
* @c: UBIFS file-system description object
* @k: key to initialize
@@ -295,25 +278,6 @@ static inline void data_key_init(const struct ubifs_info *c,
}
/**
- * data_key_init_flash - initialize on-flash data key.
- * @c: UBIFS file-system description object
- * @k: key to initialize
- * @inum: inode number
- * @block: block number
- */
-static inline void data_key_init_flash(const struct ubifs_info *c, void *k,
- ino_t inum, unsigned int block)
-{
- union ubifs_key *key = k;
-
- ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
- key->j32[0] = cpu_to_le32(inum);
- key->j32[1] = cpu_to_le32(block |
- (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS));
- memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
-}
-
-/**
* trun_key_init - initialize truncation node key.
* @c: UBIFS file-system description object
* @key: key to initialize
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 26d2e0d80465..22b2db3cad23 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -36,7 +36,6 @@
#include <linux/mount.h>
#include <linux/math64.h>
#include <linux/writeback.h>
-#include <linux/smp_lock.h>
#include "ubifs.h"
/*
@@ -438,12 +437,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
{
int i, err;
struct ubifs_info *c = sb->s_fs_info;
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .range_start = 0,
- .range_end = LLONG_MAX,
- .nr_to_write = LONG_MAX,
- };
/*
* Zero @wait is just an advisory thing to help the file system shove
@@ -454,17 +447,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
return 0;
/*
- * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
- * pages, so synchronize them first, then commit the journal. Strictly
- * speaking, it is not necessary to commit the journal here,
- * synchronizing write-buffers would be enough. But committing makes
- * UBIFS free space predictions much more accurate, so we want to let
- * the user be able to get more accurate results of 'statfs()' after
- * they synchronize the file system.
- */
- generic_sync_sb_inodes(sb, &wbc);
-
- /*
* Synchronize write buffers, because 'ubifs_run_commit()' does not
* do this if it waits for an already running commit.
*/
@@ -474,6 +456,13 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
return err;
}
+ /*
+ * Strictly speaking, it is not necessary to commit the journal here,
+ * synchronizing write-buffers would be enough. But committing makes
+ * UBIFS free space predictions much more accurate, so we want to let
+ * the user be able to get more accurate results of 'statfs()' after
+ * they synchronize the file system.
+ */
err = ubifs_run_commit(c);
if (err)
return err;
@@ -1726,8 +1715,6 @@ static void ubifs_put_super(struct super_block *sb)
ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num,
c->vi.vol_id);
- lock_kernel();
-
/*
* The following asserts are only valid if there has not been a failure
* of the media. For example, there will be dirty inodes if we failed
@@ -1792,8 +1779,6 @@ static void ubifs_put_super(struct super_block *sb)
ubi_close_volume(c->ubi);
mutex_unlock(&c->umount_mutex);
kfree(c);
-
- unlock_kernel();
}
static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -1809,22 +1794,17 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
return err;
}
- lock_kernel();
if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
if (c->ro_media) {
ubifs_msg("cannot re-mount due to prior errors");
- unlock_kernel();
return -EROFS;
}
err = ubifs_remount_rw(c);
- if (err) {
- unlock_kernel();
+ if (err)
return err;
- }
} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
if (c->ro_media) {
ubifs_msg("cannot re-mount due to prior errors");
- unlock_kernel();
return -EROFS;
}
ubifs_remount_ro(c);
@@ -1839,7 +1819,6 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
}
ubifs_assert(c->lst.taken_empty_lebs > 0);
- unlock_kernel();
return 0;
}
@@ -1971,6 +1950,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
*
* Read-ahead will be disabled because @c->bdi.ra_pages is 0.
*/
+ c->bdi.name = "ubifs",
c->bdi.capabilities = BDI_CAP_MAP_COPY;
c->bdi.unplug_io_fn = default_unplug_io_fn;
err = bdi_init(&c->bdi);
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index 1d2c570704c8..2ffdb6733af1 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -18,59 +18,6 @@
#include <linux/string.h>
#include <linux/buffer_head.h>
-#if 0
-static uint8_t *udf_filead_read(struct inode *dir, uint8_t *tmpad,
- uint8_t ad_size, struct kernel_lb_addr fe_loc,
- int *pos, int *offset, struct buffer_head **bh,
- int *error)
-{
- int loffset = *offset;
- int block;
- uint8_t *ad;
- int remainder;
-
- *error = 0;
-
- ad = (uint8_t *)(*bh)->b_data + *offset;
- *offset += ad_size;
-
- if (!ad) {
- brelse(*bh);
- *error = 1;
- return NULL;
- }
-
- if (*offset == dir->i_sb->s_blocksize) {
- brelse(*bh);
- block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
- if (!block)
- return NULL;
- *bh = udf_tread(dir->i_sb, block);
- if (!*bh)
- return NULL;
- } else if (*offset > dir->i_sb->s_blocksize) {
- ad = tmpad;
-
- remainder = dir->i_sb->s_blocksize - loffset;
- memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
-
- brelse(*bh);
- block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
- if (!block)
- return NULL;
- (*bh) = udf_tread(dir->i_sb, block);
- if (!*bh)
- return NULL;
-
- memcpy((uint8_t *)ad + remainder, (*bh)->b_data,
- ad_size - remainder);
- *offset = ad_size - remainder;
- }
-
- return ad;
-}
-#endif
-
struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
struct udf_fileident_bh *fibh,
struct fileIdentDesc *cfi,
@@ -248,39 +195,6 @@ struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
return fi;
}
-#if 0
-static struct extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
-{
- struct extent_ad *ext;
- struct fileEntry *fe;
- uint8_t *ptr;
-
- if ((!buffer) || (!offset)) {
- printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
- return NULL;
- }
-
- fe = (struct fileEntry *)buffer;
-
- if (fe->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FE)) {
- udf_debug("0x%x != TAG_IDENT_FE\n",
- le16_to_cpu(fe->descTag.tagIdent));
- return NULL;
- }
-
- ptr = (uint8_t *)(fe->extendedAttr) +
- le32_to_cpu(fe->lengthExtendedAttr);
-
- if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)))
- ptr += *offset;
-
- ext = (struct extent_ad *)ptr;
-
- *offset = *offset + sizeof(struct extent_ad);
- return ext;
-}
-#endif
-
struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
int inc)
{
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index e7533f785636..6d24c2c63f93 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -90,19 +90,16 @@ no_delete:
}
/*
- * If we are going to release inode from memory, we discard preallocation and
- * truncate last inode extent to proper length. We could use drop_inode() but
- * it's called under inode_lock and thus we cannot mark inode dirty there. We
- * use clear_inode() but we have to make sure to write inode as it's not written
- * automatically.
+ * If we are going to release inode from memory, we truncate last inode extent
+ * to proper length. We could use drop_inode() but it's called under inode_lock
+ * and thus we cannot mark inode dirty there. We use clear_inode() but we have
+ * to make sure to write inode as it's not written automatically.
*/
void udf_clear_inode(struct inode *inode)
{
struct udf_inode_info *iinfo;
if (!(inode->i_sb->s_flags & MS_RDONLY)) {
lock_kernel();
- /* Discard preallocation for directories, symlinks, etc. */
- udf_discard_prealloc(inode);
udf_truncate_tail_extent(inode);
unlock_kernel();
write_inode_now(inode, 0);
@@ -664,8 +661,12 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
#ifdef UDF_PREALLOCATE
- /* preallocate blocks */
- udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
+ /* We preallocate blocks only for regular files. It also makes sense
+ * for directories but there's a problem when to drop the
+ * preallocation. We might use some delayed work for that but I feel
+ * it's overengineering for a filesystem like UDF. */
+ if (S_ISREG(inode->i_mode))
+ udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
#endif
/* merge any continuous blocks in laarr */
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 1b88fd5df05d..43e24a3b8e10 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -36,14 +36,10 @@ unsigned int udf_get_last_session(struct super_block *sb)
ms_info.addr_format = CDROM_LBA;
i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
-#define WE_OBEY_THE_WRITTEN_STANDARDS 1
-
if (i == 0) {
udf_debug("XA disk: %s, vol_desc_start=%d\n",
(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
-#if WE_OBEY_THE_WRITTEN_STANDARDS
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
-#endif
vol_desc_start = ms_info.addr.lba;
} else {
udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 6a29fa34c478..21dad8c608f9 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -943,7 +943,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
pc->componentType = 1;
pc->lengthComponentIdent = 0;
pc->componentFileVersionNum = 0;
- pc += sizeof(struct pathComponent);
elen += sizeof(struct pathComponent);
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 6832135159b6..9d1b8c2e6c45 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1087,11 +1087,23 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
struct udf_inode_info *vati;
uint32_t pos;
struct virtualAllocationTable20 *vat20;
+ sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
/* VAT file entry is in the last recorded block */
ino.partitionReferenceNum = type1_index;
ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root;
sbi->s_vat_inode = udf_iget(sb, &ino);
+ if (!sbi->s_vat_inode &&
+ sbi->s_last_block != blocks - 1) {
+ printk(KERN_NOTICE "UDF-fs: Failed to read VAT inode from the"
+ " last recorded block (%lu), retrying with the last "
+ "block of the device (%lu).\n",
+ (unsigned long)sbi->s_last_block,
+ (unsigned long)blocks - 1);
+ ino.partitionReferenceNum = type1_index;
+ ino.logicalBlockNum = blocks - 1 - map->s_partition_root;
+ sbi->s_vat_inode = udf_iget(sb, &ino);
+ }
if (!sbi->s_vat_inode)
return 1;
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 7ec89fc05b2b..aecf2519db76 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -1268,6 +1268,14 @@ xfs_vm_writepage(
if (!page_has_buffers(page))
create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+
+ /*
+ * VM calculation for nr_to_write seems off. Bump it way
+ * up, this gets simple streaming writes zippy again.
+ * To be reviewed again after Jens' writeback changes.
+ */
+ wbc->nr_to_write *= 4;
+
/*
* Convert delayed allocate, unwritten or unmapped space
* to real space and flush out to disk.
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 58973bb46038..8070b34cc287 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -680,8 +680,8 @@ xfs_vn_fiemap(
else
bm.bmv_length = BTOBB(length);
- /* our formatter will tell xfs_getbmap when to stop. */
- bm.bmv_count = MAXEXTNUM;
+ /* We add one because in getbmap world count includes the header */
+ bm.bmv_count = fieinfo->fi_extents_max + 1;
bm.bmv_iflags = BMV_IF_PREALLOC;
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR)
bm.bmv_iflags |= BMV_IF_ATTRFORK;
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index a220d36f789b..c709ed61a53e 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -687,7 +687,7 @@ xfs_barrier_test(
return error;
}
-void
+STATIC void
xfs_mountfs_check_barriers(xfs_mount_t *mp)
{
int error;
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index b619d6b8ca43..fbf3e0288b34 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -740,21 +740,6 @@ __xfs_inode_clear_reclaim_tag(
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
}
-void
-xfs_inode_clear_reclaim_tag(
- xfs_inode_t *ip)
-{
- xfs_mount_t *mp = ip->i_mount;
- xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
-
- read_lock(&pag->pag_ici_lock);
- spin_lock(&ip->i_flags_lock);
- __xfs_inode_clear_reclaim_tag(mp, pag, ip);
- spin_unlock(&ip->i_flags_lock);
- read_unlock(&pag->pag_ici_lock);
- xfs_put_perag(mp, pag);
-}
-
STATIC int
xfs_reclaim_inode_now(
struct xfs_inode *ip,
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index 2a10301c99c7..23e7e7e6e136 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -48,7 +48,6 @@ int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);
int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
-void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip);
void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
struct xfs_inode *ip);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 7928b9983c1d..975972482e8f 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -3713,7 +3713,7 @@ done:
* entry (null if none). Else, *lastxp will be set to the index
* of the found entry; *gotp will contain the entry.
*/
-xfs_bmbt_rec_host_t * /* pointer to found extent entry */
+STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */
xfs_bmap_search_multi_extents(
xfs_ifork_t *ifp, /* inode fork pointer */
xfs_fileoff_t bno, /* block number searched for */
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 1b8ff9256bd0..56f62d2edc35 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -392,17 +392,6 @@ xfs_bmap_count_blocks(
int whichfork,
int *count);
-/*
- * Search the extent records for the entry containing block bno.
- * If bno lies in a hole, point to the next entry. If bno lies
- * past eof, *eofp will be set, and *prevp will contain the last
- * entry (null if none). Else, *lastxp will be set to the index
- * of the found entry; *gotp will contain the entry.
- */
-xfs_bmbt_rec_host_t *
-xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *,
- xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *);
-
#endif /* __KERNEL__ */
#endif /* __XFS_BMAP_H__ */
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 5c1ade06578e..eb7b702d0690 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -202,16 +202,6 @@ xfs_bmbt_get_state(
ext_flag);
}
-/* Endian flipping versions of the bmbt extraction functions */
-void
-xfs_bmbt_disk_get_all(
- xfs_bmbt_rec_t *r,
- xfs_bmbt_irec_t *s)
-{
- __xfs_bmbt_get_all(get_unaligned_be64(&r->l0),
- get_unaligned_be64(&r->l1), s);
-}
-
/*
* Extract the blockcount field from an on disk bmap extent record.
*/
@@ -816,6 +806,16 @@ xfs_bmbt_trace_key(
*l1 = 0;
}
+/* Endian flipping versions of the bmbt extraction functions */
+STATIC void
+xfs_bmbt_disk_get_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s)
+{
+ __xfs_bmbt_get_all(get_unaligned_be64(&r->l0),
+ get_unaligned_be64(&r->l1), s);
+}
+
STATIC void
xfs_bmbt_trace_record(
struct xfs_btree_cur *cur,
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
index 0e8df007615e..5549d495947f 100644
--- a/fs/xfs/xfs_bmap_btree.h
+++ b/fs/xfs/xfs_bmap_btree.h
@@ -220,7 +220,6 @@ extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r);
extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r);
extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r);
-extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r);
extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r);
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index e9df99574829..cde5a2668293 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -646,46 +646,6 @@ xfs_btree_read_bufl(
}
/*
- * Get a buffer for the block, return it read in.
- * Short-form addressing.
- */
-int /* error */
-xfs_btree_read_bufs(
- xfs_mount_t *mp, /* file system mount point */
- xfs_trans_t *tp, /* transaction pointer */
- xfs_agnumber_t agno, /* allocation group number */
- xfs_agblock_t agbno, /* allocation group block number */
- uint lock, /* lock flags for read_buf */
- xfs_buf_t **bpp, /* buffer for agno/agbno */
- int refval) /* ref count value for buffer */
-{
- xfs_buf_t *bp; /* return value */
- xfs_daddr_t d; /* real disk block address */
- int error;
-
- ASSERT(agno != NULLAGNUMBER);
- ASSERT(agbno != NULLAGBLOCK);
- d = XFS_AGB_TO_DADDR(mp, agno, agbno);
- if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d,
- mp->m_bsize, lock, &bp))) {
- return error;
- }
- ASSERT(!bp || !XFS_BUF_GETERROR(bp));
- if (bp != NULL) {
- switch (refval) {
- case XFS_ALLOC_BTREE_REF:
- XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
- break;
- case XFS_INO_BTREE_REF:
- XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval);
- break;
- }
- }
- *bpp = bp;
- return 0;
-}
-
-/*
* Read-ahead the block, don't wait for it, don't return a buffer.
* Long-form addressing.
*/
@@ -2951,7 +2911,7 @@ error0:
* inode we have to copy the single block it was pointing to into the
* inode.
*/
-int
+STATIC int
xfs_btree_kill_iroot(
struct xfs_btree_cur *cur)
{
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
index 4f852b735b96..7fa07062bdda 100644
--- a/fs/xfs/xfs_btree.h
+++ b/fs/xfs/xfs_btree.h
@@ -379,20 +379,6 @@ xfs_btree_read_bufl(
int refval);/* ref count value for buffer */
/*
- * Get a buffer for the block, return it read in.
- * Short-form addressing.
- */
-int /* error */
-xfs_btree_read_bufs(
- struct xfs_mount *mp, /* file system mount point */
- struct xfs_trans *tp, /* transaction pointer */
- xfs_agnumber_t agno, /* allocation group number */
- xfs_agblock_t agbno, /* allocation group block number */
- uint lock, /* lock flags for read_buf */
- struct xfs_buf **bpp, /* buffer for agno/agbno */
- int refval);/* ref count value for buffer */
-
-/*
* Read-ahead the block, don't wait for it, don't return a buffer.
* Long-form addressing.
*/
@@ -432,7 +418,6 @@ int xfs_btree_decrement(struct xfs_btree_cur *, int, int *);
int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *);
int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *);
int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *);
-int xfs_btree_kill_iroot(struct xfs_btree_cur *);
int xfs_btree_insert(struct xfs_btree_cur *, int *);
int xfs_btree_delete(struct xfs_btree_cur *, int *);
int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index c4ea51b55dce..f52ac276277e 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -117,7 +117,7 @@ struct getbmapx {
#define BMV_IF_VALID \
(BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC)
-/* bmv_oflags values - returned for for each non-header segment */
+/* bmv_oflags values - returned for each non-header segment */
#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
#define BMV_OF_LAST 0x4 /* segment is the last in the file */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 1f22d65fed0a..2dcb3d781ae5 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -641,7 +641,7 @@ xfs_iformat_btree(
return 0;
}
-void
+STATIC void
xfs_dinode_from_disk(
xfs_icdinode_t *to,
xfs_dinode_t *from)
@@ -1237,7 +1237,7 @@ xfs_isize_check(
* In that case the pages will still be in memory, but the inode size
* will never have been updated.
*/
-xfs_fsize_t
+STATIC xfs_fsize_t
xfs_file_last_byte(
xfs_inode_t *ip)
{
@@ -3827,7 +3827,7 @@ xfs_iext_inline_to_direct(
/*
* Resize an extent indirection array to new_size bytes.
*/
-void
+STATIC void
xfs_iext_realloc_indirect(
xfs_ifork_t *ifp, /* inode fork pointer */
int new_size) /* new indirection array size */
@@ -3852,7 +3852,7 @@ xfs_iext_realloc_indirect(
/*
* Switch from indirection array to linear (direct) extent allocations.
*/
-void
+STATIC void
xfs_iext_indirect_to_direct(
xfs_ifork_t *ifp) /* inode fork pointer */
{
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 1804f866a71d..5104daedaf6c 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -521,7 +521,6 @@ void xfs_ipin(xfs_inode_t *);
void xfs_iunpin(xfs_inode_t *);
int xfs_iflush(xfs_inode_t *, uint);
void xfs_ichgtime(xfs_inode_t *, int);
-xfs_fsize_t xfs_file_last_byte(xfs_inode_t *);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
@@ -589,8 +588,6 @@ int xfs_itobp(struct xfs_mount *, struct xfs_trans *,
struct xfs_buf **, uint);
int xfs_iread(struct xfs_mount *, struct xfs_trans *,
struct xfs_inode *, xfs_daddr_t, uint);
-void xfs_dinode_from_disk(struct xfs_icdinode *,
- struct xfs_dinode *);
void xfs_dinode_to_disk(struct xfs_dinode *,
struct xfs_icdinode *);
void xfs_idestroy_fork(struct xfs_inode *, int);
@@ -609,8 +606,6 @@ void xfs_iext_remove_inline(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_remove_indirect(xfs_ifork_t *, xfs_extnum_t, int);
void xfs_iext_realloc_direct(xfs_ifork_t *, int);
-void xfs_iext_realloc_indirect(xfs_ifork_t *, int);
-void xfs_iext_indirect_to_direct(xfs_ifork_t *);
void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t);
void xfs_iext_inline_to_direct(xfs_ifork_t *, int);
void xfs_iext_destroy(xfs_ifork_t *);
diff --git a/fs/xfs/xfs_inum.h b/fs/xfs/xfs_inum.h
index 7a28191cb0de..b8e4ee4e89a4 100644
--- a/fs/xfs/xfs_inum.h
+++ b/fs/xfs/xfs_inum.h
@@ -72,7 +72,6 @@ struct xfs_mount;
#if XFS_BIG_INUMS
#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL))
-#define XFS_INO64_OFFSET ((xfs_ino_t)(1ULL << 32))
#else
#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL))
#endif
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index aeb2d2221c7d..c471122d2234 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -39,7 +39,7 @@
#include "xfs_error.h"
#include "xfs_btree.h"
-int
+STATIC int
xfs_internal_inum(
xfs_mount_t *mp,
xfs_ino_t ino)
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index 1fb04e7deb61..20792bf45946 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -99,11 +99,6 @@ xfs_bulkstat_one(
void *dibuff,
int *stat);
-int
-xfs_internal_inum(
- xfs_mount_t *mp,
- xfs_ino_t ino);
-
typedef int (*inumbers_fmt_pf)(
void __user *ubuffer, /* buffer to write to */
const xfs_inogrp_t *buffer, /* buffer to read from */
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index bcad5f4c1fd1..679c7c4926a2 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -451,8 +451,6 @@ extern int xlog_find_tail(xlog_t *log,
extern int xlog_recover(xlog_t *log);
extern int xlog_recover_finish(xlog_t *log);
extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
-extern void xlog_recover_process_iunlinks(xlog_t *log);
-
extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
extern void xlog_put_bp(struct xfs_buf *);
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 47da2fb45377..1099395d7d6c 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3263,7 +3263,7 @@ xlog_recover_process_one_iunlink(
* freeing of the inode and its removal from the list must be
* atomic.
*/
-void
+STATIC void
xlog_recover_process_iunlinks(
xlog_t *log)
{
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 5c6f092659c1..8b6c9e807efb 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1568,7 +1568,7 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
*
* The m_sb_lock must be held when this routine is called.
*/
-int
+STATIC int
xfs_mod_incore_sb_unlocked(
xfs_mount_t *mp,
xfs_sb_field_t field,
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index a5122382afde..a6c023bc0fb2 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -414,13 +414,10 @@ typedef struct xfs_mod_sb {
extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern int xfs_mountfs(xfs_mount_t *mp);
-extern void xfs_mountfs_check_barriers(xfs_mount_t *mp);
extern void xfs_unmountfs(xfs_mount_t *);
extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
-extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
- int64_t, int);
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c
index afee7eb24323..4b0613d99faa 100644
--- a/fs/xfs/xfs_mru_cache.c
+++ b/fs/xfs/xfs_mru_cache.c
@@ -564,35 +564,6 @@ xfs_mru_cache_lookup(
}
/*
- * To look up an element using its key, but leave its location in the internal
- * lists alone, call xfs_mru_cache_peek(). If the element isn't found, this
- * function returns NULL.
- *
- * See the comments above the declaration of the xfs_mru_cache_lookup() function
- * for important locking information pertaining to this call.
- */
-void *
-xfs_mru_cache_peek(
- xfs_mru_cache_t *mru,
- unsigned long key)
-{
- xfs_mru_cache_elem_t *elem;
-
- ASSERT(mru && mru->lists);
- if (!mru || !mru->lists)
- return NULL;
-
- spin_lock(&mru->lock);
- elem = radix_tree_lookup(&mru->store, key);
- if (!elem)
- spin_unlock(&mru->lock);
- else
- __release(mru_lock); /* help sparse not be stupid */
-
- return elem ? elem->value : NULL;
-}
-
-/*
* To release the internal data structure spinlock after having performed an
* xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done()
* with the data store pointer.
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h
index dd58ea1bbebe..5d439f34b0c9 100644
--- a/fs/xfs/xfs_mru_cache.h
+++ b/fs/xfs/xfs_mru_cache.h
@@ -49,7 +49,6 @@ int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
-void *xfs_mru_cache_peek(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_done(struct xfs_mru_cache *mru);
#endif /* __XFS_MRU_CACHE_H__ */
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
index f76c003ec55d..ae65f0df87da 100644
--- a/fs/xfs/xfs_rw.h
+++ b/fs/xfs/xfs_rw.h
@@ -78,10 +78,4 @@ extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp,
extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
xfs_buf_t *bp, xfs_daddr_t blkno);
-/*
- * Prototypes for functions in xfs_vnodeops.c.
- */
-extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
- int flags);
-
#endif /* __XFS_RW_H__ */
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 8ee2f8c8b0a6..218829e6a152 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -307,7 +307,7 @@ xfs_trans_read_buf(
return (flags & XFS_BUF_TRYLOCK) ?
EAGAIN : XFS_ERROR(ENOMEM);
- if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) {
+ if (XFS_BUF_GETERROR(bp) != 0) {
xfs_ioerror_alert("xfs_trans_read_buf", mp,
bp, blkno);
error = XFS_BUF_GETERROR(bp);
@@ -315,7 +315,7 @@ xfs_trans_read_buf(
return error;
}
#ifdef DEBUG
- if (xfs_do_error && (bp != NULL)) {
+ if (xfs_do_error) {
if (xfs_error_target == target) {
if (((xfs_req_num++) % xfs_error_mod) == 0) {
xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index c4eca5ed5dab..1dd706887156 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -716,7 +716,7 @@ xfs_fsync(
* when the link count isn't zero and by xfs_dm_punch_hole() when
* punching a hole to EOF.
*/
-int
+STATIC int
xfs_free_eofblocks(
xfs_mount_t *mp,
xfs_inode_t *ip,
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f485107ddc43..fa77df875ece 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -87,7 +87,6 @@ struct acpi_device;
typedef int (*acpi_op_add) (struct acpi_device * device);
typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
typedef int (*acpi_op_start) (struct acpi_device * device);
-typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
typedef int (*acpi_op_suspend) (struct acpi_device * device,
pm_message_t state);
typedef int (*acpi_op_resume) (struct acpi_device * device);
@@ -104,7 +103,6 @@ struct acpi_device_ops {
acpi_op_add add;
acpi_op_remove remove;
acpi_op_start start;
- acpi_op_stop stop;
acpi_op_suspend suspend;
acpi_op_resume resume;
acpi_op_bind bind;
@@ -171,17 +169,15 @@ struct acpi_device_dir {
typedef char acpi_bus_id[8];
typedef unsigned long acpi_bus_address;
-typedef char acpi_hardware_id[15];
-typedef char acpi_unique_id[9];
typedef char acpi_device_name[40];
typedef char acpi_device_class[20];
struct acpi_device_pnp {
acpi_bus_id bus_id; /* Object name */
acpi_bus_address bus_address; /* _ADR */
- acpi_hardware_id hardware_id; /* _HID */
- struct acpi_compatible_id_list *cid_list; /* _CIDs */
- acpi_unique_id unique_id; /* _UID */
+ char *hardware_id; /* _HID */
+ struct acpica_device_id_list *cid_list; /* _CIDs */
+ char *unique_id; /* _UID */
acpi_device_name device_name; /* Driver-determined */
acpi_device_class device_class; /* " */
};
@@ -312,7 +308,7 @@ struct acpi_bus_event {
extern struct kobject *acpi_kobj;
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
-void acpi_bus_private_data_handler(acpi_handle, u32, void *);
+void acpi_bus_private_data_handler(acpi_handle, void *);
int acpi_bus_get_private_data(acpi_handle, void **);
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
extern int register_acpi_notifier(struct notifier_block *);
@@ -325,7 +321,7 @@ extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
*/
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context);
+void acpi_bus_data_handler(acpi_handle handle, void *context);
int acpi_bus_get_status(struct acpi_device *device);
int acpi_bus_get_power(acpi_handle handle, int *state);
int acpi_bus_set_power(acpi_handle handle, int state);
@@ -367,10 +363,26 @@ int register_acpi_bus_type(struct acpi_bus_type *);
int unregister_acpi_bus_type(struct acpi_bus_type *);
struct device *acpi_get_physical_device(acpi_handle);
+struct acpi_pci_root {
+ struct list_head node;
+ struct acpi_device * device;
+ struct acpi_pci_id id;
+ struct pci_bus *bus;
+ u16 segment;
+ u8 bus_nr;
+
+ u32 osc_support_set; /* _OSC state of support bits */
+ u32 osc_control_set; /* _OSC state of control bits */
+ u32 osc_control_qry; /* the latest _OSC query result */
+
+ u32 osc_queried:1; /* has _OSC control been queried? */
+};
+
/* helper */
acpi_handle acpi_get_child(acpi_handle, acpi_integer);
int acpi_is_root_bridge(acpi_handle);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
+struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
#ifdef CONFIG_PM_SLEEP
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 3e798593b17b..ab0b85cf21f3 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -242,6 +242,10 @@ acpi_os_derive_pci_id(acpi_handle rhandle,
acpi_status acpi_os_validate_interface(char *interface);
acpi_status acpi_osi_invalidate(char* interface);
+acpi_status
+acpi_os_validate_address(u8 space_id, acpi_physical_address address,
+ acpi_size length, char *name);
+
u64 acpi_os_get_timer(void);
acpi_status acpi_os_signal(u32 function, void *info);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 82ec6a3c0500..063e577e791e 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 0x20090521
+#define ACPI_CA_VERSION 0x20090625
#include "actypes.h"
#include "actbl.h"
@@ -64,6 +64,7 @@ extern u8 acpi_gbl_enable_interpreter_slack;
extern u8 acpi_gbl_all_methods_serialized;
extern u8 acpi_gbl_create_osi_method;
extern u8 acpi_gbl_leave_wake_gpes_disabled;
+extern u8 acpi_gbl_use_default_register_widths;
extern acpi_name acpi_gbl_trace_method_name;
extern u32 acpi_gbl_trace_flags;
@@ -199,7 +200,8 @@ acpi_evaluate_object_typed(acpi_handle object,
acpi_object_type return_type);
acpi_status
-acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);
+acpi_get_object_info(acpi_handle handle,
+ struct acpi_device_info **return_buffer);
acpi_status acpi_install_method(u8 *buffer);
@@ -359,9 +361,9 @@ acpi_status acpi_set_firmware_waking_vector(u32 physical_address);
acpi_status acpi_set_firmware_waking_vector64(u64 physical_address);
#endif
-acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg);
+acpi_status acpi_read(u64 *value, struct acpi_generic_address *reg);
-acpi_status acpi_write(u32 value, struct acpi_generic_address *reg);
+acpi_status acpi_write(u64 value, struct acpi_generic_address *reg);
acpi_status
acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b);
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 222733d01f36..0649a5670026 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -161,17 +161,24 @@ struct acpi_table_facs {
u32 flags;
u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */
u8 version; /* Version of this table (ACPI 2.0+) */
- u8 reserved[31]; /* Reserved, must be zero */
+ u8 reserved[3]; /* Reserved, must be zero */
+ u32 ospm_flags; /* Flags to be set by OSPM (ACPI 4.0) */
+ u8 reserved1[24]; /* Reserved, must be zero */
};
-/* Flag macros */
+/* global_lock flags */
+
+#define ACPI_GLOCK_PENDING (1) /* 00: Pending global lock ownership */
+#define ACPI_GLOCK_OWNED (1<<1) /* 01: Global lock is owned */
+
+/* Flags */
-#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */
+#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */
+#define ACPI_FACS_64BIT_WAKE (1<<1) /* 01: 64-bit wake vector supported (ACPI 4.0) */
-/* Global lock flags */
+/* ospm_flags */
-#define ACPI_GLOCK_PENDING 0x01 /* 00: Pending global lock ownership */
-#define ACPI_GLOCK_OWNED 0x02 /* 01: Global lock is owned */
+#define ACPI_FACS_64BIT_ENVIRONMENT (1) /* 00: 64-bit wake environment is required (ACPI 4.0) */
/*******************************************************************************
*
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 59ade0752473..ec36693f868c 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -1011,7 +1011,7 @@ struct acpi_madt_interrupt_source {
#define ACPI_MADT_CPEI_OVERRIDE (1)
-/* 9: Processor Local X2_APIC (07/2008) */
+/* 9: Processor Local X2APIC (ACPI 4.0) */
struct acpi_madt_local_x2apic {
struct acpi_subtable_header header;
@@ -1021,7 +1021,7 @@ struct acpi_madt_local_x2apic {
u32 uid; /* ACPI processor UID */
};
-/* 10: Local X2APIC NMI (07/2008) */
+/* 10: Local X2APIC NMI (ACPI 4.0) */
struct acpi_madt_local_x2apic_nmi {
struct acpi_subtable_header header;
@@ -1211,7 +1211,7 @@ struct acpi_srat_mem_affinity {
#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */
-/* 2: Processor Local X2_APIC Affinity (07/2008) */
+/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */
struct acpi_srat_x2apic_cpu_affinity {
struct acpi_subtable_header header;
@@ -1219,6 +1219,8 @@ struct acpi_srat_x2apic_cpu_affinity {
u32 proximity_domain;
u32 apic_id;
u32 flags;
+ u32 clock_domain;
+ u32 reserved2;
};
/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 37ba576d06e8..153f12dc3373 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -288,7 +288,7 @@ typedef u32 acpi_physical_address;
/*
* Some compilers complain about unused variables. Sometimes we don't want to
* use all the variables (for example, _acpi_module_name). This allows us
- * to to tell the compiler in a per-variable manner that a variable
+ * to tell the compiler in a per-variable manner that a variable
* is unused
*/
#ifndef ACPI_UNUSED_VAR
@@ -338,7 +338,7 @@ typedef u32 acpi_physical_address;
/* PM Timer ticks per second (HZ) */
-#define PM_TIMER_FREQUENCY 3579545
+#define PM_TIMER_FREQUENCY 3579545
/*******************************************************************************
*
@@ -732,7 +732,8 @@ typedef u8 acpi_adr_space_type;
#define ACPI_ADR_SPACE_SMBUS (acpi_adr_space_type) 4
#define ACPI_ADR_SPACE_CMOS (acpi_adr_space_type) 5
#define ACPI_ADR_SPACE_PCI_BAR_TARGET (acpi_adr_space_type) 6
-#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 7
+#define ACPI_ADR_SPACE_IPMI (acpi_adr_space_type) 7
+#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 8
#define ACPI_ADR_SPACE_FIXED_HARDWARE (acpi_adr_space_type) 127
/*
@@ -921,7 +922,7 @@ typedef
void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context);
typedef
-void (*acpi_object_handler) (acpi_handle object, u32 function, void *data);
+void (*acpi_object_handler) (acpi_handle object, void *data);
typedef acpi_status(*acpi_init_handler) (acpi_handle object, u32 function);
@@ -969,38 +970,60 @@ acpi_status(*acpi_walk_callback) (acpi_handle obj_handle,
#define ACPI_INTERRUPT_NOT_HANDLED 0x00
#define ACPI_INTERRUPT_HANDLED 0x01
-/* Length of _HID, _UID, _CID, and UUID values */
+/* Length of 32-bit EISAID values when converted back to a string */
+
+#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */
+
+/* Length of UUID (string) values */
-#define ACPI_DEVICE_ID_LENGTH 0x09
-#define ACPI_MAX_CID_LENGTH 48
#define ACPI_UUID_LENGTH 16
-/* Common string version of device HIDs and UIDs */
+/* Structures used for device/processor HID, UID, CID */
struct acpica_device_id {
- char value[ACPI_DEVICE_ID_LENGTH];
+ u32 length; /* Length of string + null */
+ char *string;
};
-/* Common string version of device CIDs */
-
-struct acpi_compatible_id {
- char value[ACPI_MAX_CID_LENGTH];
+struct acpica_device_id_list {
+ u32 count; /* Number of IDs in Ids array */
+ u32 list_size; /* Size of list, including ID strings */
+ struct acpica_device_id ids[1]; /* ID array */
};
-struct acpi_compatible_id_list {
- u32 count;
- u32 size;
- struct acpi_compatible_id id[1];
+/*
+ * Structure returned from acpi_get_object_info.
+ * Optimized for both 32- and 64-bit builds
+ */
+struct acpi_device_info {
+ u32 info_size; /* Size of info, including ID strings */
+ u32 name; /* ACPI object Name */
+ acpi_object_type type; /* ACPI object Type */
+ u8 param_count; /* If a method, required parameter count */
+ u8 valid; /* Indicates which optional fields are valid */
+ u8 flags; /* Miscellaneous info */
+ u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */
+ u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */
+ u32 current_status; /* _STA value */
+ acpi_integer address; /* _ADR value */
+ struct acpica_device_id hardware_id; /* _HID value */
+ struct acpica_device_id unique_id; /* _UID value */
+ struct acpica_device_id_list compatible_id_list; /* _CID list <must be last> */
};
-/* Structure and flags for acpi_get_object_info */
+/* Values for Flags field above (acpi_get_object_info) */
+
+#define ACPI_PCI_ROOT_BRIDGE 0x01
-#define ACPI_VALID_STA 0x0001
-#define ACPI_VALID_ADR 0x0002
-#define ACPI_VALID_HID 0x0004
-#define ACPI_VALID_UID 0x0008
-#define ACPI_VALID_CID 0x0010
-#define ACPI_VALID_SXDS 0x0020
+/* Flags for Valid field above (acpi_get_object_info) */
+
+#define ACPI_VALID_STA 0x01
+#define ACPI_VALID_ADR 0x02
+#define ACPI_VALID_HID 0x04
+#define ACPI_VALID_UID 0x08
+#define ACPI_VALID_CID 0x10
+#define ACPI_VALID_SXDS 0x20
+#define ACPI_VALID_SXWS 0x40
/* Flags for _STA method */
@@ -1011,29 +1034,6 @@ struct acpi_compatible_id_list {
#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */
#define ACPI_STA_BATTERY_PRESENT 0x10
-#define ACPI_COMMON_OBJ_INFO \
- acpi_object_type type; /* ACPI object type */ \
- acpi_name name /* ACPI object Name */
-
-struct acpi_obj_info_header {
- ACPI_COMMON_OBJ_INFO;
-};
-
-/* Structure returned from Get Object Info */
-
-struct acpi_device_info {
- ACPI_COMMON_OBJ_INFO;
-
- u32 param_count; /* If a method, required parameter count */
- u32 valid; /* Indicates which fields below are valid */
- u32 current_status; /* _STA value */
- acpi_integer address; /* _ADR value if any */
- struct acpica_device_id hardware_id; /* _HID value if any */
- struct acpica_device_id unique_id; /* _UID value if any */
- u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */
- struct acpi_compatible_id_list compatibility_id; /* List of _CIDs if any */
-};
-
/* Context structs for address space handlers */
struct acpi_pci_id {
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 935c5d7fc86e..6aadbf84ae71 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -57,7 +57,7 @@
/*
* Some compilers complain about unused variables. Sometimes we don't want to
* use all the variables (for example, _acpi_module_name). This allows us
- * to to tell the compiler warning in a per-variable manner that a variable
+ * to tell the compiler warning in a per-variable manner that a variable
* is unused.
*/
#define ACPI_UNUSED_VAR __attribute__ ((unused))
diff --git a/include/asm-generic/4level-fixup.h b/include/asm-generic/4level-fixup.h
index 9d40e879f99e..77ff547730af 100644
--- a/include/asm-generic/4level-fixup.h
+++ b/include/asm-generic/4level-fixup.h
@@ -27,9 +27,9 @@
#define pud_page_vaddr(pud) pgd_page_vaddr(pud)
#undef pud_free_tlb
-#define pud_free_tlb(tlb, x) do { } while (0)
+#define pud_free_tlb(tlb, x, addr) do { } while (0)
#define pud_free(mm, x) do { } while (0)
-#define __pud_free_tlb(tlb, x) do { } while (0)
+#define __pud_free_tlb(tlb, x, addr) do { } while (0)
#undef pud_addr_end
#define pud_addr_end(addr, end) (end)
diff --git a/include/asm-generic/device.h b/include/asm-generic/device.h
index c17c9600f220..d7c76bba640d 100644
--- a/include/asm-generic/device.h
+++ b/include/asm-generic/device.h
@@ -9,4 +9,7 @@
struct dev_archdata {
};
+struct pdev_archdata {
+};
+
#endif /* _ASM_GENERIC_DEVICE_H */
diff --git a/include/asm-generic/pci.h b/include/asm-generic/pci.h
index b4326b5466eb..26373cff4546 100644
--- a/include/asm-generic/pci.h
+++ b/include/asm-generic/pci.h
@@ -30,7 +30,18 @@ pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
res->end = region->end;
}
-#define pcibios_scan_all_fns(a, b) 0
+static inline struct resource *
+pcibios_select_root(struct pci_dev *pdev, struct resource *res)
+{
+ struct resource *root = NULL;
+
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ if (res->flags & IORESOURCE_MEM)
+ root = &iomem_resource;
+
+ return root;
+}
#ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index a7cdc48e8b78..725612b793ce 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -59,7 +59,7 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
}
-#define __pmd_free_tlb(tlb, x) do { } while (0)
+#define __pmd_free_tlb(tlb, x, a) do { } while (0)
#undef pmd_addr_end
#define pmd_addr_end(addr, end) (end)
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 87cf449a6df3..810431d8351b 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -52,7 +52,7 @@ static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address)
*/
#define pud_alloc_one(mm, address) NULL
#define pud_free(mm, x) do { } while (0)
-#define __pud_free_tlb(tlb, x) do { } while (0)
+#define __pud_free_tlb(tlb, x, a) do { } while (0)
#undef pud_addr_end
#define pud_addr_end(addr, end) (end)
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index f490e43a90b9..e43f9766259f 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -123,24 +123,24 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
__tlb_remove_tlb_entry(tlb, ptep, address); \
} while (0)
-#define pte_free_tlb(tlb, ptep) \
+#define pte_free_tlb(tlb, ptep, address) \
do { \
tlb->need_flush = 1; \
- __pte_free_tlb(tlb, ptep); \
+ __pte_free_tlb(tlb, ptep, address); \
} while (0)
#ifndef __ARCH_HAS_4LEVEL_HACK
-#define pud_free_tlb(tlb, pudp) \
+#define pud_free_tlb(tlb, pudp, address) \
do { \
tlb->need_flush = 1; \
- __pud_free_tlb(tlb, pudp); \
+ __pud_free_tlb(tlb, pudp, address); \
} while (0)
#endif
-#define pmd_free_tlb(tlb, pmdp) \
+#define pmd_free_tlb(tlb, pmdp, address) \
do { \
tlb->need_flush = 1; \
- __pmd_free_tlb(tlb, pmdp); \
+ __pmd_free_tlb(tlb, pmdp, address); \
} while (0)
#define tlb_migrate_finish(mm) do {} while (0)
diff --git a/include/asm-generic/topology.h b/include/asm-generic/topology.h
index 88bada2ebc4b..510df36dd5d4 100644
--- a/include/asm-generic/topology.h
+++ b/include/asm-generic/topology.h
@@ -37,9 +37,6 @@
#ifndef parent_node
#define parent_node(node) ((void)(node),0)
#endif
-#ifndef node_to_cpumask
-#define node_to_cpumask(node) ((void)node, cpu_online_map)
-#endif
#ifndef cpumask_of_node
#define cpumask_of_node(node) ((void)node, cpu_online_mask)
#endif
@@ -55,18 +52,4 @@
#endif /* CONFIG_NUMA */
-/*
- * returns pointer to cpumask for specified node
- * Deprecated: use "const struct cpumask *mask = cpumask_of_node(node)"
- */
-#ifndef node_to_cpumask_ptr
-
-#define node_to_cpumask_ptr(v, node) \
- cpumask_t _##v = node_to_cpumask(node); \
- const cpumask_t *v = &_##v
-
-#define node_to_cpumask_ptr_next(v, node) \
- _##v = node_to_cpumask(node)
-#endif
-
#endif /* _ASM_GENERIC_TOPOLOGY_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 6ad76bf5fb40..a43223af98b6 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -33,13 +33,10 @@
* BSS_SECTION(0, 0, 0)
* _end = .;
*
- * /DISCARD/ : {
- * EXIT_TEXT
- * EXIT_DATA
- * EXIT_CALL
- * }
* STABS_DEBUG
* DWARF_DEBUG
+ *
+ * DISCARDS // must be the last
* }
*
* [__init_begin, __init_end] is the init section that may be freed after init
@@ -626,6 +623,23 @@
#define INIT_RAM_FS
#endif
+/*
+ * Default discarded sections.
+ *
+ * Some archs want to discard exit text/data at runtime rather than
+ * link time due to cross-section references such as alt instructions,
+ * bug table, eh_frame, etc. DISCARDS must be the last of output
+ * section definitions so that such archs put those in earlier section
+ * definitions.
+ */
+#define DISCARDS \
+ /DISCARD/ : { \
+ EXIT_TEXT \
+ EXIT_DATA \
+ EXIT_CALL \
+ *(.discard) \
+ }
+
/**
* PERCPU_VADDR - define output section for percpu area
* @vaddr: explicit base address (optional)
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 010545436efa..3f388146a914 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -22,11 +22,9 @@ struct seq_file;
struct crypto_type {
unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask);
- unsigned int (*extsize)(struct crypto_alg *alg,
- const struct crypto_type *frontend);
+ unsigned int (*extsize)(struct crypto_alg *alg);
int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask);
- int (*init_tfm)(struct crypto_tfm *tfm,
- const struct crypto_type *frontend);
+ int (*init_tfm)(struct crypto_tfm *tfm);
void (*show)(struct seq_file *m, struct crypto_alg *alg);
struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
@@ -52,6 +50,7 @@ struct crypto_template {
struct crypto_instance *(*alloc)(struct rtattr **tb);
void (*free)(struct crypto_instance *inst);
+ int (*create)(struct crypto_template *tmpl, struct rtattr **tb);
char name[CRYPTO_MAX_ALG_NAME];
};
@@ -60,6 +59,7 @@ struct crypto_spawn {
struct list_head list;
struct crypto_alg *alg;
struct crypto_instance *inst;
+ const struct crypto_type *frontend;
u32 mask;
};
@@ -114,11 +114,19 @@ int crypto_register_template(struct crypto_template *tmpl);
void crypto_unregister_template(struct crypto_template *tmpl);
struct crypto_template *crypto_lookup_template(const char *name);
+int crypto_register_instance(struct crypto_template *tmpl,
+ struct crypto_instance *inst);
+
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
struct crypto_instance *inst, u32 mask);
+int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg,
+ struct crypto_instance *inst,
+ const struct crypto_type *frontend);
+
void crypto_drop_spawn(struct crypto_spawn *spawn);
struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
u32 mask);
+void *crypto_spawn_tfm2(struct crypto_spawn *spawn);
static inline void crypto_set_spawn(struct crypto_spawn *spawn,
struct crypto_instance *inst)
@@ -129,8 +137,19 @@ static inline void crypto_set_spawn(struct crypto_spawn *spawn,
struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
int crypto_check_attr_type(struct rtattr **tb, u32 type);
const char *crypto_attr_alg_name(struct rtattr *rta);
-struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask);
+struct crypto_alg *crypto_attr_alg2(struct rtattr *rta,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask);
+
+static inline struct crypto_alg *crypto_attr_alg(struct rtattr *rta,
+ u32 type, u32 mask)
+{
+ return crypto_attr_alg2(rta, NULL, type, mask);
+}
+
int crypto_attr_u32(struct rtattr *rta, u32 *num);
+void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg,
+ unsigned int head);
struct crypto_instance *crypto_alloc_instance(const char *name,
struct crypto_alg *alg);
@@ -156,12 +175,8 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc,
static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm)
{
- unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
- unsigned long align = crypto_tfm_alg_alignmask(tfm);
-
- if (align <= crypto_tfm_ctx_alignment())
- align = 1;
- return (void *)ALIGN(addr, align);
+ return PTR_ALIGN(crypto_tfm_ctx(tfm),
+ crypto_tfm_alg_alignmask(tfm) + 1);
}
static inline struct crypto_instance *crypto_tfm_alg_instance(
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index d56bb71617c3..26cb1eb16f4c 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -15,6 +15,42 @@
#include <linux/crypto.h>
+struct crypto_ahash;
+
+struct hash_alg_common {
+ unsigned int digestsize;
+ unsigned int statesize;
+
+ struct crypto_alg base;
+};
+
+struct ahash_request {
+ struct crypto_async_request base;
+
+ unsigned int nbytes;
+ struct scatterlist *src;
+ u8 *result;
+
+ /* This field may only be used by the ahash API code. */
+ void *priv;
+
+ void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
+struct ahash_alg {
+ int (*init)(struct ahash_request *req);
+ int (*update)(struct ahash_request *req);
+ int (*final)(struct ahash_request *req);
+ int (*finup)(struct ahash_request *req);
+ int (*digest)(struct ahash_request *req);
+ int (*export)(struct ahash_request *req, void *out);
+ int (*import)(struct ahash_request *req, const void *in);
+ int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen);
+
+ struct hash_alg_common halg;
+};
+
struct shash_desc {
struct crypto_shash *tfm;
u32 flags;
@@ -24,7 +60,6 @@ struct shash_desc {
struct shash_alg {
int (*init)(struct shash_desc *desc);
- int (*reinit)(struct shash_desc *desc);
int (*update)(struct shash_desc *desc, const u8 *data,
unsigned int len);
int (*final)(struct shash_desc *desc, u8 *out);
@@ -32,38 +67,48 @@ struct shash_alg {
unsigned int len, u8 *out);
int (*digest)(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out);
+ int (*export)(struct shash_desc *desc, void *out);
+ int (*import)(struct shash_desc *desc, const void *in);
int (*setkey)(struct crypto_shash *tfm, const u8 *key,
unsigned int keylen);
unsigned int descsize;
- unsigned int digestsize;
+
+ /* These fields must match hash_alg_common. */
+ unsigned int digestsize
+ __attribute__ ((aligned(__alignof__(struct hash_alg_common))));
+ unsigned int statesize;
struct crypto_alg base;
};
struct crypto_ahash {
+ int (*init)(struct ahash_request *req);
+ int (*update)(struct ahash_request *req);
+ int (*final)(struct ahash_request *req);
+ int (*finup)(struct ahash_request *req);
+ int (*digest)(struct ahash_request *req);
+ int (*export)(struct ahash_request *req, void *out);
+ int (*import)(struct ahash_request *req, const void *in);
+ int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen);
+
+ unsigned int reqsize;
struct crypto_tfm base;
};
struct crypto_shash {
+ unsigned int descsize;
struct crypto_tfm base;
};
static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm)
{
- return (struct crypto_ahash *)tfm;
+ return container_of(tfm, struct crypto_ahash, base);
}
-static inline struct crypto_ahash *crypto_alloc_ahash(const char *alg_name,
- u32 type, u32 mask)
-{
- type &= ~CRYPTO_ALG_TYPE_MASK;
- mask &= ~CRYPTO_ALG_TYPE_MASK;
- type |= CRYPTO_ALG_TYPE_AHASH;
- mask |= CRYPTO_ALG_TYPE_AHASH_MASK;
-
- return __crypto_ahash_cast(crypto_alloc_base(alg_name, type, mask));
-}
+struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
+ u32 mask);
static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm)
{
@@ -72,7 +117,7 @@ static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm)
static inline void crypto_free_ahash(struct crypto_ahash *tfm)
{
- crypto_free_tfm(crypto_ahash_tfm(tfm));
+ crypto_destroy_tfm(tfm, crypto_ahash_tfm(tfm));
}
static inline unsigned int crypto_ahash_alignmask(
@@ -81,14 +126,26 @@ static inline unsigned int crypto_ahash_alignmask(
return crypto_tfm_alg_alignmask(crypto_ahash_tfm(tfm));
}
-static inline struct ahash_tfm *crypto_ahash_crt(struct crypto_ahash *tfm)
+static inline struct hash_alg_common *__crypto_hash_alg_common(
+ struct crypto_alg *alg)
+{
+ return container_of(alg, struct hash_alg_common, base);
+}
+
+static inline struct hash_alg_common *crypto_hash_alg_common(
+ struct crypto_ahash *tfm)
{
- return &crypto_ahash_tfm(tfm)->crt_ahash;
+ return __crypto_hash_alg_common(crypto_ahash_tfm(tfm)->__crt_alg);
}
static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm)
{
- return crypto_ahash_crt(tfm)->digestsize;
+ return crypto_hash_alg_common(tfm)->digestsize;
+}
+
+static inline unsigned int crypto_ahash_statesize(struct crypto_ahash *tfm)
+{
+ return crypto_hash_alg_common(tfm)->statesize;
}
static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm)
@@ -114,7 +171,7 @@ static inline struct crypto_ahash *crypto_ahash_reqtfm(
static inline unsigned int crypto_ahash_reqsize(struct crypto_ahash *tfm)
{
- return crypto_ahash_crt(tfm)->reqsize;
+ return tfm->reqsize;
}
static inline void *ahash_request_ctx(struct ahash_request *req)
@@ -122,44 +179,30 @@ static inline void *ahash_request_ctx(struct ahash_request *req)
return req->__ctx;
}
-static inline int crypto_ahash_setkey(struct crypto_ahash *tfm,
- const u8 *key, unsigned int keylen)
-{
- struct ahash_tfm *crt = crypto_ahash_crt(tfm);
-
- return crt->setkey(tfm, key, keylen);
-}
+int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen);
+int crypto_ahash_finup(struct ahash_request *req);
+int crypto_ahash_final(struct ahash_request *req);
+int crypto_ahash_digest(struct ahash_request *req);
-static inline int crypto_ahash_digest(struct ahash_request *req)
+static inline int crypto_ahash_export(struct ahash_request *req, void *out)
{
- struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
- return crt->digest(req);
+ return crypto_ahash_reqtfm(req)->export(req, out);
}
-static inline void crypto_ahash_export(struct ahash_request *req, u8 *out)
+static inline int crypto_ahash_import(struct ahash_request *req, const void *in)
{
- memcpy(out, ahash_request_ctx(req),
- crypto_ahash_reqsize(crypto_ahash_reqtfm(req)));
+ return crypto_ahash_reqtfm(req)->import(req, in);
}
-int crypto_ahash_import(struct ahash_request *req, const u8 *in);
-
static inline int crypto_ahash_init(struct ahash_request *req)
{
- struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
- return crt->init(req);
+ return crypto_ahash_reqtfm(req)->init(req);
}
static inline int crypto_ahash_update(struct ahash_request *req)
{
- struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
- return crt->update(req);
-}
-
-static inline int crypto_ahash_final(struct ahash_request *req)
-{
- struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
- return crt->final(req);
+ return crypto_ahash_reqtfm(req)->update(req);
}
static inline void ahash_request_set_tfm(struct ahash_request *req,
@@ -184,7 +227,7 @@ static inline struct ahash_request *ahash_request_alloc(
static inline void ahash_request_free(struct ahash_request *req)
{
- kfree(req);
+ kzfree(req);
}
static inline struct ahash_request *ahash_request_cast(
@@ -251,6 +294,11 @@ static inline unsigned int crypto_shash_digestsize(struct crypto_shash *tfm)
return crypto_shash_alg(tfm)->digestsize;
}
+static inline unsigned int crypto_shash_statesize(struct crypto_shash *tfm)
+{
+ return crypto_shash_alg(tfm)->statesize;
+}
+
static inline u32 crypto_shash_get_flags(struct crypto_shash *tfm)
{
return crypto_tfm_get_flags(crypto_shash_tfm(tfm));
@@ -268,7 +316,7 @@ static inline void crypto_shash_clear_flags(struct crypto_shash *tfm, u32 flags)
static inline unsigned int crypto_shash_descsize(struct crypto_shash *tfm)
{
- return crypto_shash_alg(tfm)->descsize;
+ return tfm->descsize;
}
static inline void *shash_desc_ctx(struct shash_desc *desc)
@@ -281,12 +329,15 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out);
-static inline void crypto_shash_export(struct shash_desc *desc, u8 *out)
+static inline int crypto_shash_export(struct shash_desc *desc, void *out)
{
- memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm));
+ return crypto_shash_alg(desc->tfm)->export(desc, out);
}
-int crypto_shash_import(struct shash_desc *desc, const u8 *in);
+static inline int crypto_shash_import(struct shash_desc *desc, const void *in)
+{
+ return crypto_shash_alg(desc->tfm)->import(desc, in);
+}
static inline int crypto_shash_init(struct shash_desc *desc)
{
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 82b70564bcab..5bfad8c80595 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -34,6 +34,22 @@ struct crypto_hash_walk {
unsigned int flags;
};
+struct ahash_instance {
+ struct ahash_alg alg;
+};
+
+struct shash_instance {
+ struct shash_alg alg;
+};
+
+struct crypto_ahash_spawn {
+ struct crypto_spawn base;
+};
+
+struct crypto_shash_spawn {
+ struct crypto_spawn base;
+};
+
extern const struct crypto_type crypto_ahash_type;
int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
@@ -43,18 +59,100 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
struct crypto_hash_walk *walk,
struct scatterlist *sg, unsigned int len);
+static inline int crypto_hash_walk_last(struct crypto_hash_walk *walk)
+{
+ return !(walk->entrylen | walk->total);
+}
+
+int crypto_register_ahash(struct ahash_alg *alg);
+int crypto_unregister_ahash(struct ahash_alg *alg);
+int ahash_register_instance(struct crypto_template *tmpl,
+ struct ahash_instance *inst);
+void ahash_free_instance(struct crypto_instance *inst);
+
+int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
+ struct hash_alg_common *alg,
+ struct crypto_instance *inst);
+
+static inline void crypto_drop_ahash(struct crypto_ahash_spawn *spawn)
+{
+ crypto_drop_spawn(&spawn->base);
+}
+
+struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask);
+
int crypto_register_shash(struct shash_alg *alg);
int crypto_unregister_shash(struct shash_alg *alg);
+int shash_register_instance(struct crypto_template *tmpl,
+ struct shash_instance *inst);
+void shash_free_instance(struct crypto_instance *inst);
+
+int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn,
+ struct shash_alg *alg,
+ struct crypto_instance *inst);
+
+static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn)
+{
+ crypto_drop_spawn(&spawn->base);
+}
+
+struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask);
+
+int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
+int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc);
+int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc);
+
+int crypto_init_shash_ops_async(struct crypto_tfm *tfm);
static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
{
- return crypto_tfm_ctx(&tfm->base);
+ return crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+}
+
+static inline struct ahash_alg *__crypto_ahash_alg(struct crypto_alg *alg)
+{
+ return container_of(__crypto_hash_alg_common(alg), struct ahash_alg,
+ halg);
+}
+
+static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm,
+ unsigned int reqsize)
+{
+ tfm->reqsize = reqsize;
+}
+
+static inline struct crypto_instance *ahash_crypto_instance(
+ struct ahash_instance *inst)
+{
+ return container_of(&inst->alg.halg.base, struct crypto_instance, alg);
}
-static inline struct ahash_alg *crypto_ahash_alg(
- struct crypto_ahash *tfm)
+static inline struct ahash_instance *ahash_instance(
+ struct crypto_instance *inst)
{
- return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash;
+ return container_of(&inst->alg, struct ahash_instance, alg.halg.base);
+}
+
+static inline void *ahash_instance_ctx(struct ahash_instance *inst)
+{
+ return crypto_instance_ctx(ahash_crypto_instance(inst));
+}
+
+static inline unsigned int ahash_instance_headroom(void)
+{
+ return sizeof(struct ahash_alg) - sizeof(struct crypto_alg);
+}
+
+static inline struct ahash_instance *ahash_alloc_instance(
+ const char *name, struct crypto_alg *alg)
+{
+ return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
+}
+
+static inline struct crypto_ahash *crypto_spawn_ahash(
+ struct crypto_ahash_spawn *spawn)
+{
+ return crypto_spawn_tfm2(&spawn->base);
}
static inline int ahash_enqueue_request(struct crypto_queue *queue,
@@ -80,5 +178,46 @@ static inline void *crypto_shash_ctx(struct crypto_shash *tfm)
return crypto_tfm_ctx(&tfm->base);
}
+static inline struct crypto_instance *shash_crypto_instance(
+ struct shash_instance *inst)
+{
+ return container_of(&inst->alg.base, struct crypto_instance, alg);
+}
+
+static inline struct shash_instance *shash_instance(
+ struct crypto_instance *inst)
+{
+ return container_of(__crypto_shash_alg(&inst->alg),
+ struct shash_instance, alg);
+}
+
+static inline void *shash_instance_ctx(struct shash_instance *inst)
+{
+ return crypto_instance_ctx(shash_crypto_instance(inst));
+}
+
+static inline struct shash_instance *shash_alloc_instance(
+ const char *name, struct crypto_alg *alg)
+{
+ return crypto_alloc_instance2(name, alg,
+ sizeof(struct shash_alg) - sizeof(*alg));
+}
+
+static inline struct crypto_shash *crypto_spawn_shash(
+ struct crypto_shash_spawn *spawn)
+{
+ return crypto_spawn_tfm2(&spawn->base);
+}
+
+static inline void *crypto_shash_ctx_aligned(struct crypto_shash *tfm)
+{
+ return crypto_tfm_ctx_aligned(&tfm->base);
+}
+
+static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm)
+{
+ return container_of(tfm, struct crypto_shash, base);
+}
+
#endif /* _CRYPTO_INTERNAL_HASH_H */
diff --git a/include/crypto/sha.h b/include/crypto/sha.h
index c0ccc2b1a2d8..069e85ba97e1 100644
--- a/include/crypto/sha.h
+++ b/include/crypto/sha.h
@@ -5,6 +5,8 @@
#ifndef _CRYPTO_SHA_H
#define _CRYPTO_SHA_H
+#include <linux/types.h>
+
#define SHA1_DIGEST_SIZE 20
#define SHA1_BLOCK_SIZE 64
@@ -62,4 +64,22 @@
#define SHA512_H6 0x1f83d9abfb41bd6bULL
#define SHA512_H7 0x5be0cd19137e2179ULL
+struct sha1_state {
+ u64 count;
+ u32 state[SHA1_DIGEST_SIZE / 4];
+ u8 buffer[SHA1_BLOCK_SIZE];
+};
+
+struct sha256_state {
+ u64 count;
+ u32 state[SHA256_DIGEST_SIZE / 4];
+ u8 buf[SHA256_BLOCK_SIZE];
+};
+
+struct sha512_state {
+ u64 count[2];
+ u64 state[SHA512_DIGEST_SIZE / 8];
+ u8 buf[SHA512_BLOCK_SIZE];
+};
+
#endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7300fb866767..125994d8ac0b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -736,4 +736,10 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern bool drm_detect_hdmi_monitor(struct edid *edid);
+extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
+ int hdisplay, int vdisplay, int vrefresh,
+ bool reduced, bool interlaced);
+extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
+ int hdisplay, int vdisplay, int vrefresh,
+ bool interlaced, int margins);
#endif /* __DRM_CRTC_H__ */
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index 41862e9a4c20..af4b4826997e 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -506,6 +506,8 @@ typedef struct {
#define DRM_RADEON_GEM_WAIT_IDLE 0x24
#define DRM_RADEON_CS 0x26
#define DRM_RADEON_INFO 0x27
+#define DRM_RADEON_GEM_SET_TILING 0x28
+#define DRM_RADEON_GEM_GET_TILING 0x29
#define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
#define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -544,7 +546,8 @@ typedef struct {
#define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle)
#define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs)
#define DRM_IOCTL_RADEON_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info)
-
+#define DRM_IOCTL_RADEON_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling)
+#define DRM_IOCTL_RADEON_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling)
typedef struct drm_radeon_init {
enum {
@@ -796,6 +799,24 @@ struct drm_radeon_gem_create {
uint32_t flags;
};
+#define RADEON_TILING_MACRO 0x1
+#define RADEON_TILING_MICRO 0x2
+#define RADEON_TILING_SWAP 0x4
+#define RADEON_TILING_SURFACE 0x8 /* this object requires a surface
+ * when mapped - i.e. front buffer */
+
+struct drm_radeon_gem_set_tiling {
+ uint32_t handle;
+ uint32_t tiling_flags;
+ uint32_t pitch;
+};
+
+struct drm_radeon_gem_get_tiling {
+ uint32_t handle;
+ uint32_t tiling_flags;
+ uint32_t pitch;
+};
+
struct drm_radeon_gem_mmap {
uint32_t handle;
uint32_t pad;
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index 62ed733c52a2..a68829db381a 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -121,6 +121,7 @@ struct ttm_backend {
#define TTM_PAGE_FLAG_SWAPPED (1 << 4)
#define TTM_PAGE_FLAG_PERSISTANT_SWAP (1 << 5)
#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6)
+#define TTM_PAGE_FLAG_DMA32 (1 << 7)
enum ttm_caching_state {
tt_uncached,
@@ -353,6 +354,14 @@ struct ttm_bo_driver {
int (*sync_obj_flush) (void *sync_obj, void *sync_arg);
void (*sync_obj_unref) (void **sync_obj);
void *(*sync_obj_ref) (void *sync_obj);
+
+ /* hook to notify driver about a driver move so it
+ * can do tiling things */
+ void (*move_notify)(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *new_mem);
+ /* notify the driver we are taking a fault on this BO
+ * and have reserved it */
+ void (*fault_reserve_notify)(struct ttm_buffer_object *bo);
};
#define TTM_NUM_MEM_TYPES 8
@@ -429,6 +438,8 @@ struct ttm_bo_device {
*/
struct delayed_work wq;
+
+ bool need_dma32;
};
/**
@@ -648,7 +659,14 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
extern int ttm_bo_device_init(struct ttm_bo_device *bdev,
struct ttm_mem_global *mem_glob,
struct ttm_bo_driver *driver,
- uint64_t file_page_offset);
+ uint64_t file_page_offset, bool need_dma32);
+
+/**
+ * ttm_bo_unmap_virtual
+ *
+ * @bo: tear down the virtual mappings for this BO
+ */
+extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
/**
* ttm_bo_reserve:
diff --git a/include/drm/ttm/ttm_module.h b/include/drm/ttm/ttm_module.h
index 889a4c7958ae..d1d433834e4f 100644
--- a/include/drm/ttm/ttm_module.h
+++ b/include/drm/ttm/ttm_module.h
@@ -33,7 +33,7 @@
#include <linux/kernel.h>
-#define TTM_PFX "[TTM]"
+#define TTM_PFX "[TTM] "
enum ttm_global_types {
TTM_GLOBAL_TTM_MEM = 0,
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 9c75921f0c16..6299a259ed19 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -210,15 +210,25 @@ enum {
ATA_CMD_STANDBY = 0xE2, /* place in standby power mode */
ATA_CMD_IDLE = 0xE3, /* place in idle power mode */
ATA_CMD_EDD = 0x90, /* execute device diagnostic */
+ ATA_CMD_DOWNLOAD_MICRO = 0x92,
+ ATA_CMD_NOP = 0x00,
ATA_CMD_FLUSH = 0xE7,
ATA_CMD_FLUSH_EXT = 0xEA,
ATA_CMD_ID_ATA = 0xEC,
ATA_CMD_ID_ATAPI = 0xA1,
+ ATA_CMD_SERVICE = 0xA2,
ATA_CMD_READ = 0xC8,
ATA_CMD_READ_EXT = 0x25,
+ ATA_CMD_READ_QUEUED = 0x26,
+ ATA_CMD_READ_STREAM_EXT = 0x2B,
+ ATA_CMD_READ_STREAM_DMA_EXT = 0x2A,
ATA_CMD_WRITE = 0xCA,
ATA_CMD_WRITE_EXT = 0x35,
+ ATA_CMD_WRITE_QUEUED = 0x36,
+ ATA_CMD_WRITE_STREAM_EXT = 0x3B,
+ ATA_CMD_WRITE_STREAM_DMA_EXT = 0x3A,
ATA_CMD_WRITE_FUA_EXT = 0x3D,
+ ATA_CMD_WRITE_QUEUED_FUA_EXT = 0x3E,
ATA_CMD_FPDMA_READ = 0x60,
ATA_CMD_FPDMA_WRITE = 0x61,
ATA_CMD_PIO_READ = 0x20,
@@ -235,6 +245,7 @@ enum {
ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40,
ATA_CMD_VERIFY_EXT = 0x42,
+ ATA_CMD_WRITE_UNCORR_EXT = 0x45,
ATA_CMD_STANDBYNOW1 = 0xE0,
ATA_CMD_IDLEIMMEDIATE = 0xE1,
ATA_CMD_SLEEP = 0xE6,
@@ -243,15 +254,34 @@ enum {
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
ATA_CMD_SET_MAX = 0xF9,
ATA_CMD_SET_MAX_EXT = 0x37,
- ATA_CMD_READ_LOG_EXT = 0x2f,
+ ATA_CMD_READ_LOG_EXT = 0x2F,
+ ATA_CMD_WRITE_LOG_EXT = 0x3F,
+ ATA_CMD_READ_LOG_DMA_EXT = 0x47,
+ ATA_CMD_WRITE_LOG_DMA_EXT = 0x57,
+ ATA_CMD_TRUSTED_RCV = 0x5C,
+ ATA_CMD_TRUSTED_RCV_DMA = 0x5D,
+ ATA_CMD_TRUSTED_SND = 0x5E,
+ ATA_CMD_TRUSTED_SND_DMA = 0x5F,
ATA_CMD_PMP_READ = 0xE4,
ATA_CMD_PMP_WRITE = 0xE8,
ATA_CMD_CONF_OVERLAY = 0xB1,
+ ATA_CMD_SEC_SET_PASS = 0xF1,
+ ATA_CMD_SEC_UNLOCK = 0xF2,
+ ATA_CMD_SEC_ERASE_PREP = 0xF3,
+ ATA_CMD_SEC_ERASE_UNIT = 0xF4,
ATA_CMD_SEC_FREEZE_LOCK = 0xF5,
+ ATA_CMD_SEC_DISABLE_PASS = 0xF6,
+ ATA_CMD_CONFIG_STREAM = 0x51,
ATA_CMD_SMART = 0xB0,
ATA_CMD_MEDIA_LOCK = 0xDE,
ATA_CMD_MEDIA_UNLOCK = 0xDF,
ATA_CMD_DSM = 0x06,
+ ATA_CMD_CHK_MED_CRD_TYP = 0xD1,
+ ATA_CMD_CFA_REQ_EXT_ERR = 0x03,
+ ATA_CMD_CFA_WRITE_NE = 0x38,
+ ATA_CMD_CFA_TRANS_SECT = 0x87,
+ ATA_CMD_CFA_ERASE = 0xC0,
+ ATA_CMD_CFA_WRITE_MULT_NE = 0xCD,
/* marked obsolete in the ATA/ATAPI-7 spec */
ATA_CMD_RESTORE = 0x10,
@@ -306,6 +336,7 @@ enum {
/* 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 */
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
@@ -525,6 +556,9 @@ static inline int ata_is_data(u8 prot)
#define ata_id_has_atapi_AN(id) \
( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
((id)[78] & (1 << 5)) )
+#define ata_id_has_fpdma_aa(id) \
+ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
+ ((id)[78] & (1 << 2)) )
#define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10))
#define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11))
#define ata_id_u32(id,n) \
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 1d52425a6118..47ed0f22d020 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -13,6 +13,9 @@
#include <linux/proportions.h>
#include <linux/kernel.h>
#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/srcu.h>
+#include <linux/writeback.h>
#include <asm/atomic.h>
struct page;
@@ -23,9 +26,12 @@ struct dentry;
* Bits in backing_dev_info.state
*/
enum bdi_state {
- BDI_pdflush, /* A pdflush thread is working this device */
+ BDI_pending, /* On its way to being activated */
+ BDI_wb_alloc, /* Default embedded wb allocated */
+ BDI_wblist_lock, /* bdi->wb_list now needs locking */
BDI_async_congested, /* The async (write) queue is getting full */
BDI_sync_congested, /* The sync queue is getting full */
+ BDI_registered, /* bdi_register() was done */
BDI_unused, /* Available bits start here */
};
@@ -39,7 +45,23 @@ enum bdi_stat_item {
#define BDI_STAT_BATCH (8*(1+ilog2(nr_cpu_ids)))
+struct bdi_writeback {
+ struct list_head list; /* hangs off the bdi */
+
+ struct backing_dev_info *bdi; /* our parent bdi */
+ unsigned int nr;
+
+ struct task_struct *task; /* writeback task */
+ struct list_head b_dirty; /* dirty inodes */
+ struct list_head b_io; /* parked for writeback */
+ struct list_head b_more_io; /* parked for more writeback */
+};
+
+#define BDI_MAX_FLUSHERS 32
+
struct backing_dev_info {
+ struct srcu_struct srcu; /* for wb_list read side protection */
+ struct list_head bdi_list;
unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
unsigned long state; /* Always use atomic bitops on this */
unsigned int capabilities; /* Device capabilities */
@@ -48,6 +70,8 @@ struct backing_dev_info {
void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
void *unplug_io_data;
+ char *name;
+
struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS];
struct prop_local_percpu completions;
@@ -56,6 +80,14 @@ struct backing_dev_info {
unsigned int min_ratio;
unsigned int max_ratio, max_prop_frac;
+ struct bdi_writeback wb; /* default writeback info for this bdi */
+ spinlock_t wb_lock; /* protects update side of wb_list */
+ struct list_head wb_list; /* the flusher threads hanging off this bdi */
+ unsigned long wb_mask; /* bitmask of registered tasks */
+ unsigned int wb_cnt; /* number of registered tasks */
+
+ struct list_head work_list;
+
struct device *dev;
#ifdef CONFIG_DEBUG_FS
@@ -71,6 +103,32 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
const char *fmt, ...);
int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
void bdi_unregister(struct backing_dev_info *bdi);
+void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
+ long nr_pages, enum writeback_sync_modes sync_mode);
+int bdi_writeback_task(struct bdi_writeback *wb);
+void bdi_writeback_all(struct super_block *sb, struct writeback_control *wbc);
+void bdi_add_flusher_task(struct backing_dev_info *bdi);
+int bdi_has_dirty_io(struct backing_dev_info *bdi);
+
+extern spinlock_t bdi_lock;
+extern struct list_head bdi_list;
+
+static inline int wb_is_default_task(struct bdi_writeback *wb)
+{
+ return wb == &wb->bdi->wb;
+}
+
+static inline int bdi_wblist_needs_lock(struct backing_dev_info *bdi)
+{
+ return test_bit(BDI_wblist_lock, &bdi->state);
+}
+
+static inline int wb_has_dirty_io(struct bdi_writeback *wb)
+{
+ return !list_empty(&wb->b_dirty) ||
+ !list_empty(&wb->b_io) ||
+ !list_empty(&wb->b_more_io);
+}
static inline void __add_bdi_stat(struct backing_dev_info *bdi,
enum bdi_stat_item item, s64 amount)
@@ -261,6 +319,11 @@ static inline bool bdi_cap_swap_backed(struct backing_dev_info *bdi)
return bdi->capabilities & BDI_CAP_SWAP_BACKED;
}
+static inline bool bdi_cap_flush_forker(struct backing_dev_info *bdi)
+{
+ return bdi == &default_backing_dev_info;
+}
+
static inline bool mapping_cap_writeback_dirty(struct address_space *mapping)
{
return bdi_cap_writeback_dirty(mapping->backing_dev_info);
@@ -276,4 +339,10 @@ static inline bool mapping_cap_swap_backed(struct address_space *mapping)
return bdi_cap_swap_backed(mapping->backing_dev_info);
}
+static inline int bdi_sched_wait(void *word)
+{
+ schedule();
+ return 0;
+}
+
#endif /* _LINUX_BACKING_DEV_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2892b710771c..5be93f18d842 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -142,56 +142,51 @@ struct bio {
*
* bit 0 -- data direction
* If not set, bio is a read from device. If set, it's a write to device.
- * bit 1 -- rw-ahead when set
- * bit 2 -- barrier
+ * bit 1 -- fail fast device errors
+ * bit 2 -- fail fast transport errors
+ * bit 3 -- fail fast driver errors
+ * bit 4 -- rw-ahead when set
+ * bit 5 -- barrier
* Insert a serialization point in the IO queue, forcing previously
* submitted IO to be completed before this one is issued.
- * bit 3 -- synchronous I/O hint.
- * bit 4 -- Unplug the device immediately after submitting this bio.
- * bit 5 -- metadata request
+ * bit 6 -- synchronous I/O hint.
+ * bit 7 -- Unplug the device immediately after submitting this bio.
+ * bit 8 -- metadata request
* Used for tracing to differentiate metadata and data IO. May also
* get some preferential treatment in the IO scheduler
- * bit 6 -- discard sectors
+ * bit 9 -- discard sectors
* Informs the lower level device that this range of sectors is no longer
* used by the file system and may thus be freed by the device. Used
* for flash based storage.
- * bit 7 -- fail fast device errors
- * bit 8 -- fail fast transport errors
- * bit 9 -- fail fast driver errors
* Don't want driver retries for any fast fail whatever the reason.
* bit 10 -- Tell the IO scheduler not to wait for more requests after this
one has been submitted, even if it is a SYNC request.
*/
-#define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */
-#define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */
-#define BIO_RW_BARRIER 2
-#define BIO_RW_SYNCIO 3
-#define BIO_RW_UNPLUG 4
-#define BIO_RW_META 5
-#define BIO_RW_DISCARD 6
-#define BIO_RW_FAILFAST_DEV 7
-#define BIO_RW_FAILFAST_TRANSPORT 8
-#define BIO_RW_FAILFAST_DRIVER 9
-#define BIO_RW_NOIDLE 10
-
-#define bio_rw_flagged(bio, flag) ((bio)->bi_rw & (1 << (flag)))
+enum bio_rw_flags {
+ BIO_RW,
+ BIO_RW_FAILFAST_DEV,
+ BIO_RW_FAILFAST_TRANSPORT,
+ BIO_RW_FAILFAST_DRIVER,
+ /* above flags must match REQ_* */
+ BIO_RW_AHEAD,
+ BIO_RW_BARRIER,
+ BIO_RW_SYNCIO,
+ BIO_RW_UNPLUG,
+ BIO_RW_META,
+ BIO_RW_DISCARD,
+ BIO_RW_NOIDLE,
+};
/*
- * Old defines, these should eventually be replaced by direct usage of
- * bio_rw_flagged()
+ * First four bits must match between bio->bi_rw and rq->cmd_flags, make
+ * that explicit here.
*/
-#define bio_barrier(bio) bio_rw_flagged(bio, BIO_RW_BARRIER)
-#define bio_sync(bio) bio_rw_flagged(bio, BIO_RW_SYNCIO)
-#define bio_unplug(bio) bio_rw_flagged(bio, BIO_RW_UNPLUG)
-#define bio_failfast_dev(bio) bio_rw_flagged(bio, BIO_RW_FAILFAST_DEV)
-#define bio_failfast_transport(bio) \
- bio_rw_flagged(bio, BIO_RW_FAILFAST_TRANSPORT)
-#define bio_failfast_driver(bio) \
- bio_rw_flagged(bio, BIO_RW_FAILFAST_DRIVER)
-#define bio_rw_ahead(bio) bio_rw_flagged(bio, BIO_RW_AHEAD)
-#define bio_rw_meta(bio) bio_rw_flagged(bio, BIO_RW_META)
-#define bio_discard(bio) bio_rw_flagged(bio, BIO_RW_DISCARD)
-#define bio_noidle(bio) bio_rw_flagged(bio, BIO_RW_NOIDLE)
+#define BIO_RW_RQ_MASK 0xf
+
+static inline bool bio_rw_flagged(struct bio *bio, enum bio_rw_flags flag)
+{
+ return (bio->bi_rw & (1 << flag)) != 0;
+}
/*
* upper 16 bits of bi_rw define the io priority of this bio
@@ -216,7 +211,7 @@ struct bio {
#define bio_offset(bio) bio_iovec((bio))->bv_offset
#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_idx)
#define bio_sectors(bio) ((bio)->bi_size >> 9)
-#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio))
+#define bio_empty_barrier(bio) (bio_rw_flagged(bio, BIO_RW_BARRIER) && !bio_has_data(bio) && !bio_rw_flagged(bio, BIO_RW_DISCARD))
static inline unsigned int bio_cur_bytes(struct bio *bio)
{
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e7cb5dbf6c26..29ad57c279f3 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -86,13 +86,14 @@ enum {
};
/*
- * request type modified bits. first two bits match BIO_RW* bits, important
+ * request type modified bits. first four bits match BIO_RW* bits, important
*/
enum rq_flag_bits {
__REQ_RW, /* not set, read. set, write */
__REQ_FAILFAST_DEV, /* no driver retries of device errors */
__REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */
__REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */
+ /* above flags must match BIO_RW_* */
__REQ_DISCARD, /* request to discard sectors */
__REQ_SORTED, /* elevator knows about this request */
__REQ_SOFTBARRIER, /* may not be passed by ioscheduler */
@@ -114,6 +115,7 @@ enum rq_flag_bits {
__REQ_INTEGRITY, /* integrity metadata has been remapped */
__REQ_NOIDLE, /* Don't anticipate more IO after this one */
__REQ_IO_STAT, /* account I/O stat */
+ __REQ_MIXED_MERGE, /* merge of different types, fail separately */
__REQ_NR_BITS, /* stops here */
};
@@ -142,6 +144,10 @@ enum rq_flag_bits {
#define REQ_INTEGRITY (1 << __REQ_INTEGRITY)
#define REQ_NOIDLE (1 << __REQ_NOIDLE)
#define REQ_IO_STAT (1 << __REQ_IO_STAT)
+#define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE)
+
+#define REQ_FAILFAST_MASK (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | \
+ REQ_FAILFAST_DRIVER)
#define BLK_MAX_CDB 16
@@ -828,11 +834,13 @@ static inline void blk_run_address_space(struct address_space *mapping)
}
/*
- * blk_rq_pos() : the current sector
- * blk_rq_bytes() : bytes left in the entire request
- * blk_rq_cur_bytes() : bytes left in the current segment
- * blk_rq_sectors() : sectors left in the entire request
- * blk_rq_cur_sectors() : sectors left in the current segment
+ * blk_rq_pos() : the current sector
+ * blk_rq_bytes() : bytes left in the entire request
+ * blk_rq_cur_bytes() : bytes left in the current segment
+ * blk_rq_err_bytes() : bytes left till the next error boundary
+ * blk_rq_sectors() : sectors left in the entire request
+ * blk_rq_cur_sectors() : sectors left in the current segment
+ * blk_rq_err_sectors() : sectors left till the next error boundary
*/
static inline sector_t blk_rq_pos(const struct request *rq)
{
@@ -849,6 +857,8 @@ static inline int blk_rq_cur_bytes(const struct request *rq)
return rq->bio ? bio_cur_bytes(rq->bio) : 0;
}
+extern unsigned int blk_rq_err_bytes(const struct request *rq);
+
static inline unsigned int blk_rq_sectors(const struct request *rq)
{
return blk_rq_bytes(rq) >> 9;
@@ -859,6 +869,11 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
return blk_rq_cur_bytes(rq) >> 9;
}
+static inline unsigned int blk_rq_err_sectors(const struct request *rq)
+{
+ return blk_rq_err_bytes(rq) >> 9;
+}
+
/*
* Request issue related functions.
*/
@@ -885,10 +900,12 @@ extern bool blk_end_request(struct request *rq, int error,
unsigned int nr_bytes);
extern void blk_end_request_all(struct request *rq, int error);
extern bool blk_end_request_cur(struct request *rq, int error);
+extern bool blk_end_request_err(struct request *rq, int error);
extern bool __blk_end_request(struct request *rq, int error,
unsigned int nr_bytes);
extern void __blk_end_request_all(struct request *rq, int error);
extern bool __blk_end_request_cur(struct request *rq, int error);
+extern bool __blk_end_request_err(struct request *rq, int error);
extern void blk_complete_request(struct request *);
extern void __blk_complete_request(struct request *);
@@ -913,6 +930,7 @@ extern void blk_queue_logical_block_size(struct request_queue *, unsigned short)
extern void blk_queue_physical_block_size(struct request_queue *, unsigned short);
extern void blk_queue_alignment_offset(struct request_queue *q,
unsigned int alignment);
+extern void blk_limits_io_min(struct queue_limits *limits, unsigned int min);
extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
extern void blk_set_default_limits(struct queue_limits *lim);
@@ -920,7 +938,6 @@ extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
sector_t offset);
extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
sector_t offset);
-extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b);
extern void blk_queue_dma_pad(struct request_queue *, unsigned int);
extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int);
extern int blk_queue_dma_drain(struct request_queue *q,
diff --git a/include/linux/capability.h b/include/linux/capability.h
index c3021105edc0..c8f2a5f70ed5 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -7,7 +7,7 @@
*
* See here for the libcap library ("POSIX draft" compliance):
*
- * ftp://linux.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/
+ * ftp://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/
*/
#ifndef _LINUX_CAPABILITY_H
diff --git a/include/linux/cb710.h b/include/linux/cb710.h
index 63bc9a4d2926..8cc10411bab2 100644
--- a/include/linux/cb710.h
+++ b/include/linux/cb710.h
@@ -140,29 +140,6 @@ void cb710_dump_regs(struct cb710_chip *chip, unsigned dump);
#include <linux/highmem.h>
#include <linux/scatterlist.h>
-/**
- * cb710_sg_miter_stop_writing - stop mapping iteration after writing
- * @miter: sg mapping iter to be stopped
- *
- * Description:
- * Stops mapping iterator @miter. @miter should have been started
- * started using sg_miter_start(). A stopped iteration can be
- * resumed by calling sg_miter_next() on it. This is useful when
- * resources (kmap) need to be released during iteration.
- *
- * This is a convenience wrapper that will be optimized out for arches
- * that don't need flush_kernel_dcache_page().
- *
- * Context:
- * IRQ disabled if the SG_MITER_ATOMIC is set. Don't care otherwise.
- */
-static inline void cb710_sg_miter_stop_writing(struct sg_mapping_iter *miter)
-{
- if (miter->page)
- flush_kernel_dcache_page(miter->page);
- sg_miter_stop(miter);
-}
-
/*
* 32-bit PIO mapping sg iterator
*
@@ -171,12 +148,12 @@ static inline void cb710_sg_miter_stop_writing(struct sg_mapping_iter *miter)
* without DMA support).
*
* Best-case reading (transfer from device):
- * sg_miter_start();
+ * sg_miter_start(, SG_MITER_TO_SG);
* cb710_sg_dwiter_write_from_io();
- * cb710_sg_miter_stop_writing();
+ * sg_miter_stop();
*
* Best-case writing (transfer to device):
- * sg_miter_start();
+ * sg_miter_start(, SG_MITER_FROM_SG);
* cb710_sg_dwiter_read_to_io();
* sg_miter_stop();
*/
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 665fa70e4094..90bba9e62286 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -179,14 +179,11 @@ struct cgroup {
*/
struct list_head release_list;
- /* pids_mutex protects the fields below */
+ /* pids_mutex protects pids_list and cached pid arrays. */
struct rw_semaphore pids_mutex;
- /* Array of process ids in the cgroup */
- pid_t *tasks_pids;
- /* How many files are using the current tasks_pids array */
- int pids_use_count;
- /* Length of the current tasks_pids array */
- int pids_length;
+
+ /* Linked list of struct cgroup_pids */
+ struct list_head pids_list;
/* For RCU-protected deletion */
struct rcu_head rcu_head;
@@ -366,6 +363,23 @@ int cgroup_task_count(const struct cgroup *cgrp);
int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
/*
+ * When the subsys has to access css and may add permanent refcnt to css,
+ * it should take care of racy conditions with rmdir(). Following set of
+ * functions, is for stop/restart rmdir if necessary.
+ * Because these will call css_get/put, "css" should be alive css.
+ *
+ * cgroup_exclude_rmdir();
+ * ...do some jobs which may access arbitrary empty cgroup
+ * cgroup_release_and_wakeup_rmdir();
+ *
+ * When someone removes a cgroup while cgroup_exclude_rmdir() holds it,
+ * it sleeps and cgroup_release_and_wakeup_rmdir() will wake him up.
+ */
+
+void cgroup_exclude_rmdir(struct cgroup_subsys_state *css);
+void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css);
+
+/*
* Control Group subsystem type.
* See Documentation/cgroups/cgroups.txt for details
*/
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index c56457c8334e..1219be4fb42e 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -293,7 +293,12 @@ static inline int clocksource_enable(struct clocksource *cs)
if (cs->enable)
ret = cs->enable(cs);
- /* save mult_orig on enable */
+ /*
+ * The frequency may have changed while the clocksource
+ * was disabled. If so the code in ->enable() must update
+ * the mult value to reflect the new frequency. Make sure
+ * mult_orig follows this change.
+ */
cs->mult_orig = cs->mult;
return ret;
@@ -309,6 +314,13 @@ static inline int clocksource_enable(struct clocksource *cs)
*/
static inline void clocksource_disable(struct clocksource *cs)
{
+ /*
+ * Save mult_orig in mult so clocksource_enable() can
+ * restore the value regardless if ->enable() updates
+ * the value of mult or not.
+ */
+ cs->mult = cs->mult_orig;
+
if (cs->disable)
cs->disable(cs);
}
diff --git a/include/linux/connector.h b/include/linux/connector.h
index b68d27850d51..47ebf416f512 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -136,7 +136,7 @@ struct cn_callback_data {
void *ddata;
void *callback_priv;
- void (*callback) (void *);
+ void (*callback) (struct cn_msg *);
void *free;
};
@@ -167,11 +167,11 @@ struct cn_dev {
struct cn_queue_dev *cbdev;
};
-int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));
+int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *));
void cn_del_callback(struct cb_id *);
int cn_netlink_send(struct cn_msg *, u32, gfp_t);
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *));
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *));
void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work);
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index c5ac87ca7bc6..5b44e9fe510d 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -3,444 +3,37 @@
/*
* Cpumasks provide a bitmap suitable for representing the
- * set of CPU's in a system, one bit position per CPU number.
- *
- * The new cpumask_ ops take a "struct cpumask *"; the old ones
- * use cpumask_t.
- *
- * See detailed comments in the file linux/bitmap.h describing the
- * data type on which these cpumasks are based.
- *
- * For details of cpumask_scnprintf() and cpumask_parse_user(),
- * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
- * For details of cpulist_scnprintf() and cpulist_parse(), see
- * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
- * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
- * For details of cpus_remap(), see bitmap_remap in lib/bitmap.c.
- * For details of cpus_onto(), see bitmap_onto in lib/bitmap.c.
- * For details of cpus_fold(), see bitmap_fold in lib/bitmap.c.
- *
- * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- * Note: The alternate operations with the suffix "_nr" are used
- * to limit the range of the loop to nr_cpu_ids instead of
- * NR_CPUS when NR_CPUS > 64 for performance reasons.
- * If NR_CPUS is <= 64 then most assembler bitmask
- * operators execute faster with a constant range, so
- * the operator will continue to use NR_CPUS.
- *
- * Another consideration is that nr_cpu_ids is initialized
- * to NR_CPUS and isn't lowered until the possible cpus are
- * discovered (including any disabled cpus). So early uses
- * will span the entire range of NR_CPUS.
- * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- *
- * The obsolescent cpumask operations are:
- *
- * void cpu_set(cpu, mask) turn on bit 'cpu' in mask
- * void cpu_clear(cpu, mask) turn off bit 'cpu' in mask
- * void cpus_setall(mask) set all bits
- * void cpus_clear(mask) clear all bits
- * int cpu_isset(cpu, mask) true iff bit 'cpu' set in mask
- * int cpu_test_and_set(cpu, mask) test and set bit 'cpu' in mask
- *
- * void cpus_and(dst, src1, src2) dst = src1 & src2 [intersection]
- * void cpus_or(dst, src1, src2) dst = src1 | src2 [union]
- * void cpus_xor(dst, src1, src2) dst = src1 ^ src2
- * void cpus_andnot(dst, src1, src2) dst = src1 & ~src2
- * void cpus_complement(dst, src) dst = ~src
- *
- * int cpus_equal(mask1, mask2) Does mask1 == mask2?
- * int cpus_intersects(mask1, mask2) Do mask1 and mask2 intersect?
- * int cpus_subset(mask1, mask2) Is mask1 a subset of mask2?
- * int cpus_empty(mask) Is mask empty (no bits sets)?
- * int cpus_full(mask) Is mask full (all bits sets)?
- * int cpus_weight(mask) Hamming weigh - number of set bits
- * int cpus_weight_nr(mask) Same using nr_cpu_ids instead of NR_CPUS
- *
- * void cpus_shift_right(dst, src, n) Shift right
- * void cpus_shift_left(dst, src, n) Shift left
- *
- * int first_cpu(mask) Number lowest set bit, or NR_CPUS
- * int next_cpu(cpu, mask) Next cpu past 'cpu', or NR_CPUS
- * int next_cpu_nr(cpu, mask) Next cpu past 'cpu', or nr_cpu_ids
- *
- * cpumask_t cpumask_of_cpu(cpu) Return cpumask with bit 'cpu' set
- * (can be used as an lvalue)
- * CPU_MASK_ALL Initializer - all bits set
- * CPU_MASK_NONE Initializer - no bits set
- * unsigned long *cpus_addr(mask) Array of unsigned long's in mask
- *
- * CPUMASK_ALLOC kmalloc's a structure that is a composite of many cpumask_t
- * variables, and CPUMASK_PTR provides pointers to each field.
- *
- * The structure should be defined something like this:
- * struct my_cpumasks {
- * cpumask_t mask1;
- * cpumask_t mask2;
- * };
- *
- * Usage is then:
- * CPUMASK_ALLOC(my_cpumasks);
- * CPUMASK_PTR(mask1, my_cpumasks);
- * CPUMASK_PTR(mask2, my_cpumasks);
- *
- * --- DO NOT reference cpumask_t pointers until this check ---
- * if (my_cpumasks == NULL)
- * "kmalloc failed"...
- *
- * References are now pointers to the cpumask_t variables (*mask1, ...)
- *
- *if NR_CPUS > BITS_PER_LONG
- * CPUMASK_ALLOC(m) Declares and allocates struct m *m =
- * kmalloc(sizeof(*m), GFP_KERNEL)
- * CPUMASK_FREE(m) Macro for kfree(m)
- *else
- * CPUMASK_ALLOC(m) Declares struct m _m, *m = &_m
- * CPUMASK_FREE(m) Nop
- *endif
- * CPUMASK_PTR(v, m) Declares cpumask_t *v = &(m->v)
- * ------------------------------------------------------------------------
- *
- * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
- * int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask
- * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
- * int cpulist_parse(buf, map) Parse ascii string as cpulist
- * int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
- * void cpus_remap(dst, src, old, new) *dst = map(old, new)(src)
- * void cpus_onto(dst, orig, relmap) *dst = orig relative to relmap
- * void cpus_fold(dst, orig, sz) dst bits = orig bits mod sz
- *
- * for_each_cpu_mask(cpu, mask) for-loop cpu over mask using NR_CPUS
- * for_each_cpu_mask_nr(cpu, mask) for-loop cpu over mask using nr_cpu_ids
- *
- * int num_online_cpus() Number of online CPUs
- * int num_possible_cpus() Number of all possible CPUs
- * int num_present_cpus() Number of present CPUs
- *
- * int cpu_online(cpu) Is some cpu online?
- * int cpu_possible(cpu) Is some cpu possible?
- * int cpu_present(cpu) Is some cpu present (can schedule)?
- *
- * int any_online_cpu(mask) First online cpu in mask
- *
- * for_each_possible_cpu(cpu) for-loop cpu over cpu_possible_map
- * for_each_online_cpu(cpu) for-loop cpu over cpu_online_map
- * for_each_present_cpu(cpu) for-loop cpu over cpu_present_map
- *
- * Subtlety:
- * 1) The 'type-checked' form of cpu_isset() causes gcc (3.3.2, anyway)
- * to generate slightly worse code. Note for example the additional
- * 40 lines of assembly code compiling the "for each possible cpu"
- * loops buried in the disk_stat_read() macros calls when compiling
- * drivers/block/genhd.c (arch i386, CONFIG_SMP=y). So use a simple
- * one-line #define for cpu_isset(), instead of wrapping an inline
- * inside a macro, the way we do the other calls.
+ * set of CPU's in a system, one bit position per CPU number. In general,
+ * only nr_cpu_ids (<= NR_CPUS) bits are valid.
*/
-
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/bitmap.h>
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
-extern cpumask_t _unused_cpumask_arg_;
-
-#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-#define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
-static inline void __cpu_set(int cpu, volatile cpumask_t *dstp)
-{
- set_bit(cpu, dstp->bits);
-}
-
-#define cpu_clear(cpu, dst) __cpu_clear((cpu), &(dst))
-static inline void __cpu_clear(int cpu, volatile cpumask_t *dstp)
-{
- clear_bit(cpu, dstp->bits);
-}
-
-#define cpus_setall(dst) __cpus_setall(&(dst), NR_CPUS)
-static inline void __cpus_setall(cpumask_t *dstp, int nbits)
-{
- bitmap_fill(dstp->bits, nbits);
-}
-
-#define cpus_clear(dst) __cpus_clear(&(dst), NR_CPUS)
-static inline void __cpus_clear(cpumask_t *dstp, int nbits)
-{
- bitmap_zero(dstp->bits, nbits);
-}
-
-/* No static inline type checking - see Subtlety (1) above. */
-#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits)
-
-#define cpu_test_and_set(cpu, cpumask) __cpu_test_and_set((cpu), &(cpumask))
-static inline int __cpu_test_and_set(int cpu, cpumask_t *addr)
-{
- return test_and_set_bit(cpu, addr->bits);
-}
-
-#define cpus_and(dst, src1, src2) __cpus_and(&(dst), &(src1), &(src2), NR_CPUS)
-static inline void __cpus_and(cpumask_t *dstp, const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_or(dst, src1, src2) __cpus_or(&(dst), &(src1), &(src2), NR_CPUS)
-static inline void __cpus_or(cpumask_t *dstp, const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_xor(dst, src1, src2) __cpus_xor(&(dst), &(src1), &(src2), NR_CPUS)
-static inline void __cpus_xor(cpumask_t *dstp, const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_andnot(dst, src1, src2) \
- __cpus_andnot(&(dst), &(src1), &(src2), NR_CPUS)
-static inline void __cpus_andnot(cpumask_t *dstp, const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_complement(dst, src) __cpus_complement(&(dst), &(src), NR_CPUS)
-static inline void __cpus_complement(cpumask_t *dstp,
- const cpumask_t *srcp, int nbits)
-{
- bitmap_complement(dstp->bits, srcp->bits, nbits);
-}
-
-#define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS)
-static inline int __cpus_equal(const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- return bitmap_equal(src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_intersects(src1, src2) __cpus_intersects(&(src1), &(src2), NR_CPUS)
-static inline int __cpus_intersects(const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- return bitmap_intersects(src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_subset(src1, src2) __cpus_subset(&(src1), &(src2), NR_CPUS)
-static inline int __cpus_subset(const cpumask_t *src1p,
- const cpumask_t *src2p, int nbits)
-{
- return bitmap_subset(src1p->bits, src2p->bits, nbits);
-}
-
-#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS)
-static inline int __cpus_empty(const cpumask_t *srcp, int nbits)
-{
- return bitmap_empty(srcp->bits, nbits);
-}
-
-#define cpus_full(cpumask) __cpus_full(&(cpumask), NR_CPUS)
-static inline int __cpus_full(const cpumask_t *srcp, int nbits)
-{
- return bitmap_full(srcp->bits, nbits);
-}
-
-#define cpus_weight(cpumask) __cpus_weight(&(cpumask), NR_CPUS)
-static inline int __cpus_weight(const cpumask_t *srcp, int nbits)
-{
- return bitmap_weight(srcp->bits, nbits);
-}
-
-#define cpus_shift_right(dst, src, n) \
- __cpus_shift_right(&(dst), &(src), (n), NR_CPUS)
-static inline void __cpus_shift_right(cpumask_t *dstp,
- const cpumask_t *srcp, int n, int nbits)
-{
- bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
-}
-
-#define cpus_shift_left(dst, src, n) \
- __cpus_shift_left(&(dst), &(src), (n), NR_CPUS)
-static inline void __cpus_shift_left(cpumask_t *dstp,
- const cpumask_t *srcp, int n, int nbits)
-{
- bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
-}
-#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
/**
- * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
- * @bitmap: the bitmap
- *
- * There are a few places where cpumask_var_t isn't appropriate and
- * static cpumasks must be used (eg. very early boot), yet we don't
- * expose the definition of 'struct cpumask'.
- *
- * This does the conversion, and can be used as a constant initializer.
- */
-#define to_cpumask(bitmap) \
- ((struct cpumask *)(1 ? (bitmap) \
- : (void *)sizeof(__check_is_bitmap(bitmap))))
-
-static inline int __check_is_bitmap(const unsigned long *bitmap)
-{
- return 1;
-}
-
-/*
- * Special-case data structure for "single bit set only" constant CPU masks.
+ * cpumask_bits - get the bits in a cpumask
+ * @maskp: the struct cpumask *
*
- * We pre-generate all the 64 (or 32) possible bit positions, with enough
- * padding to the left and the right, and return the constant pointer
- * appropriately offset.
- */
-extern const unsigned long
- cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)];
-
-static inline const struct cpumask *get_cpu_mask(unsigned int cpu)
-{
- const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG];
- p -= cpu / BITS_PER_LONG;
- return to_cpumask(p);
-}
-
-#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-/*
- * In cases where we take the address of the cpumask immediately,
- * gcc optimizes it out (it's a constant) and there's no huge stack
- * variable created:
+ * You should only assume nr_cpu_ids bits of this mask are valid. This is
+ * a macro so it's const-correct.
*/
-#define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu))
-
-
-#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
-
-#if NR_CPUS <= BITS_PER_LONG
-
-#define CPU_MASK_ALL \
-(cpumask_t) { { \
- [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
-} }
-
-#define CPU_MASK_ALL_PTR (&CPU_MASK_ALL)
-
-#else
-
-#define CPU_MASK_ALL \
-(cpumask_t) { { \
- [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
- [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
-} }
-
-/* cpu_mask_all is in init/main.c */
-extern cpumask_t cpu_mask_all;
-#define CPU_MASK_ALL_PTR (&cpu_mask_all)
-
-#endif
-
-#define CPU_MASK_NONE \
-(cpumask_t) { { \
- [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
-} }
-
-#define CPU_MASK_CPU0 \
-(cpumask_t) { { \
- [0] = 1UL \
-} }
-
-#define cpus_addr(src) ((src).bits)
-
-#if NR_CPUS > BITS_PER_LONG
-#define CPUMASK_ALLOC(m) struct m *m = kmalloc(sizeof(*m), GFP_KERNEL)
-#define CPUMASK_FREE(m) kfree(m)
-#else
-#define CPUMASK_ALLOC(m) struct m _m, *m = &_m
-#define CPUMASK_FREE(m)
-#endif
-#define CPUMASK_PTR(v, m) cpumask_t *v = &(m->v)
-
-#define cpu_remap(oldbit, old, new) \
- __cpu_remap((oldbit), &(old), &(new), NR_CPUS)
-static inline int __cpu_remap(int oldbit,
- const cpumask_t *oldp, const cpumask_t *newp, int nbits)
-{
- return bitmap_bitremap(oldbit, oldp->bits, newp->bits, nbits);
-}
-
-#define cpus_remap(dst, src, old, new) \
- __cpus_remap(&(dst), &(src), &(old), &(new), NR_CPUS)
-static inline void __cpus_remap(cpumask_t *dstp, const cpumask_t *srcp,
- const cpumask_t *oldp, const cpumask_t *newp, int nbits)
-{
- bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits);
-}
-
-#define cpus_onto(dst, orig, relmap) \
- __cpus_onto(&(dst), &(orig), &(relmap), NR_CPUS)
-static inline void __cpus_onto(cpumask_t *dstp, const cpumask_t *origp,
- const cpumask_t *relmapp, int nbits)
-{
- bitmap_onto(dstp->bits, origp->bits, relmapp->bits, nbits);
-}
-
-#define cpus_fold(dst, orig, sz) \
- __cpus_fold(&(dst), &(orig), sz, NR_CPUS)
-static inline void __cpus_fold(cpumask_t *dstp, const cpumask_t *origp,
- int sz, int nbits)
-{
- bitmap_fold(dstp->bits, origp->bits, sz, nbits);
-}
-#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
+#define cpumask_bits(maskp) ((maskp)->bits)
#if NR_CPUS == 1
-
#define nr_cpu_ids 1
-#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-#define first_cpu(src) ({ (void)(src); 0; })
-#define next_cpu(n, src) ({ (void)(src); 1; })
-#define any_online_cpu(mask) 0
-#define for_each_cpu_mask(cpu, mask) \
- for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
-#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
-#else /* NR_CPUS > 1 */
-
+#else
extern int nr_cpu_ids;
-#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-int __first_cpu(const cpumask_t *srcp);
-int __next_cpu(int n, const cpumask_t *srcp);
-int __any_online_cpu(const cpumask_t *mask);
-
-#define first_cpu(src) __first_cpu(&(src))
-#define next_cpu(n, src) __next_cpu((n), &(src))
-#define any_online_cpu(mask) __any_online_cpu(&(mask))
-#define for_each_cpu_mask(cpu, mask) \
- for ((cpu) = -1; \
- (cpu) = next_cpu((cpu), (mask)), \
- (cpu) < NR_CPUS; )
-#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
#endif
-#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-#if NR_CPUS <= 64
-
-#define next_cpu_nr(n, src) next_cpu(n, src)
-#define cpus_weight_nr(cpumask) cpus_weight(cpumask)
-#define for_each_cpu_mask_nr(cpu, mask) for_each_cpu_mask(cpu, mask)
-
-#else /* NR_CPUS > 64 */
-
-int __next_cpu_nr(int n, const cpumask_t *srcp);
-#define next_cpu_nr(n, src) __next_cpu_nr((n), &(src))
-#define cpus_weight_nr(cpumask) __cpus_weight(&(cpumask), nr_cpu_ids)
-#define for_each_cpu_mask_nr(cpu, mask) \
- for ((cpu) = -1; \
- (cpu) = next_cpu_nr((cpu), (mask)), \
- (cpu) < nr_cpu_ids; )
-
-#endif /* NR_CPUS > 64 */
-#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
+#ifdef CONFIG_CPUMASK_OFFSTACK
+/* Assuming NR_CPUS is huge, a runtime limit is more efficient. Also,
+ * not all bits may be allocated. */
+#define nr_cpumask_bits nr_cpu_ids
+#else
+#define nr_cpumask_bits NR_CPUS
+#endif
/*
* The following particular system cpumasks and operations manage
@@ -487,12 +80,6 @@ extern const struct cpumask *const cpu_online_mask;
extern const struct cpumask *const cpu_present_mask;
extern const struct cpumask *const cpu_active_mask;
-/* These strip const, as traditionally they weren't const. */
-#define cpu_possible_map (*(cpumask_t *)cpu_possible_mask)
-#define cpu_online_map (*(cpumask_t *)cpu_online_mask)
-#define cpu_present_map (*(cpumask_t *)cpu_present_mask)
-#define cpu_active_map (*(cpumask_t *)cpu_active_mask)
-
#if NR_CPUS > 1
#define num_online_cpus() cpumask_weight(cpu_online_mask)
#define num_possible_cpus() cpumask_weight(cpu_possible_mask)
@@ -511,35 +98,6 @@ extern const struct cpumask *const cpu_active_mask;
#define cpu_active(cpu) ((cpu) == 0)
#endif
-#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
-
-/* These are the new versions of the cpumask operators: passed by pointer.
- * The older versions will be implemented in terms of these, then deleted. */
-#define cpumask_bits(maskp) ((maskp)->bits)
-
-#if NR_CPUS <= BITS_PER_LONG
-#define CPU_BITS_ALL \
-{ \
- [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
-}
-
-#else /* NR_CPUS > BITS_PER_LONG */
-
-#define CPU_BITS_ALL \
-{ \
- [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
- [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
-}
-#endif /* NR_CPUS > BITS_PER_LONG */
-
-#ifdef CONFIG_CPUMASK_OFFSTACK
-/* Assuming NR_CPUS is huge, a runtime limit is more efficient. Also,
- * not all bits may be allocated. */
-#define nr_cpumask_bits nr_cpu_ids
-#else
-#define nr_cpumask_bits NR_CPUS
-#endif
-
/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
@@ -1088,4 +646,241 @@ void set_cpu_active(unsigned int cpu, bool active);
void init_cpu_present(const struct cpumask *src);
void init_cpu_possible(const struct cpumask *src);
void init_cpu_online(const struct cpumask *src);
+
+/**
+ * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
+ * @bitmap: the bitmap
+ *
+ * There are a few places where cpumask_var_t isn't appropriate and
+ * static cpumasks must be used (eg. very early boot), yet we don't
+ * expose the definition of 'struct cpumask'.
+ *
+ * This does the conversion, and can be used as a constant initializer.
+ */
+#define to_cpumask(bitmap) \
+ ((struct cpumask *)(1 ? (bitmap) \
+ : (void *)sizeof(__check_is_bitmap(bitmap))))
+
+static inline int __check_is_bitmap(const unsigned long *bitmap)
+{
+ return 1;
+}
+
+/*
+ * Special-case data structure for "single bit set only" constant CPU masks.
+ *
+ * We pre-generate all the 64 (or 32) possible bit positions, with enough
+ * padding to the left and the right, and return the constant pointer
+ * appropriately offset.
+ */
+extern const unsigned long
+ cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)];
+
+static inline const struct cpumask *get_cpu_mask(unsigned int cpu)
+{
+ const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG];
+ p -= cpu / BITS_PER_LONG;
+ return to_cpumask(p);
+}
+
+#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
+
+#if NR_CPUS <= BITS_PER_LONG
+#define CPU_BITS_ALL \
+{ \
+ [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
+}
+
+#else /* NR_CPUS > BITS_PER_LONG */
+
+#define CPU_BITS_ALL \
+{ \
+ [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
+ [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
+}
+#endif /* NR_CPUS > BITS_PER_LONG */
+
+/*
+ *
+ * From here down, all obsolete. Use cpumask_ variants!
+ *
+ */
+#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
+/* These strip const, as traditionally they weren't const. */
+#define cpu_possible_map (*(cpumask_t *)cpu_possible_mask)
+#define cpu_online_map (*(cpumask_t *)cpu_online_mask)
+#define cpu_present_map (*(cpumask_t *)cpu_present_mask)
+#define cpu_active_map (*(cpumask_t *)cpu_active_mask)
+
+#define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu))
+
+#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
+
+#if NR_CPUS <= BITS_PER_LONG
+
+#define CPU_MASK_ALL \
+(cpumask_t) { { \
+ [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
+} }
+
+#else
+
+#define CPU_MASK_ALL \
+(cpumask_t) { { \
+ [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
+ [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
+} }
+
+#endif
+
+#define CPU_MASK_NONE \
+(cpumask_t) { { \
+ [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
+} }
+
+#define CPU_MASK_CPU0 \
+(cpumask_t) { { \
+ [0] = 1UL \
+} }
+
+#if NR_CPUS == 1
+#define first_cpu(src) ({ (void)(src); 0; })
+#define next_cpu(n, src) ({ (void)(src); 1; })
+#define any_online_cpu(mask) 0
+#define for_each_cpu_mask(cpu, mask) \
+ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
+#else /* NR_CPUS > 1 */
+int __first_cpu(const cpumask_t *srcp);
+int __next_cpu(int n, const cpumask_t *srcp);
+int __any_online_cpu(const cpumask_t *mask);
+
+#define first_cpu(src) __first_cpu(&(src))
+#define next_cpu(n, src) __next_cpu((n), &(src))
+#define any_online_cpu(mask) __any_online_cpu(&(mask))
+#define for_each_cpu_mask(cpu, mask) \
+ for ((cpu) = -1; \
+ (cpu) = next_cpu((cpu), (mask)), \
+ (cpu) < NR_CPUS; )
+#endif /* SMP */
+
+#if NR_CPUS <= 64
+
+#define for_each_cpu_mask_nr(cpu, mask) for_each_cpu_mask(cpu, mask)
+
+#else /* NR_CPUS > 64 */
+
+int __next_cpu_nr(int n, const cpumask_t *srcp);
+#define for_each_cpu_mask_nr(cpu, mask) \
+ for ((cpu) = -1; \
+ (cpu) = __next_cpu_nr((cpu), &(mask)), \
+ (cpu) < nr_cpu_ids; )
+
+#endif /* NR_CPUS > 64 */
+
+#define cpus_addr(src) ((src).bits)
+
+#define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
+static inline void __cpu_set(int cpu, volatile cpumask_t *dstp)
+{
+ set_bit(cpu, dstp->bits);
+}
+
+#define cpu_clear(cpu, dst) __cpu_clear((cpu), &(dst))
+static inline void __cpu_clear(int cpu, volatile cpumask_t *dstp)
+{
+ clear_bit(cpu, dstp->bits);
+}
+
+#define cpus_setall(dst) __cpus_setall(&(dst), NR_CPUS)
+static inline void __cpus_setall(cpumask_t *dstp, int nbits)
+{
+ bitmap_fill(dstp->bits, nbits);
+}
+
+#define cpus_clear(dst) __cpus_clear(&(dst), NR_CPUS)
+static inline void __cpus_clear(cpumask_t *dstp, int nbits)
+{
+ bitmap_zero(dstp->bits, nbits);
+}
+
+/* No static inline type checking - see Subtlety (1) above. */
+#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits)
+
+#define cpu_test_and_set(cpu, cpumask) __cpu_test_and_set((cpu), &(cpumask))
+static inline int __cpu_test_and_set(int cpu, cpumask_t *addr)
+{
+ return test_and_set_bit(cpu, addr->bits);
+}
+
+#define cpus_and(dst, src1, src2) __cpus_and(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_and(cpumask_t *dstp, const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_or(dst, src1, src2) __cpus_or(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_or(cpumask_t *dstp, const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_xor(dst, src1, src2) __cpus_xor(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_xor(cpumask_t *dstp, const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_andnot(dst, src1, src2) \
+ __cpus_andnot(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_andnot(cpumask_t *dstp, const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_equal(const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ return bitmap_equal(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_intersects(src1, src2) __cpus_intersects(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_intersects(const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ return bitmap_intersects(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_subset(src1, src2) __cpus_subset(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_subset(const cpumask_t *src1p,
+ const cpumask_t *src2p, int nbits)
+{
+ return bitmap_subset(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS)
+static inline int __cpus_empty(const cpumask_t *srcp, int nbits)
+{
+ return bitmap_empty(srcp->bits, nbits);
+}
+
+#define cpus_weight(cpumask) __cpus_weight(&(cpumask), NR_CPUS)
+static inline int __cpus_weight(const cpumask_t *srcp, int nbits)
+{
+ return bitmap_weight(srcp->bits, nbits);
+}
+
+#define cpus_shift_left(dst, src, n) \
+ __cpus_shift_left(&(dst), &(src), (n), NR_CPUS)
+static inline void __cpus_shift_left(cpumask_t *dstp,
+ const cpumask_t *srcp, int n, int nbits)
+{
+ bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
+}
+#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */
+
#endif /* __LINUX_CPUMASK_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index ec29fa268b94..fd929889e8dc 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -115,7 +115,6 @@ struct crypto_async_request;
struct crypto_aead;
struct crypto_blkcipher;
struct crypto_hash;
-struct crypto_ahash;
struct crypto_rng;
struct crypto_tfm;
struct crypto_type;
@@ -146,16 +145,6 @@ struct ablkcipher_request {
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
-struct ahash_request {
- struct crypto_async_request base;
-
- unsigned int nbytes;
- struct scatterlist *src;
- u8 *result;
-
- void *__ctx[] CRYPTO_MINALIGN_ATTR;
-};
-
/**
* struct aead_request - AEAD request
* @base: Common attributes for async crypto requests
@@ -220,18 +209,6 @@ struct ablkcipher_alg {
unsigned int ivsize;
};
-struct ahash_alg {
- int (*init)(struct ahash_request *req);
- int (*reinit)(struct ahash_request *req);
- int (*update)(struct ahash_request *req);
- int (*final)(struct ahash_request *req);
- int (*digest)(struct ahash_request *req);
- int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
- unsigned int keylen);
-
- unsigned int digestsize;
-};
-
struct aead_alg {
int (*setkey)(struct crypto_aead *tfm, const u8 *key,
unsigned int keylen);
@@ -318,7 +295,6 @@ struct rng_alg {
#define cra_cipher cra_u.cipher
#define cra_digest cra_u.digest
#define cra_hash cra_u.hash
-#define cra_ahash cra_u.ahash
#define cra_compress cra_u.compress
#define cra_rng cra_u.rng
@@ -346,7 +322,6 @@ struct crypto_alg {
struct cipher_alg cipher;
struct digest_alg digest;
struct hash_alg hash;
- struct ahash_alg ahash;
struct compress_alg compress;
struct rng_alg rng;
} cra_u;
@@ -433,18 +408,6 @@ struct hash_tfm {
unsigned int digestsize;
};
-struct ahash_tfm {
- int (*init)(struct ahash_request *req);
- int (*update)(struct ahash_request *req);
- int (*final)(struct ahash_request *req);
- int (*digest)(struct ahash_request *req);
- int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
- unsigned int keylen);
-
- unsigned int digestsize;
- unsigned int reqsize;
-};
-
struct compress_tfm {
int (*cot_compress)(struct crypto_tfm *tfm,
const u8 *src, unsigned int slen,
@@ -465,7 +428,6 @@ struct rng_tfm {
#define crt_blkcipher crt_u.blkcipher
#define crt_cipher crt_u.cipher
#define crt_hash crt_u.hash
-#define crt_ahash crt_u.ahash
#define crt_compress crt_u.compress
#define crt_rng crt_u.rng
@@ -479,7 +441,6 @@ struct crypto_tfm {
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
- struct ahash_tfm ahash;
struct compress_tfm compress;
struct rng_tfm rng;
} crt_u;
@@ -770,7 +731,7 @@ static inline struct ablkcipher_request *ablkcipher_request_alloc(
static inline void ablkcipher_request_free(struct ablkcipher_request *req)
{
- kfree(req);
+ kzfree(req);
}
static inline void ablkcipher_request_set_callback(
@@ -901,7 +862,7 @@ static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
static inline void aead_request_free(struct aead_request *req)
{
- kfree(req);
+ kzfree(req);
}
static inline void aead_request_set_callback(struct aead_request *req,
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 0d6310657f32..655e7721580a 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -84,7 +84,7 @@ typedef int (*dm_merge_fn) (struct dm_target *ti, struct bvec_merge_data *bvm,
typedef int (*iterate_devices_callout_fn) (struct dm_target *ti,
struct dm_dev *dev,
- sector_t physical_start,
+ sector_t start, sector_t len,
void *data);
typedef int (*dm_iterate_devices_fn) (struct dm_target *ti,
@@ -104,7 +104,7 @@ void dm_error(const char *message);
* Combine device limits.
*/
int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
- sector_t start, void *data);
+ sector_t start, sector_t len, void *data);
struct dm_dev {
struct block_device *bdev;
diff --git a/include/linux/device.h b/include/linux/device.h
index aebb81036db2..a28642975053 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -62,7 +62,7 @@ struct bus_type {
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
- struct dev_pm_ops *pm;
+ const struct dev_pm_ops *pm;
struct bus_type_private *p;
};
@@ -132,7 +132,7 @@ struct device_driver {
int (*resume) (struct device *dev);
struct attribute_group **groups;
- struct dev_pm_ops *pm;
+ const struct dev_pm_ops *pm;
struct driver_private *p;
};
@@ -200,7 +200,8 @@ struct class {
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
- struct dev_pm_ops *pm;
+ const struct dev_pm_ops *pm;
+
struct class_private *p;
};
@@ -291,7 +292,7 @@ struct device_type {
char *(*nodename)(struct device *dev);
void (*release)(struct device *dev);
- struct dev_pm_ops *pm;
+ const struct dev_pm_ops *pm;
};
/* interface for exporting device attributes */
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
new file mode 100644
index 000000000000..3a25433a809e
--- /dev/null
+++ b/include/linux/drbd.h
@@ -0,0 +1,349 @@
+/*
+ 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.2"
+#define API_VERSION 88
+#define PRO_VERSION_MIN 86
+#define PRO_VERSION_MAX 90
+
+
+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 */
+
+ /* 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/dvb/dmx.h b/include/linux/dvb/dmx.h
index fef943738a24..f078f3ac82d4 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -151,5 +151,7 @@ struct dmx_stc {
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
+#define DMX_ADD_PID _IOW('o', 51, __u16)
+#define DMX_REMOVE_PID _IOW('o', 52, __u16)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 9b660bd2e2b3..90c4a3616d94 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -368,6 +368,7 @@ struct net_device;
/* Some generic methods drivers may use in their ethtool_ops */
u32 ethtool_op_get_link(struct net_device *dev);
+u32 ethtool_op_get_rx_csum(struct net_device *dev);
u32 ethtool_op_get_tx_csum(struct net_device *dev);
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 634a5e5aba3e..7499b3667798 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -874,7 +874,7 @@ struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
- int create, int extend_disksize);
+ int create);
extern struct inode *ext3_iget(struct super_block *, unsigned long);
extern int ext3_write_inode (struct inode *, int);
diff --git a/include/linux/fips.h b/include/linux/fips.h
new file mode 100644
index 000000000000..f8fb07b0b6b8
--- /dev/null
+++ b/include/linux/fips.h
@@ -0,0 +1,10 @@
+#ifndef _FIPS_H
+#define _FIPS_H
+
+#ifdef CONFIG_CRYPTO_FIPS
+extern int fips_enabled;
+#else
+#define fips_enabled 0
+#endif
+
+#endif
diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h
new file mode 100644
index 000000000000..23c1ec79a31b
--- /dev/null
+++ b/include/linux/flex_array.h
@@ -0,0 +1,47 @@
+#ifndef _FLEX_ARRAY_H
+#define _FLEX_ARRAY_H
+
+#include <linux/types.h>
+#include <asm/page.h>
+
+#define FLEX_ARRAY_PART_SIZE PAGE_SIZE
+#define FLEX_ARRAY_BASE_SIZE PAGE_SIZE
+
+struct flex_array_part;
+
+/*
+ * This is meant to replace cases where an array-like
+ * structure has gotten too big to fit into kmalloc()
+ * and the developer is getting tempted to use
+ * vmalloc().
+ */
+
+struct flex_array {
+ union {
+ struct {
+ int element_size;
+ int total_nr_elements;
+ struct flex_array_part *parts[0];
+ };
+ /*
+ * This little trick makes sure that
+ * sizeof(flex_array) == PAGE_SIZE
+ */
+ char padding[FLEX_ARRAY_BASE_SIZE];
+ };
+};
+
+#define FLEX_ARRAY_INIT(size, total) { { {\
+ .element_size = (size), \
+ .total_nr_elements = (total), \
+} } }
+
+struct flex_array *flex_array_alloc(int element_size, int total, gfp_t flags);
+int flex_array_prealloc(struct flex_array *fa, int start, int end, gfp_t flags);
+void flex_array_free(struct flex_array *fa);
+void flex_array_free_parts(struct flex_array *fa);
+int flex_array_put(struct flex_array *fa, int element_nr, void *src,
+ gfp_t flags);
+void *flex_array_get(struct flex_array *fa, int element_nr);
+
+#endif /* _FLEX_ARRAY_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0872372184fe..694cffd7cef9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -715,7 +715,7 @@ struct posix_acl;
struct inode {
struct hlist_node i_hash;
- struct list_head i_list;
+ struct list_head i_list; /* backing dev IO list */
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
@@ -1336,9 +1336,6 @@ struct super_block {
struct xattr_handler **s_xattr;
struct list_head s_inodes; /* all inodes */
- struct list_head s_dirty; /* dirty inodes */
- struct list_head s_io; /* parked for writeback */
- struct list_head s_more_io; /* parked for more writeback */
struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
struct list_head s_files;
/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
@@ -1555,11 +1552,14 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
unsigned long, loff_t *);
+struct bdi_writeback;
+
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);
+ struct bdi_writeback *(*inode_get_wb) (struct inode *);
int (*write_inode) (struct inode *, int);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
@@ -1946,6 +1946,7 @@ extern void putname(const char *name);
extern int register_blkdev(unsigned int, const char *);
extern void unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
+extern struct block_device *bdgrab(struct block_device *bdev);
extern void bd_set_size(struct block_device *, loff_t size);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
@@ -2071,6 +2072,8 @@ extern int invalidate_inode_pages2_range(struct address_space *mapping,
pgoff_t start, pgoff_t end);
extern void generic_sync_sb_inodes(struct super_block *sb,
struct writeback_control *wbc);
+extern void generic_sync_bdi_inodes(struct super_block *sb,
+ struct writeback_control *);
extern int write_inode_now(struct inode *, int);
extern int filemap_fdatawrite(struct address_space *);
extern int filemap_flush(struct address_space *);
@@ -2184,7 +2187,6 @@ extern int bdev_read_only(struct block_device *);
extern int set_blocksize(struct block_device *, int);
extern int sb_set_blocksize(struct super_block *, int);
extern int sb_min_blocksize(struct super_block *, int);
-extern int sb_has_dirty_inodes(struct super_block *);
extern int generic_file_mmap(struct file *, struct vm_area_struct *);
extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 6c3de999fb34..e25284371020 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -58,9 +58,13 @@
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
FS_DELETE)
+#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
+
/* listeners that hard code group numbers near the top */
#define DNOTIFY_GROUP_NUM UINT_MAX
-#define INOTIFY_GROUP_NUM (DNOTIFY_GROUP_NUM-1)
+#define AUDIT_WATCH_GROUP_NUM (DNOTIFY_GROUP_NUM-1)
+#define AUDIT_TREE_GROUP_NUM (AUDIT_WATCH_GROUP_NUM-1)
+#define INOTIFY_GROUP_NUM (AUDIT_TREE_GROUP_NUM-1)
struct fsnotify_group;
struct fsnotify_event;
@@ -339,8 +343,10 @@ extern void fsnotify_recalc_inode_mask(struct inode *inode);
extern void fsnotify_init_mark(struct fsnotify_mark_entry *entry, void (*free_mark)(struct fsnotify_mark_entry *entry));
/* find (and take a reference) to a mark associated with group and inode */
extern struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group, struct inode *inode);
+/* copy the values from old into new */
+extern void fsnotify_duplicate_mark(struct fsnotify_mark_entry *new, struct fsnotify_mark_entry *old);
/* attach the mark to both the group and the inode */
-extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode);
+extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode, int allow_dups);
/* given a mark, flag it to be freed when all references are dropped */
extern void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry);
/* run all the marks in a group, and flag them to be freed */
@@ -352,7 +358,7 @@ extern void fsnotify_unmount_inodes(struct list_head *list);
/* put here because inotify does some weird stuff when destroying watches */
extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
void *data, int data_is, const char *name,
- u32 cookie);
+ u32 cookie, gfp_t gfp);
#else
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index cf593bf9fd32..3e2925a34bf0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -30,6 +30,10 @@
* - add umask flag to input argument of open, mknod and mkdir
* - add notification messages for invalidation of inodes and
* directory entries
+ *
+ * 7.13
+ * - make max number of background requests and congestion threshold
+ * tunables
*/
#ifndef _LINUX_FUSE_H
@@ -37,11 +41,31 @@
#include <linux/types.h>
+/*
+ * Version negotiation:
+ *
+ * Both the kernel and userspace send the version they support in the
+ * INIT request and reply respectively.
+ *
+ * If the major versions match then both shall use the smallest
+ * of the two minor versions for communication.
+ *
+ * If the kernel supports a larger major version, then userspace shall
+ * reply with the major version it supports, ignore the rest of the
+ * INIT message and expect a new INIT message from the kernel with a
+ * matching major version.
+ *
+ * If the library supports a larger major version, then it shall fall
+ * back to the major protocol version sent by the kernel for
+ * communication and reply with that major version (and an arbitrary
+ * supported minor version).
+ */
+
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 12
+#define FUSE_KERNEL_MINOR_VERSION 13
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -427,7 +451,8 @@ struct fuse_init_out {
__u32 minor;
__u32 max_readahead;
__u32 flags;
- __u32 unused;
+ __u16 max_background;
+ __u16 congestion_threshold;
__u32 max_write;
};
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
index 50d568ec178a..53744fa1c8b7 100644
--- a/include/linux/hid-debug.h
+++ b/include/linux/hid-debug.h
@@ -2,7 +2,7 @@
#define __HID_DEBUG_H
/*
- * Copyright (c) 2007 Jiri Kosina
+ * Copyright (c) 2007-2009 Jiri Kosina
*/
/*
@@ -22,24 +22,44 @@
*
*/
-#ifdef CONFIG_HID_DEBUG
+#define HID_DEBUG_BUFSIZE 512
-void hid_dump_input(struct hid_usage *, __s32);
-void hid_dump_device(struct hid_device *);
-void hid_dump_field(struct hid_field *, int);
-void hid_resolv_usage(unsigned);
-void hid_resolv_event(__u8, __u16);
+#ifdef CONFIG_DEBUG_FS
+
+void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
+void hid_dump_device(struct hid_device *, struct seq_file *);
+void hid_dump_field(struct hid_field *, int, struct seq_file *);
+char *hid_resolv_usage(unsigned, struct seq_file *);
+void hid_debug_register(struct hid_device *, const char *);
+void hid_debug_unregister(struct hid_device *);
+void hid_debug_init(void);
+void hid_debug_exit(void);
+void hid_debug_event(struct hid_device *, char *);
-#else
-#define hid_dump_input(a,b) do { } while (0)
-#define hid_dump_device(c) do { } while (0)
-#define hid_dump_field(a,b) do { } while (0)
-#define hid_resolv_usage(a) do { } while (0)
-#define hid_resolv_event(a,b) do { } while (0)
+struct hid_debug_list {
+ char *hid_debug_buf;
+ int head;
+ int tail;
+ struct fasync_struct *fasync;
+ struct hid_device *hdev;
+ struct list_head node;
+ struct mutex read_mutex;
+};
-#endif /* CONFIG_HID_DEBUG */
+#else
+#define hid_dump_input(a,b,c) do { } while (0)
+#define hid_dump_device(a,b) do { } while (0)
+#define hid_dump_field(a,b,c) do { } while (0)
+#define hid_resolv_usage(a,b) do { } while (0)
+#define hid_debug_register(a, b) do { } while (0)
+#define hid_debug_unregister(a) do { } while (0)
+#define hid_debug_init() do { } while (0)
+#define hid_debug_exit() do { } while (0)
+#define hid_debug_event(a,b) do { } while (0)
+
+#endif
#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 53489fd4d700..a0ebdace7baa 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -500,6 +500,14 @@ struct hid_device { /* device report descriptor */
/* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
+
+ /* debugging support via debugfs */
+ unsigned short debug;
+ struct dentry *debug_dir;
+ struct dentry *debug_rdesc;
+ struct dentry *debug_events;
+ struct list_head debug_list;
+ wait_queue_head_t debug_wait;
};
static inline void *hid_get_drvdata(struct hid_device *hdev)
@@ -657,9 +665,7 @@ struct hid_ll_driver {
/* HID core API */
-#ifdef CONFIG_HID_DEBUG
extern int hid_debug;
-#endif
extern int hid_add_device(struct hid_device *);
extern void hid_destroy_device(struct hid_device *);
@@ -815,21 +821,9 @@ int hid_pidff_init(struct hid_device *hid);
#define hid_pidff_init NULL
#endif
-#ifdef CONFIG_HID_DEBUG
#define dbg_hid(format, arg...) if (hid_debug) \
printk(KERN_DEBUG "%s: " format ,\
__FILE__ , ## arg)
-#define dbg_hid_line(format, arg...) if (hid_debug) \
- printk(format, ## arg)
-#else
-static inline int __attribute__((format(printf, 1, 2)))
-dbg_hid(const char *fmt, ...)
-{
- return 0;
-}
-#define dbg_hid_line dbg_hid
-#endif /* HID_DEBUG */
-
#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
__FILE__ , ## arg)
#endif /* HID_FF */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index c9087de5c6c6..e844a0b18695 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -28,17 +28,6 @@
identify a legacy client. If you don't need them, just don't set them. */
/*
- * ---- Driver types -----------------------------------------------------
- */
-
-#define I2C_DRIVERID_MSP3400 1
-#define I2C_DRIVERID_TUNER 2
-#define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */
-#define I2C_DRIVERID_TVAUDIO 29 /* Generic TV sound driver */
-#define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */
-#define I2C_DRIVERID_INFRARED 75 /* I2C InfraRed on Video boards */
-
-/*
* ---- Adapter types ----------------------------------------------------
*/
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index f4784c0fe975..57d41b0abce2 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -98,7 +98,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
/**
* struct i2c_driver - represent an I2C device driver
- * @id: Unique driver ID (optional)
* @class: What kind of i2c device we instantiate (for detect)
* @attach_adapter: Callback for bus addition (for legacy drivers)
* @detach_adapter: Callback for bus removal (for legacy drivers)
@@ -135,7 +134,6 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
* not allowed.
*/
struct i2c_driver {
- int id;
unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a9173d5434d1..21556a2d9e7e 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -802,6 +802,31 @@ struct ieee80211_ht_cap {
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C
+/*
+ * Maximum length of AMPDU that the STA can receive.
+ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+enum ieee80211_max_ampdu_length_exp {
+ IEEE80211_HT_MAX_AMPDU_8K = 0,
+ IEEE80211_HT_MAX_AMPDU_16K = 1,
+ IEEE80211_HT_MAX_AMPDU_32K = 2,
+ IEEE80211_HT_MAX_AMPDU_64K = 3
+};
+
+#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
+
+/* Minimum MPDU start spacing */
+enum ieee80211_min_mpdu_spacing {
+ IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */
+ IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */
+ IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */
+ IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */
+ IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */
+ IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */
+ IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */
+ IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */
+};
+
/**
* struct ieee80211_ht_info - HT information
*
@@ -1196,6 +1221,10 @@ enum ieee80211_sa_query_action {
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X 0x000FAC01
+#define WLAN_AKM_SUITE_PSK 0x000FAC02
+
#define WLAN_MAX_KEY_LEN 32
/**
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 70fdba2bbf71..580b6004d00e 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -139,10 +139,10 @@ extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
/*
* Display a 6 byte device address (MAC) in a readable format.
*/
-extern char *print_mac(char *buf, const unsigned char *addr);
+extern char *print_mac(char *buf, const unsigned char *addr) __deprecated;
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_BUF_SIZE 18
-#define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] __maybe_unused
+#define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE]
#endif
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 915ba5789f0e..3f5fd523b49d 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -62,6 +62,7 @@
#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */
#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */
#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
+#define TUN_F_UFO 0x10 /* I can handle UFO packets */
/* Protocol info prepended to the packets (when IFF_NO_PI is not set) */
#define TUN_PKT_STRIP 0x0001
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index acef2a770b6b..ad27c7da8798 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -82,7 +82,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
#define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING)
#define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING)
-#define IN_DEV_RPFILTER(in_dev) IN_DEV_ANDCONF((in_dev), RP_FILTER)
+#define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER)
#define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \
ACCEPT_SOURCE_ROUTE)
#define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 35e7df1e9f30..6967f6aab33a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -80,7 +80,6 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
* struct irqaction - per interrupt action descriptor
* @handler: interrupt handler function
* @flags: flags (see IRQF_* above)
- * @mask: no comment as it is useless and about to be removed
* @name: name of the device
* @dev_id: cookie to identify the device
* @next: pointer to the next irqaction for shared interrupts
@@ -93,7 +92,6 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
struct irqaction {
irq_handler_t handler;
unsigned long flags;
- cpumask_t mask;
const char *name;
void *dev_id;
struct irqaction *next;
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
index dd05434fa45f..4da4a75c3f1e 100644
--- a/include/linux/iocontext.h
+++ b/include/linux/iocontext.h
@@ -92,7 +92,7 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc)
* a race).
*/
if (ioc && atomic_long_inc_not_zero(&ioc->refcount)) {
- atomic_long_inc(&ioc->refcount);
+ atomic_inc(&ioc->nr_tasks);
return ioc;
}
diff --git a/include/linux/iova.h b/include/linux/iova.h
index 228f6c94b69c..76a0759e88ec 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -28,7 +28,6 @@ struct iova {
/* holds all the iova translations for a domain */
struct iova_domain {
- spinlock_t iova_alloc_lock;/* Lock to protect iova allocation */
spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */
struct rb_root rbroot; /* iova domain rbtree root */
struct rb_node *cached32_node; /* Save last alloced node */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index cb2e77a3f7f7..6956df9961ab 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -220,13 +220,6 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node);
/*
- * Migration helpers for obsolete names, they will go away:
- */
-#define hw_interrupt_type irq_chip
-#define no_irq_type no_irq_chip
-typedef struct irq_desc irq_desc_t;
-
-/*
* Pick up the arch-dependent methods:
*/
#include <asm/hw_irq.h>
diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h
new file mode 100644
index 000000000000..4b3ecc40889a
--- /dev/null
+++ b/include/linux/isdn/hdlc.h
@@ -0,0 +1,82 @@
+/*
+ * hdlc.h -- General purpose ISDN HDLC decoder.
+ *
+ * Implementation of a HDLC decoder/encoder in software.
+ * Neccessary because some ISDN devices don't have HDLC
+ * controllers.
+ *
+ * Copyright (C)
+ * 2009 Karsten Keil <keil@b1-systems.de>
+ * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ * 2001 Frode Isaksen <fisaksen@bewan.com>
+ * 2001 Kai Germaschewski <kai.germaschewski@gmx.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ISDNHDLC_H__
+#define __ISDNHDLC_H__
+
+struct isdnhdlc_vars {
+ int bit_shift;
+ int hdlc_bits1;
+ int data_bits;
+ int ffbit_shift; /* encoding only */
+ int state;
+ int dstpos;
+
+ u16 crc;
+
+ u8 cbin;
+ u8 shift_reg;
+ u8 ffvalue;
+
+ /* set if transferring data */
+ u32 data_received:1;
+ /* set if D channel (send idle instead of flags) */
+ u32 dchannel:1;
+ /* set if 56K adaptation */
+ u32 do_adapt56:1;
+ /* set if in closing phase (need to send CRC + flag) */
+ u32 do_closing:1;
+ /* set if data is bitreverse */
+ u32 do_bitreverse:1;
+};
+
+/* Feature Flags */
+#define HDLC_56KBIT 0x01
+#define HDLC_DCHANNEL 0x02
+#define HDLC_BITREVERSE 0x04
+
+/*
+ The return value from isdnhdlc_decode is
+ the frame length, 0 if no complete frame was decoded,
+ or a negative error number
+*/
+#define HDLC_FRAMING_ERROR 1
+#define HDLC_CRC_ERROR 2
+#define HDLC_LENGTH_ERROR 3
+
+extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features);
+
+extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src,
+ int slen, int *count, u8 *dst, int dsize);
+
+extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features);
+
+extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src,
+ u16 slen, int *count, u8 *dst, int dsize);
+
+#endif /* __ISDNHDLC_H__ */
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 6adcc297e354..cedae0b71192 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -29,8 +29,7 @@ struct pt_regs;
*
* On some architectures it is required to skip a breakpoint
* exception when it occurs after a breakpoint has been removed.
- * This can be implemented in the architecture specific portion of
- * for kgdb.
+ * This can be implemented in the architecture specific portion of kgdb.
*/
extern int kgdb_skipexception(int exception, struct pt_regs *regs);
@@ -65,7 +64,7 @@ struct uart_port;
/**
* kgdb_breakpoint - compiled in breakpoint
*
- * This will be impelmented a static inline per architecture. This
+ * This will be implemented as a static inline per architecture. This
* function is called by the kgdb core to execute an architecture
* specific trap to cause kgdb to enter the exception processing.
*
@@ -190,7 +189,7 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code,
* @flags: Current IRQ state
*
* On SMP systems, we need to get the attention of the other CPUs
- * and get them be in a known state. This should do what is needed
+ * and get them into a known state. This should do what is needed
* to get the other CPUs to call kgdb_wait(). Note that on some arches,
* the NMI approach is not used for rounding up all the CPUs. For example,
* in case of MIPS, smp_call_function() is used to roundup CPUs. In
@@ -267,8 +266,45 @@ extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern int kgdb_hex2long(char **ptr, unsigned long *long_val);
-extern int kgdb_mem2hex(char *mem, char *buf, int count);
-extern int kgdb_hex2mem(char *buf, char *mem, int count);
+
+/**
+ * kgdb_mem2hex - (optional arch override) translate bin to hex chars
+ * @mem: source buffer
+ * @buf: target buffer
+ * @count: number of bytes in mem
+ *
+ * Architectures which do not support probe_kernel_(read|write),
+ * can make an alternate implementation of this function.
+ * This function safely reads memory into hex
+ * characters for use with the kgdb protocol.
+ */
+extern int __weak kgdb_mem2hex(char *mem, char *buf, int count);
+
+/**
+ * kgdb_hex2mem - (optional arch override) translate hex chars to bin
+ * @buf: source buffer
+ * @mem: target buffer
+ * @count: number of bytes in mem
+ *
+ * Architectures which do not support probe_kernel_(read|write),
+ * can make an alternate implementation of this function.
+ * This function safely writes hex characters into memory
+ * for use with the kgdb protocol.
+ */
+extern int __weak kgdb_hex2mem(char *buf, char *mem, int count);
+
+/**
+ * kgdb_ebin2mem - (optional arch override) Copy binary array from @buf into @mem
+ * @buf: source buffer
+ * @mem: target buffer
+ * @count: number of bytes in mem
+ *
+ * Architectures which do not support probe_kernel_(read|write),
+ * can make an alternate implementation of this function.
+ * This function safely copies binary array into memory
+ * for use with the kgdb protocol.
+ */
+extern int __weak kgdb_ebin2mem(char *buf, char *mem, int count);
extern int kgdb_isremovedbreak(unsigned long addr);
diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h
index 6a63807f714e..3c7497d46ee9 100644
--- a/include/linux/kmemleak.h
+++ b/include/linux/kmemleak.h
@@ -23,18 +23,18 @@
#ifdef CONFIG_DEBUG_KMEMLEAK
-extern void kmemleak_init(void);
+extern void kmemleak_init(void) __ref;
extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
- gfp_t gfp);
-extern void kmemleak_free(const void *ptr);
-extern void kmemleak_free_part(const void *ptr, size_t size);
+ gfp_t gfp) __ref;
+extern void kmemleak_free(const void *ptr) __ref;
+extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
extern void kmemleak_padding(const void *ptr, unsigned long offset,
- size_t size);
-extern void kmemleak_not_leak(const void *ptr);
-extern void kmemleak_ignore(const void *ptr);
+ size_t size) __ref;
+extern void kmemleak_not_leak(const void *ptr) __ref;
+extern void kmemleak_ignore(const void *ptr) __ref;
extern void kmemleak_scan_area(const void *ptr, unsigned long offset,
- size_t length, gfp_t gfp);
-extern void kmemleak_no_scan(const void *ptr);
+ size_t length, gfp_t gfp) __ref;
+extern void kmemleak_no_scan(const void *ptr) __ref;
static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
int min_count, unsigned long flags,
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 3db5d8d37485..f8f8900fc5ec 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -14,7 +14,7 @@
#define KVM_API_VERSION 12
-/* for KVM_TRACE_ENABLE */
+/* for KVM_TRACE_ENABLE, deprecated */
struct kvm_user_trace_setup {
__u32 buf_size; /* sub_buffer size of each per-cpu */
__u32 buf_nr; /* the number of sub_buffers of each per-cpu */
@@ -70,6 +70,14 @@ struct kvm_irqchip {
} chip;
};
+/* for KVM_CREATE_PIT2 */
+struct kvm_pit_config {
+ __u32 flags;
+ __u32 pad[15];
+};
+
+#define KVM_PIT_SPEAKER_DUMMY 1
+
#define KVM_EXIT_UNKNOWN 0
#define KVM_EXIT_EXCEPTION 1
#define KVM_EXIT_IO 2
@@ -87,6 +95,10 @@ struct kvm_irqchip {
#define KVM_EXIT_S390_RESET 14
#define KVM_EXIT_DCR 15
#define KVM_EXIT_NMI 16
+#define KVM_EXIT_INTERNAL_ERROR 17
+
+/* For KVM_EXIT_INTERNAL_ERROR */
+#define KVM_INTERNAL_ERROR_EMULATION 1
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
@@ -173,6 +185,9 @@ struct kvm_run {
__u32 data;
__u8 is_write;
} dcr;
+ struct {
+ __u32 suberror;
+ } internal;
/* Fix the size of the union. */
char padding[256];
};
@@ -292,6 +307,28 @@ struct kvm_guest_debug {
struct kvm_guest_debug_arch arch;
};
+enum {
+ kvm_ioeventfd_flag_nr_datamatch,
+ kvm_ioeventfd_flag_nr_pio,
+ kvm_ioeventfd_flag_nr_deassign,
+ kvm_ioeventfd_flag_nr_max,
+};
+
+#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
+#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio)
+#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign)
+
+#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1)
+
+struct kvm_ioeventfd {
+ __u64 datamatch;
+ __u64 addr; /* legal pio/mmio address */
+ __u32 len; /* 1, 2, 4, or 8 bytes */
+ __s32 fd;
+ __u32 flags;
+ __u8 pad[36];
+};
+
#define KVM_TRC_SHIFT 16
/*
* kvm trace categories
@@ -310,35 +347,6 @@ struct kvm_guest_debug {
#define KVM_TRC_CYCLE_SIZE 8
#define KVM_TRC_EXTRA_MAX 7
-/* This structure represents a single trace buffer record. */
-struct kvm_trace_rec {
- /* variable rec_val
- * is split into:
- * bits 0 - 27 -> event id
- * bits 28 -30 -> number of extra data args of size u32
- * bits 31 -> binary indicator for if tsc is in record
- */
- __u32 rec_val;
- __u32 pid;
- __u32 vcpu_id;
- union {
- struct {
- __u64 timestamp;
- __u32 extra_u32[KVM_TRC_EXTRA_MAX];
- } __attribute__((packed)) timestamp;
- struct {
- __u32 extra_u32[KVM_TRC_EXTRA_MAX];
- } notimestamp;
- } u;
-};
-
-#define TRACE_REC_EVENT_ID(val) \
- (0x0fffffff & (val))
-#define TRACE_REC_NUM_DATA_ARGS(val) \
- (0x70000000 & ((val) << 28))
-#define TRACE_REC_TCS(val) \
- (0x80000000 & ((val) << 31))
-
#define KVMIO 0xAE
/*
@@ -415,6 +423,19 @@ struct kvm_trace_rec {
#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
+#define KVM_CAP_IRQFD 32
+#ifdef __KVM_HAVE_PIT
+#define KVM_CAP_PIT2 33
+#endif
+#define KVM_CAP_SET_BOOT_CPU_ID 34
+#ifdef __KVM_HAVE_PIT_STATE2
+#define KVM_CAP_PIT_STATE2 35
+#endif
+#define KVM_CAP_IOEVENTFD 36
+#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
#ifdef KVM_CAP_IRQ_ROUTING
@@ -454,15 +475,32 @@ struct kvm_irq_routing {
#endif
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+ __u64 status;
+ __u64 addr;
+ __u64 misc;
+ __u64 mcg_status;
+ __u8 bank;
+ __u8 pad1[7];
+ __u64 pad2[3];
+};
+#endif
+
+#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
+
+struct kvm_irqfd {
+ __u32 fd;
+ __u32 gsi;
+ __u32 flags;
+ __u8 pad[20];
+};
+
/*
* ioctls for VM fds
*/
#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region)
-#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
-#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45)
-#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\
- struct kvm_userspace_memory_region)
-#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
/*
* KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
* a vcpu fd.
@@ -470,6 +508,12 @@ struct kvm_irq_routing {
#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
+#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
+#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\
+ struct kvm_userspace_memory_region)
+#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
+#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
/* Device model IOC */
#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
@@ -498,6 +542,10 @@ struct kvm_irq_routing {
#define KVM_ASSIGN_SET_MSIX_ENTRY \
_IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry)
#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
+#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
+#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
+#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
+#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
/*
* ioctls for vcpu fds
@@ -541,6 +589,10 @@ struct kvm_irq_routing {
#define KVM_NMI _IO(KVMIO, 0x9a)
/* Available with KVM_CAP_SET_GUEST_DEBUG */
#define KVM_SET_GUEST_DEBUG _IOW(KVMIO, 0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
+#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
/*
* Deprecated interfaces
@@ -563,6 +615,9 @@ struct kvm_debug_guest {
#define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
#define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *)
+#define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
+
#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04)
@@ -633,7 +688,7 @@ struct kvm_assigned_msix_nr {
__u16 padding;
};
-#define KVM_MAX_MSIX_PER_DEV 512
+#define KVM_MAX_MSIX_PER_DEV 256
struct kvm_assigned_msix_entry {
__u32 assigned_dev_id;
__u32 gsi;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 16713dc672e4..f244f11f2d27 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -42,6 +42,7 @@
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
+struct kvm;
struct kvm_vcpu;
extern struct kmem_cache *kvm_vcpu_cache;
@@ -59,10 +60,18 @@ struct kvm_io_bus {
void kvm_io_bus_init(struct kvm_io_bus *bus);
void kvm_io_bus_destroy(struct kvm_io_bus *bus);
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
- gpa_t addr, int len, int is_write);
-void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
- struct kvm_io_device *dev);
+int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, int len,
+ const void *val);
+int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len,
+ void *val);
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+ struct kvm_io_device *dev);
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+ struct kvm_io_device *dev);
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+ struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+ struct kvm_io_device *dev);
struct kvm_vcpu {
struct kvm *kvm;
@@ -103,7 +112,7 @@ struct kvm_memory_slot {
struct {
unsigned long rmap_pde;
int write_count;
- } *lpage_info;
+ } *lpage_info[KVM_NR_PAGE_SIZES - 1];
unsigned long userspace_addr;
int user_alloc;
};
@@ -123,7 +132,6 @@ struct kvm_kernel_irq_routing_entry {
};
struct kvm {
- struct mutex lock; /* protects the vcpus array and APIC accesses */
spinlock_t mmu_lock;
spinlock_t requests_lock;
struct rw_semaphore slots_lock;
@@ -131,10 +139,23 @@ struct kvm {
int nmemslots;
struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS +
KVM_PRIVATE_MEM_SLOTS];
+#ifdef CONFIG_KVM_APIC_ARCHITECTURE
+ u32 bsp_vcpu_id;
+ struct kvm_vcpu *bsp_vcpu;
+#endif
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ atomic_t online_vcpus;
struct list_head vm_list;
+ struct mutex lock;
struct kvm_io_bus mmio_bus;
struct kvm_io_bus pio_bus;
+#ifdef CONFIG_HAVE_KVM_EVENTFD
+ struct {
+ spinlock_t lock;
+ struct list_head items;
+ } irqfds;
+ struct list_head ioeventfds;
+#endif
struct kvm_vm_stat stat;
struct kvm_arch arch;
atomic_t users_count;
@@ -143,6 +164,7 @@ struct kvm {
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
#endif
+ struct mutex irq_lock;
#ifdef CONFIG_HAVE_KVM_IRQCHIP
struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */
struct hlist_head mask_notifier_list;
@@ -166,6 +188,17 @@ struct kvm {
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
+{
+ smp_rmb();
+ return kvm->vcpus[i];
+}
+
+#define kvm_for_each_vcpu(idx, vcpup, kvm) \
+ for (idx = 0, vcpup = kvm_get_vcpu(kvm, idx); \
+ idx < atomic_read(&kvm->online_vcpus) && vcpup; \
+ vcpup = kvm_get_vcpu(kvm, ++idx))
+
int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
@@ -200,6 +233,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old,
int user_alloc);
+void kvm_disable_largepages(void);
void kvm_arch_flush_shadow(struct kvm *kvm);
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
@@ -242,8 +276,6 @@ long kvm_arch_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg);
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg);
-void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
-void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);
int kvm_dev_ioctl_check_extension(long ext);
@@ -299,7 +331,6 @@ int kvm_arch_hardware_setup(void);
void kvm_arch_hardware_unsetup(void);
void kvm_arch_check_processor_compat(void *rtn);
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
-int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
void kvm_free_physmem(struct kvm *kvm);
@@ -308,8 +339,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm);
void kvm_free_all_assigned_devices(struct kvm *kvm);
void kvm_arch_sync_events(struct kvm *kvm);
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
@@ -361,11 +390,17 @@ 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);
+#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, int 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);
-void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
+void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
+ struct kvm_irq_ack_notifier *kian);
int kvm_request_irq_source_id(struct kvm *kvm);
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
@@ -458,37 +493,6 @@ struct kvm_stats_debugfs_item {
extern struct kvm_stats_debugfs_item debugfs_entries[];
extern struct dentry *kvm_debugfs_dir;
-#define KVMTRACE_5D(evt, vcpu, d1, d2, d3, d4, d5, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 5, d1, d2, d3, d4, d5)
-#define KVMTRACE_4D(evt, vcpu, d1, d2, d3, d4, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 4, d1, d2, d3, d4, 0)
-#define KVMTRACE_3D(evt, vcpu, d1, d2, d3, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 3, d1, d2, d3, 0, 0)
-#define KVMTRACE_2D(evt, vcpu, d1, d2, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 2, d1, d2, 0, 0, 0)
-#define KVMTRACE_1D(evt, vcpu, d1, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 1, d1, 0, 0, 0, 0)
-#define KVMTRACE_0D(evt, vcpu, name) \
- trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
- vcpu, 0, 0, 0, 0, 0, 0)
-
-#ifdef CONFIG_KVM_TRACE
-int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg);
-void kvm_trace_cleanup(void);
-#else
-static inline
-int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg)
-{
- return -EINVAL;
-}
-#define kvm_trace_cleanup() ((void)0)
-#endif
-
#ifdef KVM_ARCH_WANT_MMU_NOTIFIER
static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_seq)
{
@@ -524,4 +528,33 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
#endif
+#ifdef CONFIG_HAVE_KVM_EVENTFD
+
+void kvm_eventfd_init(struct kvm *kvm);
+int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
+void kvm_irqfd_release(struct kvm *kvm);
+int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
+
+#else
+
+static inline void kvm_eventfd_init(struct kvm *kvm) {}
+static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+{
+ return -EINVAL;
+}
+
+static inline void kvm_irqfd_release(struct kvm *kvm) {}
+static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_HAVE_KVM_EVENTFD */
+
+#ifdef CONFIG_KVM_APIC_ARCHITECTURE
+static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
+{
+ return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;
+}
+#endif
#endif
diff --git a/include/linux/lguest.h b/include/linux/lguest.h
index dbf2479e808e..2fb1dcbcb5aa 100644
--- a/include/linux/lguest.h
+++ b/include/linux/lguest.h
@@ -1,5 +1,7 @@
-/* Things the lguest guest needs to know. Note: like all lguest interfaces,
- * this is subject to wild and random change between versions. */
+/*
+ * Things the lguest guest needs to know. Note: like all lguest interfaces,
+ * this is subject to wild and random change between versions.
+ */
#ifndef _LINUX_LGUEST_H
#define _LINUX_LGUEST_H
@@ -11,32 +13,41 @@
#define LG_CLOCK_MIN_DELTA 100UL
#define LG_CLOCK_MAX_DELTA ULONG_MAX
-/*G:031 The second method of communicating with the Host is to via "struct
+/*G:031
+ * The second method of communicating with the Host is to via "struct
* lguest_data". Once the Guest's initialization hypercall tells the Host where
- * this is, the Guest and Host both publish information in it. :*/
-struct lguest_data
-{
- /* 512 == enabled (same as eflags in normal hardware). The Guest
- * changes interrupts so often that a hypercall is too slow. */
+ * this is, the Guest and Host both publish information in it.
+:*/
+struct lguest_data {
+ /*
+ * 512 == enabled (same as eflags in normal hardware). The Guest
+ * changes interrupts so often that a hypercall is too slow.
+ */
unsigned int irq_enabled;
/* Fine-grained interrupt disabling by the Guest */
DECLARE_BITMAP(blocked_interrupts, LGUEST_IRQS);
- /* The Host writes the virtual address of the last page fault here,
+ /*
+ * The Host writes the virtual address of the last page fault here,
* which saves the Guest a hypercall. CR2 is the native register where
- * this address would normally be found. */
+ * this address would normally be found.
+ */
unsigned long cr2;
/* Wallclock time set by the Host. */
struct timespec time;
- /* Interrupt pending set by the Host. The Guest should do a hypercall
- * if it re-enables interrupts and sees this set (to X86_EFLAGS_IF). */
+ /*
+ * Interrupt pending set by the Host. The Guest should do a hypercall
+ * if it re-enables interrupts and sees this set (to X86_EFLAGS_IF).
+ */
int irq_pending;
- /* Async hypercall ring. Instead of directly making hypercalls, we can
+ /*
+ * Async hypercall ring. Instead of directly making hypercalls, we can
* place them in here for processing the next time the Host wants.
- * This batching can be quite efficient. */
+ * This batching can be quite efficient.
+ */
/* 0xFF == done (set by Host), 0 == pending (set by Guest). */
u8 hcall_status[LHCALL_RING_SIZE];
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
index bfefbdf7498a..495203ff221c 100644
--- a/include/linux/lguest_launcher.h
+++ b/include/linux/lguest_launcher.h
@@ -29,8 +29,10 @@ struct lguest_device_desc {
__u8 type;
/* The number of virtqueues (first in config array) */
__u8 num_vq;
- /* The number of bytes of feature bits. Multiply by 2: one for host
- * features and one for Guest acknowledgements. */
+ /*
+ * The number of bytes of feature bits. Multiply by 2: one for host
+ * features and one for Guest acknowledgements.
+ */
__u8 feature_len;
/* The number of bytes of the config array after virtqueues. */
__u8 config_len;
@@ -39,8 +41,10 @@ struct lguest_device_desc {
__u8 config[0];
};
-/*D:135 This is how we expect the device configuration field for a virtqueue
- * to be laid out in config space. */
+/*D:135
+ * This is how we expect the device configuration field for a virtqueue
+ * to be laid out in config space.
+ */
struct lguest_vqconfig {
/* The number of entries in the virtio_ring */
__u16 num;
@@ -61,7 +65,9 @@ enum lguest_req
LHREQ_EVENTFD, /* + address, fd. */
};
-/* The alignment to use between consumer and producer parts of vring.
- * x86 pagesize for historical reasons. */
+/*
+ * The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize for historical reasons.
+ */
#define LGUEST_VRING_ALIGN 4096
#endif /* _LINUX_LGUEST_LAUNCHER */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 79b6d7fd4ac2..76319bf03e37 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -143,7 +143,6 @@ enum {
ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */
- ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */
ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */
ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */
ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */
@@ -190,6 +189,7 @@ enum {
ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */
ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */
ATA_FLAG_DEBUGMSG = (1 << 13),
+ ATA_FLAG_FPDMA_AA = (1 << 14), /* driver supports Auto-Activate */
ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
@@ -386,6 +386,7 @@ enum {
ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firmware update warning */
ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */
ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */
+ ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */
/* DMA mask for user DMA control: User visible values; DO NOT
renumber */
@@ -589,6 +590,7 @@ struct ata_device {
#endif
/* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
u64 n_sectors; /* size of device, if ATA */
+ u64 n_native_sectors; /* native size, if ATA */
unsigned int class; /* ATA_DEV_xxx */
unsigned long unpark_deadline;
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/lsm_audit.h b/include/linux/lsm_audit.h
index e461b2c3d711..a5514a3a4f17 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -66,16 +66,19 @@ struct common_audit_data {
} key_struct;
#endif
} u;
- const char *function;
/* this union contains LSM specific data */
union {
+#ifdef CONFIG_SECURITY_SMACK
/* SMACK data */
struct smack_audit_data {
+ const char *function;
char *subject;
char *object;
char *request;
int result;
} smack_audit_data;
+#endif
+#ifdef CONFIG_SECURITY_SELINUX
/* SELinux data */
struct {
u32 ssid;
@@ -86,7 +89,8 @@ struct common_audit_data {
struct av_decision *avd;
int result;
} selinux_audit_data;
- } lsm_priv;
+#endif
+ };
/* these callback will be implemented by a specific LSM */
void (*lsm_pre_audit)(struct audit_buffer *, void *);
void (*lsm_post_audit)(struct audit_buffer *, void *);
@@ -104,7 +108,7 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
/* Initialize an LSM audit data structure. */
#define COMMON_AUDIT_DATA_INIT(_d, _t) \
{ memset((_d), 0, sizeof(struct common_audit_data)); \
- (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; }
+ (_d)->type = LSM_AUDIT_DATA_##_t; }
void common_lsm_audit(struct common_audit_data *a);
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 7f9831da847f..4af841408fb5 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -168,6 +168,7 @@ struct bchannel {
extern int mISDN_initdchannel(struct dchannel *, int, void *);
extern int mISDN_initbchannel(struct bchannel *, int);
extern int mISDN_freedchannel(struct dchannel *);
+extern void mISDN_clear_bchannel(struct bchannel *);
extern int mISDN_freebchannel(struct bchannel *);
extern void queue_ch_frame(struct mISDNchannel *, u_int,
int, struct sk_buff *);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 45100b39a7cf..78c3bed1c3f5 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
*/
#define MISDN_MAJOR_VERSION 1
#define MISDN_MINOR_VERSION 1
-#define MISDN_RELEASE 20
+#define MISDN_RELEASE 21
/* primitives for information exchange
* generell format
@@ -104,7 +104,7 @@
#define DL_UNITDATA_IND 0x3108
#define DL_INFORMATION_IND 0x0008
-/* intern layer 2 managment */
+/* intern layer 2 management */
#define MDL_ASSIGN_REQ 0x1804
#define MDL_ASSIGN_IND 0x1904
#define MDL_REMOVE_REQ 0x1A04
@@ -153,6 +153,18 @@
#define HFC_VOL_CHANGE_RX 0x2602
#define HFC_SPL_LOOP_ON 0x2603
#define HFC_SPL_LOOP_OFF 0x2604
+/* for T30 FAX and analog modem */
+#define HW_MOD_FRM 0x4000
+#define HW_MOD_FRH 0x4001
+#define HW_MOD_FTM 0x4002
+#define HW_MOD_FTH 0x4003
+#define HW_MOD_FTS 0x4004
+#define HW_MOD_CONNECT 0x4010
+#define HW_MOD_OK 0x4011
+#define HW_MOD_NOCARR 0x4012
+#define HW_MOD_FCERROR 0x4013
+#define HW_MOD_READY 0x4014
+#define HW_MOD_LASTDATA 0x4015
/* DSP_TONE_PATT_ON parameter */
#define TONE_OFF 0x0000
@@ -224,6 +236,8 @@
#define ISDN_P_B_L2DTMF 0x24
#define ISDN_P_B_L2DSP 0x25
#define ISDN_P_B_L2DSPHDLC 0x26
+#define ISDN_P_B_T30_FAX 0x27
+#define ISDN_P_B_MODEM_ASYNC 0x28
#define OPTION_L2_PMX 1
#define OPTION_L2_PTP 2
diff --git a/include/linux/mfd/da903x.h b/include/linux/mfd/da903x.h
index 115dbe965082..c63b65c94429 100644
--- a/include/linux/mfd/da903x.h
+++ b/include/linux/mfd/da903x.h
@@ -1,7 +1,7 @@
#ifndef __LINUX_PMIC_DA903X_H
#define __LINUX_PMIC_DA903X_H
-/* Unified sub device IDs for DA9030/DA9034 */
+/* Unified sub device IDs for DA9030/DA9034/DA9035 */
enum {
DA9030_ID_LED_1,
DA9030_ID_LED_2,
@@ -57,6 +57,8 @@ enum {
DA9034_ID_LDO13,
DA9034_ID_LDO14,
DA9034_ID_LDO15,
+
+ DA9035_ID_BUCK3,
};
/*
diff --git a/include/linux/mfd/ezx-pcap.h b/include/linux/mfd/ezx-pcap.h
index c12c3c0932bf..dec82b0b05f9 100644
--- a/include/linux/mfd/ezx-pcap.h
+++ b/include/linux/mfd/ezx-pcap.h
@@ -25,9 +25,12 @@ struct pcap_chip;
int ezx_pcap_write(struct pcap_chip *, u8, u32);
int ezx_pcap_read(struct pcap_chip *, u8, u32 *);
+int ezx_pcap_set_bits(struct pcap_chip *, u8, u32, u32);
int pcap_to_irq(struct pcap_chip *, int);
+int irq_to_pcap(struct pcap_chip *, int);
int pcap_adc_async(struct pcap_chip *, u8, u32, u8[], void *, void *);
int pcap_adc_sync(struct pcap_chip *, u8, u32, u8[], u16[]);
+void pcap_set_ts_bits(struct pcap_chip *, u32);
#define PCAP_SECOND_PORT 1
#define PCAP_CS_AH 2
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index 39751c8cde9c..2dbfb5a05994 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -22,6 +22,12 @@
/*
* Vendors and devices. Sort key: vendor first, device next.
*/
+#define SDIO_VENDOR_ID_INTEL 0x0089
+#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
+#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403
+#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
+#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405
+#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406
#define SDIO_VENDOR_ID_MARVELL 0x02df
#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d870ae2faedc..ec0f607b364a 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -40,7 +40,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
* - follow links at the end
* - require a directory
* - ending slashes ok even for nonexistent files
- * - internal "there are more path compnents" flag
+ * - internal "there are more path components" flag
* - locked when lookup done with dcache_lock held
* - dentry cache is untrusted; force a real lookup
*/
diff --git a/include/linux/net_dropmon.h b/include/linux/net_dropmon.h
index 3ceb0cc1bc78..2a739462caeb 100644
--- a/include/linux/net_dropmon.h
+++ b/include/linux/net_dropmon.h
@@ -3,7 +3,6 @@
#include <linux/types.h>
#include <linux/netlink.h>
-#include <linux/types.h>
struct net_dm_drop_point {
__u8 pc[8];
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d4a4d9867794..9f25ab2899de 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -72,10 +72,6 @@ struct wireless_dev;
/* Backlog congestion levels */
#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */
#define NET_RX_DROP 1 /* packet dropped */
-#define NET_RX_CN_LOW 2 /* storm alert, just in case */
-#define NET_RX_CN_MOD 3 /* Storm on its way! */
-#define NET_RX_CN_HIGH 4 /* The storm is here */
-#define NET_RX_BAD 5 /* packet dropped due to kernel error */
/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It
* indicates that the device will soon be dropping packets, or already drops
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index bd2eba530667..aff924a24abb 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -234,7 +234,7 @@ enum nfs_opnum4 {
Needs to be updated if more operations are defined in future.*/
#define FIRST_NFS4_OP OP_ACCESS
-#define LAST_NFS4_OP OP_RELEASE_LOCKOWNER
+#define LAST_NFS4_OP OP_RECLAIM_COMPLETE
enum nfsstat4 {
NFS4_OK = 0,
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 2b49d676d0c9..2812ed52669d 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -56,6 +56,9 @@ extern struct svc_version nfsd_version2, nfsd_version3,
extern u32 nfsd_supported_minorversion;
extern struct mutex nfsd_mutex;
extern struct svc_serv *nfsd_serv;
+extern spinlock_t nfsd_drc_lock;
+extern unsigned int nfsd_drc_max_mem;
+extern unsigned int nfsd_drc_mem_used;
extern struct seq_operations nfs_exports_op;
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 57ab2ed08459..58bb19784e12 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -96,6 +96,7 @@ struct nfs4_cb_conn {
#define NFSD_MAX_SLOTS_PER_SESSION 128
/* Maximum number of pages per slot cache entry */
#define NFSD_PAGES_PER_SLOT 1
+#define NFSD_SLOT_CACHE_SIZE PAGE_SIZE
/* Maximum number of operations per session compound */
#define NFSD_MAX_OPS_PER_COMPOUND 16
@@ -126,6 +127,25 @@ struct nfsd4_channel_attrs {
u32 rdma_attrs;
};
+struct nfsd4_create_session {
+ clientid_t clientid;
+ struct nfs4_sessionid sessionid;
+ u32 seqid;
+ u32 flags;
+ struct nfsd4_channel_attrs fore_channel;
+ struct nfsd4_channel_attrs back_channel;
+ u32 callback_prog;
+ u32 uid;
+ u32 gid;
+};
+
+/* The single slot clientid cache structure */
+struct nfsd4_clid_slot {
+ u32 sl_seqid;
+ __be32 sl_status;
+ struct nfsd4_create_session sl_cr_ses;
+};
+
struct nfsd4_session {
struct kref se_ref;
struct list_head se_hash; /* hash by sessionid */
@@ -192,7 +212,7 @@ struct nfs4_client {
/* for nfs41 */
struct list_head cl_sessions;
- struct nfsd4_slot cl_slot; /* create_session slot */
+ struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */
u32 cl_exchange_flags;
struct nfs4_sessionid cl_sessionid;
};
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 2bacf7535069..5e4beb0deb80 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -366,18 +366,6 @@ struct nfsd4_exchange_id {
int spa_how;
};
-struct nfsd4_create_session {
- clientid_t clientid;
- struct nfs4_sessionid sessionid;
- u32 seqid;
- u32 flags;
- struct nfsd4_channel_attrs fore_channel;
- struct nfsd4_channel_attrs back_channel;
- u32 callback_prog;
- u32 uid;
- u32 gid;
-};
-
struct nfsd4_sequence {
struct nfs4_sessionid sessionid; /* request/response */
u32 seqid; /* request/response */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index dbea93b694e5..cb3dc6027fd9 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -242,6 +242,29 @@
* @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
* determined by the network interface.
*
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ * to identify the device, and the TESTDATA blob attribute to pass through
+ * to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ * requests to connect to a specified network but without separating
+ * auth and assoc steps. For this, you need to specify the SSID in a
+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ * It is also sent as an event, with the BSSID and response IEs when the
+ * connection is established or failed to be established. This can be
+ * determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ * sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ * userspace that a connection was dropped by the AP or due to other
+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ * %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ * associated with this wiphy must be down and will follow.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -310,6 +333,14 @@ enum nl80211_commands {
NL80211_CMD_JOIN_IBSS,
NL80211_CMD_LEAVE_IBSS,
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -511,6 +542,44 @@ enum nl80211_commands {
* authorized by user space. Otherwise, port is marked authorized by
* default in station mode.
*
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ * We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ * event was due to the AP disconnecting the station, and not due to
+ * a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ * event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ * that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ * indicate which unicast key ciphers will be used with the connection
+ * (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ * which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ * which WPA version(s) the AP we want to associate with is using
+ * (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ * which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ * sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ * commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ * and join_ibss(), key information is in a nested attribute each
+ * with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -619,6 +688,28 @@ enum nl80211_attrs {
NL80211_ATTR_CONTROL_PORT,
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -629,6 +720,7 @@ enum nl80211_attrs {
* Allow user space programs to use #ifdef on new attributes by defining them
* here
*/
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
@@ -642,6 +734,12 @@ enum nl80211_attrs {
#define NL80211_ATTR_SSID NL80211_ATTR_SSID
#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -650,6 +748,9 @@ enum nl80211_attrs {
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
+#define NL80211_MAX_NR_CIPHER_SUITES 5
+#define NL80211_MAX_NR_AKM_SUITES 2
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -1168,6 +1269,7 @@ enum nl80211_channel_type {
* in mBm (100 * dBm) (s32)
* @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_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -1181,6 +1283,7 @@ enum nl80211_bss {
NL80211_BSS_INFORMATION_ELEMENTS,
NL80211_BSS_SIGNAL_MBM,
NL80211_BSS_SIGNAL_UNSPEC,
+ NL80211_BSS_STATUS,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -1188,18 +1291,37 @@ enum nl80211_bss {
};
/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+ NL80211_BSS_STATUS_AUTHENTICATED,
+ NL80211_BSS_STATUS_ASSOCIATED,
+ NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
* enum nl80211_auth_type - AuthenticationType
*
* @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
* @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ * trying multiple times); this is invalid in netlink -- leave out
+ * the attribute for this on CONNECT commands.
*/
enum nl80211_auth_type {
NL80211_AUTHTYPE_OPEN_SYSTEM,
NL80211_AUTHTYPE_SHARED_KEY,
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
+
+ /* keep last */
+ __NL80211_AUTHTYPE_NUM,
+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+ NL80211_AUTHTYPE_AUTOMATIC
};
/**
@@ -1224,4 +1346,39 @@ enum nl80211_mfp {
NL80211_MFP_REQUIRED,
};
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h
index c9663c690303..53b94e025c7c 100644
--- a/include/linux/of_mdio.h
+++ b/include/linux/of_mdio.h
@@ -18,5 +18,8 @@ extern struct phy_device *of_phy_connect(struct net_device *dev,
struct device_node *phy_np,
void (*hndlr)(struct net_device *),
u32 flags, phy_interface_t iface);
+extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
+ void (*hndlr)(struct net_device *),
+ phy_interface_t iface);
#endif /* __LINUX_OF_MDIO_H */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 1d9518bc4c58..5171639ecf0f 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -67,6 +67,9 @@ struct oprofile_operations {
/* Initiate a stack backtrace. Optional. */
void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
+
+ /* Multiplex between different events. Optional. */
+ int (*switch_events)(void);
/* CPU identification string. */
char * cpu_type;
};
@@ -171,7 +174,6 @@ struct op_sample;
struct op_entry {
struct ring_buffer_event *event;
struct op_sample *sample;
- unsigned long irq_flags;
unsigned long size;
unsigned long *data;
};
@@ -180,6 +182,7 @@ void oprofile_write_reserve(struct op_entry *entry,
struct pt_regs * const regs,
unsigned long pc, int code, int size);
int oprofile_add_data(struct op_entry *entry, unsigned long val);
+int oprofile_add_data64(struct op_entry *entry, u64 val);
int oprofile_write_commit(struct op_entry *entry);
#endif /* OPROFILE_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 115fb7ba5089..bcc8ae5433bf 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -276,6 +276,7 @@ struct pci_dev {
unsigned int state_saved:1;
unsigned int is_physfn:1;
unsigned int is_virtfn:1;
+ unsigned int reset_fn:1;
pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device has been called */
@@ -834,7 +835,7 @@ struct msix_entry {
#ifndef CONFIG_PCI_MSI
static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
{
- return -1;
+ return -ENXIO;
}
static inline void pci_msi_shutdown(struct pci_dev *dev)
@@ -849,7 +850,7 @@ static inline int pci_msix_table_size(struct pci_dev *dev)
static inline int pci_enable_msix(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- return -1;
+ return -ENXIO;
}
static inline void pci_msix_shutdown(struct pci_dev *dev)
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index 68438e18fff4..aefc2f12b48c 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -10,22 +10,70 @@
/*
* Base implementations of per-CPU variable declarations and definitions, where
* the section in which the variable is to be placed is provided by the
- * 'section' argument. This may be used to affect the parameters governing the
+ * 'sec' argument. This may be used to affect the parameters governing the
* variable's storage.
*
* NOTE! The sections for the DECLARE and for the DEFINE must match, lest
* linkage errors occur due the compiler generating the wrong code to access
* that section.
*/
-#define DECLARE_PER_CPU_SECTION(type, name, section) \
- extern \
- __attribute__((__section__(PER_CPU_BASE_SECTION section))) \
- PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
-
-#define DEFINE_PER_CPU_SECTION(type, name, section) \
- __attribute__((__section__(PER_CPU_BASE_SECTION section))) \
- PER_CPU_ATTRIBUTES PER_CPU_DEF_ATTRIBUTES \
+#define __PCPU_ATTRS(sec) \
+ __attribute__((section(PER_CPU_BASE_SECTION sec))) \
+ PER_CPU_ATTRIBUTES
+
+#define __PCPU_DUMMY_ATTRS \
+ __attribute__((section(".discard"), unused))
+
+/*
+ * s390 and alpha modules require percpu variables to be defined as
+ * weak to force the compiler to generate GOT based external
+ * references for them. This is necessary because percpu sections
+ * will be located outside of the usually addressable area.
+ *
+ * This definition puts the following two extra restrictions when
+ * defining percpu variables.
+ *
+ * 1. The symbol must be globally unique, even the static ones.
+ * 2. Static percpu variables cannot be defined inside a function.
+ *
+ * Archs which need weak percpu definitions should define
+ * ARCH_NEEDS_WEAK_PER_CPU in asm/percpu.h when necessary.
+ *
+ * To ensure that the generic code observes the above two
+ * restrictions, if CONFIG_DEBUG_FORCE_WEAK_PER_CPU is set weak
+ * definition is used for all cases.
+ */
+#if defined(ARCH_NEEDS_WEAK_PER_CPU) || defined(CONFIG_DEBUG_FORCE_WEAK_PER_CPU)
+/*
+ * __pcpu_scope_* dummy variable is used to enforce scope. It
+ * receives the static modifier when it's used in front of
+ * DEFINE_PER_CPU() and will trigger build failure if
+ * DECLARE_PER_CPU() is used for the same variable.
+ *
+ * __pcpu_unique_* dummy variable is used to enforce symbol uniqueness
+ * such that hidden weak symbol collision, which will cause unrelated
+ * variables to share the same address, can be detected during build.
+ */
+#define DECLARE_PER_CPU_SECTION(type, name, sec) \
+ extern __PCPU_DUMMY_ATTRS char __pcpu_scope_##name; \
+ extern __PCPU_ATTRS(sec) __typeof__(type) per_cpu__##name
+
+#define DEFINE_PER_CPU_SECTION(type, name, sec) \
+ __PCPU_DUMMY_ATTRS char __pcpu_scope_##name; \
+ __PCPU_DUMMY_ATTRS char __pcpu_unique_##name; \
+ __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES __weak \
+ __typeof__(type) per_cpu__##name
+#else
+/*
+ * Normal declaration and definition macros.
+ */
+#define DECLARE_PER_CPU_SECTION(type, name, sec) \
+ extern __PCPU_ATTRS(sec) __typeof__(type) per_cpu__##name
+
+#define DEFINE_PER_CPU_SECTION(type, name, sec) \
+ __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES \
__typeof__(type) per_cpu__##name
+#endif
/*
* Variant on the per-CPU variable declaration/definition theme used for
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 26fd9d12f050..e134c8229631 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -34,7 +34,7 @@
#ifdef CONFIG_SMP
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
/* minimum unit size, also is the maximum supported allocation size */
#define PCPU_MIN_UNIT_SIZE PFN_ALIGN(64 << 10)
@@ -57,19 +57,73 @@
#endif
extern void *pcpu_base_addr;
+extern const int *pcpu_unit_map;
-typedef struct page * (*pcpu_get_page_fn_t)(unsigned int cpu, int pageno);
-typedef void (*pcpu_populate_pte_fn_t)(unsigned long addr);
+typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size);
+typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size);
+typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr);
+typedef int (pcpu_fc_cpu_distance_fn_t)(unsigned int from, unsigned int to);
+typedef void (*pcpu_fc_map_fn_t)(void *ptr, size_t size, void *addr);
-extern size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
+extern size_t __init pcpu_setup_first_chunk(
size_t static_size, size_t reserved_size,
- ssize_t dyn_size, ssize_t unit_size,
- void *base_addr,
- pcpu_populate_pte_fn_t populate_pte_fn);
+ ssize_t dyn_size, size_t unit_size,
+ void *base_addr, const int *unit_map);
extern ssize_t __init pcpu_embed_first_chunk(
size_t static_size, size_t reserved_size,
- ssize_t dyn_size, ssize_t unit_size);
+ ssize_t dyn_size);
+
+extern ssize_t __init pcpu_4k_first_chunk(
+ size_t static_size, size_t reserved_size,
+ pcpu_fc_alloc_fn_t alloc_fn,
+ pcpu_fc_free_fn_t free_fn,
+ pcpu_fc_populate_pte_fn_t populate_pte_fn);
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+extern int __init pcpu_lpage_build_unit_map(
+ size_t static_size, size_t reserved_size,
+ ssize_t *dyn_sizep, size_t *unit_sizep,
+ size_t lpage_size, int *unit_map,
+ pcpu_fc_cpu_distance_fn_t cpu_distance_fn);
+
+extern ssize_t __init pcpu_lpage_first_chunk(
+ size_t static_size, size_t reserved_size,
+ size_t dyn_size, size_t unit_size,
+ size_t lpage_size, const int *unit_map,
+ int nr_units,
+ pcpu_fc_alloc_fn_t alloc_fn,
+ pcpu_fc_free_fn_t free_fn,
+ pcpu_fc_map_fn_t map_fn);
+
+extern void *pcpu_lpage_remapped(void *kaddr);
+#else
+static inline int pcpu_lpage_build_unit_map(
+ size_t static_size, size_t reserved_size,
+ ssize_t *dyn_sizep, size_t *unit_sizep,
+ size_t lpage_size, int *unit_map,
+ pcpu_fc_cpu_distance_fn_t cpu_distance_fn)
+{
+ return -EINVAL;
+}
+
+static inline ssize_t __init pcpu_lpage_first_chunk(
+ size_t static_size, size_t reserved_size,
+ size_t dyn_size, size_t unit_size,
+ size_t lpage_size, const int *unit_map,
+ int nr_units,
+ pcpu_fc_alloc_fn_t alloc_fn,
+ pcpu_fc_free_fn_t free_fn,
+ pcpu_fc_map_fn_t map_fn)
+{
+ return -EINVAL;
+}
+
+static inline void *pcpu_lpage_remapped(void *kaddr)
+{
+ return NULL;
+}
+#endif
/*
* Use this to get to a cpu's version of the per-cpu object
@@ -80,7 +134,7 @@ extern ssize_t __init pcpu_embed_first_chunk(
extern void *__alloc_reserved_percpu(size_t size, size_t align);
-#else /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
struct percpu_data {
void *ptrs[1];
@@ -99,11 +153,15 @@ struct percpu_data {
(__typeof__(ptr))__p->ptrs[(cpu)]; \
})
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
extern void *__alloc_percpu(size_t size, size_t align);
extern void free_percpu(void *__pdata);
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+extern void __init setup_per_cpu_areas(void);
+#endif
+
#else /* CONFIG_SMP */
#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
@@ -124,6 +182,13 @@ static inline void free_percpu(void *p)
kfree(p);
}
+static inline void __init setup_per_cpu_areas(void) { }
+
+static inline void *pcpu_lpage_remapped(void *kaddr)
+{
+ return NULL;
+}
+
#endif /* CONFIG_SMP */
#define alloc_percpu(type) (type *)__alloc_percpu(sizeof(type), \
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 8dc5123b6305..3c6675c2444b 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -22,6 +22,9 @@ struct platform_device {
struct resource * resource;
struct platform_device_id *id_entry;
+
+ /* arch specific additions */
+ struct pdev_archdata archdata;
};
#define platform_get_device_id(pdev) ((pdev)->id_entry)
@@ -57,8 +60,6 @@ struct platform_driver {
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
- int (*suspend_late)(struct platform_device *, pm_message_t state);
- int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
struct platform_device_id *id_table;
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 6729f7dcd60e..229322707f5f 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -2,13 +2,25 @@
#define _LINUX_POISON_H
/********** include/linux/list.h **********/
+
+/*
+ * Architectures might want to move the poison pointer offset
+ * into some well-recognized area such as 0xdead000000000000,
+ * that is also not mappable by user-space exploits:
+ */
+#ifdef CONFIG_ILLEGAL_POINTER_VALUE
+# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
+#else
+# define POISON_POINTER_DELTA 0
+#endif
+
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
+#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
/********** include/linux/timer.h **********/
/*
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 594c494ac3f0..b5d096d3a9be 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -39,6 +39,13 @@ enum {
};
enum {
+ POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0,
+ POWER_SUPPLY_CHARGE_TYPE_NONE,
+ POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
+ POWER_SUPPLY_CHARGE_TYPE_FAST,
+};
+
+enum {
POWER_SUPPLY_HEALTH_UNKNOWN = 0,
POWER_SUPPLY_HEALTH_GOOD,
POWER_SUPPLY_HEALTH_OVERHEAT,
@@ -58,9 +65,19 @@ enum {
POWER_SUPPLY_TECHNOLOGY_LiMn,
};
+enum {
+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_LOW,
+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
+ POWER_SUPPLY_CAPACITY_LEVEL_FULL,
+};
+
enum power_supply_property {
/* Properties of type `int' */
POWER_SUPPLY_PROP_STATUS = 0,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
@@ -89,6 +106,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_ENERGY_AVG,
POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
@@ -126,6 +144,7 @@ struct power_supply {
enum power_supply_property psp,
union power_supply_propval *val);
void (*external_power_changed)(struct power_supply *psy);
+ void (*set_charged)(struct power_supply *psy);
/* For APM emulation, think legacy userspace. */
int use_for_apm;
@@ -165,8 +184,10 @@ struct power_supply_info {
int use_for_apm;
};
+extern struct power_supply *power_supply_get_by_name(char *name);
extern void power_supply_changed(struct power_supply *psy);
extern int power_supply_am_i_supplied(struct power_supply *psy);
+extern int power_supply_set_battery_charged(struct power_supply *psy);
#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
extern int power_supply_is_system_supplied(void);
diff --git a/include/linux/pps.h b/include/linux/pps.h
index cfe5c7214ec6..0194ab06177b 100644
--- a/include/linux/pps.h
+++ b/include/linux/pps.h
@@ -22,6 +22,8 @@
#ifndef _PPS_H_
#define _PPS_H_
+#include <linux/types.h>
+
#define PPS_VERSION "5.3.6"
#define PPS_MAX_SOURCES 16 /* should be enough... */
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/rcuclassic.h b/include/linux/rcuclassic.h
deleted file mode 100644
index bfd92e1e5d2c..000000000000
--- a/include/linux/rcuclassic.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Read-Copy Update mechanism for mutual exclusion (classic version)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright IBM Corporation, 2001
- *
- * Author: Dipankar Sarma <dipankar@in.ibm.com>
- *
- * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
- * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
- * Papers:
- * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
- * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
- *
- * For detailed explanation of Read-Copy Update mechanism see -
- * Documentation/RCU
- *
- */
-
-#ifndef __LINUX_RCUCLASSIC_H
-#define __LINUX_RCUCLASSIC_H
-
-#include <linux/cache.h>
-#include <linux/spinlock.h>
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/seqlock.h>
-
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-#define RCU_SECONDS_TILL_STALL_CHECK (10 * HZ) /* for rcp->jiffies_stall */
-#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ) /* for rcp->jiffies_stall */
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
-/* Global control variables for rcupdate callback mechanism. */
-struct rcu_ctrlblk {
- long cur; /* Current batch number. */
- long completed; /* Number of the last completed batch */
- long pending; /* Number of the last pending batch */
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
- unsigned long gp_start; /* Time at which GP started in jiffies. */
- unsigned long jiffies_stall;
- /* Time at which to check for CPU stalls. */
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
- int signaled;
-
- spinlock_t lock ____cacheline_internodealigned_in_smp;
- DECLARE_BITMAP(cpumask, NR_CPUS); /* CPUs that need to switch for */
- /* current batch to proceed. */
-} ____cacheline_internodealigned_in_smp;
-
-/* Is batch a before batch b ? */
-static inline int rcu_batch_before(long a, long b)
-{
- return (a - b) < 0;
-}
-
-/* Is batch a after batch b ? */
-static inline int rcu_batch_after(long a, long b)
-{
- return (a - b) > 0;
-}
-
-/* Per-CPU data for Read-Copy UPdate. */
-struct rcu_data {
- /* 1) quiescent state handling : */
- long quiescbatch; /* Batch # for grace period */
- int passed_quiesc; /* User-mode/idle loop etc. */
- int qs_pending; /* core waits for quiesc state */
-
- /* 2) batch handling */
- /*
- * if nxtlist is not NULL, then:
- * batch:
- * The batch # for the last entry of nxtlist
- * [*nxttail[1], NULL = *nxttail[2]):
- * Entries that batch # <= batch
- * [*nxttail[0], *nxttail[1]):
- * Entries that batch # <= batch - 1
- * [nxtlist, *nxttail[0]):
- * Entries that batch # <= batch - 2
- * The grace period for these entries has completed, and
- * the other grace-period-completed entries may be moved
- * here temporarily in rcu_process_callbacks().
- */
- long batch;
- struct rcu_head *nxtlist;
- struct rcu_head **nxttail[3];
- long qlen; /* # of queued callbacks */
- struct rcu_head *donelist;
- struct rcu_head **donetail;
- long blimit; /* Upper limit on a processed batch */
- int cpu;
- struct rcu_head barrier;
-};
-
-/*
- * Increment the quiescent state counter.
- * The counter is a bit degenerated: We do not need to know
- * how many quiescent states passed, just if there was at least
- * one since the start of the grace period. Thus just a flag.
- */
-extern void rcu_qsctr_inc(int cpu);
-extern void rcu_bh_qsctr_inc(int cpu);
-
-extern int rcu_pending(int cpu);
-extern int rcu_needs_cpu(int cpu);
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-extern struct lockdep_map rcu_lock_map;
-# define rcu_read_acquire() \
- lock_acquire(&rcu_lock_map, 0, 0, 2, 1, NULL, _THIS_IP_)
-# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_)
-#else
-# define rcu_read_acquire() do { } while (0)
-# define rcu_read_release() do { } while (0)
-#endif
-
-#define __rcu_read_lock() \
- do { \
- preempt_disable(); \
- __acquire(RCU); \
- rcu_read_acquire(); \
- } while (0)
-#define __rcu_read_unlock() \
- do { \
- rcu_read_release(); \
- __release(RCU); \
- preempt_enable(); \
- } while (0)
-#define __rcu_read_lock_bh() \
- do { \
- local_bh_disable(); \
- __acquire(RCU_BH); \
- rcu_read_acquire(); \
- } while (0)
-#define __rcu_read_unlock_bh() \
- do { \
- rcu_read_release(); \
- __release(RCU_BH); \
- local_bh_enable(); \
- } while (0)
-
-#define __synchronize_sched() synchronize_rcu()
-
-#define call_rcu_sched(head, func) call_rcu(head, func)
-
-extern void __rcu_init(void);
-#define rcu_init_sched() do { } while (0)
-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);
-
-#define rcu_enter_nohz() do { } while (0)
-#define rcu_exit_nohz() do { } while (0)
-
-/* A context switch is a grace period for rcuclassic. */
-static inline int rcu_blocking_is_gp(void)
-{
- return num_online_cpus() == 1;
-}
-
-#endif /* __LINUX_RCUCLASSIC_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 15fbb3ca634d..f8cad2b20778 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,22 +42,22 @@
#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 */
+extern void synchronize_rcu(void);
+extern void synchronize_rcu_bh(void);
+extern void rcu_barrier(void);
+extern void rcu_barrier_bh(void);
+extern void rcu_barrier_sched(void);
+extern void synchronize_sched_expedited(void);
+extern int sched_expedited_torture_stats(char *page);
-/* Internal to kernel, but needed by rcupreempt.h. */
+/* Internal to kernel */
+extern void rcu_init(void);
+extern void rcu_scheduler_starting(void);
+extern int rcu_needs_cpu(int cpu);
extern int rcu_scheduler_active;
-#if defined(CONFIG_CLASSIC_RCU)
-#include <linux/rcuclassic.h>
-#elif defined(CONFIG_TREE_RCU)
+#if defined(CONFIG_TREE_RCU)
#include <linux/rcutree.h>
#elif defined(CONFIG_PREEMPT_RCU)
#include <linux/rcupreempt.h>
@@ -259,15 +260,4 @@ extern void call_rcu(struct rcu_head *head,
extern void call_rcu_bh(struct rcu_head *head,
void (*func)(struct rcu_head *head));
-/* Exported common interfaces */
-extern void synchronize_rcu(void);
-extern void rcu_barrier(void);
-extern void rcu_barrier_bh(void);
-extern void rcu_barrier_sched(void);
-
-/* Internal to kernel */
-extern void rcu_init(void);
-extern void rcu_scheduler_starting(void);
-extern int rcu_needs_cpu(int cpu);
-
#endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
index fce522782ffa..f164ac9b7807 100644
--- a/include/linux/rcupreempt.h
+++ b/include/linux/rcupreempt.h
@@ -74,6 +74,16 @@ extern int rcu_needs_cpu(int cpu);
extern void __synchronize_sched(void);
+static inline void synchronize_rcu_expedited(void)
+{
+ synchronize_rcu(); /* Placeholder for new rcupreempt implementation. */
+}
+
+static inline void synchronize_rcu_bh_expedited(void)
+{
+ synchronize_rcu_bh(); /* Placeholder for new rcupreempt impl. */
+}
+
extern void __rcu_init(void);
extern void rcu_init_sched(void);
extern void rcu_check_callbacks(int cpu, int user);
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 5a5153806c42..d4dfd2489633 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -286,8 +286,14 @@ static inline void __rcu_read_unlock_bh(void)
#define call_rcu_sched(head, func) call_rcu(head, func)
-static inline void rcu_init_sched(void)
+static inline void synchronize_rcu_expedited(void)
+{
+ synchronize_sched_expedited();
+}
+
+static inline void synchronize_rcu_bh_expedited(void)
{
+ synchronize_sched_expedited();
}
extern void __rcu_init(void);
@@ -297,6 +303,10 @@ extern void rcu_restart_cpu(int cpu);
extern long rcu_batches_completed(void);
extern long rcu_batches_completed_bh(void);
+static inline void rcu_init_sched(void)
+{
+}
+
#ifdef CONFIG_NO_HZ
void rcu_enter_nohz(void);
void rcu_exit_nohz(void);
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 277f4b964df5..490c5b37b6d7 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -125,6 +125,8 @@ struct regulator_bulk_data {
/* regulator get and put */
struct regulator *__must_check regulator_get(struct device *dev,
const char *id);
+struct regulator *__must_check regulator_get_exclusive(struct device *dev,
+ const char *id);
void regulator_put(struct regulator *regulator);
/* regulator output control and status */
@@ -144,6 +146,8 @@ void regulator_bulk_free(int num_consumers,
int regulator_count_voltages(struct regulator *regulator);
int regulator_list_voltage(struct regulator *regulator, unsigned selector);
+int regulator_is_supported_voltage(struct regulator *regulator,
+ int min_uV, int max_uV);
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
int regulator_get_voltage(struct regulator *regulator);
int regulator_set_current_limit(struct regulator *regulator,
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 225f733e7533..73c9cd6cda7d 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -162,6 +162,8 @@ struct regulator_desc {
struct regulator_dev {
struct regulator_desc *desc;
int use_count;
+ int open_count;
+ int exclusive;
/* lists we belong to */
struct list_head list; /* list of all regulators */
@@ -193,6 +195,8 @@ void *rdev_get_drvdata(struct regulator_dev *rdev);
struct device *rdev_get_dev(struct regulator_dev *rdev);
int rdev_get_id(struct regulator_dev *rdev);
+int regulator_mode_to_status(unsigned int);
+
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
#endif
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index bac64fa390f2..99a4e2eb36aa 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -126,16 +126,28 @@ struct regulation_constraints {
/**
* struct regulator_consumer_supply - supply -> device mapping
*
- * This maps a supply name to a device.
+ * This maps a supply name to a device. Only one of dev or dev_name
+ * can be specified. Use of dev_name allows support for buses which
+ * make struct device available late such as I2C and is the preferred
+ * form.
*
* @dev: Device structure for the consumer.
+ * @dev_name: Result of dev_name() for the consumer.
* @supply: Name for the supply.
*/
struct regulator_consumer_supply {
struct device *dev; /* consumer */
+ const char *dev_name; /* dev_name() for consumer */
const char *supply; /* consumer supply - e.g. "vcc" */
};
+/* Initialize struct regulator_consumer_supply */
+#define REGULATOR_SUPPLY(_name, _dev_name) \
+{ \
+ .supply = _name, \
+ .dev_name = _dev_name, \
+}
+
/**
* struct regulator_init_data - regulator platform initialisation data.
*
@@ -166,6 +178,12 @@ struct regulator_init_data {
int regulator_suspend_prepare(suspend_state_t state);
+#ifdef CONFIG_REGULATOR
void regulator_has_full_constraints(void);
+#else
+static inline void regulator_has_full_constraints(void)
+{
+}
+#endif
#endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index dd31e7bae35c..a498d9266d8c 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 */
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/rfkill.h b/include/linux/rfkill.h
index 2ce29831feb6..10202903141a 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -82,6 +82,20 @@ struct rfkill_event {
__u8 soft, hard;
} __packed;
+/*
+ * We are planning to be backward and forward compatible with changes
+ * to the event struct, by adding new, optional, members at the end.
+ * When reading an event (whether the kernel from userspace or vice
+ * versa) we need to accept anything that's at least as large as the
+ * version 1 event size, but might be able to accept other sizes in
+ * the future.
+ *
+ * One exception is the kernel -- we already have two event sizes in
+ * that we've made the 'hard' member optional since our only option
+ * is to ignore it anyway.
+ */
+#define RFKILL_EVENT_SIZE_V1 8
+
/* ioctl for turning off rfkill-input (if present) */
#define RFKILL_IOC_MAGIC 'R'
#define RFKILL_IOC_NOINPUT 1
@@ -224,7 +238,7 @@ void rfkill_destroy(struct rfkill *rfkill);
* should be blocked) so that drivers need not keep track of the soft
* block state -- which they might not be able to.
*/
-bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
+bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
/**
* rfkill_set_sw_state - Set the internal rfkill software block state
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index e5996984ddd0..9aaf5bfdad1a 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -242,6 +242,8 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
*/
#define SG_MITER_ATOMIC (1 << 0) /* use kmap_atomic */
+#define SG_MITER_TO_SG (1 << 1) /* flush back to phys on unmap */
+#define SG_MITER_FROM_SG (1 << 2) /* nop */
struct sg_mapping_iter {
/* the following three fields can be accessed directly */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3ab08e4bb6b8..dcdcc1e635cc 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -38,6 +38,8 @@
#define SCHED_BATCH 3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE 5
+/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
+#define SCHED_RESET_ON_FORK 0x40000000
#ifdef __KERNEL__
@@ -300,6 +302,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,
struct file *filp, void __user *buffer,
@@ -313,6 +316,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)
{
}
@@ -1229,6 +1235,10 @@ struct task_struct {
unsigned did_exec:1;
unsigned in_execve:1; /* Tell the LSMs that the process is doing an
* execve */
+
+ /* Revert to default priority/policy when forking */
+ unsigned sched_reset_on_fork:1;
+
pid_t pid;
pid_t tgid;
@@ -2076,7 +2086,7 @@ static inline unsigned long wait_task_inactive(struct task_struct *p,
#define for_each_process(p) \
for (p = &init_task ; (p = next_task(p)) != &init_task ; )
-extern bool is_single_threaded(struct task_struct *);
+extern bool current_is_single_threaded(void);
/*
* Careful: do_each_thread/while_each_thread is a double loop so
diff --git a/include/linux/security.h b/include/linux/security.h
index 5eff459b3833..145909165dbf 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -52,7 +52,7 @@ struct audit_krule;
extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
int cap, int audit);
extern int cap_settime(struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
+extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset(struct cred *new, const struct cred *old,
@@ -1209,7 +1209,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @alter contains the flag indicating whether changes are to be made.
* Return 0 if permission is granted.
*
- * @ptrace_may_access:
+ * @ptrace_access_check:
* Check permission before allowing the current process to trace the
* @child process.
* Security modules may also want to perform a process tracing check
@@ -1224,7 +1224,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Check that the @parent process has sufficient permission to trace the
* current process before allowing the current process to present itself
* to the @parent process for tracing.
- * The parent process will still have to undergo the ptrace_may_access
+ * The parent process will still have to undergo the ptrace_access_check
* checks before it is allowed to trace this one.
* @parent contains the task_struct structure for debugger process.
* Return 0 if permission is granted.
@@ -1336,7 +1336,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
- int (*ptrace_may_access) (struct task_struct *child, unsigned int mode);
+ int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
int (*ptrace_traceme) (struct task_struct *parent);
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
@@ -1617,7 +1617,7 @@ extern int security_module_enable(struct security_operations *ops);
extern int register_security(struct security_operations *ops);
/* Security operations */
-int security_ptrace_may_access(struct task_struct *child, unsigned int mode);
+int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
int security_ptrace_traceme(struct task_struct *parent);
int security_capget(struct task_struct *target,
kernel_cap_t *effective,
@@ -1798,10 +1798,10 @@ static inline int security_init(void)
return 0;
}
-static inline int security_ptrace_may_access(struct task_struct *child,
+static inline int security_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- return cap_ptrace_may_access(child, mode);
+ return cap_ptrace_access_check(child, mode);
}
static inline int security_ptrace_traceme(struct task_struct *parent)
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 126d24c9eaa8..a640bc2afe76 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -31,8 +31,6 @@ struct serio {
bool manual_bind;
bool registered; /* port has been fully registered with driver core */
- bool suspended; /* port is suspended */
-
struct serio_device_id id;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f2c69a2cca17..df7b23ac66e6 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -304,7 +304,6 @@ typedef unsigned char *sk_buff_data_t;
* @tc_index: Traffic control index
* @tc_verd: traffic control verdict
* @ndisc_nodetype: router type (from link layer)
- * @do_not_encrypt: set to prevent encryption of this frame
* @dma_cookie: a cookie to one of several possible DMA operations
* done by skb DMA functions
* @secmark: security marking
@@ -380,12 +379,9 @@ struct sk_buff {
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif
-#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
- __u8 do_not_encrypt:1;
-#endif
kmemcheck_bitfield_end(flags2);
- /* 0/13/14 bit hole */
+ /* 0/14 bit hole */
#ifdef CONFIG_NET_DMA
dma_cookie_t dma_cookie;
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2da8372519f5..62d2b16d9ff2 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -74,6 +74,10 @@
/* The following flags affect the page allocator grouping pages by mobility */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
+
+/* Following flags should only be used by allocator specific flags */
+#define SLAB_ALLOC_PRIVATE 0x000000ffUL
+
/*
* ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
*
@@ -160,6 +164,8 @@ size_t ksize(const void *);
*/
#ifdef CONFIG_SLUB
#include <linux/slub_def.h>
+#elif defined(CONFIG_SLQB)
+#include <linux/slqb_def.h>
#elif defined(CONFIG_SLOB)
#include <linux/slob_def.h>
#else
@@ -262,7 +268,7 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
* allocator where we care about the real place the memory allocation
* request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || defined(CONFIG_SLQB_DEBUG)
extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
#define kmalloc_track_caller(size, flags) \
__kmalloc_track_caller(size, flags, _RET_IP_)
@@ -280,7 +286,7 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
* standard allocator where we care about the real place the memory
* allocation request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || defined(CONFIG_SLQB_DEBUG)
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);
#define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \
diff --git a/include/linux/slqb_def.h b/include/linux/slqb_def.h
new file mode 100644
index 000000000000..1243dda50473
--- /dev/null
+++ b/include/linux/slqb_def.h
@@ -0,0 +1,301 @@
+#ifndef _LINUX_SLQB_DEF_H
+#define _LINUX_SLQB_DEF_H
+
+/*
+ * SLQB : A slab allocator with object queues.
+ *
+ * (C) 2008 Nick Piggin <npiggin@suse.de>
+ */
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/rcu_types.h>
+#include <linux/mm_types.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+
+#define SLAB_NUMA 0x00000001UL /* shortcut */
+
+enum stat_item {
+ ALLOC, /* Allocation count */
+ ALLOC_SLAB_FILL, /* Fill freelist from page list */
+ ALLOC_SLAB_NEW, /* New slab acquired from page allocator */
+ FREE, /* Free count */
+ FREE_REMOTE, /* NUMA: freeing to remote list */
+ FLUSH_FREE_LIST, /* Freelist flushed */
+ FLUSH_FREE_LIST_OBJECTS, /* Objects flushed from freelist */
+ FLUSH_FREE_LIST_REMOTE, /* Objects flushed from freelist to remote */
+ FLUSH_SLAB_PARTIAL, /* Freeing moves slab to partial list */
+ FLUSH_SLAB_FREE, /* Slab freed to the page allocator */
+ FLUSH_RFREE_LIST, /* Rfree list flushed */
+ FLUSH_RFREE_LIST_OBJECTS, /* Rfree objects flushed */
+ CLAIM_REMOTE_LIST, /* Remote freed list claimed */
+ CLAIM_REMOTE_LIST_OBJECTS, /* Remote freed objects claimed */
+ NR_SLQB_STAT_ITEMS
+};
+
+/*
+ * Singly-linked list with head, tail, and nr
+ */
+struct kmlist {
+ unsigned long nr;
+ void **head;
+ void **tail;
+};
+
+/*
+ * Every kmem_cache_list has a kmem_cache_remote_free structure, by which
+ * objects can be returned to the kmem_cache_list from remote CPUs.
+ */
+struct kmem_cache_remote_free {
+ spinlock_t lock;
+ struct kmlist list;
+} ____cacheline_aligned;
+
+/*
+ * A kmem_cache_list manages all the slabs and objects allocated from a given
+ * source. Per-cpu kmem_cache_lists allow node-local allocations. Per-node
+ * kmem_cache_lists allow off-node allocations (but require locking).
+ */
+struct kmem_cache_list {
+ /* Fastpath LIFO freelist of objects */
+ struct kmlist freelist;
+#ifdef CONFIG_SMP
+ /* remote_free has reached a watermark */
+ int remote_free_check;
+#endif
+ /* kmem_cache corresponding to this list */
+ struct kmem_cache *cache;
+
+ /* Number of partial slabs (pages) */
+ unsigned long nr_partial;
+
+ /* Slabs which have some free objects */
+ struct list_head partial;
+
+ /* Total number of slabs allocated */
+ unsigned long nr_slabs;
+
+ /* Protects nr_partial, nr_slabs, and partial */
+ spinlock_t page_lock;
+
+#ifdef CONFIG_SMP
+ /*
+ * In the case of per-cpu lists, remote_free is for objects freed by
+ * non-owner CPU back to its home list. For per-node lists, remote_free
+ * is always used to free objects.
+ */
+ struct kmem_cache_remote_free remote_free;
+#endif
+
+#ifdef CONFIG_SLQB_STATS
+ unsigned long stats[NR_SLQB_STAT_ITEMS];
+#endif
+} ____cacheline_aligned;
+
+/*
+ * Primary per-cpu, per-kmem_cache structure.
+ */
+struct kmem_cache_cpu {
+ struct kmem_cache_list list; /* List for node-local slabs */
+ unsigned int colour_next; /* Next colour offset to use */
+
+#ifdef CONFIG_SMP
+ /*
+ * rlist is a list of objects that don't fit on list.freelist (ie.
+ * wrong node). The objects all correspond to a given kmem_cache_list,
+ * remote_cache_list. To free objects to another list, we must first
+ * flush the existing objects, then switch remote_cache_list.
+ *
+ * An NR_CPUS or MAX_NUMNODES array would be nice here, but then we
+ * get to O(NR_CPUS^2) memory consumption situation.
+ */
+ struct kmlist rlist;
+ struct kmem_cache_list *remote_cache_list;
+#endif
+} ____cacheline_aligned_in_smp;
+
+/*
+ * Per-node, per-kmem_cache structure. Used for node-specific allocations.
+ */
+struct kmem_cache_node {
+ struct kmem_cache_list list;
+ spinlock_t list_lock; /* protects access to list */
+} ____cacheline_aligned;
+
+/*
+ * Management object for a slab cache.
+ */
+struct kmem_cache {
+ unsigned long flags;
+ int hiwater; /* LIFO list high watermark */
+ int freebatch; /* LIFO freelist batch flush size */
+#ifdef CONFIG_SMP
+ struct kmem_cache_cpu **cpu_slab; /* dynamic per-cpu structures */
+#else
+ struct kmem_cache_cpu cpu_slab;
+#endif
+ int objsize; /* Size of object without meta data */
+ int offset; /* Free pointer offset. */
+ int objects; /* Number of objects in slab */
+
+#ifdef CONFIG_NUMA
+ struct kmem_cache_node **node_slab; /* dynamic per-node structures */
+#endif
+
+ int size; /* Size of object including meta data */
+ int order; /* Allocation order */
+ gfp_t allocflags; /* gfp flags to use on allocation */
+ unsigned int colour_range; /* range of colour counter */
+ unsigned int colour_off; /* offset per colour */
+ void (*ctor)(void *);
+
+ const char *name; /* Name (only for display!) */
+ struct list_head list; /* List of slab caches */
+
+ int align; /* Alignment */
+ int inuse; /* Offset to metadata */
+
+#ifdef CONFIG_SLQB_SYSFS
+ struct kobject kobj; /* For sysfs */
+#endif
+} ____cacheline_aligned;
+
+/*
+ * Kmalloc subsystem.
+ */
+#if defined(ARCH_KMALLOC_MINALIGN) && ARCH_KMALLOC_MINALIGN > 8
+#define KMALLOC_MIN_SIZE ARCH_KMALLOC_MINALIGN
+#else
+#define KMALLOC_MIN_SIZE 8
+#endif
+
+#define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
+#define KMALLOC_SHIFT_SLQB_HIGH (PAGE_SHIFT + \
+ ((9 <= (MAX_ORDER - 1)) ? 9 : (MAX_ORDER - 1)))
+
+extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_SLQB_HIGH + 1];
+extern struct kmem_cache kmalloc_caches_dma[KMALLOC_SHIFT_SLQB_HIGH + 1];
+
+/*
+ * Constant size allocations use this path to find index into kmalloc caches
+ * arrays. get_slab() function is used for non-constant sizes.
+ */
+static __always_inline int kmalloc_index(size_t size)
+{
+ extern int ____kmalloc_too_large(void);
+
+ if (unlikely(size <= KMALLOC_MIN_SIZE))
+ return KMALLOC_SHIFT_LOW;
+
+#if L1_CACHE_BYTES < 64
+ if (size > 64 && size <= 96)
+ return 1;
+#endif
+#if L1_CACHE_BYTES < 128
+ if (size > 128 && size <= 192)
+ return 2;
+#endif
+ if (size <= 8) return 3;
+ if (size <= 16) return 4;
+ if (size <= 32) return 5;
+ if (size <= 64) return 6;
+ if (size <= 128) return 7;
+ if (size <= 256) return 8;
+ if (size <= 512) return 9;
+ if (size <= 1024) return 10;
+ if (size <= 2 * 1024) return 11;
+ if (size <= 4 * 1024) return 12;
+ if (size <= 8 * 1024) return 13;
+ if (size <= 16 * 1024) return 14;
+ if (size <= 32 * 1024) return 15;
+ if (size <= 64 * 1024) return 16;
+ if (size <= 128 * 1024) return 17;
+ if (size <= 256 * 1024) return 18;
+ if (size <= 512 * 1024) return 19;
+ if (size <= 1024 * 1024) return 20;
+ if (size <= 2 * 1024 * 1024) return 21;
+ if (size <= 4 * 1024 * 1024) return 22;
+ if (size <= 8 * 1024 * 1024) return 23;
+ if (size <= 16 * 1024 * 1024) return 24;
+ if (size <= 32 * 1024 * 1024) return 25;
+ return ____kmalloc_too_large();
+}
+
+#ifdef CONFIG_ZONE_DMA
+#define SLQB_DMA __GFP_DMA
+#else
+/* Disable "DMA slabs" */
+#define SLQB_DMA (__force gfp_t)0
+#endif
+
+/*
+ * Find the kmalloc slab cache for a given combination of allocation flags and
+ * size. Should really only be used for constant 'size' arguments, due to
+ * bloat.
+ */
+static __always_inline struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
+{
+ int index;
+
+ if (unlikely(size > 1UL << KMALLOC_SHIFT_SLQB_HIGH))
+ return NULL;
+ if (unlikely(!size))
+ return ZERO_SIZE_PTR;
+
+ index = kmalloc_index(size);
+ if (likely(!(flags & SLQB_DMA)))
+ return &kmalloc_caches[index];
+ else
+ return &kmalloc_caches_dma[index];
+}
+
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+void *__kmalloc(size_t size, gfp_t flags);
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#define KMALLOC_HEADER (ARCH_KMALLOC_MINALIGN < sizeof(void *) ? \
+ sizeof(void *) : ARCH_KMALLOC_MINALIGN)
+
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size)) {
+ struct kmem_cache *s;
+
+ s = kmalloc_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return kmem_cache_alloc(s, flags);
+ }
+ return __kmalloc(size, flags);
+}
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node);
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+
+static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ if (__builtin_constant_p(size)) {
+ struct kmem_cache *s;
+
+ s = kmalloc_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return kmem_cache_alloc_node(s, flags, node);
+ }
+ return __kmalloc_node(size, flags, node);
+}
+#endif
+
+#endif /* _LINUX_SLQB_DEF_H */
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 9e3d8af09207..39c64bae776d 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -73,15 +73,6 @@ int smp_call_function(void(*func)(void *info), void *info, int wait);
void smp_call_function_many(const struct cpumask *mask,
void (*func)(void *info), void *info, bool wait);
-/* Deprecated: Use smp_call_function_many which takes a pointer to the mask. */
-static inline int
-smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
- int wait)
-{
- smp_call_function_many(&mask, func, info, wait);
- return 0;
-}
-
void __smp_call_function_single(int cpuid, struct call_single_data *data,
int wait);
@@ -144,8 +135,6 @@ static inline int up_smp_call_function(void (*func)(void *), void *info)
static inline void smp_send_reschedule(int cpu) { }
#define num_booting_cpus() 1
#define smp_prepare_boot_cpu() do {} while (0)
-#define smp_call_function_mask(mask, func, info, wait) \
- (up_smp_call_function(func, info))
#define smp_call_function_many(mask, func, info, wait) \
(up_smp_call_function(func, info))
static inline void init_call_single_data(void)
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index ea8009695c69..52e8cb0a7569 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -94,8 +94,6 @@ struct svc_serv {
struct module * sv_module; /* optional module to count when
* adding threads */
svc_thread_fn sv_function; /* main function for threads */
- unsigned int sv_drc_max_pages; /* Total pages for DRC */
- unsigned int sv_drc_pages_used;/* DRC pages used */
#if defined(CONFIG_NFS_V4_1)
struct list_head sv_cb_list; /* queue for callback requests
* that arrive over the same
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index bea469455a0c..3d92396639de 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -209,5 +209,7 @@ struct sockaddr_tipc {
#define TIPC_SRC_DROPPABLE 128 /* Default: 0 (resend congested msg) */
#define TIPC_DEST_DROPPABLE 129 /* Default: based on socket type */
#define TIPC_CONN_TIMEOUT 130 /* Default: 8000 (ms) */
+#define TIPC_NODE_RECVQ_DEPTH 131 /* Default: none (read only) */
+#define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */
#endif
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 7402c1a27c4f..61e313118112 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -180,21 +180,21 @@ int arch_update_cpu_topology(void);
#ifndef topology_physical_package_id
#define topology_physical_package_id(cpu) ((void)(cpu), -1)
#endif
+#ifndef topology_cpu_node_id
+#define topology_cpu_node_id(cpu) ((void)(cpu), 0)
+#endif
#ifndef topology_core_id
#define topology_core_id(cpu) ((void)(cpu), 0)
#endif
-#ifndef topology_thread_siblings
-#define topology_thread_siblings(cpu) cpumask_of_cpu(cpu)
-#endif
-#ifndef topology_core_siblings
-#define topology_core_siblings(cpu) cpumask_of_cpu(cpu)
-#endif
#ifndef topology_thread_cpumask
#define topology_thread_cpumask(cpu) cpumask_of(cpu)
#endif
#ifndef topology_core_cpumask
#define topology_core_cpumask(cpu) cpumask_of(cpu)
#endif
+#ifndef topology_cpu_node_cpumask
+#define topology_cpu_node_cpumask(cpu) topology_core_cpumask(cpu)
+#endif
/* Returns the number of the current Node. */
#ifndef numa_node_id
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1488d8c81aac..e8c6c9136c97 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -394,6 +394,7 @@ extern void __do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
extern void no_tty(void);
extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_flush_to_ldisc(struct tty_struct *tty);
extern void tty_buffer_free_all(struct tty_struct *tty);
extern void tty_buffer_flush(struct tty_struct *tty);
extern void tty_buffer_init(struct tty_struct *tty);
diff --git a/include/linux/uio.h b/include/linux/uio.h
index b7fe13883bdb..98c114323a8b 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -19,15 +19,6 @@ struct iovec
__kernel_size_t iov_len; /* Must be size_t (1003.1g) */
};
-#ifdef __KERNEL__
-
-struct kvec {
- void *iov_base; /* and that should *never* hold a userland pointer */
- size_t iov_len;
-};
-
-#endif
-
/*
* UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1)
*/
@@ -35,6 +26,13 @@ struct kvec {
#define UIO_FASTIOV 8
#define UIO_MAXIOV 1024
+#ifdef __KERNEL__
+
+struct kvec {
+ void *iov_base; /* and that should *never* hold a userland pointer */
+ size_t iov_len;
+};
+
/*
* Total number of bytes covered by an iovec.
*
@@ -53,5 +51,6 @@ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
}
unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to);
+#endif
#endif
diff --git a/include/linux/usb.h b/include/linux/usb.h
index b1e3c2fbfe11..5c60e58a8bae 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1071,7 +1071,7 @@ typedef void (*usb_complete_t)(struct urb *);
* @start_frame: Returns the initial frame for isochronous transfers.
* @number_of_packets: Lists the number of ISO transfer buffers.
* @interval: Specifies the polling interval for interrupt or isochronous
- * transfers. The units are frames (milliseconds) for for full and low
+ * transfers. The units are frames (milliseconds) for full and low
* speed devices, and microframes (1/8 millisecond) for highspeed ones.
* @error_count: Returns the number of ISO transfers that reported errors.
* @context: For use in completion functions. This normally points to
diff --git a/include/linux/usb/m66592.h b/include/linux/usb/m66592.h
new file mode 100644
index 000000000000..cda9625e7df0
--- /dev/null
+++ b/include/linux/usb/m66592.h
@@ -0,0 +1,44 @@
+/*
+ * M66592 driver platform data
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __LINUX_USB_M66592_H
+#define __LINUX_USB_M66592_H
+
+#define M66592_PLATDATA_XTAL_12MHZ 0x01
+#define M66592_PLATDATA_XTAL_24MHZ 0x02
+#define M66592_PLATDATA_XTAL_48MHZ 0x03
+
+struct m66592_platdata {
+ /* one = on chip controller, zero = external controller */
+ unsigned on_chip:1;
+
+ /* one = big endian, zero = little endian */
+ unsigned endian:1;
+
+ /* (external controller only) M66592_PLATDATA_XTAL_nnMHZ */
+ unsigned xtal:2;
+
+ /* (external controller only) one = 3.3V, zero = 1.5V */
+ unsigned vif:1;
+
+};
+
+#endif /* __LINUX_USB_M66592_H */
+
diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h
index e9f0384fa20c..26d216734057 100644
--- a/include/linux/usb/r8a66597.h
+++ b/include/linux/usb/r8a66597.h
@@ -28,9 +28,12 @@
#define R8A66597_PLATDATA_XTAL_48MHZ 0x03
struct r8a66597_platdata {
- /* This ops can controll port power instead of DVSTCTR register. */
+ /* This callback can control port power instead of DVSTCTR register. */
void (*port_power)(int port, int power);
+ /* set one = on chip controller, set zero = external controller */
+ unsigned on_chip:1;
+
/* (external controller only) set R8A66597_PLATDATA_XTAL_nnMHZ */
unsigned xtal:2;
@@ -40,5 +43,373 @@ struct r8a66597_platdata {
/* set one = big endian, set zero = little endian */
unsigned endian:1;
};
-#endif
+
+/* Register definitions */
+#define SYSCFG0 0x00
+#define SYSCFG1 0x02
+#define SYSSTS0 0x04
+#define SYSSTS1 0x06
+#define DVSTCTR0 0x08
+#define DVSTCTR1 0x0A
+#define TESTMODE 0x0C
+#define PINCFG 0x0E
+#define DMA0CFG 0x10
+#define DMA1CFG 0x12
+#define CFIFO 0x14
+#define D0FIFO 0x18
+#define D1FIFO 0x1C
+#define CFIFOSEL 0x20
+#define CFIFOCTR 0x22
+#define CFIFOSIE 0x24
+#define D0FIFOSEL 0x28
+#define D0FIFOCTR 0x2A
+#define D1FIFOSEL 0x2C
+#define D1FIFOCTR 0x2E
+#define INTENB0 0x30
+#define INTENB1 0x32
+#define INTENB2 0x34
+#define BRDYENB 0x36
+#define NRDYENB 0x38
+#define BEMPENB 0x3A
+#define SOFCFG 0x3C
+#define INTSTS0 0x40
+#define INTSTS1 0x42
+#define INTSTS2 0x44
+#define BRDYSTS 0x46
+#define NRDYSTS 0x48
+#define BEMPSTS 0x4A
+#define FRMNUM 0x4C
+#define UFRMNUM 0x4E
+#define USBADDR 0x50
+#define USBREQ 0x54
+#define USBVAL 0x56
+#define USBINDX 0x58
+#define USBLENG 0x5A
+#define DCPCFG 0x5C
+#define DCPMAXP 0x5E
+#define DCPCTR 0x60
+#define PIPESEL 0x64
+#define PIPECFG 0x68
+#define PIPEBUF 0x6A
+#define PIPEMAXP 0x6C
+#define PIPEPERI 0x6E
+#define PIPE1CTR 0x70
+#define PIPE2CTR 0x72
+#define PIPE3CTR 0x74
+#define PIPE4CTR 0x76
+#define PIPE5CTR 0x78
+#define PIPE6CTR 0x7A
+#define PIPE7CTR 0x7C
+#define PIPE8CTR 0x7E
+#define PIPE9CTR 0x80
+#define PIPE1TRE 0x90
+#define PIPE1TRN 0x92
+#define PIPE2TRE 0x94
+#define PIPE2TRN 0x96
+#define PIPE3TRE 0x98
+#define PIPE3TRN 0x9A
+#define PIPE4TRE 0x9C
+#define PIPE4TRN 0x9E
+#define PIPE5TRE 0xA0
+#define PIPE5TRN 0xA2
+#define DEVADD0 0xD0
+#define DEVADD1 0xD2
+#define DEVADD2 0xD4
+#define DEVADD3 0xD6
+#define DEVADD4 0xD8
+#define DEVADD5 0xDA
+#define DEVADD6 0xDC
+#define DEVADD7 0xDE
+#define DEVADD8 0xE0
+#define DEVADD9 0xE2
+#define DEVADDA 0xE4
+
+/* System Configuration Control Register */
+#define XTAL 0xC000 /* b15-14: Crystal selection */
+#define XTAL48 0x8000 /* 48MHz */
+#define XTAL24 0x4000 /* 24MHz */
+#define XTAL12 0x0000 /* 12MHz */
+#define XCKE 0x2000 /* b13: External clock enable */
+#define PLLC 0x0800 /* b11: PLL control */
+#define SCKE 0x0400 /* b10: USB clock enable */
+#define PCSDIS 0x0200 /* b9: not CS wakeup */
+#define LPSME 0x0100 /* b8: Low power sleep mode */
+#define HSE 0x0080 /* b7: Hi-speed enable */
+#define DCFM 0x0040 /* b6: Controller function select */
+#define DRPD 0x0020 /* b5: D+/- pull down control */
+#define DPRPU 0x0010 /* b4: D+ pull up control */
+#define USBE 0x0001 /* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define OVCBIT 0x8000 /* b15-14: Over-current bit */
+#define OVCMON 0xC000 /* b15-14: Over-current monitor */
+#define SOFEA 0x0020 /* b5: SOF monitor */
+#define IDMON 0x0004 /* b3: ID-pin monitor */
+#define LNST 0x0003 /* b1-0: D+, D- line status */
+#define SE1 0x0003 /* SE1 */
+#define FS_KSTS 0x0002 /* Full-Speed K State */
+#define FS_JSTS 0x0001 /* Full-Speed J State */
+#define LS_JSTS 0x0002 /* Low-Speed J State */
+#define LS_KSTS 0x0001 /* Low-Speed K State */
+#define SE0 0x0000 /* SE0 */
+
+/* Device State Control Register */
+#define EXTLP0 0x0400 /* b10: External port */
+#define VBOUT 0x0200 /* b9: VBUS output */
+#define WKUP 0x0100 /* b8: Remote wakeup */
+#define RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define USBRST 0x0040 /* b6: USB reset enable */
+#define RESUME 0x0020 /* b5: Resume enable */
+#define UACT 0x0010 /* b4: USB bus enable */
+#define RHST 0x0007 /* b1-0: Reset handshake status */
+#define HSPROC 0x0004 /* HS handshake is processing */
+#define HSMODE 0x0003 /* Hi-Speed mode */
+#define FSMODE 0x0002 /* Full-Speed mode */
+#define LSMODE 0x0001 /* Low-Speed mode */
+#define UNDECID 0x0000 /* Undecided */
+
+/* Test Mode Register */
+#define UTST 0x000F /* b3-0: Test select */
+#define H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define H_TST_K 0x000A /* HOST TEST K */
+#define H_TST_J 0x0009 /* HOST TEST J */
+#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define P_TST_K 0x0002 /* PERI TEST K */
+#define P_TST_J 0x0001 /* PERI TEST J */
+#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define LDRV 0x8000 /* b15: Drive Current Adjust */
+#define VIF1 0x0000 /* VIF = 1.8V */
+#define VIF3 0x8000 /* VIF = 3.3V */
+#define INTA 0x0001 /* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define DREQA 0x4000 /* b14: Dreq active select */
+#define BURST 0x2000 /* b13: Burst mode */
+#define DACKA 0x0400 /* b10: Dack active select */
+#define DFORM 0x0380 /* b9-7: DMA mode select */
+#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define DENDA 0x0040 /* b6: Dend active select */
+#define PKTM 0x0020 /* b5: Packet mode */
+#define DENDE 0x0010 /* b4: Dend enable */
+#define OBUS 0x0004 /* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define RCNT 0x8000 /* b15: Read count mode */
+#define REW 0x4000 /* b14: Buffer rewind */
+#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define DREQE 0x1000 /* b12: DREQ output enable */
+#define MBW_8 0x0000 /* 8bit */
+#define MBW_16 0x0400 /* 16bit */
+#define MBW_32 0x0800 /* 32bit */
+#define BIGEND 0x0100 /* b8: Big endian mode */
+#define BYTE_LITTLE 0x0000 /* little dendian */
+#define BYTE_BIG 0x0100 /* big endifan */
+#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define CURPIPE 0x000F /* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define BVAL 0x8000 /* b15: Buffer valid flag */
+#define BCLR 0x4000 /* b14: Buffer clear */
+#define FRDY 0x2000 /* b13: FIFO ready */
+#define DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define VBSE 0x8000 /* b15: VBUS interrupt */
+#define RSME 0x4000 /* b14: Resume interrupt */
+#define SOFE 0x2000 /* b13: Frame update interrupt */
+#define DVSE 0x1000 /* b12: Device state transition interrupt */
+#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define OVRCRE 0x8000 /* b15: Over-current interrupt */
+#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
+#define EOFERRE 0x0040 /* b6: EOF error interrupt */
+#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define BRDY9 0x0200 /* b9: PIPE9 */
+#define BRDY8 0x0100 /* b8: PIPE8 */
+#define BRDY7 0x0080 /* b7: PIPE7 */
+#define BRDY6 0x0040 /* b6: PIPE6 */
+#define BRDY5 0x0020 /* b5: PIPE5 */
+#define BRDY4 0x0010 /* b4: PIPE4 */
+#define BRDY3 0x0008 /* b3: PIPE3 */
+#define BRDY2 0x0004 /* b2: PIPE2 */
+#define BRDY1 0x0002 /* b1: PIPE1 */
+#define BRDY0 0x0001 /* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define NRDY9 0x0200 /* b9: PIPE9 */
+#define NRDY8 0x0100 /* b8: PIPE8 */
+#define NRDY7 0x0080 /* b7: PIPE7 */
+#define NRDY6 0x0040 /* b6: PIPE6 */
+#define NRDY5 0x0020 /* b5: PIPE5 */
+#define NRDY4 0x0010 /* b4: PIPE4 */
+#define NRDY3 0x0008 /* b3: PIPE3 */
+#define NRDY2 0x0004 /* b2: PIPE2 */
+#define NRDY1 0x0002 /* b1: PIPE1 */
+#define NRDY0 0x0001 /* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define BEMP9 0x0200 /* b9: PIPE9 */
+#define BEMP8 0x0100 /* b8: PIPE8 */
+#define BEMP7 0x0080 /* b7: PIPE7 */
+#define BEMP6 0x0040 /* b6: PIPE6 */
+#define BEMP5 0x0020 /* b5: PIPE5 */
+#define BEMP4 0x0010 /* b4: PIPE4 */
+#define BEMP3 0x0008 /* b3: PIPE3 */
+#define BEMP2 0x0004 /* b2: PIPE2 */
+#define BEMP1 0x0002 /* b1: PIPE1 */
+#define BEMP0 0x0001 /* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
+#define BRDYM 0x0040 /* b6: BRDY clear timing */
+#define INTL 0x0020 /* b5: Interrupt sense select */
+#define EDGESTS 0x0010 /* b4: */
+#define SOFMODE 0x000C /* b3-2: SOF pin select */
+#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
+#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define VBINT 0x8000 /* b15: VBUS interrupt */
+#define RESM 0x4000 /* b14: Resume interrupt */
+#define SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define DVST 0x1000 /* b12: Device state transition interrupt */
+#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define VBSTS 0x0080 /* b7: VBUS input port */
+#define DVSQ 0x0070 /* b6-4: Device state */
+#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define DS_SUSP 0x0040 /* Suspend */
+#define DS_CNFG 0x0030 /* Configured */
+#define DS_ADDS 0x0020 /* Address */
+#define DS_DFLT 0x0010 /* Default */
+#define DS_POWR 0x0000 /* Powered */
+#define DVSQS 0x0030 /* b5-4: Device state */
+#define VALID 0x0008 /* b3: Setup packet detected flag */
+#define CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define CS_SQER 0x0006 /* Sequence error */
+#define CS_WRND 0x0005 /* Control write nodata status stage */
+#define CS_WRSS 0x0004 /* Control write status stage */
+#define CS_WRDS 0x0003 /* Control write data stage */
+#define CS_RDSS 0x0002 /* Control read status stage */
+#define CS_RDDS 0x0001 /* Control read data stage */
+#define CS_IDST 0x0000 /* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define OVRCR 0x8000 /* b15: Over-current interrupt */
+#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define DTCH 0x1000 /* b12: Detach sense interrupt */
+#define ATTCH 0x0800 /* b11: Attach sense interrupt */
+#define EOFERR 0x0040 /* b6: EOF-error interrupt */
+#define SIGN 0x0020 /* b5: Setup ignore interrupt */
+#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define OVRN 0x8000 /* b15: Overrun error */
+#define CRCE 0x4000 /* b14: Received data error */
+#define FRNM 0x07FF /* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define UFRNM 0x0007 /* b2-0: Micro frame number */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define DEVSEL 0xF000 /* b15-14: Device address select */
+#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define SUREQ 0x4000 /* b14: Send USB request */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define SUREQCLR 0x0800 /* b11: stop setup request */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PINGE 0x0010 /* b4: ping enable */
+#define CCPL 0x0004 /* b2: Enable control transfer complete */
+#define PID 0x0003 /* b1-0: Response PID */
+#define PID_STALL11 0x0003 /* STALL */
+#define PID_STALL 0x0002 /* STALL */
+#define PID_BUF 0x0001 /* BUF */
+#define PID_NAK 0x0000 /* NAK */
+
+/* Pipe Window Select Register */
+#define PIPENM 0x0007 /* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
+#define R8A66597_ISO 0xC000 /* Isochronous */
+#define R8A66597_INT 0x8000 /* Interrupt */
+#define R8A66597_BULK 0x4000 /* Bulk */
+#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
+#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
+#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
+#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
+#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
+#define PIPE0BUF 256
+#define PIPExBUF 64
+
+/* Pipe Maxpacket Size Register */
+#define MXPS 0x07FF /* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
+#define IITV 0x0007 /* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define ATREPM 0x0400 /* b10: Auto repeat mode */
+#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PID 0x0003 /* b1-0: Response PID */
+
+/* PIPExTRE */
+#define TRENB 0x0200 /* b9: Transaction counter enable */
+#define TRCLR 0x0100 /* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define UPPHUB 0x7800
+#define HUBPORT 0x0700
+#define USBSPD 0x00C0
+#define RTPORT 0x0001
+
+#endif /* __LINUX_USB_R8A66597_H */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 310e18a880ff..7c17b2efba86 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -97,6 +97,9 @@ struct driver_info {
/* reset device ... can sleep */
int (*reset)(struct usbnet *);
+ /* stop device ... can sleep */
+ int (*stop)(struct usbnet *);
+
/* see if peer is connected ... can sleep */
int (*check_connect)(struct usbnet *);
diff --git a/include/linux/usb/video.h b/include/linux/usb/video.h
new file mode 100644
index 000000000000..be436d9ee479
--- /dev/null
+++ b/include/linux/usb/video.h
@@ -0,0 +1,164 @@
+/*
+ * USB Video Class definitions.
+ *
+ * Copyright (C) 2009 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * This file holds USB constants and structures defined by the USB Device
+ * Class Definition for Video Devices. Unless otherwise stated, comments
+ * below reference relevant sections of the USB Video Class 1.1 specification
+ * available at
+ *
+ * http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip
+ */
+
+#ifndef __LINUX_USB_VIDEO_H
+#define __LINUX_USB_VIDEO_H
+
+#include <linux/types.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+/* A.2. Video Interface Subclass Codes */
+#define UVC_SC_UNDEFINED 0x00
+#define UVC_SC_VIDEOCONTROL 0x01
+#define UVC_SC_VIDEOSTREAMING 0x02
+#define UVC_SC_VIDEO_INTERFACE_COLLECTION 0x03
+
+/* A.3. Video Interface Protocol Codes */
+#define UVC_PC_PROTOCOL_UNDEFINED 0x00
+
+/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
+#define UVC_VC_DESCRIPTOR_UNDEFINED 0x00
+#define UVC_VC_HEADER 0x01
+#define UVC_VC_INPUT_TERMINAL 0x02
+#define UVC_VC_OUTPUT_TERMINAL 0x03
+#define UVC_VC_SELECTOR_UNIT 0x04
+#define UVC_VC_PROCESSING_UNIT 0x05
+#define UVC_VC_EXTENSION_UNIT 0x06
+
+/* A.6. Video Class-Specific VS Interface Descriptor Subtypes */
+#define UVC_VS_UNDEFINED 0x00
+#define UVC_VS_INPUT_HEADER 0x01
+#define UVC_VS_OUTPUT_HEADER 0x02
+#define UVC_VS_STILL_IMAGE_FRAME 0x03
+#define UVC_VS_FORMAT_UNCOMPRESSED 0x04
+#define UVC_VS_FRAME_UNCOMPRESSED 0x05
+#define UVC_VS_FORMAT_MJPEG 0x06
+#define UVC_VS_FRAME_MJPEG 0x07
+#define UVC_VS_FORMAT_MPEG2TS 0x0a
+#define UVC_VS_FORMAT_DV 0x0c
+#define UVC_VS_COLORFORMAT 0x0d
+#define UVC_VS_FORMAT_FRAME_BASED 0x10
+#define UVC_VS_FRAME_FRAME_BASED 0x11
+#define UVC_VS_FORMAT_STREAM_BASED 0x12
+
+/* A.7. Video Class-Specific Endpoint Descriptor Subtypes */
+#define UVC_EP_UNDEFINED 0x00
+#define UVC_EP_GENERAL 0x01
+#define UVC_EP_ENDPOINT 0x02
+#define UVC_EP_INTERRUPT 0x03
+
+/* A.8. Video Class-Specific Request Codes */
+#define UVC_RC_UNDEFINED 0x00
+#define UVC_SET_CUR 0x01
+#define UVC_GET_CUR 0x81
+#define UVC_GET_MIN 0x82
+#define UVC_GET_MAX 0x83
+#define UVC_GET_RES 0x84
+#define UVC_GET_LEN 0x85
+#define UVC_GET_INFO 0x86
+#define UVC_GET_DEF 0x87
+
+/* A.9.1. VideoControl Interface Control Selectors */
+#define UVC_VC_CONTROL_UNDEFINED 0x00
+#define UVC_VC_VIDEO_POWER_MODE_CONTROL 0x01
+#define UVC_VC_REQUEST_ERROR_CODE_CONTROL 0x02
+
+/* A.9.2. Terminal Control Selectors */
+#define UVC_TE_CONTROL_UNDEFINED 0x00
+
+/* A.9.3. Selector Unit Control Selectors */
+#define UVC_SU_CONTROL_UNDEFINED 0x00
+#define UVC_SU_INPUT_SELECT_CONTROL 0x01
+
+/* A.9.4. Camera Terminal Control Selectors */
+#define UVC_CT_CONTROL_UNDEFINED 0x00
+#define UVC_CT_SCANNING_MODE_CONTROL 0x01
+#define UVC_CT_AE_MODE_CONTROL 0x02
+#define UVC_CT_AE_PRIORITY_CONTROL 0x03
+#define UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
+#define UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
+#define UVC_CT_FOCUS_ABSOLUTE_CONTROL 0x06
+#define UVC_CT_FOCUS_RELATIVE_CONTROL 0x07
+#define UVC_CT_FOCUS_AUTO_CONTROL 0x08
+#define UVC_CT_IRIS_ABSOLUTE_CONTROL 0x09
+#define UVC_CT_IRIS_RELATIVE_CONTROL 0x0a
+#define UVC_CT_ZOOM_ABSOLUTE_CONTROL 0x0b
+#define UVC_CT_ZOOM_RELATIVE_CONTROL 0x0c
+#define UVC_CT_PANTILT_ABSOLUTE_CONTROL 0x0d
+#define UVC_CT_PANTILT_RELATIVE_CONTROL 0x0e
+#define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
+#define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
+#define UVC_CT_PRIVACY_CONTROL 0x11
+
+/* A.9.5. Processing Unit Control Selectors */
+#define UVC_PU_CONTROL_UNDEFINED 0x00
+#define UVC_PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
+#define UVC_PU_BRIGHTNESS_CONTROL 0x02
+#define UVC_PU_CONTRAST_CONTROL 0x03
+#define UVC_PU_GAIN_CONTROL 0x04
+#define UVC_PU_POWER_LINE_FREQUENCY_CONTROL 0x05
+#define UVC_PU_HUE_CONTROL 0x06
+#define UVC_PU_SATURATION_CONTROL 0x07
+#define UVC_PU_SHARPNESS_CONTROL 0x08
+#define UVC_PU_GAMMA_CONTROL 0x09
+#define UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
+#define UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
+#define UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
+#define UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
+#define UVC_PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
+#define UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
+#define UVC_PU_HUE_AUTO_CONTROL 0x10
+#define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
+#define UVC_PU_ANALOG_LOCK_STATUS_CONTROL 0x12
+
+/* A.9.7. VideoStreaming Interface Control Selectors */
+#define UVC_VS_CONTROL_UNDEFINED 0x00
+#define UVC_VS_PROBE_CONTROL 0x01
+#define UVC_VS_COMMIT_CONTROL 0x02
+#define UVC_VS_STILL_PROBE_CONTROL 0x03
+#define UVC_VS_STILL_COMMIT_CONTROL 0x04
+#define UVC_VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
+#define UVC_VS_STREAM_ERROR_CODE_CONTROL 0x06
+#define UVC_VS_GENERATE_KEY_FRAME_CONTROL 0x07
+#define UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define UVC_VS_SYNC_DELAY_CONTROL 0x09
+
+/* B.1. USB Terminal Types */
+#define UVC_TT_VENDOR_SPECIFIC 0x0100
+#define UVC_TT_STREAMING 0x0101
+
+/* B.2. Input Terminal Types */
+#define UVC_ITT_VENDOR_SPECIFIC 0x0200
+#define UVC_ITT_CAMERA 0x0201
+#define UVC_ITT_MEDIA_TRANSPORT_INPUT 0x0202
+
+/* B.3. Output Terminal Types */
+#define UVC_OTT_VENDOR_SPECIFIC 0x0300
+#define UVC_OTT_DISPLAY 0x0301
+#define UVC_OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
+
+/* B.4. External Terminal Types */
+#define UVC_EXTERNAL_VENDOR_SPECIFIC 0x0400
+#define UVC_COMPOSITE_CONNECTOR 0x0401
+#define UVC_SVIDEO_CONNECTOR 0x0402
+#define UVC_COMPONENT_CONNECTOR 0x0403
+
+/* 2.4.2.2. Status Packet Type */
+#define UVC_STATUS_TYPE_CONTROL 1
+#define UVC_STATUS_TYPE_STREAMING 2
+
+#endif /* __LINUX_USB_VIDEO_H */
+
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 95846d988011..293ba181f95a 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -252,10 +252,12 @@ struct v4l2_capability {
#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */
#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */
+#define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */
#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */
#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */
+#define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */
#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
@@ -275,7 +277,9 @@ struct v4l2_pix_format {
__u32 priv; /* private data, depends on pixelformat */
};
-/* Pixel format FOURCC depth Description */
+/* Pixel format FOURCC depth Description */
+
+/* RGB formats */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */
@@ -286,12 +290,20 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */
+
+/* Grey formats */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */
#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */
+
+/* Palette formats */
#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */
+
+/* Luminance+Chrominance formats */
#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */
@@ -301,6 +313,10 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */
#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */
#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */
+#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */
+#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
+#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */
+#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
@@ -308,25 +324,17 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */
-/* The following formats are not defined in the V4L2 specification */
-#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */
-#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
-#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */
-#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */
-#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
-
-/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
+/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */
#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */
#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */
-
-/*
- * 10bit raw bayer, expanded to 16 bits
- * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
- */
-#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0')
-/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */
+ /* 10bit raw bayer DPCM compressed to 8 bits */
#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+ /*
+ * 10bit raw bayer, expanded to 16 bits
+ * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
+ */
#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */
/* compressed formats */
@@ -338,6 +346,7 @@ struct v4l2_pix_format {
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
@@ -349,7 +358,6 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
#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 */
@@ -1180,6 +1188,7 @@ struct v4l2_modulator {
#define V4L2_TUNER_CAP_LANG2 0x0020
#define V4L2_TUNER_CAP_SAP 0x0020
#define V4L2_TUNER_CAP_LANG1 0x0040
+#define V4L2_TUNER_CAP_RDS 0x0080
/* Flags for the 'rxsubchans' field */
#define V4L2_TUNER_SUB_MONO 0x0001
@@ -1187,6 +1196,7 @@ struct v4l2_modulator {
#define V4L2_TUNER_SUB_LANG2 0x0004
#define V4L2_TUNER_SUB_SAP 0x0004
#define V4L2_TUNER_SUB_LANG1 0x0008
+#define V4L2_TUNER_SUB_RDS 0x0010
/* Values for the 'audmode' field */
#define V4L2_TUNER_MODE_MONO 0x0000
@@ -1212,6 +1222,27 @@ struct v4l2_hw_freq_seek {
};
/*
+ * R D S
+ */
+
+struct v4l2_rds_data {
+ __u8 lsb;
+ __u8 msb;
+ __u8 block;
+} __attribute__ ((packed));
+
+#define V4L2_RDS_BLOCK_MSK 0x7
+#define V4L2_RDS_BLOCK_A 0
+#define V4L2_RDS_BLOCK_B 1
+#define V4L2_RDS_BLOCK_C 2
+#define V4L2_RDS_BLOCK_D 3
+#define V4L2_RDS_BLOCK_C_ALT 4
+#define V4L2_RDS_BLOCK_INVALID 7
+
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR 0x80
+
+/*
* A U D I O
*/
struct v4l2_audio {
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index be7d255fc7cf..8dab9f2b8832 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -20,8 +20,7 @@
#define VIRTIO_BLK_ID_BYTES (sizeof(__u16[256])) /* IDENTIFY DATA */
-struct virtio_blk_config
-{
+struct virtio_blk_config {
/* The capacity (in 512-byte sectors). */
__u64 capacity;
/* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
@@ -50,8 +49,7 @@ struct virtio_blk_config
#define VIRTIO_BLK_T_BARRIER 0x80000000
/* This is the first element of the read scatter-gather list. */
-struct virtio_blk_outhdr
-{
+struct virtio_blk_outhdr {
/* VIRTIO_BLK_T* */
__u32 type;
/* io priority. */
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 99f514575f6a..e547e3c8ee9a 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -79,8 +79,7 @@
* the dev->feature bits if it wants.
*/
typedef void vq_callback_t(struct virtqueue *);
-struct virtio_config_ops
-{
+struct virtio_config_ops {
void (*get)(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len);
void (*set)(struct virtio_device *vdev, unsigned offset,
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 9c543d6ac535..d8dd539c9f48 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -31,8 +31,7 @@
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
-struct virtio_net_config
-{
+struct virtio_net_config {
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
__u8 mac[6];
/* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
@@ -41,8 +40,7 @@ struct virtio_net_config
/* This is the first element of the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header. */
-struct virtio_net_hdr
-{
+struct virtio_net_hdr {
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
__u8 flags;
#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 693e0ec5afa6..e4d144b132b5 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -30,8 +30,7 @@
#define VIRTIO_RING_F_INDIRECT_DESC 28
/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
-struct vring_desc
-{
+struct vring_desc {
/* Address (guest-physical). */
__u64 addr;
/* Length. */
@@ -42,24 +41,21 @@ struct vring_desc
__u16 next;
};
-struct vring_avail
-{
+struct vring_avail {
__u16 flags;
__u16 idx;
__u16 ring[];
};
/* u32 is used here for ids for padding reasons. */
-struct vring_used_elem
-{
+struct vring_used_elem {
/* Index of start of used descriptor chain. */
__u32 id;
/* Total length of the descriptor chain which was used (written to) */
__u32 len;
};
-struct vring_used
-{
+struct vring_used {
__u16 flags;
__u16 idx;
struct vring_used_elem ring[];
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index cb24204851f7..5b4c6c772a9b 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1132,6 +1132,14 @@ struct __compat_iw_event {
};
#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
+
+/* Size of the various events for compat */
+#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
+#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
+#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
#define IW_EV_COMPAT_POINT_LEN \
(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
IW_EV_COMPAT_POINT_OFF)
diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
index 6f69968eab24..0c9878123d5f 100644
--- a/include/linux/wm97xx.h
+++ b/include/linux/wm97xx.h
@@ -16,6 +16,12 @@
#include <linux/platform_device.h>
/*
+ * WM97xx variants
+ */
+#define WM97xx_GENERIC 0x0000
+#define WM97xx_WM1613 0x1613
+
+/*
* WM97xx AC97 Touchscreen registers
*/
#define AC97_WM97XX_DIGITISER1 0x76
@@ -283,6 +289,7 @@ struct wm97xx {
unsigned pen_is_down:1; /* Pen is down */
unsigned aux_waiting:1; /* aux measurement waiting */
unsigned pen_probably_down:1; /* used in polling mode */
+ u16 variant; /* WM97xx chip variant */
u16 suspend_mode; /* PRP in suspend mode */
};
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 13e1adf55c4c..f3a61fdb6f5d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -94,7 +94,7 @@ struct execute_work {
/*
* initialize all of a work item in one go
*
- * NOTE! No point in using "atomic_long_set()": useing a direct
+ * NOTE! No point in using "atomic_long_set()": using a direct
* assignment of the work data initializer allows the compiler
* to generate better code.
*/
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 3224820c8514..e070b91905d6 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -14,17 +14,6 @@ extern struct list_head inode_in_use;
extern struct list_head inode_unused;
/*
- * Yes, writeback.h requires sched.h
- * No, sched.h is not included from here.
- */
-static inline int task_is_pdflush(struct task_struct *task)
-{
- return task->flags & PF_FLUSHER;
-}
-
-#define current_is_pdflush() task_is_pdflush(current)
-
-/*
* fs/fs-writeback.c
*/
enum writeback_sync_modes {
@@ -79,6 +68,7 @@ struct writeback_control {
void writeback_inodes(struct writeback_control *wbc);
int inode_wait(void *);
void sync_inodes_sb(struct super_block *, int wait);
+long wb_do_writeback(struct bdi_writeback *wb, int force_wait);
/* writeback.h requires fs.h; it, too, is not included from here. */
static inline void wait_on_inode(struct inode *inode)
@@ -98,7 +88,7 @@ static inline void inode_sync_wait(struct inode *inode)
/*
* mm/page-writeback.c
*/
-int wakeup_pdflush(long nr_pages);
+void wakeup_flusher_threads(long nr_pages);
void laptop_io_completion(void);
void laptop_sync_completion(void);
void throttle_vm_writeout(gfp_t gfp_mask);
@@ -150,7 +140,6 @@ balance_dirty_pages_ratelimited(struct address_space *mapping)
typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
void *data);
-int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
int generic_writepages(struct address_space *mapping,
struct writeback_control *wbc);
int write_cache_pages(struct address_space *mapping,
diff --git a/include/media/davinci/ccdc_types.h b/include/media/davinci/ccdc_types.h
new file mode 100644
index 000000000000..5773874bf266
--- /dev/null
+++ b/include/media/davinci/ccdc_types.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _CCDC_TYPES_H
+#define _CCDC_TYPES_H
+enum ccdc_pixfmt {
+ CCDC_PIXFMT_RAW,
+ CCDC_PIXFMT_YCBCR_16BIT,
+ CCDC_PIXFMT_YCBCR_8BIT
+};
+
+enum ccdc_frmfmt {
+ CCDC_FRMFMT_PROGRESSIVE,
+ CCDC_FRMFMT_INTERLACED
+};
+
+/* PIXEL ORDER IN MEMORY from LSB to MSB */
+/* only applicable for 8-bit input mode */
+enum ccdc_pixorder {
+ CCDC_PIXORDER_YCBYCR,
+ CCDC_PIXORDER_CBYCRY,
+};
+
+enum ccdc_buftype {
+ CCDC_BUFTYPE_FLD_INTERLEAVED,
+ CCDC_BUFTYPE_FLD_SEPARATED
+};
+#endif
diff --git a/include/media/davinci/dm355_ccdc.h b/include/media/davinci/dm355_ccdc.h
new file mode 100644
index 000000000000..df8a7b107477
--- /dev/null
+++ b/include/media/davinci/dm355_ccdc.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2005-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _DM355_CCDC_H
+#define _DM355_CCDC_H
+#include <media/davinci/ccdc_types.h>
+#include <media/davinci/vpfe_types.h>
+
+/* enum for No of pixel per line to be avg. in Black Clamping */
+enum ccdc_sample_length {
+ CCDC_SAMPLE_1PIXELS,
+ CCDC_SAMPLE_2PIXELS,
+ CCDC_SAMPLE_4PIXELS,
+ CCDC_SAMPLE_8PIXELS,
+ CCDC_SAMPLE_16PIXELS
+};
+
+/* enum for No of lines in Black Clamping */
+enum ccdc_sample_line {
+ CCDC_SAMPLE_1LINES,
+ CCDC_SAMPLE_2LINES,
+ CCDC_SAMPLE_4LINES,
+ CCDC_SAMPLE_8LINES,
+ CCDC_SAMPLE_16LINES
+};
+
+/* enum for Alaw gama width */
+enum ccdc_gamma_width {
+ CCDC_GAMMA_BITS_13_4,
+ CCDC_GAMMA_BITS_12_3,
+ CCDC_GAMMA_BITS_11_2,
+ CCDC_GAMMA_BITS_10_1,
+ CCDC_GAMMA_BITS_09_0
+};
+
+enum ccdc_colpats {
+ CCDC_RED,
+ CCDC_GREEN_RED,
+ CCDC_GREEN_BLUE,
+ CCDC_BLUE
+};
+
+struct ccdc_col_pat {
+ enum ccdc_colpats olop;
+ enum ccdc_colpats olep;
+ enum ccdc_colpats elop;
+ enum ccdc_colpats elep;
+};
+
+enum ccdc_datasft {
+ CCDC_DATA_NO_SHIFT,
+ CCDC_DATA_SHIFT_1BIT,
+ CCDC_DATA_SHIFT_2BIT,
+ CCDC_DATA_SHIFT_3BIT,
+ CCDC_DATA_SHIFT_4BIT,
+ CCDC_DATA_SHIFT_5BIT,
+ CCDC_DATA_SHIFT_6BIT
+};
+
+enum ccdc_data_size {
+ CCDC_DATA_16BITS,
+ CCDC_DATA_15BITS,
+ CCDC_DATA_14BITS,
+ CCDC_DATA_13BITS,
+ CCDC_DATA_12BITS,
+ CCDC_DATA_11BITS,
+ CCDC_DATA_10BITS,
+ CCDC_DATA_8BITS
+};
+enum ccdc_mfilt1 {
+ CCDC_NO_MEDIAN_FILTER1,
+ CCDC_AVERAGE_FILTER1,
+ CCDC_MEDIAN_FILTER1
+};
+
+enum ccdc_mfilt2 {
+ CCDC_NO_MEDIAN_FILTER2,
+ CCDC_AVERAGE_FILTER2,
+ CCDC_MEDIAN_FILTER2
+};
+
+/* structure for ALaw */
+struct ccdc_a_law {
+ /* Enable/disable A-Law */
+ unsigned char enable;
+ /* Gama Width Input */
+ enum ccdc_gamma_width gama_wd;
+};
+
+/* structure for Black Clamping */
+struct ccdc_black_clamp {
+ /* only if bClampEnable is TRUE */
+ unsigned char b_clamp_enable;
+ /* only if bClampEnable is TRUE */
+ enum ccdc_sample_length sample_pixel;
+ /* only if bClampEnable is TRUE */
+ enum ccdc_sample_line sample_ln;
+ /* only if bClampEnable is TRUE */
+ unsigned short start_pixel;
+ /* only if bClampEnable is FALSE */
+ unsigned short sgain;
+ unsigned short dc_sub;
+};
+
+/* structure for Black Level Compensation */
+struct ccdc_black_compensation {
+ /* Constant value to subtract from Red component */
+ unsigned char r;
+ /* Constant value to subtract from Gr component */
+ unsigned char gr;
+ /* Constant value to subtract from Blue component */
+ unsigned char b;
+ /* Constant value to subtract from Gb component */
+ unsigned char gb;
+};
+
+struct ccdc_float {
+ int integer;
+ unsigned int decimal;
+};
+
+#define CCDC_CSC_COEFF_TABLE_SIZE 16
+/* structure for color space converter */
+struct ccdc_csc {
+ unsigned char enable;
+ /*
+ * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99.
+ * example - to use 1.03, set integer part as 1, and decimal part as 3
+ * to use -1.03, set integer part as -1 and decimal part as 3
+ */
+ struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE];
+};
+
+/* Structures for Vertical Defect Correction*/
+enum ccdc_vdf_csl {
+ CCDC_VDF_NORMAL,
+ CCDC_VDF_HORZ_INTERPOL_SAT,
+ CCDC_VDF_HORZ_INTERPOL
+};
+
+enum ccdc_vdf_cuda {
+ CCDC_VDF_WHOLE_LINE_CORRECT,
+ CCDC_VDF_UPPER_DISABLE
+};
+
+enum ccdc_dfc_mwr {
+ CCDC_DFC_MWR_WRITE_COMPLETE,
+ CCDC_DFC_WRITE_REG
+};
+
+enum ccdc_dfc_mrd {
+ CCDC_DFC_READ_COMPLETE,
+ CCDC_DFC_READ_REG
+};
+
+enum ccdc_dfc_ma_rst {
+ CCDC_DFC_INCR_ADDR,
+ CCDC_DFC_CLR_ADDR
+};
+
+enum ccdc_dfc_mclr {
+ CCDC_DFC_CLEAR_COMPLETE,
+ CCDC_DFC_CLEAR
+};
+
+struct ccdc_dft_corr_ctl {
+ enum ccdc_vdf_csl vdfcsl;
+ enum ccdc_vdf_cuda vdfcuda;
+ unsigned int vdflsft;
+};
+
+struct ccdc_dft_corr_mem_ctl {
+ enum ccdc_dfc_mwr dfcmwr;
+ enum ccdc_dfc_mrd dfcmrd;
+ enum ccdc_dfc_ma_rst dfcmarst;
+ enum ccdc_dfc_mclr dfcmclr;
+};
+
+#define CCDC_DFT_TABLE_SIZE 16
+/*
+ * Main Structure for vertical defect correction. Vertical defect
+ * correction can correct upto 16 defects if defects less than 16
+ * then pad the rest with 0
+ */
+struct ccdc_vertical_dft {
+ unsigned char ver_dft_en;
+ unsigned char gen_dft_en;
+ unsigned int saturation_ctl;
+ struct ccdc_dft_corr_ctl dft_corr_ctl;
+ struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl;
+ int table_size;
+ unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE];
+ unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE];
+ unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE];
+ unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE];
+ unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE];
+};
+
+struct ccdc_data_offset {
+ unsigned char horz_offset;
+ unsigned char vert_offset;
+};
+
+/*
+ * Structure for CCDC configuration parameters for raw capture mode passed
+ * by application
+ */
+struct ccdc_config_params_raw {
+ /* data shift to be applied before storing */
+ enum ccdc_datasft datasft;
+ /* data size value from 8 to 16 bits */
+ enum ccdc_data_size data_sz;
+ /* median filter for sdram */
+ enum ccdc_mfilt1 mfilt1;
+ enum ccdc_mfilt2 mfilt2;
+ /* low pass filter enable/disable */
+ unsigned char lpf_enable;
+ /* Threshold of median filter */
+ int med_filt_thres;
+ /*
+ * horz and vertical data offset. Appliable for defect correction
+ * and lsc
+ */
+ struct ccdc_data_offset data_offset;
+ /* Structure for Optional A-Law */
+ struct ccdc_a_law alaw;
+ /* Structure for Optical Black Clamp */
+ struct ccdc_black_clamp blk_clamp;
+ /* Structure for Black Compensation */
+ struct ccdc_black_compensation blk_comp;
+ /* struture for vertical Defect Correction Module Configuration */
+ struct ccdc_vertical_dft vertical_dft;
+ /* structure for color space converter Module Configuration */
+ struct ccdc_csc csc;
+ /* color patters for bayer capture */
+ struct ccdc_col_pat col_pat_field0;
+ struct ccdc_col_pat col_pat_field1;
+};
+
+#ifdef __KERNEL__
+#include <linux/io.h>
+
+#define CCDC_WIN_PAL {0, 0, 720, 576}
+#define CCDC_WIN_VGA {0, 0, 640, 480}
+
+struct ccdc_params_ycbcr {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ /* video window */
+ struct v4l2_rect win;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* enable BT.656 embedded sync mode */
+ int bt656_enable;
+ /* cb:y:cr:y or y:cb:y:cr in memory */
+ enum ccdc_pixorder pix_order;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+};
+
+/* Gain applied to Raw Bayer data */
+struct ccdc_gain {
+ unsigned short r_ye;
+ unsigned short gr_cy;
+ unsigned short gb_g;
+ unsigned short b_mg;
+};
+
+/* Structure for CCDC configuration parameters for raw capture mode */
+struct ccdc_params_raw {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ /* video window */
+ struct v4l2_rect win;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+ /* Gain values */
+ struct ccdc_gain gain;
+ /* offset */
+ unsigned int ccdc_offset;
+ /* horizontal flip enable */
+ unsigned char horz_flip_enable;
+ /*
+ * enable to store the image in inverse order in memory
+ * (bottom to top)
+ */
+ unsigned char image_invert_enable;
+ /* Configurable part of raw data */
+ struct ccdc_config_params_raw config_params;
+};
+
+#endif
+#endif /* DM355_CCDC_H */
diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h
new file mode 100644
index 000000000000..3e178eb52fb3
--- /dev/null
+++ b/include/media/davinci/dm644x_ccdc.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2006-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _DM644X_CCDC_H
+#define _DM644X_CCDC_H
+#include <media/davinci/ccdc_types.h>
+#include <media/davinci/vpfe_types.h>
+
+/* enum for No of pixel per line to be avg. in Black Clamping*/
+enum ccdc_sample_length {
+ CCDC_SAMPLE_1PIXELS,
+ CCDC_SAMPLE_2PIXELS,
+ CCDC_SAMPLE_4PIXELS,
+ CCDC_SAMPLE_8PIXELS,
+ CCDC_SAMPLE_16PIXELS
+};
+
+/* enum for No of lines in Black Clamping */
+enum ccdc_sample_line {
+ CCDC_SAMPLE_1LINES,
+ CCDC_SAMPLE_2LINES,
+ CCDC_SAMPLE_4LINES,
+ CCDC_SAMPLE_8LINES,
+ CCDC_SAMPLE_16LINES
+};
+
+/* enum for Alaw gama width */
+enum ccdc_gama_width {
+ CCDC_GAMMA_BITS_15_6,
+ CCDC_GAMMA_BITS_14_5,
+ CCDC_GAMMA_BITS_13_4,
+ CCDC_GAMMA_BITS_12_3,
+ CCDC_GAMMA_BITS_11_2,
+ CCDC_GAMMA_BITS_10_1,
+ CCDC_GAMMA_BITS_09_0
+};
+
+enum ccdc_data_size {
+ CCDC_DATA_16BITS,
+ CCDC_DATA_15BITS,
+ CCDC_DATA_14BITS,
+ CCDC_DATA_13BITS,
+ CCDC_DATA_12BITS,
+ CCDC_DATA_11BITS,
+ CCDC_DATA_10BITS,
+ CCDC_DATA_8BITS
+};
+
+/* structure for ALaw */
+struct ccdc_a_law {
+ /* Enable/disable A-Law */
+ unsigned char enable;
+ /* Gama Width Input */
+ enum ccdc_gama_width gama_wd;
+};
+
+/* structure for Black Clamping */
+struct ccdc_black_clamp {
+ unsigned char enable;
+ /* only if bClampEnable is TRUE */
+ enum ccdc_sample_length sample_pixel;
+ /* only if bClampEnable is TRUE */
+ enum ccdc_sample_line sample_ln;
+ /* only if bClampEnable is TRUE */
+ unsigned short start_pixel;
+ /* only if bClampEnable is TRUE */
+ unsigned short sgain;
+ /* only if bClampEnable is FALSE */
+ unsigned short dc_sub;
+};
+
+/* structure for Black Level Compensation */
+struct ccdc_black_compensation {
+ /* Constant value to subtract from Red component */
+ char r;
+ /* Constant value to subtract from Gr component */
+ char gr;
+ /* Constant value to subtract from Blue component */
+ char b;
+ /* Constant value to subtract from Gb component */
+ char gb;
+};
+
+/* structure for fault pixel correction */
+struct ccdc_fault_pixel {
+ /* Enable or Disable fault pixel correction */
+ unsigned char enable;
+ /* Number of fault pixel */
+ unsigned short fp_num;
+ /* Address of fault pixel table */
+ unsigned int fpc_table_addr;
+};
+
+/* Structure for CCDC configuration parameters for raw capture mode passed
+ * by application
+ */
+struct ccdc_config_params_raw {
+ /* data size value from 8 to 16 bits */
+ enum ccdc_data_size data_sz;
+ /* Structure for Optional A-Law */
+ struct ccdc_a_law alaw;
+ /* Structure for Optical Black Clamp */
+ struct ccdc_black_clamp blk_clamp;
+ /* Structure for Black Compensation */
+ struct ccdc_black_compensation blk_comp;
+ /* Structure for Fault Pixel Module Configuration */
+ struct ccdc_fault_pixel fault_pxl;
+};
+
+
+#ifdef __KERNEL__
+#include <linux/io.h>
+/* Define to enable/disable video port */
+#define FP_NUM_BYTES 4
+/* Define for extra pixel/line and extra lines/frame */
+#define NUM_EXTRAPIXELS 8
+#define NUM_EXTRALINES 8
+
+/* settings for commonly used video formats */
+#define CCDC_WIN_PAL {0, 0, 720, 576}
+/* ntsc square pixel */
+#define CCDC_WIN_VGA {0, 0, (640 + NUM_EXTRAPIXELS), (480 + NUM_EXTRALINES)}
+
+/* Structure for CCDC configuration parameters for raw capture mode */
+struct ccdc_params_raw {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ /* video window */
+ struct v4l2_rect win;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+ /*
+ * enable to store the image in inverse
+ * order in memory(bottom to top)
+ */
+ unsigned char image_invert_enable;
+ /* configurable paramaters */
+ struct ccdc_config_params_raw config_params;
+};
+
+struct ccdc_params_ycbcr {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ /* video window */
+ struct v4l2_rect win;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* enable BT.656 embedded sync mode */
+ int bt656_enable;
+ /* cb:y:cr:y or y:cb:y:cr in memory */
+ enum ccdc_pixorder pix_order;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+};
+#endif
+#endif /* _DM644X_CCDC_H */
diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h
new file mode 100644
index 000000000000..71d8982e13ff
--- /dev/null
+++ b/include/media/davinci/vpfe_capture.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _VPFE_CAPTURE_H
+#define _VPFE_CAPTURE_H
+
+#ifdef __KERNEL__
+
+/* Header files */
+#include <media/v4l2-dev.h>
+#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/davinci/vpfe_types.h>
+
+#define VPFE_CAPTURE_NUM_DECODERS 5
+
+/* Macros */
+#define VPFE_MAJOR_RELEASE 0
+#define VPFE_MINOR_RELEASE 0
+#define VPFE_BUILD 1
+#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \
+ (VPFE_MINOR_RELEASE << 8) | \
+ VPFE_BUILD)
+
+#define CAPTURE_DRV_NAME "vpfe-capture"
+
+struct vpfe_pixel_format {
+ struct v4l2_fmtdesc fmtdesc;
+ /* bytes per pixel */
+ int bpp;
+};
+
+struct vpfe_std_info {
+ int active_pixels;
+ int active_lines;
+ /* current frame format */
+ int frame_format;
+};
+
+struct vpfe_route {
+ u32 input;
+ u32 output;
+};
+
+struct vpfe_subdev_info {
+ /* Sub device name */
+ char name[32];
+ /* Sub device group id */
+ int grp_id;
+ /* Number of inputs supported */
+ int num_inputs;
+ /* inputs available at the sub device */
+ struct v4l2_input *inputs;
+ /* Sub dev routing information for each input */
+ struct vpfe_route *routes;
+ /* check if sub dev supports routing */
+ int can_route;
+ /* ccdc bus/interface configuration */
+ struct vpfe_hw_if_param ccdc_if_params;
+ /* i2c subdevice board info */
+ struct i2c_board_info board_info;
+};
+
+struct vpfe_config {
+ /* Number of sub devices connected to vpfe */
+ int num_subdevs;
+ /* information about each subdev */
+ struct vpfe_subdev_info *sub_devs;
+ /* evm card info */
+ char *card_name;
+ /* ccdc name */
+ char *ccdc;
+ /* vpfe clock */
+ struct clk *vpssclk;
+ struct clk *slaveclk;
+};
+
+struct vpfe_device {
+ /* V4l2 specific parameters */
+ /* Identifies video device for this channel */
+ struct video_device *video_dev;
+ /* sub devices */
+ struct v4l2_subdev **sd;
+ /* vpfe cfg */
+ struct vpfe_config *cfg;
+ /* V4l2 device */
+ struct v4l2_device v4l2_dev;
+ /* parent device */
+ struct device *pdev;
+ /* Used to keep track of state of the priority */
+ struct v4l2_prio_state prio;
+ /* number of open instances of the channel */
+ u32 usrs;
+ /* Indicates id of the field which is being displayed */
+ u32 field_id;
+ /* flag to indicate whether decoder is initialized */
+ u8 initialized;
+ /* current interface type */
+ struct vpfe_hw_if_param vpfe_if_params;
+ /* ptr to currently selected sub device */
+ struct vpfe_subdev_info *current_subdev;
+ /* current input at the sub device */
+ int current_input;
+ /* Keeps track of the information about the standard */
+ struct vpfe_std_info std_info;
+ /* std index into std table */
+ int std_index;
+ /* CCDC IRQs used when CCDC/ISIF output to SDRAM */
+ unsigned int ccdc_irq0;
+ unsigned int ccdc_irq1;
+ /* number of buffers in fbuffers */
+ u32 numbuffers;
+ /* List of buffer pointers for storing frames */
+ u8 *fbuffers[VIDEO_MAX_FRAME];
+ /* Pointer pointing to current v4l2_buffer */
+ struct videobuf_buffer *cur_frm;
+ /* Pointer pointing to next v4l2_buffer */
+ struct videobuf_buffer *next_frm;
+ /*
+ * This field keeps track of type of buffer exchange mechanism
+ * user has selected
+ */
+ enum v4l2_memory memory;
+ /* Used to store pixel format */
+ struct v4l2_format fmt;
+ /*
+ * used when IMP is chained to store the crop window which
+ * is different from the image window
+ */
+ struct v4l2_rect crop;
+ /* Buffer queue used in video-buf */
+ struct videobuf_queue buffer_queue;
+ /* Queue of filled frames */
+ struct list_head dma_queue;
+ /* Used in video-buf */
+ spinlock_t irqlock;
+ /* IRQ lock for DMA queue */
+ spinlock_t dma_queue_lock;
+ /* lock used to access this structure */
+ struct mutex lock;
+ /* number of users performing IO */
+ u32 io_usrs;
+ /* Indicates whether streaming started */
+ u8 started;
+ /*
+ * offset where second field starts from the starting of the
+ * buffer for field seperated YCbCr formats
+ */
+ u32 field_off;
+};
+
+/* File handle structure */
+struct vpfe_fh {
+ struct vpfe_device *vpfe_dev;
+ /* Indicates whether this file handle is doing IO */
+ u8 io_allowed;
+ /* Used to keep track priority of this instance */
+ enum v4l2_priority prio;
+};
+
+struct vpfe_config_params {
+ u8 min_numbuffers;
+ u8 numbuffers;
+ u32 min_bufsize;
+ u32 device_bufsize;
+};
+
+#endif /* End of __KERNEL__ */
+/**
+ * VPFE_CMD_S_CCDC_RAW_PARAMS - EXPERIMENTAL IOCTL to set raw capture params
+ * This can be used to configure modules such as defect pixel correction,
+ * color space conversion, culling etc. This is an experimental ioctl that
+ * will change in future kernels. So use this ioctl with care !
+ * TODO: This is to be split into multiple ioctls and also explore the
+ * possibility of extending the v4l2 api to include this
+ **/
+#define VPFE_CMD_S_CCDC_RAW_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 1, \
+ void *)
+#endif /* _DAVINCI_VPFE_H */
diff --git a/include/media/davinci/vpfe_types.h b/include/media/davinci/vpfe_types.h
new file mode 100644
index 000000000000..76fb74bad08c
--- /dev/null
+++ b/include/media/davinci/vpfe_types.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008-2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option)any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _VPFE_TYPES_H
+#define _VPFE_TYPES_H
+
+#ifdef __KERNEL__
+
+enum vpfe_pin_pol {
+ VPFE_PINPOL_POSITIVE,
+ VPFE_PINPOL_NEGATIVE
+};
+
+enum vpfe_hw_if_type {
+ /* BT656 - 8 bit */
+ VPFE_BT656,
+ /* BT1120 - 16 bit */
+ VPFE_BT1120,
+ /* Raw Bayer */
+ VPFE_RAW_BAYER,
+ /* YCbCr - 8 bit with external sync */
+ VPFE_YCBCR_SYNC_8,
+ /* YCbCr - 16 bit with external sync */
+ VPFE_YCBCR_SYNC_16,
+ /* BT656 - 10 bit */
+ VPFE_BT656_10BIT
+};
+
+/* interface description */
+struct vpfe_hw_if_param {
+ enum vpfe_hw_if_type if_type;
+ enum vpfe_pin_pol hdpol;
+ enum vpfe_pin_pol vdpol;
+};
+
+#endif
+#endif
diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h
new file mode 100644
index 000000000000..fcdff745fae2
--- /dev/null
+++ b/include/media/davinci/vpss.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * vpss - video processing subsystem module header file.
+ *
+ * Include this header file if a driver needs to configure vpss system
+ * module. It exports a set of library functions for video drivers to
+ * configure vpss system module functions such as clock enable/disable,
+ * vpss interrupt mux to arm, and other common vpss system module
+ * functions.
+ */
+#ifndef _VPSS_H
+#define _VPSS_H
+
+/* selector for ccdc input selection on DM355 */
+enum vpss_ccdc_source_sel {
+ VPSS_CCDCIN,
+ VPSS_HSSIIN
+};
+
+/* Used for enable/diable VPSS Clock */
+enum vpss_clock_sel {
+ /* DM355/DM365 */
+ VPSS_CCDC_CLOCK,
+ VPSS_IPIPE_CLOCK,
+ VPSS_H3A_CLOCK,
+ VPSS_CFALD_CLOCK,
+ /*
+ * When using VPSS_VENC_CLOCK_SEL in vpss_enable_clock() api
+ * following applies:-
+ * en = 0 selects ENC_CLK
+ * en = 1 selects ENC_CLK/2
+ */
+ VPSS_VENC_CLOCK_SEL,
+ VPSS_VPBE_CLOCK,
+};
+
+/* select input to ccdc on dm355 */
+int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel);
+/* enable/disable a vpss clock, 0 - success, -1 - failure */
+int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en);
+
+/* wbl reset for dm644x */
+enum vpss_wbl_sel {
+ VPSS_PCR_AEW_WBL_0 = 16,
+ VPSS_PCR_AF_WBL_0,
+ VPSS_PCR_RSZ4_WBL_0,
+ VPSS_PCR_RSZ3_WBL_0,
+ VPSS_PCR_RSZ2_WBL_0,
+ VPSS_PCR_RSZ1_WBL_0,
+ VPSS_PCR_PREV_WBL_0,
+ VPSS_PCR_CCDC_WBL_O,
+};
+int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel);
+#endif
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 3ad4ed5402fb..defef3b18dfd 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -20,10 +20,27 @@ struct IR_i2c {
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
+enum ir_kbd_get_key_fn {
+ IR_KBD_GET_KEY_CUSTOM = 0,
+ IR_KBD_GET_KEY_PIXELVIEW,
+ IR_KBD_GET_KEY_PV951,
+ IR_KBD_GET_KEY_HAUP,
+ IR_KBD_GET_KEY_KNC1,
+ IR_KBD_GET_KEY_FUSIONHDTV,
+ IR_KBD_GET_KEY_HAUP_XVR,
+ IR_KBD_GET_KEY_AVERMEDIA_CARDBUS,
+};
+
/* Can be passed when instantiating an ir_video i2c device */
struct IR_i2c_init_data {
IR_KEYTAB_TYPE *ir_codes;
const char *name;
+ int type; /* IR_TYPE_RC5, IR_TYPE_PD, etc */
+ /*
+ * Specify either a function pointer or a value indicating one of
+ * ir_kbd_i2c's internal get_key functions
+ */
int (*get_key)(struct IR_i2c*, u32*, u32*);
+ enum ir_kbd_get_key_fn internal_get_key_func;
};
#endif
diff --git a/include/media/tuner.h b/include/media/tuner.h
index cbf97f45fbec..c146f2f530b0 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -126,6 +126,7 @@
#define TUNER_PHILIPS_FMD1216MEX_MK3 78
#define TUNER_PHILIPS_FM1216MK5 79
#define TUNER_PHILIPS_FQ1216LME_MK3 80 /* Active loopthrough, no FM */
+#define TUNER_PARTSNIC_PTI_5NF05 81
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
index 5e7ee968c6dc..74387e83f5b9 100644
--- a/include/media/tvp514x.h
+++ b/include/media/tvp514x.h
@@ -104,10 +104,6 @@ enum tvp514x_output {
* @ vs_polarity: VSYNC Polarity configuration for current interface.
*/
struct tvp514x_platform_data {
- char *master;
- int (*power_set) (enum v4l2_power on);
- int (*ifparm) (struct v4l2_ifparm *p);
- int (*priv_data_set) (void *);
/* Interface control params */
bool clk_polarity;
bool hs_polarity;
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 11a4a2d3e364..94e908c0d7a0 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -60,6 +60,10 @@ enum {
V4L2_IDENT_OV7670 = 250,
V4L2_IDENT_OV7720 = 251,
V4L2_IDENT_OV7725 = 252,
+ V4L2_IDENT_OV7660 = 253,
+ V4L2_IDENT_OV9650 = 254,
+ V4L2_IDENT_OV9655 = 255,
+ V4L2_IDENT_SOI968 = 256,
/* module saa7146: reserved range 300-309 */
V4L2_IDENT_SAA7146 = 300,
@@ -161,6 +165,9 @@ enum {
/* module tw9910: just ident 9910 */
V4L2_IDENT_TW9910 = 9910,
+ /* module sn9c20x: just ident 10000 */
+ V4L2_IDENT_SN9C20X = 10000,
+
/* module msp3400: reserved range 34000-34999 and 44000-44999 */
V4L2_IDENT_MSPX4XX = 34000, /* generic MSPX4XX identifier, only
use internally (tveeprom.c). */
@@ -237,6 +244,11 @@ enum {
V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */
V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */
V4L2_IDENT_MT9T031 = 45020,
+ V4L2_IDENT_MT9V111 = 45031,
+ V4L2_IDENT_MT9V112 = 45032,
+
+ /* HV7131R CMOS sensor: just ident 46000 */
+ V4L2_IDENT_HV7131R = 46000,
/* module cs53132a: just ident 53132 */
V4L2_IDENT_CS53l32A = 53132,
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 5dcb36785529..89a39ce17294 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -220,6 +220,9 @@ struct v4l2_subdev_video_ops {
int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
int (*try_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+ int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
+ int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
+ int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/af_ieee802154.h
index 0d78605fb1a6..0d78605fb1a6 100644
--- a/include/net/ieee802154/af_ieee802154.h
+++ b/include/net/af_ieee802154.h
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e919fca1072a..06b072fd6d54 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -190,7 +190,7 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_RETRANS 0x01
#define L2CAP_MODE_FLOWCTL 0x02
#define L2CAP_MODE_ERTM 0x03
-#define L2CAP_MODE_STREAM 0x04
+#define L2CAP_MODE_STREAMING 0x04
struct l2cap_disconn_req {
__le16 dcid;
@@ -271,9 +271,11 @@ struct l2cap_pinfo {
__u16 imtu;
__u16 omtu;
__u16 flush_to;
- __u8 sec_level;
+ __u8 mode;
+ __u8 fcs;
+ __u8 sec_level;
__u8 role_switch;
- __u8 force_reliable;
+ __u8 force_reliable;
__u8 conf_req[64];
__u8 conf_len;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1a21895b732b..e1b92358242b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -538,11 +538,11 @@ struct cfg80211_ssid {
* @ssids: SSIDs to scan for (active scan only)
* @n_ssids: number of SSIDs
* @channels: channels to scan on.
- * @n_channels: number of channels for each band
+ * @n_channels: total number of channels to scan
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
* @wiphy: the wiphy this was for
- * @ifidx: the interface index
+ * @dev: the interface
*/
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
@@ -554,7 +554,8 @@ struct cfg80211_scan_request {
/* internal */
struct wiphy *wiphy;
- int ifidx;
+ struct net_device *dev;
+ bool aborted;
};
/**
@@ -584,7 +585,6 @@ enum cfg80211_signal_type {
* is no guarantee that these are well-formed!)
* @len_information_elements: total length of the information elements
* @signal: signal strength value (type depends on the wiphy's signal_type)
- * @hold: BSS should not expire
* @free_priv: function pointer to free private data
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
*/
@@ -605,37 +605,59 @@ struct cfg80211_bss {
};
/**
+ * ieee80211_bss_get_ie - find IE with given ID
+ * @bss: the bss to search
+ * @ie: the IE ID
+ * Returns %NULL if not found.
+ */
+const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
+
+
+/**
+ * struct cfg80211_crypto_settings - Crypto settings
+ * @wpa_versions: indicates which, if any, WPA versions are enabled
+ * (from enum nl80211_wpa_versions)
+ * @cipher_group: group key cipher suite (or 0 if unset)
+ * @n_ciphers_pairwise: number of AP supported unicast ciphers
+ * @ciphers_pairwise: unicast key cipher suites
+ * @n_akm_suites: number of AKM suites
+ * @akm_suites: AKM suites
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ * required to assume that the port is unauthorized until authorized by
+ * user space. Otherwise, port is marked authorized by default.
+ */
+struct cfg80211_crypto_settings {
+ u32 wpa_versions;
+ u32 cipher_group;
+ int n_ciphers_pairwise;
+ u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
+ int n_akm_suites;
+ u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+ bool control_port;
+};
+
+/**
* struct cfg80211_auth_request - Authentication request data
*
* This structure provides information needed to complete IEEE 802.11
* authentication.
- * NOTE: This structure will likely change when more code from mac80211 is
- * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
- * Before using this in a driver that does not use mac80211, it would be better
- * to check the status of that work and better yet, volunteer to work on it.
- *
- * @chan: The channel to use or %NULL if not specified (auto-select based on
- * scan results)
- * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case);
- * this field is required to be present; if the driver wants to help with
- * BSS selection, it should use (yet to be added) MLME event to allow user
- * space SME to be notified of roaming candidate, so that the SME can then
- * use the authentication request with the recommended BSSID and whatever
- * other data may be needed for authentication/association
- * @ssid: SSID or %NULL if not yet available
- * @ssid_len: Length of ssid in octets
+ *
+ * @bss: The BSS to authenticate with.
* @auth_type: Authentication type (algorithm)
* @ie: Extra IEs to add to Authentication frame or %NULL
* @ie_len: Length of ie buffer in octets
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
*/
struct cfg80211_auth_request {
- struct ieee80211_channel *chan;
- u8 *peer_addr;
- const u8 *ssid;
- size_t ssid_len;
- enum nl80211_auth_type auth_type;
+ struct cfg80211_bss *bss;
const u8 *ie;
size_t ie_len;
+ enum nl80211_auth_type auth_type;
+ const u8 *key;
+ u8 key_len, key_idx;
};
/**
@@ -643,35 +665,19 @@ struct cfg80211_auth_request {
*
* This structure provides information needed to complete IEEE 802.11
* (re)association.
- * NOTE: This structure will likely change when more code from mac80211 is
- * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
- * Before using this in a driver that does not use mac80211, it would be better
- * to check the status of that work and better yet, volunteer to work on it.
- *
- * @chan: The channel to use or %NULL if not specified (auto-select based on
- * scan results)
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- * to be present and the STA must be in State 2 (authenticated) with the
- * peer STA
- * @ssid: SSID
- * @ssid_len: Length of ssid in octets
+ * @bss: The BSS to associate with.
* @ie: Extra IEs to add to (Re)Association Request frame or %NULL
* @ie_len: Length of ie buffer in octets
* @use_mfp: Use management frame protection (IEEE 802.11w) in this association
- * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
- * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
- * required to assume that the port is unauthorized until authorized by
- * user space. Otherwise, port is marked authorized by default.
+ * @crypto: crypto settings
+ * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
*/
struct cfg80211_assoc_request {
- struct ieee80211_channel *chan;
- u8 *peer_addr;
- const u8 *ssid;
- size_t ssid_len;
- const u8 *ie;
+ struct cfg80211_bss *bss;
+ const u8 *ie, *prev_bssid;
size_t ie_len;
+ struct cfg80211_crypto_settings crypto;
bool use_mfp;
- bool control_port;
};
/**
@@ -680,16 +686,16 @@ struct cfg80211_assoc_request {
* This structure provides information needed to complete IEEE 802.11
* deauthentication.
*
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- * to be present and the STA must be authenticated with the peer STA
+ * @bss: the BSS to deauthenticate from
* @ie: Extra IEs to add to Deauthentication frame or %NULL
* @ie_len: Length of ie buffer in octets
+ * @reason_code: The reason code for the deauthentication
*/
struct cfg80211_deauth_request {
- u8 *peer_addr;
- u16 reason_code;
+ struct cfg80211_bss *bss;
const u8 *ie;
size_t ie_len;
+ u16 reason_code;
};
/**
@@ -698,16 +704,16 @@ struct cfg80211_deauth_request {
* This structure provides information needed to complete IEEE 802.11
* disassocation.
*
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- * to be present and the STA must be associated with the peer STA
+ * @bss: the BSS to disassociate from
* @ie: Extra IEs to add to Disassociation frame or %NULL
* @ie_len: Length of ie buffer in octets
+ * @reason_code: The reason code for the disassociation
*/
struct cfg80211_disassoc_request {
- u8 *peer_addr;
- u16 reason_code;
+ struct cfg80211_bss *bss;
const u8 *ie;
size_t ie_len;
+ u16 reason_code;
};
/**
@@ -726,6 +732,8 @@ struct cfg80211_disassoc_request {
* @ie: information element(s) to include in the beacon
* @ie_len: length of that
* @beacon_interval: beacon interval to use
+ * @privacy: this is a protected network, keys will be configured
+ * after joining
*/
struct cfg80211_ibss_params {
u8 *ssid;
@@ -735,6 +743,42 @@ struct cfg80211_ibss_params {
u8 ssid_len, ie_len;
u16 beacon_interval;
bool channel_fixed;
+ bool privacy;
+};
+
+/**
+ * struct cfg80211_connect_params - Connection parameters
+ *
+ * This structure provides information needed to complete IEEE 802.11
+ * authentication and association.
+ *
+ * @channel: The channel to use or %NULL if not specified (auto-select based
+ * on scan results)
+ * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
+ * results)
+ * @ssid: SSID
+ * @ssid_len: Length of ssid in octets
+ * @auth_type: Authentication type (algorithm)
+ * @assoc_ie: IEs for association request
+ * @assoc_ie_len: Length of assoc_ie in octets
+ * @privacy: indicates whether privacy-enabled APs should be used
+ * @crypto: crypto settings
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
+ */
+struct cfg80211_connect_params {
+ struct ieee80211_channel *channel;
+ u8 *bssid;
+ u8 *ssid;
+ size_t ssid_len;
+ enum nl80211_auth_type auth_type;
+ u8 *ie;
+ size_t ie_len;
+ bool privacy;
+ struct cfg80211_crypto_settings crypto;
+ const u8 *key;
+ u8 key_len, key_idx;
};
/**
@@ -764,6 +808,26 @@ enum tx_power_setting {
TX_POWER_FIXED,
};
+/*
+ * cfg80211_bitrate_mask - masks for bitrate control
+ */
+struct cfg80211_bitrate_mask {
+/*
+ * As discussed in Berlin, this struct really
+ * should look like this:
+
+ struct {
+ u32 legacy;
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
+ } control[IEEE80211_NUM_BANDS];
+
+ * Since we can always fix in-kernel users, let's keep
+ * it simpler for now:
+ */
+ u32 fixed; /* fixed bitrate, 0 == not fixed */
+ u32 maxrate; /* in kbps, 0 == no limit */
+};
+
/**
* struct cfg80211_ops - backend description for wireless configuration
*
@@ -781,7 +845,8 @@ enum tx_power_setting {
* @resume: wiphy device needs to be resumed
*
* @add_virtual_intf: create a new virtual interface with the given name,
- * must set the struct wireless_dev's iftype.
+ * must set the struct wireless_dev's iftype. Beware: You must create
+ * the new netdev in the wiphy's network namespace!
*
* @del_virtual_intf: remove the virtual interface determined by ifindex.
*
@@ -841,6 +906,12 @@ enum tx_power_setting {
* @deauth: Request to deauthenticate from the specified peer
* @disassoc: Request to disassociate from the specified peer
*
+ * @connect: Connect to the ESS with the specified parameters. When connected,
+ * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
+ * If the connection fails for some reason, call cfg80211_connect_result()
+ * with the status from the AP.
+ * @disconnect: Disconnect from the BSS/ESS.
+ *
* @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
* cfg80211_ibss_joined(), also call that function when changing BSSID due
* to a merge.
@@ -857,6 +928,8 @@ enum tx_power_setting {
*
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
+ *
+ * @testmode_cmd: run a test mode command
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@@ -865,8 +938,9 @@ struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
- int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
- int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
+ int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev);
+ int (*change_virtual_intf)(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
@@ -939,9 +1013,16 @@ struct cfg80211_ops {
int (*assoc)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_request *req);
int (*deauth)(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_deauth_request *req);
+ struct cfg80211_deauth_request *req,
+ void *cookie);
int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_disassoc_request *req);
+ struct cfg80211_disassoc_request *req,
+ void *cookie);
+
+ int (*connect)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+ int (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code);
int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params);
@@ -953,7 +1034,23 @@ struct cfg80211_ops {
enum tx_power_setting type, int dbm);
int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
+ int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *addr);
+
void (*rfkill_poll)(struct wiphy *wiphy);
+
+#ifdef CONFIG_NL80211_TESTMODE
+ int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
+#endif
+
+ int (*set_bitrate_mask)(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *peer,
+ const struct cfg80211_bitrate_mask *mask);
+
+ /* some temporary stuff to finish wext */
+ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout);
};
/*
@@ -992,6 +1089,9 @@ struct cfg80211_ops {
* @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
* -1 = fragmentation disabled, only odd values >= 256 used
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
+ * @net: the network namespace this wiphy currently lives in
+ * @netnsok: if set to false, do not allow changing the netns of this
+ * wiphy at all
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -1005,6 +1105,8 @@ struct wiphy {
bool custom_regulatory;
bool strict_regulatory;
+ bool netnsok;
+
enum cfg80211_signal_type signal_type;
int bss_priv_size;
@@ -1043,9 +1145,35 @@ struct wiphy {
/* dir in debugfs: ieee80211/<wiphyname> */
struct dentry *debugfsdir;
+#ifdef CONFIG_NET_NS
+ /* the network namespace this phy lives in currently */
+ struct net *_net;
+#endif
+
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
+#ifdef CONFIG_NET_NS
+static inline struct net *wiphy_net(struct wiphy *wiphy)
+{
+ return wiphy->_net;
+}
+
+static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
+{
+ wiphy->_net = net;
+}
+#else
+static inline struct net *wiphy_net(struct wiphy *wiphy)
+{
+ return &init_net;
+}
+
+static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
+{
+}
+#endif
+
/**
* wiphy_priv - return priv from wiphy
*
@@ -1058,6 +1186,17 @@ static inline void *wiphy_priv(struct wiphy *wiphy)
}
/**
+ * priv_to_wiphy - return the wiphy containing the priv
+ *
+ * @priv: a pointer previously returned by wiphy_priv
+ */
+static inline struct wiphy *priv_to_wiphy(void *priv)
+{
+ BUG_ON(!priv);
+ return container_of(priv, struct wiphy, priv);
+}
+
+/**
* set_wiphy_dev - set device pointer for wiphy
*
* @wiphy: The wiphy whose device to bind
@@ -1129,6 +1268,13 @@ extern void wiphy_unregister(struct wiphy *wiphy);
*/
extern void wiphy_free(struct wiphy *wiphy);
+/* internal structs */
+struct cfg80211_conn;
+struct cfg80211_internal_bss;
+struct cfg80211_cached_keys;
+
+#define MAX_AUTH_BSSES 4
+
/**
* struct wireless_dev - wireless per-netdev state
*
@@ -1152,22 +1298,43 @@ struct wireless_dev {
struct wiphy *wiphy;
enum nl80211_iftype iftype;
- /* private to the generic wireless code */
+ /* the remainder of this struct should be private to cfg80211 */
struct list_head list;
struct net_device *netdev;
- /* currently used for IBSS - might be rearranged in the future */
- struct cfg80211_bss *current_bss;
- u8 bssid[ETH_ALEN];
+ struct mutex mtx;
+
+ /* currently used for IBSS and SME - might be rearranged later */
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
+ enum {
+ CFG80211_SME_IDLE,
+ CFG80211_SME_CONNECTING,
+ CFG80211_SME_CONNECTED,
+ } sme_state;
+ struct cfg80211_conn *conn;
+ struct cfg80211_cached_keys *connect_keys;
+
+ struct list_head event_list;
+ spinlock_t event_lock;
+
+ struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
+ struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
+ struct cfg80211_internal_bss *current_bss; /* associated / joined */
#ifdef CONFIG_WIRELESS_EXT
/* wext data */
struct {
struct cfg80211_ibss_params ibss;
+ struct cfg80211_connect_params connect;
+ struct cfg80211_cached_keys *keys;
+ u8 *ie;
+ size_t ie_len;
u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
s8 default_key, default_mgmt_key;
+ bool ps;
+ int ps_timeout;
} wext;
#endif
};
@@ -1428,27 +1595,34 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
int cfg80211_wext_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra);
-int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra);
-int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra);
-int cfg80211_ibss_wext_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid);
-int cfg80211_ibss_wext_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid);
-int cfg80211_ibss_wext_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra);
-int cfg80211_ibss_wext_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra);
+int cfg80211_wext_siwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+int cfg80211_wext_siwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra);
+int cfg80211_wext_giwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra);
-struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
- struct iw_freq *freq);
+int cfg80211_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_wext_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra);
+int cfg80211_wext_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra);
int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_request_info *info,
@@ -1483,6 +1657,21 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
int cfg80211_wext_giwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *keybuf);
+struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev);
+
+int cfg80211_wext_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra);
+int cfg80211_wext_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra);
+
+int cfg80211_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
/*
* callbacks for asynchronous cfg80211 methods, notification
@@ -1564,7 +1753,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
* This function is called whenever an authentication has been processed in
* station mode. The driver is required to call either this function or
* cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth()
- * call.
+ * call. This function may sleep.
*/
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
@@ -1572,6 +1761,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
* cfg80211_send_auth_timeout - notification of timed out authentication
* @dev: network device
* @addr: The MAC address of the device with which the authentication timed out
+ *
+ * This function may sleep.
*/
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
@@ -1584,7 +1775,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
* This function is called whenever a (re)association response has been
* processed in station mode. The driver is required to call either this
* function or cfg80211_send_assoc_timeout() to indicate the result of
- * cfg80211_ops::assoc() call.
+ * cfg80211_ops::assoc() call. This function may sleep.
*/
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
@@ -1592,6 +1783,8 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
* cfg80211_send_assoc_timeout - notification of timed out association
* @dev: network device
* @addr: The MAC address of the device with which the association timed out
+ *
+ * This function may sleep.
*/
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
@@ -1600,41 +1793,30 @@ 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.
+ * locally generated ones. This function may sleep.
*/
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
+ void *cookie);
/**
* 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.
+ * generated ones. This function may sleep.
*/
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
-
-/**
- * cfg80211_hold_bss - exclude bss from expiration
- * @bss: bss which should not expire
- *
- * In a case when the BSS is not updated but it shouldn't expire this
- * function can be used to mark the BSS to be excluded from expiration.
- */
-void cfg80211_hold_bss(struct cfg80211_bss *bss);
-
-/**
- * cfg80211_unhold_bss - remove expiration exception from the BSS
- * @bss: bss which can expire again
- *
- * This function marks the BSS to be expirable again.
- */
-void cfg80211_unhold_bss(struct cfg80211_bss *bss);
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
+ void *cookie);
/**
* cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
@@ -1643,6 +1825,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss);
* @key_type: The key type that the received frame used
* @key_id: Key identifier (0..3)
* @tsc: The TSC value of the frame that generated the MIC failure (6 octets)
+ * @gfp: allocation flags
*
* This function is called whenever the local MAC detects a MIC failure in a
* received frame. This matches with MLME-MICHAELMICFAILURE.indication()
@@ -1650,7 +1833,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss);
*/
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
- const u8 *tsc);
+ const u8 *tsc, gfp_t gfp);
/**
* cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS
@@ -1687,4 +1870,137 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy);
*/
void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
+#ifdef CONFIG_NL80211_TESTMODE
+/**
+ * cfg80211_testmode_alloc_reply_skb - allocate testmode reply
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ * be put into the skb
+ *
+ * This function allocates and pre-fills an skb for a reply to
+ * the testmode command. Since it is intended for a reply, calling
+ * it outside of the @testmode_cmd operation is invalid.
+ *
+ * The returned skb (or %NULL if any errors happen) is pre-filled
+ * with the wiphy index and set up in a way that any data that is
+ * put into the skb (with skb_put(), nla_put() or similar) will end
+ * up being within the %NL80211_ATTR_TESTDATA attribute, so all that
+ * needs to be done with the skb is adding data for the corresponding
+ * userspace tool which can then read that data out of the testdata
+ * attribute. You must not modify the skb in any other way.
+ *
+ * When done, call cfg80211_testmode_reply() with the skb and return
+ * its error code as the result of the @testmode_cmd operation.
+ */
+struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
+ int approxlen);
+
+/**
+ * cfg80211_testmode_reply - send the reply skb
+ * @skb: The skb, must have been allocated with
+ * cfg80211_testmode_alloc_reply_skb()
+ *
+ * Returns an error code or 0 on success, since calling this
+ * function will usually be the last thing before returning
+ * from the @testmode_cmd you should return the error code.
+ * Note that this function consumes the skb regardless of the
+ * return value.
+ */
+int cfg80211_testmode_reply(struct sk_buff *skb);
+
+/**
+ * cfg80211_testmode_alloc_event_skb - allocate testmode event
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ * be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * testmode multicast group.
+ *
+ * The returned skb (or %NULL if any errors happen) is set up in the
+ * same way as with cfg80211_testmode_alloc_reply_skb() but prepared
+ * for an event. As there, you should simply add data to it that will
+ * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must
+ * not modify the skb in any other way.
+ *
+ * When done filling the skb, call cfg80211_testmode_event() with the
+ * skb to send the event.
+ */
+struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
+ int approxlen, gfp_t gfp);
+
+/**
+ * cfg80211_testmode_event - send the event
+ * @skb: The skb, must have been allocated with
+ * cfg80211_testmode_alloc_event_skb()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_testmode_alloc_event_skb(), as an event. It always
+ * consumes it.
+ */
+void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+
+#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd),
+#else
+#define CFG80211_TESTMODE_CMD(cmd)
+#endif
+
+/**
+ * cfg80211_connect_result - notify cfg80211 of connection result
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the AP
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @status: status code, 0 for successful connection, use
+ * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ * the real status code for failures.
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver whenever connect() has
+ * succeeded.
+ */
+void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, gfp_t gfp);
+
+/**
+ * cfg80211_roamed - notify cfg80211 of roaming
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the new AP
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver whenever it roamed
+ * from one AP to another while connected.
+ */
+void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+
+/**
+ * cfg80211_disconnected - notify cfg80211 that connection was dropped
+ *
+ * @dev: network device
+ * @ie: information elements of the deauth/disassoc frame (may be %NULL)
+ * @ie_len: length of IEs
+ * @reason: reason code for the disconnection, set it to 0 if unknown
+ * @gfp: allocation flags
+ *
+ * After it calls this function, the driver should enter an idle state
+ * and not try to connect to any AP any more.
+ */
+void cfg80211_disconnected(struct net_device *dev, u16 reason,
+ u8 *ie, size_t ie_len, gfp_t gfp);
+
+
#endif /* __NET_CFG80211_H */
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 1b0e3ee4ddd8..2a1c06874c42 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -3,6 +3,7 @@
#include <linux/genetlink.h>
#include <net/netlink.h>
+#include <net/net_namespace.h>
/**
* struct genl_multicast_group - generic netlink multicast group
@@ -27,6 +28,8 @@ struct genl_multicast_group
* @name: name of family
* @version: protocol version
* @maxattr: maximum number of attributes supported
+ * @netnsok: set to true if the family can handle network
+ * namespaces and should be presented in all of them
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
@@ -39,6 +42,7 @@ struct genl_family
char name[GENL_NAMSIZ];
unsigned int version;
unsigned int maxattr;
+ bool netnsok;
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
@@ -62,8 +66,32 @@ struct genl_info
struct genlmsghdr * genlhdr;
void * userhdr;
struct nlattr ** attrs;
+#ifdef CONFIG_NET_NS
+ struct net * _net;
+#endif
};
+#ifdef CONFIG_NET_NS
+static inline struct net *genl_info_net(struct genl_info *info)
+{
+ return info->_net;
+}
+
+static inline void genl_info_net_set(struct genl_info *info, struct net *net)
+{
+ info->_net = net;
+}
+#else
+static inline struct net *genl_info_net(struct genl_info *info)
+{
+ return &init_net;
+}
+
+static inline void genl_info_net_set(struct genl_info *info, struct net *net)
+{
+}
+#endif
+
/**
* struct genl_ops - generic netlink operations
* @cmd: command identifier
@@ -98,8 +126,6 @@ extern int genl_register_mc_group(struct genl_family *family,
extern void genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp);
-extern struct sock *genl_sock;
-
/**
* genlmsg_put - Add generic netlink header to netlink message
* @skb: socket buffer holding the message
@@ -170,7 +196,21 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
}
/**
- * genlmsg_multicast - multicast a netlink message
+ * genlmsg_multicast_netns - multicast a netlink message to a specific netns
+ * @net: the net namespace
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ */
+static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
+ u32 pid, unsigned int group, gfp_t flags)
+{
+ return nlmsg_multicast(net->genl_sock, skb, pid, group, flags);
+}
+
+/**
+ * genlmsg_multicast - multicast a netlink message to the default netns
* @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id
@@ -179,17 +219,29 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
unsigned int group, gfp_t flags)
{
- return nlmsg_multicast(genl_sock, skb, pid, group, flags);
+ return genlmsg_multicast_netns(&init_net, skb, pid, group, flags);
}
/**
+ * genlmsg_multicast_allns - multicast a netlink message to all net namespaces
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ *
+ * This function must hold the RTNL or rcu_read_lock().
+ */
+int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid,
+ unsigned int group, gfp_t flags);
+
+/**
* genlmsg_unicast - unicast a netlink message
* @skb: netlink message as socket buffer
* @pid: netlink pid of the destination socket
*/
-static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
+static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid)
{
- return nlmsg_unicast(genl_sock, skb, pid);
+ return nlmsg_unicast(net->genl_sock, skb, pid);
}
/**
@@ -199,7 +251,7 @@ static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
*/
static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
{
- return genlmsg_unicast(skb, info->snd_pid);
+ return genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
}
/**
diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154.h
index 8cb684635650..d52685defb11 100644
--- a/include/net/ieee802154/mac_def.h
+++ b/include/net/ieee802154.h
@@ -23,8 +23,8 @@
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
*/
-#ifndef IEEE802154_MAC_DEF_H
-#define IEEE802154_MAC_DEF_H
+#ifndef NET_IEEE802154_H
+#define NET_IEEE802154_H
#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */
#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */
diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h
deleted file mode 100644
index 78efcdf52b59..000000000000
--- a/include/net/ieee802154/nl802154.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * nl802154.h
- *
- * Copyright (C) 2007, 2008, 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#ifndef IEEE802154_NL_H
-#define IEEE802154_NL_H
-
-struct net_device;
-struct ieee802154_addr;
-
-int ieee802154_nl_assoc_indic(struct net_device *dev,
- struct ieee802154_addr *addr, u8 cap);
-int ieee802154_nl_assoc_confirm(struct net_device *dev,
- u16 short_addr, u8 status);
-int ieee802154_nl_disassoc_indic(struct net_device *dev,
- struct ieee802154_addr *addr, u8 reason);
-int ieee802154_nl_disassoc_confirm(struct net_device *dev,
- u8 status);
-int ieee802154_nl_scan_confirm(struct net_device *dev,
- u8 status, u8 scan_type, u32 unscanned,
- u8 *edl/*, struct list_head *pan_desc_list */);
-int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
- u16 coord_addr);
-
-#endif
diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154_netdev.h
index e2506af3e7c8..e2506af3e7c8 100644
--- a/include/net/ieee802154/netdevice.h
+++ b/include/net/ieee802154_netdev.h
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 7c5c0f79168a..15b492a9aa79 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -22,6 +22,12 @@
#include <net/flow.h>
#include <net/netlink.h>
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+#define FIB6_TABLE_HASHSZ 256
+#else
+#define FIB6_TABLE_HASHSZ 1
+#endif
+
struct rt6_info;
struct fib6_config
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index bbae1e87efcd..910820327bc4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -99,47 +99,47 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
return &buf[*idx - len];
}
-#define IP_VS_DBG_BUF(level, msg...) \
- do { \
- char ip_vs_dbg_buf[160]; \
- int ip_vs_dbg_idx = 0; \
- if (level <= ip_vs_get_debug_level()) \
- printk(KERN_DEBUG "IPVS: " msg); \
- } while (0)
-#define IP_VS_ERR_BUF(msg...) \
- do { \
- char ip_vs_dbg_buf[160]; \
- int ip_vs_dbg_idx = 0; \
- printk(KERN_ERR "IPVS: " msg); \
- } while (0)
+#define IP_VS_DBG_BUF(level, msg, ...) \
+ do { \
+ char ip_vs_dbg_buf[160]; \
+ int ip_vs_dbg_idx = 0; \
+ if (level <= ip_vs_get_debug_level()) \
+ printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \
+ } while (0)
+#define IP_VS_ERR_BUF(msg...) \
+ do { \
+ char ip_vs_dbg_buf[160]; \
+ int ip_vs_dbg_idx = 0; \
+ pr_err(msg); \
+ } while (0)
/* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */
-#define IP_VS_DBG_ADDR(af, addr) \
- ip_vs_dbg_addr(af, ip_vs_dbg_buf, \
- sizeof(ip_vs_dbg_buf), addr, \
- &ip_vs_dbg_idx)
-
-#define IP_VS_DBG(level, msg...) \
- do { \
- if (level <= ip_vs_get_debug_level()) \
- printk(KERN_DEBUG "IPVS: " msg); \
- } while (0)
-#define IP_VS_DBG_RL(msg...) \
- do { \
- if (net_ratelimit()) \
- printk(KERN_DEBUG "IPVS: " msg); \
- } while (0)
-#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \
- do { \
- if (level <= ip_vs_get_debug_level()) \
- pp->debug_packet(pp, skb, ofs, msg); \
- } while (0)
-#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \
- do { \
- if (level <= ip_vs_get_debug_level() && \
- net_ratelimit()) \
- pp->debug_packet(pp, skb, ofs, msg); \
- } while (0)
+#define IP_VS_DBG_ADDR(af, addr) \
+ ip_vs_dbg_addr(af, ip_vs_dbg_buf, \
+ sizeof(ip_vs_dbg_buf), addr, \
+ &ip_vs_dbg_idx)
+
+#define IP_VS_DBG(level, msg, ...) \
+ do { \
+ if (level <= ip_vs_get_debug_level()) \
+ printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \
+ } while (0)
+#define IP_VS_DBG_RL(msg, ...) \
+ do { \
+ if (net_ratelimit()) \
+ printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \
+ } while (0)
+#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \
+ do { \
+ if (level <= ip_vs_get_debug_level()) \
+ pp->debug_packet(pp, skb, ofs, msg); \
+ } while (0)
+#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \
+ do { \
+ if (level <= ip_vs_get_debug_level() && \
+ net_ratelimit()) \
+ pp->debug_packet(pp, skb, ofs, msg); \
+ } while (0)
#else /* NO DEBUGGING at ALL */
#define IP_VS_DBG_BUF(level, msg...) do {} while (0)
#define IP_VS_ERR_BUF(msg...) do {} while (0)
@@ -150,29 +150,30 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
#endif
#define IP_VS_BUG() BUG()
-#define IP_VS_ERR(msg...) printk(KERN_ERR "IPVS: " msg)
-#define IP_VS_INFO(msg...) printk(KERN_INFO "IPVS: " msg)
-#define IP_VS_WARNING(msg...) \
- printk(KERN_WARNING "IPVS: " msg)
-#define IP_VS_ERR_RL(msg...) \
- do { \
- if (net_ratelimit()) \
- printk(KERN_ERR "IPVS: " msg); \
- } while (0)
+#define IP_VS_ERR(msg...) pr_err(msg)
+#define IP_VS_INFO(msg...) pr_info(msg)
+#define IP_VS_WARNING(msg...) pr_warning(msg)
+#define IP_VS_ERR_RL(msg...) \
+ do { \
+ if (net_ratelimit()) \
+ pr_err(msg); \
+ } while (0)
#ifdef CONFIG_IP_VS_DEBUG
#define EnterFunction(level) \
- do { \
- if (level <= ip_vs_get_debug_level()) \
- printk(KERN_DEBUG "Enter: %s, %s line %i\n", \
- __func__, __FILE__, __LINE__); \
- } while (0)
-#define LeaveFunction(level) \
- do { \
- if (level <= ip_vs_get_debug_level()) \
- printk(KERN_DEBUG "Leave: %s, %s line %i\n", \
- __func__, __FILE__, __LINE__); \
- } while (0)
+ do { \
+ if (level <= ip_vs_get_debug_level()) \
+ printk(KERN_DEBUG \
+ pr_fmt("Enter: %s, %s line %i\n"), \
+ __func__, __FILE__, __LINE__); \
+ } while (0)
+#define LeaveFunction(level) \
+ do { \
+ if (level <= ip_vs_get_debug_level()) \
+ printk(KERN_DEBUG \
+ pr_fmt("Leave: %s, %s line %i\n"), \
+ __func__, __FILE__, __LINE__); \
+ } while (0)
#else
#define EnterFunction(level) do {} while (0)
#define LeaveFunction(level) do {} while (0)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index f27fd83d67d8..ad9a51130254 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -441,6 +441,18 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
}
+static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr)
+{
+ static u32 ipv6_fragmentation_id = 1;
+ static DEFINE_SPINLOCK(ip6_id_lock);
+
+ spin_lock_bh(&ip6_id_lock);
+ fhdr->identification = htonl(ipv6_fragmentation_id);
+ if (++ipv6_fragmentation_id == 0)
+ ipv6_fragmentation_id = 1;
+ spin_unlock_bh(&ip6_id_lock);
+}
+
/*
* Prototypes exported by ipv6
*/
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index 51b9a37de991..2b3fbbb8669e 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -443,7 +443,7 @@ extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
extern void wireless_send_event(struct net_device * dev,
unsigned int cmd,
union iwreq_data * wrqu,
- char * extra);
+ const char * extra);
/* We may need a function to send a stream of events to user space.
* More on that later... */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c06104476973..d4e09a06b4a2 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -241,6 +241,11 @@ struct ieee80211_bss_conf {
* it can be sent out.
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
* used to indicate that a frame was already retried due to PS
+ * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
+ * used to indicate frame should not be encrypted
+ * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?)
+ * This frame is a response to a PS-poll frame and should be sent
+ * although the station is in powersave mode.
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@@ -259,6 +264,8 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_RCALGO = BIT(13),
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15),
+ IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
+ IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17),
};
/**
@@ -397,6 +404,11 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
return (struct ieee80211_tx_info *)skb->cb;
}
+static inline struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb)
+{
+ return (struct ieee80211_rx_status *)skb->cb;
+}
+
/**
* ieee80211_tx_info_clear_status - clear TX status
*
@@ -478,7 +490,7 @@ enum mac80211_rx_flags {
*
* The low-level driver should provide this information (the subset
* supported by hardware) to the 802.11 code with each received
- * frame.
+ * frame, in the skb's control buffer (cb).
*
* @mactime: value in microseconds of the 64-bit Time Synchronization Function
* (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
@@ -1411,6 +1423,8 @@ enum ieee80211_ampdu_mlme_action {
* @rfkill_poll: Poll rfkill hardware state. If you need this, you also
* need to set wiphy->rfkill_poll to %true before registration,
* and need to call wiphy_rfkill_set_hw_state() in the callback.
+ *
+ * @testmode_cmd: Implement a cfg80211 test mode command.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1461,6 +1475,9 @@ struct ieee80211_ops {
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
void (*rfkill_poll)(struct ieee80211_hw *hw);
+#ifdef CONFIG_NL80211_TESTMODE
+ int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
+#endif
};
/**
@@ -1606,9 +1623,11 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
*/
void ieee80211_restart_hw(struct ieee80211_hw *hw);
-/* trick to avoid symbol clashes with the ieee80211 subsystem */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_rx_status *status);
+/*
+ * trick to avoid symbol clashes with the ieee80211 subsystem,
+ * use the inline below instead
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
* ieee80211_rx - receive frame
@@ -1624,13 +1643,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
- * @status: status of this frame; the status pointer need not be valid
- * after this function returns
*/
-static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_rx_status *status)
+static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- __ieee80211_rx(hw, skb, status);
+ __ieee80211_rx(hw, skb);
}
/**
@@ -1644,13 +1660,8 @@ static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
- * @status: status of this frame; the status pointer need not be valid
- * after this function returns and is not freed by mac80211,
- * it is recommended that it points to a stack area
*/
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_rx_status *status);
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
* ieee80211_tx_status - transmit status callback
@@ -2090,6 +2101,29 @@ static inline int rate_supported(struct ieee80211_sta *sta,
return (sta == NULL || sta->supp_rates[band] & BIT(index));
}
+/**
+ * rate_control_send_low - helper for drivers for management/no-ack frames
+ *
+ * Rate control algorithms that agree to use the lowest rate to
+ * send management frames and NO_ACK data with the respective hw
+ * retries should use this in the beginning of their mac80211 get_rate
+ * callback. If true is returned the rate control can simply return.
+ * If false is returned we guarantee that sta and sta and priv_sta is
+ * not null.
+ *
+ * Rate control algorithms wishing to do more intelligent selection of
+ * rate for multicast/broadcast frames may choose to not use this.
+ *
+ * @sta: &struct ieee80211_sta pointer to the target destination. Note
+ * that this may be null.
+ * @priv_sta: private rate control structure. This may be null.
+ * @txrc: rate control information we sholud populate for mac80211.
+ */
+bool rate_control_send_low(struct ieee80211_sta *sta,
+ void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc);
+
+
static inline s8
rate_lowest_index(struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta)
@@ -2106,6 +2140,17 @@ rate_lowest_index(struct ieee80211_supported_band *sband,
return 0;
}
+static inline
+bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta)
+{
+ unsigned int i;
+
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (rate_supported(sta, sband->band, i))
+ return true;
+ return false;
+}
int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index ded434b032a4..a1202841aadd 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -26,6 +26,7 @@ struct net_device;
struct sock;
struct ctl_table_header;
struct net_generic;
+struct sock;
struct net {
atomic_t count; /* To decided when the network
@@ -57,6 +58,7 @@ struct net {
spinlock_t rules_mod_lock;
struct sock *rtnl; /* rtnetlink socket */
+ struct sock *genl_sock;
struct netns_core core;
struct netns_mib mib;
@@ -78,6 +80,9 @@ struct net {
#ifdef CONFIG_XFRM
struct netns_xfrm xfrm;
#endif
+#ifdef CONFIG_WIRELESS_EXT
+ struct sk_buff_head wext_nlevents;
+#endif
struct net_generic *gen;
};
@@ -106,6 +111,8 @@ static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns)
extern struct list_head net_namespace_list;
+extern struct net *get_net_ns_by_pid(pid_t pid);
+
#ifdef CONFIG_NET_NS
extern void __put_net(struct net *net);
@@ -208,6 +215,9 @@ static inline struct net *read_pnet(struct net * const *pnet)
#define for_each_net(VAR) \
list_for_each_entry(VAR, &net_namespace_list, list)
+#define for_each_net_rcu(VAR) \
+ list_for_each_entry_rcu(VAR, &net_namespace_list, list)
+
#ifdef CONFIG_NET_NS
#define __net_init
#define __net_exit
@@ -229,13 +239,15 @@ struct pernet_operations {
* needs per network namespace operations use device pernet operations,
* otherwise use pernet subsys operations.
*
- * This is critically important. Most of the network code cleanup
- * runs with the assumption that dev_remove_pack has been called so no
- * new packets will arrive during and after the cleanup functions have
- * been called. dev_remove_pack is not per namespace so instead the
- * guarantee of no more packets arriving in a network namespace is
- * provided by ensuring that all network devices and all sockets have
- * left the network namespace before the cleanup methods are called.
+ * Network interfaces need to be removed from a dying netns _before_
+ * subsys notifiers can be called, as most of the network code cleanup
+ * (which is done from subsys notifiers) runs with the assumption that
+ * dev_remove_pack has been called so no new packets will arrive during
+ * and after the cleanup functions have been called. dev_remove_pack
+ * is not per namespace so instead the guarantee of no more packets
+ * arriving in a network namespace is provided by ensuring that all
+ * network devices and all sockets have left the network namespace
+ * before the cleanup methods are called.
*
* For the longest time the ipv4 icmp code was registered as a pernet
* device which caused kernel oops, and panics during network
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 9554a644a8f8..591db7d657a3 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -8,8 +8,11 @@ struct ebt_table;
struct netns_xt {
struct list_head tables[NFPROTO_NUMPROTO];
+#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
+ defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
struct ebt_table *broute_table;
struct ebt_table *frame_filter;
struct ebt_table *frame_nat;
+#endif
};
#endif
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
new file mode 100644
index 000000000000..6096096f6d7d
--- /dev/null
+++ b/include/net/nl802154.h
@@ -0,0 +1,117 @@
+/*
+ * nl802154.h
+ *
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef IEEE802154_NL_H
+#define IEEE802154_NL_H
+
+struct net_device;
+struct ieee802154_addr;
+
+/**
+ * ieee802154_nl_assoc_indic - Notify userland of an association request.
+ * @dev: The network device on which this association request was
+ * received.
+ * @addr: The address of the device requesting association.
+ * @cap: The capability information field from the device.
+ *
+ * This informs a userland coordinator of a device requesting to
+ * associate with the PAN controlled by the coordinator.
+ *
+ * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document.
+ */
+int ieee802154_nl_assoc_indic(struct net_device *dev,
+ struct ieee802154_addr *addr, u8 cap);
+
+/**
+ * ieee802154_nl_assoc_confirm - Notify userland of association.
+ * @dev: The device which has completed association.
+ * @short_addr: The short address assigned to the device.
+ * @status: The status of the association.
+ *
+ * Inform userland of the result of an association request. If the
+ * association request included asking the coordinator to allocate
+ * a short address then it is returned in @short_addr.
+ *
+ * Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
+ */
+int ieee802154_nl_assoc_confirm(struct net_device *dev,
+ u16 short_addr, u8 status);
+
+/**
+ * ieee802154_nl_disassoc_indic - Notify userland of disassociation.
+ * @dev: The device on which disassociation was indicated.
+ * @addr: The device which is disassociating.
+ * @reason: The reason for the disassociation.
+ *
+ * Inform userland that a device has disassociated from the network.
+ *
+ * Note: This is in section 7.3.3 of the IEEE 802.15.4 document.
+ */
+int ieee802154_nl_disassoc_indic(struct net_device *dev,
+ struct ieee802154_addr *addr, u8 reason);
+
+/**
+ * ieee802154_nl_disassoc_confirm - Notify userland of disassociation
+ * completion.
+ * @dev: The device on which disassociation was ordered.
+ * @status: The result of the disassociation.
+ *
+ * Inform userland of the result of requesting that a device
+ * disassociate, or the result of requesting that we disassociate from
+ * a PAN managed by another coordinator.
+ *
+ * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document.
+ */
+int ieee802154_nl_disassoc_confirm(struct net_device *dev,
+ u8 status);
+
+/**
+ * ieee802154_nl_scan_confirm - Notify userland of completion of scan.
+ * @dev: The device which was instructed to scan.
+ * @status: The status of the scan operation.
+ * @scan_type: What type of scan was performed.
+ * @unscanned: Any channels that the device was unable to scan.
+ * @edl: The energy levels (if a passive scan).
+ *
+ *
+ * Note: This is in section 7.1.11 of the IEEE 802.15.4 document.
+ * Note: This API does not permit the return of an active scan result.
+ */
+int ieee802154_nl_scan_confirm(struct net_device *dev,
+ u8 status, u8 scan_type, u32 unscanned,
+ u8 *edl/*, struct list_head *pan_desc_list */);
+
+/**
+ * ieee802154_nl_beacon_indic - Notify userland of a received beacon.
+ * @dev: The device on which a beacon was received.
+ * @panid: The PAN of the coordinator.
+ * @coord_addr: The short address of the coordinator on that PAN.
+ *
+ * Note: This is in section 7.1.5 of the IEEE 802.15.4 document.
+ * Note: This API does not provide extended information such as what
+ * channel the PAN is on or what the LQI of the beacon frame was on
+ * receipt.
+ * Note: This API cannot indicate a beacon frame for a coordinator
+ * operating in long addressing mode.
+ */
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
+ u16 coord_addr);
+
+#endif
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index 29d126736611..44c923c9e21d 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr);
#define PN_NO_ADDR 0xff
+extern const struct file_operations pn_sock_seq_fops;
+
#endif
diff --git a/include/net/rose.h b/include/net/rose.h
index cbd5364b2c8a..5ba9f02731eb 100644
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -156,7 +156,7 @@ extern int sysctl_rose_maximum_vcs;
extern int sysctl_rose_window_size;
extern int rosecmp(rose_address *, rose_address *);
extern int rosecmpm(rose_address *, rose_address *, unsigned short);
-extern const char *rose2asc(const rose_address *);
+extern char *rose2asc(char *buf, const rose_address *);
extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *);
extern void rose_kill_by_neigh(struct rose_neigh *);
extern unsigned int rose_new_lci(struct rose_neigh *);
diff --git a/include/net/scm.h b/include/net/scm.h
index f45bb6eca7d4..cf48c800e926 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -26,7 +26,6 @@ struct scm_cookie
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
- unsigned long seq; /* Connection seqno */
};
extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -59,7 +58,6 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
scm->creds.gid = current_gid();
scm->creds.pid = task_tgid_vnr(p);
scm->fp = NULL;
- scm->seq = 0;
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
diff --git a/include/net/udp.h b/include/net/udp.h
index 90e6ce56be65..5fb029f817a3 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -207,4 +207,7 @@ extern void udp4_proc_exit(void);
#endif
extern void udp_init(void);
+
+extern int udp4_ufo_send_check(struct sk_buff *skb);
+extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features);
#endif /* _UDP_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9e3a3f4c1f60..223e90a44824 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1280,7 +1280,7 @@ struct xfrm6_tunnel {
};
extern void xfrm_init(void);
-extern void xfrm4_init(void);
+extern void xfrm4_init(int rt_hash_size);
extern int xfrm_state_init(struct net *net);
extern void xfrm_state_fini(struct net *net);
extern void xfrm4_state_init(void);
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h
index 938858304300..c8f94e8db69c 100644
--- a/include/rdma/ib_cm.h
+++ b/include/rdma/ib_cm.h
@@ -482,7 +482,7 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id,
* message.
* @cm_id: Connection identifier associated with the connection message.
* @service_timeout: The lower 5-bits specify the maximum time required for
- * the sender to reply to to the connection message. The upper 3-bits
+ * the sender to reply to the connection message. The upper 3-bits
* specify additional control flags.
* @private_data: Optional user-defined private data sent with the
* message receipt acknowledgement.
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 3f566af3f101..1f3a4c8044c0 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -191,6 +191,8 @@ struct scsi_device_handler {
struct scsi_dh_data {
struct scsi_device_handler *scsi_dh;
+ struct scsi_device *sdev;
+ struct kref kref;
char buf[0];
};
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 251fc1cd5002..9b1c0985480c 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -642,4 +642,10 @@ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime);
/* ad hoc AC97 device driver access */
extern struct bus_type ac97_bus_type;
+/* AC97 platform_data adding function */
+static inline void snd_ac97_dev_add_pdata(struct snd_ac97 *ac97, void *data)
+{
+ ac97->dev.platform_data = data;
+}
+
#endif /* __SOUND_AC97_CODEC_H */
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index 7ccce94a5255..c42506212649 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -47,7 +47,11 @@ struct snd_dma_device {
#define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
+#ifdef CONFIG_SND_DMA_SGBUF
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
+#else
+#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
+#endif
/*
* info for buffer allocation
@@ -60,6 +64,7 @@ struct snd_dma_buffer {
void *private_data; /* private for allocator; don't touch */
};
+#ifdef CONFIG_SND_DMA_SGBUF
/*
* Scatter-Gather generic device pages
*/
@@ -107,6 +112,7 @@ static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset)
{
return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
}
+#endif /* CONFIG_SND_DMA_SGBUF */
/* allocate/release a buffer */
int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 23893523dc8c..1691c7fe35af 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -902,6 +902,7 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
+#ifdef CONFIG_SND_DMA_SGBUF
/*
* SG-buffer handling
*/
@@ -927,6 +928,28 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
unsigned int ofs, unsigned int size);
+#else /* !SND_DMA_SGBUF */
+/*
+ * fake using a continuous buffer
+ */
+static inline dma_addr_t
+snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+ return substream->runtime->dma_addr + ofs;
+}
+
+static inline void *
+snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
+{
+ return substream->runtime->dma_area + ofs;
+}
+
+#define snd_pcm_sgbuf_ops_page NULL
+
+#define snd_pcm_sgbuf_get_chunk_size(subs, ofs, size) (size)
+
+#endif /* SND_DMA_SGBUF */
+
/* handle mmap counter - PCM mmap callback should handle this counter properly */
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 352d7eee9b6d..25d62ac53fc5 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -27,8 +27,8 @@ struct snd_pcm_substream;
#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */
#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */
#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */
-#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_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 */
/* left and right justified also known as MSB and LSB respectively */
@@ -38,7 +38,7 @@ struct snd_pcm_substream;
/*
* DAI Clock gating.
*
- * DAI bit clocks can be be gated (disabled) when not the DAI is not
+ * DAI bit clocks can be be gated (disabled) when the DAI is not
* sending or receiving PCM data in a frame. This can be used to save power.
*/
#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */
@@ -51,21 +51,21 @@ struct snd_pcm_substream;
* format.
*/
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
-#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */
-#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */
-#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */
+#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal BCLK + inv FRM */
+#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert BCLK + nor FRM */
+#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert BCLK + FRM */
/*
* DAI hardware clock masters.
*
* This is wrt the codec, the inverse is true for the interface
- * i.e. if the codec is clk and frm master then the interface is
+ * i.e. if the codec is clk and FRM master then the interface is
* clk and frame slave.
*/
-#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
-#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & FRM master */
+#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & FRM master */
#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
-#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
+#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & FRM slave */
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
@@ -116,12 +116,12 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
/*
* Digital Audio Interface.
*
- * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97
- * operations an capabilities. Codec and platfom drivers will register a this
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
* structure for every DAI they have.
*
* This structure covers the clocking, formating and ALSA operations for each
- * interface a
+ * interface.
*/
struct snd_soc_dai_ops {
/*
@@ -179,6 +179,7 @@ struct snd_soc_dai {
int ac97_control;
struct device *dev;
+ void *ac97_pdata; /* platform_data for the ac97 codec */
/* DAI callbacks */
int (*probe)(struct platform_device *pdev,
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index ec8a45f9a069..35814ced2d22 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -279,6 +279,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
/* dapm events */
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
int event);
+void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index cf6111d72b17..756fb59772d1 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -135,6 +135,28 @@
.info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+#define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
+ xhandler_get, xhandler_put, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .shift = shift_left, .rshift = shift_right, \
+ .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
+ xhandler_get, xhandler_put, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_2r, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+ .max = xmax, .invert = xinvert} }
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_bool_ext, \
@@ -191,6 +213,12 @@ int snd_soc_register_platform(struct snd_soc_platform *platform);
void snd_soc_unregister_platform(struct snd_soc_platform *platform);
int snd_soc_register_codec(struct snd_soc_codec *codec);
void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
+
+#ifdef CONFIG_PM
+int snd_soc_suspend_device(struct device *dev);
+int snd_soc_resume_device(struct device *dev);
+#endif
/* pcm <-> DAI connect */
void snd_soc_free_pcms(struct snd_soc_device *socdev);
@@ -216,9 +244,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
/* codec register bit access */
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned short mask, unsigned short value);
+ unsigned int mask, unsigned int value);
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned short mask, unsigned short value);
+ unsigned int mask, unsigned int value);
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num);
@@ -356,6 +384,7 @@ struct snd_soc_codec {
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
int (*display_register)(struct snd_soc_codec *, char *,
size_t, unsigned int);
+ int (*volatile_register)(unsigned int);
hw_write_t hw_write;
hw_read_t hw_read;
void *reg_cache;
@@ -369,8 +398,6 @@ struct snd_soc_codec {
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
- struct list_head up_list;
- struct list_head down_list;
/* codec DAI's */
struct snd_soc_dai *dai;
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index d136ea2181ed..9fd5b19ccf5c 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -35,6 +35,8 @@
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
+#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
+#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
#define TLV_DB_SCALE_ITEM(min, step, mute) \
SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
@@ -42,6 +44,18 @@
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
+/* dB scale specified with min/max values instead of step */
+#define TLV_DB_MINMAX_ITEM(min_dB, max_dB) \
+ SNDRV_CTL_TLVT_DB_MINMAX, 2 * sizeof(unsigned int), \
+ (min_dB), (max_dB)
+#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \
+ SNDRV_CTL_TLVT_DB_MINMAX_MUTE, 2 * sizeof(unsigned int), \
+ (min_dB), (max_dB)
+#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \
+ unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) }
+#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \
+ unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) }
+
/* linear volume between min_dB and max_dB (.01dB unit) */
#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h
new file mode 100644
index 000000000000..381319c7000c
--- /dev/null
+++ b/include/sound/uda1380.h
@@ -0,0 +1,22 @@
+/*
+ * UDA1380 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * 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 __UDA1380_H
+#define __UDA1380_H
+
+struct uda1380_platform_data {
+ int gpio_power;
+ int gpio_reset;
+ int dac_clk;
+#define UDA1380_DAC_CLK_SYSCLK 0
+#define UDA1380_DAC_CLK_WSPLL 1
+};
+
+#endif /* __UDA1380_H */
diff --git a/include/sound/wm8993.h b/include/sound/wm8993.h
new file mode 100644
index 000000000000..9c661f2f8cda
--- /dev/null
+++ b/include/sound/wm8993.h
@@ -0,0 +1,44 @@
+/*
+ * linux/sound/wm8993.h -- Platform data for WM8993
+ *
+ * Copyright 2009 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM8993_H
+#define __LINUX_SND_WM8993_H
+
+/* Note that EQ1 only contains the enable/disable bit so will be
+ ignored but is included for simplicity.
+ */
+struct wm8993_retune_mobile_setting {
+ const char *name;
+ unsigned int rate;
+ u16 config[24];
+};
+
+struct wm8993_platform_data {
+ struct wm8993_retune_mobile_setting *retune_configs;
+ int num_retune_configs;
+
+ /* LINEOUT can be differential or single ended */
+ unsigned int lineout1_diff:1;
+ unsigned int lineout2_diff:1;
+
+ /* Common mode feedback */
+ unsigned int lineout1fb:1;
+ unsigned int lineout2fb:1;
+
+ /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
+ unsigned int micbias1_lvl:1;
+ unsigned int micbias2_lvl:1;
+
+ /* Jack detect threashold levels, see datasheet for values */
+ unsigned int jd_scthr:2;
+ unsigned int jd_thr:2;
+};
+
+#endif
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h
new file mode 100644
index 000000000000..dbe108455275
--- /dev/null
+++ b/include/trace/events/kvm.h
@@ -0,0 +1,151 @@
+#if !defined(_TRACE_KVM_MAIN_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_MAIN_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_FILE kvm
+
+#if defined(__KVM_HAVE_IOAPIC)
+TRACE_EVENT(kvm_set_irq,
+ TP_PROTO(unsigned int gsi, int level, int irq_source_id),
+ TP_ARGS(gsi, level, irq_source_id),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, gsi )
+ __field( int, level )
+ __field( int, irq_source_id )
+ ),
+
+ TP_fast_assign(
+ __entry->gsi = gsi;
+ __entry->level = level;
+ __entry->irq_source_id = irq_source_id;
+ ),
+
+ TP_printk("gsi %u level %d source %d",
+ __entry->gsi, __entry->level, __entry->irq_source_id)
+);
+
+#define kvm_deliver_mode \
+ {0x0, "Fixed"}, \
+ {0x1, "LowPrio"}, \
+ {0x2, "SMI"}, \
+ {0x3, "Res3"}, \
+ {0x4, "NMI"}, \
+ {0x5, "INIT"}, \
+ {0x6, "SIPI"}, \
+ {0x7, "ExtINT"}
+
+TRACE_EVENT(kvm_ioapic_set_irq,
+ TP_PROTO(__u64 e, int pin, bool coalesced),
+ TP_ARGS(e, pin, coalesced),
+
+ TP_STRUCT__entry(
+ __field( __u64, e )
+ __field( int, pin )
+ __field( bool, coalesced )
+ ),
+
+ TP_fast_assign(
+ __entry->e = e;
+ __entry->pin = pin;
+ __entry->coalesced = coalesced;
+ ),
+
+ TP_printk("pin %u dst %x vec=%u (%s|%s|%s%s)%s",
+ __entry->pin, (u8)(__entry->e >> 56), (u8)__entry->e,
+ __print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode),
+ (__entry->e & (1<<11)) ? "logical" : "physical",
+ (__entry->e & (1<<15)) ? "level" : "edge",
+ (__entry->e & (1<<16)) ? "|masked" : "",
+ __entry->coalesced ? " (coalesced)" : "")
+);
+
+TRACE_EVENT(kvm_msi_set_irq,
+ TP_PROTO(__u64 address, __u64 data),
+ TP_ARGS(address, data),
+
+ TP_STRUCT__entry(
+ __field( __u64, address )
+ __field( __u64, data )
+ ),
+
+ TP_fast_assign(
+ __entry->address = address;
+ __entry->data = data;
+ ),
+
+ TP_printk("dst %u vec %x (%s|%s|%s%s)",
+ (u8)(__entry->address >> 12), (u8)__entry->data,
+ __print_symbolic((__entry->data >> 8 & 0x7), kvm_deliver_mode),
+ (__entry->address & (1<<2)) ? "logical" : "physical",
+ (__entry->data & (1<<15)) ? "level" : "edge",
+ (__entry->address & (1<<3)) ? "|rh" : "")
+);
+
+#define kvm_irqchips \
+ {KVM_IRQCHIP_PIC_MASTER, "PIC master"}, \
+ {KVM_IRQCHIP_PIC_SLAVE, "PIC slave"}, \
+ {KVM_IRQCHIP_IOAPIC, "IOAPIC"}
+
+TRACE_EVENT(kvm_ack_irq,
+ TP_PROTO(unsigned int irqchip, unsigned int pin),
+ TP_ARGS(irqchip, pin),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, irqchip )
+ __field( unsigned int, pin )
+ ),
+
+ TP_fast_assign(
+ __entry->irqchip = irqchip;
+ __entry->pin = pin;
+ ),
+
+ TP_printk("irqchip %s pin %u",
+ __print_symbolic(__entry->irqchip, kvm_irqchips),
+ __entry->pin)
+);
+
+
+
+#endif /* defined(__KVM_HAVE_IOAPIC) */
+
+#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
+#define KVM_TRACE_MMIO_READ 1
+#define KVM_TRACE_MMIO_WRITE 2
+
+#define kvm_trace_symbol_mmio \
+ { KVM_TRACE_MMIO_READ_UNSATISFIED, "unsatisfied-read" }, \
+ { KVM_TRACE_MMIO_READ, "read" }, \
+ { KVM_TRACE_MMIO_WRITE, "write" }
+
+TRACE_EVENT(kvm_mmio,
+ TP_PROTO(int type, int len, u64 gpa, u64 val),
+ TP_ARGS(type, len, gpa, val),
+
+ TP_STRUCT__entry(
+ __field( u32, type )
+ __field( u32, len )
+ __field( u64, gpa )
+ __field( u64, val )
+ ),
+
+ TP_fast_assign(
+ __entry->type = type;
+ __entry->len = len;
+ __entry->gpa = gpa;
+ __entry->val = val;
+ ),
+
+ TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx",
+ __print_symbolic(__entry->type, kvm_trace_symbol_mmio),
+ __entry->len, __entry->gpa, __entry->val)
+);
+
+#endif /* _TRACE_KVM_MAIN_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/init/Kconfig b/init/Kconfig
index cb2c09270226..432559b535c6 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -302,13 +302,17 @@ config AUDITSYSCALL
help
Enable low-overhead system-call auditing infrastructure that
can be used independently or with another kernel subsystem,
- such as SELinux. To use audit's filesystem watch feature, please
- ensure that INOTIFY is configured.
+ such as SELinux.
+
+config AUDIT_WATCH
+ def_bool y
+ depends on AUDITSYSCALL
+ select FSNOTIFY
config AUDIT_TREE
def_bool y
depends on AUDITSYSCALL
- select INOTIFY
+ select FSNOTIFY
menu "RCU Subsystem"
@@ -316,21 +320,13 @@ choice
prompt "RCU Implementation"
default TREE_RCU
-config CLASSIC_RCU
- bool "Classic RCU"
- help
- This option selects the classic RCU implementation that is
- designed for best read-side performance on non-realtime
- systems.
-
- Select this option if you are unsure.
-
config TREE_RCU
bool "Tree-based hierarchical RCU"
help
This option selects the RCU implementation that is
designed for very large SMP system with hundreds or
- thousands of CPUs.
+ thousands of CPUs. It also scales down nicely to
+ smaller systems.
config PREEMPT_RCU
bool "Preemptible RCU"
@@ -1017,18 +1013,23 @@ config COMPAT_BRK
choice
prompt "Choose SLAB allocator"
- default SLUB
+ default SLQB_ALLOCATOR
help
This option allows to select a slab allocator.
-config SLAB
+config SLAB_ALLOCATOR
bool "SLAB"
help
The regular slab allocator that is established and known to work
well in all environments. It organizes cache hot objects in
per cpu and per node queues.
-config SLUB
+config SLAB
+ bool
+ default y
+ depends on SLAB_ALLOCATOR
+
+config SLUB_ALLOCATOR
bool "SLUB (Unqueued Allocator)"
help
SLUB is a slab allocator that minimizes cache line usage
@@ -1038,6 +1039,21 @@ config SLUB
and has enhanced diagnostics. SLUB is the default choice for
a slab allocator.
+config SLUB
+ bool
+ default y
+ depends on SLUB_ALLOCATOR
+
+config SLQB_ALLOCATOR
+ bool "SLQB (Queued allocator)"
+ help
+ SLQB is a proposed new slab allocator.
+
+config SLQB
+ bool
+ default y
+ depends on SLQB_ALLOCATOR
+
config SLOB
depends on EMBEDDED
bool "SLOB (Simple Allocator)"
@@ -1093,7 +1109,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/main.c b/init/main.c
index d32a1ffef815..59f911c3135c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -354,17 +354,11 @@ static void __init smp_init(void)
#define smp_init() do { } while (0)
#endif
-static inline void setup_per_cpu_areas(void) { }
static inline void setup_nr_cpu_ids(void) { }
static inline void smp_prepare_cpus(unsigned int maxcpus) { }
#else
-#if NR_CPUS > BITS_PER_LONG
-cpumask_t cpu_mask_all __read_mostly = CPU_MASK_ALL;
-EXPORT_SYMBOL(cpu_mask_all);
-#endif
-
/* Setup number of possible processor ids */
int nr_cpu_ids __read_mostly = NR_CPUS;
EXPORT_SYMBOL(nr_cpu_ids);
@@ -375,29 +369,6 @@ static void __init setup_nr_cpu_ids(void)
nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
}
-#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-
-EXPORT_SYMBOL(__per_cpu_offset);
-
-static void __init setup_per_cpu_areas(void)
-{
- unsigned long size, i;
- char *ptr;
- unsigned long nr_possible_cpus = num_possible_cpus();
-
- /* Copy section for each CPU (we discard the original) */
- size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
- ptr = alloc_bootmem_pages(size * nr_possible_cpus);
-
- for_each_possible_cpu(i) {
- __per_cpu_offset[i] = ptr - __per_cpu_start;
- memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
- ptr += size;
- }
-}
-#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
-
/* Called by boot processor to activate the rest. */
static void __init smp_init(void)
{
diff --git a/kernel/Makefile b/kernel/Makefile
index 2093a691f1c2..a00eb1c3a8af 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -69,10 +69,11 @@ obj-$(CONFIG_IKCONFIG) += configs.o
obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
-obj-$(CONFIG_AUDIT) += audit.o auditfilter.o audit_watch.o
+obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_GCOV_KERNEL) += gcov/
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
+obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
@@ -80,7 +81,6 @@ obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
-obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o
obj-$(CONFIG_TREE_RCU) += rcutree.o
obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o
obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o
diff --git a/kernel/audit.c b/kernel/audit.c
index defc2e6f1e3b..601e3f280ee4 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -55,7 +55,6 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
-#include <linux/inotify.h>
#include <linux/freezer.h>
#include <linux/tty.h>
diff --git a/kernel/audit.h b/kernel/audit.h
index 208687be4f30..f7206db4e13d 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -103,21 +103,27 @@ extern struct mutex audit_filter_mutex;
extern void audit_free_rule_rcu(struct rcu_head *);
extern struct list_head audit_filter_list[];
+extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
+
/* audit watch functions */
-extern unsigned long audit_watch_inode(struct audit_watch *watch);
-extern dev_t audit_watch_dev(struct audit_watch *watch);
+#ifdef CONFIG_AUDIT_WATCH
extern void audit_put_watch(struct audit_watch *watch);
extern void audit_get_watch(struct audit_watch *watch);
extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
-extern int audit_add_watch(struct audit_krule *krule);
-extern void audit_remove_watch(struct audit_watch *watch);
-extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
-extern void audit_inotify_unregister(struct list_head *in_list);
+extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
+extern void audit_remove_watch_rule(struct audit_krule *krule);
extern char *audit_watch_path(struct audit_watch *watch);
-extern struct list_head *audit_watch_rules(struct audit_watch *watch);
-
-extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch);
+extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+#else
+#define audit_put_watch(w) {}
+#define audit_get_watch(w) {}
+#define audit_to_watch(k, p, l, o) (-EINVAL)
+#define audit_add_watch(k, l) (-EINVAL)
+#define audit_remove_watch_rule(k) BUG()
+#define audit_watch_path(w) ""
+#define audit_watch_compare(w, i, d) 0
+
+#endif /* CONFIG_AUDIT_WATCH */
#ifdef CONFIG_AUDIT_TREE
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 2451dc6f3282..184ca3f35b86 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -1,5 +1,5 @@
#include "audit.h"
-#include <linux/inotify.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/kthread.h>
@@ -21,7 +21,7 @@ struct audit_tree {
struct audit_chunk {
struct list_head hash;
- struct inotify_watch watch;
+ struct fsnotify_mark_entry mark;
struct list_head trees; /* with root here */
int dead;
int count;
@@ -67,7 +67,7 @@ static LIST_HEAD(prune_list);
* that makes a difference. Some.
*/
-static struct inotify_handle *rtree_ih;
+static struct fsnotify_group *audit_tree_group;
static struct audit_tree *alloc_tree(const char *s)
{
@@ -110,29 +110,6 @@ const char *audit_tree_path(struct audit_tree *tree)
return tree->pathname;
}
-static struct audit_chunk *alloc_chunk(int count)
-{
- struct audit_chunk *chunk;
- size_t size;
- int i;
-
- size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
- chunk = kzalloc(size, GFP_KERNEL);
- if (!chunk)
- return NULL;
-
- INIT_LIST_HEAD(&chunk->hash);
- INIT_LIST_HEAD(&chunk->trees);
- chunk->count = count;
- atomic_long_set(&chunk->refs, 1);
- for (i = 0; i < count; i++) {
- INIT_LIST_HEAD(&chunk->owners[i].list);
- chunk->owners[i].index = i;
- }
- inotify_init_watch(&chunk->watch);
- return chunk;
-}
-
static void free_chunk(struct audit_chunk *chunk)
{
int i;
@@ -156,6 +133,35 @@ static void __put_chunk(struct rcu_head *rcu)
audit_put_chunk(chunk);
}
+static void audit_tree_destroy_watch(struct fsnotify_mark_entry *entry)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+ call_rcu(&chunk->head, __put_chunk);
+}
+
+static struct audit_chunk *alloc_chunk(int count)
+{
+ struct audit_chunk *chunk;
+ size_t size;
+ int i;
+
+ size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
+ chunk = kzalloc(size, GFP_KERNEL);
+ if (!chunk)
+ return NULL;
+
+ INIT_LIST_HEAD(&chunk->hash);
+ INIT_LIST_HEAD(&chunk->trees);
+ chunk->count = count;
+ atomic_long_set(&chunk->refs, 1);
+ for (i = 0; i < count; i++) {
+ INIT_LIST_HEAD(&chunk->owners[i].list);
+ chunk->owners[i].index = i;
+ }
+ fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch);
+ return chunk;
+}
+
enum {HASH_SIZE = 128};
static struct list_head chunk_hash_heads[HASH_SIZE];
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
@@ -166,10 +172,15 @@ static inline struct list_head *chunk_hash(const struct inode *inode)
return chunk_hash_heads + n % HASH_SIZE;
}
-/* hash_lock is held by caller */
+/* hash_lock & entry->lock is held by caller */
static void insert_hash(struct audit_chunk *chunk)
{
- struct list_head *list = chunk_hash(chunk->watch.inode);
+ struct fsnotify_mark_entry *entry = &chunk->mark;
+ struct list_head *list;
+
+ if (!entry->inode)
+ return;
+ list = chunk_hash(entry->inode);
list_add_rcu(&chunk->hash, list);
}
@@ -180,7 +191,8 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
struct audit_chunk *p;
list_for_each_entry_rcu(p, list, hash) {
- if (p->watch.inode == inode) {
+ /* mark.inode may have gone NULL, but who cares? */
+ if (p->mark.inode == inode) {
atomic_long_inc(&p->refs);
return p;
}
@@ -209,38 +221,19 @@ static struct audit_chunk *find_chunk(struct node *p)
static void untag_chunk(struct node *p)
{
struct audit_chunk *chunk = find_chunk(p);
+ struct fsnotify_mark_entry *entry = &chunk->mark;
struct audit_chunk *new;
struct audit_tree *owner;
int size = chunk->count - 1;
int i, j;
- if (!pin_inotify_watch(&chunk->watch)) {
- /*
- * Filesystem is shutting down; all watches are getting
- * evicted, just take it off the node list for this
- * tree and let the eviction logics take care of the
- * rest.
- */
- owner = p->owner;
- if (owner->root == chunk) {
- list_del_init(&owner->same_root);
- owner->root = NULL;
- }
- list_del_init(&p->list);
- p->owner = NULL;
- put_tree(owner);
- return;
- }
+ fsnotify_get_mark(entry);
spin_unlock(&hash_lock);
- /*
- * pin_inotify_watch() succeeded, so the watch won't go away
- * from under us.
- */
- mutex_lock(&chunk->watch.inode->inotify_mutex);
- if (chunk->dead) {
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_lock(&entry->lock);
+ if (chunk->dead || !entry->inode) {
+ spin_unlock(&entry->lock);
goto out;
}
@@ -255,16 +248,17 @@ static void untag_chunk(struct node *p)
list_del_init(&p->list);
list_del_rcu(&chunk->hash);
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
goto out;
}
new = alloc_chunk(size);
if (!new)
goto Fallback;
- if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) {
+ fsnotify_duplicate_mark(&new->mark, entry);
+ if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.inode, 1)) {
free_chunk(new);
goto Fallback;
}
@@ -297,9 +291,9 @@ static void untag_chunk(struct node *p)
list_for_each_entry(owner, &new->trees, same_root)
owner->root = new;
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
goto out;
Fallback:
@@ -313,31 +307,33 @@ Fallback:
p->owner = NULL;
put_tree(owner);
spin_unlock(&hash_lock);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_unlock(&entry->lock);
out:
- unpin_inotify_watch(&chunk->watch);
+ fsnotify_put_mark(entry);
spin_lock(&hash_lock);
}
static int create_chunk(struct inode *inode, struct audit_tree *tree)
{
+ struct fsnotify_mark_entry *entry;
struct audit_chunk *chunk = alloc_chunk(1);
if (!chunk)
return -ENOMEM;
- if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) {
+ entry = &chunk->mark;
+ if (fsnotify_add_mark(entry, audit_tree_group, inode, 0)) {
free_chunk(chunk);
return -ENOSPC;
}
- mutex_lock(&inode->inotify_mutex);
+ spin_lock(&entry->lock);
spin_lock(&hash_lock);
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
return 0;
}
chunk->owners[0].index = (1U << 31);
@@ -350,30 +346,33 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
}
insert_hash(chunk);
spin_unlock(&hash_lock);
- mutex_unlock(&inode->inotify_mutex);
+ spin_unlock(&entry->lock);
return 0;
}
/* the first tagged inode becomes root of tree */
static int tag_chunk(struct inode *inode, struct audit_tree *tree)
{
- struct inotify_watch *watch;
+ struct fsnotify_mark_entry *old_entry, *chunk_entry;
struct audit_tree *owner;
struct audit_chunk *chunk, *old;
struct node *p;
int n;
- if (inotify_find_watch(rtree_ih, inode, &watch) < 0)
+ spin_lock(&inode->i_lock);
+ old_entry = fsnotify_find_mark_entry(audit_tree_group, inode);
+ spin_unlock(&inode->i_lock);
+ if (!old_entry)
return create_chunk(inode, tree);
- old = container_of(watch, struct audit_chunk, watch);
+ old = container_of(old_entry, struct audit_chunk, mark);
/* are we already there? */
spin_lock(&hash_lock);
for (n = 0; n < old->count; n++) {
if (old->owners[n].owner == tree) {
spin_unlock(&hash_lock);
- put_inotify_watch(watch);
+ fsnotify_put_mark(old_entry);
return 0;
}
}
@@ -382,22 +381,40 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
chunk = alloc_chunk(old->count + 1);
if (!chunk)
return -ENOMEM;
+ chunk_entry = &chunk->mark;
- mutex_lock(&inode->inotify_mutex);
- if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
+ spin_lock(&old_entry->lock);
+ if (!old_entry->inode) {
+ /* old_entry is being shot, lets just lie */
+ spin_unlock(&old_entry->lock);
+ fsnotify_put_mark(old_entry);
free_chunk(chunk);
+ return -ENOENT;
+ }
+
+ fsnotify_duplicate_mark(chunk_entry, old_entry);
+ if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->inode, 1)) {
+ spin_unlock(&old_entry->lock);
+ free_chunk(chunk);
+ fsnotify_put_mark(old_entry);
return -ENOSPC;
}
+
+ /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */
+ spin_lock(&chunk_entry->lock);
spin_lock(&hash_lock);
+
+ /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+
+ fsnotify_destroy_mark_by_entry(chunk_entry);
+
+ fsnotify_put_mark(chunk_entry);
+ fsnotify_put_mark(old_entry);
return 0;
}
list_replace_init(&old->trees, &chunk->trees);
@@ -423,9 +440,10 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
list_add(&tree->same_root, &chunk->trees);
}
spin_unlock(&hash_lock);
- inotify_evict_watch(&old->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+ fsnotify_destroy_mark_by_entry(old_entry);
+ fsnotify_put_mark(old_entry);
return 0;
}
@@ -578,7 +596,8 @@ void audit_trim_trees(void)
spin_lock(&hash_lock);
list_for_each_entry(node, &tree->chunks, list) {
struct audit_chunk *chunk = find_chunk(node);
- struct inode *inode = chunk->watch.inode;
+ /* this could be NULL if the watch is dieing else where... */
+ struct inode *inode = chunk->mark.inode;
struct vfsmount *mnt;
node->index |= 1U<<31;
list_for_each_entry(mnt, &list, mnt_list) {
@@ -925,34 +944,40 @@ static void evict_chunk(struct audit_chunk *chunk)
mutex_unlock(&audit_filter_mutex);
}
-static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static int audit_tree_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+ BUG();
+ return -EOPNOTSUPP;
+}
- if (mask & IN_IGNORED) {
- evict_chunk(chunk);
- put_inotify_watch(watch);
- }
+static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+
+ evict_chunk(chunk);
+ fsnotify_put_mark(entry);
}
-static void destroy_watch(struct inotify_watch *watch)
+static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
- call_rcu(&chunk->head, __put_chunk);
+ return 0;
}
-static const struct inotify_operations rtree_inotify_ops = {
- .handle_event = handle_event,
- .destroy_watch = destroy_watch,
+static const struct fsnotify_ops audit_tree_ops = {
+ .handle_event = audit_tree_handle_event,
+ .should_send_event = audit_tree_send_event,
+ .free_group_priv = NULL,
+ .free_event_priv = NULL,
+ .freeing_mark = audit_tree_freeing_mark,
};
static int __init audit_tree_init(void)
{
int i;
- rtree_ih = inotify_init(&rtree_inotify_ops);
- if (IS_ERR(rtree_ih))
+ audit_tree_group = fsnotify_obtain_group(AUDIT_TREE_GROUP_NUM,
+ 0, &audit_tree_ops);
+ if (IS_ERR(audit_tree_group))
audit_panic("cannot initialize inotify handle for rectree watches");
for (i = 0; i < HASH_SIZE; i++)
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 0e96dbc60ea9..cfaa248b21f7 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -24,17 +24,17 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/netlink.h>
#include <linux/sched.h>
-#include <linux/inotify.h>
#include <linux/security.h>
#include "audit.h"
/*
* Reference counting:
*
- * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED
+ * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
* event. Each audit_watch holds a reference to its associated parent.
*
* audit_watch: if added to lists, lifetime is from audit_init_watch() to
@@ -50,40 +50,64 @@ struct audit_watch {
unsigned long ino; /* associated inode number */
struct audit_parent *parent; /* associated parent */
struct list_head wlist; /* entry in parent->watches list */
- struct list_head rules; /* associated rules */
+ struct list_head rules; /* anchor for krule->rlist */
};
struct audit_parent {
- struct list_head ilist; /* entry in inotify registration list */
- struct list_head watches; /* associated watches */
- struct inotify_watch wdata; /* inotify watch data */
- unsigned flags; /* status flags */
+ struct list_head watches; /* anchor for audit_watch->wlist */
+ struct fsnotify_mark_entry mark; /* fsnotify mark on the inode */
};
-/* Inotify handle. */
-struct inotify_handle *audit_ih;
+/* fsnotify handle. */
+struct fsnotify_group *audit_watch_group;
-/*
- * audit_parent status flags:
- *
- * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
- * a filesystem event to ensure we're adding audit watches to a valid parent.
- * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot
- * receive them while we have nameidata, but must be used for IN_MOVE_SELF which
- * we can receive while holding nameidata.
- */
-#define AUDIT_PARENT_INVALID 0x001
+/* fsnotify events we care about. */
+#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
+ FS_MOVE_SELF | FS_EVENT_ON_CHILD)
-/* Inotify events we care about. */
-#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+static void audit_free_parent(struct audit_parent *parent)
+{
+ WARN_ON(!list_empty(&parent->watches));
+ kfree(parent);
+}
-static void audit_free_parent(struct inotify_watch *i_watch)
+static void audit_watch_free_mark(struct fsnotify_mark_entry *entry)
{
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
- WARN_ON(!list_empty(&parent->watches));
- kfree(parent);
+ parent = container_of(entry, struct audit_parent, mark);
+ audit_free_parent(parent);
+}
+
+static void audit_get_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_get_mark(&parent->mark);
+}
+
+static void audit_put_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_put_mark(&parent->mark);
+}
+
+/*
+ * Find and return the audit_parent on the given inode. If found a reference
+ * is taken on this parent.
+ */
+static inline struct audit_parent *audit_find_parent(struct inode *inode)
+{
+ struct audit_parent *parent = NULL;
+ struct fsnotify_mark_entry *entry;
+
+ spin_lock(&inode->i_lock);
+ entry = fsnotify_find_mark_entry(audit_watch_group, inode);
+ spin_unlock(&inode->i_lock);
+
+ if (entry)
+ parent = container_of(entry, struct audit_parent, mark);
+
+ return parent;
}
void audit_get_watch(struct audit_watch *watch)
@@ -104,7 +128,7 @@ void audit_put_watch(struct audit_watch *watch)
void audit_remove_watch(struct audit_watch *watch)
{
list_del(&watch->wlist);
- put_inotify_watch(&watch->parent->wdata);
+ audit_put_parent(watch->parent);
watch->parent = NULL;
audit_put_watch(watch); /* match initial get */
}
@@ -114,42 +138,32 @@ char *audit_watch_path(struct audit_watch *watch)
return watch->path;
}
-struct list_head *audit_watch_rules(struct audit_watch *watch)
-{
- return &watch->rules;
-}
-
-unsigned long audit_watch_inode(struct audit_watch *watch)
-{
- return watch->ino;
-}
-
-dev_t audit_watch_dev(struct audit_watch *watch)
+int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
{
- return watch->dev;
+ return (watch->ino != (unsigned long)-1) &&
+ (watch->ino == ino) &&
+ (watch->dev == dev);
}
/* Initialize a parent watch entry. */
static struct audit_parent *audit_init_parent(struct nameidata *ndp)
{
+ struct inode *inode = ndp->path.dentry->d_inode;
struct audit_parent *parent;
- s32 wd;
+ int ret;
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (unlikely(!parent))
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&parent->watches);
- parent->flags = 0;
-
- inotify_init_watch(&parent->wdata);
- /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */
- get_inotify_watch(&parent->wdata);
- wd = inotify_add_watch(audit_ih, &parent->wdata,
- ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
- if (wd < 0) {
- audit_free_parent(&parent->wdata);
- return ERR_PTR(wd);
+
+ fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
+ parent->mark.mask = AUDIT_FS_WATCH;
+ ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, 0);
+ if (ret < 0) {
+ audit_free_parent(parent);
+ return ERR_PTR(ret);
}
return parent;
@@ -178,7 +192,7 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
{
struct audit_watch *watch;
- if (!audit_ih)
+ if (!audit_watch_group)
return -EOPNOTSUPP;
if (path[0] != '/' || path[len-1] == '/' ||
@@ -216,7 +230,7 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
new->dev = old->dev;
new->ino = old->ino;
- get_inotify_watch(&old->parent->wdata);
+ audit_get_parent(old->parent);
new->parent = old->parent;
out:
@@ -250,15 +264,19 @@ static void audit_update_watch(struct audit_parent *parent,
struct audit_entry *oentry, *nentry;
mutex_lock(&audit_filter_mutex);
+ /* Run all of the watches on this parent looking for the one that
+ * matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
if (audit_compare_dname_path(dname, owatch->path, NULL))
continue;
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */
- if (invalidating && current->audit_context)
+ if (invalidating && !audit_dummy_context())
audit_filter_inodes(current, current->audit_context);
+ /* updating ino will likely change which audit_hash_list we
+ * are on so we need a new watch for the new list */
nwatch = audit_dupe_watch(owatch);
if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
@@ -274,12 +292,21 @@ static void audit_update_watch(struct audit_parent *parent,
list_del(&oentry->rule.rlist);
list_del_rcu(&oentry->list);
- nentry = audit_dupe_rule(&oentry->rule, nwatch);
+ nentry = audit_dupe_rule(&oentry->rule);
if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing");
} else {
int h = audit_hash_ino((u32)ino);
+
+ /*
+ * nentry->rule.watch == oentry->rule.watch so
+ * we must drop that reference and set it to our
+ * new watch.
+ */
+ audit_put_watch(nentry->rule.watch);
+ audit_get_watch(nwatch);
+ nentry->rule.watch = nwatch;
list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
@@ -311,7 +338,6 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
struct audit_entry *e;
mutex_lock(&audit_filter_mutex);
- parent->flags |= AUDIT_PARENT_INVALID;
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
e = container_of(r, struct audit_entry, rule);
@@ -324,20 +350,8 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
audit_remove_watch(w);
}
mutex_unlock(&audit_filter_mutex);
-}
-
-/* Unregister inotify watches for parents on in_list.
- * Generates an IN_IGNORED event. */
-void audit_inotify_unregister(struct list_head *in_list)
-{
- struct audit_parent *p, *n;
- list_for_each_entry_safe(p, n, in_list, ilist) {
- list_del(&p->ilist);
- inotify_rm_watch(audit_ih, &p->wdata);
- /* the unpin matching the pin in audit_do_del_rule() */
- unpin_inotify_watch(&p->wdata);
- }
+ fsnotify_destroy_mark_by_entry(&parent->mark);
}
/* Get path information necessary for adding watches. */
@@ -388,7 +402,7 @@ static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
}
}
-/* Associate the given rule with an existing parent inotify_watch.
+/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
struct audit_parent *parent)
@@ -396,6 +410,8 @@ static void audit_add_to_parent(struct audit_krule *krule,
struct audit_watch *w, *watch = krule->watch;
int watch_found = 0;
+ BUG_ON(!mutex_is_locked(&audit_filter_mutex));
+
list_for_each_entry(w, &parent->watches, wlist) {
if (strcmp(watch->path, w->path))
continue;
@@ -412,7 +428,7 @@ static void audit_add_to_parent(struct audit_krule *krule,
}
if (!watch_found) {
- get_inotify_watch(&parent->wdata);
+ audit_get_parent(parent);
watch->parent = parent;
list_add(&watch->wlist, &parent->watches);
@@ -422,13 +438,12 @@ static void audit_add_to_parent(struct audit_krule *krule,
/* Find a matching watch entry, or add this one.
* Caller must hold audit_filter_mutex. */
-int audit_add_watch(struct audit_krule *krule)
+int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{
struct audit_watch *watch = krule->watch;
- struct inotify_watch *i_watch;
struct audit_parent *parent;
struct nameidata *ndp = NULL, *ndw = NULL;
- int ret = 0;
+ int h, ret = 0;
mutex_unlock(&audit_filter_mutex);
@@ -440,47 +455,38 @@ int audit_add_watch(struct audit_krule *krule)
goto error;
}
+ mutex_lock(&audit_filter_mutex);
+
/* update watch filter fields */
if (ndw) {
watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
watch->ino = ndw->path.dentry->d_inode->i_ino;
}
- /* The audit_filter_mutex must not be held during inotify calls because
- * we hold it during inotify event callback processing. If an existing
- * inotify watch is found, inotify_find_watch() grabs a reference before
- * returning.
- */
- if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
- &i_watch) < 0) {
+ /* either find an old parent or attach a new one */
+ parent = audit_find_parent(ndp->path.dentry->d_inode);
+ if (!parent) {
parent = audit_init_parent(ndp);
if (IS_ERR(parent)) {
- /* caller expects mutex locked */
- mutex_lock(&audit_filter_mutex);
ret = PTR_ERR(parent);
goto error;
}
- } else
- parent = container_of(i_watch, struct audit_parent, wdata);
-
- mutex_lock(&audit_filter_mutex);
+ }
- /* parent was moved before we took audit_filter_mutex */
- if (parent->flags & AUDIT_PARENT_INVALID)
- ret = -ENOENT;
- else
- audit_add_to_parent(krule, parent);
+ audit_add_to_parent(krule, parent);
- /* match get in audit_init_parent or inotify_find_watch */
- put_inotify_watch(&parent->wdata);
+ /* match get in audit_find_parent or audit_init_parent */
+ audit_put_parent(parent);
+ h = audit_hash_ino((u32)watch->ino);
+ *list = &audit_inode_hash[h];
error:
audit_put_nd(ndp, ndw); /* NULL args OK */
return ret;
}
-void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
+void audit_remove_watch_rule(struct audit_krule *krule)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent = watch->parent;
@@ -491,53 +497,90 @@ void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
audit_remove_watch(watch);
if (list_empty(&parent->watches)) {
- /* Put parent on the inotify un-registration
- * list. Grab a reference before releasing
- * audit_filter_mutex, to be released in
- * audit_inotify_unregister().
- * If filesystem is going away, just leave
- * the sucker alone, eviction will take
- * care of it. */
- if (pin_inotify_watch(&parent->wdata))
- list_add(&parent->ilist, list);
+ audit_get_parent(parent);
+ fsnotify_destroy_mark_by_entry(&parent->mark);
+ audit_put_parent(parent);
}
}
}
-/* Update watch data in audit rules based on inotify events. */
-static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+{
+ struct fsnotify_mark_entry *entry;
+ bool send;
+
+ spin_lock(&inode->i_lock);
+ entry = fsnotify_find_mark_entry(group, inode);
+ spin_unlock(&inode->i_lock);
+ if (!entry)
+ return false;
+
+ mask = (mask & ~FS_EVENT_ON_CHILD);
+ send = (entry->mask & mask);
+
+ /* find took a reference */
+ fsnotify_put_mark(entry);
+
+ return send;
+}
+
+/* Update watch data in audit rules based on fsnotify events. */
+static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
+ struct inode *inode;
+ __u32 mask = event->mask;
+ const char *dname = event->file_name;
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
+ BUG_ON(group != audit_watch_group);
- if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
- audit_update_watch(parent, dname, inode->i_sb->s_dev,
- inode->i_ino, 0);
- else if (mask & (IN_DELETE|IN_MOVED_FROM))
+ parent = audit_find_parent(event->to_tell);
+ if (unlikely(!parent))
+ return 0;
+
+ switch (event->data_type) {
+ case (FSNOTIFY_EVENT_PATH):
+ inode = event->path.dentry->d_inode;
+ break;
+ case (FSNOTIFY_EVENT_INODE):
+ inode = event->inode;
+ break;
+ default:
+ BUG();
+ inode = NULL;
+ break;
+ };
+
+ if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
+ audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
+ else if (mask & (FS_DELETE|FS_MOVED_FROM))
audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
- /* inotify automatically removes the watch and sends IN_IGNORED */
- else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))
+ else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
audit_remove_parent_watches(parent);
- /* inotify does not remove the watch, so remove it manually */
- else if(mask & IN_MOVE_SELF) {
- audit_remove_parent_watches(parent);
- inotify_remove_watch_locked(audit_ih, i_watch);
- } else if (mask & IN_IGNORED)
- put_inotify_watch(i_watch);
+ /* moved put_inotify_watch to freeing mark */
+
+ /* matched the ref taken by audit_find_parent */
+ audit_put_parent(parent);
+
+ return 0;
}
-static const struct inotify_operations audit_inotify_ops = {
- .handle_event = audit_handle_ievent,
- .destroy_watch = audit_free_parent,
+static const struct fsnotify_ops audit_watch_fsnotify_ops = {
+ .should_send_event = audit_watch_should_send_event,
+ .handle_event = audit_watch_handle_event,
+ .free_group_priv = NULL,
+ .freeing_mark = NULL,
+ .free_event_priv = NULL,
};
static int __init audit_watch_init(void)
{
- audit_ih = inotify_init(&audit_inotify_ops);
- if (IS_ERR(audit_ih))
- audit_panic("cannot initialize inotify handle");
+ audit_watch_group = fsnotify_obtain_group(AUDIT_WATCH_GROUP_NUM, AUDIT_FS_WATCH,
+ &audit_watch_fsnotify_ops);
+ if (IS_ERR(audit_watch_group)) {
+ audit_watch_group = NULL;
+ audit_panic("cannot create audit fsnotify group");
+ }
return 0;
}
-subsys_initcall(audit_watch_init);
+device_initcall(audit_watch_init);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a70604047f3c..f5e4cae5ad82 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -70,6 +70,7 @@ static inline void audit_free_rule(struct audit_entry *e)
{
int i;
struct audit_krule *erule = &e->rule;
+
/* some rules don't have associated watches */
if (erule->watch)
audit_put_watch(erule->watch);
@@ -745,8 +746,7 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
* rule with the new rule in the filterlist, then free the old rule.
* The rlist element is undefined; list manipulations are handled apart from
* the initial copy. */
-struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch)
+struct audit_entry *audit_dupe_rule(struct audit_krule *old)
{
u32 fcount = old->field_count;
struct audit_entry *entry;
@@ -768,8 +768,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
new->prio = old->prio;
new->buflen = old->buflen;
new->inode_f = old->inode_f;
- new->watch = NULL;
new->field_count = old->field_count;
+
/*
* note that we are OK with not refcounting here; audit_match_tree()
* never dereferences tree and we can't get false positives there
@@ -810,9 +810,9 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
}
}
- if (watch) {
- audit_get_watch(watch);
- new->watch = watch;
+ if (old->watch) {
+ audit_get_watch(old->watch);
+ new->watch = old->watch;
}
return entry;
@@ -865,7 +865,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- int h, err;
+ int err;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -888,15 +888,11 @@ static inline int audit_add_rule(struct audit_entry *entry)
if (watch) {
/* audit_filter_mutex is dropped and re-taken during this call */
- err = audit_add_watch(&entry->rule);
+ err = audit_add_watch(&entry->rule, &list);
if (err) {
mutex_unlock(&audit_filter_mutex);
goto error;
}
- /* entry->rule.watch may have changed during audit_add_watch() */
- watch = entry->rule.watch;
- h = audit_hash_ino((u32)audit_watch_inode(watch));
- list = &audit_inode_hash[h];
}
if (tree) {
err = audit_add_tree_rule(&entry->rule);
@@ -948,7 +944,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- LIST_HEAD(inotify_list);
int ret = 0;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -968,7 +963,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
}
if (e->rule.watch)
- audit_remove_watch_rule(&e->rule, &inotify_list);
+ audit_remove_watch_rule(&e->rule);
if (e->rule.tree)
audit_remove_tree_rule(&e->rule);
@@ -986,9 +981,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
#endif
mutex_unlock(&audit_filter_mutex);
- if (!list_empty(&inotify_list))
- audit_inotify_unregister(&inotify_list);
-
out:
if (watch)
audit_put_watch(watch); /* match initial get */
@@ -1322,30 +1314,23 @@ static int update_lsm_rule(struct audit_krule *r)
{
struct audit_entry *entry = container_of(r, struct audit_entry, rule);
struct audit_entry *nentry;
- struct audit_watch *watch;
- struct audit_tree *tree;
int err = 0;
if (!security_audit_rule_known(r))
return 0;
- watch = r->watch;
- tree = r->tree;
- nentry = audit_dupe_rule(r, watch);
+ nentry = audit_dupe_rule(r);
if (IS_ERR(nentry)) {
/* save the first error encountered for the
* return value */
err = PTR_ERR(nentry);
audit_panic("error updating LSM filters");
- if (watch)
+ if (r->watch)
list_del(&r->rlist);
list_del_rcu(&entry->list);
list_del(&r->list);
} else {
- if (watch) {
- list_add(&nentry->rule.rlist, audit_watch_rules(watch));
- list_del(&r->rlist);
- } else if (tree)
+ if (r->watch || r->tree)
list_replace_init(&r->rlist, &nentry->rule.rlist);
list_replace_rcu(&entry->list, &nentry->list);
list_replace(&r->list, &nentry->rule.list);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 68d3c6a0ecd6..2a5dbfefa8de 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -549,9 +549,8 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_WATCH:
- if (name && audit_watch_inode(rule->watch) != (unsigned long)-1)
- result = (name->dev == audit_watch_dev(rule->watch) &&
- name->ino == audit_watch_inode(rule->watch));
+ if (name)
+ result = audit_watch_compare(rule->watch, name->ino, name->dev);
break;
case AUDIT_DIR:
if (ctx)
@@ -1726,7 +1725,7 @@ static inline void handle_one(const struct inode *inode)
struct audit_tree_refs *p;
struct audit_chunk *chunk;
int count;
- if (likely(list_empty(&inode->inotify_watches)))
+ if (likely(hlist_empty(&inode->i_fsnotify_mark_entries)))
return;
context = current->audit_context;
p = context->trees;
@@ -1769,7 +1768,7 @@ retry:
seq = read_seqbegin(&rename_lock);
for(;;) {
struct inode *inode = d->d_inode;
- if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+ if (inode && unlikely(!hlist_empty(&inode->i_fsnotify_mark_entries))) {
struct audit_chunk *chunk;
chunk = audit_tree_lookup(inode);
if (chunk) {
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 3737a682cdf5..c7ece8f027f2 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -47,6 +47,7 @@
#include <linux/hash.h>
#include <linux/namei.h>
#include <linux/smp_lock.h>
+#include <linux/pid_namespace.h>
#include <asm/atomic.h>
@@ -599,6 +600,7 @@ static struct inode_operations cgroup_dir_inode_operations;
static struct file_operations proc_cgroupstats_operations;
static struct backing_dev_info cgroup_backing_dev_info = {
+ .name = "cgroup",
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
@@ -734,16 +736,28 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
* reference to css->refcnt. In general, this refcnt is expected to goes down
* to zero, soon.
*
- * CGRP_WAIT_ON_RMDIR flag is modified under cgroup's inode->i_mutex;
+ * CGRP_WAIT_ON_RMDIR flag is set under cgroup's inode->i_mutex;
*/
DECLARE_WAIT_QUEUE_HEAD(cgroup_rmdir_waitq);
-static void cgroup_wakeup_rmdir_waiters(const struct cgroup *cgrp)
+static void cgroup_wakeup_rmdir_waiter(struct cgroup *cgrp)
{
- if (unlikely(test_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags)))
+ if (unlikely(test_and_clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags)))
wake_up_all(&cgroup_rmdir_waitq);
}
+void cgroup_exclude_rmdir(struct cgroup_subsys_state *css)
+{
+ css_get(css);
+}
+
+void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css)
+{
+ cgroup_wakeup_rmdir_waiter(css->cgroup);
+ css_put(css);
+}
+
+
static int rebind_subsystems(struct cgroupfs_root *root,
unsigned long final_bits)
{
@@ -960,6 +974,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
INIT_LIST_HEAD(&cgrp->children);
INIT_LIST_HEAD(&cgrp->css_sets);
INIT_LIST_HEAD(&cgrp->release_list);
+ INIT_LIST_HEAD(&cgrp->pids_list);
init_rwsem(&cgrp->pids_mutex);
}
static void init_cgroup_root(struct cgroupfs_root *root)
@@ -1357,7 +1372,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
* wake up rmdir() waiter. the rmdir should fail since the cgroup
* is no longer empty.
*/
- cgroup_wakeup_rmdir_waiters(cgrp);
+ cgroup_wakeup_rmdir_waiter(cgrp);
return 0;
}
@@ -2201,12 +2216,30 @@ err:
return ret;
}
+/*
+ * Cache pids for all threads in the same pid namespace that are
+ * opening the same "tasks" file.
+ */
+struct cgroup_pids {
+ /* The node in cgrp->pids_list */
+ struct list_head list;
+ /* The cgroup those pids belong to */
+ struct cgroup *cgrp;
+ /* The namepsace those pids belong to */
+ struct pid_namespace *ns;
+ /* Array of process ids in the cgroup */
+ pid_t *tasks_pids;
+ /* How many files are using the this tasks_pids array */
+ int use_count;
+ /* Length of the current tasks_pids array */
+ int length;
+};
+
static int cmppid(const void *a, const void *b)
{
return *(pid_t *)a - *(pid_t *)b;
}
-
/*
* seq_file methods for the "tasks" file. The seq_file position is the
* next pid to display; the seq_file iterator is a pointer to the pid
@@ -2221,45 +2254,47 @@ static void *cgroup_tasks_start(struct seq_file *s, loff_t *pos)
* after a seek to the start). Use a binary-search to find the
* next pid to display, if any
*/
- struct cgroup *cgrp = s->private;
+ struct cgroup_pids *cp = s->private;
+ struct cgroup *cgrp = cp->cgrp;
int index = 0, pid = *pos;
int *iter;
down_read(&cgrp->pids_mutex);
if (pid) {
- int end = cgrp->pids_length;
+ int end = cp->length;
while (index < end) {
int mid = (index + end) / 2;
- if (cgrp->tasks_pids[mid] == pid) {
+ if (cp->tasks_pids[mid] == pid) {
index = mid;
break;
- } else if (cgrp->tasks_pids[mid] <= pid)
+ } else if (cp->tasks_pids[mid] <= pid)
index = mid + 1;
else
end = mid;
}
}
/* If we're off the end of the array, we're done */
- if (index >= cgrp->pids_length)
+ if (index >= cp->length)
return NULL;
/* Update the abstract position to be the actual pid that we found */
- iter = cgrp->tasks_pids + index;
+ iter = cp->tasks_pids + index;
*pos = *iter;
return iter;
}
static void cgroup_tasks_stop(struct seq_file *s, void *v)
{
- struct cgroup *cgrp = s->private;
+ struct cgroup_pids *cp = s->private;
+ struct cgroup *cgrp = cp->cgrp;
up_read(&cgrp->pids_mutex);
}
static void *cgroup_tasks_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct cgroup *cgrp = s->private;
+ struct cgroup_pids *cp = s->private;
int *p = v;
- int *end = cgrp->tasks_pids + cgrp->pids_length;
+ int *end = cp->tasks_pids + cp->length;
/*
* Advance to the next pid in the array. If this goes off the
@@ -2286,26 +2321,33 @@ static struct seq_operations cgroup_tasks_seq_operations = {
.show = cgroup_tasks_show,
};
-static void release_cgroup_pid_array(struct cgroup *cgrp)
+static void release_cgroup_pid_array(struct cgroup_pids *cp)
{
+ struct cgroup *cgrp = cp->cgrp;
+
down_write(&cgrp->pids_mutex);
- BUG_ON(!cgrp->pids_use_count);
- if (!--cgrp->pids_use_count) {
- kfree(cgrp->tasks_pids);
- cgrp->tasks_pids = NULL;
- cgrp->pids_length = 0;
+ BUG_ON(!cp->use_count);
+ if (!--cp->use_count) {
+ list_del(&cp->list);
+ put_pid_ns(cp->ns);
+ kfree(cp->tasks_pids);
+ kfree(cp);
}
up_write(&cgrp->pids_mutex);
}
static int cgroup_tasks_release(struct inode *inode, struct file *file)
{
- struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
+ struct seq_file *seq;
+ struct cgroup_pids *cp;
if (!(file->f_mode & FMODE_READ))
return 0;
- release_cgroup_pid_array(cgrp);
+ seq = file->private_data;
+ cp = seq->private;
+
+ release_cgroup_pid_array(cp);
return seq_release(inode, file);
}
@@ -2324,6 +2366,8 @@ static struct file_operations cgroup_tasks_operations = {
static int cgroup_tasks_open(struct inode *unused, struct file *file)
{
struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
+ struct pid_namespace *ns = current->nsproxy->pid_ns;
+ struct cgroup_pids *cp;
pid_t *pidarray;
int npids;
int retval;
@@ -2350,20 +2394,37 @@ static int cgroup_tasks_open(struct inode *unused, struct file *file)
* array if necessary
*/
down_write(&cgrp->pids_mutex);
- kfree(cgrp->tasks_pids);
- cgrp->tasks_pids = pidarray;
- cgrp->pids_length = npids;
- cgrp->pids_use_count++;
+
+ list_for_each_entry(cp, &cgrp->pids_list, list) {
+ if (ns == cp->ns)
+ goto found;
+ }
+
+ cp = kzalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp) {
+ up_write(&cgrp->pids_mutex);
+ kfree(pidarray);
+ return -ENOMEM;
+ }
+ cp->cgrp = cgrp;
+ cp->ns = ns;
+ get_pid_ns(ns);
+ list_add(&cp->list, &cgrp->pids_list);
+found:
+ kfree(cp->tasks_pids);
+ cp->tasks_pids = pidarray;
+ cp->length = npids;
+ cp->use_count++;
up_write(&cgrp->pids_mutex);
file->f_op = &cgroup_tasks_operations;
retval = seq_open(file, &cgroup_tasks_seq_operations);
if (retval) {
- release_cgroup_pid_array(cgrp);
+ release_cgroup_pid_array(cp);
return retval;
}
- ((struct seq_file *)file->private_data)->private = cgrp;
+ ((struct seq_file *)file->private_data)->private = cp;
return 0;
}
@@ -2696,33 +2757,42 @@ again:
mutex_unlock(&cgroup_mutex);
/*
+ * In general, subsystem has no css->refcnt after pre_destroy(). But
+ * in racy cases, subsystem may have to get css->refcnt after
+ * pre_destroy() and it makes rmdir return with -EBUSY. This sometimes
+ * make rmdir return -EBUSY too often. To avoid that, we use waitqueue
+ * for cgroup's rmdir. CGRP_WAIT_ON_RMDIR is for synchronizing rmdir
+ * and subsystem's reference count handling. Please see css_get/put
+ * and css_tryget() and cgroup_wakeup_rmdir_waiter() implementation.
+ */
+ set_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
+
+ /*
* Call pre_destroy handlers of subsys. Notify subsystems
* that rmdir() request comes.
*/
ret = cgroup_call_pre_destroy(cgrp);
- if (ret)
+ if (ret) {
+ clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
return ret;
+ }
mutex_lock(&cgroup_mutex);
parent = cgrp->parent;
if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) {
+ clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
mutex_unlock(&cgroup_mutex);
return -EBUSY;
}
- /*
- * css_put/get is provided for subsys to grab refcnt to css. In typical
- * case, subsystem has no reference after pre_destroy(). But, under
- * hierarchy management, some *temporal* refcnt can be hold.
- * To avoid returning -EBUSY to a user, waitqueue is used. If subsys
- * is really busy, it should return -EBUSY at pre_destroy(). wake_up
- * is called when css_put() is called and refcnt goes down to 0.
- */
- set_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE);
-
if (!cgroup_clear_css_refs(cgrp)) {
mutex_unlock(&cgroup_mutex);
- schedule();
+ /*
+ * Because someone may call cgroup_wakeup_rmdir_waiter() before
+ * prepare_to_wait(), we need to check this flag.
+ */
+ if (test_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags))
+ schedule();
finish_wait(&cgroup_rmdir_waitq, &wait);
clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags);
if (signal_pending(current))
@@ -3294,7 +3364,7 @@ void __css_put(struct cgroup_subsys_state *css)
set_bit(CGRP_RELEASABLE, &cgrp->flags);
check_for_release(cgrp);
}
- cgroup_wakeup_rmdir_waiters(cgrp);
+ cgroup_wakeup_rmdir_waiter(cgrp);
}
rcu_read_unlock();
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 9b42695f0d14..5020e2afd8e2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -62,6 +62,7 @@
#include <linux/fs_struct.h>
#include <linux/magic.h>
#include <linux/perf_counter.h>
+#include <linux/kmemleak.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -104,16 +105,20 @@ static struct kmem_cache *task_struct_cachep;
#ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR
static inline struct thread_info *alloc_thread_info(struct task_struct *tsk)
{
+ struct thread_info *ti;
#ifdef CONFIG_DEBUG_STACK_USAGE
gfp_t mask = GFP_KERNEL | __GFP_ZERO;
#else
gfp_t mask = GFP_KERNEL;
#endif
- return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
+ ti = (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
+ kmemleak_alloc(ti, THREAD_SIZE, 1, mask);
+ return ti;
}
static inline void free_thread_info(struct thread_info *ti)
{
+ kmemleak_free(ti);
free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
}
#endif
@@ -426,6 +431,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
init_rwsem(&mm->mmap_sem);
INIT_LIST_HEAD(&mm->mmlist);
mm->flags = (current->mm) ? current->mm->flags : default_dump_filter;
+ mm->oom_adj = (current->mm) ? current->mm->oom_adj : 0;
mm->core_state = NULL;
mm->nr_ptes = 0;
set_mm_counter(mm, file_rss, 0);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 61c679db4687..d1538bd4a5f7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -978,7 +978,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
kfree(action);
#ifdef CONFIG_DEBUG_SHIRQ
- if (irqflags & IRQF_SHARED) {
+ if (!retval && (irqflags & IRQF_SHARED)) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 638d8bedec14..a0bb09e79867 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -15,10 +15,10 @@
/**
* suspend_device_irqs - disable all currently enabled interrupt lines
*
- * During system-wide suspend or hibernation device interrupts need to be
- * disabled at the chip level and this function is provided for this purpose.
- * It disables all interrupt lines that are enabled at the moment and sets the
- * IRQ_SUSPENDED flag for them.
+ * During system-wide suspend or hibernation device drivers need to be prevented
+ * from receiving interrupts and this function is provided for this purpose.
+ * It marks all interrupt lines in use, except for the timer ones, as disabled
+ * and sets the IRQ_SUSPENDED flag for each of them.
*/
void suspend_device_irqs(void)
{
diff --git a/kernel/kexec.c b/kernel/kexec.c
index ae1c35201cc8..f336e2107f98 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1228,7 +1228,7 @@ static int __init parse_crashkernel_mem(char *cmdline,
} while (*cur++ == ',');
if (*crash_size > 0) {
- while (*cur != ' ' && *cur != '@')
+ while (*cur && *cur != ' ' && *cur != '@')
cur++;
if (*cur == '@') {
cur++;
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 9147a3190c9d..ebaccad70f02 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];
@@ -363,7 +364,7 @@ static void put_packet(char *buffer)
* Convert the memory pointed to by mem into hex, placing result in buf.
* Return a pointer to the last char put in buf (null). May return an error.
*/
-int kgdb_mem2hex(char *mem, char *buf, int count)
+int __weak kgdb_mem2hex(char *mem, char *buf, int count)
{
char *tmp;
int err;
@@ -393,7 +394,7 @@ int kgdb_mem2hex(char *mem, char *buf, int count)
* 0x7d escaped with 0x7d. Return a pointer to the character after
* the last byte written.
*/
-static int kgdb_ebin2mem(char *buf, char *mem, int count)
+int __weak kgdb_ebin2mem(char *buf, char *mem, int count)
{
int err = 0;
char c;
@@ -418,7 +419,7 @@ static int kgdb_ebin2mem(char *buf, char *mem, int count)
* Return a pointer to the character AFTER the last byte written.
* May return an error.
*/
-int kgdb_hex2mem(char *buf, char *mem, int count)
+int __weak kgdb_hex2mem(char *buf, char *mem, int count)
{
char *tmp_raw;
char *tmp_hex;
@@ -590,7 +591,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 +1205,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 +1433,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 +1527,16 @@ acquirelock:
}
kgdb_restore:
+ if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
+ int sstep_cpu = atomic_read(&kgdb_cpu_doing_single_step);
+ if (kgdb_info[sstep_cpu].task)
+ kgdb_sstep_pid = kgdb_info[sstep_cpu].task->pid;
+ else
+ kgdb_sstep_pid = 0;
+ }
/* Free kgdb_active */
atomic_set(&kgdb_active, -1);
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sync();
clocksource_touch_watchdog();
local_irq_restore(flags);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 16b5739c516a..ef177d653b2c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -103,7 +103,7 @@ static struct kprobe_blackpoint kprobe_blacklist[] = {
#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
struct kprobe_insn_page {
- struct hlist_node hlist;
+ struct list_head list;
kprobe_opcode_t *insns; /* Page of instruction slots */
char slot_used[INSNS_PER_PAGE];
int nused;
@@ -117,7 +117,7 @@ enum kprobe_slot_state {
};
static DEFINE_MUTEX(kprobe_insn_mutex); /* Protects kprobe_insn_pages */
-static struct hlist_head kprobe_insn_pages;
+static LIST_HEAD(kprobe_insn_pages);
static int kprobe_garbage_slots;
static int collect_garbage_slots(void);
@@ -152,10 +152,9 @@ loop_end:
static kprobe_opcode_t __kprobes *__get_insn_slot(void)
{
struct kprobe_insn_page *kip;
- struct hlist_node *pos;
retry:
- hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
+ list_for_each_entry(kip, &kprobe_insn_pages, list) {
if (kip->nused < INSNS_PER_PAGE) {
int i;
for (i = 0; i < INSNS_PER_PAGE; i++) {
@@ -189,8 +188,8 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(void)
kfree(kip);
return NULL;
}
- INIT_HLIST_NODE(&kip->hlist);
- hlist_add_head(&kip->hlist, &kprobe_insn_pages);
+ INIT_LIST_HEAD(&kip->list);
+ list_add(&kip->list, &kprobe_insn_pages);
memset(kip->slot_used, SLOT_CLEAN, INSNS_PER_PAGE);
kip->slot_used[0] = SLOT_USED;
kip->nused = 1;
@@ -219,12 +218,8 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
* so as not to have to set it up again the
* next time somebody inserts a probe.
*/
- hlist_del(&kip->hlist);
- if (hlist_empty(&kprobe_insn_pages)) {
- INIT_HLIST_NODE(&kip->hlist);
- hlist_add_head(&kip->hlist,
- &kprobe_insn_pages);
- } else {
+ if (!list_is_singular(&kprobe_insn_pages)) {
+ list_del(&kip->list);
module_free(NULL, kip->insns);
kfree(kip);
}
@@ -235,14 +230,13 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
static int __kprobes collect_garbage_slots(void)
{
- struct kprobe_insn_page *kip;
- struct hlist_node *pos, *next;
+ struct kprobe_insn_page *kip, *next;
/* Ensure no-one is preepmted on the garbages */
if (check_safety())
return -EAGAIN;
- hlist_for_each_entry_safe(kip, pos, next, &kprobe_insn_pages, hlist) {
+ list_for_each_entry_safe(kip, next, &kprobe_insn_pages, list) {
int i;
if (kip->ngarbage == 0)
continue;
@@ -260,19 +254,17 @@ static int __kprobes collect_garbage_slots(void)
void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
{
struct kprobe_insn_page *kip;
- struct hlist_node *pos;
mutex_lock(&kprobe_insn_mutex);
- hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
+ list_for_each_entry(kip, &kprobe_insn_pages, list) {
if (kip->insns <= slot &&
slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
int i = (slot - kip->insns) / MAX_INSN_SIZE;
if (dirty) {
kip->slot_used[i] = SLOT_DIRTY;
kip->ngarbage++;
- } else {
+ } else
collect_one_slot(kip, i);
- }
break;
}
}
@@ -694,7 +686,7 @@ int __kprobes register_kprobe(struct kprobe *p)
p->addr = addr;
preempt_disable();
- if (!__kernel_text_address((unsigned long) p->addr) ||
+ if (!kernel_text_address((unsigned long) p->addr) ||
in_kprobes_functions((unsigned long) p->addr)) {
preempt_enable();
return -EINVAL;
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 9b1a7de26979..eb8751aa0418 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -180,10 +180,12 @@ EXPORT_SYMBOL(kthread_bind);
* @k: thread created by kthread_create().
*
* Sets kthread_should_stop() for @k to return true, wakes it, and
- * waits for it to exit. Your threadfn() must not call do_exit()
- * itself if you use this function! This can also be called after
- * kthread_create() instead of calling wake_up_process(): the thread
- * will exit without calling threadfn().
+ * waits for it to exit. This can also be called after kthread_create()
+ * instead of calling wake_up_process(): the thread will exit without
+ * calling threadfn().
+ *
+ * If threadfn() may call do_exit() itself, the caller must ensure
+ * task_struct can't go away.
*
* Returns the result of threadfn(), or %-EINTR if wake_up_process()
* was never called.
diff --git a/kernel/module.c b/kernel/module.c
index 0a049837008e..3a4db71ea494 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(find_module);
#ifdef CONFIG_SMP
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
static void *percpu_modalloc(unsigned long size, unsigned long align,
const char *name)
@@ -389,7 +389,7 @@ static void percpu_modfree(void *freeme)
free_percpu(freeme);
}
-#else /* ... !CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */
/* Number of blocks used and allocated. */
static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -535,7 +535,7 @@ static int percpu_modinit(void)
}
__initcall(percpu_modinit);
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
static unsigned int find_pcpusec(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs,
@@ -1068,7 +1068,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
{
const unsigned long *crc;
- if (!find_symbol("module_layout", NULL, &crc, true, false))
+ if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL,
+ &crc, true, false))
BUG();
return check_version(sechdrs, versindex, "module_layout", mod, crc);
}
diff --git a/kernel/panic.c b/kernel/panic.c
index 984b3ecbd72c..b855012e1ee0 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -177,7 +177,7 @@ static const struct tnt tnts[] = {
* 'W' - Taint on warning.
* 'C' - modules from drivers/staging are loaded.
*
- * The string is overwritten by the next call to print_taint().
+ * The string is overwritten by the next call to print_tainted().
*/
const char *print_tainted(void)
{
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 950931041954..05de4b201a78 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -98,16 +98,16 @@ hw_perf_group_sched_in(struct perf_counter *group_leader,
void __weak perf_counter_print_debug(void) { }
-static DEFINE_PER_CPU(int, disable_count);
+static DEFINE_PER_CPU(int, perf_disable_count);
void __perf_disable(void)
{
- __get_cpu_var(disable_count)++;
+ __get_cpu_var(perf_disable_count)++;
}
bool __perf_enable(void)
{
- return !--__get_cpu_var(disable_count);
+ return !--__get_cpu_var(perf_disable_count);
}
void perf_disable(void)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 81d2e7464893..04b3a83d686f 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -298,8 +298,8 @@ int hibernation_snapshot(int platform_mode)
if (error)
return error;
- /* Free memory before shutting down devices. */
- error = swsusp_shrink_memory();
+ /* Preallocate image memory before shutting down devices. */
+ error = hibernate_preallocate_memory();
if (error)
goto Close;
@@ -315,6 +315,10 @@ int hibernation_snapshot(int platform_mode)
/* Control returns here after successful restore */
Resume_devices:
+ /* We may need to release the preallocated image pages here. */
+ if (error || !in_suspend)
+ swsusp_free();
+
dpm_resume_end(in_suspend ?
(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
resume_console();
@@ -460,11 +464,11 @@ int hibernation_platform_enter(void)
error = hibernation_ops->prepare();
if (error)
- goto Platofrm_finish;
+ goto Platform_finish;
error = disable_nonboot_cpus();
if (error)
- goto Platofrm_finish;
+ goto Platform_finish;
local_irq_disable();
sysdev_suspend(PMSG_HIBERNATE);
@@ -476,7 +480,7 @@ int hibernation_platform_enter(void)
* We don't need to reenable the nonboot CPUs or resume consoles, since
* the system is going to be halted anyway.
*/
- Platofrm_finish:
+ Platform_finish:
hibernation_ops->finish();
dpm_suspend_noirq(PMSG_RESTORE);
@@ -578,7 +582,10 @@ int hibernate(void)
goto Thaw;
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
- if (in_suspend && !error) {
+ if (error)
+ goto Thaw;
+
+ if (in_suspend) {
unsigned int flags = 0;
if (hibernation_mode == HIBERNATION_PLATFORM)
@@ -590,8 +597,8 @@ int hibernate(void)
power_down();
} else {
pr_debug("PM: Image restored successfully.\n");
- swsusp_free();
}
+
Thaw:
thaw_processes();
Finish:
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 26d5a26f82e3..46c5a26630a3 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void);
extern int create_basic_memory_bitmaps(void);
extern void free_basic_memory_bitmaps(void);
-extern int swsusp_shrink_memory(void);
+extern int hibernate_preallocate_memory(void);
/**
* Auxiliary structure used for reading the snapshot image data and
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 523a451b45d3..97955b0e44f4 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -233,7 +233,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
#define BM_END_OF_MAP (~0UL)
-#define BM_BITS_PER_BLOCK (PAGE_SIZE << 3)
+#define BM_BITS_PER_BLOCK (PAGE_SIZE * BITS_PER_BYTE)
struct bm_block {
struct list_head hook; /* hook into a list of bitmap blocks */
@@ -275,7 +275,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free);
/**
* create_bm_block_list - create a list of block bitmap objects
- * @nr_blocks - number of blocks to allocate
+ * @pages - number of pages to track
* @list - list to put the allocated blocks into
* @ca - chain allocator to be used for allocating memory
*/
@@ -853,7 +853,7 @@ static unsigned int count_highmem_pages(void)
struct zone *zone;
unsigned int n = 0;
- for_each_zone(zone) {
+ for_each_populated_zone(zone) {
unsigned long pfn, max_zone_pfn;
if (!is_highmem(zone))
@@ -916,7 +916,7 @@ static unsigned int count_data_pages(void)
unsigned long pfn, max_zone_pfn;
unsigned int n = 0;
- for_each_zone(zone) {
+ for_each_populated_zone(zone) {
if (is_highmem(zone))
continue;
@@ -1010,7 +1010,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
struct zone *zone;
unsigned long pfn;
- for_each_zone(zone) {
+ for_each_populated_zone(zone) {
unsigned long max_zone_pfn;
mark_free_pages(zone);
@@ -1033,6 +1033,25 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
static unsigned int nr_copy_pages;
/* Number of pages needed for saving the original pfns of the image pages */
static unsigned int nr_meta_pages;
+/*
+ * Numbers of normal and highmem page frames allocated for hibernation image
+ * before suspending devices.
+ */
+unsigned int alloc_normal, alloc_highmem;
+/*
+ * Memory bitmap used for marking saveable pages (during hibernation) or
+ * hibernation image pages (during restore)
+ */
+static struct memory_bitmap orig_bm;
+/*
+ * Memory bitmap used during hibernation for marking allocated page frames that
+ * will contain copies of saveable pages. During restore it is initially used
+ * for marking hibernation image pages, but then the set bits from it are
+ * duplicated in @orig_bm and it is released. On highmem systems it is next
+ * used for marking "safe" highmem pages, but it has to be reinitialized for
+ * this purpose.
+ */
+static struct memory_bitmap copy_bm;
/**
* swsusp_free - free pages allocated for the suspend.
@@ -1046,7 +1065,7 @@ void swsusp_free(void)
struct zone *zone;
unsigned long pfn, max_zone_pfn;
- for_each_zone(zone) {
+ for_each_populated_zone(zone) {
max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn)) {
@@ -1064,74 +1083,286 @@ void swsusp_free(void)
nr_meta_pages = 0;
restore_pblist = NULL;
buffer = NULL;
+ alloc_normal = 0;
+ alloc_highmem = 0;
}
+/* Helper functions used for the shrinking of memory. */
+
+#define GFP_IMAGE (GFP_KERNEL | __GFP_NOWARN)
+
/**
- * swsusp_shrink_memory - Try to free as much memory as needed
- *
- * ... but do not OOM-kill anyone
+ * preallocate_image_pages - Allocate a number of pages for hibernation image
+ * @nr_pages: Number of page frames to allocate.
+ * @mask: GFP flags to use for the allocation.
*
- * Notice: all userland should be stopped before it is called, or
- * livelock is possible.
+ * Return value: Number of page frames actually allocated
+ */
+static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
+{
+ unsigned long nr_alloc = 0;
+
+ while (nr_pages > 0) {
+ struct page *page;
+
+ page = alloc_image_page(mask);
+ if (!page)
+ break;
+ memory_bm_set_bit(&copy_bm, page_to_pfn(page));
+ if (PageHighMem(page))
+ alloc_highmem++;
+ else
+ alloc_normal++;
+ nr_pages--;
+ nr_alloc++;
+ }
+
+ return nr_alloc;
+}
+
+static unsigned long preallocate_image_memory(unsigned long nr_pages)
+{
+ return preallocate_image_pages(nr_pages, GFP_IMAGE);
+}
+
+#ifdef CONFIG_HIGHMEM
+static unsigned long preallocate_image_highmem(unsigned long nr_pages)
+{
+ return preallocate_image_pages(nr_pages, GFP_IMAGE | __GFP_HIGHMEM);
+}
+
+/**
+ * __fraction - Compute (an approximation of) x * (multiplier / base)
*/
+static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
+{
+ x *= multiplier;
+ do_div(x, base);
+ return (unsigned long)x;
+}
+
+static unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
+ unsigned long highmem,
+ unsigned long total)
+{
+ unsigned long alloc = __fraction(nr_pages, highmem, total);
-#define SHRINK_BITE 10000
-static inline unsigned long __shrink_memory(long tmp)
+ return preallocate_image_pages(alloc, GFP_IMAGE | __GFP_HIGHMEM);
+}
+#else /* CONFIG_HIGHMEM */
+static inline unsigned long preallocate_image_highmem(unsigned long nr_pages)
{
- if (tmp > SHRINK_BITE)
- tmp = SHRINK_BITE;
- return shrink_all_memory(tmp);
+ return 0;
}
-int swsusp_shrink_memory(void)
+static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
+ unsigned long highmem,
+ unsigned long total)
+{
+ return 0;
+}
+#endif /* CONFIG_HIGHMEM */
+
+/**
+ * free_unnecessary_pages - Release preallocated pages not needed for the image
+ */
+static void free_unnecessary_pages(void)
+{
+ unsigned long save_highmem, to_free_normal, to_free_highmem;
+
+ to_free_normal = alloc_normal - count_data_pages();
+ save_highmem = count_highmem_pages();
+ if (alloc_highmem > save_highmem) {
+ to_free_highmem = alloc_highmem - save_highmem;
+ } else {
+ to_free_highmem = 0;
+ to_free_normal -= save_highmem - alloc_highmem;
+ }
+
+ memory_bm_position_reset(&copy_bm);
+
+ while (to_free_normal > 0 && to_free_highmem > 0) {
+ unsigned long pfn = memory_bm_next_pfn(&copy_bm);
+ struct page *page = pfn_to_page(pfn);
+
+ if (PageHighMem(page)) {
+ if (!to_free_highmem)
+ continue;
+ to_free_highmem--;
+ alloc_highmem--;
+ } else {
+ if (!to_free_normal)
+ continue;
+ to_free_normal--;
+ alloc_normal--;
+ }
+ memory_bm_clear_bit(&copy_bm, pfn);
+ swsusp_unset_page_forbidden(page);
+ swsusp_unset_page_free(page);
+ __free_page(page);
+ }
+}
+
+/**
+ * minimum_image_size - Estimate the minimum acceptable size of an image
+ * @saveable: Number of saveable pages in the system.
+ *
+ * We want to avoid attempting to free too much memory too hard, so estimate the
+ * minimum acceptable size of a hibernation image to use as the lower limit for
+ * preallocating memory.
+ *
+ * We assume that the minimum image size should be proportional to
+ *
+ * [number of saveable pages] - [number of pages that can be freed in theory]
+ *
+ * where the second term is the sum of (1) reclaimable slab pages, (2) active
+ * and (3) inactive anonymouns pages, (4) active and (5) inactive file pages,
+ * minus mapped file pages.
+ */
+static unsigned long minimum_image_size(unsigned long saveable)
+{
+ unsigned long size;
+
+ size = global_page_state(NR_SLAB_RECLAIMABLE)
+ + global_page_state(NR_ACTIVE_ANON)
+ + global_page_state(NR_INACTIVE_ANON)
+ + global_page_state(NR_ACTIVE_FILE)
+ + global_page_state(NR_INACTIVE_FILE)
+ - global_page_state(NR_FILE_MAPPED);
+
+ return saveable <= size ? 0 : saveable - size;
+}
+
+/**
+ * hibernate_preallocate_memory - Preallocate memory for hibernation image
+ *
+ * To create a hibernation image it is necessary to make a copy of every page
+ * frame in use. We also need a number of page frames to be free during
+ * hibernation for allocations made while saving the image and for device
+ * drivers, in case they need to allocate memory from their hibernation
+ * callbacks (these two numbers are given by PAGES_FOR_IO and SPARE_PAGES,
+ * respectively, both of which are rough estimates). To make this happen, we
+ * compute the total number of available page frames and allocate at least
+ *
+ * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 + 2 * SPARE_PAGES
+ *
+ * of them, which corresponds to the maximum size of a hibernation image.
+ *
+ * If image_size is set below the number following from the above formula,
+ * the preallocation of memory is continued until the total number of saveable
+ * pages in the system is below the requested image size or the minimum
+ * acceptable image size returned by minimum_image_size(), whichever is greater.
+ */
+int hibernate_preallocate_memory(void)
{
- long tmp;
struct zone *zone;
- unsigned long pages = 0;
- unsigned int i = 0;
- char *p = "-\\|/";
+ unsigned long saveable, size, max_size, count, highmem, pages = 0;
+ unsigned long alloc, save_highmem, pages_highmem;
struct timeval start, stop;
+ int error;
- printk(KERN_INFO "PM: Shrinking memory... ");
+ printk(KERN_INFO "PM: Preallocating image memory... ");
do_gettimeofday(&start);
- do {
- long size, highmem_size;
-
- highmem_size = count_highmem_pages();
- size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
- tmp = size;
- size += highmem_size;
- for_each_populated_zone(zone) {
- tmp += snapshot_additional_pages(zone);
- if (is_highmem(zone)) {
- highmem_size -=
- zone_page_state(zone, NR_FREE_PAGES);
- } else {
- tmp -= zone_page_state(zone, NR_FREE_PAGES);
- tmp += zone->lowmem_reserve[ZONE_NORMAL];
- }
- }
- if (highmem_size < 0)
- highmem_size = 0;
+ error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
+ if (error)
+ goto err_out;
- tmp += highmem_size;
- if (tmp > 0) {
- tmp = __shrink_memory(tmp);
- if (!tmp)
- return -ENOMEM;
- pages += tmp;
- } else if (size > image_size / PAGE_SIZE) {
- tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
- pages += tmp;
- }
- printk("\b%c", p[i++%4]);
- } while (tmp > 0);
+ error = memory_bm_create(&copy_bm, GFP_IMAGE, PG_ANY);
+ if (error)
+ goto err_out;
+
+ alloc_normal = 0;
+ alloc_highmem = 0;
+
+ /* Count the number of saveable data pages. */
+ save_highmem = count_highmem_pages();
+ saveable = count_data_pages();
+
+ /*
+ * Compute the total number of page frames we can use (count) and the
+ * number of pages needed for image metadata (size).
+ */
+ count = saveable;
+ saveable += save_highmem;
+ highmem = save_highmem;
+ size = 0;
+ for_each_populated_zone(zone) {
+ size += snapshot_additional_pages(zone);
+ if (is_highmem(zone))
+ highmem += zone_page_state(zone, NR_FREE_PAGES);
+ else
+ count += zone_page_state(zone, NR_FREE_PAGES);
+ }
+ count += highmem;
+ count -= totalreserve_pages;
+
+ /* Compute the maximum number of saveable pages to leave in memory. */
+ max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES;
+ size = DIV_ROUND_UP(image_size, PAGE_SIZE);
+ if (size > max_size)
+ size = max_size;
+ /*
+ * If the maximum is not less than the current number of saveable pages
+ * in memory, allocate page frames for the image and we're done.
+ */
+ if (size >= saveable) {
+ pages = preallocate_image_highmem(save_highmem);
+ pages += preallocate_image_memory(saveable - pages);
+ goto out;
+ }
+
+ /* Estimate the minimum size of the image. */
+ pages = minimum_image_size(saveable);
+ if (size < pages)
+ size = min_t(unsigned long, pages, max_size);
+
+ /*
+ * Let the memory management subsystem know that we're going to need a
+ * large number of page frames to allocate and make it free some memory.
+ * NOTE: If this is not done, performance will be hurt badly in some
+ * test cases.
+ */
+ shrink_all_memory(saveable - size);
+
+ /*
+ * The number of saveable pages in memory was too high, so apply some
+ * pressure to decrease it. First, make room for the largest possible
+ * image and fail if that doesn't work. Next, try to decrease the size
+ * of the image as much as indicated by 'size' using allocations from
+ * highmem and non-highmem zones separately.
+ */
+ pages_highmem = preallocate_image_highmem(highmem / 2);
+ alloc = (count - max_size) - pages_highmem;
+ pages = preallocate_image_memory(alloc);
+ if (pages < alloc)
+ goto err_out;
+ size = max_size - size;
+ alloc = size;
+ size = preallocate_highmem_fraction(size, highmem, count);
+ pages_highmem += size;
+ alloc -= size;
+ pages += preallocate_image_memory(alloc);
+ pages += pages_highmem;
+
+ /*
+ * We only need as many page frames for the image as there are saveable
+ * pages in memory, but we have allocated more. Release the excessive
+ * ones now.
+ */
+ free_unnecessary_pages();
+
+ out:
do_gettimeofday(&stop);
- printk("\bdone (%lu pages freed)\n", pages);
- swsusp_show_speed(&start, &stop, pages, "Freed");
+ printk(KERN_CONT "done (allocated %lu pages)\n", pages);
+ swsusp_show_speed(&start, &stop, pages, "Allocated");
return 0;
+
+ err_out:
+ printk(KERN_CONT "\n");
+ swsusp_free();
+ return -ENOMEM;
}
#ifdef CONFIG_HIGHMEM
@@ -1142,7 +1373,7 @@ int swsusp_shrink_memory(void)
static unsigned int count_pages_for_highmem(unsigned int nr_highmem)
{
- unsigned int free_highmem = count_free_highmem_pages();
+ unsigned int free_highmem = count_free_highmem_pages() + alloc_highmem;
if (free_highmem >= nr_highmem)
nr_highmem = 0;
@@ -1164,19 +1395,17 @@ count_pages_for_highmem(unsigned int nr_highmem) { return 0; }
static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
{
struct zone *zone;
- unsigned int free = 0, meta = 0;
+ unsigned int free = alloc_normal;
- for_each_zone(zone) {
- meta += snapshot_additional_pages(zone);
+ for_each_populated_zone(zone)
if (!is_highmem(zone))
free += zone_page_state(zone, NR_FREE_PAGES);
- }
nr_pages += count_pages_for_highmem(nr_highmem);
- pr_debug("PM: Normal pages needed: %u + %u + %u, available pages: %u\n",
- nr_pages, PAGES_FOR_IO, meta, free);
+ pr_debug("PM: Normal pages needed: %u + %u, available pages: %u\n",
+ nr_pages, PAGES_FOR_IO, free);
- return free > nr_pages + PAGES_FOR_IO + meta;
+ return free > nr_pages + PAGES_FOR_IO;
}
#ifdef CONFIG_HIGHMEM
@@ -1198,7 +1427,7 @@ static inline int get_highmem_buffer(int safe_needed)
*/
static inline unsigned int
-alloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int nr_highmem)
+alloc_highmem_pages(struct memory_bitmap *bm, unsigned int nr_highmem)
{
unsigned int to_alloc = count_free_highmem_pages();
@@ -1218,7 +1447,7 @@ alloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int nr_highmem)
static inline int get_highmem_buffer(int safe_needed) { return 0; }
static inline unsigned int
-alloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int n) { return 0; }
+alloc_highmem_pages(struct memory_bitmap *bm, unsigned int n) { return 0; }
#endif /* CONFIG_HIGHMEM */
/**
@@ -1237,51 +1466,36 @@ static int
swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
unsigned int nr_pages, unsigned int nr_highmem)
{
- int error;
-
- error = memory_bm_create(orig_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);
- if (error)
- goto Free;
-
- error = memory_bm_create(copy_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);
- if (error)
- goto Free;
+ int error = 0;
if (nr_highmem > 0) {
error = get_highmem_buffer(PG_ANY);
if (error)
- goto Free;
-
- nr_pages += alloc_highmem_image_pages(copy_bm, nr_highmem);
+ goto err_out;
+ if (nr_highmem > alloc_highmem) {
+ nr_highmem -= alloc_highmem;
+ nr_pages += alloc_highmem_pages(copy_bm, nr_highmem);
+ }
}
- while (nr_pages-- > 0) {
- struct page *page = alloc_image_page(GFP_ATOMIC | __GFP_COLD);
-
- if (!page)
- goto Free;
+ if (nr_pages > alloc_normal) {
+ nr_pages -= alloc_normal;
+ while (nr_pages-- > 0) {
+ struct page *page;
- memory_bm_set_bit(copy_bm, page_to_pfn(page));
+ page = alloc_image_page(GFP_ATOMIC | __GFP_COLD);
+ if (!page)
+ goto err_out;
+ memory_bm_set_bit(copy_bm, page_to_pfn(page));
+ }
}
+
return 0;
- Free:
+ err_out:
swsusp_free();
- return -ENOMEM;
+ return error;
}
-/* Memory bitmap used for marking saveable pages (during suspend) or the
- * suspend image pages (during resume)
- */
-static struct memory_bitmap orig_bm;
-/* Memory bitmap used on suspend for marking allocated pages that will contain
- * the copies of saveable pages. During resume it is initially used for
- * marking the suspend image pages, but then its set bits are duplicated in
- * @orig_bm and it is released. Next, on systems with high memory, it may be
- * used for marking "safe" highmem pages, but it has to be reinitialized for
- * this purpose.
- */
-static struct memory_bitmap copy_bm;
-
asmlinkage int swsusp_save(void)
{
unsigned int nr_pages, nr_highmem;
@@ -1474,7 +1688,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
unsigned long pfn, max_zone_pfn;
/* Clear page flags */
- for_each_zone(zone) {
+ for_each_populated_zone(zone) {
max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn))
diff --git a/kernel/printk.c b/kernel/printk.c
index b4d97b54c1ec..41fe60995530 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -37,6 +37,12 @@
#include <asm/uaccess.h>
/*
+ * for_each_console() allows you to iterate on each console
+ */
+#define for_each_console(con) \
+ for (con = console_drivers; con != NULL; con = con->next)
+
+/*
* Architectures can override it:
*/
void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
@@ -412,7 +418,7 @@ static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con;
- for (con = console_drivers; con; con = con->next) {
+ for_each_console(con) {
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
@@ -544,7 +550,7 @@ static int have_callable_console(void)
{
struct console *con;
- for (con = console_drivers; con; con = con->next)
+ for_each_console(con)
if (con->flags & CON_ANYTIME)
return 1;
@@ -1082,7 +1088,7 @@ void console_unblank(void)
console_locked = 1;
console_may_schedule = 0;
- for (c = console_drivers; c != NULL; c = c->next)
+ for_each_console(c)
if ((c->flags & CON_ENABLED) && c->unblank)
c->unblank();
release_console_sem();
@@ -1097,7 +1103,7 @@ struct tty_driver *console_device(int *index)
struct tty_driver *driver = NULL;
acquire_console_sem();
- for (c = console_drivers; c != NULL; c = c->next) {
+ for_each_console(c) {
if (!c->device)
continue;
driver = c->device(c, index);
@@ -1134,25 +1140,49 @@ EXPORT_SYMBOL(console_start);
* to register the console printing procedure with printk() and to
* print any messages that were printed by the kernel before the
* console driver was initialized.
+ *
+ * This can happen pretty early during the boot process (because of
+ * early_printk) - sometimes before setup_arch() completes - be careful
+ * of what kernel features are used - they may not be initialised yet.
+ *
+ * There are two types of consoles - bootconsoles (early_printk) and
+ * "real" consoles (everything which is not a bootconsole) which are
+ * handled differently.
+ * - Any number of bootconsoles can be registered at any time.
+ * - As soon as a "real" console is registered, all bootconsoles
+ * will be unregistered automatically.
+ * - Once a "real" console is registered, any attempt to register a
+ * bootconsoles will be rejected
*/
-void register_console(struct console *console)
+void register_console(struct console *newcon)
{
int i;
unsigned long flags;
- struct console *bootconsole = NULL;
+ struct console *bcon = NULL;
- if (console_drivers) {
- if (console->flags & CON_BOOT)
- return;
- if (console_drivers->flags & CON_BOOT)
- bootconsole = console_drivers;
+ /*
+ * before we register a new CON_BOOT console, make sure we don't
+ * already have a valid console
+ */
+ if (console_drivers && newcon->flags & CON_BOOT) {
+ /* find the last or real console */
+ for_each_console(bcon) {
+ if (!(bcon->flags & CON_BOOT)) {
+ printk(KERN_INFO "Too late to register bootconsole %s%d\n",
+ newcon->name, newcon->index);
+ return;
+ }
+ }
}
- if (preferred_console < 0 || bootconsole || !console_drivers)
+ if (console_drivers && console_drivers->flags & CON_BOOT)
+ bcon = console_drivers;
+
+ if (preferred_console < 0 || bcon || !console_drivers)
preferred_console = selected_console;
- if (console->early_setup)
- console->early_setup();
+ if (newcon->early_setup)
+ newcon->early_setup();
/*
* See if we want to use this console driver. If we
@@ -1160,13 +1190,13 @@ void register_console(struct console *console)
* that registers here.
*/
if (preferred_console < 0) {
- if (console->index < 0)
- console->index = 0;
- if (console->setup == NULL ||
- console->setup(console, NULL) == 0) {
- console->flags |= CON_ENABLED;
- if (console->device) {
- console->flags |= CON_CONSDEV;
+ if (newcon->index < 0)
+ newcon->index = 0;
+ if (newcon->setup == NULL ||
+ newcon->setup(newcon, NULL) == 0) {
+ newcon->flags |= CON_ENABLED;
+ if (newcon->device) {
+ newcon->flags |= CON_CONSDEV;
preferred_console = 0;
}
}
@@ -1178,47 +1208,53 @@ void register_console(struct console *console)
*/
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) {
- if (strcmp(console_cmdline[i].name, console->name) != 0)
+ if (strcmp(console_cmdline[i].name, newcon->name) != 0)
continue;
- if (console->index >= 0 &&
- console->index != console_cmdline[i].index)
+ if (newcon->index >= 0 &&
+ newcon->index != console_cmdline[i].index)
continue;
- if (console->index < 0)
- console->index = console_cmdline[i].index;
+ if (newcon->index < 0)
+ newcon->index = console_cmdline[i].index;
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
if (console_cmdline[i].brl_options) {
- console->flags |= CON_BRL;
- braille_register_console(console,
+ newcon->flags |= CON_BRL;
+ braille_register_console(newcon,
console_cmdline[i].index,
console_cmdline[i].options,
console_cmdline[i].brl_options);
return;
}
#endif
- if (console->setup &&
- console->setup(console, console_cmdline[i].options) != 0)
+ if (newcon->setup &&
+ newcon->setup(newcon, console_cmdline[i].options) != 0)
break;
- console->flags |= CON_ENABLED;
- console->index = console_cmdline[i].index;
+ newcon->flags |= CON_ENABLED;
+ newcon->index = console_cmdline[i].index;
if (i == selected_console) {
- console->flags |= CON_CONSDEV;
+ newcon->flags |= CON_CONSDEV;
preferred_console = selected_console;
}
break;
}
- if (!(console->flags & CON_ENABLED))
+ if (!(newcon->flags & CON_ENABLED))
return;
- if (bootconsole && (console->flags & CON_CONSDEV)) {
- printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n",
- bootconsole->name, bootconsole->index,
- console->name, console->index);
- unregister_console(bootconsole);
- console->flags &= ~CON_PRINTBUFFER;
+ if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
+ /* we need to iterate through twice, to make sure we print
+ * everything out, before we unregister the console(s)
+ */
+ printk(KERN_INFO "console handover:");
+ for_each_console(bcon)
+ printk("boot [%s%d] ", bcon->name, bcon->index);
+ printk(" -> real [%s%d]\n", newcon->name, newcon->index);
+ for_each_console(bcon)
+ unregister_console(bcon);
+ newcon->flags &= ~CON_PRINTBUFFER;
} else {
- printk(KERN_INFO "console [%s%d] enabled\n",
- console->name, console->index);
+ printk(KERN_INFO "%sconsole [%s%d] enabled\n",
+ (newcon->flags & CON_BOOT) ? "boot" : "" ,
+ newcon->name, newcon->index);
}
/*
@@ -1226,16 +1262,16 @@ void register_console(struct console *console)
* preferred driver at the head of the list.
*/
acquire_console_sem();
- if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
- console->next = console_drivers;
- console_drivers = console;
- if (console->next)
- console->next->flags &= ~CON_CONSDEV;
+ if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
+ newcon->next = console_drivers;
+ console_drivers = newcon;
+ if (newcon->next)
+ newcon->next->flags &= ~CON_CONSDEV;
} else {
- console->next = console_drivers->next;
- console_drivers->next = console;
+ newcon->next = console_drivers->next;
+ console_drivers->next = newcon;
}
- if (console->flags & CON_PRINTBUFFER) {
+ if (newcon->flags & CON_PRINTBUFFER) {
/*
* release_console_sem() will print out the buffered messages
* for us.
@@ -1287,11 +1323,13 @@ EXPORT_SYMBOL(unregister_console);
static int __init disable_boot_consoles(void)
{
- if (console_drivers != NULL) {
- if (console_drivers->flags & CON_BOOT) {
+ struct console *con;
+
+ for_each_console(con) {
+ if (con->flags & CON_BOOT) {
printk(KERN_INFO "turn off boot console %s%d\n",
- console_drivers->name, console_drivers->index);
- return unregister_console(console_drivers);
+ con->name, con->index);
+ return unregister_console(con);
}
}
return 0;
diff --git a/kernel/profile.c b/kernel/profile.c
index 69911b5745eb..419250ebec4d 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -117,11 +117,12 @@ int __ref profile_init(void)
cpumask_copy(prof_cpu_mask, cpu_possible_mask);
- prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL);
+ prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL|__GFP_NOWARN);
if (prof_buffer)
return 0;
- prof_buffer = alloc_pages_exact(buffer_bytes, GFP_KERNEL|__GFP_ZERO);
+ prof_buffer = alloc_pages_exact(buffer_bytes,
+ GFP_KERNEL|__GFP_ZERO|__GFP_NOWARN);
if (prof_buffer)
return 0;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 082c320e4dbf..307c285af59e 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -152,7 +152,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
- return security_ptrace_may_access(task, mode);
+ return security_ptrace_access_check(task, mode);
}
bool ptrace_may_access(struct task_struct *task, unsigned int mode)
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c
deleted file mode 100644
index 0f2b0b311304..000000000000
--- a/kernel/rcuclassic.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Read-Copy Update mechanism for mutual exclusion
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright IBM Corporation, 2001
- *
- * Authors: Dipankar Sarma <dipankar@in.ibm.com>
- * Manfred Spraul <manfred@colorfullife.com>
- *
- * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
- * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
- * Papers:
- * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
- * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
- *
- * For detailed explanation of Read-Copy Update mechanism see -
- * Documentation/RCU
- *
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp.h>
-#include <linux/rcupdate.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <asm/atomic.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/completion.h>
-#include <linux/moduleparam.h>
-#include <linux/percpu.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/mutex.h>
-#include <linux/time.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
-
-
-/* Definition for rcupdate control block. */
-static struct rcu_ctrlblk rcu_ctrlblk = {
- .cur = -300,
- .completed = -300,
- .pending = -300,
- .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
- .cpumask = CPU_BITS_NONE,
-};
-
-static struct rcu_ctrlblk rcu_bh_ctrlblk = {
- .cur = -300,
- .completed = -300,
- .pending = -300,
- .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
- .cpumask = CPU_BITS_NONE,
-};
-
-static DEFINE_PER_CPU(struct rcu_data, rcu_data);
-static DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
-
-/*
- * Increment the quiescent state counter.
- * The counter is a bit degenerated: We do not need to know
- * how many quiescent states passed, just if there was at least
- * one since the start of the grace period. Thus just a flag.
- */
-void rcu_qsctr_inc(int cpu)
-{
- struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
- rdp->passed_quiesc = 1;
-}
-
-void rcu_bh_qsctr_inc(int cpu)
-{
- struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
- rdp->passed_quiesc = 1;
-}
-
-static int blimit = 10;
-static int qhimark = 10000;
-static int qlowmark = 100;
-
-#ifdef CONFIG_SMP
-static void force_quiescent_state(struct rcu_data *rdp,
- struct rcu_ctrlblk *rcp)
-{
- int cpu;
- unsigned long flags;
-
- set_need_resched();
- spin_lock_irqsave(&rcp->lock, flags);
- if (unlikely(!rcp->signaled)) {
- rcp->signaled = 1;
- /*
- * Don't send IPI to itself. With irqs disabled,
- * rdp->cpu is the current cpu.
- *
- * cpu_online_mask is updated by the _cpu_down()
- * using __stop_machine(). Since we're in irqs disabled
- * section, __stop_machine() is not exectuting, hence
- * the cpu_online_mask is stable.
- *
- * However, a cpu might have been offlined _just_ before
- * we disabled irqs while entering here.
- * And rcu subsystem might not yet have handled the CPU_DEAD
- * notification, leading to the offlined cpu's bit
- * being set in the rcp->cpumask.
- *
- * Hence cpumask = (rcp->cpumask & cpu_online_mask) to prevent
- * sending smp_reschedule() to an offlined CPU.
- */
- for_each_cpu_and(cpu,
- to_cpumask(rcp->cpumask), cpu_online_mask) {
- if (cpu != rdp->cpu)
- smp_send_reschedule(cpu);
- }
- }
- spin_unlock_irqrestore(&rcp->lock, flags);
-}
-#else
-static inline void force_quiescent_state(struct rcu_data *rdp,
- struct rcu_ctrlblk *rcp)
-{
- set_need_resched();
-}
-#endif
-
-static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp,
- struct rcu_data *rdp)
-{
- long batch;
-
- head->next = NULL;
- smp_mb(); /* Read of rcu->cur must happen after any change by caller. */
-
- /*
- * Determine the batch number of this callback.
- *
- * Using ACCESS_ONCE to avoid the following error when gcc eliminates
- * local variable "batch" and emits codes like this:
- * 1) rdp->batch = rcp->cur + 1 # gets old value
- * ......
- * 2)rcu_batch_after(rcp->cur + 1, rdp->batch) # gets new value
- * then [*nxttail[0], *nxttail[1]) may contain callbacks
- * that batch# = rdp->batch, see the comment of struct rcu_data.
- */
- batch = ACCESS_ONCE(rcp->cur) + 1;
-
- if (rdp->nxtlist && rcu_batch_after(batch, rdp->batch)) {
- /* process callbacks */
- rdp->nxttail[0] = rdp->nxttail[1];
- rdp->nxttail[1] = rdp->nxttail[2];
- if (rcu_batch_after(batch - 1, rdp->batch))
- rdp->nxttail[0] = rdp->nxttail[2];
- }
-
- rdp->batch = batch;
- *rdp->nxttail[2] = head;
- rdp->nxttail[2] = &head->next;
-
- if (unlikely(++rdp->qlen > qhimark)) {
- rdp->blimit = INT_MAX;
- force_quiescent_state(rdp, &rcu_ctrlblk);
- }
-}
-
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-
-static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
-{
- rcp->gp_start = jiffies;
- rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK;
-}
-
-static void print_other_cpu_stall(struct rcu_ctrlblk *rcp)
-{
- int cpu;
- long delta;
- unsigned long flags;
-
- /* Only let one CPU complain about others per time interval. */
-
- spin_lock_irqsave(&rcp->lock, flags);
- delta = jiffies - rcp->jiffies_stall;
- if (delta < 2 || rcp->cur != rcp->completed) {
- spin_unlock_irqrestore(&rcp->lock, flags);
- return;
- }
- rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
- spin_unlock_irqrestore(&rcp->lock, flags);
-
- /* OK, time to rat on our buddy... */
-
- printk(KERN_ERR "INFO: RCU detected CPU stalls:");
- for_each_possible_cpu(cpu) {
- if (cpumask_test_cpu(cpu, to_cpumask(rcp->cpumask)))
- printk(" %d", cpu);
- }
- printk(" (detected by %d, t=%ld jiffies)\n",
- smp_processor_id(), (long)(jiffies - rcp->gp_start));
-}
-
-static void print_cpu_stall(struct rcu_ctrlblk *rcp)
-{
- unsigned long flags;
-
- printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu/%lu jiffies)\n",
- smp_processor_id(), jiffies,
- jiffies - rcp->gp_start);
- dump_stack();
- spin_lock_irqsave(&rcp->lock, flags);
- if ((long)(jiffies - rcp->jiffies_stall) >= 0)
- rcp->jiffies_stall =
- jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
- spin_unlock_irqrestore(&rcp->lock, flags);
- set_need_resched(); /* kick ourselves to get things going. */
-}
-
-static void check_cpu_stall(struct rcu_ctrlblk *rcp)
-{
- long delta;
-
- delta = jiffies - rcp->jiffies_stall;
- if (cpumask_test_cpu(smp_processor_id(), to_cpumask(rcp->cpumask)) &&
- delta >= 0) {
-
- /* We haven't checked in, so go dump stack. */
- print_cpu_stall(rcp);
-
- } else if (rcp->cur != rcp->completed && delta >= 2) {
-
- /* They had two seconds to dump stack, so complain. */
- print_other_cpu_stall(rcp);
- }
-}
-
-#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
-static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
-{
-}
-
-static inline void check_cpu_stall(struct rcu_ctrlblk *rcp)
-{
-}
-
-#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
-
-/**
- * call_rcu - Queue an RCU callback for invocation after a grace period.
- * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
- *
- * The update function will be invoked some time after a full grace
- * period elapses, in other words after all currently executing RCU
- * read-side critical sections have completed. RCU read-side critical
- * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
- * and may be nested.
- */
-void call_rcu(struct rcu_head *head,
- void (*func)(struct rcu_head *rcu))
-{
- unsigned long flags;
-
- head->func = func;
- local_irq_save(flags);
- __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data));
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(call_rcu);
-
-/**
- * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
- * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
- *
- * The update function will be invoked some time after a full grace
- * period elapses, in other words after all currently executing RCU
- * read-side critical sections have completed. call_rcu_bh() assumes
- * that the read-side critical sections end on completion of a softirq
- * handler. This means that read-side critical sections in process
- * context must not be interrupted by softirqs. This interface is to be
- * used when most of the read-side critical sections are in softirq context.
- * RCU read-side critical sections are delimited by rcu_read_lock() and
- * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh()
- * and rcu_read_unlock_bh(), if in process context. These may be nested.
- */
-void call_rcu_bh(struct rcu_head *head,
- void (*func)(struct rcu_head *rcu))
-{
- unsigned long flags;
-
- head->func = func;
- local_irq_save(flags);
- __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(call_rcu_bh);
-
-/*
- * Return the number of RCU batches processed thus far. Useful
- * for debug and statistics.
- */
-long rcu_batches_completed(void)
-{
- return rcu_ctrlblk.completed;
-}
-EXPORT_SYMBOL_GPL(rcu_batches_completed);
-
-/*
- * Return the number of RCU batches processed thus far. Useful
- * for debug and statistics.
- */
-long rcu_batches_completed_bh(void)
-{
- return rcu_bh_ctrlblk.completed;
-}
-EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
-
-/* Raises the softirq for processing rcu_callbacks. */
-static inline void raise_rcu_softirq(void)
-{
- raise_softirq(RCU_SOFTIRQ);
-}
-
-/*
- * Invoke the completed RCU callbacks. They are expected to be in
- * a per-cpu list.
- */
-static void rcu_do_batch(struct rcu_data *rdp)
-{
- unsigned long flags;
- struct rcu_head *next, *list;
- int count = 0;
-
- list = rdp->donelist;
- while (list) {
- next = list->next;
- prefetch(next);
- list->func(list);
- list = next;
- if (++count >= rdp->blimit)
- break;
- }
- rdp->donelist = list;
-
- local_irq_save(flags);
- rdp->qlen -= count;
- local_irq_restore(flags);
- if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
- rdp->blimit = blimit;
-
- if (!rdp->donelist)
- rdp->donetail = &rdp->donelist;
- else
- raise_rcu_softirq();
-}
-
-/*
- * Grace period handling:
- * The grace period handling consists out of two steps:
- * - A new grace period is started.
- * This is done by rcu_start_batch. The start is not broadcasted to
- * all cpus, they must pick this up by comparing rcp->cur with
- * rdp->quiescbatch. All cpus are recorded in the
- * rcu_ctrlblk.cpumask bitmap.
- * - All cpus must go through a quiescent state.
- * Since the start of the grace period is not broadcasted, at least two
- * calls to rcu_check_quiescent_state are required:
- * The first call just notices that a new grace period is running. The
- * following calls check if there was a quiescent state since the beginning
- * of the grace period. If so, it updates rcu_ctrlblk.cpumask. If
- * the bitmap is empty, then the grace period is completed.
- * rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
- * period (if necessary).
- */
-
-/*
- * Register a new batch of callbacks, and start it up if there is currently no
- * active batch and the batch to be registered has not already occurred.
- * Caller must hold rcu_ctrlblk.lock.
- */
-static void rcu_start_batch(struct rcu_ctrlblk *rcp)
-{
- if (rcp->cur != rcp->pending &&
- rcp->completed == rcp->cur) {
- rcp->cur++;
- record_gp_stall_check_time(rcp);
-
- /*
- * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
- * Barrier Otherwise it can cause tickless idle CPUs to be
- * included in rcp->cpumask, which will extend graceperiods
- * unnecessarily.
- */
- smp_mb();
- cpumask_andnot(to_cpumask(rcp->cpumask),
- cpu_online_mask, nohz_cpu_mask);
-
- rcp->signaled = 0;
- }
-}
-
-/*
- * cpu went through a quiescent state since the beginning of the grace period.
- * Clear it from the cpu mask and complete the grace period if it was the last
- * cpu. Start another grace period if someone has further entries pending
- */
-static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp)
-{
- cpumask_clear_cpu(cpu, to_cpumask(rcp->cpumask));
- if (cpumask_empty(to_cpumask(rcp->cpumask))) {
- /* batch completed ! */
- rcp->completed = rcp->cur;
- rcu_start_batch(rcp);
- }
-}
-
-/*
- * Check if the cpu has gone through a quiescent state (say context
- * switch). If so and if it already hasn't done so in this RCU
- * quiescent cycle, then indicate that it has done so.
- */
-static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
- struct rcu_data *rdp)
-{
- unsigned long flags;
-
- if (rdp->quiescbatch != rcp->cur) {
- /* start new grace period: */
- rdp->qs_pending = 1;
- rdp->passed_quiesc = 0;
- rdp->quiescbatch = rcp->cur;
- return;
- }
-
- /* Grace period already completed for this cpu?
- * qs_pending is checked instead of the actual bitmap to avoid
- * cacheline trashing.
- */
- if (!rdp->qs_pending)
- return;
-
- /*
- * Was there a quiescent state since the beginning of the grace
- * period? If no, then exit and wait for the next call.
- */
- if (!rdp->passed_quiesc)
- return;
- rdp->qs_pending = 0;
-
- spin_lock_irqsave(&rcp->lock, flags);
- /*
- * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync
- * during cpu startup. Ignore the quiescent state.
- */
- if (likely(rdp->quiescbatch == rcp->cur))
- cpu_quiet(rdp->cpu, rcp);
-
- spin_unlock_irqrestore(&rcp->lock, flags);
-}
-
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
- * locking requirements, the list it's pulling from has to belong to a cpu
- * which is dead and hence not processing interrupts.
- */
-static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
- struct rcu_head **tail, long batch)
-{
- unsigned long flags;
-
- if (list) {
- local_irq_save(flags);
- this_rdp->batch = batch;
- *this_rdp->nxttail[2] = list;
- this_rdp->nxttail[2] = tail;
- local_irq_restore(flags);
- }
-}
-
-static void __rcu_offline_cpu(struct rcu_data *this_rdp,
- struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
-{
- unsigned long flags;
-
- /*
- * if the cpu going offline owns the grace period
- * we can block indefinitely waiting for it, so flush
- * it here
- */
- spin_lock_irqsave(&rcp->lock, flags);
- if (rcp->cur != rcp->completed)
- cpu_quiet(rdp->cpu, rcp);
- rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1);
- rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1);
- spin_unlock(&rcp->lock);
-
- this_rdp->qlen += rdp->qlen;
- local_irq_restore(flags);
-}
-
-static void rcu_offline_cpu(int cpu)
-{
- struct rcu_data *this_rdp = &get_cpu_var(rcu_data);
- struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data);
-
- __rcu_offline_cpu(this_rdp, &rcu_ctrlblk,
- &per_cpu(rcu_data, cpu));
- __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk,
- &per_cpu(rcu_bh_data, cpu));
- put_cpu_var(rcu_data);
- put_cpu_var(rcu_bh_data);
-}
-
-#else
-
-static void rcu_offline_cpu(int cpu)
-{
-}
-
-#endif
-
-/*
- * This does the RCU processing work from softirq context.
- */
-static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
- struct rcu_data *rdp)
-{
- unsigned long flags;
- long completed_snap;
-
- if (rdp->nxtlist) {
- local_irq_save(flags);
- completed_snap = ACCESS_ONCE(rcp->completed);
-
- /*
- * move the other grace-period-completed entries to
- * [rdp->nxtlist, *rdp->nxttail[0]) temporarily
- */
- if (!rcu_batch_before(completed_snap, rdp->batch))
- rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2];
- else if (!rcu_batch_before(completed_snap, rdp->batch - 1))
- rdp->nxttail[0] = rdp->nxttail[1];
-
- /*
- * the grace period for entries in
- * [rdp->nxtlist, *rdp->nxttail[0]) has completed and
- * move these entries to donelist
- */
- if (rdp->nxttail[0] != &rdp->nxtlist) {
- *rdp->donetail = rdp->nxtlist;
- rdp->donetail = rdp->nxttail[0];
- rdp->nxtlist = *rdp->nxttail[0];
- *rdp->donetail = NULL;
-
- if (rdp->nxttail[1] == rdp->nxttail[0])
- rdp->nxttail[1] = &rdp->nxtlist;
- if (rdp->nxttail[2] == rdp->nxttail[0])
- rdp->nxttail[2] = &rdp->nxtlist;
- rdp->nxttail[0] = &rdp->nxtlist;
- }
-
- local_irq_restore(flags);
-
- if (rcu_batch_after(rdp->batch, rcp->pending)) {
- unsigned long flags2;
-
- /* and start it/schedule start if it's a new batch */
- spin_lock_irqsave(&rcp->lock, flags2);
- if (rcu_batch_after(rdp->batch, rcp->pending)) {
- rcp->pending = rdp->batch;
- rcu_start_batch(rcp);
- }
- spin_unlock_irqrestore(&rcp->lock, flags2);
- }
- }
-
- rcu_check_quiescent_state(rcp, rdp);
- if (rdp->donelist)
- rcu_do_batch(rdp);
-}
-
-static void rcu_process_callbacks(struct softirq_action *unused)
-{
- /*
- * Memory references from any prior RCU read-side critical sections
- * executed by the interrupted code must be see before any RCU
- * grace-period manupulations below.
- */
-
- smp_mb(); /* See above block comment. */
-
- __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
- __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
-
- /*
- * Memory references from any later RCU read-side critical sections
- * executed by the interrupted code must be see after any RCU
- * grace-period manupulations above.
- */
-
- smp_mb(); /* See above block comment. */
-}
-
-static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
-{
- /* Check for CPU stalls, if enabled. */
- check_cpu_stall(rcp);
-
- if (rdp->nxtlist) {
- long completed_snap = ACCESS_ONCE(rcp->completed);
-
- /*
- * This cpu has pending rcu entries and the grace period
- * for them has completed.
- */
- if (!rcu_batch_before(completed_snap, rdp->batch))
- return 1;
- if (!rcu_batch_before(completed_snap, rdp->batch - 1) &&
- rdp->nxttail[0] != rdp->nxttail[1])
- return 1;
- if (rdp->nxttail[0] != &rdp->nxtlist)
- return 1;
-
- /*
- * This cpu has pending rcu entries and the new batch
- * for then hasn't been started nor scheduled start
- */
- if (rcu_batch_after(rdp->batch, rcp->pending))
- return 1;
- }
-
- /* This cpu has finished callbacks to invoke */
- if (rdp->donelist)
- return 1;
-
- /* The rcu core waits for a quiescent state from the cpu */
- if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
- return 1;
-
- /* nothing to do */
- return 0;
-}
-
-/*
- * Check to see if there is any immediate RCU-related work to be done
- * by the current CPU, returning 1 if so. This function is part of the
- * RCU implementation; it is -not- an exported member of the RCU API.
- */
-int rcu_pending(int cpu)
-{
- return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
- __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
-}
-
-/*
- * Check to see if any future RCU-related work will need to be done
- * by the current CPU, even if none need be done immediately, returning
- * 1 if so. This function is part of the RCU implementation; it is -not-
- * an exported member of the RCU API.
- */
-int rcu_needs_cpu(int cpu)
-{
- struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
- struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
-
- return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu);
-}
-
-/*
- * Top-level function driving RCU grace-period detection, normally
- * invoked from the scheduler-clock interrupt. This function simply
- * increments counters that are read only from softirq by this same
- * CPU, so there are no memory barriers required.
- */
-void rcu_check_callbacks(int cpu, int user)
-{
- if (user ||
- (idle_cpu(cpu) && rcu_scheduler_active &&
- !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
-
- /*
- * Get here if this CPU took its interrupt from user
- * mode or from the idle loop, and if this is not a
- * nested interrupt. In this case, the CPU is in
- * a quiescent state, so count it.
- *
- * Also do a memory barrier. This is needed to handle
- * the case where writes from a preempt-disable section
- * of code get reordered into schedule() by this CPU's
- * write buffer. The memory barrier makes sure that
- * the rcu_qsctr_inc() and rcu_bh_qsctr_inc() are see
- * by other CPUs to happen after any such write.
- */
-
- smp_mb(); /* See above block comment. */
- rcu_qsctr_inc(cpu);
- rcu_bh_qsctr_inc(cpu);
-
- } else if (!in_softirq()) {
-
- /*
- * Get here if this CPU did not take its interrupt from
- * softirq, in other words, if it is not interrupting
- * a rcu_bh read-side critical section. This is an _bh
- * critical section, so count it. The memory barrier
- * is needed for the same reason as is the above one.
- */
-
- smp_mb(); /* See above block comment. */
- rcu_bh_qsctr_inc(cpu);
- }
- raise_rcu_softirq();
-}
-
-static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
- struct rcu_data *rdp)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&rcp->lock, flags);
- memset(rdp, 0, sizeof(*rdp));
- rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist;
- rdp->donetail = &rdp->donelist;
- rdp->quiescbatch = rcp->completed;
- rdp->qs_pending = 0;
- rdp->cpu = cpu;
- rdp->blimit = blimit;
- spin_unlock_irqrestore(&rcp->lock, flags);
-}
-
-static void __cpuinit rcu_online_cpu(int cpu)
-{
- struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
- struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu);
-
- rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
- rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp);
- open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
-}
-
-static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- long cpu = (long)hcpu;
-
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- rcu_online_cpu(cpu);
- break;
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- rcu_offline_cpu(cpu);
- break;
- default:
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata rcu_nb = {
- .notifier_call = rcu_cpu_notify,
-};
-
-/*
- * Initializes rcu mechanism. Assumed to be called early.
- * That is before local timer(SMP) or jiffie timer (uniproc) is setup.
- * Note that rcu_qsctr and friends are implicitly
- * initialized due to the choice of ``0'' for RCU_CTR_INVALID.
- */
-void __init __rcu_init(void)
-{
-#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
- printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
- rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
- (void *)(long)smp_processor_id());
- /* Register notifier for non-boot CPUs */
- register_cpu_notifier(&rcu_nb);
-}
-
-module_param(blimit, int, 0);
-module_param(qhimark, int, 0);
-module_param(qlowmark, int, 0);
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index a967c9feb90a..eae29c25fb14 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -98,6 +98,30 @@ void synchronize_rcu(void)
}
EXPORT_SYMBOL_GPL(synchronize_rcu);
+/**
+ * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed.
+ *
+ * Control will return to the caller some time after a full rcu_bh grace
+ * period has elapsed, in other words after all currently executing rcu_bh
+ * read-side critical sections have completed. RCU read-side critical
+ * sections are delimited by rcu_read_lock_bh() and rcu_read_unlock_bh(),
+ * and may be nested.
+ */
+void synchronize_rcu_bh(void)
+{
+ struct rcu_synchronize rcu;
+
+ if (rcu_blocking_is_gp())
+ return;
+
+ init_completion(&rcu.completion);
+ /* Will wake me after RCU finished. */
+ call_rcu_bh(&rcu.head, wakeme_after_rcu);
+ /* Wait for it. */
+ wait_for_completion(&rcu.completion);
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
+
static void rcu_barrier_callback(struct rcu_head *notused)
{
if (atomic_dec_and_test(&rcu_barrier_cpu_count))
@@ -129,6 +153,7 @@ static void rcu_barrier_func(void *type)
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. */
}
/*
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 9b4a975a4b4a..b33db539a8ad 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -257,14 +257,14 @@ struct rcu_torture_ops {
void (*init)(void);
void (*cleanup)(void);
int (*readlock)(void);
- void (*readdelay)(struct rcu_random_state *rrsp);
+ void (*read_delay)(struct rcu_random_state *rrsp);
void (*readunlock)(int idx);
int (*completed)(void);
- void (*deferredfree)(struct rcu_torture *p);
+ void (*deferred_free)(struct rcu_torture *p);
void (*sync)(void);
void (*cb_barrier)(void);
int (*stats)(char *page);
- int irqcapable;
+ int irq_capable;
char *name;
};
static struct rcu_torture_ops *cur_ops = NULL;
@@ -320,7 +320,7 @@ rcu_torture_cb(struct rcu_head *p)
rp->rtort_mbtest = 0;
rcu_torture_free(rp);
} else
- cur_ops->deferredfree(rp);
+ cur_ops->deferred_free(rp);
}
static void rcu_torture_deferred_free(struct rcu_torture *p)
@@ -329,18 +329,18 @@ static void rcu_torture_deferred_free(struct rcu_torture *p)
}
static struct rcu_torture_ops rcu_ops = {
- .init = NULL,
- .cleanup = NULL,
- .readlock = rcu_torture_read_lock,
- .readdelay = rcu_read_delay,
- .readunlock = rcu_torture_read_unlock,
- .completed = rcu_torture_completed,
- .deferredfree = rcu_torture_deferred_free,
- .sync = synchronize_rcu,
- .cb_barrier = rcu_barrier,
- .stats = NULL,
- .irqcapable = 1,
- .name = "rcu"
+ .init = NULL,
+ .cleanup = NULL,
+ .readlock = rcu_torture_read_lock,
+ .read_delay = rcu_read_delay,
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_torture_completed,
+ .deferred_free = rcu_torture_deferred_free,
+ .sync = synchronize_rcu,
+ .cb_barrier = rcu_barrier,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "rcu"
};
static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
@@ -370,18 +370,18 @@ static void rcu_sync_torture_init(void)
}
static struct rcu_torture_ops rcu_sync_ops = {
- .init = rcu_sync_torture_init,
- .cleanup = NULL,
- .readlock = rcu_torture_read_lock,
- .readdelay = rcu_read_delay,
- .readunlock = rcu_torture_read_unlock,
- .completed = rcu_torture_completed,
- .deferredfree = rcu_sync_torture_deferred_free,
- .sync = synchronize_rcu,
- .cb_barrier = NULL,
- .stats = NULL,
- .irqcapable = 1,
- .name = "rcu_sync"
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_torture_read_lock,
+ .read_delay = rcu_read_delay,
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = synchronize_rcu,
+ .cb_barrier = NULL,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "rcu_sync"
};
/*
@@ -432,33 +432,33 @@ static void rcu_bh_torture_synchronize(void)
}
static struct rcu_torture_ops rcu_bh_ops = {
- .init = NULL,
- .cleanup = NULL,
- .readlock = rcu_bh_torture_read_lock,
- .readdelay = rcu_read_delay, /* just reuse rcu's version. */
- .readunlock = rcu_bh_torture_read_unlock,
- .completed = rcu_bh_torture_completed,
- .deferredfree = rcu_bh_torture_deferred_free,
- .sync = rcu_bh_torture_synchronize,
- .cb_barrier = rcu_barrier_bh,
- .stats = NULL,
- .irqcapable = 1,
- .name = "rcu_bh"
+ .init = NULL,
+ .cleanup = NULL,
+ .readlock = rcu_bh_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_bh_torture_read_unlock,
+ .completed = rcu_bh_torture_completed,
+ .deferred_free = rcu_bh_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
+ .cb_barrier = rcu_barrier_bh,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "rcu_bh"
};
static struct rcu_torture_ops rcu_bh_sync_ops = {
- .init = rcu_sync_torture_init,
- .cleanup = NULL,
- .readlock = rcu_bh_torture_read_lock,
- .readdelay = rcu_read_delay, /* just reuse rcu's version. */
- .readunlock = rcu_bh_torture_read_unlock,
- .completed = rcu_bh_torture_completed,
- .deferredfree = rcu_sync_torture_deferred_free,
- .sync = rcu_bh_torture_synchronize,
- .cb_barrier = NULL,
- .stats = NULL,
- .irqcapable = 1,
- .name = "rcu_bh_sync"
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_bh_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_bh_torture_read_unlock,
+ .completed = rcu_bh_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
+ .cb_barrier = NULL,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "rcu_bh_sync"
};
/*
@@ -530,17 +530,17 @@ static int srcu_torture_stats(char *page)
}
static struct rcu_torture_ops srcu_ops = {
- .init = srcu_torture_init,
- .cleanup = srcu_torture_cleanup,
- .readlock = srcu_torture_read_lock,
- .readdelay = srcu_read_delay,
- .readunlock = srcu_torture_read_unlock,
- .completed = srcu_torture_completed,
- .deferredfree = rcu_sync_torture_deferred_free,
- .sync = srcu_torture_synchronize,
- .cb_barrier = NULL,
- .stats = srcu_torture_stats,
- .name = "srcu"
+ .init = srcu_torture_init,
+ .cleanup = srcu_torture_cleanup,
+ .readlock = srcu_torture_read_lock,
+ .read_delay = srcu_read_delay,
+ .readunlock = srcu_torture_read_unlock,
+ .completed = srcu_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = srcu_torture_synchronize,
+ .cb_barrier = NULL,
+ .stats = srcu_torture_stats,
+ .name = "srcu"
};
/*
@@ -574,32 +574,49 @@ static void sched_torture_synchronize(void)
}
static struct rcu_torture_ops sched_ops = {
- .init = rcu_sync_torture_init,
- .cleanup = NULL,
- .readlock = sched_torture_read_lock,
- .readdelay = rcu_read_delay, /* just reuse rcu's version. */
- .readunlock = sched_torture_read_unlock,
- .completed = sched_torture_completed,
- .deferredfree = rcu_sched_torture_deferred_free,
- .sync = sched_torture_synchronize,
- .cb_barrier = rcu_barrier_sched,
- .stats = NULL,
- .irqcapable = 1,
- .name = "sched"
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = sched_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = sched_torture_read_unlock,
+ .completed = sched_torture_completed,
+ .deferred_free = rcu_sched_torture_deferred_free,
+ .sync = sched_torture_synchronize,
+ .cb_barrier = rcu_barrier_sched,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "sched"
};
static struct rcu_torture_ops sched_ops_sync = {
- .init = rcu_sync_torture_init,
- .cleanup = NULL,
- .readlock = sched_torture_read_lock,
- .readdelay = rcu_read_delay, /* just reuse rcu's version. */
- .readunlock = sched_torture_read_unlock,
- .completed = sched_torture_completed,
- .deferredfree = rcu_sync_torture_deferred_free,
- .sync = sched_torture_synchronize,
- .cb_barrier = NULL,
- .stats = NULL,
- .name = "sched_sync"
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = sched_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = sched_torture_read_unlock,
+ .completed = sched_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = sched_torture_synchronize,
+ .cb_barrier = NULL,
+ .stats = NULL,
+ .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,
+ .readlock = sched_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = sched_torture_read_unlock,
+ .completed = sched_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = synchronize_sched_expedited,
+ .cb_barrier = NULL,
+ .stats = rcu_expedited_torture_stats,
+ .irq_capable = 1,
+ .name = "sched_expedited"
};
/*
@@ -635,7 +652,7 @@ rcu_torture_writer(void *arg)
i = RCU_TORTURE_PIPE_LEN;
atomic_inc(&rcu_torture_wcount[i]);
old_rp->rtort_pipe_count++;
- cur_ops->deferredfree(old_rp);
+ cur_ops->deferred_free(old_rp);
}
rcu_torture_current_version++;
oldbatch = cur_ops->completed();
@@ -700,7 +717,7 @@ static void rcu_torture_timer(unsigned long unused)
if (p->rtort_mbtest == 0)
atomic_inc(&n_rcu_torture_mberror);
spin_lock(&rand_lock);
- cur_ops->readdelay(&rand);
+ cur_ops->read_delay(&rand);
n_rcu_torture_timers++;
spin_unlock(&rand_lock);
preempt_disable();
@@ -738,11 +755,11 @@ rcu_torture_reader(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
set_user_nice(current, 19);
- if (irqreader && cur_ops->irqcapable)
+ if (irqreader && cur_ops->irq_capable)
setup_timer_on_stack(&t, rcu_torture_timer, 0);
do {
- if (irqreader && cur_ops->irqcapable) {
+ if (irqreader && cur_ops->irq_capable) {
if (!timer_pending(&t))
mod_timer(&t, 1);
}
@@ -757,7 +774,7 @@ rcu_torture_reader(void *arg)
}
if (p->rtort_mbtest == 0)
atomic_inc(&n_rcu_torture_mberror);
- cur_ops->readdelay(&rand);
+ cur_ops->read_delay(&rand);
preempt_disable();
pipe_count = p->rtort_pipe_count;
if (pipe_count > RCU_TORTURE_PIPE_LEN) {
@@ -778,7 +795,7 @@ rcu_torture_reader(void *arg)
} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
rcutorture_shutdown_absorb("rcu_torture_reader");
- if (irqreader && cur_ops->irqcapable)
+ if (irqreader && cur_ops->irq_capable)
del_timer_sync(&t);
while (!kthread_should_stop())
schedule_timeout_uninterruptible(1);
@@ -1078,6 +1095,7 @@ rcu_torture_init(void)
int firsterr = 0;
static struct rcu_torture_ops *torture_ops[] =
{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
+ &sched_expedited_ops,
&srcu_ops, &sched_ops, &sched_ops_sync, };
mutex_lock(&fullstop_mutex);
diff --git a/kernel/sched.c b/kernel/sched.c
index 1b59e265273b..7a637ab977bf 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -318,12 +318,12 @@ struct task_group root_task_group;
/* Default task group's sched entity on each cpu */
static DEFINE_PER_CPU(struct sched_entity, init_sched_entity);
/* Default task group's cfs_rq on each cpu */
-static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cfs_rq, init_cfs_rq);
#endif /* CONFIG_FAIR_GROUP_SCHED */
#ifdef CONFIG_RT_GROUP_SCHED
static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity);
-static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rt_rq, init_rt_rq);
#endif /* CONFIG_RT_GROUP_SCHED */
#else /* !CONFIG_USER_SCHED */
#define root_task_group init_task_group
@@ -693,6 +693,7 @@ static inline int cpu_of(struct rq *rq)
#define this_rq() (&__get_cpu_var(runqueues))
#define task_rq(p) cpu_rq(task_cpu(p))
#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
+#define raw_rq() (&__raw_get_cpu_var(runqueues))
inline void update_rq_clock(struct rq *rq)
{
@@ -2637,9 +2638,32 @@ void sched_fork(struct task_struct *p, int clone_flags)
set_task_cpu(p, cpu);
/*
- * Make sure we do not leak PI boosting priority to the child:
+ * 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)
+ p->policy = SCHED_NORMAL;
+
+ if (p->normal_prio < DEFAULT_PRIO)
+ p->prio = DEFAULT_PRIO;
+
+ if (PRIO_TO_NICE(p->static_prio) < 0) {
+ p->static_prio = NICE_TO_PRIO(0);
+ set_load_weight(p);
+ }
+
+ /*
+ * We don't need the reset flag anymore after the fork. It has
+ * fulfilled its duty:
+ */
+ p->sched_reset_on_fork = 0;
+ }
+
if (!rt_prio(p->prio))
p->sched_class = &fair_sched_class;
@@ -6123,17 +6147,25 @@ static int __sched_setscheduler(struct task_struct *p, int policy,
unsigned long flags;
const struct sched_class *prev_class = p->sched_class;
struct rq *rq;
+ int reset_on_fork;
/* may grab non-irq protected spin_locks */
BUG_ON(in_interrupt());
recheck:
/* double check policy once rq lock held */
- if (policy < 0)
+ if (policy < 0) {
+ reset_on_fork = p->sched_reset_on_fork;
policy = oldpolicy = p->policy;
- else if (policy != SCHED_FIFO && policy != SCHED_RR &&
- policy != SCHED_NORMAL && policy != SCHED_BATCH &&
- policy != SCHED_IDLE)
- return -EINVAL;
+ } else {
+ reset_on_fork = !!(policy & SCHED_RESET_ON_FORK);
+ policy &= ~SCHED_RESET_ON_FORK;
+
+ if (policy != SCHED_FIFO && policy != SCHED_RR &&
+ policy != SCHED_NORMAL && policy != SCHED_BATCH &&
+ policy != SCHED_IDLE)
+ return -EINVAL;
+ }
+
/*
* Valid priorities for SCHED_FIFO and SCHED_RR are
* 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL,
@@ -6177,6 +6209,10 @@ recheck:
/* can't change other user's priorities */
if (!check_same_owner(p))
return -EPERM;
+
+ /* Normal users shall not reset the sched_reset_on_fork flag */
+ if (p->sched_reset_on_fork && !reset_on_fork)
+ return -EPERM;
}
if (user) {
@@ -6220,6 +6256,8 @@ recheck:
if (running)
p->sched_class->put_prev_task(rq, p);
+ p->sched_reset_on_fork = reset_on_fork;
+
oldprio = p->prio;
__setscheduler(rq, p, policy, param->sched_priority);
@@ -6336,14 +6374,15 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
if (p) {
retval = security_task_getscheduler(p);
if (!retval)
- retval = p->policy;
+ retval = p->policy
+ | (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0);
}
read_unlock(&tasklist_lock);
return retval;
}
/**
- * sys_sched_getscheduler - get the RT priority of a thread
+ * sys_sched_getparam - get the RT priority of a thread
* @pid: the pid in question.
* @param: structure containing the RT priority.
*/
@@ -6658,7 +6697,7 @@ EXPORT_SYMBOL(yield);
*/
void __sched io_schedule(void)
{
- struct rq *rq = &__raw_get_cpu_var(runqueues);
+ struct rq *rq = raw_rq();
delayacct_blkio_start();
atomic_inc(&rq->nr_iowait);
@@ -6670,7 +6709,7 @@ EXPORT_SYMBOL(io_schedule);
long __sched io_schedule_timeout(long timeout)
{
- struct rq *rq = &__raw_get_cpu_var(runqueues);
+ struct rq *rq = raw_rq();
long ret;
delayacct_blkio_start();
@@ -7051,6 +7090,11 @@ fail:
return ret;
}
+#define RCU_MIGRATION_IDLE 0
+#define RCU_MIGRATION_NEED_QS 1
+#define RCU_MIGRATION_GOT_QS 2
+#define RCU_MIGRATION_MUST_SYNC 3
+
/*
* migration_thread - this is a highprio system thread that performs
* thread migration by bumping thread off CPU then 'pushing' onto
@@ -7058,6 +7102,7 @@ fail:
*/
static int migration_thread(void *data)
{
+ int badcpu;
int cpu = (long)data;
struct rq *rq;
@@ -7092,8 +7137,17 @@ static int migration_thread(void *data)
req = list_entry(head->next, struct migration_req, list);
list_del_init(head->next);
- spin_unlock(&rq->lock);
- __migrate_task(req->task, cpu, req->dest_cpu);
+ if (req->task != NULL) {
+ spin_unlock(&rq->lock);
+ __migrate_task(req->task, cpu, req->dest_cpu);
+ } else if (likely(cpu == (badcpu = smp_processor_id()))) {
+ req->dest_cpu = RCU_MIGRATION_GOT_QS;
+ spin_unlock(&rq->lock);
+ } else {
+ req->dest_cpu = RCU_MIGRATION_MUST_SYNC;
+ spin_unlock(&rq->lock);
+ WARN_ONCE(1, "migration_thread() on CPU %d, expected %d\n", badcpu, cpu);
+ }
local_irq_enable();
complete(&req->done);
@@ -10581,3 +10635,113 @@ struct cgroup_subsys cpuacct_subsys = {
.subsys_id = cpuacct_subsys_id,
};
#endif /* CONFIG_CGROUP_CPUACCT */
+
+#ifndef CONFIG_SMP
+
+int rcu_expedited_torture_stats(char *page)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats);
+
+void synchronize_sched_expedited(void)
+{
+}
+EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
+
+#else /* #ifndef CONFIG_SMP */
+
+static DEFINE_PER_CPU(struct migration_req, rcu_migration_req);
+static DEFINE_MUTEX(rcu_sched_expedited_mutex);
+
+#define RCU_EXPEDITED_STATE_POST -2
+#define RCU_EXPEDITED_STATE_IDLE -1
+
+static int rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE;
+
+int rcu_expedited_torture_stats(char *page)
+{
+ int cnt = 0;
+ int cpu;
+
+ cnt += sprintf(&page[cnt], "state: %d /", rcu_expedited_state);
+ for_each_online_cpu(cpu) {
+ cnt += sprintf(&page[cnt], " %d:%d",
+ cpu, per_cpu(rcu_migration_req, cpu).dest_cpu);
+ }
+ cnt += sprintf(&page[cnt], "\n");
+ return cnt;
+}
+EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats);
+
+static long synchronize_sched_expedited_count;
+
+/*
+ * Wait for an rcu-sched grace period to elapse, but use "big hammer"
+ * approach to force grace period to end quickly. This consumes
+ * significant time on all CPUs, and is thus not recommended for
+ * any sort of common-case code.
+ *
+ * Note that it is illegal to call this function while holding any
+ * lock that is acquired by a CPU-hotplug notifier. Failing to
+ * observe this restriction will result in deadlock.
+ */
+void synchronize_sched_expedited(void)
+{
+ int cpu;
+ unsigned long flags;
+ bool need_full_sync = 0;
+ struct rq *rq;
+ struct migration_req *req;
+ long snap;
+ int trycount = 0;
+
+ smp_mb(); /* ensure prior mod happens before capturing snap. */
+ snap = ACCESS_ONCE(synchronize_sched_expedited_count) + 1;
+ get_online_cpus();
+ while (!mutex_trylock(&rcu_sched_expedited_mutex)) {
+ put_online_cpus();
+ if (trycount++ < 10)
+ udelay(trycount * num_online_cpus());
+ else {
+ synchronize_sched();
+ return;
+ }
+ if (ACCESS_ONCE(synchronize_sched_expedited_count) - snap > 0) {
+ smp_mb(); /* ensure test happens before caller kfree */
+ return;
+ }
+ get_online_cpus();
+ }
+ rcu_expedited_state = RCU_EXPEDITED_STATE_POST;
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ req = &per_cpu(rcu_migration_req, cpu);
+ init_completion(&req->done);
+ req->task = NULL;
+ req->dest_cpu = RCU_MIGRATION_NEED_QS;
+ spin_lock_irqsave(&rq->lock, flags);
+ list_add(&req->list, &rq->migration_queue);
+ spin_unlock_irqrestore(&rq->lock, flags);
+ wake_up_process(rq->migration_thread);
+ }
+ for_each_online_cpu(cpu) {
+ rcu_expedited_state = cpu;
+ req = &per_cpu(rcu_migration_req, cpu);
+ rq = cpu_rq(cpu);
+ wait_for_completion(&req->done);
+ spin_lock_irqsave(&rq->lock, flags);
+ if (unlikely(req->dest_cpu == RCU_MIGRATION_MUST_SYNC))
+ need_full_sync = 1;
+ req->dest_cpu = RCU_MIGRATION_IDLE;
+ spin_unlock_irqrestore(&rq->lock, flags);
+ }
+ rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE;
+ mutex_unlock(&rcu_sched_expedited_mutex);
+ put_online_cpus();
+ if (need_full_sync)
+ synchronize_sched();
+}
+EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
+
+#endif /* #else #ifndef CONFIG_SMP */
diff --git a/kernel/signal.c b/kernel/signal.c
index ccf1ceedaebe..64c5deeaca5d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2454,11 +2454,9 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
stack_t oss;
int error;
- if (uoss) {
- oss.ss_sp = (void __user *) current->sas_ss_sp;
- oss.ss_size = current->sas_ss_size;
- oss.ss_flags = sas_ss_flags(sp);
- }
+ oss.ss_sp = (void __user *) current->sas_ss_sp;
+ oss.ss_size = current->sas_ss_size;
+ oss.ss_flags = sas_ss_flags(sp);
if (uss) {
void __user *ss_sp;
@@ -2466,10 +2464,12 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
int ss_flags;
error = -EFAULT;
- if (!access_ok(VERIFY_READ, uss, sizeof(*uss))
- || __get_user(ss_sp, &uss->ss_sp)
- || __get_user(ss_flags, &uss->ss_flags)
- || __get_user(ss_size, &uss->ss_size))
+ if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
+ goto out;
+ error = __get_user(ss_sp, &uss->ss_sp) |
+ __get_user(ss_flags, &uss->ss_flags) |
+ __get_user(ss_size, &uss->ss_size);
+ if (error)
goto out;
error = -EPERM;
@@ -2501,13 +2501,16 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
current->sas_ss_size = ss_size;
}
+ error = 0;
if (uoss) {
error = -EFAULT;
- if (copy_to_user(uoss, &oss, sizeof(oss)))
+ if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
goto out;
+ error = __put_user(oss.ss_sp, &uoss->ss_sp) |
+ __put_user(oss.ss_size, &uoss->ss_size) |
+ __put_user(oss.ss_flags, &uoss->ss_flags);
}
- error = 0;
out:
return error;
}
diff --git a/kernel/smp.c b/kernel/smp.c
index ad63d8501207..415ae238753b 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -335,13 +335,6 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
generic_exec_single(cpu, data, wait);
}
-/* Deprecated: shim for archs using old arch_send_call_function_ipi API. */
-
-#ifndef arch_send_call_function_ipi_mask
-# define arch_send_call_function_ipi_mask(maskp) \
- arch_send_call_function_ipi(*(maskp))
-#endif
-
/**
* smp_call_function_many(): Run a function on a set of other CPUs.
* @mask: The set of cpus to run on (only runs on online subset).
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 88796c330838..0bad4f900e45 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/taskstats.c b/kernel/taskstats.c
index 888adbcca30c..ea8384d3caa7 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -108,7 +108,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
/*
* Send taskstats data in @skb to listener with nl_pid @pid
*/
-static int send_reply(struct sk_buff *skb, pid_t pid)
+static int send_reply(struct sk_buff *skb, struct genl_info *info)
{
struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
void *reply = genlmsg_data(genlhdr);
@@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *skb, pid_t pid)
return rc;
}
- return genlmsg_unicast(skb, pid);
+ return genlmsg_reply(skb, info);
}
/*
@@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
if (!skb_next)
break;
}
- rc = genlmsg_unicast(skb_cur, s->pid);
+ rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
if (rc == -ECONNREFUSED) {
s->valid = 0;
delcount++;
@@ -418,7 +418,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
goto err;
}
- rc = send_reply(rep_skb, info->snd_pid);
+ rc = send_reply(rep_skb, info);
err:
fput_light(file, fput_needed);
@@ -487,7 +487,7 @@ free_return_rc:
} else
goto err;
- return send_reply(rep_skb, info->snd_pid);
+ return send_reply(rep_skb, info);
err:
nlmsg_free(rep_skb);
return rc;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4521c77d1a1a..1f3ec2afa511 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2596,6 +2596,14 @@ ftrace_graph_open(struct inode *inode, struct file *file)
}
static int
+ftrace_graph_release(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ seq_release(inode, file);
+ return 0;
+}
+
+static int
ftrace_set_func(unsigned long *array, int *idx, char *buffer)
{
struct dyn_ftrace *rec;
@@ -2724,9 +2732,10 @@ ftrace_graph_write(struct file *file, const char __user *ubuf,
}
static const struct file_operations ftrace_graph_fops = {
- .open = ftrace_graph_open,
- .read = seq_read,
- .write = ftrace_graph_write,
+ .open = ftrace_graph_open,
+ .read = seq_read,
+ .write = ftrace_graph_write,
+ .release = ftrace_graph_release,
};
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c
index 1edaa9516e81..74903b62bcb6 100644
--- a/kernel/trace/kmemtrace.c
+++ b/kernel/trace/kmemtrace.c
@@ -239,12 +239,52 @@ struct kmemtrace_user_event_alloc {
};
static enum print_line_t
-kmemtrace_print_alloc_user(struct trace_iterator *iter,
- struct kmemtrace_alloc_entry *entry)
+kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags)
+{
+ struct trace_seq *s = &iter->seq;
+ struct kmemtrace_alloc_entry *entry;
+ int ret;
+
+ trace_assign_type(entry, iter->ent);
+
+ ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu "
+ "bytes_req %lu bytes_alloc %lu gfp_flags %lu node %d\n",
+ entry->type_id, (void *)entry->call_site, (unsigned long)entry->ptr,
+ (unsigned long)entry->bytes_req, (unsigned long)entry->bytes_alloc,
+ (unsigned long)entry->gfp_flags, entry->node);
+
+ if (!ret)
+ return TRACE_TYPE_PARTIAL_LINE;
+ return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+kmemtrace_print_free_user(struct trace_iterator *iter, int flags)
{
- struct kmemtrace_user_event_alloc *ev_alloc;
struct trace_seq *s = &iter->seq;
+ struct kmemtrace_free_entry *entry;
+ int ret;
+
+ trace_assign_type(entry, iter->ent);
+
+ ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu\n",
+ entry->type_id, (void *)entry->call_site,
+ (unsigned long)entry->ptr);
+
+ if (!ret)
+ return TRACE_TYPE_PARTIAL_LINE;
+ return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+kmemtrace_print_alloc_user_bin(struct trace_iterator *iter, int flags)
+{
+ struct trace_seq *s = &iter->seq;
+ struct kmemtrace_alloc_entry *entry;
struct kmemtrace_user_event *ev;
+ struct kmemtrace_user_event_alloc *ev_alloc;
+
+ trace_assign_type(entry, iter->ent);
ev = trace_seq_reserve(s, sizeof(*ev));
if (!ev)
@@ -271,12 +311,14 @@ kmemtrace_print_alloc_user(struct trace_iterator *iter,
}
static enum print_line_t
-kmemtrace_print_free_user(struct trace_iterator *iter,
- struct kmemtrace_free_entry *entry)
+kmemtrace_print_free_user_bin(struct trace_iterator *iter, int flags)
{
struct trace_seq *s = &iter->seq;
+ struct kmemtrace_free_entry *entry;
struct kmemtrace_user_event *ev;
+ trace_assign_type(entry, iter->ent);
+
ev = trace_seq_reserve(s, sizeof(*ev));
if (!ev)
return TRACE_TYPE_PARTIAL_LINE;
@@ -294,12 +336,14 @@ kmemtrace_print_free_user(struct trace_iterator *iter,
/* The two other following provide a more minimalistic output */
static enum print_line_t
-kmemtrace_print_alloc_compress(struct trace_iterator *iter,
- struct kmemtrace_alloc_entry *entry)
+kmemtrace_print_alloc_compress(struct trace_iterator *iter)
{
+ struct kmemtrace_alloc_entry *entry;
struct trace_seq *s = &iter->seq;
int ret;
+ trace_assign_type(entry, iter->ent);
+
/* Alloc entry */
ret = trace_seq_printf(s, " + ");
if (!ret)
@@ -362,12 +406,14 @@ kmemtrace_print_alloc_compress(struct trace_iterator *iter,
}
static enum print_line_t
-kmemtrace_print_free_compress(struct trace_iterator *iter,
- struct kmemtrace_free_entry *entry)
+kmemtrace_print_free_compress(struct trace_iterator *iter)
{
+ struct kmemtrace_free_entry *entry;
struct trace_seq *s = &iter->seq;
int ret;
+ trace_assign_type(entry, iter->ent);
+
/* Free entry */
ret = trace_seq_printf(s, " - ");
if (!ret)
@@ -421,32 +467,31 @@ static enum print_line_t kmemtrace_print_line(struct trace_iterator *iter)
{
struct trace_entry *entry = iter->ent;
- switch (entry->type) {
- case TRACE_KMEM_ALLOC: {
- struct kmemtrace_alloc_entry *field;
-
- trace_assign_type(field, entry);
- if (kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL)
- return kmemtrace_print_alloc_compress(iter, field);
- else
- return kmemtrace_print_alloc_user(iter, field);
- }
-
- case TRACE_KMEM_FREE: {
- struct kmemtrace_free_entry *field;
-
- trace_assign_type(field, entry);
- if (kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL)
- return kmemtrace_print_free_compress(iter, field);
- else
- return kmemtrace_print_free_user(iter, field);
- }
+ if (!(kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL))
+ return TRACE_TYPE_UNHANDLED;
+ switch (entry->type) {
+ case TRACE_KMEM_ALLOC:
+ return kmemtrace_print_alloc_compress(iter);
+ case TRACE_KMEM_FREE:
+ return kmemtrace_print_free_compress(iter);
default:
return TRACE_TYPE_UNHANDLED;
}
}
+static struct trace_event kmem_trace_alloc = {
+ .type = TRACE_KMEM_ALLOC,
+ .trace = kmemtrace_print_alloc_user,
+ .binary = kmemtrace_print_alloc_user_bin,
+};
+
+static struct trace_event kmem_trace_free = {
+ .type = TRACE_KMEM_FREE,
+ .trace = kmemtrace_print_free_user,
+ .binary = kmemtrace_print_free_user_bin,
+};
+
static struct tracer kmem_tracer __read_mostly = {
.name = "kmemtrace",
.init = kmem_trace_init,
@@ -463,6 +508,21 @@ void kmemtrace_init(void)
static int __init init_kmem_tracer(void)
{
- return register_tracer(&kmem_tracer);
+ if (!register_ftrace_event(&kmem_trace_alloc)) {
+ pr_warning("Warning: could not register kmem events\n");
+ return 1;
+ }
+
+ if (!register_ftrace_event(&kmem_trace_free)) {
+ pr_warning("Warning: could not register kmem events\n");
+ return 1;
+ }
+
+ if (!register_tracer(&kmem_tracer)) {
+ pr_warning("Warning: could not register the kmem tracer\n");
+ return 1;
+ }
+
+ return 0;
}
device_initcall(init_kmem_tracer);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8bc8d8afea6a..f968cba37105 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -50,7 +50,7 @@ unsigned long __read_mostly tracing_thresh;
* On boot up, the ring buffer is set to the minimum size, so that
* we do not waste memory on systems that are not using tracing.
*/
-static int ring_buffer_expanded;
+int ring_buffer_expanded;
/*
* We need to change this state when a selftest is running.
@@ -64,7 +64,7 @@ static bool __read_mostly tracing_selftest_running;
/*
* If a tracer is running, we do not want to run SELFTEST.
*/
-static bool __read_mostly tracing_selftest_disabled;
+bool __read_mostly tracing_selftest_disabled;
/* For tracers that don't implement custom flags */
static struct tracer_opt dummy_tracer_opt[] = {
@@ -1919,11 +1919,9 @@ __tracing_open(struct inode *inode, struct file *file)
if (current_trace)
*iter->trace = *current_trace;
- if (!alloc_cpumask_var(&iter->started, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
goto fail;
- cpumask_clear(iter->started);
-
if (current_trace && current_trace->print_max)
iter->tr = &max_tr;
else
@@ -4279,7 +4277,7 @@ __init static int tracer_alloc_buffers(void)
if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL))
goto out_free_buffer_mask;
- if (!alloc_cpumask_var(&tracing_reader_cpumask, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&tracing_reader_cpumask, GFP_KERNEL))
goto out_free_tracing_cpumask;
/* To save memory, keep the ring buffer size to its minimum */
@@ -4290,7 +4288,6 @@ __init static int tracer_alloc_buffers(void)
cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
cpumask_copy(tracing_cpumask, cpu_all_mask);
- cpumask_clear(tracing_reader_cpumask);
/* TODO: make the number of buffers hot pluggable with CPUS */
global_trace.buffer = ring_buffer_alloc(ring_buf_size,
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 3548ae5cc780..52eb0d8dcd75 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -517,6 +517,9 @@ extern unsigned long ftrace_update_tot_cnt;
extern int DYN_FTRACE_TEST_NAME(void);
#endif
+extern int ring_buffer_expanded;
+extern bool tracing_selftest_disabled;
+
#ifdef CONFIG_FTRACE_STARTUP_TEST
extern int trace_selftest_startup_function(struct tracer *trace,
struct trace_array *tr);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 53c8fd376a88..66848aa8213e 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -17,6 +17,8 @@
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <asm/setup.h>
+
#include "trace_output.h"
#define TRACE_SYSTEM "TRACE_SYSTEM"
@@ -1133,6 +1135,18 @@ struct notifier_block trace_module_nb = {
extern struct ftrace_event_call __start_ftrace_events[];
extern struct ftrace_event_call __stop_ftrace_events[];
+static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
+
+static __init int setup_trace_event(char *str)
+{
+ strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
+ ring_buffer_expanded = 1;
+ tracing_selftest_disabled = 1;
+
+ return 1;
+}
+__setup("trace_event=", setup_trace_event);
+
static __init int event_trace_init(void)
{
struct ftrace_event_call *call;
@@ -1140,6 +1154,8 @@ static __init int event_trace_init(void)
struct dentry *entry;
struct dentry *d_events;
int ret;
+ char *buf = bootup_event_buf;
+ char *token;
d_tracer = tracing_init_dentry();
if (!d_tracer)
@@ -1185,6 +1201,19 @@ static __init int event_trace_init(void)
&ftrace_event_format_fops);
}
+ while (true) {
+ token = strsep(&buf, ",");
+
+ if (!token)
+ break;
+ if (!*token)
+ continue;
+
+ ret = ftrace_set_clr_event(token, 1);
+ if (ret)
+ pr_warning("Failed to enable trace event: %s\n", token);
+ }
+
ret = register_module_notifier(&trace_module_nb);
if (ret)
pr_warning("Failed to register trace events module notifier\n");
@@ -1334,7 +1363,7 @@ static __init void event_trace_self_tests(void)
#ifdef CONFIG_FUNCTION_TRACER
-static DEFINE_PER_CPU(atomic_t, test_event_disable);
+static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable);
static void
function_test_events_call(unsigned long ip, unsigned long parent_ip)
@@ -1350,7 +1379,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
pc = preempt_count();
resched = ftrace_preempt_disable();
cpu = raw_smp_processor_id();
- disabled = atomic_inc_return(&per_cpu(test_event_disable, cpu));
+ disabled = atomic_inc_return(&per_cpu(ftrace_test_event_disable, cpu));
if (disabled != 1)
goto out;
@@ -1368,7 +1397,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
trace_nowake_buffer_unlock_commit(event, flags, pc);
out:
- atomic_dec(&per_cpu(test_event_disable, cpu));
+ atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
ftrace_preempt_enable(resched);
}
@@ -1392,10 +1421,10 @@ static __init void event_trace_self_test_with_function(void)
static __init int event_trace_self_tests_init(void)
{
-
- event_trace_self_tests();
-
- event_trace_self_test_with_function();
+ if (!tracing_selftest_disabled) {
+ event_trace_self_tests();
+ event_trace_self_test_with_function();
+ }
return 0;
}
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index e644af910124..6a2a9d484cd6 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -301,17 +301,14 @@ static const struct seq_operations stack_trace_seq_ops = {
static int stack_trace_open(struct inode *inode, struct file *file)
{
- int ret;
-
- ret = seq_open(file, &stack_trace_seq_ops);
-
- return ret;
+ return seq_open(file, &stack_trace_seq_ops);
}
static const struct file_operations stack_trace_fops = {
.open = stack_trace_open,
.read = seq_read,
.llseek = seq_lseek,
+ .release = seq_release,
};
int
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index e66f5e493342..aea321c82fa0 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -73,7 +73,7 @@ static struct rb_node *release_next(struct rb_node *node)
}
}
-static void reset_stat_session(struct stat_session *session)
+static void __reset_stat_session(struct stat_session *session)
{
struct rb_node *node = session->stat_root.rb_node;
@@ -83,10 +83,17 @@ static void reset_stat_session(struct stat_session *session)
session->stat_root = RB_ROOT;
}
+static void reset_stat_session(struct stat_session *session)
+{
+ mutex_lock(&session->stat_mutex);
+ __reset_stat_session(session);
+ mutex_unlock(&session->stat_mutex);
+}
+
static void destroy_session(struct stat_session *session)
{
debugfs_remove(session->file);
- reset_stat_session(session);
+ __reset_stat_session(session);
mutex_destroy(&session->stat_mutex);
kfree(session);
}
@@ -150,7 +157,7 @@ static int stat_seq_init(struct stat_session *session)
int i;
mutex_lock(&session->stat_mutex);
- reset_stat_session(session);
+ __reset_stat_session(session);
if (!ts->stat_cmp)
ts->stat_cmp = dummy_cmp;
@@ -183,7 +190,7 @@ exit:
return ret;
exit_free_rbtree:
- reset_stat_session(session);
+ __reset_stat_session(session);
mutex_unlock(&session->stat_mutex);
return ret;
}
@@ -250,16 +257,21 @@ static const struct seq_operations trace_stat_seq_ops = {
static int tracing_stat_open(struct inode *inode, struct file *file)
{
int ret;
-
+ struct seq_file *m;
struct stat_session *session = inode->i_private;
+ ret = stat_seq_init(session);
+ if (ret)
+ return ret;
+
ret = seq_open(file, &trace_stat_seq_ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
- m->private = session;
- ret = stat_seq_init(session);
+ if (ret) {
+ reset_stat_session(session);
+ return ret;
}
+ m = file->private_data;
+ m->private = session;
return ret;
}
@@ -270,11 +282,9 @@ static int tracing_stat_release(struct inode *i, struct file *f)
{
struct stat_session *session = i->i_private;
- mutex_lock(&session->stat_mutex);
reset_stat_session(session);
- mutex_unlock(&session->stat_mutex);
- return 0;
+ return seq_release(i, f);
}
static const struct file_operations tracing_stat_fops = {
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 1ef5d3a601c7..b6bce8613a9c 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -47,7 +47,7 @@ static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
/*
* Note about RCU :
- * It is used to to delay the free of multiple probes array until a quiescent
+ * It is used to delay the free of multiple probes array until a quiescent
* state is reached.
* Tracepoint entries modifications are protected by the tracepoints_mutex.
*/
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 12327b2bb785..e30274f6b840 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -336,6 +336,26 @@ config SLUB_STATS
out which slabs are relevant to a particular load.
Try running: slabinfo -DA
+config SLQB_DEBUG
+ default y
+ bool "Enable SLQB debugging support"
+ depends on SLQB
+
+config SLQB_DEBUG_ON
+ default n
+ bool "SLQB debugging on by default"
+ depends on SLQB_DEBUG
+
+config SLQB_SYSFS
+ bool "Create SYSFS entries for slab caches"
+ default n
+ depends on SLQB
+
+config SLQB_STATS
+ bool "Enable SLQB performance statistics"
+ default n
+ depends on SLQB_SYSFS
+
config DEBUG_KMEMLEAK
bool "Kernel memory leak detector"
depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \
@@ -790,6 +810,21 @@ config DEBUG_BLOCK_EXT_DEVT
Say N if you are unsure.
+config DEBUG_FORCE_WEAK_PER_CPU
+ bool "Force weak per-cpu definitions"
+ depends on DEBUG_KERNEL
+ help
+ s390 and alpha require percpu variables in modules to be
+ defined weak to work around addressing range issue which
+ puts the following two restrictions on percpu variable
+ definitions.
+
+ 1. percpu symbols must be unique whether static or not
+ 2. percpu variables can't be defined inside a function
+
+ To ensure that generic code follows the above rules, this
+ option forces all percpu variables to be defined as weak.
+
config LKDTM
tristate "Linux Kernel Dump Test Tool Module"
depends on DEBUG_KERNEL
diff --git a/lib/Makefile b/lib/Makefile
index b6d1857bbf08..347ad8db29d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o
+ is_single_threaded.o plist.o decompress.o flex_array.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -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/atomic64.c b/lib/atomic64.c
index c5e725562416..8bee16ec7524 100644
--- a/lib/atomic64.c
+++ b/lib/atomic64.c
@@ -13,6 +13,7 @@
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/atomic.h>
/*
@@ -52,6 +53,7 @@ long long atomic64_read(const atomic64_t *v)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_read);
void atomic64_set(atomic64_t *v, long long i)
{
@@ -62,6 +64,7 @@ void atomic64_set(atomic64_t *v, long long i)
v->counter = i;
spin_unlock_irqrestore(lock, flags);
}
+EXPORT_SYMBOL(atomic64_set);
void atomic64_add(long long a, atomic64_t *v)
{
@@ -72,6 +75,7 @@ void atomic64_add(long long a, atomic64_t *v)
v->counter += a;
spin_unlock_irqrestore(lock, flags);
}
+EXPORT_SYMBOL(atomic64_add);
long long atomic64_add_return(long long a, atomic64_t *v)
{
@@ -84,6 +88,7 @@ long long atomic64_add_return(long long a, atomic64_t *v)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_add_return);
void atomic64_sub(long long a, atomic64_t *v)
{
@@ -94,6 +99,7 @@ void atomic64_sub(long long a, atomic64_t *v)
v->counter -= a;
spin_unlock_irqrestore(lock, flags);
}
+EXPORT_SYMBOL(atomic64_sub);
long long atomic64_sub_return(long long a, atomic64_t *v)
{
@@ -106,6 +112,7 @@ long long atomic64_sub_return(long long a, atomic64_t *v)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_sub_return);
long long atomic64_dec_if_positive(atomic64_t *v)
{
@@ -120,6 +127,7 @@ long long atomic64_dec_if_positive(atomic64_t *v)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_dec_if_positive);
long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
{
@@ -134,6 +142,7 @@ long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_cmpxchg);
long long atomic64_xchg(atomic64_t *v, long long new)
{
@@ -147,6 +156,7 @@ long long atomic64_xchg(atomic64_t *v, long long new)
spin_unlock_irqrestore(lock, flags);
return val;
}
+EXPORT_SYMBOL(atomic64_xchg);
int atomic64_add_unless(atomic64_t *v, long long a, long long u)
{
@@ -162,6 +172,7 @@ int atomic64_add_unless(atomic64_t *v, long long a, long long u)
spin_unlock_irqrestore(lock, flags);
return ret;
}
+EXPORT_SYMBOL(atomic64_add_unless);
static int init_atomic64_lock(void)
{
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 833139ce1e22..e22c148e4b7f 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -164,7 +164,7 @@ static void ddebug_change(const struct ddebug_query *query,
if (!newflags)
dt->num_enabled--;
- else if (!dp-flags)
+ else if (!dp->flags)
dt->num_enabled++;
dp->flags = newflags;
if (newflags) {
diff --git a/lib/flex_array.c b/lib/flex_array.c
new file mode 100644
index 000000000000..0e7894ce8882
--- /dev/null
+++ b/lib/flex_array.c
@@ -0,0 +1,269 @@
+/*
+ * Flexible array managed in PAGE_SIZE parts
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2009
+ *
+ * Author: Dave Hansen <dave@linux.vnet.ibm.com>
+ */
+
+#include <linux/flex_array.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+
+struct flex_array_part {
+ char elements[FLEX_ARRAY_PART_SIZE];
+};
+
+static inline int __elements_per_part(int element_size)
+{
+ return FLEX_ARRAY_PART_SIZE / element_size;
+}
+
+static inline int bytes_left_in_base(void)
+{
+ int element_offset = offsetof(struct flex_array, parts);
+ int bytes_left = FLEX_ARRAY_BASE_SIZE - element_offset;
+ return bytes_left;
+}
+
+static inline int nr_base_part_ptrs(void)
+{
+ return bytes_left_in_base() / sizeof(struct flex_array_part *);
+}
+
+/*
+ * If a user requests an allocation which is small
+ * enough, we may simply use the space in the
+ * flex_array->parts[] array to store the user
+ * data.
+ */
+static inline int elements_fit_in_base(struct flex_array *fa)
+{
+ int data_size = fa->element_size * fa->total_nr_elements;
+ if (data_size <= bytes_left_in_base())
+ return 1;
+ return 0;
+}
+
+/**
+ * flex_array_alloc - allocate a new flexible array
+ * @element_size: the size of individual elements in the array
+ * @total: total number of elements that this should hold
+ *
+ * Note: all locking must be provided by the caller.
+ *
+ * @total is used to size internal structures. If the user ever
+ * accesses any array indexes >=@total, it will produce errors.
+ *
+ * The maximum number of elements is defined as: the number of
+ * elements that can be stored in a page times the number of
+ * page pointers that we can fit in the base structure or (using
+ * integer math):
+ *
+ * (PAGE_SIZE/element_size) * (PAGE_SIZE-8)/sizeof(void *)
+ *
+ * Here's a table showing example capacities. Note that the maximum
+ * index that the get/put() functions is just nr_objects-1. This
+ * basically means that you get 4MB of storage on 32-bit and 2MB on
+ * 64-bit.
+ *
+ *
+ * Element size | Objects | Objects |
+ * PAGE_SIZE=4k | 32-bit | 64-bit |
+ * ---------------------------------|
+ * 1 bytes | 4186112 | 2093056 |
+ * 2 bytes | 2093056 | 1046528 |
+ * 3 bytes | 1395030 | 697515 |
+ * 4 bytes | 1046528 | 523264 |
+ * 32 bytes | 130816 | 65408 |
+ * 33 bytes | 126728 | 63364 |
+ * 2048 bytes | 2044 | 1022 |
+ * 2049 bytes | 1022 | 511 |
+ * void * | 1046528 | 261632 |
+ *
+ * Since 64-bit pointers are twice the size, we lose half the
+ * capacity in the base structure. Also note that no effort is made
+ * to efficiently pack objects across page boundaries.
+ */
+struct flex_array *flex_array_alloc(int element_size, int total, gfp_t flags)
+{
+ struct flex_array *ret;
+ int max_size = nr_base_part_ptrs() * __elements_per_part(element_size);
+
+ /* max_size will end up 0 if element_size > PAGE_SIZE */
+ if (total > max_size)
+ return NULL;
+ ret = kzalloc(sizeof(struct flex_array), flags);
+ if (!ret)
+ return NULL;
+ ret->element_size = element_size;
+ ret->total_nr_elements = total;
+ return ret;
+}
+
+static int fa_element_to_part_nr(struct flex_array *fa, int element_nr)
+{
+ return element_nr / __elements_per_part(fa->element_size);
+}
+
+/**
+ * flex_array_free_parts - just free the second-level pages
+ * @src: address of data to copy into the array
+ * @element_nr: index of the position in which to insert
+ * the new element.
+ *
+ * This is to be used in cases where the base 'struct flex_array'
+ * has been statically allocated and should not be free.
+ */
+void flex_array_free_parts(struct flex_array *fa)
+{
+ int part_nr;
+ int max_part = nr_base_part_ptrs();
+
+ if (elements_fit_in_base(fa))
+ return;
+ for (part_nr = 0; part_nr < max_part; part_nr++)
+ kfree(fa->parts[part_nr]);
+}
+
+void flex_array_free(struct flex_array *fa)
+{
+ flex_array_free_parts(fa);
+ kfree(fa);
+}
+
+static int fa_index_inside_part(struct flex_array *fa, int element_nr)
+{
+ return element_nr % __elements_per_part(fa->element_size);
+}
+
+static int index_inside_part(struct flex_array *fa, int element_nr)
+{
+ int part_offset = fa_index_inside_part(fa, element_nr);
+ return part_offset * fa->element_size;
+}
+
+static struct flex_array_part *
+__fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
+{
+ struct flex_array_part *part = fa->parts[part_nr];
+ if (!part) {
+ /*
+ * This leaves the part pages uninitialized
+ * and with potentially random data, just
+ * as if the user had kmalloc()'d the whole.
+ * __GFP_ZERO can be used to zero it.
+ */
+ part = kmalloc(FLEX_ARRAY_PART_SIZE, flags);
+ if (!part)
+ return NULL;
+ fa->parts[part_nr] = part;
+ }
+ return part;
+}
+
+/**
+ * flex_array_put - copy data into the array at @element_nr
+ * @src: address of data to copy into the array
+ * @element_nr: index of the position in which to insert
+ * the new element.
+ *
+ * Note that this *copies* the contents of @src into
+ * the array. If you are trying to store an array of
+ * pointers, make sure to pass in &ptr instead of ptr.
+ *
+ * Locking must be provided by the caller.
+ */
+int flex_array_put(struct flex_array *fa, int element_nr, void *src, gfp_t flags)
+{
+ int part_nr = fa_element_to_part_nr(fa, element_nr);
+ struct flex_array_part *part;
+ void *dst;
+
+ if (element_nr >= fa->total_nr_elements)
+ return -ENOSPC;
+ if (elements_fit_in_base(fa))
+ part = (struct flex_array_part *)&fa->parts[0];
+ else
+ part = __fa_get_part(fa, part_nr, flags);
+ if (!part)
+ return -ENOMEM;
+ dst = &part->elements[index_inside_part(fa, element_nr)];
+ memcpy(dst, src, fa->element_size);
+ return 0;
+}
+
+/**
+ * flex_array_prealloc - guarantee that array space exists
+ * @start: index of first array element for which space is allocated
+ * @end: index of last (inclusive) element for which space is allocated
+ *
+ * This will guarantee that no future calls to flex_array_put()
+ * will allocate memory. It can be used if you are expecting to
+ * be holding a lock or in some atomic context while writing
+ * data into the array.
+ *
+ * Locking must be provided by the caller.
+ */
+int flex_array_prealloc(struct flex_array *fa, int start, int end, gfp_t flags)
+{
+ int start_part;
+ int end_part;
+ int part_nr;
+ struct flex_array_part *part;
+
+ if (start >= fa->total_nr_elements || end >= fa->total_nr_elements)
+ return -ENOSPC;
+ if (elements_fit_in_base(fa))
+ return 0;
+ start_part = fa_element_to_part_nr(fa, start);
+ end_part = fa_element_to_part_nr(fa, end);
+ for (part_nr = start_part; part_nr <= end_part; part_nr++) {
+ part = __fa_get_part(fa, part_nr, flags);
+ if (!part)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * flex_array_get - pull data back out of the array
+ * @element_nr: index of the element to fetch from the array
+ *
+ * Returns a pointer to the data at index @element_nr. Note
+ * that this is a copy of the data that was passed in. If you
+ * are using this to store pointers, you'll get back &ptr.
+ *
+ * Locking must be provided by the caller.
+ */
+void *flex_array_get(struct flex_array *fa, int element_nr)
+{
+ int part_nr = fa_element_to_part_nr(fa, element_nr);
+ struct flex_array_part *part;
+ int index;
+
+ if (element_nr >= fa->total_nr_elements)
+ return NULL;
+ if (!fa->parts[part_nr])
+ return NULL;
+ if (elements_fit_in_base(fa))
+ part = (struct flex_array_part *)&fa->parts[0];
+ else
+ part = fa->parts[part_nr];
+ index = index_inside_part(fa, element_nr);
+ return &part->elements[index_inside_part(fa, element_nr)];
+}
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
index f1ed2fe76c65..bd2bea963364 100644
--- a/lib/is_single_threaded.c
+++ b/lib/is_single_threaded.c
@@ -12,34 +12,47 @@
#include <linux/sched.h>
-/**
- * is_single_threaded - Determine if a thread group is single-threaded or not
- * @p: A task in the thread group in question
- *
- * This returns true if the thread group to which a task belongs is single
- * threaded, false if it is not.
+/*
+ * Returns true if the task does not share ->mm with another thread/process.
*/
-bool is_single_threaded(struct task_struct *p)
+bool current_is_single_threaded(void)
{
- struct task_struct *g, *t;
- struct mm_struct *mm = p->mm;
+ struct task_struct *task = current;
+ struct mm_struct *mm = task->mm;
+ struct task_struct *p, *t;
+ bool ret;
- if (atomic_read(&p->signal->count) != 1)
- goto no;
+ if (atomic_read(&task->signal->live) != 1)
+ return false;
- if (atomic_read(&p->mm->mm_users) != 1) {
- read_lock(&tasklist_lock);
- do_each_thread(g, t) {
- if (t->mm == mm && t != p)
- goto no_unlock;
- } while_each_thread(g, t);
- read_unlock(&tasklist_lock);
- }
+ if (atomic_read(&mm->mm_users) == 1)
+ return true;
- return true;
+ ret = false;
+ rcu_read_lock();
+ for_each_process(p) {
+ if (unlikely(p->flags & PF_KTHREAD))
+ continue;
+ if (unlikely(p == task->group_leader))
+ continue;
+
+ t = p;
+ do {
+ if (unlikely(t->mm == mm))
+ goto found;
+ if (likely(t->mm))
+ break;
+ /*
+ * t->mm == NULL. Make sure next_thread/next_task
+ * will see other CLONE_VM tasks which might be
+ * forked before exiting.
+ */
+ smp_rmb();
+ } while_each_thread(p, t);
+ }
+ ret = true;
+found:
+ rcu_read_unlock();
-no_unlock:
- read_unlock(&tasklist_lock);
-no:
- return false;
+ return ret;
}
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
new file mode 100644
index 000000000000..ab11a710b6e2
--- /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 eviced 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 houskeeping
+ * 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 embeded in.
+ */
+void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
+ void (*detail) (struct seq_file *, struct lc_element *))
+{
+ unsigned int nr_elements = lc->nr_elements;
+ struct lc_element *e;
+ int i;
+
+ seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext);
+ for (i = 0; i < nr_elements; i++) {
+ e = lc_element_by_index(lc, i);
+ if (e->lc_number == LC_FREE) {
+ seq_printf(seq, "\t%2d: FREE\n", i);
+ } else {
+ seq_printf(seq, "\t%2d: %4u %4u ", i,
+ e->lc_number, e->refcnt);
+ detail(seq, e);
+ }
+ }
+}
+
+EXPORT_SYMBOL(lc_create);
+EXPORT_SYMBOL(lc_reset);
+EXPORT_SYMBOL(lc_destroy);
+EXPORT_SYMBOL(lc_set);
+EXPORT_SYMBOL(lc_del);
+EXPORT_SYMBOL(lc_try_get);
+EXPORT_SYMBOL(lc_find);
+EXPORT_SYMBOL(lc_get);
+EXPORT_SYMBOL(lc_put);
+EXPORT_SYMBOL(lc_changed);
+EXPORT_SYMBOL(lc_element_by_index);
+EXPORT_SYMBOL(lc_index_of);
+EXPORT_SYMBOL(lc_seq_printf_stats);
+EXPORT_SYMBOL(lc_seq_dump_details);
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index a295e404e908..0d475d8167bf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -314,6 +314,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
miter->__sg = sgl;
miter->__nents = nents;
miter->__offset = 0;
+ WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
miter->__flags = flags;
}
EXPORT_SYMBOL(sg_miter_start);
@@ -394,6 +395,9 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
if (miter->addr) {
miter->__offset += miter->consumed;
+ if (miter->__flags & SG_MITER_TO_SG)
+ flush_kernel_dcache_page(miter->page);
+
if (miter->__flags & SG_MITER_ATOMIC) {
WARN_ON(!irqs_disabled());
kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ);
@@ -426,8 +430,14 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
unsigned int offset = 0;
struct sg_mapping_iter miter;
unsigned long flags;
+ unsigned int sg_flags = SG_MITER_ATOMIC;
+
+ if (to_buffer)
+ sg_flags |= SG_MITER_FROM_SG;
+ else
+ sg_flags |= SG_MITER_TO_SG;
- sg_miter_start(&miter, sgl, nents, SG_MITER_ATOMIC);
+ sg_miter_start(&miter, sgl, nents, sg_flags);
local_irq_save(flags);
@@ -438,10 +448,8 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
if (to_buffer)
memcpy(buf + offset, miter.addr, len);
- else {
+ else
memcpy(miter.addr, buf + offset, len);
- flush_kernel_dcache_page(miter.page);
- }
offset += len;
}
diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c
index c3e4a2baf835..46a31e5f49c3 100644
--- a/lib/zlib_deflate/deflate.c
+++ b/lib/zlib_deflate/deflate.c
@@ -135,7 +135,7 @@ static const config configuration_table[10] = {
/* ===========================================================================
* Update a hash value with the given input byte
- * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * IN assertion: all calls to UPDATE_HASH are made with consecutive
* input characters, so that a running hash key can be computed from the
* previous key instead of complete recalculation each time.
*/
@@ -146,7 +146,7 @@ static const config configuration_table[10] = {
* Insert string str in the dictionary and set match_head to the previous head
* of the hash chain (the most recent string with same hash key). Return
* the previous length of the hash chain.
- * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * IN assertion: all calls to INSERT_STRING are made with consecutive
* input characters and the first MIN_MATCH bytes of str are valid
* (except for the last MIN_MATCH-1 bytes of the input file).
*/
diff --git a/mm/Makefile b/mm/Makefile
index 5e0bd6426693..b2b96c27d520 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \
vmalloc.o
obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
- maccess.o page_alloc.o page-writeback.o pdflush.o \
+ maccess.o page_alloc.o page-writeback.o \
readahead.o swap.o truncate.o vmscan.o shmem.o \
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
page_isolation.o mm_init.o $(mmu-y)
@@ -28,12 +28,13 @@ obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_SLUB) += slub.o
+obj-$(CONFIG_SLQB) += slqb.o
obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
obj-$(CONFIG_FAILSLAB) += failslab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
-ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
obj-$(CONFIG_SMP) += percpu.o
else
obj-$(CONFIG_SMP) += allocpercpu.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
index dfdee6a47359..df34ceae0c67 100644
--- a/mm/allocpercpu.c
+++ b/mm/allocpercpu.c
@@ -5,6 +5,8 @@
*/
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <asm/sections.h>
#ifndef cache_line_size
#define cache_line_size() L1_CACHE_BYTES
@@ -147,3 +149,29 @@ void free_percpu(void *__pdata)
kfree(__percpu_disguise(__pdata));
}
EXPORT_SYMBOL_GPL(free_percpu);
+
+/*
+ * Generic percpu area setup.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+
+EXPORT_SYMBOL(__per_cpu_offset);
+
+void __init setup_per_cpu_areas(void)
+{
+ unsigned long size, i;
+ char *ptr;
+ unsigned long nr_possible_cpus = num_possible_cpus();
+
+ /* Copy section for each CPU (we discard the original) */
+ size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+ ptr = alloc_bootmem_pages(size * nr_possible_cpus);
+
+ for_each_possible_cpu(i) {
+ __per_cpu_offset[i] = ptr - __per_cpu_start;
+ memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+ ptr += size;
+ }
+}
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index c86edd244294..036b07ba393b 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -1,8 +1,11 @@
#include <linux/wait.h>
#include <linux/backing-dev.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/writeback.h>
@@ -14,6 +17,7 @@ void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
EXPORT_SYMBOL(default_unplug_io_fn);
struct backing_dev_info default_backing_dev_info = {
+ .name = "default",
.ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE,
.state = 0,
.capabilities = BDI_CAP_MAP_COPY,
@@ -22,6 +26,18 @@ struct backing_dev_info default_backing_dev_info = {
EXPORT_SYMBOL_GPL(default_backing_dev_info);
static struct class *bdi_class;
+DEFINE_SPINLOCK(bdi_lock);
+LIST_HEAD(bdi_list);
+LIST_HEAD(bdi_pending_list);
+
+static struct task_struct *sync_supers_tsk;
+static struct timer_list sync_supers_timer;
+
+static int bdi_sync_supers(void *);
+static void sync_supers_timer_fn(unsigned long);
+static void arm_supers_timer(void);
+
+static void bdi_add_default_flusher_task(struct backing_dev_info *bdi);
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
@@ -37,9 +53,29 @@ static void bdi_debug_init(void)
static int bdi_debug_stats_show(struct seq_file *m, void *v)
{
struct backing_dev_info *bdi = m->private;
+ struct bdi_writeback *wb;
unsigned long background_thresh;
unsigned long dirty_thresh;
unsigned long bdi_thresh;
+ unsigned long nr_dirty, nr_io, nr_more_io, nr_wb;
+ struct inode *inode;
+
+ /*
+ * inode lock is enough here, the bdi->wb_list is protected by
+ * RCU on the reader side
+ */
+ nr_wb = nr_dirty = nr_io = nr_more_io = 0;
+ spin_lock(&inode_lock);
+ list_for_each_entry(wb, &bdi->wb_list, list) {
+ nr_wb++;
+ list_for_each_entry(inode, &wb->b_dirty, i_list)
+ nr_dirty++;
+ list_for_each_entry(inode, &wb->b_io, i_list)
+ nr_io++;
+ list_for_each_entry(inode, &wb->b_more_io, i_list)
+ nr_more_io++;
+ }
+ spin_unlock(&inode_lock);
get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi);
@@ -49,12 +85,22 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
"BdiReclaimable: %8lu kB\n"
"BdiDirtyThresh: %8lu kB\n"
"DirtyThresh: %8lu kB\n"
- "BackgroundThresh: %8lu kB\n",
+ "BackgroundThresh: %8lu kB\n"
+ "WriteBack threads:%8lu\n"
+ "b_dirty: %8lu\n"
+ "b_io: %8lu\n"
+ "b_more_io: %8lu\n"
+ "bdi_list: %8u\n"
+ "state: %8lx\n"
+ "wb_mask: %8lx\n"
+ "wb_list: %8u\n"
+ "wb_cnt: %8u\n",
(unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)),
(unsigned long) K(bdi_stat(bdi, BDI_RECLAIMABLE)),
- K(bdi_thresh),
- K(dirty_thresh),
- K(background_thresh));
+ K(bdi_thresh), K(dirty_thresh),
+ K(background_thresh), nr_wb, nr_dirty, nr_io, nr_more_io,
+ !list_empty(&bdi->bdi_list), bdi->state, bdi->wb_mask,
+ !list_empty(&bdi->wb_list), bdi->wb_cnt);
#undef K
return 0;
@@ -185,6 +231,13 @@ static int __init default_bdi_init(void)
{
int err;
+ sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
+ BUG_ON(IS_ERR(sync_supers_tsk));
+
+ init_timer(&sync_supers_timer);
+ setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
+ arm_supers_timer();
+
err = bdi_init(&default_backing_dev_info);
if (!err)
bdi_register(&default_backing_dev_info, NULL, "default");
@@ -193,6 +246,390 @@ static int __init default_bdi_init(void)
}
subsys_initcall(default_bdi_init);
+static int wb_assign_nr(struct backing_dev_info *bdi, struct bdi_writeback *wb)
+{
+ unsigned long mask = BDI_MAX_FLUSHERS - 1;
+ unsigned int nr;
+
+ do {
+ if ((bdi->wb_mask & mask) == mask)
+ return 1;
+
+ nr = find_first_zero_bit(&bdi->wb_mask, BDI_MAX_FLUSHERS);
+ } while (test_and_set_bit(nr, &bdi->wb_mask));
+
+ wb->nr = nr;
+
+ spin_lock(&bdi->wb_lock);
+ bdi->wb_cnt++;
+ spin_unlock(&bdi->wb_lock);
+
+ return 0;
+}
+
+static void bdi_put_wb(struct backing_dev_info *bdi, struct bdi_writeback *wb)
+{
+ /*
+ * If this is the default wb thread exiting, leave the bit set
+ * in the wb mask as we set that before it's created as well. This
+ * is done to make sure that assigned work with no thread has at
+ * least one receipient.
+ */
+ if (wb == &bdi->wb)
+ clear_bit(BDI_wb_alloc, &bdi->state);
+ else {
+ clear_bit(wb->nr, &bdi->wb_mask);
+ kfree(wb);
+ spin_lock(&bdi->wb_lock);
+ bdi->wb_cnt--;
+ spin_unlock(&bdi->wb_lock);
+ }
+}
+
+static int bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi)
+{
+ memset(wb, 0, sizeof(*wb));
+
+ wb->bdi = bdi;
+ INIT_LIST_HEAD(&wb->b_dirty);
+ INIT_LIST_HEAD(&wb->b_io);
+ INIT_LIST_HEAD(&wb->b_more_io);
+
+ return wb_assign_nr(bdi, wb);
+}
+
+static struct bdi_writeback *bdi_new_wb(struct backing_dev_info *bdi)
+{
+ struct bdi_writeback *wb;
+
+ /*
+ * Default bdi->wb is already assigned, so just return it
+ */
+ if (!test_and_set_bit(BDI_wb_alloc, &bdi->state))
+ wb = &bdi->wb;
+ else {
+ wb = kmalloc(sizeof(struct bdi_writeback), GFP_KERNEL);
+ if (wb) {
+ if (bdi_wb_init(wb, bdi)) {
+ kfree(wb);
+ wb = NULL;
+ }
+ }
+ }
+
+ return wb;
+}
+
+static void bdi_task_init(struct backing_dev_info *bdi,
+ struct bdi_writeback *wb)
+{
+ struct task_struct *tsk = current;
+ int was_empty;
+
+ /*
+ * Add us to the active bdi_list. If we are adding threads beyond
+ * the default embedded bdi_writeback, then we need to start using
+ * proper locking. Check the list for empty first, then set the
+ * BDI_wblist_lock flag if there's > 1 entry on the list now
+ */
+ spin_lock(&bdi->wb_lock);
+
+ was_empty = list_empty(&bdi->wb_list);
+ list_add_tail_rcu(&wb->list, &bdi->wb_list);
+ if (!was_empty)
+ set_bit(BDI_wblist_lock, &bdi->state);
+
+ spin_unlock(&bdi->wb_lock);
+
+ tsk->flags |= PF_FLUSHER | PF_SWAPWRITE;
+ set_freezable();
+
+ /*
+ * Our parent may run at a different priority, just set us to normal
+ */
+ set_user_nice(tsk, 0);
+}
+
+static int bdi_start_fn(void *ptr)
+{
+ struct bdi_writeback *wb = ptr;
+ struct backing_dev_info *bdi = wb->bdi;
+ int ret;
+
+ /*
+ * Add us to the active bdi_list
+ */
+ spin_lock(&bdi_lock);
+ list_add(&bdi->bdi_list, &bdi_list);
+ spin_unlock(&bdi_lock);
+
+ bdi_task_init(bdi, wb);
+
+ /*
+ * Clear pending bit and wakeup anybody waiting to tear us down
+ */
+ clear_bit(BDI_pending, &bdi->state);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&bdi->state, BDI_pending);
+
+ ret = bdi_writeback_task(wb);
+
+ /*
+ * Remove us from the list
+ */
+ spin_lock(&bdi->wb_lock);
+ list_del_rcu(&wb->list);
+ spin_unlock(&bdi->wb_lock);
+
+ /*
+ * wait for rcu grace period to end, so we can free wb
+ */
+ synchronize_srcu(&bdi->srcu);
+
+ /*
+ * Flush any work that raced with us exiting. No new work
+ * will be added, since this bdi isn't discoverable anymore.
+ */
+ if (!list_empty(&bdi->work_list))
+ wb_do_writeback(wb, 1);
+
+ wb->task = NULL;
+ bdi_put_wb(bdi, wb);
+ return ret;
+}
+
+int bdi_has_dirty_io(struct backing_dev_info *bdi)
+{
+ struct bdi_writeback *wb;
+ int ret = 0;
+
+ if (!bdi_wblist_needs_lock(bdi))
+ ret = wb_has_dirty_io(&bdi->wb);
+ else {
+ int idx;
+
+ idx = srcu_read_lock(&bdi->srcu);
+
+ list_for_each_entry_rcu(wb, &bdi->wb_list, list) {
+ ret = wb_has_dirty_io(wb);
+ if (ret)
+ break;
+ }
+
+ srcu_read_unlock(&bdi->srcu, idx);
+ }
+
+ return ret;
+}
+
+static void bdi_flush_io(struct backing_dev_info *bdi)
+{
+ struct writeback_control wbc = {
+ .bdi = bdi,
+ .sync_mode = WB_SYNC_NONE,
+ .older_than_this = NULL,
+ .range_cyclic = 1,
+ .nr_to_write = 1024,
+ };
+
+ generic_sync_bdi_inodes(NULL, &wbc);
+}
+
+/*
+ * kupdated() used to do this. We cannot do it from the bdi_forker_task()
+ * or we risk deadlocking on ->s_umount. The longer term solution would be
+ * to implement sync_supers_bdi() or similar and simply do it from the
+ * bdi writeback tasks individually.
+ */
+static int bdi_sync_supers(void *unused)
+{
+ set_user_nice(current, 0);
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ /*
+ * Do this periodically, like kupdated() did before.
+ */
+ sync_supers();
+ }
+
+ return 0;
+}
+
+static void arm_supers_timer(void)
+{
+ unsigned long next;
+
+ next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
+ mod_timer(&sync_supers_timer, round_jiffies_up(next));
+}
+
+static void sync_supers_timer_fn(unsigned long unused)
+{
+ wake_up_process(sync_supers_tsk);
+ arm_supers_timer();
+}
+
+static int bdi_forker_task(void *ptr)
+{
+ struct bdi_writeback *me = ptr;
+
+ bdi_task_init(me->bdi, me);
+
+ for (;;) {
+ struct backing_dev_info *bdi, *tmp;
+ struct bdi_writeback *wb;
+
+ /*
+ * Temporary measure, we want to make sure we don't see
+ * dirty data on the default backing_dev_info
+ */
+ if (wb_has_dirty_io(me) || !list_empty(&me->bdi->work_list))
+ wb_do_writeback(me, 0);
+
+ spin_lock(&bdi_lock);
+
+ /*
+ * Check if any existing bdi's have dirty data without
+ * a thread registered. If so, set that up.
+ */
+ list_for_each_entry_safe(bdi, tmp, &bdi_list, bdi_list) {
+ if (bdi->wb.task)
+ continue;
+ if (list_empty(&bdi->work_list) &&
+ !bdi_has_dirty_io(bdi))
+ continue;
+
+ bdi_add_default_flusher_task(bdi);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (list_empty(&bdi_pending_list)) {
+ unsigned long wait;
+
+ spin_unlock(&bdi_lock);
+ wait = msecs_to_jiffies(dirty_writeback_interval * 10);
+ schedule_timeout(wait);
+ try_to_freeze();
+ continue;
+ }
+
+ __set_current_state(TASK_RUNNING);
+
+ /*
+ * This is our real job - check for pending entries in
+ * bdi_pending_list, and create the tasks that got added
+ */
+ bdi = list_entry(bdi_pending_list.next, struct backing_dev_info,
+ bdi_list);
+ list_del_init(&bdi->bdi_list);
+ spin_unlock(&bdi_lock);
+
+ wb = bdi_new_wb(bdi);
+ if (!wb)
+ goto readd_flush;
+
+ wb->task = kthread_run(bdi_start_fn, wb, "flush-%s",
+ dev_name(bdi->dev));
+ /*
+ * If task creation fails, then readd the bdi to
+ * the pending list and force writeout of the bdi
+ * from this forker thread. That will free some memory
+ * and we can try again.
+ */
+ if (IS_ERR(wb->task)) {
+ wb->task = NULL;
+ bdi_put_wb(bdi, wb);
+readd_flush:
+ /*
+ * Add this 'bdi' to the back, so we get
+ * a chance to flush other bdi's to free
+ * memory.
+ */
+ spin_lock(&bdi_lock);
+ list_add_tail(&bdi->bdi_list, &bdi_pending_list);
+ spin_unlock(&bdi_lock);
+
+ bdi_flush_io(bdi);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * bdi_lock held on entry
+ */
+static void bdi_add_one_flusher_task(struct backing_dev_info *bdi,
+ int(*func)(struct backing_dev_info *))
+{
+ if (!bdi_cap_writeback_dirty(bdi))
+ return;
+
+ if (WARN_ON(!test_bit(BDI_registered, &bdi->state))) {
+ printk("bdi %p/%s is not registered!\n", bdi, bdi->name);
+ return;
+ }
+
+ /*
+ * Check with the helper whether to proceed adding a task. Will only
+ * abort if we two or more simultanous calls to
+ * bdi_add_default_flusher_task() occured, further additions will block
+ * waiting for previous additions to finish.
+ */
+ if (!func(bdi)) {
+ list_move_tail(&bdi->bdi_list, &bdi_pending_list);
+
+ /*
+ * We are now on the pending list, wake up bdi_forker_task()
+ * to finish the job and add us back to the active bdi_list
+ */
+ wake_up_process(default_backing_dev_info.wb.task);
+ }
+}
+
+static int flusher_add_helper_block(struct backing_dev_info *bdi)
+{
+ spin_unlock(&bdi_lock);
+ wait_on_bit_lock(&bdi->state, BDI_pending, bdi_sched_wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_lock(&bdi_lock);
+ return 0;
+}
+
+static int flusher_add_helper_test(struct backing_dev_info *bdi)
+{
+ return test_and_set_bit(BDI_pending, &bdi->state);
+}
+
+/*
+ * Add the default flusher task that gets created for any bdi
+ * that has dirty data pending writeout
+ */
+void static bdi_add_default_flusher_task(struct backing_dev_info *bdi)
+{
+ bdi_add_one_flusher_task(bdi, flusher_add_helper_test);
+}
+
+/**
+ * bdi_add_flusher_task - add one more flusher task to this @bdi
+ * @bdi: the bdi
+ *
+ * Add an additional flusher task to this @bdi. Will block waiting on
+ * previous additions, if any.
+ *
+ */
+void bdi_add_flusher_task(struct backing_dev_info *bdi)
+{
+ spin_lock(&bdi_lock);
+ bdi_add_one_flusher_task(bdi, flusher_add_helper_block);
+ spin_unlock(&bdi_lock);
+}
+EXPORT_SYMBOL(bdi_add_flusher_task);
+
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
const char *fmt, ...)
{
@@ -211,9 +648,42 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
goto exit;
}
+ spin_lock(&bdi_lock);
+ list_add_tail(&bdi->bdi_list, &bdi_list);
+ spin_unlock(&bdi_lock);
+
bdi->dev = dev;
- bdi_debug_register(bdi, dev_name(dev));
+ /*
+ * Just start the forker thread for our default backing_dev_info,
+ * and add other bdi's to the list. They will get a thread created
+ * on-demand when they need it.
+ */
+ if (bdi_cap_flush_forker(bdi)) {
+ struct bdi_writeback *wb;
+
+ wb = bdi_new_wb(bdi);
+ if (!wb) {
+ ret = -ENOMEM;
+ goto remove_err;
+ }
+
+ wb->task = kthread_run(bdi_forker_task, wb, "bdi-%s",
+ dev_name(dev));
+ if (IS_ERR(wb->task)) {
+ wb->task = NULL;
+ bdi_put_wb(bdi, wb);
+ ret = -ENOMEM;
+remove_err:
+ spin_lock(&bdi_lock);
+ list_del(&bdi->bdi_list);
+ spin_unlock(&bdi_lock);
+ goto exit;
+ }
+ }
+
+ bdi_debug_register(bdi, dev_name(dev));
+ set_bit(BDI_registered, &bdi->state);
exit:
return ret;
}
@@ -225,9 +695,42 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
}
EXPORT_SYMBOL(bdi_register_dev);
+/*
+ * Remove bdi from the global list and shutdown any threads we have running
+ */
+static void bdi_wb_shutdown(struct backing_dev_info *bdi)
+{
+ struct bdi_writeback *wb;
+
+ if (!bdi_cap_writeback_dirty(bdi))
+ return;
+
+ /*
+ * If setup is pending, wait for that to complete first
+ */
+ wait_on_bit(&bdi->state, BDI_pending, bdi_sched_wait,
+ TASK_UNINTERRUPTIBLE);
+
+ /*
+ * Make sure nobody finds us on the bdi_list anymore
+ */
+ spin_lock(&bdi_lock);
+ list_del(&bdi->bdi_list);
+ spin_unlock(&bdi_lock);
+
+ /*
+ * Finally, kill the kernel threads. We don't need to be RCU
+ * safe anymore, since the bdi is gone from visibility.
+ */
+ list_for_each_entry(wb, &bdi->wb_list, list)
+ kthread_stop(wb->task);
+}
+
void bdi_unregister(struct backing_dev_info *bdi)
{
if (bdi->dev) {
+ if (!bdi_cap_flush_forker(bdi))
+ bdi_wb_shutdown(bdi);
bdi_debug_unregister(bdi);
device_unregister(bdi->dev);
bdi->dev = NULL;
@@ -237,14 +740,21 @@ EXPORT_SYMBOL(bdi_unregister);
int bdi_init(struct backing_dev_info *bdi)
{
- int i;
- int err;
+ int i, err;
bdi->dev = NULL;
bdi->min_ratio = 0;
bdi->max_ratio = 100;
bdi->max_prop_frac = PROP_FRAC_BASE;
+ spin_lock_init(&bdi->wb_lock);
+ bdi->wb_mask = 0;
+ bdi->wb_cnt = 0;
+ INIT_LIST_HEAD(&bdi->bdi_list);
+ INIT_LIST_HEAD(&bdi->wb_list);
+ INIT_LIST_HEAD(&bdi->work_list);
+
+ bdi_wb_init(&bdi->wb, bdi);
for (i = 0; i < NR_BDI_STAT_ITEMS; i++) {
err = percpu_counter_init(&bdi->bdi_stat[i], 0);
@@ -252,10 +762,15 @@ int bdi_init(struct backing_dev_info *bdi)
goto err;
}
+ err = init_srcu_struct(&bdi->srcu);
+ if (err)
+ goto err;
+
bdi->dirty_exceeded = 0;
err = prop_local_init_percpu(&bdi->completions);
if (err) {
+ cleanup_srcu_struct(&bdi->srcu);
err:
while (i--)
percpu_counter_destroy(&bdi->bdi_stat[i]);
@@ -269,8 +784,12 @@ void bdi_destroy(struct backing_dev_info *bdi)
{
int i;
+ WARN_ON(bdi_has_dirty_io(bdi));
+
bdi_unregister(bdi);
+ cleanup_srcu_struct(&bdi->srcu);
+
for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
percpu_counter_destroy(&bdi->bdi_stat[i]);
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 701740c9e81b..555d5d2731c6 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -521,7 +521,11 @@ find_block:
region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
start_off);
memset(region, 0, size);
- kmemleak_alloc(region, size, 1, 0);
+ /*
+ * The min_count is set to 0 so that bootmem allocated blocks
+ * are never reported as leaks.
+ */
+ kmemleak_alloc(region, size, 0, 0);
return region;
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index d0351e31f474..b16d63634777 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -234,6 +234,7 @@ unsigned long vma_kernel_pagesize(struct vm_area_struct *vma)
return 1UL << (hstate->order + PAGE_SHIFT);
}
+EXPORT_SYMBOL_GPL(vma_kernel_pagesize);
/*
* Return the page size being used by the MMU to back a VMA. In the majority
@@ -2370,7 +2371,7 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
long chg = region_truncate(&inode->i_mapping->private_list, offset);
spin_lock(&inode->i_lock);
- inode->i_blocks -= blocks_per_huge_page(h);
+ inode->i_blocks -= (blocks_per_huge_page(h) * freed);
spin_unlock(&inode->i_lock);
hugetlb_put_quota(inode->i_mapping, (chg - freed));
diff --git a/mm/kmemleak-test.c b/mm/kmemleak-test.c
index d5292fc6f523..177a5169bbde 100644
--- a/mm/kmemleak-test.c
+++ b/mm/kmemleak-test.c
@@ -36,7 +36,7 @@ struct test_node {
};
static LIST_HEAD(test_list);
-static DEFINE_PER_CPU(void *, test_pointer);
+static DEFINE_PER_CPU(void *, kmemleak_test_pointer);
/*
* Some very simple testing. This function needs to be extended for
@@ -86,9 +86,9 @@ static int __init kmemleak_test_init(void)
}
for_each_possible_cpu(i) {
- per_cpu(test_pointer, i) = kmalloc(129, GFP_KERNEL);
+ per_cpu(kmemleak_test_pointer, i) = kmalloc(129, GFP_KERNEL);
pr_info("kmemleak: kmalloc(129) = %p\n",
- per_cpu(test_pointer, i));
+ per_cpu(kmemleak_test_pointer, i));
}
return 0;
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 5aabd41ffb8f..752a27678474 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -107,6 +107,7 @@
#define SECS_FIRST_SCAN 60 /* delay before the first scan */
#define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */
#define GRAY_LIST_PASSES 25 /* maximum number of gray list scans */
+#define MAX_SCAN_SIZE 4096 /* maximum size of a scanned block */
#define BYTES_PER_POINTER sizeof(void *)
@@ -161,6 +162,15 @@ struct kmemleak_object {
/* flag set on newly allocated objects */
#define OBJECT_NEW (1 << 3)
+/* number of bytes to print per line; must be 16 or 32 */
+#define HEX_ROW_SIZE 16
+/* number of bytes to print at a time (1, 2, 4, 8) */
+#define HEX_GROUP_SIZE 1
+/* include ASCII after the hex output */
+#define HEX_ASCII 1
+/* max number of lines to be printed */
+#define HEX_MAX_LINES 2
+
/* the list of all allocated objects */
static LIST_HEAD(object_list);
/* the list of gray-colored objects (see color_gray comment below) */
@@ -193,8 +203,6 @@ static unsigned long jiffies_min_age;
static unsigned long jiffies_last_scan;
/* delay between automatic memory scannings */
static signed long jiffies_scan_wait;
-/* enables or disables the task stacks scanning */
-static int kmemleak_stack_scan = 1;
/* protects the memory scanning, parameters and debug/kmemleak file access */
static DEFINE_MUTEX(scan_mutex);
@@ -228,11 +236,14 @@ struct early_log {
int min_count; /* minimum reference count */
unsigned long offset; /* scan area offset */
size_t length; /* scan area length */
+ unsigned long trace[MAX_TRACE]; /* stack trace */
+ unsigned int trace_len; /* stack trace length */
};
/* early logging buffer and current position */
-static struct early_log early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE];
-static int crt_early_log;
+static struct early_log
+ early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE] __initdata;
+static int crt_early_log __initdata;
static void kmemleak_disable(void);
@@ -255,6 +266,35 @@ static void kmemleak_disable(void);
} while (0)
/*
+ * Printing of the objects hex dump to the seq file. The number of lines to be
+ * printed is limited to HEX_MAX_LINES to prevent seq file spamming. The
+ * actual number of printed bytes depends on HEX_ROW_SIZE. It must be called
+ * with the object->lock held.
+ */
+static void hex_dump_object(struct seq_file *seq,
+ struct kmemleak_object *object)
+{
+ const u8 *ptr = (const u8 *)object->pointer;
+ int i, len, remaining;
+ unsigned char linebuf[HEX_ROW_SIZE * 5];
+
+ /* limit the number of lines to HEX_MAX_LINES */
+ remaining = len =
+ min(object->size, (size_t)(HEX_MAX_LINES * HEX_ROW_SIZE));
+
+ seq_printf(seq, " hex dump (first %d bytes):\n", len);
+ for (i = 0; i < len; i += HEX_ROW_SIZE) {
+ int linelen = min(remaining, HEX_ROW_SIZE);
+
+ remaining -= HEX_ROW_SIZE;
+ hex_dump_to_buffer(ptr + i, linelen, HEX_ROW_SIZE,
+ HEX_GROUP_SIZE, linebuf, sizeof(linebuf),
+ HEX_ASCII);
+ seq_printf(seq, " %s\n", linebuf);
+ }
+}
+
+/*
* Object colors, encoded with count and min_count:
* - white - orphan object, not enough references to it (count < min_count)
* - gray - not orphan, not marked as false positive (min_count == 0) or
@@ -304,6 +344,7 @@ static void print_unreferenced(struct seq_file *seq,
object->pointer, object->size);
seq_printf(seq, " comm \"%s\", pid %d, jiffies %lu\n",
object->comm, object->pid, object->jiffies);
+ hex_dump_object(seq, object);
seq_printf(seq, " backtrace:\n");
for (i = 0; i < object->trace_len; i++) {
@@ -330,6 +371,7 @@ static void dump_object_info(struct kmemleak_object *object)
object->comm, object->pid, object->jiffies);
pr_notice(" min_count = %d\n", object->min_count);
pr_notice(" count = %d\n", object->count);
+ pr_notice(" flags = 0x%lx\n", object->flags);
pr_notice(" backtrace:\n");
print_stack_trace(&trace, 4);
}
@@ -434,21 +476,36 @@ static struct kmemleak_object *find_and_get_object(unsigned long ptr, int alias)
}
/*
+ * Save stack trace to the given array of MAX_TRACE size.
+ */
+static int __save_stack_trace(unsigned long *trace)
+{
+ struct stack_trace stack_trace;
+
+ stack_trace.max_entries = MAX_TRACE;
+ stack_trace.nr_entries = 0;
+ stack_trace.entries = trace;
+ stack_trace.skip = 2;
+ save_stack_trace(&stack_trace);
+
+ return stack_trace.nr_entries;
+}
+
+/*
* Create the metadata (struct kmemleak_object) corresponding to an allocated
* memory block and add it to the object_list and object_tree_root.
*/
-static void create_object(unsigned long ptr, size_t size, int min_count,
- gfp_t gfp)
+static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
+ int min_count, gfp_t gfp)
{
unsigned long flags;
struct kmemleak_object *object;
struct prio_tree_node *node;
- struct stack_trace trace;
object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK);
if (!object) {
kmemleak_stop("Cannot allocate a kmemleak_object structure\n");
- return;
+ return NULL;
}
INIT_LIST_HEAD(&object->object_list);
@@ -482,12 +539,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
}
/* kernel backtrace */
- trace.max_entries = MAX_TRACE;
- trace.nr_entries = 0;
- trace.entries = object->trace;
- trace.skip = 1;
- save_stack_trace(&trace);
- object->trace_len = trace.nr_entries;
+ object->trace_len = __save_stack_trace(object->trace);
INIT_PRIO_TREE_NODE(&object->tree_node);
object->tree_node.start = ptr;
@@ -518,6 +570,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
list_add_tail_rcu(&object->object_list, &object_list);
out:
write_unlock_irqrestore(&kmemleak_lock, flags);
+ return object;
}
/*
@@ -715,8 +768,8 @@ static void object_no_scan(unsigned long ptr)
* Log an early kmemleak_* call to the early_log buffer. These calls will be
* processed later once kmemleak is fully initialized.
*/
-static void log_early(int op_type, const void *ptr, size_t size,
- int min_count, unsigned long offset, size_t length)
+static void __init log_early(int op_type, const void *ptr, size_t size,
+ int min_count, unsigned long offset, size_t length)
{
unsigned long flags;
struct early_log *log;
@@ -739,16 +792,45 @@ static void log_early(int op_type, const void *ptr, size_t size,
log->min_count = min_count;
log->offset = offset;
log->length = length;
+ if (op_type == KMEMLEAK_ALLOC)
+ log->trace_len = __save_stack_trace(log->trace);
crt_early_log++;
local_irq_restore(flags);
}
/*
+ * Log an early allocated block and populate the stack trace.
+ */
+static void early_alloc(struct early_log *log)
+{
+ struct kmemleak_object *object;
+ unsigned long flags;
+ int i;
+
+ if (!atomic_read(&kmemleak_enabled) || !log->ptr || IS_ERR(log->ptr))
+ return;
+
+ /*
+ * RCU locking needed to ensure object is not freed via put_object().
+ */
+ rcu_read_lock();
+ object = create_object((unsigned long)log->ptr, log->size,
+ log->min_count, GFP_KERNEL);
+ 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);
+ rcu_read_unlock();
+}
+
+/*
* Memory allocation function callback. This function is called from the
* kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc,
* vmalloc etc.).
*/
-void kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp)
+void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
+ gfp_t gfp)
{
pr_debug("%s(0x%p, %zu, %d)\n", __func__, ptr, size, min_count);
@@ -763,7 +845,7 @@ EXPORT_SYMBOL_GPL(kmemleak_alloc);
* Memory freeing function callback. This function is called from the kernel
* allocators when a block is freed (kmem_cache_free, kfree, vfree etc.).
*/
-void kmemleak_free(const void *ptr)
+void __ref kmemleak_free(const void *ptr)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -778,7 +860,7 @@ EXPORT_SYMBOL_GPL(kmemleak_free);
* Partial memory freeing function callback. This function is usually called
* from bootmem allocator when (part of) a memory block is freed.
*/
-void kmemleak_free_part(const void *ptr, size_t size)
+void __ref kmemleak_free_part(const void *ptr, size_t size)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -793,7 +875,7 @@ EXPORT_SYMBOL_GPL(kmemleak_free_part);
* Mark an already allocated memory block as a false positive. This will cause
* the block to no longer be reported as leak and always be scanned.
*/
-void kmemleak_not_leak(const void *ptr)
+void __ref kmemleak_not_leak(const void *ptr)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -809,7 +891,7 @@ EXPORT_SYMBOL(kmemleak_not_leak);
* corresponding block is not a leak and does not contain any references to
* other allocated memory blocks.
*/
-void kmemleak_ignore(const void *ptr)
+void __ref kmemleak_ignore(const void *ptr)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -823,8 +905,8 @@ EXPORT_SYMBOL(kmemleak_ignore);
/*
* Limit the range to be scanned in an allocated memory block.
*/
-void kmemleak_scan_area(const void *ptr, unsigned long offset, size_t length,
- gfp_t gfp)
+void __ref kmemleak_scan_area(const void *ptr, unsigned long offset,
+ size_t length, gfp_t gfp)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -838,7 +920,7 @@ EXPORT_SYMBOL(kmemleak_scan_area);
/*
* Inform kmemleak not to scan the given memory block.
*/
-void kmemleak_no_scan(const void *ptr)
+void __ref kmemleak_no_scan(const void *ptr)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
@@ -949,10 +1031,20 @@ static void scan_object(struct kmemleak_object *object)
if (!(object->flags & OBJECT_ALLOCATED))
/* already freed object */
goto out;
- if (hlist_empty(&object->area_list))
- scan_block((void *)object->pointer,
- (void *)(object->pointer + object->size), object, 0);
- else
+ if (hlist_empty(&object->area_list)) {
+ void *start = (void *)object->pointer;
+ void *end = (void *)(object->pointer + object->size);
+
+ while (start < end && (object->flags & OBJECT_ALLOCATED)) {
+ scan_block(start, min(start + MAX_SCAN_SIZE, end),
+ object, 0);
+ start += MAX_SCAN_SIZE;
+
+ spin_unlock_irqrestore(&object->lock, flags);
+ cond_resched();
+ spin_lock_irqsave(&object->lock, flags);
+ }
+ } else
hlist_for_each_entry(area, elem, &object->area_list, node)
scan_block((void *)(object->pointer + area->offset),
(void *)(object->pointer + area->offset
@@ -970,7 +1062,6 @@ static void kmemleak_scan(void)
{
unsigned long flags;
struct kmemleak_object *object, *tmp;
- struct task_struct *task;
int i;
int new_leaks = 0;
int gray_list_pass = 0;
@@ -1037,19 +1128,6 @@ static void kmemleak_scan(void)
}
/*
- * Scanning the task stacks may introduce false negatives and it is
- * not enabled by default.
- */
- if (kmemleak_stack_scan) {
- read_lock(&tasklist_lock);
- for_each_process(task)
- scan_block(task_stack_page(task),
- task_stack_page(task) + THREAD_SIZE,
- NULL, 0);
- read_unlock(&tasklist_lock);
- }
-
- /*
* Scan the objects already referenced from the sections scanned
* above. More objects will be referenced and, if there are no memory
* leaks, all the objects will be scanned. The list traversal is safe
@@ -1217,7 +1295,6 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos)
}
object = NULL;
out:
- rcu_read_unlock();
return object;
}
@@ -1233,13 +1310,11 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++(*pos);
- rcu_read_lock();
list_for_each_continue_rcu(n, &object_list) {
next_obj = list_entry(n, struct kmemleak_object, object_list);
if (get_object(next_obj))
break;
}
- rcu_read_unlock();
put_object(prev_obj);
return next_obj;
@@ -1255,6 +1330,7 @@ static void kmemleak_seq_stop(struct seq_file *seq, void *v)
* kmemleak_seq_start may return ERR_PTR if the scan_mutex
* waiting was interrupted, so only release it if !IS_ERR.
*/
+ rcu_read_unlock();
mutex_unlock(&scan_mutex);
if (v)
put_object(v);
@@ -1296,17 +1372,37 @@ static int kmemleak_release(struct inode *inode, struct file *file)
return seq_release(inode, file);
}
+static int dump_str_object_info(const char *str)
+{
+ unsigned long flags;
+ struct kmemleak_object *object;
+ unsigned long addr;
+
+ addr= simple_strtoul(str, NULL, 0);
+ object = find_and_get_object(addr, 0);
+ if (!object) {
+ pr_info("Unknown object at 0x%08lx\n", addr);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&object->lock, flags);
+ dump_object_info(object);
+ spin_unlock_irqrestore(&object->lock, flags);
+
+ put_object(object);
+ return 0;
+}
+
/*
* File write operation to configure kmemleak at run-time. The following
* commands can be written to the /sys/kernel/debug/kmemleak file:
* off - disable kmemleak (irreversible)
- * stack=on - enable the task stacks scanning
- * stack=off - disable the tasks stacks scanning
* scan=on - start the automatic memory scanning thread
* scan=off - stop the automatic memory scanning thread
* scan=... - set the automatic memory scanning period in seconds (0 to
* disable it)
* scan - trigger a memory scan
+ * dump=... - dump information about the object found at the given address
*/
static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
size_t size, loff_t *ppos)
@@ -1326,10 +1422,6 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
if (strncmp(buf, "off", 3) == 0)
kmemleak_disable();
- else if (strncmp(buf, "stack=on", 8) == 0)
- kmemleak_stack_scan = 1;
- else if (strncmp(buf, "stack=off", 9) == 0)
- kmemleak_stack_scan = 0;
else if (strncmp(buf, "scan=on", 7) == 0)
start_scan_thread();
else if (strncmp(buf, "scan=off", 8) == 0)
@@ -1347,6 +1439,8 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
}
} else if (strncmp(buf, "scan", 4) == 0)
kmemleak_scan();
+ else if (strncmp(buf, "dump=", 5) == 0)
+ ret = dump_str_object_info(buf + 5);
else
ret = -EINVAL;
@@ -1471,8 +1565,7 @@ void __init kmemleak_init(void)
switch (log->op_type) {
case KMEMLEAK_ALLOC:
- kmemleak_alloc(log->ptr, log->size, log->min_count,
- GFP_KERNEL);
+ early_alloc(log);
break;
case KMEMLEAK_FREE:
kmemleak_free(log->ptr);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e717964cb5a0..fd4529d86de5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1207,6 +1207,12 @@ static int mem_cgroup_move_account(struct page_cgroup *pc,
ret = 0;
out:
unlock_page_cgroup(pc);
+ /*
+ * We charges against "to" which may not have any tasks. Then, "to"
+ * can be under rmdir(). But in current implementation, caller of
+ * this function is just force_empty() and it's garanteed that
+ * "to" is never removed. So, we don't check rmdir status here.
+ */
return ret;
}
@@ -1428,6 +1434,7 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
return;
if (!ptr)
return;
+ cgroup_exclude_rmdir(&ptr->css);
pc = lookup_page_cgroup(page);
mem_cgroup_lru_del_before_commit_swapcache(page);
__mem_cgroup_commit_charge(ptr, pc, ctype);
@@ -1457,8 +1464,12 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
}
rcu_read_unlock();
}
- /* add this page(page_cgroup) to the LRU we want. */
-
+ /*
+ * At swapin, we may charge account against cgroup which has no tasks.
+ * So, rmdir()->pre_destroy() can be called while we do this charge.
+ * In that case, we need to call pre_destroy() again. check it here.
+ */
+ cgroup_release_and_wakeup_rmdir(&ptr->css);
}
void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
@@ -1664,7 +1675,7 @@ void mem_cgroup_end_migration(struct mem_cgroup *mem,
if (!mem)
return;
-
+ cgroup_exclude_rmdir(&mem->css);
/* at migration success, oldpage->mapping is NULL. */
if (oldpage->mapping) {
target = oldpage;
@@ -1704,6 +1715,12 @@ void mem_cgroup_end_migration(struct mem_cgroup *mem,
*/
if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
mem_cgroup_uncharge_page(target);
+ /*
+ * At migration, we may charge account against cgroup which has no tasks
+ * So, rmdir()->pre_destroy() can be called while we do this charge.
+ * In that case, we need to call pre_destroy() again. check it here.
+ */
+ cgroup_release_and_wakeup_rmdir(&mem->css);
}
/*
diff --git a/mm/memory.c b/mm/memory.c
index 65216194eb8d..aede2ce3aba4 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -135,11 +135,12 @@ void pmd_clear_bad(pmd_t *pmd)
* Note: this doesn't free the actual pages themselves. That
* has been handled earlier when unmapping all the memory regions.
*/
-static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd)
+static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
+ unsigned long addr)
{
pgtable_t token = pmd_pgtable(*pmd);
pmd_clear(pmd);
- pte_free_tlb(tlb, token);
+ pte_free_tlb(tlb, token, addr);
tlb->mm->nr_ptes--;
}
@@ -157,7 +158,7 @@ static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
next = pmd_addr_end(addr, end);
if (pmd_none_or_clear_bad(pmd))
continue;
- free_pte_range(tlb, pmd);
+ free_pte_range(tlb, pmd, addr);
} while (pmd++, addr = next, addr != end);
start &= PUD_MASK;
@@ -173,7 +174,7 @@ static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
pmd = pmd_offset(pud, start);
pud_clear(pud);
- pmd_free_tlb(tlb, pmd);
+ pmd_free_tlb(tlb, pmd, start);
}
static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
@@ -206,7 +207,7 @@ static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
pud = pud_offset(pgd, start);
pgd_clear(pgd);
- pud_free_tlb(tlb, pud);
+ pud_free_tlb(tlb, pud, start);
}
/*
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 81627ebcd313..3d0948234c7d 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -36,15 +36,6 @@
#include <linux/pagevec.h>
/*
- * The maximum number of pages to writeout in a single bdflush/kupdate
- * operation. We do this so we don't hold I_SYNC against an inode for
- * enormous amounts of time, which would block a userspace task which has
- * been forced to throttle against that inode. Also, the code reevaluates
- * the dirty each time it has written this many pages.
- */
-#define MAX_WRITEBACK_PAGES 1024
-
-/*
* After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
* will look to see if it needs to force writeback or throttling.
*/
@@ -117,8 +108,6 @@ EXPORT_SYMBOL(laptop_mode);
/* End of sysctl-exported parameters */
-static void background_writeout(unsigned long _min_pages);
-
/*
* Scale the writeback cache size proportional to the relative writeout speeds.
*
@@ -320,15 +309,13 @@ static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty)
/*
*
*/
-static DEFINE_SPINLOCK(bdi_lock);
static unsigned int bdi_min_ratio;
int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
{
int ret = 0;
- unsigned long flags;
- spin_lock_irqsave(&bdi_lock, flags);
+ spin_lock(&bdi_lock);
if (min_ratio > bdi->max_ratio) {
ret = -EINVAL;
} else {
@@ -340,27 +327,26 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
ret = -EINVAL;
}
}
- spin_unlock_irqrestore(&bdi_lock, flags);
+ spin_unlock(&bdi_lock);
return ret;
}
int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
{
- unsigned long flags;
int ret = 0;
if (max_ratio > 100)
return -EINVAL;
- spin_lock_irqsave(&bdi_lock, flags);
+ spin_lock(&bdi_lock);
if (bdi->min_ratio > max_ratio) {
ret = -EINVAL;
} else {
bdi->max_ratio = max_ratio;
bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
}
- spin_unlock_irqrestore(&bdi_lock, flags);
+ spin_unlock(&bdi_lock);
return ret;
}
@@ -546,7 +532,7 @@ static void balance_dirty_pages(struct address_space *mapping)
* up.
*/
if (bdi_nr_reclaimable > bdi_thresh) {
- writeback_inodes(&wbc);
+ generic_sync_bdi_inodes(NULL, &wbc);
pages_written += write_chunk - wbc.nr_to_write;
get_dirty_limits(&background_thresh, &dirty_thresh,
&bdi_thresh, bdi);
@@ -597,7 +583,7 @@ static void balance_dirty_pages(struct address_space *mapping)
(!laptop_mode && (global_page_state(NR_FILE_DIRTY)
+ global_page_state(NR_UNSTABLE_NFS)
> background_thresh)))
- pdflush_operation(background_writeout, 0);
+ bdi_start_writeback(bdi, NULL, 0, WB_SYNC_NONE);
}
void set_page_dirty_balance(struct page *page, int page_mkwrite)
@@ -610,6 +596,8 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite)
}
}
+static DEFINE_PER_CPU(unsigned long, bdp_ratelimits) = 0;
+
/**
* balance_dirty_pages_ratelimited_nr - balance dirty memory state
* @mapping: address_space which was dirtied
@@ -627,7 +615,6 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite)
void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
unsigned long nr_pages_dirtied)
{
- static DEFINE_PER_CPU(unsigned long, ratelimits) = 0;
unsigned long ratelimit;
unsigned long *p;
@@ -640,7 +627,7 @@ void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
* tasks in balance_dirty_pages(). Period.
*/
preempt_disable();
- p = &__get_cpu_var(ratelimits);
+ p = &__get_cpu_var(bdp_ratelimits);
*p += nr_pages_dirtied;
if (unlikely(*p >= ratelimit)) {
*p = 0;
@@ -682,152 +669,53 @@ void throttle_vm_writeout(gfp_t gfp_mask)
}
/*
- * writeback at least _min_pages, and keep writing until the amount of dirty
- * memory is less than the background threshold, or until we're all clean.
+ * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back
+ * the whole world.
*/
-static void background_writeout(unsigned long _min_pages)
+void wakeup_flusher_threads(long nr_pages)
{
- long min_pages = _min_pages;
struct writeback_control wbc = {
- .bdi = NULL,
.sync_mode = WB_SYNC_NONE,
.older_than_this = NULL,
- .nr_to_write = 0,
- .nonblocking = 1,
.range_cyclic = 1,
};
- for ( ; ; ) {
- unsigned long background_thresh;
- unsigned long dirty_thresh;
-
- get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);
- if (global_page_state(NR_FILE_DIRTY) +
- global_page_state(NR_UNSTABLE_NFS) < background_thresh
- && min_pages <= 0)
- break;
- wbc.more_io = 0;
- wbc.encountered_congestion = 0;
- wbc.nr_to_write = MAX_WRITEBACK_PAGES;
- wbc.pages_skipped = 0;
- writeback_inodes(&wbc);
- min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
- if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
- /* Wrote less than expected */
- if (wbc.encountered_congestion || wbc.more_io)
- congestion_wait(BLK_RW_ASYNC, HZ/10);
- else
- break;
- }
- }
-}
-
-/*
- * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back
- * the whole world. Returns 0 if a pdflush thread was dispatched. Returns
- * -1 if all pdflush threads were busy.
- */
-int wakeup_pdflush(long nr_pages)
-{
if (nr_pages == 0)
nr_pages = global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_UNSTABLE_NFS);
- return pdflush_operation(background_writeout, nr_pages);
+ wbc.nr_to_write = nr_pages;
+ bdi_writeback_all(NULL, &wbc);
}
-static void wb_timer_fn(unsigned long unused);
static void laptop_timer_fn(unsigned long unused);
-static DEFINE_TIMER(wb_timer, wb_timer_fn, 0, 0);
static DEFINE_TIMER(laptop_mode_wb_timer, laptop_timer_fn, 0, 0);
/*
- * Periodic writeback of "old" data.
- *
- * Define "old": the first time one of an inode's pages is dirtied, we mark the
- * dirtying-time in the inode's address_space. So this periodic writeback code
- * just walks the superblock inode list, writing back any inodes which are
- * older than a specific point in time.
- *
- * Try to run once per dirty_writeback_interval. But if a writeback event
- * takes longer than a dirty_writeback_interval interval, then leave a
- * one-second gap.
- *
- * older_than_this takes precedence over nr_to_write. So we'll only write back
- * all dirty pages if they are all attached to "old" mappings.
- */
-static void wb_kupdate(unsigned long arg)
-{
- unsigned long oldest_jif;
- unsigned long start_jif;
- unsigned long next_jif;
- long nr_to_write;
- struct writeback_control wbc = {
- .bdi = NULL,
- .sync_mode = WB_SYNC_NONE,
- .older_than_this = &oldest_jif,
- .nr_to_write = 0,
- .nonblocking = 1,
- .for_kupdate = 1,
- .range_cyclic = 1,
- };
-
- sync_supers();
-
- oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval * 10);
- start_jif = jiffies;
- next_jif = start_jif + msecs_to_jiffies(dirty_writeback_interval * 10);
- nr_to_write = global_page_state(NR_FILE_DIRTY) +
- global_page_state(NR_UNSTABLE_NFS) +
- (inodes_stat.nr_inodes - inodes_stat.nr_unused);
- while (nr_to_write > 0) {
- wbc.more_io = 0;
- wbc.encountered_congestion = 0;
- wbc.nr_to_write = MAX_WRITEBACK_PAGES;
- writeback_inodes(&wbc);
- if (wbc.nr_to_write > 0) {
- if (wbc.encountered_congestion || wbc.more_io)
- congestion_wait(BLK_RW_ASYNC, HZ/10);
- else
- break; /* All the old data is written */
- }
- nr_to_write -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
- }
- if (time_before(next_jif, jiffies + HZ))
- next_jif = jiffies + HZ;
- if (dirty_writeback_interval)
- mod_timer(&wb_timer, next_jif);
-}
-
-/*
* sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
*/
int dirty_writeback_centisecs_handler(ctl_table *table, int write,
struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
{
proc_dointvec(table, write, file, buffer, length, ppos);
- if (dirty_writeback_interval)
- mod_timer(&wb_timer, jiffies +
- msecs_to_jiffies(dirty_writeback_interval * 10));
- else
- del_timer(&wb_timer);
return 0;
}
-static void wb_timer_fn(unsigned long unused)
+static void do_laptop_sync(struct work_struct *work)
{
- if (pdflush_operation(wb_kupdate, 0) < 0)
- mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
-}
-
-static void laptop_flush(unsigned long unused)
-{
- sys_sync();
+ wakeup_flusher_threads(0);
+ kfree(work);
}
static void laptop_timer_fn(unsigned long unused)
{
- pdflush_operation(laptop_flush, 0);
+ struct work_struct *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (work) {
+ INIT_WORK(work, do_laptop_sync);
+ schedule_work(work);
+ }
}
/*
@@ -910,8 +798,6 @@ void __init page_writeback_init(void)
{
int shift;
- mod_timer(&wb_timer,
- jiffies + msecs_to_jiffies(dirty_writeback_interval * 10));
writeback_set_ratelimit();
register_cpu_notifier(&ratelimit_nb);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index caa92689aac9..d052abbe3063 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -882,7 +882,7 @@ retry_reserve:
*/
static int rmqueue_bulk(struct zone *zone, unsigned int order,
unsigned long count, struct list_head *list,
- int migratetype)
+ int migratetype, int cold)
{
int i;
@@ -901,7 +901,10 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
* merge IO requests if the physical pages are ordered
* properly.
*/
- list_add(&page->lru, list);
+ if (likely(cold == 0))
+ list_add(&page->lru, list);
+ else
+ list_add_tail(&page->lru, list);
set_page_private(page, migratetype);
list = &page->lru;
}
@@ -1119,7 +1122,8 @@ again:
local_irq_save(flags);
if (!pcp->count) {
pcp->count = rmqueue_bulk(zone, 0,
- pcp->batch, &pcp->list, migratetype);
+ pcp->batch, &pcp->list,
+ migratetype, cold);
if (unlikely(!pcp->count))
goto failed;
}
@@ -1138,7 +1142,8 @@ again:
/* Allocate more to the pcp list if necessary */
if (unlikely(&page->lru == &pcp->list)) {
pcp->count += rmqueue_bulk(zone, 0,
- pcp->batch, &pcp->list, migratetype);
+ pcp->batch, &pcp->list,
+ migratetype, cold);
page = list_entry(pcp->list.next, struct page, lru);
}
@@ -1740,8 +1745,10 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* be using allocators in order of preference for an area that is
* too large.
*/
- if (WARN_ON_ONCE(order >= MAX_ORDER))
+ if (order >= MAX_ORDER) {
+ WARN_ON_ONCE(!(gfp_mask & __GFP_NOWARN));
return NULL;
+ }
/*
* GFP_THISNODE (meaning __GFP_THISNODE, __GFP_NORETRY and
@@ -1789,6 +1796,10 @@ rebalance:
if (p->flags & PF_MEMALLOC)
goto nopage;
+ /* Avoid allocations with no watermarks from looping endlessly */
+ if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL))
+ goto nopage;
+
/* Try direct reclaim and then allocating */
page = __alloc_pages_direct_reclaim(gfp_mask, order,
zonelist, high_zoneidx,
diff --git a/mm/pdflush.c b/mm/pdflush.c
deleted file mode 100644
index 235ac440c44e..000000000000
--- a/mm/pdflush.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * mm/pdflush.c - worker threads for writing back filesystem data
- *
- * Copyright (C) 2002, Linus Torvalds.
- *
- * 09Apr2002 Andrew Morton
- * Initial version
- * 29Feb2004 kaos@sgi.com
- * Move worker thread creation to kthread to avoid chewing
- * up stack space with nested calls to kernel_thread.
- */
-
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/signal.h>
-#include <linux/spinlock.h>
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/fs.h> /* Needed by writeback.h */
-#include <linux/writeback.h> /* Prototypes pdflush_operation() */
-#include <linux/kthread.h>
-#include <linux/cpuset.h>
-#include <linux/freezer.h>
-
-
-/*
- * Minimum and maximum number of pdflush instances
- */
-#define MIN_PDFLUSH_THREADS 2
-#define MAX_PDFLUSH_THREADS 8
-
-static void start_one_pdflush_thread(void);
-
-
-/*
- * The pdflush threads are worker threads for writing back dirty data.
- * Ideally, we'd like one thread per active disk spindle. But the disk
- * topology is very hard to divine at this level. Instead, we take
- * care in various places to prevent more than one pdflush thread from
- * performing writeback against a single filesystem. pdflush threads
- * have the PF_FLUSHER flag set in current->flags to aid in this.
- */
-
-/*
- * All the pdflush threads. Protected by pdflush_lock
- */
-static LIST_HEAD(pdflush_list);
-static DEFINE_SPINLOCK(pdflush_lock);
-
-/*
- * The count of currently-running pdflush threads. Protected
- * by pdflush_lock.
- *
- * Readable by sysctl, but not writable. Published to userspace at
- * /proc/sys/vm/nr_pdflush_threads.
- */
-int nr_pdflush_threads = 0;
-
-/*
- * The time at which the pdflush thread pool last went empty
- */
-static unsigned long last_empty_jifs;
-
-/*
- * The pdflush thread.
- *
- * Thread pool management algorithm:
- *
- * - The minimum and maximum number of pdflush instances are bound
- * by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS.
- *
- * - If there have been no idle pdflush instances for 1 second, create
- * a new one.
- *
- * - If the least-recently-went-to-sleep pdflush thread has been asleep
- * for more than one second, terminate a thread.
- */
-
-/*
- * A structure for passing work to a pdflush thread. Also for passing
- * state information between pdflush threads. Protected by pdflush_lock.
- */
-struct pdflush_work {
- struct task_struct *who; /* The thread */
- void (*fn)(unsigned long); /* A callback function */
- unsigned long arg0; /* An argument to the callback */
- struct list_head list; /* On pdflush_list, when idle */
- unsigned long when_i_went_to_sleep;
-};
-
-static int __pdflush(struct pdflush_work *my_work)
-{
- current->flags |= PF_FLUSHER | PF_SWAPWRITE;
- set_freezable();
- my_work->fn = NULL;
- my_work->who = current;
- INIT_LIST_HEAD(&my_work->list);
-
- spin_lock_irq(&pdflush_lock);
- for ( ; ; ) {
- struct pdflush_work *pdf;
-
- set_current_state(TASK_INTERRUPTIBLE);
- list_move(&my_work->list, &pdflush_list);
- my_work->when_i_went_to_sleep = jiffies;
- spin_unlock_irq(&pdflush_lock);
- schedule();
- try_to_freeze();
- spin_lock_irq(&pdflush_lock);
- if (!list_empty(&my_work->list)) {
- /*
- * Someone woke us up, but without removing our control
- * structure from the global list. swsusp will do this
- * in try_to_freeze()->refrigerator(). Handle it.
- */
- my_work->fn = NULL;
- continue;
- }
- if (my_work->fn == NULL) {
- printk("pdflush: bogus wakeup\n");
- continue;
- }
- spin_unlock_irq(&pdflush_lock);
-
- (*my_work->fn)(my_work->arg0);
-
- spin_lock_irq(&pdflush_lock);
-
- /*
- * Thread creation: For how long have there been zero
- * available threads?
- *
- * To throttle creation, we reset last_empty_jifs.
- */
- if (time_after(jiffies, last_empty_jifs + 1 * HZ)) {
- if (list_empty(&pdflush_list)) {
- if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) {
- last_empty_jifs = jiffies;
- nr_pdflush_threads++;
- spin_unlock_irq(&pdflush_lock);
- start_one_pdflush_thread();
- spin_lock_irq(&pdflush_lock);
- }
- }
- }
-
- my_work->fn = NULL;
-
- /*
- * Thread destruction: For how long has the sleepiest
- * thread slept?
- */
- if (list_empty(&pdflush_list))
- continue;
- if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
- continue;
- pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
- if (time_after(jiffies, pdf->when_i_went_to_sleep + 1 * HZ)) {
- /* Limit exit rate */
- pdf->when_i_went_to_sleep = jiffies;
- break; /* exeunt */
- }
- }
- nr_pdflush_threads--;
- spin_unlock_irq(&pdflush_lock);
- return 0;
-}
-
-/*
- * Of course, my_work wants to be just a local in __pdflush(). It is
- * separated out in this manner to hopefully prevent the compiler from
- * performing unfortunate optimisations against the auto variables. Because
- * these are visible to other tasks and CPUs. (No problem has actually
- * been observed. This is just paranoia).
- */
-static int pdflush(void *dummy)
-{
- struct pdflush_work my_work;
- cpumask_var_t cpus_allowed;
-
- /*
- * Since the caller doesn't even check kthread_run() worked, let's not
- * freak out too much if this fails.
- */
- if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
- printk(KERN_WARNING "pdflush failed to allocate cpumask\n");
- return 0;
- }
-
- /*
- * pdflush can spend a lot of time doing encryption via dm-crypt. We
- * don't want to do that at keventd's priority.
- */
- set_user_nice(current, 0);
-
- /*
- * Some configs put our parent kthread in a limited cpuset,
- * which kthread() overrides, forcing cpus_allowed == cpu_all_mask.
- * Our needs are more modest - cut back to our cpusets cpus_allowed.
- * This is needed as pdflush's are dynamically created and destroyed.
- * The boottime pdflush's are easily placed w/o these 2 lines.
- */
- cpuset_cpus_allowed(current, cpus_allowed);
- set_cpus_allowed_ptr(current, cpus_allowed);
- free_cpumask_var(cpus_allowed);
-
- return __pdflush(&my_work);
-}
-
-/*
- * Attempt to wake up a pdflush thread, and get it to do some work for you.
- * Returns zero if it indeed managed to find a worker thread, and passed your
- * payload to it.
- */
-int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
-{
- unsigned long flags;
- int ret = 0;
-
- BUG_ON(fn == NULL); /* Hard to diagnose if it's deferred */
-
- spin_lock_irqsave(&pdflush_lock, flags);
- if (list_empty(&pdflush_list)) {
- ret = -1;
- } else {
- struct pdflush_work *pdf;
-
- pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
- list_del_init(&pdf->list);
- if (list_empty(&pdflush_list))
- last_empty_jifs = jiffies;
- pdf->fn = fn;
- pdf->arg0 = arg0;
- wake_up_process(pdf->who);
- }
- spin_unlock_irqrestore(&pdflush_lock, flags);
-
- return ret;
-}
-
-static void start_one_pdflush_thread(void)
-{
- struct task_struct *k;
-
- k = kthread_run(pdflush, NULL, "pdflush");
- if (unlikely(IS_ERR(k))) {
- spin_lock_irq(&pdflush_lock);
- nr_pdflush_threads--;
- spin_unlock_irq(&pdflush_lock);
- }
-}
-
-static int __init pdflush_init(void)
-{
- int i;
-
- /*
- * Pre-set nr_pdflush_threads... If we fail to create,
- * the count will be decremented.
- */
- nr_pdflush_threads = MIN_PDFLUSH_THREADS;
-
- for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
- start_one_pdflush_thread();
- return 0;
-}
-
-module_init(pdflush_init);
diff --git a/mm/percpu.c b/mm/percpu.c
index b70f2acd8853..b3d0bcff8c7c 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -8,12 +8,13 @@
*
* This is percpu allocator which can handle both static and dynamic
* areas. Percpu areas are allocated in chunks in vmalloc area. Each
- * chunk is consisted of num_possible_cpus() units and the first chunk
- * is used for static percpu variables in the kernel image (special
- * boot time alloc/init handling necessary as these areas need to be
- * brought up before allocation services are running). Unit grows as
- * necessary and all units grow or shrink in unison. When a chunk is
- * filled up, another chunk is allocated. ie. in vmalloc area
+ * chunk is consisted of boot-time determined number of units and the
+ * first chunk is used for static percpu variables in the kernel image
+ * (special boot time alloc/init handling necessary as these areas
+ * need to be brought up before allocation services are running).
+ * Unit grows as necessary and all units grow or shrink in unison.
+ * When a chunk is filled up, another chunk is allocated. ie. in
+ * vmalloc area
*
* c0 c1 c2
* ------------------- ------------------- ------------
@@ -22,11 +23,13 @@
*
* Allocation is done in offset-size areas of single unit space. Ie,
* an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0,
- * c1:u1, c1:u2 and c1:u3. Percpu access can be done by configuring
- * percpu base registers pcpu_unit_size apart.
+ * c1:u1, c1:u2 and c1:u3. On UMA, units corresponds directly to
+ * cpus. On NUMA, the mapping can be non-linear and even sparse.
+ * Percpu access can be done by configuring percpu base registers
+ * according to cpu to unit mapping and pcpu_unit_size.
*
- * There are usually many small percpu allocations many of them as
- * small as 4 bytes. The allocator organizes chunks into lists
+ * There are usually many small percpu allocations many of them being
+ * as small as 4 bytes. The allocator organizes chunks into lists
* according to free size and tries to allocate from the fullest one.
* Each chunk keeps the maximum contiguous area size hint which is
* guaranteed to be eqaul to or larger than the maximum contiguous
@@ -43,7 +46,7 @@
*
* To use this allocator, arch code should do the followings.
*
- * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ * - drop CONFIG_HAVE_LEGACY_PER_CPU_AREA
*
* - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
* regular address to percpu pointer and back if they need to be
@@ -56,6 +59,7 @@
#include <linux/bitmap.h>
#include <linux/bootmem.h>
#include <linux/list.h>
+#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -94,20 +98,27 @@ struct pcpu_chunk {
int map_alloc; /* # of map entries allocated */
int *map; /* allocation map */
bool immutable; /* no [de]population allowed */
- struct page **page; /* points to page array */
- struct page *page_ar[]; /* #cpus * UNIT_PAGES */
+ unsigned long populated[]; /* populated bitmap */
};
static int pcpu_unit_pages __read_mostly;
static int pcpu_unit_size __read_mostly;
+static int pcpu_nr_units __read_mostly;
static int pcpu_chunk_size __read_mostly;
static int pcpu_nr_slots __read_mostly;
static size_t pcpu_chunk_struct_size __read_mostly;
+/* cpus with the lowest and highest unit numbers */
+static unsigned int pcpu_first_unit_cpu __read_mostly;
+static unsigned int pcpu_last_unit_cpu __read_mostly;
+
/* the address of the first chunk which starts with the kernel static area */
void *pcpu_base_addr __read_mostly;
EXPORT_SYMBOL_GPL(pcpu_base_addr);
+/* cpu -> unit map */
+const int *pcpu_unit_map __read_mostly;
+
/*
* The first chunk which always exists. Note that unlike other
* chunks, this one can be allocated and mapped in several different
@@ -129,9 +140,9 @@ static int pcpu_reserved_chunk_limit;
* Synchronization rules.
*
* There are two locks - pcpu_alloc_mutex and pcpu_lock. The former
- * protects allocation/reclaim paths, chunks and chunk->page arrays.
- * The latter is a spinlock and protects the index data structures -
- * chunk slots, chunks and area maps in chunks.
+ * protects allocation/reclaim paths, chunks, populated bitmap and
+ * vmalloc mapping. The latter is a spinlock and protects the index
+ * data structures - chunk slots, chunks and area maps in chunks.
*
* During allocation, pcpu_alloc_mutex is kept locked all the time and
* pcpu_lock is grabbed and released as necessary. All actual memory
@@ -178,13 +189,7 @@ static int pcpu_chunk_slot(const struct pcpu_chunk *chunk)
static int pcpu_page_idx(unsigned int cpu, int page_idx)
{
- return cpu * pcpu_unit_pages + page_idx;
-}
-
-static struct page **pcpu_chunk_pagep(struct pcpu_chunk *chunk,
- unsigned int cpu, int page_idx)
-{
- return &chunk->page[pcpu_page_idx(cpu, page_idx)];
+ return pcpu_unit_map[cpu] * pcpu_unit_pages + page_idx;
}
static unsigned long pcpu_chunk_addr(struct pcpu_chunk *chunk,
@@ -194,10 +199,13 @@ static unsigned long pcpu_chunk_addr(struct pcpu_chunk *chunk,
(pcpu_page_idx(cpu, page_idx) << PAGE_SHIFT);
}
-static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk,
- int page_idx)
+static struct page *pcpu_chunk_page(struct pcpu_chunk *chunk,
+ unsigned int cpu, int page_idx)
{
- return *pcpu_chunk_pagep(chunk, 0, page_idx) != NULL;
+ /* must not be used on pre-mapped chunk */
+ WARN_ON(chunk->immutable);
+
+ return vmalloc_to_page((void *)pcpu_chunk_addr(chunk, cpu, page_idx));
}
/* set the pointer to a chunk in a page struct */
@@ -212,6 +220,34 @@ static struct pcpu_chunk *pcpu_get_page_chunk(struct page *page)
return (struct pcpu_chunk *)page->index;
}
+static void pcpu_next_unpop(struct pcpu_chunk *chunk, int *rs, int *re, int end)
+{
+ *rs = find_next_zero_bit(chunk->populated, end, *rs);
+ *re = find_next_bit(chunk->populated, end, *rs + 1);
+}
+
+static void pcpu_next_pop(struct pcpu_chunk *chunk, int *rs, int *re, int end)
+{
+ *rs = find_next_bit(chunk->populated, end, *rs);
+ *re = find_next_zero_bit(chunk->populated, end, *rs + 1);
+}
+
+/*
+ * (Un)populated page region iterators. Iterate over (un)populated
+ * page regions betwen @start and @end in @chunk. @rs and @re should
+ * be integer variables and will be set to start and end page index of
+ * the current region.
+ */
+#define pcpu_for_each_unpop_region(chunk, rs, re, start, end) \
+ for ((rs) = (start), pcpu_next_unpop((chunk), &(rs), &(re), (end)); \
+ (rs) < (re); \
+ (rs) = (re) + 1, pcpu_next_unpop((chunk), &(rs), &(re), (end)))
+
+#define pcpu_for_each_pop_region(chunk, rs, re, start, end) \
+ for ((rs) = (start), pcpu_next_pop((chunk), &(rs), &(re), (end)); \
+ (rs) < (re); \
+ (rs) = (re) + 1, pcpu_next_pop((chunk), &(rs), &(re), (end)))
+
/**
* pcpu_mem_alloc - allocate memory
* @size: bytes to allocate
@@ -290,13 +326,21 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
void *first_start = pcpu_first_chunk->vm->addr;
/* is it in the first chunk? */
- if (addr >= first_start && addr < first_start + pcpu_chunk_size) {
+ if (addr >= first_start && addr < first_start + pcpu_unit_size) {
/* is it in the reserved area? */
if (addr < first_start + pcpu_reserved_chunk_limit)
return pcpu_reserved_chunk;
return pcpu_first_chunk;
}
+ /*
+ * The address is relative to unit0 which might be unused and
+ * thus unmapped. Offset the address to the unit space of the
+ * current processor before looking it up in the vmalloc
+ * space. Note that any possible cpu id can be used here, so
+ * there's no need to worry about preemption or cpu hotplug.
+ */
+ addr += pcpu_unit_map[smp_processor_id()] * pcpu_unit_size;
return pcpu_get_page_chunk(vmalloc_to_page(addr));
}
@@ -545,125 +589,327 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
}
/**
- * pcpu_unmap - unmap pages out of a pcpu_chunk
+ * pcpu_get_pages_and_bitmap - get temp pages array and bitmap
* @chunk: chunk of interest
- * @page_start: page index of the first page to unmap
- * @page_end: page index of the last page to unmap + 1
- * @flush_tlb: whether to flush tlb or not
+ * @bitmapp: output parameter for bitmap
+ * @may_alloc: may allocate the array
*
- * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
- * If @flush is true, vcache is flushed before unmapping and tlb
- * after.
+ * Returns pointer to array of pointers to struct page and bitmap,
+ * both of which can be indexed with pcpu_page_idx(). The returned
+ * array is cleared to zero and *@bitmapp is copied from
+ * @chunk->populated. Note that there is only one array and bitmap
+ * and access exclusion is the caller's responsibility.
+ *
+ * CONTEXT:
+ * pcpu_alloc_mutex and does GFP_KERNEL allocation if @may_alloc.
+ * Otherwise, don't care.
+ *
+ * RETURNS:
+ * Pointer to temp pages array on success, NULL on failure.
*/
-static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
- bool flush_tlb)
+static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk,
+ unsigned long **bitmapp,
+ bool may_alloc)
{
- unsigned int last = num_possible_cpus() - 1;
- unsigned int cpu;
+ static struct page **pages;
+ static unsigned long *bitmap;
+ size_t pages_size = pcpu_nr_units * pcpu_unit_pages * sizeof(pages[0]);
+ size_t bitmap_size = BITS_TO_LONGS(pcpu_unit_pages) *
+ sizeof(unsigned long);
+
+ if (!pages || !bitmap) {
+ if (may_alloc && !pages)
+ pages = pcpu_mem_alloc(pages_size);
+ if (may_alloc && !bitmap)
+ bitmap = pcpu_mem_alloc(bitmap_size);
+ if (!pages || !bitmap)
+ return NULL;
+ }
- /* unmap must not be done on immutable chunk */
- WARN_ON(chunk->immutable);
+ memset(pages, 0, pages_size);
+ bitmap_copy(bitmap, chunk->populated, pcpu_unit_pages);
- /*
- * Each flushing trial can be very expensive, issue flush on
- * the whole region at once rather than doing it for each cpu.
- * This could be an overkill but is more scalable.
- */
- flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
- pcpu_chunk_addr(chunk, last, page_end));
+ *bitmapp = bitmap;
+ return pages;
+}
- for_each_possible_cpu(cpu)
- unmap_kernel_range_noflush(
- pcpu_chunk_addr(chunk, cpu, page_start),
- (page_end - page_start) << PAGE_SHIFT);
-
- /* ditto as flush_cache_vunmap() */
- if (flush_tlb)
- flush_tlb_kernel_range(pcpu_chunk_addr(chunk, 0, page_start),
- pcpu_chunk_addr(chunk, last, page_end));
+/**
+ * pcpu_free_pages - free pages which were allocated for @chunk
+ * @chunk: chunk pages were allocated for
+ * @pages: array of pages to be freed, indexed by pcpu_page_idx()
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to be freed
+ * @page_end: page index of the last page to be freed + 1
+ *
+ * Free pages [@page_start and @page_end) in @pages for all units.
+ * The pages were allocated for @chunk.
+ */
+static void pcpu_free_pages(struct pcpu_chunk *chunk,
+ struct page **pages, unsigned long *populated,
+ int page_start, int page_end)
+{
+ unsigned int cpu;
+ int i;
+
+ for_each_possible_cpu(cpu) {
+ for (i = page_start; i < page_end; i++) {
+ struct page *page = pages[pcpu_page_idx(cpu, i)];
+
+ if (page)
+ __free_page(page);
+ }
+ }
}
/**
- * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk
- * @chunk: chunk to depopulate
- * @off: offset to the area to depopulate
- * @size: size of the area to depopulate in bytes
- * @flush: whether to flush cache and tlb or not
- *
- * For each cpu, depopulate and unmap pages [@page_start,@page_end)
- * from @chunk. If @flush is true, vcache is flushed before unmapping
- * and tlb after.
- *
- * CONTEXT:
- * pcpu_alloc_mutex.
+ * pcpu_alloc_pages - allocates pages for @chunk
+ * @chunk: target chunk
+ * @pages: array to put the allocated pages into, indexed by pcpu_page_idx()
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to be allocated
+ * @page_end: page index of the last page to be allocated + 1
+ *
+ * Allocate pages [@page_start,@page_end) into @pages for all units.
+ * The allocation is for @chunk. Percpu core doesn't care about the
+ * content of @pages and will pass it verbatim to pcpu_map_pages().
*/
-static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size,
- bool flush)
+static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
+ struct page **pages, unsigned long *populated,
+ int page_start, int page_end)
{
- int page_start = PFN_DOWN(off);
- int page_end = PFN_UP(off + size);
- int unmap_start = -1;
- int uninitialized_var(unmap_end);
+ const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
unsigned int cpu;
int i;
- for (i = page_start; i < page_end; i++) {
- for_each_possible_cpu(cpu) {
- struct page **pagep = pcpu_chunk_pagep(chunk, cpu, i);
+ for_each_possible_cpu(cpu) {
+ for (i = page_start; i < page_end; i++) {
+ struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
+
+ *pagep = alloc_pages_node(cpu_to_node(cpu), gfp, 0);
+ if (!*pagep) {
+ pcpu_free_pages(chunk, pages, populated,
+ page_start, page_end);
+ return -ENOMEM;
+ }
+ }
+ }
+ return 0;
+}
- if (!*pagep)
- continue;
+/**
+ * pcpu_pre_unmap_flush - flush cache prior to unmapping
+ * @chunk: chunk the regions to be flushed belongs to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages in [@page_start,@page_end) of @chunk are about to be
+ * unmapped. Flush cache. As each flushing trial can be very
+ * expensive, issue flush on the whole region at once rather than
+ * doing it for each cpu. This could be an overkill but is more
+ * scalable.
+ */
+static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk,
+ int page_start, int page_end)
+{
+ flush_cache_vunmap(
+ pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+ pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
- __free_page(*pagep);
+static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
+{
+ unmap_kernel_range_noflush(addr, nr_pages << PAGE_SHIFT);
+}
- /*
- * If it's partial depopulation, it might get
- * populated or depopulated again. Mark the
- * page gone.
- */
- *pagep = NULL;
+/**
+ * pcpu_unmap_pages - unmap pages out of a pcpu_chunk
+ * @chunk: chunk of interest
+ * @pages: pages array which can be used to pass information to free
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to unmap
+ * @page_end: page index of the last page to unmap + 1
+ *
+ * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
+ * Corresponding elements in @pages were cleared by the caller and can
+ * be used to carry information to pcpu_free_pages() which will be
+ * called after all unmaps are finished. The caller should call
+ * proper pre/post flush functions.
+ */
+static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
+ struct page **pages, unsigned long *populated,
+ int page_start, int page_end)
+{
+ unsigned int cpu;
+ int i;
- unmap_start = unmap_start < 0 ? i : unmap_start;
- unmap_end = i + 1;
+ for_each_possible_cpu(cpu) {
+ for (i = page_start; i < page_end; i++) {
+ struct page *page;
+
+ page = pcpu_chunk_page(chunk, cpu, i);
+ WARN_ON(!page);
+ pages[pcpu_page_idx(cpu, i)] = page;
}
+ __pcpu_unmap_pages(pcpu_chunk_addr(chunk, cpu, page_start),
+ page_end - page_start);
}
- if (unmap_start >= 0)
- pcpu_unmap(chunk, unmap_start, unmap_end, flush);
+ for (i = page_start; i < page_end; i++)
+ __clear_bit(i, populated);
}
/**
- * pcpu_map - map pages into a pcpu_chunk
+ * pcpu_post_unmap_tlb_flush - flush TLB after unmapping
+ * @chunk: pcpu_chunk the regions to be flushed belong to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages [@page_start,@page_end) of @chunk have been unmapped. Flush
+ * TLB for the regions. This can be skipped if the area is to be
+ * returned to vmalloc as vmalloc will handle TLB flushing lazily.
+ *
+ * As with pcpu_pre_unmap_flush(), TLB flushing also is done at once
+ * for the whole region.
+ */
+static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk,
+ int page_start, int page_end)
+{
+ flush_tlb_kernel_range(
+ pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+ pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
+
+static int __pcpu_map_pages(unsigned long addr, struct page **pages,
+ int nr_pages)
+{
+ return map_kernel_range_noflush(addr, nr_pages << PAGE_SHIFT,
+ PAGE_KERNEL, pages);
+}
+
+/**
+ * pcpu_map_pages - map pages into a pcpu_chunk
* @chunk: chunk of interest
+ * @pages: pages array containing pages to be mapped
+ * @populated: populated bitmap
* @page_start: page index of the first page to map
* @page_end: page index of the last page to map + 1
*
- * For each cpu, map pages [@page_start,@page_end) into @chunk.
- * vcache is flushed afterwards.
+ * For each cpu, map pages [@page_start,@page_end) into @chunk. The
+ * caller is responsible for calling pcpu_post_map_flush() after all
+ * mappings are complete.
+ *
+ * This function is responsible for setting corresponding bits in
+ * @chunk->populated bitmap and whatever is necessary for reverse
+ * lookup (addr -> chunk).
*/
-static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end)
+static int pcpu_map_pages(struct pcpu_chunk *chunk,
+ struct page **pages, unsigned long *populated,
+ int page_start, int page_end)
{
- unsigned int last = num_possible_cpus() - 1;
- unsigned int cpu;
- int err;
-
- /* map must not be done on immutable chunk */
- WARN_ON(chunk->immutable);
+ unsigned int cpu, tcpu;
+ int i, err;
for_each_possible_cpu(cpu) {
- err = map_kernel_range_noflush(
- pcpu_chunk_addr(chunk, cpu, page_start),
- (page_end - page_start) << PAGE_SHIFT,
- PAGE_KERNEL,
- pcpu_chunk_pagep(chunk, cpu, page_start));
+ err = __pcpu_map_pages(pcpu_chunk_addr(chunk, cpu, page_start),
+ &pages[pcpu_page_idx(cpu, page_start)],
+ page_end - page_start);
if (err < 0)
- return err;
+ goto err;
+ }
+
+ /* mapping successful, link chunk and mark populated */
+ for (i = page_start; i < page_end; i++) {
+ for_each_possible_cpu(cpu)
+ pcpu_set_page_chunk(pages[pcpu_page_idx(cpu, i)],
+ chunk);
+ __set_bit(i, populated);
}
- /* flush at once, please read comments in pcpu_unmap() */
- flush_cache_vmap(pcpu_chunk_addr(chunk, 0, page_start),
- pcpu_chunk_addr(chunk, last, page_end));
return 0;
+
+err:
+ for_each_possible_cpu(tcpu) {
+ if (tcpu == cpu)
+ break;
+ __pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start),
+ page_end - page_start);
+ }
+ return err;
+}
+
+/**
+ * pcpu_post_map_flush - flush cache after mapping
+ * @chunk: pcpu_chunk the regions to be flushed belong to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages [@page_start,@page_end) of @chunk have been mapped. Flush
+ * cache.
+ *
+ * As with pcpu_pre_unmap_flush(), TLB flushing also is done at once
+ * for the whole region.
+ */
+static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
+ int page_start, int page_end)
+{
+ flush_cache_vmap(
+ pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+ pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
+
+/**
+ * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk
+ * @chunk: chunk to depopulate
+ * @off: offset to the area to depopulate
+ * @size: size of the area to depopulate in bytes
+ * @flush: whether to flush cache and tlb or not
+ *
+ * For each cpu, depopulate and unmap pages [@page_start,@page_end)
+ * from @chunk. If @flush is true, vcache is flushed before unmapping
+ * and tlb after.
+ *
+ * CONTEXT:
+ * pcpu_alloc_mutex.
+ */
+static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size)
+{
+ int page_start = PFN_DOWN(off);
+ int page_end = PFN_UP(off + size);
+ struct page **pages;
+ unsigned long *populated;
+ int rs, re;
+
+ /* quick path, check whether it's empty already */
+ pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+ if (rs == page_start && re == page_end)
+ return;
+ break;
+ }
+
+ /* immutable chunks can't be depopulated */
+ WARN_ON(chunk->immutable);
+
+ /*
+ * If control reaches here, there must have been at least one
+ * successful population attempt so the temp pages array must
+ * be available now.
+ */
+ pages = pcpu_get_pages_and_bitmap(chunk, &populated, false);
+ BUG_ON(!pages);
+
+ /* unmap and free */
+ pcpu_pre_unmap_flush(chunk, page_start, page_end);
+
+ pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end)
+ pcpu_unmap_pages(chunk, pages, populated, rs, re);
+
+ /* no need to flush tlb, vmalloc will handle it lazily */
+
+ pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end)
+ pcpu_free_pages(chunk, pages, populated, rs, re);
+
+ /* commit new bitmap */
+ bitmap_copy(chunk->populated, populated, pcpu_unit_pages);
}
/**
@@ -680,50 +926,60 @@ static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end)
*/
static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size)
{
- const gfp_t alloc_mask = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
int page_start = PFN_DOWN(off);
int page_end = PFN_UP(off + size);
- int map_start = -1;
- int uninitialized_var(map_end);
+ int free_end = page_start, unmap_end = page_start;
+ struct page **pages;
+ unsigned long *populated;
unsigned int cpu;
- int i;
+ int rs, re, rc;
- for (i = page_start; i < page_end; i++) {
- if (pcpu_chunk_page_occupied(chunk, i)) {
- if (map_start >= 0) {
- if (pcpu_map(chunk, map_start, map_end))
- goto err;
- map_start = -1;
- }
- continue;
- }
+ /* quick path, check whether all pages are already there */
+ pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) {
+ if (rs == page_start && re == page_end)
+ goto clear;
+ break;
+ }
- map_start = map_start < 0 ? i : map_start;
- map_end = i + 1;
+ /* need to allocate and map pages, this chunk can't be immutable */
+ WARN_ON(chunk->immutable);
- for_each_possible_cpu(cpu) {
- struct page **pagep = pcpu_chunk_pagep(chunk, cpu, i);
+ pages = pcpu_get_pages_and_bitmap(chunk, &populated, true);
+ if (!pages)
+ return -ENOMEM;
- *pagep = alloc_pages_node(cpu_to_node(cpu),
- alloc_mask, 0);
- if (!*pagep)
- goto err;
- pcpu_set_page_chunk(*pagep, chunk);
- }
+ /* alloc and map */
+ pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+ rc = pcpu_alloc_pages(chunk, pages, populated, rs, re);
+ if (rc)
+ goto err_free;
+ free_end = re;
}
- if (map_start >= 0 && pcpu_map(chunk, map_start, map_end))
- goto err;
+ pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+ rc = pcpu_map_pages(chunk, pages, populated, rs, re);
+ if (rc)
+ goto err_unmap;
+ unmap_end = re;
+ }
+ pcpu_post_map_flush(chunk, page_start, page_end);
+ /* commit new bitmap */
+ bitmap_copy(chunk->populated, populated, pcpu_unit_pages);
+clear:
for_each_possible_cpu(cpu)
- memset(chunk->vm->addr + cpu * pcpu_unit_size + off, 0,
- size);
-
+ memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size);
return 0;
-err:
- /* likely under heavy memory pressure, give memory back */
- pcpu_depopulate_chunk(chunk, off, size, true);
- return -ENOMEM;
+
+err_unmap:
+ pcpu_pre_unmap_flush(chunk, page_start, unmap_end);
+ pcpu_for_each_unpop_region(chunk, rs, re, page_start, unmap_end)
+ pcpu_unmap_pages(chunk, pages, populated, rs, re);
+ pcpu_post_unmap_tlb_flush(chunk, page_start, unmap_end);
+err_free:
+ pcpu_for_each_unpop_region(chunk, rs, re, page_start, free_end)
+ pcpu_free_pages(chunk, pages, populated, rs, re);
+ return rc;
}
static void free_pcpu_chunk(struct pcpu_chunk *chunk)
@@ -747,7 +1003,6 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
chunk->map = pcpu_mem_alloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0]));
chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
chunk->map[chunk->map_used++] = pcpu_unit_size;
- chunk->page = chunk->page_ar;
chunk->vm = get_vm_area(pcpu_chunk_size, GFP_KERNEL);
if (!chunk->vm) {
@@ -847,6 +1102,7 @@ area_found:
mutex_unlock(&pcpu_alloc_mutex);
+ /* return address relative to unit0 */
return __addr_to_pcpu_ptr(chunk->vm->addr + off);
fail_unlock:
@@ -928,7 +1184,7 @@ static void pcpu_reclaim(struct work_struct *work)
mutex_unlock(&pcpu_alloc_mutex);
list_for_each_entry_safe(chunk, next, &todo, list) {
- pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size, false);
+ pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size);
free_pcpu_chunk(chunk);
}
}
@@ -976,26 +1232,16 @@ EXPORT_SYMBOL_GPL(free_percpu);
/**
* pcpu_setup_first_chunk - initialize the first percpu chunk
- * @get_page_fn: callback to fetch page pointer
* @static_size: the size of static percpu area in bytes
- * @reserved_size: the size of reserved percpu area in bytes
+ * @reserved_size: the size of reserved percpu area in bytes, 0 for none
* @dyn_size: free size for dynamic allocation in bytes, -1 for auto
- * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
- * @base_addr: mapped address, NULL for auto
- * @populate_pte_fn: callback to allocate pagetable, NULL if unnecessary
+ * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE
+ * @base_addr: mapped address
+ * @unit_map: cpu -> unit map, NULL for sequential mapping
*
* Initialize the first percpu chunk which contains the kernel static
* perpcu area. This function is to be called from arch percpu area
- * setup path. The first two parameters are mandatory. The rest are
- * optional.
- *
- * @get_page_fn() should return pointer to percpu page given cpu
- * number and page number. It should at least return enough pages to
- * cover the static area. The returned pages for static area should
- * have been initialized with valid data. If @unit_size is specified,
- * it can also return pages after the static area. NULL return
- * indicates end of pages for the cpu. Note that @get_page_fn() must
- * return the same number of pages for all cpus.
+ * setup path.
*
* @reserved_size, if non-zero, specifies the amount of bytes to
* reserve after the static area in the first chunk. This reserves
@@ -1010,17 +1256,12 @@ EXPORT_SYMBOL_GPL(free_percpu);
* non-negative value makes percpu leave alone the area beyond
* @static_size + @reserved_size + @dyn_size.
*
- * @unit_size, if non-negative, specifies unit size and must be
- * aligned to PAGE_SIZE and equal to or larger than @static_size +
- * @reserved_size + if non-negative, @dyn_size.
- *
- * Non-null @base_addr means that the caller already allocated virtual
- * region for the first chunk and mapped it. percpu must not mess
- * with the chunk. Note that @base_addr with 0 @unit_size or non-NULL
- * @populate_pte_fn doesn't make any sense.
+ * @unit_size specifies unit size and must be aligned to PAGE_SIZE and
+ * equal to or larger than @static_size + @reserved_size + if
+ * non-negative, @dyn_size.
*
- * @populate_pte_fn is used to populate the pagetable. NULL means the
- * caller already populated the pagetable.
+ * The caller should have mapped the first chunk at @base_addr and
+ * copied static data to each unit.
*
* If the first chunk ends up with both reserved and dynamic areas, it
* is served by two chunks - one to serve the core static and reserved
@@ -1033,47 +1274,83 @@ EXPORT_SYMBOL_GPL(free_percpu);
* The determined pcpu_unit_size which can be used to initialize
* percpu access.
*/
-size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
- size_t static_size, size_t reserved_size,
- ssize_t dyn_size, ssize_t unit_size,
- void *base_addr,
- pcpu_populate_pte_fn_t populate_pte_fn)
+size_t __init pcpu_setup_first_chunk(size_t static_size, size_t reserved_size,
+ ssize_t dyn_size, size_t unit_size,
+ void *base_addr, const int *unit_map)
{
static struct vm_struct first_vm;
static int smap[2], dmap[2];
size_t size_sum = static_size + reserved_size +
(dyn_size >= 0 ? dyn_size : 0);
struct pcpu_chunk *schunk, *dchunk = NULL;
- unsigned int cpu;
- int nr_pages;
- int err, i;
+ unsigned int cpu, tcpu;
+ int i;
- /* santiy checks */
+ /* sanity checks */
BUILD_BUG_ON(ARRAY_SIZE(smap) >= PCPU_DFL_MAP_ALLOC ||
ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC);
BUG_ON(!static_size);
- if (unit_size >= 0) {
- BUG_ON(unit_size < size_sum);
- BUG_ON(unit_size & ~PAGE_MASK);
- BUG_ON(unit_size < PCPU_MIN_UNIT_SIZE);
- } else
- BUG_ON(base_addr);
- BUG_ON(base_addr && populate_pte_fn);
-
- if (unit_size >= 0)
- pcpu_unit_pages = unit_size >> PAGE_SHIFT;
- else
- pcpu_unit_pages = max_t(int, PCPU_MIN_UNIT_SIZE >> PAGE_SHIFT,
- PFN_UP(size_sum));
+ BUG_ON(!base_addr);
+ BUG_ON(unit_size < size_sum);
+ BUG_ON(unit_size & ~PAGE_MASK);
+ BUG_ON(unit_size < PCPU_MIN_UNIT_SIZE);
+
+ /* determine number of units and verify and initialize pcpu_unit_map */
+ if (unit_map) {
+ int first_unit = INT_MAX, last_unit = INT_MIN;
+
+ for_each_possible_cpu(cpu) {
+ int unit = unit_map[cpu];
+
+ BUG_ON(unit < 0);
+ for_each_possible_cpu(tcpu) {
+ if (tcpu == cpu)
+ break;
+ /* the mapping should be one-to-one */
+ BUG_ON(unit_map[tcpu] == unit);
+ }
+
+ if (unit < first_unit) {
+ pcpu_first_unit_cpu = cpu;
+ first_unit = unit;
+ }
+ if (unit > last_unit) {
+ pcpu_last_unit_cpu = cpu;
+ last_unit = unit;
+ }
+ }
+ pcpu_nr_units = last_unit + 1;
+ pcpu_unit_map = unit_map;
+ } else {
+ int *identity_map;
+
+ /* #units == #cpus, identity mapped */
+ identity_map = alloc_bootmem(num_possible_cpus() *
+ sizeof(identity_map[0]));
+ for_each_possible_cpu(cpu)
+ identity_map[cpu] = cpu;
+
+ pcpu_first_unit_cpu = 0;
+ pcpu_last_unit_cpu = pcpu_nr_units - 1;
+ pcpu_nr_units = num_possible_cpus();
+ pcpu_unit_map = identity_map;
+ }
+
+ /* determine basic parameters */
+ pcpu_unit_pages = unit_size >> PAGE_SHIFT;
pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT;
- pcpu_chunk_size = num_possible_cpus() * pcpu_unit_size;
- pcpu_chunk_struct_size = sizeof(struct pcpu_chunk)
- + num_possible_cpus() * pcpu_unit_pages * sizeof(struct page *);
+ pcpu_chunk_size = pcpu_nr_units * pcpu_unit_size;
+ pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) +
+ BITS_TO_LONGS(pcpu_unit_pages) * sizeof(unsigned long);
if (dyn_size < 0)
dyn_size = pcpu_unit_size - static_size - reserved_size;
+ first_vm.flags = VM_ALLOC;
+ first_vm.size = pcpu_chunk_size;
+ first_vm.addr = base_addr;
+
/*
* Allocate chunk slots. The additional last slot is for
* empty chunks.
@@ -1095,7 +1372,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
schunk->vm = &first_vm;
schunk->map = smap;
schunk->map_alloc = ARRAY_SIZE(smap);
- schunk->page = schunk->page_ar;
+ schunk->immutable = true;
+ bitmap_fill(schunk->populated, pcpu_unit_pages);
if (reserved_size) {
schunk->free_size = reserved_size;
@@ -1113,93 +1391,39 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
/* init dynamic chunk if necessary */
if (dyn_size) {
- dchunk = alloc_bootmem(sizeof(struct pcpu_chunk));
+ dchunk = alloc_bootmem(pcpu_chunk_struct_size);
INIT_LIST_HEAD(&dchunk->list);
dchunk->vm = &first_vm;
dchunk->map = dmap;
dchunk->map_alloc = ARRAY_SIZE(dmap);
- dchunk->page = schunk->page_ar; /* share page map with schunk */
+ dchunk->immutable = true;
+ bitmap_fill(dchunk->populated, pcpu_unit_pages);
dchunk->contig_hint = dchunk->free_size = dyn_size;
dchunk->map[dchunk->map_used++] = -pcpu_reserved_chunk_limit;
dchunk->map[dchunk->map_used++] = dchunk->free_size;
}
- /* allocate vm address */
- first_vm.flags = VM_ALLOC;
- first_vm.size = pcpu_chunk_size;
-
- if (!base_addr)
- vm_area_register_early(&first_vm, PAGE_SIZE);
- else {
- /*
- * Pages already mapped. No need to remap into
- * vmalloc area. In this case the first chunks can't
- * be mapped or unmapped by percpu and are marked
- * immutable.
- */
- first_vm.addr = base_addr;
- schunk->immutable = true;
- if (dchunk)
- dchunk->immutable = true;
- }
-
- /* assign pages */
- nr_pages = -1;
- for_each_possible_cpu(cpu) {
- for (i = 0; i < pcpu_unit_pages; i++) {
- struct page *page = get_page_fn(cpu, i);
-
- if (!page)
- break;
- *pcpu_chunk_pagep(schunk, cpu, i) = page;
- }
-
- BUG_ON(i < PFN_UP(static_size));
-
- if (nr_pages < 0)
- nr_pages = i;
- else
- BUG_ON(nr_pages != i);
- }
-
- /* map them */
- if (populate_pte_fn) {
- for_each_possible_cpu(cpu)
- for (i = 0; i < nr_pages; i++)
- populate_pte_fn(pcpu_chunk_addr(schunk,
- cpu, i));
-
- err = pcpu_map(schunk, 0, nr_pages);
- if (err)
- panic("failed to setup static percpu area, err=%d\n",
- err);
- }
-
/* link the first chunk in */
pcpu_first_chunk = dchunk ?: schunk;
pcpu_chunk_relocate(pcpu_first_chunk, -1);
/* we're done */
- pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0);
+ pcpu_base_addr = schunk->vm->addr;
return pcpu_unit_size;
}
-/*
- * Embedding first chunk setup helper.
- */
-static void *pcpue_ptr __initdata;
-static size_t pcpue_size __initdata;
-static size_t pcpue_unit_size __initdata;
-
-static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
+static size_t pcpu_calc_fc_sizes(size_t static_size, size_t reserved_size,
+ ssize_t *dyn_sizep)
{
- size_t off = (size_t)pageno << PAGE_SHIFT;
+ size_t size_sum;
- if (off >= pcpue_size)
- return NULL;
+ size_sum = PFN_ALIGN(static_size + reserved_size +
+ (*dyn_sizep >= 0 ? *dyn_sizep : 0));
+ if (*dyn_sizep != 0)
+ *dyn_sizep = size_sum - static_size - reserved_size;
- return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off);
+ return size_sum;
}
/**
@@ -1207,7 +1431,6 @@ static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
* @static_size: the size of static percpu area in bytes
* @reserved_size: the size of reserved percpu area in bytes
* @dyn_size: free size for dynamic allocation in bytes, -1 for auto
- * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
*
* This is a helper to ease setting up embedded first percpu chunk and
* can be called where pcpu_setup_first_chunk() is expected.
@@ -1219,9 +1442,9 @@ static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
* page size.
*
* When @dyn_size is positive, dynamic area might be larger than
- * specified to fill page alignment. Also, when @dyn_size is auto,
- * @dyn_size does not fill the whole first chunk but only what's
- * necessary for page alignment after static and reserved areas.
+ * specified to fill page alignment. When @dyn_size is auto,
+ * @dyn_size is just big enough to fill page alignment after static
+ * and reserved areas.
*
* If the needed size is smaller than the minimum or specified unit
* size, the leftover is returned to the bootmem allocator.
@@ -1231,28 +1454,21 @@ static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
* percpu access on success, -errno on failure.
*/
ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
- ssize_t dyn_size, ssize_t unit_size)
+ ssize_t dyn_size)
{
- size_t chunk_size;
+ size_t size_sum, unit_size, chunk_size;
+ void *base;
unsigned int cpu;
/* determine parameters and allocate */
- pcpue_size = PFN_ALIGN(static_size + reserved_size +
- (dyn_size >= 0 ? dyn_size : 0));
- if (dyn_size != 0)
- dyn_size = pcpue_size - static_size - reserved_size;
-
- if (unit_size >= 0) {
- BUG_ON(unit_size < pcpue_size);
- pcpue_unit_size = unit_size;
- } else
- pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
-
- chunk_size = pcpue_unit_size * num_possible_cpus();
-
- pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE,
- __pa(MAX_DMA_ADDRESS));
- if (!pcpue_ptr) {
+ size_sum = pcpu_calc_fc_sizes(static_size, reserved_size, &dyn_size);
+
+ unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE);
+ chunk_size = unit_size * num_possible_cpus();
+
+ base = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE,
+ __pa(MAX_DMA_ADDRESS));
+ if (!base) {
pr_warning("PERCPU: failed to allocate %zu bytes for "
"embedding\n", chunk_size);
return -ENOMEM;
@@ -1260,18 +1476,540 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
/* return the leftover and copy */
for_each_possible_cpu(cpu) {
- void *ptr = pcpue_ptr + cpu * pcpue_unit_size;
+ void *ptr = base + cpu * unit_size;
- free_bootmem(__pa(ptr + pcpue_size),
- pcpue_unit_size - pcpue_size);
+ free_bootmem(__pa(ptr + size_sum), unit_size - size_sum);
memcpy(ptr, __per_cpu_load, static_size);
}
/* we're ready, commit */
pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n",
- pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size);
+ size_sum >> PAGE_SHIFT, base, static_size);
+
+ return pcpu_setup_first_chunk(static_size, reserved_size, dyn_size,
+ unit_size, base, NULL);
+}
+
+/**
+ * pcpu_4k_first_chunk - map the first chunk using PAGE_SIZE pages
+ * @static_size: the size of static percpu area in bytes
+ * @reserved_size: the size of reserved percpu area in bytes
+ * @alloc_fn: function to allocate percpu page, always called with PAGE_SIZE
+ * @free_fn: funtion to free percpu page, always called with PAGE_SIZE
+ * @populate_pte_fn: function to populate pte
+ *
+ * This is a helper to ease setting up embedded first percpu chunk and
+ * can be called where pcpu_setup_first_chunk() is expected.
+ *
+ * This is the basic allocator. Static percpu area is allocated
+ * page-by-page into vmalloc area.
+ *
+ * RETURNS:
+ * The determined pcpu_unit_size which can be used to initialize
+ * percpu access on success, -errno on failure.
+ */
+ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size,
+ pcpu_fc_alloc_fn_t alloc_fn,
+ pcpu_fc_free_fn_t free_fn,
+ pcpu_fc_populate_pte_fn_t populate_pte_fn)
+{
+ static struct vm_struct vm;
+ int unit_pages;
+ size_t pages_size;
+ struct page **pages;
+ unsigned int cpu;
+ int i, j;
+ ssize_t ret;
+
+ unit_pages = PFN_UP(max_t(size_t, static_size + reserved_size,
+ PCPU_MIN_UNIT_SIZE));
+
+ /* unaligned allocations can't be freed, round up to page size */
+ pages_size = PFN_ALIGN(unit_pages * num_possible_cpus() *
+ sizeof(pages[0]));
+ pages = alloc_bootmem(pages_size);
+
+ /* allocate pages */
+ j = 0;
+ for_each_possible_cpu(cpu)
+ for (i = 0; i < unit_pages; i++) {
+ void *ptr;
+
+ ptr = alloc_fn(cpu, PAGE_SIZE);
+ if (!ptr) {
+ pr_warning("PERCPU: failed to allocate "
+ "4k page for cpu%u\n", cpu);
+ goto enomem;
+ }
+ pages[j++] = virt_to_page(ptr);
+ }
+
+ /* allocate vm area, map the pages and copy static data */
+ vm.flags = VM_ALLOC;
+ vm.size = num_possible_cpus() * unit_pages << PAGE_SHIFT;
+ vm_area_register_early(&vm, PAGE_SIZE);
+
+ for_each_possible_cpu(cpu) {
+ unsigned long unit_addr = (unsigned long)vm.addr +
+ (cpu * unit_pages << PAGE_SHIFT);
+
+ for (i = 0; i < unit_pages; i++)
+ populate_pte_fn(unit_addr + (i << PAGE_SHIFT));
+
+ /* pte already populated, the following shouldn't fail */
+ ret = __pcpu_map_pages(unit_addr, &pages[cpu * unit_pages],
+ unit_pages);
+ if (ret < 0)
+ panic("failed to map percpu area, err=%zd\n", ret);
+
+ /*
+ * FIXME: Archs with virtual cache should flush local
+ * cache for the linear mapping here - something
+ * equivalent to flush_cache_vmap() on the local cpu.
+ * flush_cache_vmap() can't be used as most supporting
+ * data structures are not set up yet.
+ */
+
+ /* copy static data */
+ memcpy((void *)unit_addr, __per_cpu_load, static_size);
+ }
+
+ /* we're ready, commit */
+ pr_info("PERCPU: %d 4k pages per cpu, static data %zu bytes\n",
+ unit_pages, static_size);
+
+ ret = pcpu_setup_first_chunk(static_size, reserved_size, -1,
+ unit_pages << PAGE_SHIFT, vm.addr, NULL);
+ goto out_free_ar;
+
+enomem:
+ while (--j >= 0)
+ free_fn(page_address(pages[j]), PAGE_SIZE);
+ ret = -ENOMEM;
+out_free_ar:
+ free_bootmem(__pa(pages), pages_size);
+ return ret;
+}
+
+/*
+ * Large page remapping first chunk setup helper
+ */
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+
+/**
+ * pcpu_lpage_build_unit_map - build unit_map for large page remapping
+ * @static_size: the size of static percpu area in bytes
+ * @reserved_size: the size of reserved percpu area in bytes
+ * @dyn_sizep: in/out parameter for dynamic size, -1 for auto
+ * @unit_sizep: out parameter for unit size
+ * @unit_map: unit_map to be filled
+ * @cpu_distance_fn: callback to determine distance between cpus
+ *
+ * This function builds cpu -> unit map and determine other parameters
+ * considering needed percpu size, large page size and distances
+ * between CPUs in NUMA.
+ *
+ * CPUs which are of LOCAL_DISTANCE both ways are grouped together and
+ * may share units in the same large page. The returned configuration
+ * is guaranteed to have CPUs on different nodes on different large
+ * pages and >=75% usage of allocated virtual address space.
+ *
+ * RETURNS:
+ * On success, fills in @unit_map, sets *@dyn_sizep, *@unit_sizep and
+ * returns the number of units to be allocated. -errno on failure.
+ */
+int __init pcpu_lpage_build_unit_map(size_t static_size, size_t reserved_size,
+ ssize_t *dyn_sizep, size_t *unit_sizep,
+ size_t lpage_size, int *unit_map,
+ pcpu_fc_cpu_distance_fn_t cpu_distance_fn)
+{
+ static int group_map[NR_CPUS] __initdata;
+ static int group_cnt[NR_CPUS] __initdata;
+ int group_cnt_max = 0;
+ size_t size_sum, min_unit_size, alloc_size;
+ int upa, max_upa, uninitialized_var(best_upa); /* units_per_alloc */
+ int last_allocs;
+ unsigned int cpu, tcpu;
+ int group, unit;
+
+ /*
+ * Determine min_unit_size, alloc_size and max_upa such that
+ * alloc_size is multiple of lpage_size and is the smallest
+ * which can accomodate 4k aligned segments which are equal to
+ * or larger than min_unit_size.
+ */
+ size_sum = pcpu_calc_fc_sizes(static_size, reserved_size, dyn_sizep);
+ min_unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE);
+
+ alloc_size = roundup(min_unit_size, lpage_size);
+ upa = alloc_size / min_unit_size;
+ while (alloc_size % upa || ((alloc_size / upa) & ~PAGE_MASK))
+ upa--;
+ max_upa = upa;
+
+ /* group cpus according to their proximity */
+ for_each_possible_cpu(cpu) {
+ group = 0;
+ next_group:
+ for_each_possible_cpu(tcpu) {
+ if (cpu == tcpu)
+ break;
+ if (group_map[tcpu] == group &&
+ (cpu_distance_fn(cpu, tcpu) > LOCAL_DISTANCE ||
+ cpu_distance_fn(tcpu, cpu) > LOCAL_DISTANCE)) {
+ group++;
+ goto next_group;
+ }
+ }
+ group_map[cpu] = group;
+ group_cnt[group]++;
+ group_cnt_max = max(group_cnt_max, group_cnt[group]);
+ }
+
+ /*
+ * Expand unit size until address space usage goes over 75%
+ * and then as much as possible without using more address
+ * space.
+ */
+ last_allocs = INT_MAX;
+ for (upa = max_upa; upa; upa--) {
+ int allocs = 0, wasted = 0;
+
+ if (alloc_size % upa || ((alloc_size / upa) & ~PAGE_MASK))
+ continue;
+
+ for (group = 0; group_cnt[group]; group++) {
+ int this_allocs = DIV_ROUND_UP(group_cnt[group], upa);
+ allocs += this_allocs;
+ wasted += this_allocs * upa - group_cnt[group];
+ }
+
+ /*
+ * Don't accept if wastage is over 25%. The
+ * greater-than comparison ensures upa==1 always
+ * passes the following check.
+ */
+ if (wasted > num_possible_cpus() / 3)
+ continue;
+
+ /* and then don't consume more memory */
+ if (allocs > last_allocs)
+ break;
+ last_allocs = allocs;
+ best_upa = upa;
+ }
+ *unit_sizep = alloc_size / best_upa;
- return pcpu_setup_first_chunk(pcpue_get_page, static_size,
- reserved_size, dyn_size,
- pcpue_unit_size, pcpue_ptr, NULL);
+ /* assign units to cpus accordingly */
+ unit = 0;
+ for (group = 0; group_cnt[group]; group++) {
+ for_each_possible_cpu(cpu)
+ if (group_map[cpu] == group)
+ unit_map[cpu] = unit++;
+ unit = roundup(unit, best_upa);
+ }
+
+ return unit; /* unit contains aligned number of units */
+}
+
+struct pcpul_ent {
+ void *ptr;
+ void *map_addr;
+};
+
+static size_t pcpul_size;
+static size_t pcpul_lpage_size;
+static int pcpul_nr_lpages;
+static struct pcpul_ent *pcpul_map;
+
+static bool __init pcpul_unit_to_cpu(int unit, const int *unit_map,
+ unsigned int *cpup)
+{
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu)
+ if (unit_map[cpu] == unit) {
+ if (cpup)
+ *cpup = cpu;
+ return true;
+ }
+
+ return false;
+}
+
+static void __init pcpul_lpage_dump_cfg(const char *lvl, size_t static_size,
+ size_t reserved_size, size_t dyn_size,
+ size_t unit_size, size_t lpage_size,
+ const int *unit_map, int nr_units)
+{
+ int width = 1, v = nr_units;
+ char empty_str[] = "--------";
+ int upl, lpl; /* units per lpage, lpage per line */
+ unsigned int cpu;
+ int lpage, unit;
+
+ while (v /= 10)
+ width++;
+ empty_str[min_t(int, width, sizeof(empty_str) - 1)] = '\0';
+
+ upl = max_t(int, lpage_size / unit_size, 1);
+ lpl = rounddown_pow_of_two(max_t(int, 60 / (upl * (width + 1) + 2), 1));
+
+ printk("%spcpu-lpage: sta/res/dyn=%zu/%zu/%zu unit=%zu lpage=%zu", lvl,
+ static_size, reserved_size, dyn_size, unit_size, lpage_size);
+
+ for (lpage = 0, unit = 0; unit < nr_units; unit++) {
+ if (!(unit % upl)) {
+ if (!(lpage++ % lpl)) {
+ printk("\n");
+ printk("%spcpu-lpage: ", lvl);
+ } else
+ printk("| ");
+ }
+ if (pcpul_unit_to_cpu(unit, unit_map, &cpu))
+ printk("%0*d ", width, cpu);
+ else
+ printk("%s ", empty_str);
+ }
+ printk("\n");
+}
+
+/**
+ * pcpu_lpage_first_chunk - remap the first percpu chunk using large page
+ * @static_size: the size of static percpu area in bytes
+ * @reserved_size: the size of reserved percpu area in bytes
+ * @dyn_size: free size for dynamic allocation in bytes
+ * @unit_size: unit size in bytes
+ * @lpage_size: the size of a large page
+ * @unit_map: cpu -> unit mapping
+ * @nr_units: the number of units
+ * @alloc_fn: function to allocate percpu lpage, always called with lpage_size
+ * @free_fn: function to free percpu memory, @size <= lpage_size
+ * @map_fn: function to map percpu lpage, always called with lpage_size
+ *
+ * This allocator uses large page to build and map the first chunk.
+ * Unlike other helpers, the caller should always specify @dyn_size
+ * and @unit_size. These parameters along with @unit_map and
+ * @nr_units can be determined using pcpu_lpage_build_unit_map().
+ * This two stage initialization is to allow arch code to evaluate the
+ * parameters before committing to it.
+ *
+ * Large pages are allocated as directed by @unit_map and other
+ * parameters and mapped to vmalloc space. Unused holes are returned
+ * to the page allocator. Note that these holes end up being actively
+ * mapped twice - once to the physical mapping and to the vmalloc area
+ * for the first percpu chunk. Depending on architecture, this might
+ * cause problem when changing page attributes of the returned area.
+ * These double mapped areas can be detected using
+ * pcpu_lpage_remapped().
+ *
+ * RETURNS:
+ * The determined pcpu_unit_size which can be used to initialize
+ * percpu access on success, -errno on failure.
+ */
+ssize_t __init pcpu_lpage_first_chunk(size_t static_size, size_t reserved_size,
+ size_t dyn_size, size_t unit_size,
+ size_t lpage_size, const int *unit_map,
+ int nr_units,
+ pcpu_fc_alloc_fn_t alloc_fn,
+ pcpu_fc_free_fn_t free_fn,
+ pcpu_fc_map_fn_t map_fn)
+{
+ static struct vm_struct vm;
+ size_t chunk_size = unit_size * nr_units;
+ size_t map_size;
+ unsigned int cpu;
+ ssize_t ret;
+ int i, j, unit;
+
+ pcpul_lpage_dump_cfg(KERN_DEBUG, static_size, reserved_size, dyn_size,
+ unit_size, lpage_size, unit_map, nr_units);
+
+ BUG_ON(chunk_size % lpage_size);
+
+ pcpul_size = static_size + reserved_size + dyn_size;
+ pcpul_lpage_size = lpage_size;
+ pcpul_nr_lpages = chunk_size / lpage_size;
+
+ /* allocate pointer array and alloc large pages */
+ map_size = pcpul_nr_lpages * sizeof(pcpul_map[0]);
+ pcpul_map = alloc_bootmem(map_size);
+
+ /* allocate all pages */
+ for (i = 0; i < pcpul_nr_lpages; i++) {
+ size_t offset = i * lpage_size;
+ int first_unit = offset / unit_size;
+ int last_unit = (offset + lpage_size - 1) / unit_size;
+ void *ptr;
+
+ /* find out which cpu is mapped to this unit */
+ for (unit = first_unit; unit <= last_unit; unit++)
+ if (pcpul_unit_to_cpu(unit, unit_map, &cpu))
+ goto found;
+ continue;
+ found:
+ ptr = alloc_fn(cpu, lpage_size);
+ if (!ptr) {
+ pr_warning("PERCPU: failed to allocate large page "
+ "for cpu%u\n", cpu);
+ goto enomem;
+ }
+
+ pcpul_map[i].ptr = ptr;
+ }
+
+ /* return unused holes */
+ for (unit = 0; unit < nr_units; unit++) {
+ size_t start = unit * unit_size;
+ size_t end = start + unit_size;
+ size_t off, next;
+
+ /* don't free used part of occupied unit */
+ if (pcpul_unit_to_cpu(unit, unit_map, NULL))
+ start += pcpul_size;
+
+ /* unit can span more than one page, punch the holes */
+ for (off = start; off < end; off = next) {
+ void *ptr = pcpul_map[off / lpage_size].ptr;
+ next = min(roundup(off + 1, lpage_size), end);
+ if (ptr)
+ free_fn(ptr + off % lpage_size, next - off);
+ }
+ }
+
+ /* allocate address, map and copy */
+ vm.flags = VM_ALLOC;
+ vm.size = chunk_size;
+ vm_area_register_early(&vm, unit_size);
+
+ for (i = 0; i < pcpul_nr_lpages; i++) {
+ if (!pcpul_map[i].ptr)
+ continue;
+ pcpul_map[i].map_addr = vm.addr + i * lpage_size;
+ map_fn(pcpul_map[i].ptr, lpage_size, pcpul_map[i].map_addr);
+ }
+
+ for_each_possible_cpu(cpu)
+ memcpy(vm.addr + unit_map[cpu] * unit_size, __per_cpu_load,
+ static_size);
+
+ /* we're ready, commit */
+ pr_info("PERCPU: Remapped at %p with large pages, static data "
+ "%zu bytes\n", vm.addr, static_size);
+
+ ret = pcpu_setup_first_chunk(static_size, reserved_size, dyn_size,
+ unit_size, vm.addr, unit_map);
+
+ /*
+ * Sort pcpul_map array for pcpu_lpage_remapped(). Unmapped
+ * lpages are pushed to the end and trimmed.
+ */
+ for (i = 0; i < pcpul_nr_lpages - 1; i++)
+ for (j = i + 1; j < pcpul_nr_lpages; j++) {
+ struct pcpul_ent tmp;
+
+ if (!pcpul_map[j].ptr)
+ continue;
+ if (pcpul_map[i].ptr &&
+ pcpul_map[i].ptr < pcpul_map[j].ptr)
+ continue;
+
+ tmp = pcpul_map[i];
+ pcpul_map[i] = pcpul_map[j];
+ pcpul_map[j] = tmp;
+ }
+
+ while (pcpul_nr_lpages && !pcpul_map[pcpul_nr_lpages - 1].ptr)
+ pcpul_nr_lpages--;
+
+ return ret;
+
+enomem:
+ for (i = 0; i < pcpul_nr_lpages; i++)
+ if (pcpul_map[i].ptr)
+ free_fn(pcpul_map[i].ptr, lpage_size);
+ free_bootmem(__pa(pcpul_map), map_size);
+ return -ENOMEM;
+}
+
+/**
+ * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area
+ * @kaddr: the kernel address in question
+ *
+ * Determine whether @kaddr falls in the pcpul recycled area. This is
+ * used by pageattr to detect VM aliases and break up the pcpu large
+ * page mapping such that the same physical page is not mapped under
+ * different attributes.
+ *
+ * The recycled area is always at the tail of a partially used large
+ * page.
+ *
+ * RETURNS:
+ * Address of corresponding remapped pcpu address if match is found;
+ * otherwise, NULL.
+ */
+void *pcpu_lpage_remapped(void *kaddr)
+{
+ unsigned long lpage_mask = pcpul_lpage_size - 1;
+ void *lpage_addr = (void *)((unsigned long)kaddr & ~lpage_mask);
+ unsigned long offset = (unsigned long)kaddr & lpage_mask;
+ int left = 0, right = pcpul_nr_lpages - 1;
+ int pos;
+
+ /* pcpul in use at all? */
+ if (!pcpul_map)
+ return NULL;
+
+ /* okay, perform binary search */
+ while (left <= right) {
+ pos = (left + right) / 2;
+
+ if (pcpul_map[pos].ptr < lpage_addr)
+ left = pos + 1;
+ else if (pcpul_map[pos].ptr > lpage_addr)
+ right = pos - 1;
+ else
+ return pcpul_map[pos].map_addr + offset;
+ }
+
+ return NULL;
+}
+#endif
+
+/*
+ * Generic percpu area setup.
+ *
+ * The embedding helper is used because its behavior closely resembles
+ * the original non-dynamic generic percpu area setup. This is
+ * important because many archs have addressing restrictions and might
+ * fail if the percpu area is located far away from the previous
+ * location. As an added bonus, in non-NUMA cases, embedding is
+ * generally a good idea TLB-wise because percpu area can piggy back
+ * on the physical linear memory mapping which uses large page
+ * mappings on applicable archs.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+
+void __init setup_per_cpu_areas(void)
+{
+ size_t static_size = __per_cpu_end - __per_cpu_start;
+ ssize_t unit_size;
+ unsigned long delta;
+ unsigned int cpu;
+
+ /*
+ * Always reserve area for module percpu variables. That's
+ * what the legacy allocator did.
+ */
+ unit_size = pcpu_embed_first_chunk(static_size, PERCPU_MODULE_RESERVE,
+ PERCPU_DYNAMIC_RESERVE);
+ if (unit_size < 0)
+ panic("Failed to initialized percpu areas.");
+
+ delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+ for_each_possible_cpu(cpu)
+ __per_cpu_offset[cpu] = delta + cpu * unit_size;
}
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
diff --git a/mm/quicklist.c b/mm/quicklist.c
index e66d07d1b4ff..6633965bb27b 100644
--- a/mm/quicklist.c
+++ b/mm/quicklist.c
@@ -19,7 +19,7 @@
#include <linux/module.h>
#include <linux/quicklist.h>
-DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+DEFINE_PER_CPU(struct quicklist [CONFIG_NR_QUICK], quicklist);
#define FRACTION_OF_NODE_MEM 16
@@ -29,7 +29,6 @@ static unsigned long max_pages(unsigned long min_pages)
int node = numa_node_id();
struct zone *zones = NODE_DATA(node)->node_zones;
int num_cpus_on_node;
- const struct cpumask *cpumask_on_node = cpumask_of_node(node);
node_free_pages =
#ifdef CONFIG_ZONE_DMA
@@ -42,7 +41,7 @@ static unsigned long max_pages(unsigned long min_pages)
max = node_free_pages / FRACTION_OF_NODE_MEM;
- num_cpus_on_node = cpus_weight_nr(*cpumask_on_node);
+ num_cpus_on_node = cpumask_weight(cpumask_of_node(node));
max /= num_cpus_on_node;
return max(max, min_pages);
diff --git a/mm/slqb.c b/mm/slqb.c
new file mode 100644
index 000000000000..5588e9a5b6dc
--- /dev/null
+++ b/mm/slqb.c
@@ -0,0 +1,3765 @@
+/*
+ * 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>
+
+/*
+ * 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)) {
+ 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;
+
+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, but this is better than
+ * a static array */
+static DEFINE_PER_CPU(struct kmem_cache_node, kmem_cache_nodes);
+#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 DEFINE_PER_CPU(struct kmem_cache_node, kmem_cpu_nodes); /* 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 DEFINE_PER_CPU(struct kmem_cache_node, kmem_node_nodes); /*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;
+ }
+
+ ret = notifier_from_errno(ret);
+ 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 = &per_cpu(kmem_cache_nodes, i);
+ init_kmem_cache_node(&kmem_cache_cache, n);
+ kmem_cache_cache.node_slab[i] = n;
+#ifdef CONFIG_SMP
+ n = &per_cpu(kmem_cpu_nodes, i);
+ init_kmem_cache_node(&kmem_cpu_cache, n);
+ kmem_cpu_cache.node_slab[i] = n;
+#endif
+ n = &per_cpu(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 b9f1491a58a1..6167e3a05c8b 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -141,6 +141,13 @@
SLAB_POISON | SLAB_STORE_USER)
/*
+ * Debugging flags that require metadata to be stored in the slab. These get
+ * disabled when slub_debug=O is used and a cache's min order increases with
+ * metadata.
+ */
+#define DEBUG_METADATA_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER)
+
+/*
* Set of flags that will prevent slab merging
*/
#define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
@@ -325,6 +332,7 @@ static int slub_debug;
#endif
static char *slub_debug_slabs;
+static int disable_higher_order_debug;
/*
* Object debugging
@@ -976,6 +984,15 @@ static int __init setup_slub_debug(char *str)
*/
goto check_slabs;
+ if (tolower(*str) == 'o') {
+ /*
+ * Avoid enabling debugging on caches if its minimum order
+ * would increase as a result.
+ */
+ disable_higher_order_debug = 1;
+ goto out;
+ }
+
slub_debug = 0;
if (*str == '-')
/*
@@ -1026,8 +1043,8 @@ static unsigned long kmem_cache_flags(unsigned long objsize,
* Enable debugging if selected on the kernel commandline.
*/
if (slub_debug && (!slub_debug_slabs ||
- strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs)) == 0))
- flags |= slub_debug;
+ !strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs))))
+ flags |= slub_debug;
return flags;
}
@@ -1560,6 +1577,10 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
"default order: %d, min order: %d\n", s->name, s->objsize,
s->size, oo_order(s->oo), oo_order(s->min));
+ if (oo_order(s->min) > get_order(s->objsize))
+ printk(KERN_WARNING " %s debugging increased min order, use "
+ "slub_debug=O to disable.\n", s->name);
+
for_each_online_node(node) {
struct kmem_cache_node *n = get_node(s, node);
unsigned long nr_slabs;
@@ -2091,8 +2112,8 @@ init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
*/
#define NR_KMEM_CACHE_CPU 100
-static DEFINE_PER_CPU(struct kmem_cache_cpu,
- kmem_cache_cpu)[NR_KMEM_CACHE_CPU];
+static DEFINE_PER_CPU(struct kmem_cache_cpu [NR_KMEM_CACHE_CPU],
+ kmem_cache_cpu);
static DEFINE_PER_CPU(struct kmem_cache_cpu *, kmem_cache_cpu_free);
static DECLARE_BITMAP(kmem_cach_cpu_free_init_once, CONFIG_NR_CPUS);
@@ -2400,6 +2421,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
* on bootup.
*/
align = calculate_alignment(flags, align, s->objsize);
+ s->align = align;
/*
* SLUB stores one object immediately after another beginning from
@@ -2452,6 +2474,18 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
if (!calculate_sizes(s, -1))
goto error;
+ if (disable_higher_order_debug) {
+ /*
+ * Disable debugging flags that store metadata if the min slab
+ * order increased.
+ */
+ if (get_order(s->size) > get_order(s->objsize)) {
+ s->flags &= ~DEBUG_METADATA_FLAGS;
+ s->offset = 0;
+ if (!calculate_sizes(s, -1))
+ goto error;
+ }
+ }
/*
* The larger the object size is, the more pages we want on the partial
@@ -4543,8 +4577,11 @@ static int sysfs_slab_add(struct kmem_cache *s)
}
err = sysfs_create_group(&s->kobj, &slab_attr_group);
- if (err)
+ if (err) {
+ kobject_del(&s->kobj);
+ kobject_put(&s->kobj);
return err;
+ }
kobject_uevent(&s->kobj, KOBJ_ADD);
if (!unmergeable) {
/* Setup first alias */
@@ -4559,6 +4596,7 @@ static void sysfs_slab_remove(struct kmem_cache *s)
kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj);
kobject_put(&s->kobj);
+ kfree(s);
}
/*
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 42cd38eba79f..5ae6b8b78c80 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -34,6 +34,7 @@ static const struct address_space_operations swap_aops = {
};
static struct backing_dev_info swap_backing_dev_info = {
+ .name = "swap",
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
.unplug_io_fn = swap_unplug_io_fn,
};
diff --git a/mm/swapfile.c b/mm/swapfile.c
index d1ade1a48ee7..8ffdc0d23c53 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -753,7 +753,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
if (!bdev) {
if (bdev_p)
- *bdev_p = bdget(sis->bdev->bd_dev);
+ *bdev_p = bdgrab(sis->bdev);
spin_unlock(&swap_lock);
return i;
@@ -765,7 +765,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
struct swap_extent, list);
if (se->start_block == offset) {
if (bdev_p)
- *bdev_p = bdget(sis->bdev->bd_dev);
+ *bdev_p = bdgrab(sis->bdev);
spin_unlock(&swap_lock);
bdput(bdev);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index dea7abd31098..fe8e986bb6a6 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1715,7 +1715,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
*/
if (total_scanned > sc->swap_cluster_max +
sc->swap_cluster_max / 2) {
- wakeup_pdflush(laptop_mode ? 0 : total_scanned);
+ wakeup_flusher_threads(laptop_mode ? 0 : total_scanned);
sc->may_writepage = 1;
}
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index fe649081fbdc..a1f16303703a 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -225,12 +225,6 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
return -EOPNOTSUPP;
}
- /* The real device must be up and operating in order to
- * assosciate a VLAN device with it.
- */
- if (!(real_dev->flags & IFF_UP))
- return -ENETDOWN;
-
if (__find_vlan_dev(real_dev, vlan_id) != NULL)
return -EEXIST;
@@ -468,6 +462,19 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
}
break;
+ case NETDEV_CHANGEMTU:
+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ vlandev = vlan_group_get_device(grp, i);
+ if (!vlandev)
+ continue;
+
+ if (vlandev->mtu <= dev->mtu)
+ continue;
+
+ dev_set_mtu(vlandev, dev->mtu);
+ }
+ break;
+
case NETDEV_FEAT_CHANGE:
/* Propagate device features to underlying device */
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
diff --git a/net/9p/client.c b/net/9p/client.c
index 787ccddb85ea..7bbd2d5ae8d3 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -60,9 +60,9 @@ static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
/**
- * v9fs_parse_options - parse mount options into session structure
- * @options: options string passed from mount
- * @v9ses: existing v9fs session information
+ * parse_options - parse mount options into client structure
+ * @opts: options string passed from mount
+ * @clnt: existing v9fs client information
*
* Return 0 upon success, -ERRNO upon failure
*/
@@ -232,7 +232,7 @@ EXPORT_SYMBOL(p9_tag_lookup);
/**
* p9_tag_init - setup tags structure and contents
- * @tags: tags structure from the client struct
+ * @c: v9fs client struct
*
* This initializes the tags structure for each client instance.
*
@@ -258,7 +258,7 @@ error:
/**
* p9_tag_cleanup - cleans up tags structure and reclaims resources
- * @tags: tags structure from the client struct
+ * @c: v9fs client struct
*
* This frees resources associated with the tags structure
*
@@ -430,8 +430,8 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
/**
* p9_client_flush - flush (cancel) a request
- * c: client state
- * req: request to cancel
+ * @c: client state
+ * @oldreq: request to cancel
*
* This sents a flush for a particular requests and links
* the flush request to the original request. The current
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 8c2588e4edc0..8d934dd7fd54 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -119,8 +119,8 @@ struct p9_poll_wait {
* @wpos: write position for current frame
* @wsize: amount of data to write for current frame
* @wbuf: current write buffer
+ * @poll_pending_link: pending links to be polled per conn
* @poll_wait: array of wait_q's for various worker threads
- * @poll_waddr: ????
* @pt: poll state
* @rq: current read work
* @wq: current write work
@@ -700,9 +700,9 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
}
/**
- * parse_options - parse mount options into session structure
- * @options: options string passed from mount
- * @opts: transport-specific structure to parse options into
+ * parse_opts - parse mount options into p9_fd_opts structure
+ * @params: options string passed from mount
+ * @opts: fd transport-specific structure to parse options into
*
* Returns 0 upon success, -ERRNO upon failure
*/
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index ac4990041ebb..65cb29db03f8 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -67,14 +67,15 @@
* @pd: Protection Domain pointer
* @qp: Queue Pair pointer
* @cq: Completion Queue pointer
+ * @dm_mr: DMA Memory Region pointer
* @lkey: The local access only memory region key
* @timeout: Number of uSecs to wait for connection management events
* @sq_depth: The depth of the Send Queue
* @sq_sem: Semaphore for the SQ
* @rq_depth: The depth of the Receive Queue.
+ * @rq_count: Count of requests in the Receive Queue.
* @addr: The remote peer's address
* @req_lock: Protects the active request list
- * @send_wait: Wait list when the SQ fills up
* @cm_done: Completion event for connection management tracking
*/
struct p9_trans_rdma {
@@ -154,9 +155,9 @@ static match_table_t tokens = {
};
/**
- * parse_options - parse mount options into session structure
- * @options: options string passed from mount
- * @opts: transport-specific structure to parse options into
+ * parse_opts - parse mount options into rdma options structure
+ * @params: options string passed from mount
+ * @opts: rdma transport-specific structure to parse options into
*
* Returns 0 upon success, -ERRNO upon failure
*/
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index a49484e67e1d..9bf0b737aa51 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -57,11 +57,9 @@ static int chan_index;
* @initialized: whether the channel is initialized
* @inuse: whether the channel is in use
* @lock: protects multiple elements within this structure
+ * @client: client instance
* @vdev: virtio dev associated with this channel
* @vq: virtio queue associated with this channel
- * @tagpool: accounting for tag ids (and request slots)
- * @reqs: array of request slots
- * @max_tag: current number of request_slots allocated
* @sg: scatter gather list which is used to pack a request (protected?)
*
* We keep all per-channel information in a structure.
@@ -92,7 +90,7 @@ static unsigned int rest_of_page(void *data)
/**
* p9_virtio_close - reclaim resources of a channel
- * @trans: transport state
+ * @client: client instance
*
* This reclaims a channel by freeing its resources and
* reseting its inuse flag.
@@ -181,9 +179,8 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
/**
* p9_virtio_request - issue a request
- * @t: transport state
- * @tc: &p9_fcall request to transmit
- * @rc: &p9_fcall to put reponse into
+ * @client: client instance issuing the request
+ * @req: request to be issued
*
*/
diff --git a/net/Kconfig b/net/Kconfig
index 7051b9710675..041c35edb763 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -23,6 +23,26 @@ menuconfig NET
if NET
+config WANT_COMPAT_NETLINK_MESSAGES
+ bool
+ help
+ This option can be selected by other options that need compat
+ netlink messages.
+
+config COMPAT_NETLINK_MESSAGES
+ def_bool y
+ depends on COMPAT
+ depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES
+ help
+ This option makes it possible to send different netlink messages
+ to tasks depending on whether the task is a compat task or not. To
+ achieve this, you need to set skb_shinfo(skb)->frag_list to the
+ compat skb before sending the skb, the netlink code will sort out
+ which message to actually pass to the task.
+
+ Newly written code should NEVER need this option but do
+ compat-independent messages instead!
+
menu "Networking options"
source "net/packet/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index ba324aefda73..1542e7268a7b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -24,7 +24,6 @@ obj-y += ipv6/
endif
obj-$(CONFIG_PACKET) += packet/
obj-$(CONFIG_NET_KEY) += key/
-obj-$(CONFIG_NET_SCHED) += sched/
obj-$(CONFIG_BRIDGE) += bridge/
obj-$(CONFIG_NET_DSA) += dsa/
obj-$(CONFIG_IPX) += ipx/
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 2912665fc58c..848af113ba2a 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -238,7 +238,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* netif_stop_queue(dev); */
dev_kfree_skb(skb);
read_unlock(&devs_lock);
- return 0;
+ return NETDEV_TX_OK;
}
if (!br2684_xmit_vcc(skb, dev, brvcc)) {
/*
@@ -252,7 +252,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_fifo_errors++;
}
read_unlock(&devs_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/net/atm/clip.c b/net/atm/clip.c
index e65a3b1477f8..64910bb86089 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -373,7 +373,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n");
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (!skb_dst(skb)->neighbour) {
#if 0
@@ -387,7 +387,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
if (!entry->vccs) {
@@ -402,7 +402,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
}
- return 0;
+ return NETDEV_TX_OK;
}
pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
@@ -421,14 +421,14 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
if (old) {
printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
- return 0;
+ return NETDEV_TX_OK;
}
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
if (atm_may_send(vcc, 0)) {
entry->vccs->xoff = 0;
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&clip_priv->xoff_lock, flags);
netif_stop_queue(dev); /* XOFF -> throttle immediately */
@@ -440,7 +440,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
of the brief netif_stop_queue. If this isn't true or if it
changes, use netif_wake_queue instead. */
spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static int clip_mkip(struct atm_vcc *vcc, int timeout)
diff --git a/net/atm/lec.c b/net/atm/lec.c
index ff2e594dca9b..c463868c993b 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -289,7 +289,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL)
- return 0;
+ return NETDEV_TX_OK;
skb = skb2;
}
skb_push(skb, 2);
@@ -307,7 +307,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL)
- return 0;
+ return NETDEV_TX_OK;
skb = skb2;
}
#endif
@@ -345,7 +345,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
if (skb2 == NULL) {
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
skb = skb2;
}
@@ -416,7 +416,7 @@ out:
if (entry)
lec_arp_put(entry);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* The inverse routine to net_open(). */
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index e5bf11453a18..1ac4b94bf626 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -554,7 +554,7 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
while (i < mpc->number_of_mps_macs) {
if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN)))
if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */
- return 0; /* success! */
+ return NETDEV_TX_OK; /* success! */
i++;
}
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index d7a0e9722def..9c42990126a0 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -175,14 +175,14 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_BT_BNEP_MC_FILTER
if (bnep_net_mc_filter(skb, s)) {
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
if (bnep_net_proto_filter(skb, s)) {
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
@@ -203,7 +203,7 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static const struct net_device_ops bnep_netdev_ops = {
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index b18676870d55..a9f7afb6ee35 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -374,6 +374,7 @@ static void hidp_process_hid_control(struct hidp_session *session,
/* Kill session thread */
atomic_inc(&session->terminate);
+ hidp_schedule(session);
}
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index bd0a4c1bced0..7ce1a24735c8 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -50,7 +50,9 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
-#define VERSION "2.13"
+#define VERSION "2.14"
+
+static int enable_ertm = 0;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -715,12 +717,16 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->imtu = l2cap_pi(parent)->imtu;
pi->omtu = l2cap_pi(parent)->omtu;
+ pi->mode = l2cap_pi(parent)->mode;
+ pi->fcs = l2cap_pi(parent)->fcs;
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
pi->force_reliable = l2cap_pi(parent)->force_reliable;
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
+ pi->mode = L2CAP_MODE_BASIC;
+ pi->fcs = L2CAP_FCS_CRC16;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
@@ -956,6 +962,18 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
goto done;
}
+ switch (l2cap_pi(sk)->mode) {
+ case L2CAP_MODE_BASIC:
+ break;
+ case L2CAP_MODE_ERTM:
+ if (enable_ertm)
+ break;
+ /* fall through */
+ default:
+ err = -ENOTSUPP;
+ goto done;
+ }
+
switch (sk->sk_state) {
case BT_CONNECT:
case BT_CONNECT2:
@@ -1007,6 +1025,18 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
goto done;
}
+ switch (l2cap_pi(sk)->mode) {
+ case L2CAP_MODE_BASIC:
+ break;
+ case L2CAP_MODE_ERTM:
+ if (enable_ertm)
+ break;
+ /* fall through */
+ default:
+ err = -ENOTSUPP;
+ goto done;
+ }
+
if (!l2cap_pi(sk)->psm) {
bdaddr_t *src = &bt_sk(sk)->src;
u16 psm;
@@ -1257,7 +1287,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to;
- opts.mode = L2CAP_MODE_BASIC;
+ opts.mode = l2cap_pi(sk)->mode;
len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *) &opts, optval, len)) {
@@ -1265,8 +1295,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
break;
}
- l2cap_pi(sk)->imtu = opts.imtu;
- l2cap_pi(sk)->omtu = opts.omtu;
+ l2cap_pi(sk)->imtu = opts.imtu;
+ l2cap_pi(sk)->omtu = opts.omtu;
+ l2cap_pi(sk)->mode = opts.mode;
break;
case L2CAP_LM:
@@ -1379,7 +1410,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to;
- opts.mode = L2CAP_MODE_BASIC;
+ opts.mode = l2cap_pi(sk)->mode;
len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *) &opts, len))
@@ -1712,12 +1743,29 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_conf_req *req = data;
+ struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
void *ptr = req->data;
BT_DBG("sk %p", sk);
- if (pi->imtu != L2CAP_DEFAULT_MTU)
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+ switch (pi->mode) {
+ case L2CAP_MODE_BASIC:
+ if (pi->imtu != L2CAP_DEFAULT_MTU)
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+ break;
+
+ case L2CAP_MODE_ERTM:
+ rfc.mode = L2CAP_MODE_ERTM;
+ rfc.txwin_size = L2CAP_DEFAULT_RX_WINDOW;
+ rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE;
+ rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+ rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+ rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU);
+
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
+ sizeof(rfc), (unsigned long) &rfc);
+ break;
+ }
/* FIXME: Need actual value of the flush timeout */
//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
@@ -1797,7 +1845,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
rfc.mode = L2CAP_MODE_BASIC;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
+ sizeof(rfc), (unsigned long) &rfc);
}
}
@@ -2205,10 +2253,13 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
if (type == L2CAP_IT_FEAT_MASK) {
u8 buf[8];
+ u32 feat_mask = l2cap_feat_mask;
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
- put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
+ if (enable_ertm)
+ feat_mask |= L2CAP_FEAT_ERTM;
+ put_unaligned(cpu_to_le32(feat_mask), (__le32 *) rsp->data);
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else if (type == L2CAP_IT_FIXED_CHAN) {
@@ -2828,6 +2879,9 @@ EXPORT_SYMBOL(l2cap_load);
module_init(l2cap_init);
module_exit(l2cap_exit);
+module_param(enable_ertm, bool, 0644);
+MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode");
+
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 51ae0c3e470a..13c27f17192c 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -359,20 +359,9 @@ static void sco_sock_kill(struct sock *sk)
sock_put(sk);
}
-/* Close socket.
- * Must be called on unlocked socket.
- */
-static void sco_sock_close(struct sock *sk)
+static void __sco_sock_close(struct sock *sk)
{
- struct sco_conn *conn;
-
- sco_sock_clear_timer(sk);
-
- lock_sock(sk);
-
- conn = sco_pi(sk)->conn;
-
- BT_DBG("sk %p state %d conn %p socket %p", sk, sk->sk_state, conn, sk->sk_socket);
+ BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) {
case BT_LISTEN:
@@ -390,9 +379,15 @@ static void sco_sock_close(struct sock *sk)
sock_set_flag(sk, SOCK_ZAPPED);
break;
}
+}
+/* Must be called on unlocked socket. */
+static void sco_sock_close(struct sock *sk)
+{
+ sco_sock_clear_timer(sk);
+ lock_sock(sk);
+ __sco_sock_close(sk);
release_sock(sk);
-
sco_sock_kill(sk);
}
@@ -748,6 +743,30 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
return err;
}
+static int sco_sock_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+ int err = 0;
+
+ BT_DBG("sock %p, sk %p", sock, sk);
+
+ if (!sk)
+ return 0;
+
+ lock_sock(sk);
+ if (!sk->sk_shutdown) {
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ sco_sock_clear_timer(sk);
+ __sco_sock_close(sk);
+
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+ err = bt_sock_wait_state(sk, BT_CLOSED,
+ sk->sk_lingertime);
+ }
+ release_sock(sk);
+ return err;
+}
+
static int sco_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@@ -969,7 +988,7 @@ static const struct proto_ops sco_sock_ops = {
.ioctl = bt_sock_ioctl,
.mmap = sock_no_mmap,
.socketpair = sock_no_socketpair,
- .shutdown = sock_no_shutdown,
+ .shutdown = sco_sock_shutdown,
.setsockopt = sco_sock_setsockopt,
.getsockopt = sco_sock_getsockopt
};
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 18538d7460d7..15d43ba86b53 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -39,7 +39,7 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
else
br_flood_deliver(br, skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int br_dev_open(struct net_device *dev)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 8a96672e2c5c..eb404dc3ed6e 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -424,7 +424,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
err2:
br_fdb_delete_by_port(br, p, 1);
err1:
- kobject_del(&p->kobj);
+ kobject_put(&p->kobj);
err0:
dev_set_promiscuity(dev, -1);
put_back:
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index d22f611e4004..4fde7425077d 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -905,46 +905,62 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
* ip_refrag() can return NF_STOLEN. */
static struct nf_hook_ops br_nf_ops[] __read_mostly = {
- { .hook = br_nf_pre_routing,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_PRE_ROUTING,
- .priority = NF_BR_PRI_BRNF, },
- { .hook = br_nf_local_in,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_LOCAL_IN,
- .priority = NF_BR_PRI_BRNF, },
- { .hook = br_nf_forward_ip,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_FORWARD,
- .priority = NF_BR_PRI_BRNF - 1, },
- { .hook = br_nf_forward_arp,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_FORWARD,
- .priority = NF_BR_PRI_BRNF, },
- { .hook = br_nf_local_out,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_LOCAL_OUT,
- .priority = NF_BR_PRI_FIRST, },
- { .hook = br_nf_post_routing,
- .owner = THIS_MODULE,
- .pf = PF_BRIDGE,
- .hooknum = NF_BR_POST_ROUTING,
- .priority = NF_BR_PRI_LAST, },
- { .hook = ip_sabotage_in,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_INET_PRE_ROUTING,
- .priority = NF_IP_PRI_FIRST, },
- { .hook = ip_sabotage_in,
- .owner = THIS_MODULE,
- .pf = PF_INET6,
- .hooknum = NF_INET_PRE_ROUTING,
- .priority = NF_IP6_PRI_FIRST, },
+ {
+ .hook = br_nf_pre_routing,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_PRE_ROUTING,
+ .priority = NF_BR_PRI_BRNF,
+ },
+ {
+ .hook = br_nf_local_in,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_LOCAL_IN,
+ .priority = NF_BR_PRI_BRNF,
+ },
+ {
+ .hook = br_nf_forward_ip,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_FORWARD,
+ .priority = NF_BR_PRI_BRNF - 1,
+ },
+ {
+ .hook = br_nf_forward_arp,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_FORWARD,
+ .priority = NF_BR_PRI_BRNF,
+ },
+ {
+ .hook = br_nf_local_out,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_LOCAL_OUT,
+ .priority = NF_BR_PRI_FIRST,
+ },
+ {
+ .hook = br_nf_post_routing,
+ .owner = THIS_MODULE,
+ .pf = PF_BRIDGE,
+ .hooknum = NF_BR_POST_ROUTING,
+ .priority = NF_BR_PRI_LAST,
+ },
+ {
+ .hook = ip_sabotage_in,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP_PRI_FIRST,
+ },
+ {
+ .hook = ip_sabotage_in,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP6_PRI_FIRST,
+ },
};
#ifdef CONFIG_SYSCTL
diff --git a/net/compat.c b/net/compat.c
index 8d739053afe4..12728b17a226 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -743,6 +743,18 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
+asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
+{
+ return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
+}
+
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+ unsigned flags, struct sockaddr __user *addr,
+ int __user *addrlen)
+{
+ return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
+}
+
asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
@@ -788,10 +800,11 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
break;
case SYS_RECV:
- ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]);
+ ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
break;
case SYS_RECVFROM:
- ret = sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), compat_ptr(a[5]));
+ ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
+ compat_ptr(a[4]), compat_ptr(a[5]));
break;
case SYS_SHUTDOWN:
ret = sys_shutdown(a0,a1);
diff --git a/net/core/dev.c b/net/core/dev.c
index 70c27e0c7c32..ddfc02089c84 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1704,7 +1704,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
skb_dst_drop(skb);
rc = ops->ndo_start_xmit(skb, dev);
- if (rc == 0)
+ if (rc == NETDEV_TX_OK)
txq_trans_update(txq);
/*
* TODO: if skb_orphan() was called by
@@ -1730,7 +1730,7 @@ gso:
skb->next = nskb->next;
nskb->next = NULL;
rc = ops->ndo_start_xmit(nskb, dev);
- if (unlikely(rc)) {
+ if (unlikely(rc != NETDEV_TX_OK)) {
nskb->next = skb->next;
skb->next = nskb;
return rc;
@@ -1744,7 +1744,7 @@ gso:
out_kfree_skb:
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static u32 skb_tx_hashrnd;
@@ -3865,10 +3865,12 @@ int dev_unicast_delete(struct net_device *dev, void *addr)
ASSERT_RTNL();
+ netif_addr_lock_bh(dev);
err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
NETDEV_HW_ADDR_T_UNICAST);
if (!err)
__dev_set_rx_mode(dev);
+ netif_addr_unlock_bh(dev);
return err;
}
EXPORT_SYMBOL(dev_unicast_delete);
@@ -3889,10 +3891,12 @@ int dev_unicast_add(struct net_device *dev, void *addr)
ASSERT_RTNL();
+ netif_addr_lock_bh(dev);
err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
NETDEV_HW_ADDR_T_UNICAST);
if (!err)
__dev_set_rx_mode(dev);
+ netif_addr_unlock_bh(dev);
return err;
}
EXPORT_SYMBOL(dev_unicast_add);
@@ -3923,6 +3927,7 @@ int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
}
return err;
}
+EXPORT_SYMBOL_GPL(__dev_addr_sync);
void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
struct dev_addr_list **from, int *from_count)
@@ -3942,6 +3947,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
da = next;
}
}
+EXPORT_SYMBOL_GPL(__dev_addr_unsync);
/**
* dev_unicast_sync - Synchronize device's unicast list to another device
@@ -3949,7 +3955,8 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
* @from: source device
*
* Add newly added addresses to the destination device and release
- * addresses that have no users left.
+ * addresses that have no users left. The source device must be
+ * locked by netif_tx_lock_bh.
*
* This function is intended to be called from the dev->set_rx_mode
* function of layered software devices.
@@ -3958,14 +3965,14 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from)
{
int err = 0;
- ASSERT_RTNL();
-
if (to->addr_len != from->addr_len)
return -EINVAL;
+ netif_addr_lock_bh(to);
err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
if (!err)
__dev_set_rx_mode(to);
+ netif_addr_unlock_bh(to);
return err;
}
EXPORT_SYMBOL(dev_unicast_sync);
@@ -3981,28 +3988,30 @@ EXPORT_SYMBOL(dev_unicast_sync);
*/
void dev_unicast_unsync(struct net_device *to, struct net_device *from)
{
- ASSERT_RTNL();
-
if (to->addr_len != from->addr_len)
return;
+ netif_addr_lock_bh(from);
+ netif_addr_lock(to);
__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
__dev_set_rx_mode(to);
+ netif_addr_unlock(to);
+ netif_addr_unlock_bh(from);
}
EXPORT_SYMBOL(dev_unicast_unsync);
static void dev_unicast_flush(struct net_device *dev)
{
- /* rtnl_mutex must be held here */
-
+ netif_addr_lock_bh(dev);
__hw_addr_flush(&dev->uc);
+ netif_addr_unlock_bh(dev);
}
static void dev_unicast_init(struct net_device *dev)
{
- /* rtnl_mutex must be held here */
-
+ netif_addr_lock_bh(dev);
__hw_addr_init(&dev->uc);
+ netif_addr_unlock_bh(dev);
}
@@ -5342,6 +5351,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
out:
return err;
}
+EXPORT_SYMBOL_GPL(dev_change_net_namespace);
static int dev_cpu_callback(struct notifier_block *nfb,
unsigned long action,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index d9d5160610d5..44e571111d3a 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -30,10 +30,17 @@ u32 ethtool_op_get_link(struct net_device *dev)
return netif_carrier_ok(dev) ? 1 : 0;
}
+u32 ethtool_op_get_rx_csum(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_ALL_CSUM) != 0;
+}
+EXPORT_SYMBOL(ethtool_op_get_rx_csum);
+
u32 ethtool_op_get_tx_csum(struct net_device *dev)
{
return (dev->features & NETIF_F_ALL_CSUM) != 0;
}
+EXPORT_SYMBOL(ethtool_op_get_tx_csum);
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
{
@@ -1004,7 +1011,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
break;
case ETHTOOL_GRXCSUM:
rc = ethtool_get_value(dev, useraddr, ethcmd,
- dev->ethtool_ops->get_rx_csum);
+ (dev->ethtool_ops->get_rx_csum ?
+ dev->ethtool_ops->get_rx_csum :
+ ethtool_op_get_rx_csum));
break;
case ETHTOOL_SRXCSUM:
rc = ethtool_set_rx_csum(dev, useraddr);
@@ -1068,7 +1077,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
break;
case ETHTOOL_GFLAGS:
rc = ethtool_get_value(dev, useraddr, ethcmd,
- dev->ethtool_ops->get_flags);
+ (dev->ethtool_ops->get_flags ?
+ dev->ethtool_ops->get_flags :
+ ethtool_op_get_flags));
break;
case ETHTOOL_SFLAGS:
rc = ethtool_set_value(dev, useraddr,
@@ -1116,7 +1127,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
EXPORT_SYMBOL(ethtool_op_get_link);
EXPORT_SYMBOL(ethtool_op_get_sg);
EXPORT_SYMBOL(ethtool_op_get_tso);
-EXPORT_SYMBOL(ethtool_op_get_tx_csum);
EXPORT_SYMBOL(ethtool_op_set_sg);
EXPORT_SYMBOL(ethtool_op_set_tso);
EXPORT_SYMBOL(ethtool_op_set_tx_csum);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 163b4f5b0365..c6f9ad8e4c7a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1316,7 +1316,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
}
EXPORT_SYMBOL(pneigh_enqueue);
-static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
+static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
struct net *net, int ifindex)
{
struct neigh_parms *p;
@@ -1337,7 +1337,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
struct net *net = dev_net(dev);
const struct net_device_ops *ops = dev->netdev_ops;
- ref = lookup_neigh_params(tbl, net, 0);
+ ref = lookup_neigh_parms(tbl, net, 0);
if (!ref)
return NULL;
@@ -1906,7 +1906,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (tbp[NDTPA_IFINDEX])
ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
- p = lookup_neigh_params(tbl, net, ifindex);
+ p = lookup_neigh_parms(tbl, net, ifindex);
if (p == NULL) {
err = -ENOENT;
goto errout_tbl_lock;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index b7292a2719dc..1c1af2756f38 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -6,6 +6,8 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/idr.h>
+#include <linux/rculist.h>
+#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -127,7 +129,7 @@ static struct net *net_create(void)
rv = setup_net(net);
if (rv == 0) {
rtnl_lock();
- list_add_tail(&net->list, &net_namespace_list);
+ list_add_tail_rcu(&net->list, &net_namespace_list);
rtnl_unlock();
}
mutex_unlock(&net_mutex);
@@ -156,9 +158,16 @@ static void cleanup_net(struct work_struct *work)
/* Don't let anyone else find us. */
rtnl_lock();
- list_del(&net->list);
+ list_del_rcu(&net->list);
rtnl_unlock();
+ /*
+ * Another CPU might be rcu-iterating the list, wait for it.
+ * This needs to be before calling the exit() notifiers, so
+ * the rcu_barrier() below isn't sufficient alone.
+ */
+ synchronize_rcu();
+
/* Run all of the network namespace exit methods */
list_for_each_entry_reverse(ops, &pernet_list, list) {
if (ops->exit)
@@ -193,6 +202,26 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
}
#endif
+struct net *get_net_ns_by_pid(pid_t pid)
+{
+ struct task_struct *tsk;
+ struct net *net;
+
+ /* Lookup the network namespace */
+ net = ERR_PTR(-ESRCH);
+ rcu_read_lock();
+ tsk = find_task_by_vpid(pid);
+ if (tsk) {
+ struct nsproxy *nsproxy;
+ nsproxy = task_nsproxy(tsk);
+ if (nsproxy)
+ net = get_net(nsproxy->net_ns);
+ }
+ rcu_read_unlock();
+ return net;
+}
+EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+
static int __init net_ns_init(void)
{
struct net_generic *ng;
@@ -219,7 +248,7 @@ static int __init net_ns_init(void)
panic("Could not setup the initial network namespace");
rtnl_lock();
- list_add_tail(&init_net.list, &net_namespace_list);
+ list_add_tail_rcu(&init_net.list, &net_namespace_list);
rtnl_unlock();
mutex_unlock(&net_mutex);
@@ -488,7 +517,7 @@ int net_assign_generic(struct net *net, int id, void *data)
*/
ng->len = id;
- memcpy(&ng->ptr, &old_ng->ptr, old_ng->len);
+ memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
rcu_assign_pointer(net->gen, ng);
call_rcu(&old_ng->rcu, net_generic_release);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index df30feb2fc72..0ac309154b0d 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -9,6 +9,7 @@
* Copyright (C) 2002 Red Hat, Inc.
*/
+#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/string.h>
@@ -50,6 +51,9 @@ static atomic_t trapped;
static void zap_completion_queue(void);
static void arp_reply(struct sk_buff *skb);
+static unsigned int carrier_timeout = 4;
+module_param(carrier_timeout, uint, 0644);
+
static void queue_process(struct work_struct *work)
{
struct netpoll_info *npinfo =
@@ -732,7 +736,7 @@ int netpoll_setup(struct netpoll *np)
}
atleast = jiffies + HZ/10;
- atmost = jiffies + 4*HZ;
+ atmost = jiffies + carrier_timeout * HZ;
while (!netif_carrier_ok(ndev)) {
if (time_after(jiffies, atmost)) {
printk(KERN_NOTICE
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index d78030f88bd0..b44775f9f2bf 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -35,7 +35,6 @@
#include <linux/security.h>
#include <linux/mutex.h>
#include <linux/if_addr.h>
-#include <linux/nsproxy.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -52,6 +51,7 @@
#include <net/pkt_sched.h>
#include <net/fib_rules.h>
#include <net/rtnetlink.h>
+#include <net/net_namespace.h>
struct rtnl_link
{
@@ -725,25 +725,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
[IFLA_INFO_DATA] = { .type = NLA_NESTED },
};
-static struct net *get_net_ns_by_pid(pid_t pid)
-{
- struct task_struct *tsk;
- struct net *net;
-
- /* Lookup the network namespace */
- net = ERR_PTR(-ESRCH);
- rcu_read_lock();
- tsk = find_task_by_vpid(pid);
- if (tsk) {
- struct nsproxy *nsproxy;
- nsproxy = task_nsproxy(tsk);
- if (nsproxy)
- net = get_net(nsproxy->net_ns);
- }
- rcu_read_unlock();
- return net;
-}
-
static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
{
if (dev) {
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9e0597d189b0..80a96166df39 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -559,9 +559,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif
#endif
new->vlan_tci = old->vlan_tci;
-#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
- new->do_not_encrypt = old->do_not_encrypt;
-#endif
skb_copy_secmark(new, old);
}
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 94ca8eaace7d..3281013ce038 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1066,7 +1066,7 @@ static int __init dccp_init(void)
(dccp_hashinfo.ehash_size - 1))
dccp_hashinfo.ehash_size--;
dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
- __get_free_pages(GFP_ATOMIC, ehash_order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
} while (!dccp_hashinfo.ehash && --ehash_order > 0);
if (!dccp_hashinfo.ehash) {
@@ -1091,7 +1091,7 @@ static int __init dccp_init(void)
bhash_order > 0)
continue;
dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
- __get_free_pages(GFP_ATOMIC, bhash_order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, bhash_order);
} while (!dccp_hashinfo.bhash && --bhash_order >= 0);
if (!dccp_hashinfo.bhash) {
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 1d6ca8a98dc6..9383d3e5a1ab 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -774,7 +774,7 @@ static int dn_rt_bug(struct sk_buff *skb)
kfree_skb(skb);
- return NET_RX_BAD;
+ return NET_RX_DROP;
}
static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 2e1f836d4240..e114da7ca9b8 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -1072,7 +1072,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
skb->protocol = htons(ETH_P_IP);
skb_pull(skb, sizeof(struct ec_framehdr));
netif_rx(skb);
- return 0;
+ return NET_RX_SUCCESS;
}
sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);
@@ -1083,7 +1083,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
hdr->port))
goto drop;
- return 0;
+ return NET_RX_SUCCESS;
drop:
kfree_skb(skb);
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index 3bb6bdb1dac1..69c8d9207aa7 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -34,8 +34,8 @@
#include <net/tcp_states.h>
#include <net/route.h>
-#include <net/ieee802154/af_ieee802154.h>
-#include <net/ieee802154/netdevice.h>
+#include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
#include "af802154.h"
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index 14d39840dd62..53dd912d52b4 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -26,9 +26,9 @@
#include <linux/if_arp.h>
#include <linux/list.h>
#include <net/sock.h>
-#include <net/ieee802154/af_ieee802154.h>
-#include <net/ieee802154/mac_def.h>
-#include <net/ieee802154/netdevice.h>
+#include <net/af_ieee802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
#include <asm/ioctls.h>
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 27eda9fdf3c2..a615b9d13212 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -27,9 +27,9 @@
#include <net/netlink.h>
#include <net/genetlink.h>
#include <linux/nl802154.h>
-#include <net/ieee802154/af_ieee802154.h>
-#include <net/ieee802154/nl802154.h>
-#include <net/ieee802154/netdevice.h>
+#include <net/af_ieee802154.h>
+#include <net/nl802154.h>
+#include <net/ieee802154_netdev.h>
static unsigned int ieee802154_seq_num;
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index fca44d59f97e..ea8d1f15206e 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -26,7 +26,7 @@
#include <linux/if_arp.h>
#include <linux/list.h>
#include <net/sock.h>
-#include <net/ieee802154/af_ieee802154.h>
+#include <net/af_ieee802154.h>
#include "af802154.h"
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 566ea6c4321d..197d024b2536 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1187,6 +1187,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
int proto;
int ihl;
int id;
+ unsigned int offset = 0;
if (!(features & NETIF_F_V4_CSUM))
features &= ~NETIF_F_SG;
@@ -1229,7 +1230,14 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
skb = segs;
do {
iph = ip_hdr(skb);
- iph->id = htons(id++);
+ if (proto == IPPROTO_UDP) {
+ iph->id = htons(id);
+ iph->frag_off = htons(offset >> 3);
+ if (skb->next != NULL)
+ iph->frag_off |= htons(IP_MF);
+ offset += (skb->len - skb->mac_len - iph->ihl * 4);
+ } else
+ iph->id = htons(id++);
iph->tot_len = htons(skb->len - skb->mac_len);
iph->check = 0;
iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
@@ -1425,6 +1433,8 @@ static struct net_protocol tcp_protocol = {
static struct net_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
+ .gso_send_check = udp4_ufo_send_check,
+ .gso_segment = udp4_ufo_fragment,
.no_policy = 1,
.netns_ok = 1,
};
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index c29d75d8f1b1..090e9991ac2a 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1304,7 +1304,9 @@ static void arp_format_neigh_entry(struct seq_file *seq,
hbuffer[k++] = hex_asc_lo(n->ha[j]);
hbuffer[k++] = ':';
}
- hbuffer[--k] = 0;
+ if (k != 0)
+ --k;
+ hbuffer[k] = 0;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
}
#endif
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 63c2fa7b68c4..d58b49115386 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -164,6 +164,14 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn);
static struct tnode *halve(struct trie *t, struct tnode *tn);
/* tnodes to free after resize(); protected by RTNL */
static struct tnode *tnode_free_head;
+static size_t tnode_free_size;
+
+/*
+ * synchronize_rcu after call_rcu for that many pages; it should be especially
+ * useful before resizing the root node with PREEMPT_NONE configs; the value was
+ * obtained experimentally, aiming to avoid visible slowdown.
+ */
+static const int sync_pages = 128;
static struct kmem_cache *fn_alias_kmem __read_mostly;
static struct kmem_cache *trie_leaf_kmem __read_mostly;
@@ -319,6 +327,8 @@ static const int inflate_threshold = 50;
static const int halve_threshold_root = 15;
static const int inflate_threshold_root = 25;
+static int inflate_threshold_root_fix;
+#define INFLATE_FIX_MAX 10 /* a comment in resize() */
static void __alias_free_mem(struct rcu_head *head)
{
@@ -393,6 +403,8 @@ static void tnode_free_safe(struct tnode *tn)
BUG_ON(IS_LEAF(tn));
tn->tnode_free = tnode_free_head;
tnode_free_head = tn;
+ tnode_free_size += sizeof(struct tnode) +
+ (sizeof(struct node *) << tn->bits);
}
static void tnode_free_flush(void)
@@ -404,6 +416,11 @@ static void tnode_free_flush(void)
tn->tnode_free = NULL;
tnode_free(tn);
}
+
+ if (tnode_free_size >= PAGE_SIZE * sync_pages) {
+ tnode_free_size = 0;
+ synchronize_rcu();
+ }
}
static struct leaf *leaf_new(void)
@@ -602,7 +619,8 @@ static struct node *resize(struct trie *t, struct tnode *tn)
/* Keep root node larger */
if (!tn->parent)
- inflate_threshold_use = inflate_threshold_root;
+ inflate_threshold_use = inflate_threshold_root +
+ inflate_threshold_root_fix;
else
inflate_threshold_use = inflate_threshold;
@@ -626,15 +644,27 @@ static struct node *resize(struct trie *t, struct tnode *tn)
}
if (max_resize < 0) {
- if (!tn->parent)
- pr_warning("Fix inflate_threshold_root."
- " Now=%d size=%d bits\n",
- inflate_threshold_root, tn->bits);
- else
+ if (!tn->parent) {
+ /*
+ * It was observed that during large updates even
+ * inflate_threshold_root = 35 might be needed to avoid
+ * this warning; but it should be temporary, so let's
+ * try to handle this automatically.
+ */
+ if (inflate_threshold_root_fix < INFLATE_FIX_MAX)
+ inflate_threshold_root_fix++;
+ else
+ pr_warning("Fix inflate_threshold_root."
+ " Now=%d size=%d bits fix=%d\n",
+ inflate_threshold_root, tn->bits,
+ inflate_threshold_root_fix);
+ } else {
pr_warning("Fix inflate_threshold."
" Now=%d size=%d bits\n",
inflate_threshold, tn->bits);
- }
+ }
+ } else if (max_resize > 3 && !tn->parent && inflate_threshold_root_fix)
+ inflate_threshold_root_fix--;
check_tnode(tn);
@@ -1435,7 +1465,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
pos, bits);
- n = tnode_get_child(pn, cindex);
+ n = tnode_get_child_rcu(pn, cindex);
if (n == NULL) {
#ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -1570,7 +1600,7 @@ backtrace:
if (chopped_off <= pn->bits) {
cindex &= ~(1 << (chopped_off-1));
} else {
- struct tnode *parent = node_parent((struct node *) pn);
+ struct tnode *parent = node_parent_rcu((struct node *) pn);
if (!parent)
goto failed;
@@ -1783,7 +1813,7 @@ static struct leaf *trie_firstleaf(struct trie *t)
static struct leaf *trie_nextleaf(struct leaf *l)
{
struct node *c = (struct node *) l;
- struct tnode *p = node_parent(c);
+ struct tnode *p = node_parent_rcu(c);
if (!p)
return NULL; /* trie with just one leaf */
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index cb4a0f4bd5e5..b902ef55be7f 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -821,7 +821,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_dropped++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
@@ -889,7 +889,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
IPTUNNEL_XMIT();
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
@@ -898,7 +898,7 @@ tx_error:
stats->tx_errors++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
static int ipgre_tunnel_bind_dev(struct net_device *dev)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 93e2b787da20..98075b6d619c 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -486,7 +486,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_dropped++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
@@ -524,7 +524,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
IPTUNNEL_XMIT();
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
@@ -532,7 +532,7 @@ tx_error:
stats->tx_errors++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
static void ipip_tunnel_bind_dev(struct net_device *dev)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 9a8da5ed92b7..06c33fb6b321 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -212,7 +212,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
IGMPMSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static const struct net_device_ops reg_vif_netdev_ops = {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 278f46f5011b..fafbe163e2b5 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3442,7 +3442,7 @@ int __init ip_rt_init(void)
printk(KERN_ERR "Unable to create route proc files\n");
#ifdef CONFIG_XFRM
xfrm_init();
- xfrm4_init();
+ xfrm4_init(ip_rt_max_size);
#endif
rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index cd2b97f1b6e1..a6e0e077ac33 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -37,12 +37,13 @@ __initcall(init_syncookies);
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
-static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
+ ipv4_cookie_scratch);
static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
u32 count, int c)
{
- __u32 *tmp = __get_cpu_var(cookie_scratch);
+ __u32 *tmp = __get_cpu_var(ipv4_cookie_scratch);
memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c]));
tmp[0] = (__force u32)saddr;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index bd62712848fa..4e004424d400 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -59,6 +59,7 @@ int sysctl_tcp_base_mss __read_mostly = 512;
/* By default, RFC2861 behavior. */
int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
+/* Account for new data that has been sent to the network. */
static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -142,6 +143,7 @@ static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst)
tp->snd_cwnd_used = 0;
}
+/* Congestion state accounting after a packet has been sent. */
static void tcp_event_data_sent(struct tcp_sock *tp,
struct sk_buff *skb, struct sock *sk)
{
@@ -161,6 +163,7 @@ static void tcp_event_data_sent(struct tcp_sock *tp,
icsk->icsk_ack.pingpong = 1;
}
+/* Account for an ACK we sent. */
static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
{
tcp_dec_quickack_mode(sk, pkts);
@@ -276,6 +279,7 @@ static u16 tcp_select_window(struct sock *sk)
return new_win;
}
+/* Packet ECN state for a SYN-ACK */
static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
{
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR;
@@ -283,6 +287,7 @@ static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
}
+/* Packet ECN state for a SYN. */
static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -301,6 +306,9 @@ TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th)
th->ece = 1;
}
+/* Set up ECN state for a packet on a ESTABLISHED socket that is about to
+ * be sent.
+ */
static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
int tcp_header_len)
{
@@ -362,7 +370,9 @@ struct tcp_out_options {
__u32 tsval, tsecr; /* need to include OPTION_TS */
};
-/* Beware: Something in the Internet is very sensitive to the ordering of
+/* Write previously computed TCP options to the packet.
+ *
+ * Beware: Something in the Internet is very sensitive to the ordering of
* TCP options, we learned this through the hard way, so be careful here.
* Luckily we can at least blame others for their non-compliance but from
* inter-operatibility perspective it seems that we're somewhat stuck with
@@ -445,6 +455,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
}
}
+/* Compute TCP options for SYN packets. This is not the final
+ * network wire format yet.
+ */
static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5) {
@@ -493,6 +506,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
return size;
}
+/* Set up TCP options for SYN-ACKs. */
static unsigned tcp_synack_options(struct sock *sk,
struct request_sock *req,
unsigned mss, struct sk_buff *skb,
@@ -541,6 +555,9 @@ static unsigned tcp_synack_options(struct sock *sk,
return size;
}
+/* Compute TCP options for ESTABLISHED sockets. This is not the
+ * final wire format yet.
+ */
static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5) {
@@ -705,7 +722,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
return net_xmit_eval(err);
}
-/* This routine just queue's the buffer
+/* This routine just queues the buffer for sending.
*
* NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames,
* otherwise socket can stall.
@@ -722,6 +739,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
sk_mem_charge(sk, skb->truesize);
}
+/* Initialize TSO segments for a packet. */
static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
unsigned int mss_now)
{
@@ -909,6 +927,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
skb->len = skb->data_len;
}
+/* Remove acked data from a packet in the transmit queue. */
int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
{
if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
@@ -937,7 +956,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
return 0;
}
-/* Not accounting for SACKs here. */
+/* Calculate MSS. Not accounting for SACKs here. */
int tcp_mtu_to_mss(struct sock *sk, int pmtu)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -981,6 +1000,7 @@ int tcp_mss_to_mtu(struct sock *sk, int mss)
return mtu;
}
+/* MTU probing init per socket */
void tcp_mtup_init(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -1143,7 +1163,8 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
return 0;
}
-/* This must be invoked the first time we consider transmitting
+/* Intialize TSO state of a skb.
+ * This must be invoked the first time we consider transmitting
* SKB onto the wire.
*/
static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
@@ -1158,6 +1179,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
return tso_segs;
}
+/* Minshall's variant of the Nagle send check. */
static inline int tcp_minshall_check(const struct tcp_sock *tp)
{
return after(tp->snd_sml, tp->snd_una) &&
@@ -1242,6 +1264,7 @@ static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
return cwnd_quota;
}
+/* Test if sending is allowed right now. */
int tcp_may_send_now(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -1378,6 +1401,10 @@ send_now:
}
/* Create a new MTU probe if we are ready.
+ * MTU probe is regularly attempting to increase the path MTU by
+ * deliberately sending larger packets. This discovers routing
+ * changes resulting in larger path MTUs.
+ *
* Returns 0 if we should wait to probe (no cwnd available),
* 1 if a probe was sent,
* -1 otherwise
@@ -1790,6 +1817,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
sk_wmem_free_skb(sk, next_skb);
}
+/* Check if coalescing SKBs is legal. */
static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
{
if (tcp_skb_pcount(skb) > 1)
@@ -1808,6 +1836,9 @@ static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
return 1;
}
+/* Collapse packets in the retransmit queue to make to create
+ * less packets on the wire. This is only done on retransmission.
+ */
static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
int space)
{
@@ -1957,6 +1988,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
+/* Check if we forward retransmits are possible in the current
+ * window/congestion state.
+ */
static int tcp_can_forward_retransmit(struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2145,7 +2179,8 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTRSTS);
}
-/* WARNING: This routine must only be called when we have already sent
+/* Send a crossed SYN-ACK during socket establishment.
+ * WARNING: This routine must only be called when we have already sent
* a SYN packet that crossed the incoming SYN that caused this routine
* to get called. If this assumption fails then the initial rcv_wnd
* and rcv_wscale values will not be correct.
@@ -2180,9 +2215,7 @@ int tcp_send_synack(struct sock *sk)
return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
}
-/*
- * Prepare a SYN-ACK.
- */
+/* Prepare a SYN-ACK. */
struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req)
{
@@ -2269,9 +2302,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
return skb;
}
-/*
- * Do all connect socket setups that can be done AF independent.
- */
+/* Do all connect socket setups that can be done AF independent. */
static void tcp_connect_init(struct sock *sk)
{
struct dst_entry *dst = __sk_dst_get(sk);
@@ -2330,9 +2361,7 @@ static void tcp_connect_init(struct sock *sk)
tcp_clear_retrans(tp);
}
-/*
- * Build a SYN and send it off.
- */
+/* Build a SYN and send it off. */
int tcp_connect(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -2493,6 +2522,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
}
+/* Initiate keepalive or window probe from timer. */
int tcp_write_wakeup(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 80e3812837ad..29ebb0d27a1e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -110,11 +110,12 @@ struct udp_table udp_table;
EXPORT_SYMBOL(udp_table);
int sysctl_udp_mem[3] __read_mostly;
-int sysctl_udp_rmem_min __read_mostly;
-int sysctl_udp_wmem_min __read_mostly;
-
EXPORT_SYMBOL(sysctl_udp_mem);
+
+int sysctl_udp_rmem_min __read_mostly;
EXPORT_SYMBOL(sysctl_udp_rmem_min);
+
+int sysctl_udp_wmem_min __read_mostly;
EXPORT_SYMBOL(sysctl_udp_wmem_min);
atomic_t udp_memory_allocated;
@@ -158,7 +159,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
*/
int udp_lib_get_port(struct sock *sk, unsigned short snum,
int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2 ) )
+ const struct sock *sk2))
{
struct udp_hslot *hslot;
struct udp_table *udptable = sk->sk_prot->h.udp_table;
@@ -221,14 +222,15 @@ fail_unlock:
fail:
return error;
}
+EXPORT_SYMBOL(udp_lib_get_port);
static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
{
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
- return ( !ipv6_only_sock(sk2) &&
- (!inet1->rcv_saddr || !inet2->rcv_saddr ||
- inet1->rcv_saddr == inet2->rcv_saddr ));
+ return (!ipv6_only_sock(sk2) &&
+ (!inet1->rcv_saddr || !inet2->rcv_saddr ||
+ inet1->rcv_saddr == inet2->rcv_saddr));
}
int udp_v4_get_port(struct sock *sk, unsigned short snum)
@@ -383,8 +385,8 @@ found:
void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
{
struct inet_sock *inet;
- struct iphdr *iph = (struct iphdr*)skb->data;
- struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
+ struct iphdr *iph = (struct iphdr *)skb->data;
+ struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2));
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
struct sock *sk;
@@ -439,7 +441,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
} else {
- ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
+ ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1));
}
sk->sk_err = err;
sk->sk_error_report(sk);
@@ -474,7 +476,7 @@ EXPORT_SYMBOL(udp_flush_pending_frames);
* (checksum field must be zeroed out)
*/
static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
- __be32 src, __be32 dst, int len )
+ __be32 src, __be32 dst, int len)
{
unsigned int offset;
struct udphdr *uh = udp_hdr(skb);
@@ -545,7 +547,7 @@ static int udp_push_pending_frames(struct sock *sk)
} else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
- udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len);
+ udp4_hwcsum_outgoing(sk, skb, fl->fl4_src, fl->fl4_dst, up->len);
goto send;
} else /* `normal' UDP */
@@ -553,7 +555,7 @@ static int udp_push_pending_frames(struct sock *sk)
/* add protocol-dependent pseudo-header */
uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len,
- sk->sk_protocol, csum );
+ sk->sk_protocol, csum);
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
@@ -592,7 +594,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
* Check the flags.
*/
- if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */
+ if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
return -EOPNOTSUPP;
ipc.opt = NULL;
@@ -619,7 +621,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
* Get and verify the address.
*/
if (msg->msg_name) {
- struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
+ struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
if (msg->msg_namelen < sizeof(*usin))
return -EINVAL;
if (usin->sin_family != AF_INET) {
@@ -684,7 +686,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
}
if (connected)
- rt = (struct rtable*)sk_dst_check(sk, 0);
+ rt = (struct rtable *)sk_dst_check(sk, 0);
if (rt == NULL) {
struct flowi fl = { .oif = ipc.oif,
@@ -782,6 +784,7 @@ do_confirm:
err = 0;
goto out;
}
+EXPORT_SYMBOL(udp_sendmsg);
int udp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
@@ -871,6 +874,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return 0;
}
+EXPORT_SYMBOL(udp_ioctl);
/*
* This should be easy, if there is something there we
@@ -892,7 +896,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
* Check any passed addresses
*/
if (addr_len)
- *addr_len=sizeof(*sin);
+ *addr_len = sizeof(*sin);
if (flags & MSG_ERRQUEUE)
return ip_recv_error(sk, msg, len);
@@ -923,9 +927,11 @@ try_again:
if (skb_csum_unnecessary(skb))
err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
- msg->msg_iov, copied );
+ msg->msg_iov, copied);
else {
- err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
+ err = skb_copy_and_csum_datagram_iovec(skb,
+ sizeof(struct udphdr),
+ msg->msg_iov);
if (err == -EINVAL)
goto csum_copy_err;
@@ -941,8 +947,7 @@ try_again:
sock_recv_timestamp(msg, sk, skb);
/* Copy the address. */
- if (sin)
- {
+ if (sin) {
sin->sin_family = AF_INET;
sin->sin_port = udp_hdr(skb)->source;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
@@ -995,6 +1000,7 @@ int udp_disconnect(struct sock *sk, int flags)
sk_dst_reset(sk);
return 0;
}
+EXPORT_SYMBOL(udp_disconnect);
void udp_lib_unhash(struct sock *sk)
{
@@ -1044,7 +1050,7 @@ drop:
* Note that in the success and error cases, the skb is assumed to
* have either been requeued or freed.
*/
-int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct udp_sock *up = udp_sk(sk);
int rc;
@@ -1214,7 +1220,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
if (uh->check == 0) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else if (skb->ip_summed == CHECKSUM_COMPLETE) {
- if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+ if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
proto, skb->csum))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -1355,7 +1361,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
int err = 0;
int is_udplite = IS_UDPLITE(sk);
- if (optlen<sizeof(int))
+ if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
@@ -1426,6 +1432,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
return err;
}
+EXPORT_SYMBOL(udp_lib_setsockopt);
int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
@@ -1453,7 +1460,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
struct udp_sock *up = udp_sk(sk);
int val, len;
- if (get_user(len,optlen))
+ if (get_user(len, optlen))
return -EFAULT;
len = min_t(unsigned int, len, sizeof(int));
@@ -1486,10 +1493,11 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
if (put_user(len, optlen))
return -EFAULT;
- if (copy_to_user(optval, &val,len))
+ if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
+EXPORT_SYMBOL(udp_lib_getsockopt);
int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
@@ -1528,9 +1536,9 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
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)){
+ 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;
@@ -1552,6 +1560,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
return mask;
}
+EXPORT_SYMBOL(udp_poll);
struct proto udp_prot = {
.name = "UDP",
@@ -1582,6 +1591,7 @@ struct proto udp_prot = {
.compat_getsockopt = compat_udp_getsockopt,
#endif
};
+EXPORT_SYMBOL(udp_prot);
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
@@ -1703,11 +1713,13 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo)
rc = -ENOMEM;
return rc;
}
+EXPORT_SYMBOL(udp_proc_register);
void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo)
{
proc_net_remove(net, afinfo->name);
}
+EXPORT_SYMBOL(udp_proc_unregister);
/* ------------------------------------------------------------------------ */
static void udp4_format_sock(struct sock *sp, struct seq_file *f,
@@ -1741,7 +1753,7 @@ int udp4_seq_show(struct seq_file *seq, void *v)
int len;
udp4_format_sock(v, seq, state->bucket, &len);
- seq_printf(seq, "%*s\n", 127 - len ,"");
+ seq_printf(seq, "%*s\n", 127 - len, "");
}
return 0;
}
@@ -1816,16 +1828,64 @@ void __init udp_init(void)
sysctl_udp_wmem_min = SK_MEM_QUANTUM;
}
-EXPORT_SYMBOL(udp_disconnect);
-EXPORT_SYMBOL(udp_ioctl);
-EXPORT_SYMBOL(udp_prot);
-EXPORT_SYMBOL(udp_sendmsg);
-EXPORT_SYMBOL(udp_lib_getsockopt);
-EXPORT_SYMBOL(udp_lib_setsockopt);
-EXPORT_SYMBOL(udp_poll);
-EXPORT_SYMBOL(udp_lib_get_port);
+int udp4_ufo_send_check(struct sk_buff *skb)
+{
+ const struct iphdr *iph;
+ struct udphdr *uh;
+
+ if (!pskb_may_pull(skb, sizeof(*uh)))
+ return -EINVAL;
+
+ iph = ip_hdr(skb);
+ uh = udp_hdr(skb);
+
+ uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+ IPPROTO_UDP, 0);
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ return 0;
+}
+
+struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ unsigned int mss;
+ int offset;
+ __wsum csum;
+
+ mss = skb_shinfo(skb)->gso_size;
+ if (unlikely(skb->len <= mss))
+ goto out;
+
+ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
+ /* Packet is from an untrusted source, reset gso_segs. */
+ int type = skb_shinfo(skb)->gso_type;
+
+ if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+ !(type & (SKB_GSO_UDP))))
+ goto out;
+
+ skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
+
+ segs = NULL;
+ goto out;
+ }
+
+ /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+ * do checksum of UDP packets sent as multiple IP fragments.
+ */
+ offset = skb->csum_start - skb_headroom(skb);
+ csum = skb_checksum(skb, offset, skb->len - offset, 0);
+ offset += skb->csum_offset;
+ *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Fragment the skb. IP headers of the fragments are updated in
+ * inet_gso_segment()
+ */
+ segs = skb_segment(skb, features);
+out:
+ return segs;
+}
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(udp_proc_register);
-EXPORT_SYMBOL(udp_proc_unregister);
-#endif
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 0071ee6f441f..1ba44742ebbf 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -264,6 +264,20 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
.fill_dst = xfrm4_fill_dst,
};
+static struct ctl_table xfrm4_policy_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "xfrm4_gc_thresh",
+ .data = &xfrm4_dst_ops.gc_thresh,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ { }
+};
+
+static struct ctl_table_header *sysctl_hdr;
+
static void __init xfrm4_policy_init(void)
{
xfrm_policy_register_afinfo(&xfrm4_policy_afinfo);
@@ -271,12 +285,27 @@ static void __init xfrm4_policy_init(void)
static void __exit xfrm4_policy_fini(void)
{
+ if (sysctl_hdr)
+ unregister_net_sysctl_table(sysctl_hdr);
xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo);
}
-void __init xfrm4_init(void)
+void __init xfrm4_init(int rt_max_size)
{
xfrm4_state_init();
xfrm4_policy_init();
+ /*
+ * Select a default value for the gc_thresh based on the main route
+ * table hash size. It seems to me the worst case scenario is when
+ * we have ipsec operating in transport mode, in which we create a
+ * dst_entry per socket. The xfrm gc algorithm starts trying to remove
+ * entries at gc_thresh, and prevents new allocations as 2*gc_thresh
+ * so lets set an initial xfrm gc_thresh value at the rt_max_size/2.
+ * That will let us store an ipsec connection per route table entry,
+ * and start cleaning when were 1/2 full
+ */
+ xfrm4_dst_ops.gc_thresh = rt_max_size/2;
+ sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path,
+ xfrm4_policy_table);
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index caa0278d30a9..bf85d5f97032 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -772,6 +772,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
struct sk_buff *segs = ERR_PTR(-EINVAL);
struct ipv6hdr *ipv6h;
struct inet6_protocol *ops;
+ int proto;
+ struct frag_hdr *fptr;
+ unsigned int unfrag_ip6hlen;
+ u8 *prevhdr;
+ int offset = 0;
if (!(features & NETIF_F_V6_CSUM))
features &= ~NETIF_F_SG;
@@ -791,10 +796,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
__skb_pull(skb, sizeof(*ipv6h));
segs = ERR_PTR(-EPROTONOSUPPORT);
+ proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
rcu_read_lock();
- ops = rcu_dereference(inet6_protos[
- ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
-
+ ops = rcu_dereference(inet6_protos[proto]);
if (likely(ops && ops->gso_segment)) {
skb_reset_transport_header(skb);
segs = ops->gso_segment(skb, features);
@@ -808,6 +812,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
ipv6h = ipv6_hdr(skb);
ipv6h->payload_len = htons(skb->len - skb->mac_len -
sizeof(*ipv6h));
+ if (proto == IPPROTO_UDP) {
+ unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ fptr = (struct frag_hdr *)(skb_network_header(skb) +
+ unfrag_ip6hlen);
+ fptr->frag_off = htons(offset);
+ if (skb->next != NULL)
+ fptr->frag_off |= htons(IP6_MF);
+ offset += (ntohs(ipv6h->payload_len) -
+ sizeof(struct frag_hdr));
+ }
}
out:
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 52ee1dced2ff..0e93ca56eb69 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -164,12 +164,6 @@ static __inline__ void rt6_release(struct rt6_info *rt)
dst_free(&rt->u.dst);
}
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-#define FIB_TABLE_HASHSZ 256
-#else
-#define FIB_TABLE_HASHSZ 1
-#endif
-
static void fib6_link_table(struct net *net, struct fib6_table *tb)
{
unsigned int h;
@@ -180,7 +174,7 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb)
*/
rwlock_init(&tb->tb6_lock);
- h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
+ h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1);
/*
* No protection necessary, this is the only list mutatation
@@ -231,7 +225,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
if (id == 0)
id = RT6_TABLE_MAIN;
- h = id & (FIB_TABLE_HASHSZ - 1);
+ h = id & (FIB6_TABLE_HASHSZ - 1);
rcu_read_lock();
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
@@ -382,7 +376,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
arg.net = net;
w->args = &arg;
- for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
+ for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry(tb, node, head, tb6_hlist) {
@@ -1368,7 +1362,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
unsigned int h;
rcu_read_lock();
- for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+ for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
write_lock_bh(&table->tb6_lock);
@@ -1483,7 +1477,7 @@ static int fib6_net_init(struct net *net)
if (!net->ipv6.rt6_stats)
goto out_timer;
- net->ipv6.fib_table_hash = kcalloc(FIB_TABLE_HASHSZ,
+ net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ,
sizeof(*net->ipv6.fib_table_hash),
GFP_KERNEL);
if (!net->ipv6.fib_table_hash)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6d6a4277c677..2d9cbaa67edb 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -63,7 +63,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (skb->pkt_type == PACKET_OTHERHOST) {
kfree_skb(skb);
- return 0;
+ return NET_RX_DROP;
}
rcu_read_lock();
@@ -133,7 +133,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (ipv6_parse_hopopts(skb) < 0) {
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
rcu_read_unlock();
- return 0;
+ return NET_RX_DROP;
}
}
@@ -149,7 +149,7 @@ err:
drop:
rcu_read_unlock();
kfree_skb(skb);
- return 0;
+ return NET_RX_DROP;
}
/*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 87f8419a68fd..93beee944657 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -57,18 +57,6 @@
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
-static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
-{
- static u32 ipv6_fragmentation_id = 1;
- static DEFINE_SPINLOCK(ip6_id_lock);
-
- spin_lock_bh(&ip6_id_lock);
- fhdr->identification = htonl(ipv6_fragmentation_id);
- if (++ipv6_fragmentation_id == 0)
- ipv6_fragmentation_id = 1;
- spin_unlock_bh(&ip6_id_lock);
-}
-
int __ip6_local_out(struct sk_buff *skb)
{
int len;
@@ -706,7 +694,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
skb_reset_network_header(skb);
memcpy(skb_network_header(skb), tmp_hdr, hlen);
- ipv6_select_ident(skb, fh);
+ ipv6_select_ident(fh);
fh->nexthdr = nexthdr;
fh->reserved = 0;
fh->frag_off = htons(IP6_MF);
@@ -844,7 +832,7 @@ slow_path:
fh->nexthdr = nexthdr;
fh->reserved = 0;
if (!frag_id) {
- ipv6_select_ident(skb, fh);
+ ipv6_select_ident(fh);
frag_id = fh->identification;
} else
fh->identification = frag_id;
@@ -1087,11 +1075,13 @@ static inline int ip6_ufo_append_data(struct sock *sk,
if (!err) {
struct frag_hdr fhdr;
- /* specify the length of each IP datagram fragment*/
- skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
- sizeof(struct frag_hdr);
+ /* Specify the length of each IPv6 datagram fragment.
+ * It has to be a multiple of 8.
+ */
+ skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
+ sizeof(struct frag_hdr)) & ~7;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
- ipv6_select_ident(skb, &fhdr);
+ ipv6_select_ident(&fhdr);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 51f410e7775a..a1d6045c4694 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1063,14 +1063,14 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_err;
t->recursion--;
- return 0;
+ return NETDEV_TX_OK;
tx_err:
stats->tx_errors++;
stats->tx_dropped++;
kfree_skb(skb);
t->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
static void ip6_tnl_set_cap(struct ip6_tnl *t)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index c769f155c698..07ded5075b33 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -427,7 +427,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
MRT6MSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static const struct net_device_ops reg_vif_netdev_ops = {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 4b264ed40a8c..71c3dacec1ed 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2107,7 +2107,6 @@ static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
for (j=0; j<i; j++)
(void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
- struct inet6_dev *idev = pmc->idev;
struct ip6_sf_list *psf;
/* filter mode change */
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 98b7327d0949..d335a306a4db 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -753,7 +753,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_dropped++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
@@ -794,7 +794,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
IPTUNNEL_XMIT();
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
@@ -802,7 +802,7 @@ tx_error:
stats->tx_errors++;
dev_kfree_skb(skb);
tunnel->recursion--;
- return 0;
+ return NETDEV_TX_OK;
}
static void ipip6_tunnel_bind_dev(struct net_device *dev)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 8c2513982b61..6b6ae913b5d4 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -74,12 +74,13 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
return child;
}
-static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
+ ipv6_cookie_scratch);
static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
__be16 sport, __be16 dport, u32 count, int c)
{
- __u32 *tmp = __get_cpu_var(cookie_scratch);
+ __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch);
/*
* we have 320 bits of information to hash, copy in the remaining
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 33b59bd92c4d..d79fa6724451 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -638,6 +638,47 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
}
}
+/**
+ * udp6_hwcsum_outgoing - handle outgoing HW checksumming
+ * @sk: socket we are sending on
+ * @skb: sk_buff containing the filled-in UDP header
+ * (checksum field must be zeroed out)
+ */
+static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr, int len)
+{
+ unsigned int offset;
+ struct udphdr *uh = udp_hdr(skb);
+ __wsum csum = 0;
+
+ if (skb_queue_len(&sk->sk_write_queue) == 1) {
+ /* Only one fragment on the socket. */
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0);
+ } else {
+ /*
+ * HW-checksum won't work as there are two or more
+ * fragments on the socket so that all csums of sk_buffs
+ * should be together
+ */
+ offset = skb_transport_offset(skb);
+ skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ skb_queue_walk(&sk->sk_write_queue, skb) {
+ csum = csum_add(csum, skb->csum);
+ }
+
+ uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
+ csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ }
+}
+
/*
* Sending
*/
@@ -668,7 +709,11 @@ static int udp_v6_push_pending_frames(struct sock *sk)
if (is_udplite)
csum = udplite_csum_outgoing(sk, skb);
- else
+ else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
+ udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst,
+ up->len);
+ goto send;
+ } else
csum = udp_csum_outgoing(sk, skb);
/* add protocol-dependent pseudo-header */
@@ -677,6 +722,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
+send:
err = ip6_push_pending_frames(sk);
out:
up->len = 0;
@@ -1032,9 +1078,102 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
}
#endif
+static int udp6_ufo_send_check(struct sk_buff *skb)
+{
+ struct ipv6hdr *ipv6h;
+ struct udphdr *uh;
+
+ if (!pskb_may_pull(skb, sizeof(*uh)))
+ return -EINVAL;
+
+ ipv6h = ipv6_hdr(skb);
+ uh = udp_hdr(skb);
+
+ uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+ IPPROTO_UDP, 0);
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ return 0;
+}
+
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ unsigned int mss;
+ unsigned int unfrag_ip6hlen, unfrag_len;
+ struct frag_hdr *fptr;
+ u8 *mac_start, *prevhdr;
+ u8 nexthdr;
+ u8 frag_hdr_sz = sizeof(struct frag_hdr);
+ int offset;
+ __wsum csum;
+
+ mss = skb_shinfo(skb)->gso_size;
+ if (unlikely(skb->len <= mss))
+ goto out;
+
+ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
+ /* Packet is from an untrusted source, reset gso_segs. */
+ int type = skb_shinfo(skb)->gso_type;
+
+ if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+ !(type & (SKB_GSO_UDP))))
+ goto out;
+
+ skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
+
+ segs = NULL;
+ goto out;
+ }
+
+ /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+ * do checksum of UDP packets sent as multiple IP fragments.
+ */
+ offset = skb->csum_start - skb_headroom(skb);
+ csum = skb_checksum(skb, offset, skb->len- offset, 0);
+ offset += skb->csum_offset;
+ *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Check if there is enough headroom to insert fragment header. */
+ if ((skb_headroom(skb) < frag_hdr_sz) &&
+ pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
+ goto out;
+
+ /* Find the unfragmentable header and shift it left by frag_hdr_sz
+ * bytes to insert fragment header.
+ */
+ unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ nexthdr = *prevhdr;
+ *prevhdr = NEXTHDR_FRAGMENT;
+ unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
+ unfrag_ip6hlen;
+ mac_start = skb_mac_header(skb);
+ memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
+
+ skb->mac_header -= frag_hdr_sz;
+ skb->network_header -= frag_hdr_sz;
+
+ fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
+ fptr->nexthdr = nexthdr;
+ fptr->reserved = 0;
+ ipv6_select_ident(fptr);
+
+ /* Fragment the skb. ipv6 header and the remaining fields of the
+ * fragment header are updated in ipv6_gso_segment()
+ */
+ segs = skb_segment(skb, features);
+
+out:
+ return segs;
+}
+
static struct inet6_protocol udpv6_protocol = {
.handler = udpv6_rcv,
.err_handler = udpv6_err,
+ .gso_send_check = udp6_ufo_send_check,
+ .gso_segment = udp6_ufo_fragment,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 3a3c677bc0f2..611cffcf554f 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -306,9 +306,24 @@ static void xfrm6_policy_fini(void)
xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
}
+static struct ctl_table xfrm6_policy_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "xfrm6_gc_thresh",
+ .data = &xfrm6_dst_ops.gc_thresh,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ { }
+};
+
+static struct ctl_table_header *sysctl_hdr;
+
int __init xfrm6_init(void)
{
int ret;
+ unsigned int gc_thresh;
ret = xfrm6_policy_init();
if (ret)
@@ -317,6 +332,22 @@ int __init xfrm6_init(void)
ret = xfrm6_state_init();
if (ret)
goto out_policy;
+ /*
+ * We need a good default value for the xfrm6 gc threshold.
+ * In ipv4 we set it to the route hash table size * 8, which
+ * is half the size of the maximaum route cache for ipv4. It
+ * would be good to do the same thing for v6, except the table is
+ * constructed differently here. Here each table for a net namespace
+ * can have FIB_TABLE_HASHSZ entries, so lets go with the same
+ * computation that we used for ipv4 here. Also, lets keep the initial
+ * gc_thresh to a minimum of 1024, since, the ipv6 route cache defaults
+ * to that as a minimum as well
+ */
+ gc_thresh = FIB6_TABLE_HASHSZ * 8;
+ xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh;
+
+ sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path,
+ xfrm6_policy_table);
out:
return ret;
out_policy:
@@ -326,6 +357,8 @@ out_policy:
void xfrm6_fini(void)
{
+ if (sysctl_hdr)
+ unregister_net_sysctl_table(sysctl_hdr);
//xfrm6_input_fini();
xfrm6_policy_fini();
xfrm6_state_fini();
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 724bcf951b80..64230cffcfee 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -177,7 +177,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
/* Did the realloc succeed? */
if (new_skb == NULL)
- return 0;
+ return NETDEV_TX_OK;
/* Use the new skb instead */
skb = new_skb;
@@ -209,7 +209,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
self->stats.tx_bytes += skb->len;
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c
index 8dd7ed7e7c1f..476b307bd801 100644
--- a/net/irda/irnetlink.c
+++ b/net/irda/irnetlink.c
@@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
genlmsg_end(msg, hdr);
- return genlmsg_unicast(msg, info->snd_pid);
+ return genlmsg_reply(msg, info);
err_out:
nlmsg_free(msg);
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index ecf4eb2717cb..9cb79f95bf63 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1453,6 +1453,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
}
/* Dup */
memcpy(new, orig, sizeof(struct tsap_cb));
+ spin_lock_init(&new->lock);
/* We don't need the old instance any more */
spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index 2ba1bc4f3c3a..bda96d18fd98 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -407,7 +407,7 @@ int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
return lapb->callbacks.data_indication(lapb->dev, skb);
kfree_skb(skb);
- return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
+ return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */
}
int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index ba2643a43c73..7dd77b6d4c9a 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -6,7 +6,6 @@ config MAC80211
select CRYPTO_ARC4
select CRYPTO_AES
select CRC32
- select WIRELESS_EXT
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
@@ -14,22 +13,6 @@ config MAC80211
comment "CFG80211 needs to be enabled for MAC80211"
depends on CFG80211=n
-config MAC80211_DEFAULT_PS
- bool "enable powersave by default"
- depends on MAC80211
- default y
- help
- This option enables powersave mode by default.
-
- If this causes your applications to misbehave you should fix your
- applications instead -- they need to register their network
- latency requirement, see Documentation/power/pm_qos_interface.txt.
-
-config MAC80211_DEFAULT_PS_VALUE
- int
- default 1 if MAC80211_DEFAULT_PS
- default 0
-
menu "Rate control algorithm selection"
depends on MAC80211 != n
@@ -83,6 +66,7 @@ endmenu
config MAC80211_MESH
bool "Enable mac80211 mesh networking (pre-802.11s) support"
depends on MAC80211 && EXPERIMENTAL
+ depends on BROKEN
---help---
This options enables support of Draft 802.11s mesh networking.
The implementation is based on Draft 1.08 of the Mesh Networking
@@ -221,3 +205,15 @@ config MAC80211_DEBUG_COUNTERS
and show them in debugfs.
If unsure, say N.
+
+config MAC80211_DRIVER_API_TRACER
+ bool "Driver API tracer"
+ depends on MAC80211_DEBUG_MENU
+ depends on EVENT_TRACING
+ help
+ Say Y here to make mac80211 register with the ftrace
+ framework for the driver API -- you can see which
+ driver methods it is calling then by looking at the
+ trace.
+
+ If unsure, say N.
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 0e3ab88bb706..9f3cf7129324 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o
# mac80211 objects
mac80211-y := \
main.o \
- wext.o \
sta_info.o \
wep.o \
wpa.o \
@@ -41,6 +40,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
mac80211-$(CONFIG_PM) += pm.o
+mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
+CFLAGS_driver-trace.o := -I$(src)
+
# objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 9e5762ad307d..1958c7c42cd9 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- /* mark queue as pending, it is stopped already */
- __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
- &local->queue_stop_reasons[queue]);
/* copy over remaining packets */
skb_queue_splice_tail_init(
&sta->ampdu_mlme.tid_tx[tid]->pending,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3f47276caeb8..4bbf5007799b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -57,36 +57,21 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
return 0;
}
-static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
+static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev)
{
- struct net_device *dev;
- struct ieee80211_sub_if_data *sdata;
-
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- ieee80211_if_remove(sdata);
+ ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev));
return 0;
}
-static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int ieee80211_change_iface(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *dev;
struct ieee80211_sub_if_data *sdata;
int ret;
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
-
if (!nl80211_type_check(type))
return -EINVAL;
@@ -1177,123 +1162,29 @@ static int ieee80211_scan(struct wiphy *wiphy,
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_auth_request *req)
{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- switch (req->auth_type) {
- case NL80211_AUTHTYPE_OPEN_SYSTEM:
- sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN;
- break;
- case NL80211_AUTHTYPE_SHARED_KEY:
- sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY;
- break;
- case NL80211_AUTHTYPE_FT:
- sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT;
- break;
- case NL80211_AUTHTYPE_NETWORK_EAP:
- sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
- sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
-
- /* TODO: req->chan */
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
-
- if (req->ssid) {
- sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
- memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
- sdata->u.mgd.ssid_len = req->ssid_len;
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
- }
-
- kfree(sdata->u.mgd.sme_auth_ie);
- sdata->u.mgd.sme_auth_ie = NULL;
- sdata->u.mgd.sme_auth_ie_len = 0;
- if (req->ie) {
- sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
- if (sdata->u.mgd.sme_auth_ie == NULL)
- return -ENOMEM;
- memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
- sdata->u.mgd.sme_auth_ie_len = req->ie_len;
- }
-
- sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
- sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
- ieee80211_sta_req_auth(sdata);
- return 0;
+ return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
}
static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_request *req)
{
- struct ieee80211_sub_if_data *sdata;
- int ret;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 ||
- !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
- return -ENOLINK; /* not authenticated */
-
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
- sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
-
- /* TODO: req->chan */
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
-
- if (req->ssid) {
- sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
- memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
- sdata->u.mgd.ssid_len = req->ssid_len;
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
- } else
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-
- ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
- if (ret && ret != -EALREADY)
- return ret;
-
- if (req->use_mfp) {
- sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
- sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
- } else {
- sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
- sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
- }
-
- if (req->control_port)
- sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
- else
- sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-
- sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
- sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
- ieee80211_sta_req_auth(sdata);
- return 0;
+ return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}
static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_deauth_request *req)
+ struct cfg80211_deauth_request *req,
+ void *cookie)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- /* TODO: req->ie, req->peer_addr */
- return ieee80211_sta_deauthenticate(sdata, req->reason_code);
+ return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
+ req, cookie);
}
static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_disassoc_request *req)
+ struct cfg80211_disassoc_request *req,
+ void *cookie)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- /* TODO: req->ie, req->peer_addr */
- return ieee80211_sta_disassociate(sdata, req->reason_code);
+ return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
+ req, cookie);
}
static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
@@ -1374,6 +1265,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
return 0;
}
+static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
+ u8 *addr)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN);
+
+ return 0;
+}
+
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -1381,6 +1282,85 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy)
drv_rfkill_poll(local);
}
+#ifdef CONFIG_NL80211_TESTMODE
+static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (!local->ops->testmode_cmd)
+ return -EOPNOTSUPP;
+
+ return local->ops->testmode_cmd(&local->hw, data, len);
+}
+#endif
+
+static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+ return -EOPNOTSUPP;
+
+ if (enabled == sdata->u.mgd.powersave &&
+ timeout == conf->dynamic_ps_timeout)
+ return 0;
+
+ sdata->u.mgd.powersave = enabled;
+ conf->dynamic_ps_timeout = timeout;
+
+ if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+
+ ieee80211_recalc_ps(local, -1);
+
+ return 0;
+}
+
+static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *addr,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int i, err = -EINVAL;
+ u32 target_rate;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+ * target_rate = X, rate->fixed = 1 means only rate X
+ * target_rate = X, rate->fixed = 0 means all rates <= X */
+ sdata->max_ratectrl_rateidx = -1;
+ sdata->force_unicast_rateidx = -1;
+
+ if (mask->fixed)
+ target_rate = mask->fixed / 100;
+ else if (mask->maxrate)
+ target_rate = mask->maxrate / 100;
+ else
+ return 0;
+
+ for (i=0; i< sband->n_bitrates; i++) {
+ struct ieee80211_rate *brate = &sband->bitrates[i];
+ int this_rate = brate->bitrate;
+
+ if (target_rate == this_rate) {
+ sdata->max_ratectrl_rateidx = i;
+ if (mask->fixed)
+ sdata->force_unicast_rateidx = i;
+ err = 0;
+ break;
+ }
+ }
+
+ return err;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1422,5 +1402,9 @@ struct cfg80211_ops mac80211_config_ops = {
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
+ .set_wds_peer = ieee80211_set_wds_peer,
.rfkill_poll = ieee80211_rfkill_poll,
+ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+ .set_power_mgmt = ieee80211_set_power_mgmt,
+ .set_bitrate_mask = ieee80211_set_bitrate_mask,
};
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 6c439cd5ccea..96991b68f048 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
for (q = 0; q < local->hw.queues; q++)
res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
local->queue_stop_reasons[q],
- __netif_subqueue_stopped(local->mdev, q));
+ skb_queue_len(&local->pending[q]));
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index e3420329f4e6..e9ec6cae2d39 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -95,33 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
/* STA attributes */
-IEEE80211_IF_FILE(state, u.mgd.state, DEC);
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
-IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
-IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
-IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX);
IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
-IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
-IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
-IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
-IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX);
-IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
-IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC);
-
-static ssize_t ieee80211_if_fmt_flags(
- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
- return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
- sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
- sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
- sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
- sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
- sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
- sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
- sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
-}
-__IEEE80211_IF_FILE(flags);
/* AP attributes */
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -184,20 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(force_unicast_rateidx, sta);
DEBUGFS_ADD(max_ratectrl_rateidx, sta);
- DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
- DEBUGFS_ADD(prev_bssid, sta);
- DEBUGFS_ADD(ssid_len, sta);
DEBUGFS_ADD(aid, sta);
- DEBUGFS_ADD(ap_capab, sta);
DEBUGFS_ADD(capab, sta);
- DEBUGFS_ADD(extra_ie_len, sta);
- DEBUGFS_ADD(auth_tries, sta);
- DEBUGFS_ADD(assoc_tries, sta);
- DEBUGFS_ADD(auth_algs, sta);
- DEBUGFS_ADD(auth_alg, sta);
- DEBUGFS_ADD(auth_transaction, sta);
- DEBUGFS_ADD(flags, sta);
}
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -317,20 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_DEL(force_unicast_rateidx, sta);
DEBUGFS_DEL(max_ratectrl_rateidx, sta);
- DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
- DEBUGFS_DEL(prev_bssid, sta);
- DEBUGFS_DEL(ssid_len, sta);
DEBUGFS_DEL(aid, sta);
- DEBUGFS_DEL(ap_capab, sta);
DEBUGFS_DEL(capab, sta);
- DEBUGFS_DEL(extra_ie_len, sta);
- DEBUGFS_DEL(auth_tries, sta);
- DEBUGFS_DEL(assoc_tries, sta);
- DEBUGFS_DEL(auth_algs, sta);
- DEBUGFS_DEL(auth_alg, sta);
- DEBUGFS_DEL(auth_transaction, sta);
- DEBUGFS_DEL(flags, sta);
}
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 90230c718b5b..33a2e892115b 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -120,45 +120,38 @@ STA_OPS(last_seq_ctrl);
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- char buf[768], *p = buf;
+ char buf[30 + STA_TID_NUM * 70], *p = buf;
int i;
struct sta_info *sta = file->private_data;
- p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
- p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
- "TIDs info is: \n TID :",
- (sta->ampdu_mlme.dialog_token_allocator + 1));
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
-
- p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :");
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
- sta->ampdu_mlme.tid_state_rx[i]);
-
- p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
- sta->ampdu_mlme.tid_state_rx[i] ?
- sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
-
- p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :");
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
- sta->ampdu_mlme.tid_state_tx[i]);
-
- p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
- sta->ampdu_mlme.tid_state_tx[i] ?
- sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
-
- p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
- for (i = 0; i < STA_TID_NUM; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
- sta->ampdu_mlme.tid_state_tx[i] ?
- sta->ampdu_mlme.tid_tx[i]->ssn : 0);
- p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+ spin_lock_bh(&sta->lock);
+ p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n",
+ sta->ampdu_mlme.dialog_token_allocator + 1);
+ for (i = 0; i < STA_TID_NUM; i++) {
+ p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i);
+ p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x",
+ sta->ampdu_mlme.tid_state_rx[i]);
+ p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+ sta->ampdu_mlme.tid_state_rx[i] ?
+ sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
+ p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+ sta->ampdu_mlme.tid_state_rx[i] ?
+ sta->ampdu_mlme.tid_rx[i]->ssn : 0);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x",
+ sta->ampdu_mlme.tid_state_tx[i]);
+ p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+ sta->ampdu_mlme.tid_state_tx[i] ?
+ sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
+ p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+ sta->ampdu_mlme.tid_state_tx[i] ?
+ sta->ampdu_mlme.tid_tx[i]->ssn : 0);
+ p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d",
+ sta->ampdu_mlme.tid_state_tx[i] ?
+ skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+ }
+ spin_unlock_bh(&sta->lock);
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
}
@@ -203,6 +196,22 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(inactive_ms);
DEBUGFS_ADD(last_seq_ctrl);
DEBUGFS_ADD(agg_status);
+ DEBUGFS_ADD(dev);
+ DEBUGFS_ADD(rx_packets);
+ DEBUGFS_ADD(tx_packets);
+ DEBUGFS_ADD(rx_bytes);
+ DEBUGFS_ADD(tx_bytes);
+ DEBUGFS_ADD(rx_duplicates);
+ DEBUGFS_ADD(rx_fragments);
+ DEBUGFS_ADD(rx_dropped);
+ DEBUGFS_ADD(tx_fragments);
+ DEBUGFS_ADD(tx_filtered);
+ DEBUGFS_ADD(tx_retry_failed);
+ DEBUGFS_ADD(tx_retry_count);
+ DEBUGFS_ADD(last_signal);
+ DEBUGFS_ADD(last_qual);
+ DEBUGFS_ADD(last_noise);
+ DEBUGFS_ADD(wep_weak_iv_count);
}
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
@@ -212,6 +221,23 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
DEBUGFS_DEL(inactive_ms);
DEBUGFS_DEL(last_seq_ctrl);
DEBUGFS_DEL(agg_status);
+ DEBUGFS_DEL(aid);
+ DEBUGFS_DEL(dev);
+ DEBUGFS_DEL(rx_packets);
+ DEBUGFS_DEL(tx_packets);
+ DEBUGFS_DEL(rx_bytes);
+ DEBUGFS_DEL(tx_bytes);
+ DEBUGFS_DEL(rx_duplicates);
+ DEBUGFS_DEL(rx_fragments);
+ DEBUGFS_DEL(rx_dropped);
+ DEBUGFS_DEL(tx_fragments);
+ DEBUGFS_DEL(tx_filtered);
+ DEBUGFS_DEL(tx_retry_failed);
+ DEBUGFS_DEL(tx_retry_count);
+ DEBUGFS_DEL(last_signal);
+ DEBUGFS_DEL(last_qual);
+ DEBUGFS_DEL(last_noise);
+ DEBUGFS_DEL(wep_weak_iv_count);
debugfs_remove(sta->debugfs.dir);
sta->debugfs.dir = NULL;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b13446afd48f..4100c361a99d 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -3,6 +3,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
+#include "driver-trace.h"
static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
{
@@ -11,29 +12,37 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
static inline int drv_start(struct ieee80211_local *local)
{
- return local->ops->start(&local->hw);
+ int ret = local->ops->start(&local->hw);
+ trace_drv_start(local, ret);
+ return ret;
}
static inline void drv_stop(struct ieee80211_local *local)
{
local->ops->stop(&local->hw);
+ trace_drv_stop(local);
}
static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
{
- return local->ops->add_interface(&local->hw, conf);
+ int ret = local->ops->add_interface(&local->hw, conf);
+ trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
+ return ret;
}
static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_if_init_conf *conf)
{
local->ops->remove_interface(&local->hw, conf);
+ trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
}
static inline int drv_config(struct ieee80211_local *local, u32 changed)
{
- return local->ops->config(&local->hw, changed);
+ int ret = local->ops->config(&local->hw, changed);
+ trace_drv_config(local, changed, ret);
+ return ret;
}
static inline void drv_bss_info_changed(struct ieee80211_local *local,
@@ -43,6 +52,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
{
if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, vif, info, changed);
+ trace_drv_bss_info_changed(local, vif, info, changed);
}
static inline void drv_configure_filter(struct ieee80211_local *local,
@@ -53,14 +63,18 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
{
local->ops->configure_filter(&local->hw, changed_flags, total_flags,
mc_count, mc_list);
+ trace_drv_configure_filter(local, changed_flags, total_flags,
+ mc_count);
}
static inline int drv_set_tim(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool set)
{
+ int ret = 0;
if (local->ops->set_tim)
- return local->ops->set_tim(&local->hw, sta, set);
- return 0;
+ ret = local->ops->set_tim(&local->hw, sta, set);
+ trace_drv_set_tim(local, sta, set, ret);
+ return ret;
}
static inline int drv_set_key(struct ieee80211_local *local,
@@ -68,7 +82,9 @@ static inline int drv_set_key(struct ieee80211_local *local,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- return local->ops->set_key(&local->hw, cmd, vif, sta, key);
+ int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
+ trace_drv_set_key(local, cmd, vif, sta, key, ret);
+ return ret;
}
static inline void drv_update_tkip_key(struct ieee80211_local *local,
@@ -79,32 +95,41 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, conf, address,
iv32, phase1key);
+ trace_drv_update_tkip_key(local, conf, address, iv32);
}
static inline int drv_hw_scan(struct ieee80211_local *local,
struct cfg80211_scan_request *req)
{
- return local->ops->hw_scan(&local->hw, req);
+ int ret = local->ops->hw_scan(&local->hw, req);
+ trace_drv_hw_scan(local, req, ret);
+ return ret;
}
static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
if (local->ops->sw_scan_start)
local->ops->sw_scan_start(&local->hw);
+ trace_drv_sw_scan_start(local);
}
static inline void drv_sw_scan_complete(struct ieee80211_local *local)
{
if (local->ops->sw_scan_complete)
local->ops->sw_scan_complete(&local->hw);
+ trace_drv_sw_scan_complete(local);
}
static inline int drv_get_stats(struct ieee80211_local *local,
struct ieee80211_low_level_stats *stats)
{
- if (!local->ops->get_stats)
- return -EOPNOTSUPP;
- return local->ops->get_stats(&local->hw, stats);
+ int ret = -EOPNOTSUPP;
+
+ if (local->ops->get_stats)
+ ret = local->ops->get_stats(&local->hw, stats);
+ trace_drv_get_stats(local, stats, ret);
+
+ return ret;
}
static inline void drv_get_tkip_seq(struct ieee80211_local *local,
@@ -112,14 +137,17 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local,
{
if (local->ops->get_tkip_seq)
local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
+ trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
}
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
u32 value)
{
+ int ret = 0;
if (local->ops->set_rts_threshold)
- return local->ops->set_rts_threshold(&local->hw, value);
- return 0;
+ ret = local->ops->set_rts_threshold(&local->hw, value);
+ trace_drv_set_rts_threshold(local, value, ret);
+ return ret;
}
static inline void drv_sta_notify(struct ieee80211_local *local,
@@ -129,46 +157,57 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
{
if (local->ops->sta_notify)
local->ops->sta_notify(&local->hw, vif, cmd, sta);
+ trace_drv_sta_notify(local, vif, cmd, sta);
}
static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
+ int ret = -EOPNOTSUPP;
if (local->ops->conf_tx)
- return local->ops->conf_tx(&local->hw, queue, params);
- return -EOPNOTSUPP;
+ ret = local->ops->conf_tx(&local->hw, queue, params);
+ trace_drv_conf_tx(local, queue, params, ret);
+ return ret;
}
static inline int drv_get_tx_stats(struct ieee80211_local *local,
struct ieee80211_tx_queue_stats *stats)
{
- return local->ops->get_tx_stats(&local->hw, stats);
+ int ret = local->ops->get_tx_stats(&local->hw, stats);
+ trace_drv_get_tx_stats(local, stats, ret);
+ return ret;
}
static inline u64 drv_get_tsf(struct ieee80211_local *local)
{
+ u64 ret = -1ULL;
if (local->ops->get_tsf)
- return local->ops->get_tsf(&local->hw);
- return -1ULL;
+ ret = local->ops->get_tsf(&local->hw);
+ trace_drv_get_tsf(local, ret);
+ return ret;
}
static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
{
if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, tsf);
+ trace_drv_set_tsf(local, tsf);
}
static inline void drv_reset_tsf(struct ieee80211_local *local)
{
if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw);
+ trace_drv_reset_tsf(local);
}
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
{
+ int ret = 1;
if (local->ops->tx_last_beacon)
- return local->ops->tx_last_beacon(&local->hw);
- return 1;
+ ret = local->ops->tx_last_beacon(&local->hw);
+ trace_drv_tx_last_beacon(local, ret);
+ return ret;
}
static inline int drv_ampdu_action(struct ieee80211_local *local,
@@ -176,10 +215,12 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
struct ieee80211_sta *sta, u16 tid,
u16 *ssn)
{
+ int ret = -EOPNOTSUPP;
if (local->ops->ampdu_action)
- return local->ops->ampdu_action(&local->hw, action,
- sta, tid, ssn);
- return -EOPNOTSUPP;
+ ret = local->ops->ampdu_action(&local->hw, action,
+ sta, tid, ssn);
+ trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
+ return ret;
}
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
new file mode 100644
index 000000000000..6da6f79932fc
--- /dev/null
+++ b/net/mac80211/driver-trace.c
@@ -0,0 +1,6 @@
+/* bug in tracepoint.h, it should include this */
+#include <linux/module.h>
+
+#include "driver-ops.h"
+#define CREATE_TRACE_POINTS
+#include "driver-trace.h"
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
new file mode 100644
index 000000000000..5a10da2d70fd
--- /dev/null
+++ b/net/mac80211/driver-trace.h
@@ -0,0 +1,648 @@
+#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __MAC80211_DRIVER_TRACE
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211
+
+#define MAXNAME 32
+#define LOCAL_ENTRY __array(char, wiphy_name, 32)
+#define LOCAL_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
+#define LOCAL_PR_FMT "%s"
+#define LOCAL_PR_ARG __entry->wiphy_name
+
+#define STA_ENTRY __array(char, sta_addr, ETH_ALEN)
+#define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
+#define STA_PR_FMT " sta:%pM"
+#define STA_PR_ARG __entry->sta_addr
+
+#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif)
+#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
+#define VIF_PR_FMT " vif:%p(%d)"
+#define VIF_PR_ARG __entry->vif, __entry->vif_type
+
+TRACE_EVENT(drv_start,
+ TP_PROTO(struct ieee80211_local *local, int ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_stop,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_add_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ const u8 *addr,
+ struct ieee80211_vif *vif,
+ int ret),
+
+ TP_ARGS(local, addr, vif, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, addr, 6)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->addr, addr, 6);
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_remove_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ const u8 *addr, struct ieee80211_vif *vif),
+
+ TP_ARGS(local, addr, vif),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, addr, 6)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->addr, addr, 6);
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+ )
+);
+
+TRACE_EVENT(drv_config,
+ TP_PROTO(struct ieee80211_local *local,
+ u32 changed,
+ int ret),
+
+ TP_ARGS(local, changed, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, changed)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->changed = changed;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ch:%#x ret:%d",
+ LOCAL_PR_ARG, __entry->changed, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_bss_info_changed,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed),
+
+ TP_ARGS(local, vif, info, changed),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(bool, assoc)
+ __field(u16, aid)
+ __field(bool, cts)
+ __field(bool, shortpre)
+ __field(bool, shortslot)
+ __field(u8, dtimper)
+ __field(u16, bcnint)
+ __field(u16, assoc_cap)
+ __field(u64, timestamp)
+ __field(u32, basic_rates)
+ __field(u32, changed)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->changed = changed;
+ __entry->aid = info->aid;
+ __entry->assoc = info->assoc;
+ __entry->shortpre = info->use_short_preamble;
+ __entry->cts = info->use_cts_prot;
+ __entry->shortslot = info->use_short_slot;
+ __entry->dtimper = info->dtim_period;
+ __entry->bcnint = info->beacon_int;
+ __entry->assoc_cap = info->assoc_capability;
+ __entry->timestamp = info->timestamp;
+ __entry->basic_rates = info->basic_rates;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " changed:%#x",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
+ )
+);
+
+TRACE_EVENT(drv_configure_filter,
+ TP_PROTO(struct ieee80211_local *local,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count),
+
+ TP_ARGS(local, changed_flags, total_flags, mc_count),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(unsigned int, changed)
+ __field(unsigned int, total)
+ __field(int, mc)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->changed = changed_flags;
+ __entry->total = *total_flags;
+ __entry->mc = mc_count;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " changed:%#x total:%#x mc:%d",
+ LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc
+ )
+);
+
+TRACE_EVENT(drv_set_tim,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta, bool set, int ret),
+
+ TP_ARGS(local, sta, set, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ __field(bool, set)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ __entry->set = set;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d",
+ LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_set_key,
+ TP_PROTO(struct ieee80211_local *local,
+ enum set_key_cmd cmd, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key, int ret),
+
+ TP_ARGS(local, cmd, vif, sta, key, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(enum ieee80211_key_alg, alg)
+ __field(u8, hw_key_idx)
+ __field(u8, flags)
+ __field(s8, keyidx)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->alg = key->alg;
+ __entry->flags = key->flags;
+ __entry->keyidx = key->keyidx;
+ __entry->hw_key_idx = key->hw_key_idx;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_update_tkip_key,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_key_conf *conf,
+ const u8 *address, u32 iv32),
+
+ TP_ARGS(local, conf, address, iv32),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __array(u8, addr, 6)
+ __field(u32, iv32)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ memcpy(__entry->addr, address, 6);
+ __entry->iv32 = iv32;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " addr:%pM iv32:%#x",
+ LOCAL_PR_ARG, __entry->addr, __entry->iv32
+ )
+);
+
+TRACE_EVENT(drv_hw_scan,
+ TP_PROTO(struct ieee80211_local *local,
+ struct cfg80211_scan_request *req, int ret),
+
+ TP_ARGS(local, req, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_sw_scan_start,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_sw_scan_complete,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_get_stats,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_low_level_stats *stats,
+ int ret),
+
+ TP_ARGS(local, stats, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ __field(unsigned int, ackfail)
+ __field(unsigned int, rtsfail)
+ __field(unsigned int, fcserr)
+ __field(unsigned int, rtssucc)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ __entry->ackfail = stats->dot11ACKFailureCount;
+ __entry->rtsfail = stats->dot11RTSFailureCount;
+ __entry->fcserr = stats->dot11FCSErrorCount;
+ __entry->rtssucc = stats->dot11RTSSuccessCount;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tkip_seq,
+ TP_PROTO(struct ieee80211_local *local,
+ u8 hw_key_idx, u32 *iv32, u16 *iv16),
+
+ TP_ARGS(local, hw_key_idx, iv32, iv16),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u8, hw_key_idx)
+ __field(u32, iv32)
+ __field(u16, iv16)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->hw_key_idx = hw_key_idx;
+ __entry->iv32 = *iv32;
+ __entry->iv16 = *iv16;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_set_rts_threshold,
+ TP_PROTO(struct ieee80211_local *local, u32 value, int ret),
+
+ TP_ARGS(local, value, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, value)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ __entry->value = value;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " value:%d ret:%d",
+ LOCAL_PR_ARG, __entry->value, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_sta_notify,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta),
+
+ TP_ARGS(local, vif, cmd, sta),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(u32, cmd)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " cmd:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
+ )
+);
+
+TRACE_EVENT(drv_conf_tx,
+ TP_PROTO(struct ieee80211_local *local, u16 queue,
+ const struct ieee80211_tx_queue_params *params,
+ int ret),
+
+ TP_ARGS(local, queue, params, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u16, queue)
+ __field(u16, txop)
+ __field(u16, cw_min)
+ __field(u16, cw_max)
+ __field(u8, aifs)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->queue = queue;
+ __entry->ret = ret;
+ __entry->txop = params->txop;
+ __entry->cw_max = params->cw_max;
+ __entry->cw_min = params->cw_min;
+ __entry->aifs = params->aifs;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " queue:%d ret:%d",
+ LOCAL_PR_ARG, __entry->queue, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tx_stats,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_tx_queue_stats *stats,
+ int ret),
+
+ TP_ARGS(local, stats, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_get_tsf,
+ TP_PROTO(struct ieee80211_local *local, u64 ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u64, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%llu",
+ LOCAL_PR_ARG, (unsigned long long)__entry->ret
+ )
+);
+
+TRACE_EVENT(drv_set_tsf,
+ TP_PROTO(struct ieee80211_local *local, u64 tsf),
+
+ TP_ARGS(local, tsf),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u64, tsf)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->tsf = tsf;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " tsf:%llu",
+ LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+ )
+);
+
+TRACE_EVENT(drv_reset_tsf,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_tx_last_beacon,
+ TP_PROTO(struct ieee80211_local *local, int ret),
+
+ TP_ARGS(local, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " ret:%d",
+ LOCAL_PR_ARG, __entry->ret
+ )
+);
+
+TRACE_EVENT(drv_ampdu_action,
+ TP_PROTO(struct ieee80211_local *local,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid,
+ u16 *ssn, int ret),
+
+ TP_ARGS(local, action, sta, tid, ssn, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ __field(u32, action)
+ __field(u16, tid)
+ __field(u16, ssn)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ __entry->ret = ret;
+ __entry->action = action;
+ __entry->tid = tid;
+ __entry->ssn = *ssn;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
+ LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+ )
+);
+#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE driver-trace
+#include <trace/define_trace.h>
diff --git a/net/mac80211/event.c b/net/mac80211/event.c
index f288d01a6344..01ae759518f6 100644
--- a/net/mac80211/event.c
+++ b/net/mac80211/event.c
@@ -7,8 +7,7 @@
*
* mac80211 - events
*/
-
-#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "ieee80211_i.h"
/*
@@ -17,26 +16,12 @@
* driver or is still in the frame), it should provide that information.
*/
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
- struct ieee80211_hdr *hdr, const u8 *tsc)
+ struct ieee80211_hdr *hdr, const u8 *tsc,
+ gfp_t gfp)
{
- union iwreq_data wrqu;
- char *buf = kmalloc(128, GFP_ATOMIC);
-
- if (buf) {
- /* TODO: needed parameters: count, key type, TSC */
- sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
- "keyid=%d %scast addr=%pM)",
- keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
- hdr->addr2);
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
- kfree(buf);
- }
-
cfg80211_michael_mic_failure(sdata->dev, hdr->addr2,
(hdr->addr1[0] & 0x01) ?
NL80211_KEYTYPE_GROUP :
NL80211_KEYTYPE_PAIRWISE,
- keyidx, tsc);
+ keyidx, tsc, gfp);
}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 0b30277eb366..6e3cca65c460 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
*/
if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
- sdata->u.ibss.bssid, 0);
+ sdata->u.ibss.bssid, NULL, 0, 0);
}
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key)
+ if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
else
sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
return;
capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key)
+ if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
-
if (ifibss->fixed_bssid)
bssid = ifibss->bssid;
if (ifibss->fixed_channel)
@@ -705,7 +704,7 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt;
u16 fc;
- rx_status = (struct ieee80211_rx_status *) skb->cb;
+ rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
@@ -743,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
if (!netif_running(sdata->dev))
return;
- if (local->sw_scanning || local->hw_scanning)
+ if (local->scanning)
return;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
@@ -836,8 +835,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
}
ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
@@ -852,7 +850,6 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_AUTH:
skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
@@ -874,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
} else
sdata->u.ibss.fixed_bssid = false;
+ sdata->u.ibss.privacy = params->privacy;
+
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
sdata->u.ibss.channel = params->channel;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 68eb5052179a..aec6853cb435 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -24,7 +24,6 @@
#include <linux/spinlock.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#include <net/iw_handler.h>
#include <net/mac80211.h>
#include "key.h"
#include "sta_info.h"
@@ -227,86 +226,79 @@ struct mesh_preq_queue {
u8 flags;
};
+enum ieee80211_mgd_state {
+ IEEE80211_MGD_STATE_IDLE,
+ IEEE80211_MGD_STATE_PROBE,
+ IEEE80211_MGD_STATE_AUTH,
+ IEEE80211_MGD_STATE_ASSOC,
+};
+
+struct ieee80211_mgd_work {
+ struct list_head list;
+ struct ieee80211_bss *bss;
+ int ie_len;
+ u8 prev_bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len;
+ unsigned long timeout;
+ enum ieee80211_mgd_state state;
+ u16 auth_alg, auth_transaction;
+
+ int tries;
+
+ u8 key[WLAN_KEY_LEN_WEP104];
+ u8 key_len, key_idx;
+
+ /* must be last */
+ u8 ie[0]; /* for auth or assoc frame, not probe */
+};
+
/* flags used in struct ieee80211_if_managed.flags */
-#define IEEE80211_STA_SSID_SET BIT(0)
-#define IEEE80211_STA_BSSID_SET BIT(1)
-#define IEEE80211_STA_PREV_BSSID_SET BIT(2)
-#define IEEE80211_STA_AUTHENTICATED BIT(3)
-#define IEEE80211_STA_ASSOCIATED BIT(4)
-#define IEEE80211_STA_PROBEREQ_POLL BIT(5)
-#define IEEE80211_STA_CREATE_IBSS BIT(6)
-#define IEEE80211_STA_CONTROL_PORT BIT(7)
-#define IEEE80211_STA_WMM_ENABLED BIT(8)
-/* hole at 9, please re-use */
-#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
-#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11)
-#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
-#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
-#define IEEE80211_STA_TKIP_WEP_USED BIT(14)
-#define IEEE80211_STA_CSA_RECEIVED BIT(15)
-#define IEEE80211_STA_MFP_ENABLED BIT(16)
-#define IEEE80211_STA_EXT_SME BIT(17)
-/* flags for MLME request */
-#define IEEE80211_STA_REQ_SCAN 0
-#define IEEE80211_STA_REQ_AUTH 1
-#define IEEE80211_STA_REQ_RUN 2
+enum ieee80211_sta_flags {
+ IEEE80211_STA_BEACON_POLL = BIT(0),
+ IEEE80211_STA_CONNECTION_POLL = BIT(1),
+ IEEE80211_STA_CONTROL_PORT = BIT(2),
+ IEEE80211_STA_WMM_ENABLED = BIT(3),
+ IEEE80211_STA_DISABLE_11N = BIT(4),
+ IEEE80211_STA_CSA_RECEIVED = BIT(5),
+ IEEE80211_STA_MFP_ENABLED = BIT(6),
+};
-/* bitfield of allowed auth algs */
-#define IEEE80211_AUTH_ALG_OPEN BIT(0)
-#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
-#define IEEE80211_AUTH_ALG_LEAP BIT(2)
-#define IEEE80211_AUTH_ALG_FT BIT(3)
+/* flags for MLME request */
+enum ieee80211_sta_request {
+ IEEE80211_STA_REQ_SCAN,
+};
struct ieee80211_if_managed {
struct timer_list timer;
+ struct timer_list conn_mon_timer;
+ struct timer_list bcn_mon_timer;
struct timer_list chswitch_timer;
struct work_struct work;
+ struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_loss_work;
- u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
+ unsigned long probe_timeout;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- size_t ssid_len;
+ struct mutex mtx;
+ struct ieee80211_bss *associated;
+ struct list_head work_list;
- enum {
- IEEE80211_STA_MLME_DISABLED,
- IEEE80211_STA_MLME_DIRECT_PROBE,
- IEEE80211_STA_MLME_AUTHENTICATE,
- IEEE80211_STA_MLME_ASSOCIATE,
- IEEE80211_STA_MLME_ASSOCIATED,
- } state;
+ u8 bssid[ETH_ALEN];
u16 aid;
- u16 ap_capab, capab;
- u8 *extra_ie; /* to be added to the end of AssocReq */
- size_t extra_ie_len;
-
- /* The last AssocReq/Resp IEs */
- u8 *assocreq_ies, *assocresp_ies;
- size_t assocreq_ies_len, assocresp_ies_len;
+ u16 capab;
struct sk_buff_head skb_queue;
- int assoc_scan_tries; /* number of scans done pre-association */
- int direct_probe_tries; /* retries for direct probes */
- int auth_tries; /* retries for auth req */
- int assoc_tries; /* retries for assoc req */
-
unsigned long timers_running; /* used for quiesce/restart */
bool powersave; /* powersave requested for this iface */
unsigned long request;
- unsigned long last_probe;
- unsigned long last_beacon;
-
unsigned int flags;
- unsigned int auth_algs; /* bitfield of allowed auth algs */
- int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
- int auth_transaction;
-
u32 beacon_crc;
enum {
@@ -316,10 +308,6 @@ struct ieee80211_if_managed {
} mfp; /* management frame protection */
int wmm_last_param_set;
-
- /* Extra IE data for management frames */
- u8 *sme_auth_ie;
- size_t sme_auth_ie_len;
};
enum ieee80211_ibss_request {
@@ -339,6 +327,7 @@ struct ieee80211_if_ibss {
bool fixed_bssid;
bool fixed_channel;
+ bool privacy;
u8 bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -478,20 +467,9 @@ struct ieee80211_sub_if_data {
union {
struct {
struct dentry *drop_unencrypted;
- struct dentry *state;
struct dentry *bssid;
- struct dentry *prev_bssid;
- struct dentry *ssid_len;
struct dentry *aid;
- struct dentry *ap_capab;
struct dentry *capab;
- struct dentry *extra_ie_len;
- struct dentry *auth_tries;
- struct dentry *assoc_tries;
- struct dentry *auth_algs;
- struct dentry *auth_alg;
- struct dentry *auth_transaction;
- struct dentry *flags;
struct dentry *force_unicast_rateidx;
struct dentry *max_ratectrl_rateidx;
} sta;
@@ -588,12 +566,44 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_CSA,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
- IEEE80211_QUEUE_STOP_REASON_PENDING,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
};
-struct ieee80211_master_priv {
- struct ieee80211_local *local;
+/**
+ * mac80211 scan flags - currently active scan mode
+ *
+ * @SCAN_SW_SCANNING: We're currently in the process of scanning but may as
+ * well be on the operating channel
+ * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
+ * determine if we are on the operating channel or not
+ * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
+ * gets only set in conjunction with SCAN_SW_SCANNING
+ */
+enum {
+ SCAN_SW_SCANNING,
+ SCAN_HW_SCANNING,
+ SCAN_OFF_CHANNEL,
+};
+
+/**
+ * enum mac80211_scan_state - scan state machine states
+ *
+ * @SCAN_DECISION: Main entry point to the scan state machine, this state
+ * determines if we should keep on scanning or switch back to the
+ * operating channel
+ * @SCAN_SET_CHANNEL: Set the next channel to be scanned
+ * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
+ * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
+ * about us leaving the channel and stop all associated STA interfaces
+ * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
+ * AP about us being back and restart all associated STA interfaces
+ */
+enum mac80211_scan_state {
+ SCAN_DECISION,
+ SCAN_SET_CHANNEL,
+ SCAN_SEND_PROBE,
+ SCAN_LEAVE_OPER_CHANNEL,
+ SCAN_ENTER_OPER_CHANNEL,
};
struct ieee80211_local {
@@ -608,13 +618,20 @@ struct ieee80211_local {
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
- struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
+
+ /* protects the aggregated multicast list and filter calls */
+ spinlock_t filter_lock;
+
+ /* aggregated multicast list */
+ struct dev_addr_list *mc_list;
+ int mc_count;
+
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
/*
@@ -687,7 +704,7 @@ struct ieee80211_local {
/* Scanning and BSS list */
struct mutex scan_mtx;
- bool sw_scanning, hw_scanning;
+ unsigned long scanning;
struct cfg80211_ssid scan_ssid;
struct cfg80211_scan_request int_scan_req;
struct cfg80211_scan_request *scan_req;
@@ -697,7 +714,7 @@ struct ieee80211_local {
int scan_channel_idx;
int scan_ies_len;
- enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+ enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type;
@@ -834,10 +851,6 @@ struct ieee80211_local {
static inline struct ieee80211_sub_if_data *
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- BUG_ON(!local || local->mdev == dev);
-
return netdev_priv(dev);
}
@@ -937,21 +950,20 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
void ieee80211_configure_filter(struct ieee80211_local *local);
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
-/* wireless extensions */
-extern const struct iw_handler_def ieee80211_iw_handler_def;
-
/* STA code */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_auth_request *req);
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_assoc_request *req);
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_deauth_request *req,
+ void *cookie);
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_disassoc_request *req,
+ void *cookie);
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
-int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata);
-int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
-int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
-int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata);
-int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
+ struct sk_buff *skb);
void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -967,8 +979,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
u8 *bssid, u8 *addr, u32 supp_rates);
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
@@ -983,16 +994,9 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
const u8 *ssid, u8 ssid_len);
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req);
-int ieee80211_scan_results(struct ieee80211_local *local,
- struct iw_request_info *info,
- char *buf, size_t len);
void ieee80211_scan_cancel(struct ieee80211_local *local);
ieee80211_rx_result
-ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
- const char *ie, size_t len);
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
struct ieee80211_bss *
@@ -1008,8 +1012,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
- int freq, u8 *ssid, u8 ssid_len);
/* interface handling */
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
@@ -1025,7 +1027,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
void ieee80211_tx_pending(unsigned long data);
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -1092,7 +1093,8 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
int rate, int erp, int short_preamble);
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
- struct ieee80211_hdr *hdr, const u8 *tsc);
+ struct ieee80211_hdr *hdr, const u8 *tsc,
+ gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
int encrypt);
@@ -1129,8 +1131,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
- u8 *extra, size_t extra_len,
- const u8 *bssid, int encrypt);
+ u8 *extra, size_t extra_len, const u8 *bssid,
+ const u8 *key, u8 key_len, u8 key_idx);
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len);
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b7c8a4484298..6c655b6547fb 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev)
ETH_ALEN);
}
- if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
- memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
- ETH_ALEN);
-
/*
* Validate the MAC address for this device.
*/
@@ -229,13 +225,10 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
break;
- case NL80211_IFTYPE_STATION:
- sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- /* fall through */
default:
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
@@ -246,9 +239,9 @@ static int ieee80211_open(struct net_device *dev)
if (ieee80211_vif_is_mesh(&sdata->vif)) {
local->fif_other_bss++;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
ieee80211_start_mesh(sdata);
}
@@ -282,10 +275,6 @@ static int ieee80211_open(struct net_device *dev)
}
if (local->open_count == 0) {
- res = dev_open(local->mdev);
- WARN_ON(res);
- if (res)
- goto err_del_interface;
tasklet_enable(&local->tx_pending_tasklet);
tasklet_enable(&local->tasklet);
}
@@ -346,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
+ unsigned long flags;
+ struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
+ int i;
/*
* Stop TX on this interface first.
@@ -366,18 +358,6 @@ static int ieee80211_stop(struct net_device *dev)
rcu_read_unlock();
/*
- * Announce that we are leaving the network, in case we are a
- * station interface type. This must be done before removing
- * all stations associated with sta_info_flush, otherwise STA
- * information will be gone and no announce being done.
- */
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED)
- ieee80211_sta_deauthenticate(sdata,
- WLAN_REASON_DEAUTH_LEAVING);
- }
-
- /*
* Remove all stations associated with this interface.
*
* This must be done before calling ops->remove_interface()
@@ -408,7 +388,14 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_dec(&local->iff_promiscs);
- dev_mc_unsync(local->mdev, dev);
+ netif_addr_lock_bh(dev);
+ spin_lock_bh(&local->filter_lock);
+ __dev_addr_unsync(&local->mc_list, &local->mc_count,
+ &dev->mc_list, &dev->mc_count);
+ ieee80211_configure_filter(local);
+ spin_unlock_bh(&local->filter_lock);
+ netif_addr_unlock_bh(dev);
+
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -457,24 +444,25 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
break;
case NL80211_IFTYPE_STATION:
- memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
del_timer_sync(&sdata->u.mgd.chswitch_timer);
del_timer_sync(&sdata->u.mgd.timer);
+ del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+ del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
/*
- * If the timer fired while we waited for it, it will have
- * requeued the work. Now the work will be running again
+ * If any of the timers fired while we waited for it, it will
+ * have queued its work. Now the work will be running again
* but will not rearm the timer again because it checks
* whether the interface is running, which, at this point,
* it no longer is.
*/
cancel_work_sync(&sdata->u.mgd.work);
cancel_work_sync(&sdata->u.mgd.chswitch_work);
-
+ cancel_work_sync(&sdata->u.mgd.monitor_work);
cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
/*
@@ -485,12 +473,6 @@ static int ieee80211_stop(struct net_device *dev)
*/
synchronize_rcu();
skb_queue_purge(&sdata->u.mgd.skb_queue);
-
- sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |
- IEEE80211_STA_TKIP_WEP_USED);
- kfree(sdata->u.mgd.extra_ie);
- sdata->u.mgd.extra_ie = NULL;
- sdata->u.mgd.extra_ie_len = 0;
/* fall through */
case NL80211_IFTYPE_ADHOC:
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
@@ -507,9 +489,9 @@ static int ieee80211_stop(struct net_device *dev)
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
ieee80211_stop_mesh(sdata);
}
@@ -536,7 +518,7 @@ static int ieee80211_stop(struct net_device *dev)
* the scan_sdata is NULL already don't send out a
* scan event to userspace -- the scan is incomplete.
*/
- if (local->sw_scanning)
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning))
ieee80211_scan_completed(&local->hw, true);
}
@@ -555,9 +537,6 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
- if (netif_running(local->mdev))
- dev_close(local->mdev);
-
drv_stop(local);
ieee80211_led_radio(local, false);
@@ -575,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev)
if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags);
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+ skb_queue_walk_safe(&local->pending[i], skb, tmp) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ if (info->control.vif == &sdata->vif) {
+ __skb_unlink(skb, &local->pending[i]);
+ dev_kfree_skb_irq(skb);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
return 0;
}
@@ -604,8 +595,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
-
- dev_mc_sync(local->mdev, dev);
+ spin_lock_bh(&local->filter_lock);
+ __dev_addr_sync(&local->mc_list, &local->mc_count,
+ &dev->mc_list, &dev->mc_count);
+ ieee80211_configure_filter(local);
+ spin_unlock_bh(&local->filter_lock);
}
/*
@@ -652,11 +646,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
kfree_skb(sdata->u.ibss.presp);
break;
case NL80211_IFTYPE_STATION:
- kfree(sdata->u.mgd.extra_ie);
- kfree(sdata->u.mgd.assocreq_ies);
- kfree(sdata->u.mgd.assocresp_ies);
- kfree(sdata->u.mgd.sme_auth_ie);
- break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
@@ -695,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
dev->netdev_ops = &ieee80211_dataif_ops;
- dev->wireless_handlers = &ieee80211_iw_handler_def;
dev->destructor = free_netdev;
}
@@ -798,6 +786,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
name, ieee80211_if_setup);
if (!ndev)
return -ENOMEM;
+ dev_net_set(ndev, wiphy_net(local->hw.wiphy));
ndev->needed_headroom = local->tx_headroom +
4*6 /* four MAC addresses */
@@ -814,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
- ndev->features |= NETIF_F_NETNS_LOCAL;
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev);
@@ -931,7 +919,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sdata;
int count = 0;
- if (local->hw_scanning || local->sw_scanning)
+ if (local->scanning)
return ieee80211_idle_off(local, "scanning");
list_for_each_entry(sdata, &local->interfaces, list) {
@@ -939,7 +927,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
continue;
/* do not count disabled managed interfaces */
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
+ !sdata->u.mgd.associated &&
+ list_empty(&sdata->u.mgd.work_list))
continue;
/* do not count unused IBSS interfaces */
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index ce267565e180..659a42d529e3 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -67,6 +67,8 @@ static DECLARE_WORK(todo_work, key_todo);
*
* @key: key to add to do item for
* @flag: todo flag(s)
+ *
+ * Must be called with IRQs or softirqs disabled.
*/
static void add_todo(struct ieee80211_key *key, u32 flag)
{
@@ -140,9 +142,9 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
if (!ret) {
- spin_lock(&todo_lock);
+ spin_lock_bh(&todo_lock);
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
}
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
@@ -164,12 +166,12 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
if (!key || !key->local->ops->set_key)
return;
- spin_lock(&todo_lock);
+ spin_lock_bh(&todo_lock);
if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
return;
}
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
sta = get_sta_for_key(key);
sdata = key->sdata;
@@ -188,9 +190,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
- spin_lock(&todo_lock);
+ spin_lock_bh(&todo_lock);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
}
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -437,14 +439,14 @@ void ieee80211_key_link(struct ieee80211_key *key,
__ieee80211_key_replace(sdata, sta, old_key, key);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
/* free old key later */
add_todo(old_key, KEY_FLAG_TODO_DELETE);
add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
if (netif_running(sdata->dev))
add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
+
+ spin_unlock_irqrestore(&sdata->local->key_lock, flags);
}
static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -547,7 +549,7 @@ static void __ieee80211_key_todo(void)
*/
synchronize_rcu();
- spin_lock(&todo_lock);
+ spin_lock_bh(&todo_lock);
while (!list_empty(&todo_list)) {
key = list_first_entry(&todo_list, struct ieee80211_key, todo);
list_del_init(&key->todo);
@@ -558,7 +560,7 @@ static void __ieee80211_key_todo(void)
KEY_FLAG_TODO_HWACCEL_REMOVE |
KEY_FLAG_TODO_DELETE);
key->flags &= ~todoflags;
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
work_done = false;
@@ -591,9 +593,9 @@ static void __ieee80211_key_todo(void)
WARN_ON(!work_done);
- spin_lock(&todo_lock);
+ spin_lock_bh(&todo_lock);
}
- spin_unlock(&todo_lock);
+ spin_unlock_bh(&todo_lock);
}
void ieee80211_key_todo(void)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 092a017b237e..c1a799194fff 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
new_flags |= (1<<31);
drv_configure_filter(local, changed_flags, &new_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
+ local->mc_count,
+ local->mc_list);
WARN_ON(new_flags & (1<<31));
local->filter_flags = new_flags & ~(1<<31);
}
-/* master interface */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
-static const struct header_ops ieee80211_header_ops = {
- .create = eth_header,
- .parse = header_parse_80211,
- .rebuild = eth_rebuild_header,
- .cache = eth_header_cache,
- .cache_update = eth_header_cache_update,
-};
-
-static int ieee80211_master_open(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
- struct ieee80211_sub_if_data *sdata;
- int res = -EOPNOTSUPP;
-
- /* we hold the RTNL here so can safely walk the list */
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (netif_running(sdata->dev)) {
- res = 0;
- break;
- }
- }
-
- if (res)
- return res;
-
- netif_tx_start_all_queues(local->mdev);
-
- return 0;
-}
-
-static int ieee80211_master_stop(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
- struct ieee80211_sub_if_data *sdata;
-
- /* we hold the RTNL here so can safely walk the list */
- list_for_each_entry(sdata, &local->interfaces, list)
- if (netif_running(sdata->dev))
- dev_close(sdata->dev);
-
- return 0;
-}
-
-static void ieee80211_master_set_multicast_list(struct net_device *dev)
-{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
-
- ieee80211_configure_filter(local);
-}
-
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
struct ieee80211_channel *chan, *scan_chan;
@@ -259,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (local->sw_scanning) {
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
sdata->vif.bss_conf.enable_beacon = false;
} else {
/*
@@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
- skb->dev = local->mdev;
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
@@ -330,19 +268,16 @@ static void ieee80211_tasklet_handler(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
- struct ieee80211_rx_status rx_status;
struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
switch (skb->pkt_type) {
case IEEE80211_RX_MSG:
- /* status is in skb->cb */
- memcpy(&rx_status, skb->cb, sizeof(rx_status));
/* Clear skb->pkt_type in order to not confuse kernel
* netstack. */
skb->pkt_type = 0;
- __ieee80211_rx(local_to_hw(local), skb, &rx_status);
+ ieee80211_rx(local_to_hw(local), skb);
break;
case IEEE80211_TX_STATUS_MSG:
skb->pkt_type = 0;
@@ -685,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (!wiphy)
return NULL;
+ wiphy->netnsok = true;
wiphy->privid = mac80211_wiphy_privid;
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
@@ -719,7 +655,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
mutex_init(&local->scan_mtx);
spin_lock_init(&local->key_lock);
-
+ spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
@@ -755,30 +691,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
-static const struct net_device_ops ieee80211_master_ops = {
- .ndo_start_xmit = ieee80211_master_start_xmit,
- .ndo_open = ieee80211_master_open,
- .ndo_stop = ieee80211_master_stop,
- .ndo_set_multicast_list = ieee80211_master_set_multicast_list,
- .ndo_select_queue = ieee80211_select_queue,
-};
-
-static void ieee80211_master_setup(struct net_device *mdev)
-{
- mdev->type = ARPHRD_IEEE80211;
- mdev->netdev_ops = &ieee80211_master_ops;
- mdev->header_ops = &ieee80211_header_ops;
- mdev->tx_queue_len = 1000;
- mdev->addr_len = ETH_ALEN;
-}
-
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
int result;
enum ieee80211_band band;
- struct net_device *mdev;
- struct ieee80211_master_priv *mpriv;
int channels, i, j, max_bitrates;
bool supp_ht;
static const u32 cipher_suites[] = {
@@ -877,16 +794,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
- mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
- "wmaster%d", ieee80211_master_setup,
- hw->queues);
- if (!mdev)
- goto fail_mdev_alloc;
-
- mpriv = netdev_priv(mdev);
- mpriv->local = local;
- local->mdev = mdev;
-
local->hw.workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
@@ -921,17 +828,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
rtnl_lock();
- result = dev_alloc_name(local->mdev, local->mdev->name);
- if (result < 0)
- goto fail_dev;
-
- memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
- SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
- local->mdev->features |= NETIF_F_NETNS_LOCAL;
-
- result = register_netdevice(local->mdev);
- if (result < 0)
- goto fail_dev;
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
@@ -984,9 +880,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
fail_rate:
- unregister_netdevice(local->mdev);
- local->mdev = NULL;
- fail_dev:
rtnl_unlock();
ieee80211_wep_free(local);
fail_wep:
@@ -995,9 +888,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- if (local->mdev)
- free_netdev(local->mdev);
- fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
kfree(local->int_scan_req.channels);
@@ -1022,13 +912,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
-
- /* First, we remove all virtual interfaces. */
ieee80211_remove_interfaces(local);
- /* then, finally, remove the master interface */
- unregister_netdevice(local->mdev);
-
rtnl_unlock();
ieee80211_clear_tx_pending(local);
@@ -1047,7 +932,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- free_netdev(local->mdev);
kfree(local->int_scan_req.channels);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 11cf45bce38a..9a3826978b1c 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -568,7 +568,7 @@ static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ifmsh = &sdata->u.mesh;
- rx_status = (struct ieee80211_rx_status *) skb->cb;
+ rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
@@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
if (!netif_running(sdata->dev))
return;
- if (local->sw_scanning || local->hw_scanning)
+ if (local->scanning)
return;
while ((skb = skb_dequeue(&ifmsh->skb_queue)))
@@ -671,8 +671,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
}
ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
@@ -686,10 +685,12 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
fc = le16_to_cpu(mgmt->frame_control);
switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ if (skb->len < IEEE80211_MIN_ACTION_SIZE)
+ return RX_DROP_MONITOR;
+ /* fall through */
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_ACTION:
- memcpy(skb->cb, rx_status, sizeof(*rx_status));
skb_queue_tail(&ifmsh->skb_queue, skb);
queue_work(local->hw.workqueue, &ifmsh->work);
return RX_QUEUED;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index c7d72819cdd2..2a2ed182cb7e 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -208,8 +208,7 @@ void ieee80211s_init(void);
void ieee80211s_stop(void);
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status);
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f49ef288e2e2..e93c37ef6a48 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -686,11 +686,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
u8 ttl, dst_flags;
u32 lifetime;
- spin_lock(&ifmsh->mesh_preq_queue_lock);
+ spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
if (!ifmsh->preq_queue_len ||
time_before(jiffies, ifmsh->last_preq +
min_preq_int_jiff(sdata))) {
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
return;
}
@@ -698,7 +698,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
struct mesh_preq_queue, list);
list_del(&preq_node->list);
--ifmsh->preq_queue_len;
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
rcu_read_lock();
mpath = mesh_path_lookup(preq_node->dst, sdata);
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
mesh_path_add(dst_addr, sdata);
mpath = mesh_path_lookup(dst_addr, sdata);
if (!mpath) {
- dev_kfree_skb(skb);
sdata->u.mesh.mshstats.dropped_frames_no_route++;
err = -ENOSPC;
goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
memcpy(hdr->addr1, mpath->next_hop->sta.addr,
ETH_ALEN);
} else {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!(mpath->flags & MESH_PATH_RESOLVING)) {
/* Start discovery only if it is not running yet */
mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
skb_unlink(skb_to_free, &mpath->frame_queue);
}
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&mpath->frame_queue, skb);
if (skb_to_free)
mesh_path_discard_frame(skb_to_free, sdata);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3c72557df45a..04b9e4d61b8e 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -55,7 +55,25 @@ static DEFINE_RWLOCK(pathtbl_resize_lock);
*/
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff_head tmpq;
+ unsigned long flags;
+
rcu_assign_pointer(mpath->next_hop, sta);
+
+ __skb_queue_head_init(&tmpq);
+
+ spin_lock_irqsave(&mpath->frame_queue.lock, flags);
+
+ while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+ __skb_queue_tail(&tmpq, skb);
+ }
+
+ skb_queue_splice(&tmpq, &mpath->frame_queue);
+ spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}
@@ -175,6 +193,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
int err = 0;
u32 hash_idx;
+ might_sleep();
+
if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
/* never add ourselves as neighbours */
return -ENOTSUPP;
@@ -265,6 +285,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
int err = 0;
u32 hash_idx;
+ might_sleep();
if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
/* never add ourselves as neighbours */
@@ -478,11 +499,9 @@ enddel:
*/
void mesh_path_tx_pending(struct mesh_path *mpath)
{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&mpath->frame_queue)) &&
- (mpath->flags & MESH_PATH_ACTIVE))
- dev_queue_xmit(skb);
+ if (mpath->flags & MESH_PATH_ACTIVE)
+ ieee80211_add_pending_skbs(mpath->sdata->local,
+ &mpath->frame_queue);
}
/**
@@ -491,8 +510,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
* @skb: frame to discard
* @sdata: network subif the frame was to be sent through
*
- * If the frame was beign forwarded from another MP, a PERR frame will be sent
- * to the precursor.
+ * If the frame was being forwarded from another MP, a PERR frame will be sent
+ * to the precursor. The precursor's address (i.e. the previous hop) was saved
+ * in addr1 of the frame-to-be-forwarded, and would only be overwritten once
+ * the destination is successfully resolved.
*
* Locking: the function must me called within a rcu_read_lock region
*/
@@ -507,7 +528,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
u8 *ra, *da;
da = hdr->addr3;
- ra = hdr->addr2;
+ ra = hdr->addr1;
mpath = mesh_path_lookup(da, sdata);
if (mpath)
dsn = ++mpath->dsn;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index aca22b00b6a3..ee83125ed179 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -27,43 +27,98 @@
#include "rate.h"
#include "led.h"
-#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_WAIT (HZ / 5)
-#define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
+
+/*
+ * beacon loss detection timeout
+ * XXX: should depend on beacon interval
+ */
+#define IEEE80211_BEACON_LOSS_TIME (2 * HZ)
+/*
+ * Time the connection can be idle before we probe
+ * it to see if we can still talk to the AP.
+ */
+#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ)
+/*
+ * Time we wait for a probe response after sending
+ * a probe request because of beacon loss or for
+ * checking the connection still works.
+ */
+#define IEEE80211_PROBE_WAIT (HZ / 5)
#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1
+/*
+ * All cfg80211 functions have to be called outside a locked
+ * section so that they can acquire a lock themselves... This
+ * is much simpler than queuing up things in cfg80211, but we
+ * do need some indirection for that here.
+ */
+enum rx_mgmt_action {
+ /* no action required */
+ RX_MGMT_NONE,
+
+ /* caller must call cfg80211_send_rx_auth() */
+ RX_MGMT_CFG80211_AUTH,
+
+ /* caller must call cfg80211_send_rx_assoc() */
+ RX_MGMT_CFG80211_ASSOC,
+
+ /* caller must call cfg80211_send_deauth() */
+ RX_MGMT_CFG80211_DEAUTH,
+
+ /* caller must call cfg80211_send_disassoc() */
+ RX_MGMT_CFG80211_DISASSOC,
+
+ /* caller must call cfg80211_auth_timeout() & free work */
+ RX_MGMT_CFG80211_AUTH_TO,
+
+ /* caller must call cfg80211_assoc_timeout() & free work */
+ RX_MGMT_CFG80211_ASSOC_TO,
+};
+
/* utils */
-static int ecw2cw(int ecw)
+static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
{
- return (1 << ecw) - 1;
+ WARN_ON(!mutex_is_locked(&ifmgd->mtx));
}
-static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
+/*
+ * We can have multiple work items (and connection probing)
+ * scheduling this timer, but we need to take care to only
+ * reschedule it when it should fire _earlier_ than it was
+ * asked for before, or if it's not pending right now. This
+ * function ensures that. Note that it then is required to
+ * run this function for all timeouts after the first one
+ * has happened -- the work that runs from this timer will
+ * do that.
+ */
+static void run_again(struct ieee80211_if_managed *ifmgd,
+ unsigned long timeout)
{
- u8 *end, *pos;
+ ASSERT_MGD_MTX(ifmgd);
- pos = bss->cbss.information_elements;
- if (pos == NULL)
- return NULL;
- end = pos + bss->cbss.len_information_elements;
+ if (!timer_pending(&ifmgd->timer) ||
+ time_before(timeout, ifmgd->timer.expires))
+ mod_timer(&ifmgd->timer, timeout);
+}
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
+static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER)
+ return;
+
+ mod_timer(&sdata->u.mgd.bcn_mon_timer,
+ round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
+}
- return NULL;
+static int ecw2cw(int ecw)
+{
+ return (1 << ecw) - 1;
}
static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
@@ -94,11 +149,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
*/
static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct ieee80211_ht_info *hti,
- u16 ap_ht_cap_flags)
+ const u8 *bssid, u16 ap_ht_cap_flags)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
@@ -147,12 +201,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_config(local, 0);
rcu_read_lock();
-
- sta = sta_info_get(local, ifmgd->bssid);
+ sta = sta_info_get(local, bssid);
if (sta)
rate_control_rate_update(local, sband, sta,
IEEE80211_RC_HT_CHANGED);
-
rcu_read_unlock();
}
@@ -175,23 +227,24 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
/* frame sending functions */
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
- u8 *pos, *ies, *ht_ie;
+ u8 *pos;
+ const u8 *ies, *ht_ie;
int i, len, count, rates_len, supp_rates_len;
u16 capab;
- struct ieee80211_bss *bss;
int wmm = 0;
struct ieee80211_supported_band *sband;
u32 rates = 0;
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
- sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +
- ifmgd->ssid_len);
+ sizeof(*mgmt) + 200 + wk->ie_len +
+ wk->ssid_len);
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
"frame\n", sdata->dev->name);
@@ -210,45 +263,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
}
- bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
- local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
- if (bss) {
- if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
- capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_used)
- wmm = 1;
+ if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
+ capab |= WLAN_CAPABILITY_PRIVACY;
+ if (wk->bss->wmm_used)
+ wmm = 1;
- /* get all rates supported by the device and the AP as
- * some APs don't like getting a superset of their rates
- * in the association request (e.g. D-Link DAP 1353 in
- * b-only mode) */
- rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+ /* get all rates supported by the device and the AP as
+ * some APs don't like getting a superset of their rates
+ * in the association request (e.g. D-Link DAP 1353 in
+ * b-only mode) */
+ rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates);
- if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
- (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
- capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
- ieee80211_rx_bss_put(local, bss);
- } else {
- rates = ~0;
- rates_len = sband->n_bitrates;
- }
+ if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+ (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
memset(mgmt, 0, 24);
- memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
+ memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+ memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
- if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
+ if (!is_zero_ether_addr(wk->prev_bssid)) {
skb_put(skb, 10);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_REASSOC_REQ);
mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
mgmt->u.reassoc_req.listen_interval =
cpu_to_le16(local->hw.conf.listen_interval);
- memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid,
+ memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid,
ETH_ALEN);
} else {
skb_put(skb, 4);
@@ -260,10 +303,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
/* SSID */
- ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);
+ ies = pos = skb_put(skb, 2 + wk->ssid_len);
*pos++ = WLAN_EID_SSID;
- *pos++ = ifmgd->ssid_len;
- memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);
+ *pos++ = wk->ssid_len;
+ memcpy(pos, wk->ssid, wk->ssid_len);
/* add all rates which were marked to be used above */
supp_rates_len = rates_len;
@@ -318,9 +361,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
}
- if (ifmgd->extra_ie) {
- pos = skb_put(skb, ifmgd->extra_ie_len);
- memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);
+ if (wk->ie_len && wk->ie) {
+ pos = skb_put(skb, wk->ie_len);
+ memcpy(pos, wk->ie, wk->ie_len);
}
if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
@@ -345,9 +388,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*/
if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
sband->ht_cap.ht_supported &&
- (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
+ (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) &&
ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
- (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) {
+ (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) {
struct ieee80211_ht_info *ht_info =
(struct ieee80211_ht_info *)(ht_ie + 2);
u16 cap = sband->ht_cap.cap;
@@ -382,18 +425,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
}
- kfree(ifmgd->assocreq_ies);
- ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies;
- ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL);
- if (ifmgd->assocreq_ies)
- memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len);
-
ieee80211_tx_skb(sdata, skb, 0);
}
static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
- u16 stype, u16 reason)
+ const u8 *bssid, u16 stype, u16 reason,
+ void *cookie)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -410,18 +448,18 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
memset(mgmt, 0, 24);
- memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
+ memcpy(mgmt->da, bssid, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+ memcpy(mgmt->bssid, bssid, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
skb_put(skb, 2);
/* u.deauth.reason_code == u.disassoc.reason_code */
mgmt->u.deauth.reason_code = cpu_to_le16(reason);
if (stype == IEEE80211_STYPE_DEAUTH)
- cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len);
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie);
else
- cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len);
+ cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie);
ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
}
@@ -494,28 +532,26 @@ static void ieee80211_chswitch_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
- struct ieee80211_bss *bss;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
if (!netif_running(sdata->dev))
return;
- bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
- sdata->local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
- if (!bss)
- goto exit;
+ mutex_lock(&ifmgd->mtx);
+ if (!ifmgd->associated)
+ goto out;
sdata->local->oper_channel = sdata->local->csa_channel;
+ ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+
/* XXX: shouldn't really modify cfg80211-owned data! */
- if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
- bss->cbss.channel = sdata->local->oper_channel;
+ ifmgd->associated->cbss.channel = sdata->local->oper_channel;
- ieee80211_rx_bss_put(sdata->local, bss);
-exit:
- ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
+ out:
+ ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+ mutex_unlock(&ifmgd->mtx);
}
static void ieee80211_chswitch_timer(unsigned long data)
@@ -540,10 +576,12 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
- if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
+ ASSERT_MGD_MTX(ifmgd);
+
+ if (!ifmgd->associated)
return;
- if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+ if (sdata->local->scanning)
return;
/* Disregard subsequent beacons if we are already running a timer
@@ -601,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
* If we are scanning right now then the parameters will
* take effect when scan finishes.
*/
- if (local->hw_scanning || local->sw_scanning)
+ if (local->scanning)
return;
if (conf->dynamic_ps_timeout > 0 &&
@@ -651,8 +689,9 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
}
if (count == 1 && found->u.mgd.powersave &&
- (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) &&
- !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
+ found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
+ !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))) {
s32 beaconint_us;
if (latency < 0)
@@ -721,7 +760,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
- if (local->quiescing)
+ if (local->quiescing || local->suspended)
return;
queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
@@ -806,9 +845,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
u16 capab, bool erp_valid, u8 erp)
{
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-#endif
u32 changed = 0;
bool use_protection;
bool use_short_preamble;
@@ -825,42 +861,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
if (use_protection != bss_conf->use_cts_prot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
- sdata->dev->name,
- use_protection ? "enabled" : "disabled",
- ifmgd->bssid);
- }
-#endif
bss_conf->use_cts_prot = use_protection;
changed |= BSS_CHANGED_ERP_CTS_PROT;
}
if (use_short_preamble != bss_conf->use_short_preamble) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: switched to %s barker preamble"
- " (BSSID=%pM)\n",
- sdata->dev->name,
- use_short_preamble ? "short" : "long",
- ifmgd->bssid);
- }
-#endif
bss_conf->use_short_preamble = use_short_preamble;
changed |= BSS_CHANGED_ERP_PREAMBLE;
}
if (use_short_slot != bss_conf->use_short_slot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: switched to %s slot time"
- " (BSSID=%pM)\n",
- sdata->dev->name,
- use_short_slot ? "short" : "long",
- ifmgd->bssid);
- }
-#endif
bss_conf->use_short_slot = use_short_slot;
changed |= BSS_CHANGED_ERP_SLOT;
}
@@ -868,105 +878,29 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
return changed;
}
-static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)
-{
- union iwreq_data wrqu;
-
- memset(&wrqu, 0, sizeof(wrqu));
- if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)
- memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- char *buf;
- size_t len;
- int i;
- union iwreq_data wrqu;
-
- if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
- return;
-
- buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
- ifmgd->assocresp_ies_len), GFP_KERNEL);
- if (!buf)
- return;
-
- len = sprintf(buf, "ASSOCINFO(");
- if (ifmgd->assocreq_ies) {
- len += sprintf(buf + len, "ReqIEs=");
- for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
- len += sprintf(buf + len, "%02x",
- ifmgd->assocreq_ies[i]);
- }
- }
- if (ifmgd->assocresp_ies) {
- if (ifmgd->assocreq_ies)
- len += sprintf(buf + len, " ");
- len += sprintf(buf + len, "RespIEs=");
- for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
- len += sprintf(buf + len, "%02x",
- ifmgd->assocresp_ies[i]);
- }
- }
- len += sprintf(buf + len, ")");
-
- if (len > IW_CUSTOM_MAX) {
- len = sprintf(buf, "ASSOCRESPIE=");
- for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
- len += sprintf(buf + len, "%02x",
- ifmgd->assocresp_ies[i]);
- }
- }
-
- if (len <= IW_CUSTOM_MAX) {
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = len;
- wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
- }
-
- kfree(buf);
-}
-
-
static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss *bss,
u32 bss_info_changed)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- struct ieee80211_conf *conf = &local_to_hw(local)->conf;
-
- struct ieee80211_bss *bss;
bss_info_changed |= BSS_CHANGED_ASSOC;
- ifmgd->flags |= IEEE80211_STA_ASSOCIATED;
-
- bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
- conf->channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
- if (bss) {
- /* set timing information */
- sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
- sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
- sdata->vif.bss_conf.dtim_period = bss->dtim_period;
+ /* set timing information */
+ sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
+ sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
+ sdata->vif.bss_conf.dtim_period = bss->dtim_period;
- bss_info_changed |= BSS_CHANGED_BEACON_INT;
- bss_info_changed |= ieee80211_handle_bss_capability(sdata,
- bss->cbss.capability, bss->has_erp_value, bss->erp_value);
+ bss_info_changed |= BSS_CHANGED_BEACON_INT;
+ bss_info_changed |= ieee80211_handle_bss_capability(sdata,
+ bss->cbss.capability, bss->has_erp_value, bss->erp_value);
- cfg80211_hold_bss(&bss->cbss);
+ sdata->u.mgd.associated = bss;
+ memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
- ieee80211_rx_bss_put(local, bss);
- }
+ /* just to be sure */
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
- ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
- memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
- ieee80211_sta_send_associnfo(sdata);
-
- ifmgd->last_probe = jiffies;
ieee80211_led_assoc(local, 1);
sdata->vif.bss_conf.assoc = 1;
@@ -991,167 +925,140 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
netif_tx_start_all_queues(sdata->dev);
netif_carrier_on(sdata->dev);
-
- ieee80211_sta_send_apinfo(sdata);
}
-static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- ifmgd->direct_probe_tries++;
- if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+ wk->tries++;
+ if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
- sdata->dev->name, ifmgd->bssid);
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
+ sdata->dev->name, wk->bss->cbss.bssid);
/*
* Most likely AP is not in the range so remove the
- * bss information associated to the AP
+ * bss struct for that AP.
*/
- ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
- sdata->local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
+ cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
/*
* We might have a pending scan which had no chance to run yet
- * due to state == IEEE80211_STA_MLME_DIRECT_PROBE.
- * Hence, queue the STAs work again
+ * due to work needing to be done. Hence, queue the STAs work
+ * again for that.
*/
queue_work(local->hw.workqueue, &ifmgd->work);
- return;
+ return RX_MGMT_CFG80211_AUTH_TO;
}
- printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
- sdata->dev->name, ifmgd->bssid,
- ifmgd->direct_probe_tries);
+ printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
+ sdata->dev->name, wk->bss->cbss.bssid,
+ wk->tries);
- ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
-
- /* Direct probe is sent to broadcast address as some APs
+ /*
+ * Direct probe is sent to broadcast address as some APs
* will not answer to direct packet in unassociated state.
*/
- ieee80211_send_probe_req(sdata, NULL,
- ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
+ ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+ wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+ run_again(ifmgd, wk->timeout);
+
+ return RX_MGMT_NONE;
}
-static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- u8 *ies;
- size_t ies_len;
- ifmgd->auth_tries++;
- if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+ wk->tries++;
+ if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
printk(KERN_DEBUG "%s: authentication with AP %pM"
" timed out\n",
- sdata->dev->name, ifmgd->bssid);
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
- ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
- sdata->local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
+ sdata->dev->name, wk->bss->cbss.bssid);
+
+ /*
+ * Most likely AP is not in the range so remove the
+ * bss struct for that AP.
+ */
+ cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
/*
* We might have a pending scan which had no chance to run yet
- * due to state == IEEE80211_STA_MLME_AUTHENTICATE.
- * Hence, queue the STAs work again
+ * due to work needing to be done. Hence, queue the STAs work
+ * again for that.
*/
queue_work(local->hw.workqueue, &ifmgd->work);
- return;
+ return RX_MGMT_CFG80211_AUTH_TO;
}
- ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
- printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
- sdata->dev->name, ifmgd->bssid);
+ printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
+ sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
- if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
- ies = ifmgd->sme_auth_ie;
- ies_len = ifmgd->sme_auth_ie_len;
- } else {
- ies = NULL;
- ies_len = 0;
- }
- ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len,
- ifmgd->bssid, 0);
- ifmgd->auth_transaction = 2;
+ ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
+ wk->bss->cbss.bssid, NULL, 0, 0);
+ wk->auth_transaction = 2;
+
+ wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+ run_again(ifmgd, wk->timeout);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+ return RX_MGMT_NONE;
}
-/*
- * The disassoc 'reason' argument can be either our own reason
- * if self disconnected or a reason code from the AP.
- */
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
- bool deauth, bool self_disconnected,
- u16 reason)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- struct ieee80211_conf *conf = &local_to_hw(local)->conf;
- struct ieee80211_bss *bss;
struct sta_info *sta;
u32 changed = 0, config_changed = 0;
+ u8 bssid[ETH_ALEN];
- if (deauth) {
- ifmgd->direct_probe_tries = 0;
- ifmgd->auth_tries = 0;
- }
- ifmgd->assoc_scan_tries = 0;
- ifmgd->assoc_tries = 0;
+ ASSERT_MGD_MTX(ifmgd);
+
+ if (WARN_ON(!ifmgd->associated))
+ return;
+
+ memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+
+ ifmgd->associated = NULL;
+ memset(ifmgd->bssid, 0, ETH_ALEN);
+
+ /*
+ * we need to commit the associated = NULL change because the
+ * scan code uses that to determine whether this iface should
+ * go to/wake up from powersave or not -- and could otherwise
+ * wake the queues erroneously.
+ */
+ smp_mb();
+
+ /*
+ * Thus, we can only afterwards stop the queues -- to account
+ * for the case where another CPU is finishing a scan at this
+ * time -- we don't want the scan code to enable queues.
+ */
netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
rcu_read_lock();
- sta = sta_info_get(local, ifmgd->bssid);
+ sta = sta_info_get(local, bssid);
if (sta)
ieee80211_sta_tear_down_BA_sessions(sta);
rcu_read_unlock();
- bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
- conf->channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
-
- if (bss) {
- cfg80211_unhold_bss(&bss->cbss);
- ieee80211_rx_bss_put(local, bss);
- }
-
- if (self_disconnected) {
- if (deauth)
- ieee80211_send_deauth_disassoc(sdata,
- IEEE80211_STYPE_DEAUTH, reason);
- else
- ieee80211_send_deauth_disassoc(sdata,
- IEEE80211_STYPE_DISASSOC, reason);
- }
-
- ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
changed |= ieee80211_reset_erp_info(sdata);
ieee80211_led_assoc(local, 0);
changed |= BSS_CHANGED_ASSOC;
sdata->vif.bss_conf.assoc = false;
- ieee80211_sta_send_apinfo(sdata);
-
- if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
- sdata->local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
- }
-
ieee80211_set_wmm_default(sdata);
ieee80211_recalc_idle(local);
@@ -1180,7 +1087,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
- sta = sta_info_get(local, ifmgd->bssid);
+ sta = sta_info_get(local, bssid);
if (!sta) {
rcu_read_unlock();
return;
@@ -1193,83 +1100,42 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sta_info_destroy(sta);
}
-static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
-{
- if (!sdata || !sdata->default_key ||
- sdata->default_key->conf.alg != ALG_WEP)
- return 0;
- return 1;
-}
-
-static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_bss *bss;
- int bss_privacy;
- int wep_privacy;
- int privacy_invoked;
-
- if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME))
- return 0;
-
- bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
- local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
- if (!bss)
- return 0;
-
- bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
- wep_privacy = !!ieee80211_sta_wep_configured(sdata);
- privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);
-
- ieee80211_rx_bss_put(local, bss);
-
- if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
- return 0;
-
- return 1;
-}
-
-static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_associate(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- ifmgd->assoc_tries++;
- if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+ wk->tries++;
+ if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
printk(KERN_DEBUG "%s: association with AP %pM"
" timed out\n",
- sdata->dev->name, ifmgd->bssid);
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid);
- ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
- sdata->local->hw.conf.channel->center_freq,
- ifmgd->ssid, ifmgd->ssid_len);
+ sdata->dev->name, wk->bss->cbss.bssid);
+
+ /*
+ * Most likely AP is not in the range so remove the
+ * bss struct for that AP.
+ */
+ cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
+
/*
* We might have a pending scan which had no chance to run yet
- * due to state == IEEE80211_STA_MLME_ASSOCIATE.
- * Hence, queue the STAs work again
+ * due to work needing to be done. Hence, queue the STAs work
+ * again for that.
*/
queue_work(local->hw.workqueue, &ifmgd->work);
- return;
+ return RX_MGMT_CFG80211_ASSOC_TO;
}
- ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
- printk(KERN_DEBUG "%s: associate with AP %pM\n",
- sdata->dev->name, ifmgd->bssid);
- if (ieee80211_privacy_mismatch(sdata)) {
- printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
- "mixed-cell disabled - abort association\n", sdata->dev->name);
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- return;
- }
+ printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
+ sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
+ ieee80211_send_assoc(sdata, wk);
- ieee80211_send_assoc(sdata);
+ wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
+ run_again(ifmgd, wk->timeout);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+ return RX_MGMT_NONE;
}
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1280,50 +1146,86 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
* from AP because we know that the connection is working both ways
* at that time. But multicast frames (and hence also beacons) must
* be ignored here, because we need to trigger the timer during
- * data idle periods for sending the periodical probe request to
- * the AP.
+ * data idle periods for sending the periodic probe request to the
+ * AP we're connected to.
*/
- if (!is_multicast_ether_addr(hdr->addr1))
- mod_timer(&sdata->u.mgd.timer,
- jiffies + IEEE80211_MONITORING_INTERVAL);
+ if (is_multicast_ether_addr(hdr->addr1))
+ return;
+
+ mod_timer(&sdata->u.mgd.conn_mon_timer,
+ round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
}
-void ieee80211_beacon_loss_work(struct work_struct *work)
+static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
+ bool beacon)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data,
- u.mgd.beacon_loss_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ const u8 *ssid;
+ bool already = false;
- /*
- * The driver has already reported this event and we have
- * already sent a probe request. Maybe the AP died and the
- * driver keeps reporting until we disassociate... We have
- * to ignore that because otherwise we would continually
- * reset the timer and never check whether we received a
- * probe response!
- */
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+ if (!netif_running(sdata->dev))
return;
+ if (sdata->local->scanning)
+ return;
+
+ mutex_lock(&ifmgd->mtx);
+
+ if (!ifmgd->associated)
+ goto out;
+
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
- "- sending probe request\n", sdata->dev->name,
- sdata->u.mgd.bssid);
- }
+ if (beacon && net_ratelimit())
+ printk(KERN_DEBUG "%s: detected beacon loss from AP "
+ "- sending probe request\n", sdata->dev->name);
#endif
- ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ /*
+ * The driver/our work has already reported this event or the
+ * connection monitoring has kicked in and we have already sent
+ * a probe request. Or maybe the AP died and the driver keeps
+ * reporting until we disassociate...
+ *
+ * In either case we have to ignore the current call to this
+ * function (except for setting the correct probe reason bit)
+ * because otherwise we would reset the timer every time and
+ * never check whether we received a probe response!
+ */
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ already = true;
+
+ if (beacon)
+ ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
+ else
+ ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
+
+ if (already)
+ goto out;
+
+ ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1);
mutex_unlock(&sdata->local->iflist_mtx);
- ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
- ifmgd->ssid_len, NULL, 0);
+ ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
+ ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+ ssid + 2, ssid[1], NULL, 0);
+
+ run_again(ifmgd, ifmgd->probe_timeout);
+
+ out:
+ mutex_unlock(&ifmgd->mtx);
+}
+
+void ieee80211_beacon_loss_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.beacon_loss_work);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
+ ieee80211_mgd_probe_ap(sdata, true);
}
void ieee80211_beacon_loss(struct ieee80211_vif *vif)
@@ -1335,105 +1237,16 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
}
EXPORT_SYMBOL(ieee80211_beacon_loss);
-static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- unsigned long last_rx;
- bool disassoc = false;
-
- /* TODO: start monitoring current AP signal quality and number of
- * missed beacons. Scan other channels every now and then and search
- * for better APs. */
- /* TODO: remove expired BSSes */
-
- ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ifmgd->bssid);
- if (!sta) {
- printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
- sdata->dev->name, ifmgd->bssid);
- disassoc = true;
- rcu_read_unlock();
- goto out;
- }
-
- last_rx = sta->last_rx;
- rcu_read_unlock();
-
- if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
- time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) {
- printk(KERN_DEBUG "%s: no probe response from AP %pM "
- "- disassociating\n",
- sdata->dev->name, ifmgd->bssid);
- disassoc = true;
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
- goto out;
- }
-
- /*
- * Beacon filtering is only enabled with power save and then the
- * stack should not check for beacon loss.
- */
- if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) &&
- (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
- time_after(jiffies,
- ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: beacon loss from AP %pM "
- "- sending probe request\n",
- sdata->dev->name, ifmgd->bssid);
- }
-#endif
- ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
- mutex_lock(&local->iflist_mtx);
- ieee80211_recalc_ps(local, -1);
- mutex_unlock(&local->iflist_mtx);
- ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
- ifmgd->ssid_len, NULL, 0);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
- goto out;
- }
-
- if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) {
- ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
- mutex_lock(&local->iflist_mtx);
- ieee80211_recalc_ps(local, -1);
- mutex_unlock(&local->iflist_mtx);
- ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
- ifmgd->ssid_len, NULL, 0);
- }
-
- out:
- if (!disassoc)
- mod_timer(&ifmgd->timer,
- jiffies + IEEE80211_MONITORING_INTERVAL);
- else
- ieee80211_set_disassoc(sdata, true, true,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
+ wk->state = IEEE80211_MGD_STATE_IDLE;
printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
- ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;
- if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
- /* Wait for SME to request association */
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(sdata->local);
- } else
- ieee80211_associate(sdata);
}
static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk,
struct ieee80211_mgmt *mgmt,
size_t len)
{
@@ -1444,161 +1257,133 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
if (!elems.challenge)
return;
- ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg,
+ ieee80211_send_auth(sdata, 3, wk->auth_alg,
elems.challenge - 2, elems.challenge_len + 2,
- sdata->u.mgd.bssid, 1);
- sdata->u.mgd.auth_transaction = 4;
+ wk->bss->cbss.bssid,
+ wk->key, wk->key_len, wk->key_idx);
+ wk->auth_transaction = 4;
}
-static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk,
+ struct ieee80211_mgmt *mgmt, size_t len)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u16 auth_alg, auth_transaction, status_code;
- if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE)
- return;
+ if (wk->state != IEEE80211_MGD_STATE_AUTH)
+ return RX_MGMT_NONE;
if (len < 24 + 6)
- return;
+ return RX_MGMT_NONE;
- if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
- return;
+ if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+ return RX_MGMT_NONE;
- if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
- return;
+ if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+ return RX_MGMT_NONE;
auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
status_code = le16_to_cpu(mgmt->u.auth.status_code);
- if (auth_alg != ifmgd->auth_alg ||
- auth_transaction != ifmgd->auth_transaction)
- return;
+ if (auth_alg != wk->auth_alg ||
+ auth_transaction != wk->auth_transaction)
+ return RX_MGMT_NONE;
if (status_code != WLAN_STATUS_SUCCESS) {
- if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
- u8 algs[3];
- const int num_algs = ARRAY_SIZE(algs);
- int i, pos;
- algs[0] = algs[1] = algs[2] = 0xff;
- if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)
- algs[0] = WLAN_AUTH_OPEN;
- if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
- algs[1] = WLAN_AUTH_SHARED_KEY;
- if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
- algs[2] = WLAN_AUTH_LEAP;
- if (ifmgd->auth_alg == WLAN_AUTH_OPEN)
- pos = 0;
- else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY)
- pos = 1;
- else
- pos = 2;
- for (i = 0; i < num_algs; i++) {
- pos++;
- if (pos >= num_algs)
- pos = 0;
- if (algs[pos] == ifmgd->auth_alg ||
- algs[pos] == 0xff)
- continue;
- if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
- !ieee80211_sta_wep_configured(sdata))
- continue;
- ifmgd->auth_alg = algs[pos];
- break;
- }
- }
- return;
+ list_del(&wk->list);
+ kfree(wk);
+ return RX_MGMT_CFG80211_AUTH;
}
- switch (ifmgd->auth_alg) {
+ switch (wk->auth_alg) {
case WLAN_AUTH_OPEN:
case WLAN_AUTH_LEAP:
case WLAN_AUTH_FT:
- ieee80211_auth_completed(sdata);
- cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
- break;
+ ieee80211_auth_completed(sdata, wk);
+ return RX_MGMT_CFG80211_AUTH;
case WLAN_AUTH_SHARED_KEY:
- if (ifmgd->auth_transaction == 4) {
- ieee80211_auth_completed(sdata);
- cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
+ if (wk->auth_transaction == 4) {
+ ieee80211_auth_completed(sdata, wk);
+ return RX_MGMT_CFG80211_AUTH;
} else
- ieee80211_auth_challenge(sdata, mgmt, len);
+ ieee80211_auth_challenge(sdata, wk, mgmt, len);
break;
}
+
+ return RX_MGMT_NONE;
}
-static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk,
+ struct ieee80211_mgmt *mgmt, size_t len)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ const u8 *bssid = NULL;
u16 reason_code;
if (len < 24 + 2)
- return;
+ return RX_MGMT_NONE;
- if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
- return;
+ ASSERT_MGD_MTX(ifmgd);
+
+ if (wk)
+ bssid = wk->bss->cbss.bssid;
+ else
+ bssid = ifmgd->associated->cbss.bssid;
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
- if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED)
- printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
- sdata->dev->name, reason_code);
+ printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
+ sdata->dev->name, bssid, reason_code);
- if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
- (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
- ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE ||
- ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) {
- ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
- mod_timer(&ifmgd->timer, jiffies +
- IEEE80211_RETRY_AUTH_INTERVAL);
+ if (!wk) {
+ ieee80211_set_disassoc(sdata);
+ } else {
+ list_del(&wk->list);
+ kfree(wk);
}
- ieee80211_set_disassoc(sdata, true, false, 0);
- ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
- cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len);
+ return RX_MGMT_CFG80211_DEAUTH;
}
-static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u16 reason_code;
if (len < 24 + 2)
- return;
+ return RX_MGMT_NONE;
- if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
- return;
+ ASSERT_MGD_MTX(ifmgd);
- reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+ if (WARN_ON(!ifmgd->associated))
+ return RX_MGMT_NONE;
- if (ifmgd->flags & IEEE80211_STA_ASSOCIATED)
- printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
- sdata->dev->name, reason_code);
+ if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN)))
+ return RX_MGMT_NONE;
- if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
- ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {
- ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
- mod_timer(&ifmgd->timer, jiffies +
- IEEE80211_RETRY_AUTH_INTERVAL);
- }
+ reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+ printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+ sdata->dev->name, reason_code);
- ieee80211_set_disassoc(sdata, false, false, reason_code);
- cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len);
+ ieee80211_set_disassoc(sdata);
+ return RX_MGMT_CFG80211_DISASSOC;
}
-static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- int reassoc)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgd_work *wk,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ bool reassoc)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
@@ -1614,17 +1399,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
bool have_higher_than_11mbit = false, newsta = false;
u16 ap_ht_cap_flags;
- /* AssocResp and ReassocResp have identical structure, so process both
- * of them in this function. */
-
- if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
- return;
+ /*
+ * AssocResp and ReassocResp have identical structure, so process both
+ * of them in this function.
+ */
if (len < 24 + 6)
- return;
+ return RX_MGMT_NONE;
- if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
- return;
+ if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+ return RX_MGMT_NONE;
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -1647,26 +1431,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: AP rejected association temporarily; "
"comeback duration %u TU (%u ms)\n",
sdata->dev->name, tu, ms);
+ wk->timeout = jiffies + msecs_to_jiffies(ms);
if (ms > IEEE80211_ASSOC_TIMEOUT)
- mod_timer(&ifmgd->timer,
- jiffies + msecs_to_jiffies(ms));
- return;
+ run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
+ return RX_MGMT_NONE;
}
if (status_code != WLAN_STATUS_SUCCESS) {
printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
sdata->dev->name, status_code);
- /* if this was a reassociation, ensure we try a "full"
- * association next time. This works around some broken APs
- * which do not correctly reject reassociation requests. */
- ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
- if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
- /* Wait for SME to decide what to do next */
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- }
- return;
+ list_del(&wk->list);
+ kfree(wk);
+ return RX_MGMT_CFG80211_ASSOC;
}
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
@@ -1677,51 +1453,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (!elems.supp_rates) {
printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
sdata->dev->name);
- return;
+ return RX_MGMT_NONE;
}
printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
ifmgd->aid = aid;
- ifmgd->ap_capab = capab_info;
-
- kfree(ifmgd->assocresp_ies);
- ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt);
- ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL);
- if (ifmgd->assocresp_ies)
- memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len);
rcu_read_lock();
/* Add STA entry for the AP */
- sta = sta_info_get(local, ifmgd->bssid);
+ sta = sta_info_get(local, wk->bss->cbss.bssid);
if (!sta) {
newsta = true;
- sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC);
+ rcu_read_unlock();
+
+ sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
if (!sta) {
printk(KERN_DEBUG "%s: failed to alloc STA entry for"
" the AP\n", sdata->dev->name);
- rcu_read_unlock();
- return;
+ return RX_MGMT_NONE;
}
- /* update new sta with its last rx activity */
- sta->last_rx = jiffies;
- }
-
- /*
- * FIXME: Do we really need to update the sta_info's information here?
- * We already know about the AP (we found it in our list) so it
- * should already be filled with the right info, no?
- * As is stands, all this is racy because typically we assume
- * the information that is filled in here (except flags) doesn't
- * change while a STA structure is alive. As such, it should move
- * to between the sta_info_alloc() and sta_info_insert() above.
- */
+ set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_ASSOC_AP);
+ if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
- set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP);
- if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
- set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+ rcu_read_lock();
+ }
rates = 0;
basic_rates = 0;
@@ -1771,8 +1531,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- /* If TKIP/WEP is used, no need to parse AP's HT capabilities */
- if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))
+ if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
@@ -1792,7 +1551,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: failed to insert STA entry for"
" the AP (error %d)\n", sdata->dev->name, err);
rcu_read_unlock();
- return;
+ return RX_MGMT_NONE;
}
}
@@ -1806,24 +1565,27 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (elems.ht_info_elem && elems.wmm_param &&
(ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
- !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))
+ !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
+ wk->bss->cbss.bssid,
ap_ht_cap_flags);
/* set AID and assoc capability,
* ieee80211_set_associated() will tell the driver */
bss_conf->aid = aid;
bss_conf->assoc_capability = capab_info;
- ieee80211_set_associated(sdata, changed);
+ ieee80211_set_associated(sdata, wk->bss, changed);
/*
- * initialise the time of last beacon to be the association time,
- * otherwise beacon loss check will trigger immediately
+ * Start timer to probe the connection to the AP now.
+ * Also start the timer that will detect beacon loss.
*/
- ifmgd->last_beacon = jiffies;
+ ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
+ mod_beacon_timer(sdata);
- ieee80211_associated(sdata);
- cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
+ list_del(&wk->list);
+ kfree(wk);
+ return RX_MGMT_CFG80211_ASSOC;
}
@@ -1851,23 +1613,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
channel, beacon);
- if (!bss)
+ if (bss)
+ ieee80211_rx_bss_put(local, bss);
+
+ if (!sdata->u.mgd.associated)
return;
if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
- (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
+ (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid,
+ ETH_ALEN) == 0)) {
struct ieee80211_channel_sw_ie *sw_elem =
(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
}
-
- ieee80211_rx_bss_put(local, bss);
}
static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len,
+ struct ieee80211_mgd_work *wk,
+ struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_if_managed *ifmgd;
@@ -1876,6 +1640,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ifmgd = &sdata->u.mgd;
+ ASSERT_MGD_MTX(ifmgd);
+
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
return; /* ignore ProbeResp to foreign address */
@@ -1889,17 +1655,32 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
/* direct probe may be part of the association flow */
- if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) {
+ if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
printk(KERN_DEBUG "%s direct probe responded\n",
sdata->dev->name);
- ieee80211_authenticate(sdata);
+ wk->tries = 0;
+ wk->state = IEEE80211_MGD_STATE_AUTH;
+ WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
}
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ if (ifmgd->associated &&
+ memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
+ ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL)) {
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1);
mutex_unlock(&sdata->local->iflist_mtx);
+ /*
+ * We've received a probe response, but are not sure whether
+ * we have or will be receiving any beacons or data, so let's
+ * schedule the timers again, just in case.
+ */
+ mod_beacon_timer(sdata);
+ mod_timer(&ifmgd->conn_mon_timer,
+ round_jiffies_up(jiffies +
+ IEEE80211_CONNECTION_IDLE_TIME));
}
}
@@ -1937,6 +1718,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
bool erp_valid, directed_tim = false;
u8 erp_value = 0;
u32 ncrc;
+ u8 *bssid;
+
+ ASSERT_MGD_MTX(ifmgd);
/* Process beacon from the current BSS */
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1946,23 +1730,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (rx_status->freq != local->hw.conf.channel->center_freq)
return;
- if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
- memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
+ /*
+ * We might have received a number of frames, among them a
+ * disassoc frame and a beacon...
+ */
+ if (!ifmgd->associated)
+ return;
+
+ bssid = ifmgd->associated->cbss.bssid;
+
+ /*
+ * And in theory even frames from a different AP we were just
+ * associated to a split-second ago!
+ */
+ if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+ if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: cancelling probereq poll due "
"to a received beacon\n", sdata->dev->name);
}
#endif
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
}
+ /*
+ * Push the beacon loss detection into the future since
+ * we are processing a beacon from the AP just now.
+ */
+ mod_beacon_timer(sdata);
+
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
len - baselen, &elems,
@@ -2019,15 +1821,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
- !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) {
+ !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
struct sta_info *sta;
struct ieee80211_supported_band *sband;
u16 ap_ht_cap_flags;
rcu_read_lock();
- sta = sta_info_get(local, ifmgd->bssid);
- if (!sta) {
+ sta = sta_info_get(local, bssid);
+ if (WARN_ON(!sta)) {
rcu_read_unlock();
return;
}
@@ -2042,7 +1844,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
- ap_ht_cap_flags);
+ bssid, ap_ht_cap_flags);
}
if (elems.country_elem) {
@@ -2063,8 +1865,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
@@ -2080,12 +1881,12 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_AUTH:
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
case IEEE80211_STYPE_DEAUTH:
case IEEE80211_STYPE_DISASSOC:
+ case IEEE80211_STYPE_ACTION:
skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
queue_work(local->hw.workqueue, &sdata->u.mgd.work);
return RX_QUEUED;
@@ -2097,40 +1898,119 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_rx_status *rx_status;
struct ieee80211_mgmt *mgmt;
+ struct ieee80211_mgd_work *wk;
+ enum rx_mgmt_action rma = RX_MGMT_NONE;
u16 fc;
rx_status = (struct ieee80211_rx_status *) skb->cb;
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PROBE_RESP:
- ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
- rx_status);
- break;
- case IEEE80211_STYPE_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
- rx_status);
- break;
- case IEEE80211_STYPE_AUTH:
- ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
+ mutex_lock(&ifmgd->mtx);
+
+ if (ifmgd->associated &&
+ memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid,
+ ETH_ALEN) == 0) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_BEACON:
+ ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt,
+ skb->len, rx_status);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ rma = ieee80211_rx_mgmt_deauth(sdata, NULL,
+ mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_DISASSOC:
+ rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_ACTION:
+ /* XXX: differentiate, can only happen for CSA now! */
+ ieee80211_sta_process_chanswitch(sdata,
+ &mgmt->u.action.u.chan_switch.sw_elem,
+ ifmgd->associated);
+ break;
+ }
+ mutex_unlock(&ifmgd->mtx);
+
+ switch (rma) {
+ case RX_MGMT_NONE:
+ /* no action */
+ break;
+ case RX_MGMT_CFG80211_DEAUTH:
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len,
+ NULL);
+ break;
+ case RX_MGMT_CFG80211_DISASSOC:
+ cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len,
+ NULL);
+ break;
+ default:
+ WARN(1, "unexpected: %d", rma);
+ }
+ goto out;
+ }
+
+ list_for_each_entry(wk, &ifmgd->work_list, list) {
+ if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+ continue;
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_AUTH:
+ rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_ASSOC_RESP:
+ rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+ skb->len, false);
+ break;
+ case IEEE80211_STYPE_REASSOC_RESP:
+ rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+ skb->len, true);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt,
+ skb->len);
+ break;
+ }
+ /*
+ * We've processed this frame for that work, so it can't
+ * belong to another work struct.
+ * NB: this is also required for correctness because the
+ * called functions can free 'wk', and for 'rma'!
+ */
break;
- case IEEE80211_STYPE_ASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0);
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+
+ switch (rma) {
+ case RX_MGMT_NONE:
+ /* no action */
break;
- case IEEE80211_STYPE_REASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1);
+ case RX_MGMT_CFG80211_AUTH:
+ cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len);
break;
- case IEEE80211_STYPE_DEAUTH:
- ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
+ case RX_MGMT_CFG80211_ASSOC:
+ cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
break;
- case IEEE80211_STYPE_DISASSOC:
- ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+ case RX_MGMT_CFG80211_DEAUTH:
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL);
break;
+ default:
+ WARN(1, "unexpected: %d", rma);
}
+ out:
kfree_skb(skb);
}
@@ -2146,125 +2026,9 @@ static void ieee80211_sta_timer(unsigned long data)
return;
}
- set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
queue_work(local->hw.workqueue, &ifmgd->work);
}
-static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
-
- /* Reset own TSF to allow time synchronization work. */
- drv_reset_tsf(local);
-
- ifmgd->wmm_last_param_set = -1; /* allow any WMM update */
-
-
- if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)
- ifmgd->auth_alg = WLAN_AUTH_OPEN;
- else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
- ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY;
- else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
- ifmgd->auth_alg = WLAN_AUTH_LEAP;
- else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT)
- ifmgd->auth_alg = WLAN_AUTH_FT;
- else
- ifmgd->auth_alg = WLAN_AUTH_OPEN;
- ifmgd->auth_transaction = -1;
- ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
- ifmgd->assoc_scan_tries = 0;
- ifmgd->direct_probe_tries = 0;
- ifmgd->auth_tries = 0;
- ifmgd->assoc_tries = 0;
- netif_tx_stop_all_queues(sdata->dev);
- netif_carrier_off(sdata->dev);
-}
-
-static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_bss *bss;
- u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid;
- u8 ssid_len = ifmgd->ssid_len;
- u16 capa_mask = WLAN_CAPABILITY_ESS;
- u16 capa_val = WLAN_CAPABILITY_ESS;
- struct ieee80211_channel *chan = local->oper_channel;
-
- if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
- ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL)) {
- capa_mask |= WLAN_CAPABILITY_PRIVACY;
- if (sdata->default_key)
- capa_val |= WLAN_CAPABILITY_PRIVACY;
- }
-
- if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
- chan = NULL;
-
- if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL)
- bssid = NULL;
-
- if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) {
- ssid = NULL;
- ssid_len = 0;
- }
-
- bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan,
- bssid, ssid, ssid_len,
- capa_mask, capa_val);
-
- if (bss) {
- local->oper_channel = bss->cbss.channel;
- local->oper_channel_type = NL80211_CHAN_NO_HT;
- ieee80211_hw_config(local, 0);
-
- if (!(ifmgd->flags & IEEE80211_STA_SSID_SET))
- ieee80211_sta_set_ssid(sdata, bss->ssid,
- bss->ssid_len);
- ieee80211_sta_set_bssid(sdata, bss->cbss.bssid);
- ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,
- bss->supp_rates);
- if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED)
- sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
- else
- sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
-
- /* Send out direct probe if no probe resp was received or
- * the one we have is outdated
- */
- if (!bss->last_probe_resp ||
- time_after(jiffies, bss->last_probe_resp
- + IEEE80211_SCAN_RESULT_EXPIRE))
- ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
- else
- ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-
- ieee80211_rx_bss_put(local, bss);
- ieee80211_sta_reset_auth(sdata);
- return 0;
- } else {
- if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
-
- ifmgd->assoc_scan_tries++;
-
- ieee80211_request_internal_scan(sdata, ifmgd->ssid,
- ssid_len);
-
- ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
- set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
- } else {
- ifmgd->assoc_scan_tries = 0;
- ifmgd->state = IEEE80211_STA_MLME_DISABLED;
- ieee80211_recalc_idle(local);
- }
- }
- return -1;
-}
-
-
static void ieee80211_sta_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -2272,11 +2036,15 @@ static void ieee80211_sta_work(struct work_struct *work)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd;
struct sk_buff *skb;
+ struct ieee80211_mgd_work *wk, *tmp;
+ LIST_HEAD(free_work);
+ enum rx_mgmt_action rma;
+ bool anybusy = false;
if (!netif_running(sdata->dev))
return;
- if (local->sw_scanning || local->hw_scanning)
+ if (local->scanning)
return;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
@@ -2294,66 +2062,176 @@ static void ieee80211_sta_work(struct work_struct *work)
ifmgd = &sdata->u.mgd;
+ /* first process frames to avoid timing out while a frame is pending */
while ((skb = skb_dequeue(&ifmgd->skb_queue)))
ieee80211_sta_rx_queued_mgmt(sdata, skb);
- if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
- ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&
- ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&
- test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- round_jiffies_relative(0));
- return;
+ /* then process the rest of the work */
+ mutex_lock(&ifmgd->mtx);
+
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL) &&
+ ifmgd->associated) {
+ if (time_is_after_jiffies(ifmgd->probe_timeout))
+ run_again(ifmgd, ifmgd->probe_timeout);
+ else {
+ u8 bssid[ETH_ALEN];
+ /*
+ * We actually lost the connection ... or did we?
+ * Let's make sure!
+ */
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
+ memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+ printk(KERN_DEBUG "No probe response from AP %pM"
+ " after %dms, disconnecting.\n",
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
+ ieee80211_set_disassoc(sdata);
+ mutex_unlock(&ifmgd->mtx);
+ /*
+ * must be outside lock due to cfg80211,
+ * but that's not a problem.
+ */
+ ieee80211_send_deauth_disassoc(sdata, bssid,
+ IEEE80211_STYPE_DEAUTH,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ NULL);
+ mutex_lock(&ifmgd->mtx);
+ }
}
- if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) {
- if (ieee80211_sta_config_auth(sdata))
- return;
- clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
- } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
- return;
+ list_for_each_entry(wk, &ifmgd->work_list, list) {
+ if (wk->state != IEEE80211_MGD_STATE_IDLE) {
+ anybusy = true;
+ break;
+ }
+ }
ieee80211_recalc_idle(local);
- switch (ifmgd->state) {
- case IEEE80211_STA_MLME_DISABLED:
- break;
- case IEEE80211_STA_MLME_DIRECT_PROBE:
- ieee80211_direct_probe(sdata);
- break;
- case IEEE80211_STA_MLME_AUTHENTICATE:
- ieee80211_authenticate(sdata);
- break;
- case IEEE80211_STA_MLME_ASSOCIATE:
- ieee80211_associate(sdata);
- break;
- case IEEE80211_STA_MLME_ASSOCIATED:
- ieee80211_associated(sdata);
- break;
- default:
- WARN_ON(1);
- break;
+ if (!anybusy) {
+ mutex_unlock(&ifmgd->mtx);
+
+ if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
+ queue_delayed_work(local->hw.workqueue,
+ &local->scan_work,
+ round_jiffies_relative(0));
+ return;
}
- if (ieee80211_privacy_mismatch(sdata)) {
- printk(KERN_DEBUG "%s: privacy configuration mismatch and "
- "mixed-cell disabled - disassociate\n", sdata->dev->name);
+ list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
+ if (time_is_after_jiffies(wk->timeout)) {
+ /*
+ * This work item isn't supposed to be worked on
+ * right now, but take care to adjust the timer
+ * properly.
+ */
+ run_again(ifmgd, wk->timeout);
+ continue;
+ }
+
+ switch (wk->state) {
+ default:
+ WARN_ON(1);
+ /* fall through */
+ case IEEE80211_MGD_STATE_IDLE:
+ /* nothing */
+ rma = RX_MGMT_NONE;
+ break;
+ case IEEE80211_MGD_STATE_PROBE:
+ rma = ieee80211_direct_probe(sdata, wk);
+ break;
+ case IEEE80211_MGD_STATE_AUTH:
+ rma = ieee80211_authenticate(sdata, wk);
+ break;
+ case IEEE80211_MGD_STATE_ASSOC:
+ rma = ieee80211_associate(sdata, wk);
+ break;
+ }
+
+ switch (rma) {
+ case RX_MGMT_NONE:
+ /* no action required */
+ break;
+ case RX_MGMT_CFG80211_AUTH_TO:
+ case RX_MGMT_CFG80211_ASSOC_TO:
+ list_del(&wk->list);
+ list_add(&wk->list, &free_work);
+ wk->tries = rma; /* small abuse but only local */
+ break;
+ default:
+ WARN(1, "unexpected: %d", rma);
+ }
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+
+ list_for_each_entry_safe(wk, tmp, &free_work, list) {
+ switch (wk->tries) {
+ case RX_MGMT_CFG80211_AUTH_TO:
+ cfg80211_send_auth_timeout(sdata->dev,
+ wk->bss->cbss.bssid);
+ break;
+ case RX_MGMT_CFG80211_ASSOC_TO:
+ cfg80211_send_assoc_timeout(sdata->dev,
+ wk->bss->cbss.bssid);
+ break;
+ default:
+ WARN(1, "unexpected: %d", wk->tries);
+ }
- ieee80211_set_disassoc(sdata, false, true,
- WLAN_REASON_UNSPECIFIED);
+ list_del(&wk->list);
+ kfree(wk);
}
+
+ ieee80211_recalc_idle(local);
+}
+
+static void ieee80211_sta_bcn_mon_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_local *local = sdata->local;
+
+ if (local->quiescing)
+ return;
+
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.mgd.beacon_loss_work);
+}
+
+static void ieee80211_sta_conn_mon_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_local *local = sdata->local;
+
+ if (local->quiescing)
+ return;
+
+ queue_work(local->hw.workqueue, &ifmgd->monitor_work);
+}
+
+static void ieee80211_sta_monitor_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.monitor_work);
+
+ ieee80211_mgd_probe_ap(sdata, false);
}
static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- /*
- * Need to update last_beacon to avoid beacon loss
- * test to trigger.
- */
- sdata->u.mgd.last_beacon = jiffies;
-
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL);
+ /* let's probe the connection once */
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.mgd.monitor_work);
+ /* and do all the other regular work too */
queue_work(sdata->local->hw.workqueue,
&sdata->u.mgd.work);
}
@@ -2378,6 +2256,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->chswitch_work);
if (del_timer_sync(&ifmgd->chswitch_timer))
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+
+ cancel_work_sync(&ifmgd->monitor_work);
+ /* these will just be re-established on connection */
+ del_timer_sync(&ifmgd->conn_mon_timer);
+ del_timer_sync(&ifmgd->bcn_mon_timer);
}
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
@@ -2395,210 +2278,277 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd;
- u32 hw_flags;
ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->work, ieee80211_sta_work);
+ INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
+ setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
+ (unsigned long) sdata);
+ setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer,
+ (unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
(unsigned long) sdata);
skb_queue_head_init(&ifmgd->skb_queue);
+ INIT_LIST_HEAD(&ifmgd->work_list);
+
ifmgd->capab = WLAN_CAPABILITY_ESS;
- ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN |
- IEEE80211_AUTH_ALG_SHARED_KEY;
- ifmgd->flags |= IEEE80211_STA_CREATE_IBSS |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL;
+ ifmgd->flags = 0;
if (sdata->local->hw.queues >= 4)
ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
- hw_flags = sdata->local->hw.flags;
-
- if (hw_flags & IEEE80211_HW_SUPPORTS_PS) {
- ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE;
- sdata->local->hw.conf.dynamic_ps_timeout = 500;
- }
+ mutex_init(&ifmgd->mtx);
}
-/* configuration hooks */
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
+/* scan finished notification */
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
-
- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
- return;
-
- if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET |
- IEEE80211_STA_AUTO_BSSID_SEL)) &&
- (ifmgd->flags & (IEEE80211_STA_SSID_SET |
- IEEE80211_STA_AUTO_SSID_SEL))) {
-
- if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
- ieee80211_set_disassoc(sdata, true, true,
- WLAN_REASON_DEAUTH_LEAVING);
-
- if (ifmgd->ssid_len == 0) {
- /*
- * Only allow association to be started if a valid SSID
- * is configured.
- */
- return;
- }
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) ||
- ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
- set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
- else if (ifmgd->flags & IEEE80211_STA_EXT_SME)
- set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
- queue_work(local->hw.workqueue, &ifmgd->work);
- }
+ /* Restart STA timers */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ ieee80211_restart_sta_timer(sdata);
+ rcu_read_unlock();
}
-int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata)
+int ieee80211_max_network_latency(struct notifier_block *nb,
+ unsigned long data, void *dummy)
{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ s32 latency_usec = (s32) data;
+ struct ieee80211_local *local =
+ container_of(nb, struct ieee80211_local,
+ network_latency_notifier);
- if (ifmgd->ssid_len)
- ifmgd->flags |= IEEE80211_STA_SSID_SET;
- else
- ifmgd->flags &= ~IEEE80211_STA_SSID_SET;
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, latency_usec);
+ mutex_unlock(&local->iflist_mtx);
return 0;
}
-int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
+/* config hooks */
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_auth_request *req)
{
- struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ const u8 *ssid;
+ struct ieee80211_mgd_work *wk;
+ u16 auth_alg;
- if (len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
+ switch (req->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ auth_alg = WLAN_AUTH_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ auth_alg = WLAN_AUTH_SHARED_KEY;
+ break;
+ case NL80211_AUTHTYPE_FT:
+ auth_alg = WLAN_AUTH_FT;
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ auth_alg = WLAN_AUTH_LEAP;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
- ifmgd = &sdata->u.mgd;
+ wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
+ if (!wk)
+ return -ENOMEM;
- if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) {
- if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
- ieee80211_set_disassoc(sdata, true, true,
- WLAN_REASON_DEAUTH_LEAVING);
+ wk->bss = (void *)req->bss;
- /*
- * Do not use reassociation if SSID is changed (different ESS).
- */
- ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid));
- memcpy(ifmgd->ssid, ssid, len);
- ifmgd->ssid_len = len;
+ if (req->ie && req->ie_len) {
+ memcpy(wk->ie, req->ie, req->ie_len);
+ wk->ie_len = req->ie_len;
}
- return ieee80211_sta_commit(sdata);
-}
+ if (req->key && req->key_len) {
+ wk->key_len = req->key_len;
+ wk->key_idx = req->key_idx;
+ memcpy(wk->key, req->key, req->key_len);
+ }
-int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len);
- *len = ifmgd->ssid_len;
+ ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+ memcpy(wk->ssid, ssid + 2, ssid[1]);
+ wk->ssid_len = ssid[1];
+
+ wk->state = IEEE80211_MGD_STATE_PROBE;
+ wk->auth_alg = auth_alg;
+ wk->timeout = jiffies; /* run right away */
+
+ /*
+ * XXX: if still associated need to tell AP that we're going
+ * to sleep and then change channel etc.
+ */
+ sdata->local->oper_channel = req->bss->channel;
+ ieee80211_hw_config(sdata->local, 0);
+
+ mutex_lock(&ifmgd->mtx);
+ list_add(&wk->list, &sdata->u.mgd.work_list);
+ mutex_unlock(&ifmgd->mtx);
+
+ queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
return 0;
}
-int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_assoc_request *req)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_mgd_work *wk, *found = NULL;
+ int i, err;
- if (compare_ether_addr(bssid, ifmgd->bssid) != 0 &&
- ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
- ieee80211_set_disassoc(sdata, true, true,
- WLAN_REASON_DEAUTH_LEAVING);
+ mutex_lock(&ifmgd->mtx);
- if (is_valid_ether_addr(bssid)) {
- memcpy(ifmgd->bssid, bssid, ETH_ALEN);
- ifmgd->flags |= IEEE80211_STA_BSSID_SET;
- } else {
- memset(ifmgd->bssid, 0, ETH_ALEN);
- ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;
+ list_for_each_entry(wk, &ifmgd->work_list, list) {
+ if (&wk->bss->cbss == req->bss &&
+ wk->state == IEEE80211_MGD_STATE_IDLE) {
+ found = wk;
+ break;
+ }
}
- return ieee80211_sta_commit(sdata);
-}
+ if (!found) {
+ err = -ENOLINK;
+ goto out;
+ }
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
- const char *ie, size_t len)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ list_del(&found->list);
- if (len == 0 && ifmgd->extra_ie_len == 0)
- return -EALREADY;
+ wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
+ if (!wk) {
+ list_add(&found->list, &ifmgd->work_list);
+ err = -ENOMEM;
+ goto out;
+ }
- if (len == ifmgd->extra_ie_len && ifmgd->extra_ie &&
- memcmp(ifmgd->extra_ie, ie, len) == 0)
- return -EALREADY;
+ list_add(&wk->list, &ifmgd->work_list);
- kfree(ifmgd->extra_ie);
- if (len == 0) {
- ifmgd->extra_ie = NULL;
- ifmgd->extra_ie_len = 0;
- return 0;
- }
- ifmgd->extra_ie = kmalloc(len, GFP_KERNEL);
- if (!ifmgd->extra_ie) {
- ifmgd->extra_ie_len = 0;
- return -ENOMEM;
+ ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
+
+ for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+ if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
+ req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
+ req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+
+ sdata->local->oper_channel = req->bss->channel;
+ ieee80211_hw_config(sdata->local, 0);
+
+ if (req->ie && req->ie_len) {
+ memcpy(wk->ie, req->ie, req->ie_len);
+ wk->ie_len = req->ie_len;
+ } else
+ wk->ie_len = 0;
+
+ if (req->prev_bssid)
+ memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
+
+ wk->state = IEEE80211_MGD_STATE_ASSOC;
+ wk->tries = 0;
+ wk->timeout = jiffies; /* run right away */
+
+ if (req->use_mfp) {
+ ifmgd->mfp = IEEE80211_MFP_REQUIRED;
+ ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
+ } else {
+ ifmgd->mfp = IEEE80211_MFP_DISABLED;
+ ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
}
- memcpy(ifmgd->extra_ie, ie, len);
- ifmgd->extra_ie_len = len;
- return 0;
-}
-int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)
-{
- printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
- sdata->dev->name, reason);
+ if (req->crypto.control_port)
+ ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
+ else
+ ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
- ieee80211_set_disassoc(sdata, true, true, reason);
- return 0;
+ queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+
+ err = 0;
+
+ out:
+ mutex_unlock(&ifmgd->mtx);
+ return err;
}
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_deauth_request *req,
+ void *cookie)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_mgd_work *wk;
+ const u8 *bssid = NULL;
- printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
- sdata->dev->name, reason);
+ printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
+ sdata->dev->name, req->reason_code);
+
+ mutex_lock(&ifmgd->mtx);
+
+ if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
+ bssid = req->bss->bssid;
+ ieee80211_set_disassoc(sdata);
+ } else list_for_each_entry(wk, &ifmgd->work_list, list) {
+ if (&wk->bss->cbss == req->bss) {
+ bssid = req->bss->bssid;
+ list_del(&wk->list);
+ kfree(wk);
+ break;
+ }
+ }
- if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))
+ /*
+ * cfg80211 should catch this ... but it's racy since
+ * we can receive a deauth frame, process it, hand it
+ * to cfg80211 while that's in a locked section already
+ * trying to tell us that the user wants to disconnect.
+ */
+ if (!bssid) {
+ mutex_unlock(&ifmgd->mtx);
return -ENOLINK;
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+
+ ieee80211_send_deauth_disassoc(sdata, bssid,
+ IEEE80211_STYPE_DEAUTH, req->reason_code,
+ cookie);
- ieee80211_set_disassoc(sdata, false, true, reason);
return 0;
}
-/* scan finished notification */
-void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_disassoc_request *req,
+ void *cookie)
{
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- /* Restart STA timers */
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- ieee80211_restart_sta_timer(sdata);
- rcu_read_unlock();
-}
+ printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
+ sdata->dev->name, req->reason_code);
-int ieee80211_max_network_latency(struct notifier_block *nb,
- unsigned long data, void *dummy)
-{
- s32 latency_usec = (s32) data;
- struct ieee80211_local *local =
- container_of(nb, struct ieee80211_local,
- network_latency_notifier);
+ mutex_lock(&ifmgd->mtx);
- mutex_lock(&local->iflist_mtx);
- ieee80211_recalc_ps(local, latency_usec);
- mutex_unlock(&local->iflist_mtx);
+ /*
+ * cfg80211 should catch this ... but it's racy since
+ * we can receive a disassoc frame, process it, hand it
+ * to cfg80211 while that's in a locked section already
+ * trying to tell us that the user wants to disconnect.
+ */
+ if (&ifmgd->associated->cbss != req->bss) {
+ mutex_unlock(&ifmgd->mtx);
+ return -ENOLINK;
+ }
+
+ ieee80211_set_disassoc(sdata);
+
+ mutex_unlock(&ifmgd->mtx);
+ ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
+ IEEE80211_STYPE_DISASSOC, req->reason_code,
+ cookie);
return 0;
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 7a549f9deb96..5e3d476972f9 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -55,15 +55,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
rcu_read_unlock();
- /* flush again, in case driver queued work */
- flush_workqueue(local->hw.workqueue);
-
- /* stop hardware - this must stop RX */
- if (local->open_count) {
- ieee80211_led_radio(local, false);
- drv_stop(local);
- }
-
/* remove STAs */
spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry(sta, &local->sta_list, list) {
@@ -111,7 +102,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
drv_remove_interface(local, &conf);
}
+ /* stop hardware - this must stop RX */
+ if (local->open_count) {
+ ieee80211_led_radio(local, false);
+ drv_stop(local);
+ }
+
+ /*
+ * flush again, in case driver queued work -- it
+ * shouldn't be doing (or cancel everything in the
+ * stop callback) that but better safe than sorry.
+ */
+ flush_workqueue(local->hw.workqueue);
+
local->suspended = true;
+ /* need suspended to be visible before quiescing is false */
+ barrier();
local->quiescing = false;
return 0;
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 4641f00a1e5c..b33efc4fc267 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -198,6 +198,35 @@ static void rate_control_release(struct kref *kref)
kfree(ctrl_ref);
}
+static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
+{
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
+}
+
+bool rate_control_send_low(struct ieee80211_sta *sta,
+ void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+
+ if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
+ info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+ info->control.rates[0].count =
+ (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+ 1 : txrc->hw->max_rate_tries;
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL(rate_control_send_low);
+
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_tx_rate_control *txrc)
@@ -258,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
struct rate_control_ref *ref, *old;
ASSERT_RTNL();
- if (local->open_count || netif_running(local->mdev))
+ if (local->open_count)
return -EBUSY;
ref = rate_control_alloc(name, local);
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 37771abd8f5a..7c5142988bbb 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -70,20 +70,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
return i;
}
-static inline bool
-use_low_rate(struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u16 fc;
-
- fc = le16_to_cpu(hdr->frame_control);
-
- return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
- (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA);
-}
-
-
static void
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
{
@@ -232,7 +218,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
void *priv_sta, struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
- struct ieee80211_supported_band *sband = txrc->sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct minstrel_sta_info *mi = priv_sta;
struct minstrel_priv *mp = priv;
@@ -245,14 +230,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
int mrr_ndx[3];
int sample_rate;
- if (!sta || !mi || use_low_rate(skb)) {
- ar[0].idx = rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- ar[0].count = 1;
- else
- ar[0].count = mp->max_retry;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a0bef767ceb5..8c053be9dc24 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -276,11 +276,9 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
{
struct sk_buff *skb = txrc->skb;
struct ieee80211_supported_band *sband = txrc->sband;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rc_pid_sta_info *spinfo = priv_sta;
int rateidx;
- u16 fc;
if (txrc->rts)
info->control.rates[0].count =
@@ -290,16 +288,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
txrc->hw->conf.short_frame_max_tx_count;
/* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if (!sta || !spinfo ||
- (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK) {
- info->control.rates[0].idx = rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
-
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rateidx = spinfo->txrate_idx;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index de5bba7f910a..25a669c86e14 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -30,7 +30,6 @@
static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb,
- struct ieee80211_rx_status *status,
u16 mpdu_seq_num,
int bar_req);
/*
@@ -59,11 +58,11 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
return skb;
}
-static inline int should_drop_frame(struct ieee80211_rx_status *status,
- struct sk_buff *skb,
+static inline int should_drop_frame(struct sk_buff *skb,
int present_fcs_len,
int radiotap_len)
{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
@@ -111,10 +110,10 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
static void
ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
struct sk_buff *skb,
- struct ieee80211_rx_status *status,
struct ieee80211_rate *rate,
int rtap_len)
{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_radiotap_header *rthdr;
unsigned char *pos;
@@ -220,9 +219,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
*/
static struct sk_buff *
ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
- struct ieee80211_rx_status *status,
struct ieee80211_rate *rate)
{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
struct ieee80211_sub_if_data *sdata;
int needed_headroom = 0;
struct sk_buff *skb, *skb2;
@@ -248,8 +247,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
present_fcs_len = FCS_LEN;
if (!local->monitors) {
- if (should_drop_frame(status, origskb, present_fcs_len,
- rtap_len)) {
+ if (should_drop_frame(origskb, present_fcs_len, rtap_len)) {
dev_kfree_skb(origskb);
return NULL;
}
@@ -257,7 +255,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
return remove_monitor_info(local, origskb, rtap_len);
}
- if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {
+ if (should_drop_frame(origskb, present_fcs_len, rtap_len)) {
/* only need to expand headroom if necessary */
skb = origskb;
origskb = NULL;
@@ -289,7 +287,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
/* if necessary, prepend radiotap information */
if (!(status->flag & RX_FLAG_RADIOTAP))
- ieee80211_add_rx_radiotap_header(local, skb, status, rate,
+ ieee80211_add_rx_radiotap_header(local, skb, rate,
needed_headroom);
skb_reset_mac_header(skb);
@@ -420,13 +418,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb;
- if (unlikely(local->hw_scanning))
- return ieee80211_scan_rx(rx->sdata, skb, rx->status);
+ if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
+ return ieee80211_scan_rx(rx->sdata, skb);
- if (unlikely(local->sw_scanning)) {
+ if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
+ (rx->flags & IEEE80211_RX_IN_SCAN))) {
/* drop all the other packets during a software scan anyway */
- if (ieee80211_scan_rx(rx->sdata, skb, rx->status)
- != RX_QUEUED)
+ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
dev_kfree_skb(skb);
return RX_QUEUED;
}
@@ -785,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
atomic_inc(&sdata->bss->num_sta_ps);
- set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
+ set_sta_flags(sta, WLAN_STA_PS);
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
@@ -801,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
atomic_dec(&sdata->bss->num_sta_ps);
- clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
+ clear_sta_flags(sta, WLAN_STA_PS);
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
if (!skb_queue_empty(&sta->ps_tx_buf))
@@ -836,28 +834,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (!sta)
return RX_CONTINUE;
- /* Update last_rx only for IBSS packets which are for the current
- * BSSID to avoid keeping the current IBSS network alive in cases where
- * other STAs are using different BSSID. */
+ /*
+ * Update last_rx only for IBSS packets which are for the current
+ * BSSID to avoid keeping the current IBSS network alive in cases
+ * where other STAs start using different BSSID.
+ */
if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
NL80211_IFTYPE_ADHOC);
if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
sta->last_rx = jiffies;
- } else
- if (!is_multicast_ether_addr(hdr->addr1) ||
- rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
- /* Update last_rx only for unicast frames in order to prevent
- * the Probe Request frames (the only broadcast frames from a
- * STA in infrastructure mode) from keeping a connection alive.
+ } else if (!is_multicast_ether_addr(hdr->addr1)) {
+ /*
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
*/
- if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
- ieee80211_is_beacon(hdr->frame_control)) {
- rx->sdata->u.mgd.last_beacon = jiffies;
- } else
- sta->last_rx = jiffies;
+ sta->last_rx = jiffies;
}
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1125,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
skb_queue_empty(&rx->sta->ps_tx_buf);
if (skb) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) skb->data;
/*
- * Tell TX path to send one frame even though the STA may
+ * Tell TX path to send this frame even though the STA may
* still remain is PS mode after this frame exchange.
*/
- set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
+ info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
@@ -1147,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
else
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- dev_queue_xmit(skb);
+ ieee80211_add_pending_skb(rx->local, skb);
if (no_pending_pkts)
sta_info_clear_tim_bit(rx->sta);
@@ -1487,10 +1480,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct ieee80211s_hdr *mesh_hdr;
unsigned int hdrlen;
struct sk_buff *skb = rx->skb, *fwd_skb;
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_sub_if_data *sdata;
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+ sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
if (!ieee80211_is_data(hdr->frame_control))
return RX_CONTINUE;
@@ -1500,10 +1496,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
- struct ieee80211_sub_if_data *sdata;
struct mesh_path *mppath;
- sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
rcu_read_lock();
mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
if (!mppath) {
@@ -1529,6 +1523,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
dropped_frames_ttl);
else {
struct ieee80211_hdr *fwd_hdr;
+ struct ieee80211_tx_info *info;
+
fwd_skb = skb_copy(skb, GFP_ATOMIC);
if (!fwd_skb && net_ratelimit())
@@ -1542,9 +1538,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
*/
memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
- fwd_skb->dev = rx->local->mdev;
- fwd_skb->iif = rx->dev->ifindex;
- dev_queue_xmit(fwd_skb);
+ info = IEEE80211_SKB_CB(fwd_skb);
+ memset(info, 0, sizeof(*info));
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.vif = &rx->sdata->vif;
+ ieee80211_select_queue(local, fwd_skb);
+ if (is_multicast_ether_addr(fwd_hdr->addr3))
+ memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+ ETH_ALEN);
+ else {
+ int err = mesh_nexthop_lookup(fwd_skb, sdata);
+ /* Failed to immediately resolve next hop:
+ * fwded frame was dropped or will be added
+ * later to the pending skb queue. */
+ if (err)
+ return RX_DROP_MONITOR;
+ }
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+ fwded_frames);
+ ieee80211_add_pending_skb(local, fwd_skb);
}
}
@@ -1620,7 +1632,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
/* manage reordering buffer according to requested */
/* sequence number */
rcu_read_lock();
- ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
+ ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
start_seq_num, 1);
rcu_read_unlock();
return RX_DROP_UNUSABLE;
@@ -1644,12 +1656,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
- /* Not from the current AP. */
- return;
- }
-
- if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
- /* Association in progress; ignore SA Query */
+ /* Not from the current AP or not associated yet. */
return;
}
@@ -1686,7 +1693,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
- struct ieee80211_bss *bss;
int len = rx->skb->len;
if (!ieee80211_is_action(mgmt->frame_control))
@@ -1764,17 +1770,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
return RX_DROP_MONITOR;
- bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
- local->hw.conf.channel->center_freq,
- sdata->u.mgd.ssid,
- sdata->u.mgd.ssid_len);
- if (!bss)
- return RX_DROP_MONITOR;
-
- ieee80211_sta_process_chanswitch(sdata,
- &mgmt->u.action.u.chan_switch.sw_elem, bss);
- ieee80211_rx_bss_put(local, bss);
- break;
+ return ieee80211_sta_rx_mgmt(sdata, rx->skb);
}
break;
case WLAN_CATEGORY_SA_QUERY:
@@ -1817,19 +1813,18 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
if (ieee80211_vif_is_mesh(&sdata->vif))
- return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+ return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
+ return ieee80211_ibss_rx_mgmt(sdata, rx->skb);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
- return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
+ return ieee80211_sta_rx_mgmt(sdata, rx->skb);
return RX_DROP_MONITOR;
}
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
- struct ieee80211_hdr *hdr,
+static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
struct ieee80211_rx_data *rx)
{
int keyidx;
@@ -1866,7 +1861,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
!ieee80211_is_auth(hdr->frame_control))
goto ignore;
- mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL);
+ mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
+ GFP_ATOMIC);
ignore:
dev_kfree_skb(rx->skb);
rx->skb = NULL;
@@ -2028,13 +2024,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_STATION:
if (!bssid)
return 0;
- if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
- return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
- } else if (!multicast &&
- compare_ether_addr(sdata->dev->dev_addr,
- hdr->addr1) != 0) {
+ if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2114,9 +2105,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
*/
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb,
- struct ieee80211_rx_status *status,
struct ieee80211_rate *rate)
{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr;
@@ -2143,11 +2134,12 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
- ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+ ieee80211_rx_michael_mic_report(hdr, &rx);
return;
}
- if (unlikely(local->sw_scanning || local->hw_scanning))
+ if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+ test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
rx.flags |= IEEE80211_RX_IN_SCAN;
ieee80211_parse_qos(&rx);
@@ -2227,20 +2219,21 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate;
- struct ieee80211_rx_status status;
+ struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
+ struct ieee80211_rx_status *status;
- if (!tid_agg_rx->reorder_buf[index])
+ if (!skb)
goto no_frame;
+ status = IEEE80211_SKB_RXCB(skb);
+
/* release the reordered frames to stack */
- memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status));
- sband = hw->wiphy->bands[status.band];
- if (status.flag & RX_FLAG_HT)
+ sband = hw->wiphy->bands[status->band];
+ if (status->flag & RX_FLAG_HT)
rate = sband->bitrates; /* TODO: HT rates */
else
- rate = &sband->bitrates[status.rate_idx];
- __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
- &status, rate);
+ rate = &sband->bitrates[status->rate_idx];
+ __ieee80211_rx_handle_packet(hw, skb, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
@@ -2265,7 +2258,6 @@ no_frame:
static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb,
- struct ieee80211_rx_status *rxstatus,
u16 mpdu_seq_num,
int bar_req)
{
@@ -2324,8 +2316,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
/* put the frame in the reordering buffer */
tid_agg_rx->reorder_buf[index] = skb;
tid_agg_rx->reorder_time[index] = jiffies;
- memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
- sizeof(*rxstatus));
tid_agg_rx->stored_mpdu_num++;
/* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
@@ -2374,8 +2364,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
}
static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct ieee80211_rx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -2424,7 +2413,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
/* according to mpdu sequence number deal with reordering buffer */
mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
- ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
+ ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
mpdu_seq_num, 0);
end_reorder:
return ret;
@@ -2434,12 +2423,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
* This is the receive path handler. It is called by a low level driver when an
* 802.11 MPDU is received from the hardware.
*/
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_rx_status *status)
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
if (status->band < 0 ||
status->band >= IEEE80211_NUM_BANDS) {
@@ -2453,6 +2442,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
+ /*
+ * If we're suspending, it is possible although not too likely
+ * that we'd be receiving frames after having already partially
+ * quiesced the stack. We can't process such frames then since
+ * that might, for example, cause stations to be added or other
+ * driver callbacks be invoked.
+ */
+ if (unlikely(local->quiescing || local->suspended)) {
+ kfree_skb(skb);
+ return;
+ }
+
if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||
@@ -2482,7 +2483,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
* if it was previously present.
* Also, frames with less than 16 bytes are dropped.
*/
- skb = ieee80211_rx_monitor(local, skb, status, rate);
+ skb = ieee80211_rx_monitor(local, skb, rate);
if (!skb) {
rcu_read_unlock();
return;
@@ -2500,8 +2501,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
* frames from other than operational channel), but that should not
* happen in normal networks.
*/
- if (!ieee80211_rx_reorder_ampdu(local, skb, status))
- __ieee80211_rx_handle_packet(hw, skb, status, rate);
+ if (!ieee80211_rx_reorder_ampdu(local, skb))
+ __ieee80211_rx_handle_packet(hw, skb, rate);
rcu_read_unlock();
}
@@ -2509,16 +2510,12 @@ EXPORT_SYMBOL(__ieee80211_rx);
/* This is a version of the rx handler that can be called from hard irq
* context. Post the skb on the queue and schedule the tasklet */
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_rx_status *status)
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
- skb->dev = local->mdev;
- /* copy status into skb->cb for use by tasklet */
- memcpy(skb->cb, status, sizeof(*status));
skb->pkt_type = IEEE80211_RX_MSG;
skb_queue_tail(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 2a8d09ad17ff..45731000eb8d 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -18,7 +18,6 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <net/mac80211.h>
-#include <net/iw_handler.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -26,7 +25,7 @@
#define IEEE80211_PROBE_DELAY (HZ / 33)
#define IEEE80211_CHANNEL_TIME (HZ / 33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
@@ -121,23 +120,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
return bss;
}
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
- int freq, u8 *ssid, u8 ssid_len)
-{
- struct ieee80211_bss *bss;
- struct ieee80211_local *local = sdata->local;
-
- bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
- if (bss) {
- cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
- ieee80211_rx_bss_put(local, bss);
- }
-}
-
ieee80211_rx_result
-ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_mgmt *mgmt;
struct ieee80211_bss *bss;
u8 *elements;
@@ -278,7 +264,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
mutex_lock(&local->scan_mtx);
- if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
+ if (WARN_ON(!local->scanning)) {
mutex_unlock(&local->scan_mtx);
return;
}
@@ -288,16 +274,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
return;
}
- if (local->hw_scanning)
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning))
ieee80211_restore_scan_ies(local);
if (local->scan_req != &local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL;
- was_hw_scan = local->hw_scanning;
- local->hw_scanning = false;
- local->sw_scanning = false;
+ was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
+ local->scanning = 0;
local->scan_channel = NULL;
/* we only have to protect scan_req and hw/sw scan */
@@ -307,16 +292,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (was_hw_scan)
goto done;
- netif_tx_lock_bh(local->mdev);
- netif_addr_lock(local->mdev);
+ spin_lock_bh(&local->filter_lock);
local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
-
- netif_addr_unlock(local->mdev);
- netif_tx_unlock_bh(local->mdev);
+ local->mc_count,
+ local->mc_list);
+ spin_unlock_bh(&local->filter_lock);
drv_sw_scan_complete(local);
@@ -327,7 +309,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
+ if (sdata->u.mgd.associated) {
ieee80211_scan_ps_disable(sdata);
netif_tx_wake_all_queues(sdata->dev);
}
@@ -382,26 +364,25 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED);
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
- netif_tx_stop_all_queues(sdata->dev);
- ieee80211_scan_ps_enable(sdata);
- }
- } else
+ /*
+ * only handle non-STA interfaces here, STA interfaces
+ * are handled in the scan state machine
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
netif_tx_stop_all_queues(sdata->dev);
}
mutex_unlock(&local->iflist_mtx);
- local->scan_state = SCAN_SET_CHANNEL;
+ local->next_scan_state = SCAN_DECISION;
local->scan_channel_idx = 0;
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
&local->filter_flags,
- local->mdev->mc_count,
- local->mdev->mc_list);
- netif_addr_unlock_bh(local->mdev);
+ local->mc_count,
+ local->mc_list);
+ spin_unlock_bh(&local->filter_lock);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
queue_delayed_work(local->hw.workqueue, &local->scan_work,
@@ -443,18 +424,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (req != &local->int_scan_req &&
sdata->vif.type == NL80211_IFTYPE_STATION &&
- (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
- ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
- ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
- /* actually wait for the assoc to finish/time out */
+ !list_empty(&ifmgd->work_list)) {
+ /* actually wait for the work it's doing to finish/time out */
set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
return 0;
}
if (local->ops->hw_scan)
- local->hw_scanning = true;
+ __set_bit(SCAN_HW_SCANNING, &local->scanning);
else
- local->sw_scanning = true;
+ __set_bit(SCAN_SW_SCANNING, &local->scanning);
/*
* Kicking off the scan need not be protected,
* only the scan variable stuff, since now
@@ -477,11 +456,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->scan_mtx);
if (rc) {
- if (local->ops->hw_scan) {
- local->hw_scanning = false;
+ if (local->ops->hw_scan)
ieee80211_restore_scan_ies(local);
- } else
- local->sw_scanning = false;
+ local->scanning = 0;
ieee80211_recalc_idle(local);
@@ -492,13 +469,195 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
return rc;
}
+static int ieee80211_scan_state_decision(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ bool associated = false;
+ struct ieee80211_sub_if_data *sdata;
+
+ /* if no more bands/channels left, complete scan and advance to the idle state */
+ if (local->scan_channel_idx >= local->scan_req->n_channels) {
+ ieee80211_scan_completed(&local->hw, false);
+ return 1;
+ }
+
+ /* check if at least one STA interface is associated */
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!netif_running(sdata->dev))
+ continue;
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ if (sdata->u.mgd.associated) {
+ associated = true;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&local->iflist_mtx);
+
+ if (local->scan_channel) {
+ /*
+ * we're currently scanning a different channel, let's
+ * switch back to the operating channel now if at least
+ * one interface is associated. Otherwise just scan the
+ * next channel
+ */
+ if (associated)
+ local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+ else
+ local->next_scan_state = SCAN_SET_CHANNEL;
+ } else {
+ /*
+ * we're on the operating channel currently, let's
+ * leave that channel now to scan another one
+ */
+ local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+ }
+
+ *next_delay = 0;
+ return 0;
+}
+
+static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ /*
+ * notify the AP about us leaving the channel and stop all STA interfaces
+ */
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!netif_running(sdata->dev))
+ continue;
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ netif_tx_stop_all_queues(sdata->dev);
+ if (sdata->u.mgd.associated)
+ ieee80211_scan_ps_enable(sdata);
+ }
+ }
+ mutex_unlock(&local->iflist_mtx);
+
+ __set_bit(SCAN_OFF_CHANNEL, &local->scanning);
+
+ /* advance to the next channel to be scanned */
+ *next_delay = HZ / 10;
+ local->next_scan_state = SCAN_SET_CHANNEL;
+}
+
+static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+ /* switch back to the operating channel */
+ local->scan_channel = NULL;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+ /*
+ * notify the AP about us being back and restart all STA interfaces
+ */
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!netif_running(sdata->dev))
+ continue;
+
+ /* Tell AP we're back */
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ if (sdata->u.mgd.associated)
+ ieee80211_scan_ps_disable(sdata);
+ netif_tx_wake_all_queues(sdata->dev);
+ }
+ }
+ mutex_unlock(&local->iflist_mtx);
+
+ __clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
+
+ *next_delay = HZ / 5;
+ local->next_scan_state = SCAN_DECISION;
+}
+
+static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ int skip;
+ struct ieee80211_channel *chan;
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+ skip = 0;
+ chan = local->scan_req->channels[local->scan_channel_idx];
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
+ (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+ chan->flags & IEEE80211_CHAN_NO_IBSS))
+ skip = 1;
+
+ if (!skip) {
+ local->scan_channel = chan;
+ if (ieee80211_hw_config(local,
+ IEEE80211_CONF_CHANGE_CHANNEL))
+ skip = 1;
+ }
+
+ /* advance state machine to next channel/band */
+ local->scan_channel_idx++;
+
+ if (skip) {
+ /* if we skip this channel return to the decision state */
+ local->next_scan_state = SCAN_DECISION;
+ return;
+ }
+
+ /*
+ * Probe delay is used to update the NAV, cf. 11.1.3.2.2
+ * (which unfortunately doesn't say _why_ step a) is done,
+ * but it waits for the probe delay or until a frame is
+ * received - and the received frame would update the NAV).
+ * For now, we do not support waiting until a frame is
+ * received.
+ *
+ * In any case, it is not necessary for a passive scan.
+ */
+ if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+ !local->scan_req->n_ssids) {
+ *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ local->next_scan_state = SCAN_DECISION;
+ return;
+ }
+
+ /* active scan, send probes */
+ *next_delay = IEEE80211_PROBE_DELAY;
+ local->next_scan_state = SCAN_SEND_PROBE;
+}
+
+static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ int i;
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+
+ for (i = 0; i < local->scan_req->n_ssids; i++)
+ ieee80211_send_probe_req(
+ sdata, NULL,
+ local->scan_req->ssids[i].ssid,
+ local->scan_req->ssids[i].ssid_len,
+ local->scan_req->ie, local->scan_req->ie_len);
+
+ /*
+ * After sending probe requests, wait for probe responses
+ * on the channel.
+ */
+ *next_delay = IEEE80211_CHANNEL_TIME;
+ local->next_scan_state = SCAN_DECISION;
+}
+
void ieee80211_scan_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, scan_work.work);
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- struct ieee80211_channel *chan;
- int skip, i;
unsigned long next_delay = 0;
mutex_lock(&local->scan_mtx);
@@ -507,7 +666,7 @@ void ieee80211_scan_work(struct work_struct *work)
return;
}
- if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) {
+ if (local->scan_req && !local->scanning) {
struct cfg80211_scan_request *req = local->scan_req;
int rc;
@@ -531,69 +690,30 @@ void ieee80211_scan_work(struct work_struct *work)
return;
}
- switch (local->scan_state) {
- case SCAN_SET_CHANNEL:
- /* if no more bands/channels left, complete scan */
- if (local->scan_channel_idx >= local->scan_req->n_channels) {
- ieee80211_scan_completed(&local->hw, false);
- return;
- }
- skip = 0;
- chan = local->scan_req->channels[local->scan_channel_idx];
-
- if (chan->flags & IEEE80211_CHAN_DISABLED ||
- (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
- chan->flags & IEEE80211_CHAN_NO_IBSS))
- skip = 1;
-
- if (!skip) {
- local->scan_channel = chan;
- if (ieee80211_hw_config(local,
- IEEE80211_CONF_CHANGE_CHANNEL))
- skip = 1;
- }
-
- /* advance state machine to next channel/band */
- local->scan_channel_idx++;
-
- if (skip)
+ /*
+ * as long as no delay is required advance immediately
+ * without scheduling a new work
+ */
+ do {
+ switch (local->next_scan_state) {
+ case SCAN_DECISION:
+ if (ieee80211_scan_state_decision(local, &next_delay))
+ return;
break;
-
- /*
- * Probe delay is used to update the NAV, cf. 11.1.3.2.2
- * (which unfortunately doesn't say _why_ step a) is done,
- * but it waits for the probe delay or until a frame is
- * received - and the received frame would update the NAV).
- * For now, we do not support waiting until a frame is
- * received.
- *
- * In any case, it is not necessary for a passive scan.
- */
- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
- !local->scan_req->n_ssids) {
- next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ case SCAN_SET_CHANNEL:
+ ieee80211_scan_state_set_channel(local, &next_delay);
+ break;
+ case SCAN_SEND_PROBE:
+ ieee80211_scan_state_send_probe(local, &next_delay);
+ break;
+ case SCAN_LEAVE_OPER_CHANNEL:
+ ieee80211_scan_state_leave_oper_channel(local, &next_delay);
+ break;
+ case SCAN_ENTER_OPER_CHANNEL:
+ ieee80211_scan_state_enter_oper_channel(local, &next_delay);
break;
}
-
- next_delay = IEEE80211_PROBE_DELAY;
- local->scan_state = SCAN_SEND_PROBE;
- break;
- case SCAN_SEND_PROBE:
- for (i = 0; i < local->scan_req->n_ssids; i++)
- ieee80211_send_probe_req(
- sdata, NULL,
- local->scan_req->ssids[i].ssid,
- local->scan_req->ssids[i].ssid_len,
- local->scan_req->ie, local->scan_req->ie_len);
-
- /*
- * After sending probe requests, wait for probe responses
- * on the channel.
- */
- next_delay = IEEE80211_CHANNEL_TIME;
- local->scan_state = SCAN_SET_CHANNEL;
- break;
- }
+ } while (next_delay == 0);
queue_delayed_work(local->hw.workqueue, &local->scan_work,
next_delay);
@@ -643,7 +763,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* queued -- mostly at suspend under RTNL.
*/
mutex_lock(&local->scan_mtx);
- swscan = local->sw_scanning;
+ swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
mutex_unlock(&local->scan_mtx);
if (swscan)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 49a1a1f76511..ccc3adf962c7 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -30,7 +30,6 @@
* @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
* @WLAN_STA_WME: Station is a QoS-STA.
* @WLAN_STA_WDS: Station is one of our WDS peers.
- * @WLAN_STA_PSPOLL: Station has just PS-polled us.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
@@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags {
WLAN_STA_ASSOC_AP = 1<<5,
WLAN_STA_WME = 1<<6,
WLAN_STA_WDS = 1<<7,
- WLAN_STA_PSPOLL = 1<<8,
WLAN_STA_CLEAR_PS_FILT = 1<<9,
WLAN_STA_MFP = 1<<10,
WLAN_STA_SUSPEND = 1<<11
@@ -308,6 +306,23 @@ struct sta_info {
struct dentry *inactive_ms;
struct dentry *last_seq_ctrl;
struct dentry *agg_status;
+ struct dentry *aid;
+ struct dentry *dev;
+ struct dentry *rx_packets;
+ struct dentry *tx_packets;
+ struct dentry *rx_bytes;
+ struct dentry *tx_bytes;
+ struct dentry *rx_duplicates;
+ struct dentry *rx_fragments;
+ struct dentry *rx_dropped;
+ struct dentry *tx_fragments;
+ struct dentry *tx_filtered;
+ struct dentry *tx_retry_failed;
+ struct dentry *tx_retry_count;
+ struct dentry *last_signal;
+ struct dentry *last_qual;
+ struct dentry *last_noise;
+ struct dentry *wep_weak_iv_count;
bool add_has_run;
} debugfs;
#endif
@@ -342,17 +357,6 @@ static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
spin_unlock_irqrestore(&sta->flaglock, irqfl);
}
-static inline void set_and_clear_sta_flags(struct sta_info *sta,
- const u32 set, const u32 clear)
-{
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- sta->flags |= set;
- sta->flags &= ~clear;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
-}
-
static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
{
u32 ret;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d238a8939a09..4e1b2ba122cd 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE;
- if (unlikely(tx->local->sw_scanning) &&
+ if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) &&
!ieee80211_is_probe_req(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control))
/*
@@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
staflags = get_sta_flags(sta);
if (unlikely((staflags & WLAN_STA_PS) &&
- !(staflags & WLAN_STA_PSPOLL))) {
+ !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
"before %d)\n",
@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta_info_set_tim_bit(sta);
info->control.jiffies = jiffies;
+ info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED;
@@ -411,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr);
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
- /*
- * The sleeping station with pending data is now snoozing.
- * It queried us for its buffered frames and will go back
- * to deep sleep once it got everything.
- *
- * inform the driver, in case the hardware does powersave
- * frame filtering and keeps a station blacklist on its own
- * (e.g: p54), so that frames can be delivered unimpeded.
- *
- * Note: It should be safe to disable the filter now.
- * As, it is really unlikely that we still have any pending
- * frame for this station in the hw's buffers/fifos left,
- * that is not rejected with a unsuccessful tx_status yet.
- */
- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
- }
return TX_CONTINUE;
}
@@ -451,7 +435,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
- if (unlikely(tx->skb->do_not_encrypt))
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
@@ -497,7 +481,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- tx->skb->do_not_encrypt = 1;
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
return TX_CONTINUE;
}
@@ -512,6 +496,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
int i, len;
bool inval = false, rts = false, short_preamble = false;
struct ieee80211_tx_rate_control txrc;
+ u32 sta_flags;
memset(&txrc, 0, sizeof(txrc));
@@ -544,7 +529,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
(tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
txrc.short_preamble = short_preamble = true;
+ sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+ /*
+ * Lets not bother rate control if we're associated and cannot
+ * talk to the sta. This should not happen.
+ */
+ if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) &&
+ (sta_flags & WLAN_STA_ASSOC) &&
+ !rate_usable_index_exists(sband, &tx->sta->sta),
+ "%s: Dropped data frame as no usable bitrate found while "
+ "scanning and associated. Target station: "
+ "%pM on %d GHz band\n",
+ tx->dev->name, hdr->addr1,
+ tx->channel->band ? 5 : 2))
+ return TX_DROP;
+
+ /*
+ * If we're associated with the sta at this point we know we can at
+ * least send the frame at the lowest bit rate.
+ */
rate_control_get_rate(tx->sdata, tx->sta, &txrc);
if (unlikely(info->control.rates[0].idx < 0))
@@ -676,7 +680,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
* number, if we have no matching interface then we
* neither assign one ourselves nor ask the driver to.
*/
- if (unlikely(!info->control.vif))
+ if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
return TX_CONTINUE;
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
@@ -754,9 +758,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
skb_copy_queue_mapping(tmp, skb);
tmp->priority = skb->priority;
- tmp->do_not_encrypt = skb->do_not_encrypt;
tmp->dev = skb->dev;
- tmp->iif = skb->iif;
/* copy header and data */
memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
@@ -784,7 +786,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
/*
* Warn when submitting a fragmented A-MPDU frame and drop it.
- * This scenario is handled in __ieee80211_tx_prepare but extra
+ * This scenario is handled in ieee80211_tx_prepare but extra
* caution taken here as fragmented ampdu may cause Tx stop.
*/
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
@@ -923,11 +925,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
sband = tx->local->hw.wiphy->bands[tx->channel->band];
- skb->do_not_encrypt = 1;
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -965,7 +968,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
skb_trim(skb, skb->len - FCS_LEN);
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- tx->skb->do_not_encrypt = 0;
+ info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
@@ -998,13 +1001,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
* initialises @tx
*/
static ieee80211_tx_result
-__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
- struct sk_buff *skb,
- struct net_device *dev)
+ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_tx_data *tx,
+ struct sk_buff *skb)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
- struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen, tid;
u8 *qc, *state;
@@ -1012,9 +1014,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
- tx->dev = dev; /* use original interface */
+ tx->dev = sdata->dev; /* use original interface */
tx->local = local;
- tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ tx->sdata = sdata;
tx->channel = local->hw.conf.channel;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
@@ -1023,7 +1025,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
tx->flags |= IEEE80211_TX_FRAGMENTED;
/* process and remove the injection radiotap header */
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
if (!__ieee80211_parse_tx_radiotap(tx, skb))
return TX_DROP;
@@ -1075,6 +1076,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
} else if (*state != HT_AGG_STATE_IDLE) {
/* in progress */
queued = true;
+ info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
__skb_queue_tail(&tid_tx->pending, skb);
}
@@ -1119,50 +1121,29 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
return TX_CONTINUE;
}
-/*
- * NB: @tx is uninitialised when passed in here
- */
-static int ieee80211_tx_prepare(struct ieee80211_local *local,
- struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
-{
- struct net_device *dev;
-
- dev = dev_get_by_index(&init_net, skb->iif);
- if (unlikely(dev && !is_ieee80211_device(local, dev))) {
- dev_put(dev);
- dev = NULL;
- }
- if (unlikely(!dev))
- return -ENODEV;
- /*
- * initialises tx with control
- *
- * return value is safe to ignore here because this function
- * can only be invoked for multicast frames
- *
- * XXX: clean up
- */
- __ieee80211_tx_prepare(tx, skb, dev);
- dev_put(dev);
- return 0;
-}
-
static int __ieee80211_tx(struct ieee80211_local *local,
struct sk_buff **skbp,
- struct sta_info *sta)
+ struct sta_info *sta,
+ bool txpending)
{
struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info;
+ struct ieee80211_sub_if_data *sdata;
+ unsigned long flags;
int ret, len;
bool fragm = false;
- local->mdev->trans_start = jiffies;
-
while (skb) {
- if (ieee80211_queue_stopped(&local->hw,
- skb_get_queue_mapping(skb)))
- return IEEE80211_TX_PENDING;
+ int q = skb_get_queue_mapping(skb);
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ ret = IEEE80211_TX_OK;
+ if (local->queue_stop_reasons[q] ||
+ (!txpending && !skb_queue_empty(&local->pending[q])))
+ ret = IEEE80211_TX_PENDING;
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ if (ret != IEEE80211_TX_OK)
+ return ret;
info = IEEE80211_SKB_CB(skb);
@@ -1172,13 +1153,32 @@ static int __ieee80211_tx(struct ieee80211_local *local,
next = skb->next;
len = skb->len;
+
+ sdata = vif_to_sdata(info->control.vif);
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ info->control.vif = NULL;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ info->control.vif = &container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap)->vif;
+ break;
+ default:
+ /* keep */
+ break;
+ }
+
ret = drv_tx(local, skb);
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
dev_kfree_skb(skb);
ret = NETDEV_TX_OK;
}
- if (ret != NETDEV_TX_OK)
+ if (ret != NETDEV_TX_OK) {
+ info->control.vif = &sdata->vif;
return IEEE80211_TX_AGAIN;
+ }
+
*skbp = skb = next;
ieee80211_led_tx(local, 1);
fragm = true;
@@ -1234,10 +1234,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
return 0;
}
-static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
- bool txpending)
+static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, bool txpending)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1248,8 +1248,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
queue = skb_get_queue_mapping(skb);
- WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue]));
-
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
return;
@@ -1258,7 +1256,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
rcu_read_lock();
/* initialises tx */
- res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
+ res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
if (unlikely(res_prepare == TX_DROP)) {
dev_kfree_skb(skb);
@@ -1277,7 +1275,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
retries = 0;
retry:
- ret = __ieee80211_tx(local, &tx.skb, tx.sta);
+ ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
switch (ret) {
case IEEE80211_TX_OK:
break;
@@ -1295,34 +1293,35 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- if (__netif_subqueue_stopped(local->mdev, queue)) {
+ if (local->queue_stop_reasons[queue] ||
+ !skb_queue_empty(&local->pending[queue])) {
+ /*
+ * if queue is stopped, queue up frames for later
+ * transmission from the tasklet
+ */
do {
next = skb->next;
skb->next = NULL;
if (unlikely(txpending))
- skb_queue_head(&local->pending[queue],
- skb);
+ __skb_queue_head(&local->pending[queue],
+ skb);
else
- skb_queue_tail(&local->pending[queue],
- skb);
+ __skb_queue_tail(&local->pending[queue],
+ skb);
} while ((skb = next));
- /*
- * Make sure nobody will enable the queue on us
- * (without going through the tasklet) nor disable the
- * netdev queue underneath the pending handling code.
- */
- __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
- &local->queue_stop_reasons[queue]);
-
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
} else {
+ /*
+ * otherwise retry, but this is a race condition or
+ * a driver bug (which we warn about if it persists)
+ */
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
retries++;
- if (WARN(retries > 10, "tx refused but queue active"))
+ if (WARN(retries > 10, "tx refused but queue active\n"))
goto drop;
goto retry;
}
@@ -1383,40 +1382,21 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
return 0;
}
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct net_device *odev = NULL;
- struct ieee80211_sub_if_data *osdata;
+ struct ieee80211_sub_if_data *tmp_sdata;
int headroom;
bool may_encrypt;
- enum {
- NOT_MONITOR,
- FOUND_SDATA,
- UNKNOWN_ADDRESS,
- } monitor_iface = NOT_MONITOR;
-
- if (skb->iif)
- odev = dev_get_by_index(&init_net, skb->iif);
- if (unlikely(odev && !is_ieee80211_device(local, odev))) {
- dev_put(odev);
- odev = NULL;
- }
- if (unlikely(!odev)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
- "originating device\n", dev->name);
-#endif
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
+
+ dev_hold(sdata->dev);
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0 &&
- !local->sw_scanning && !local->hw_scanning && local->ps_sdata) {
+ !(local->scanning) && local->ps_sdata) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
@@ -1428,34 +1408,25 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
- memset(info, 0, sizeof(*info));
-
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
- osdata = IEEE80211_DEV_TO_SUB_IF(odev);
-
- if (ieee80211_vif_is_mesh(&osdata->vif) &&
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
ieee80211_is_data(hdr->frame_control)) {
if (is_multicast_ether_addr(hdr->addr3))
memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
else
- if (mesh_nexthop_lookup(skb, osdata)) {
- dev_put(odev);
- return NETDEV_TX_OK;
+ if (mesh_nexthop_lookup(skb, sdata)) {
+ dev_put(sdata->dev);
+ return;
}
- if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
- IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
- fwded_frames);
- } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
- struct ieee80211_sub_if_data *sdata;
+ } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
int hdrlen;
u16 len_rthdr;
info->flags |= IEEE80211_TX_CTL_INJECTED;
- monitor_iface = UNKNOWN_ADDRESS;
len_rthdr = ieee80211_get_radiotap_len(skb->data);
- hdr = (struct ieee80211_hdr *)skb->data + len_rthdr;
+ hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
hdrlen = ieee80211_hdrlen(hdr->frame_control);
/* check the header is complete in the frame */
@@ -1471,20 +1442,17 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces,
+ list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
list) {
- if (!netif_running(sdata->dev))
+ if (!netif_running(tmp_sdata->dev))
continue;
- if (sdata->vif.type != NL80211_IFTYPE_AP)
+ if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
continue;
- if (compare_ether_addr(sdata->dev->dev_addr,
+ if (compare_ether_addr(tmp_sdata->dev->dev_addr,
hdr->addr2)) {
- dev_hold(sdata->dev);
- dev_put(odev);
- osdata = sdata;
- odev = osdata->dev;
- skb->iif = sdata->dev->ifindex;
- monitor_iface = FOUND_SDATA;
+ dev_hold(tmp_sdata->dev);
+ dev_put(sdata->dev);
+ sdata = tmp_sdata;
break;
}
}
@@ -1492,31 +1460,25 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- may_encrypt = !skb->do_not_encrypt;
+ may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
- headroom = osdata->local->tx_headroom;
+ headroom = local->tx_headroom;
if (may_encrypt)
headroom += IEEE80211_ENCRYPT_HEADROOM;
headroom -= skb_headroom(skb);
headroom = max_t(int, 0, headroom);
- if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+ if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
dev_kfree_skb(skb);
- dev_put(odev);
- return NETDEV_TX_OK;
+ dev_put(sdata->dev);
+ return;
}
- if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- osdata = container_of(osdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
- if (likely(monitor_iface != UNKNOWN_ADDRESS))
- info->control.vif = &osdata->vif;
+ info->control.vif = &sdata->vif;
- ieee80211_tx(odev, skb, false);
- dev_put(odev);
-
- return NETDEV_TX_OK;
+ ieee80211_select_queue(local, skb);
+ ieee80211_tx(sdata, skb, false);
+ dev_put(sdata->dev);
}
int ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1526,6 +1488,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct ieee80211_channel *chan = local->hw.conf.channel;
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 len_rthdr;
/*
@@ -1563,15 +1526,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (unlikely(skb->len < len_rthdr))
goto fail; /* skb too short for claimed rt header extent */
- skb->dev = local->mdev;
-
- /* needed because we set skb device to master */
- skb->iif = dev->ifindex;
-
- /* sometimes we do encrypt injected frames, will be fixed
- * up in radiotap parser if not wanted */
- skb->do_not_encrypt = 0;
-
/*
* fix up the pointers accounting for the radiotap
* header still being in there. We are being given
@@ -1586,8 +1540,10 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
skb_set_network_header(skb, len_rthdr);
skb_set_transport_header(skb, len_rthdr);
- /* pass the radiotap header up to the next stage intact */
- dev_queue_xmit(skb);
+ memset(info, 0, sizeof(*info));
+
+ /* pass the radiotap header up to xmit */
+ ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
return NETDEV_TX_OK;
fail:
@@ -1615,6 +1571,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = NETDEV_TX_BUSY, head_need;
u16 ethertype, hdrlen, meshhdrlen = 0;
__le16 fc;
@@ -1627,7 +1584,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
u32 sta_flags = 0;
if (unlikely(skb->len < ETH_HLEN)) {
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -1664,7 +1621,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
/* Do not send frames with mesh_ttl == 0 */
sdata->u.mesh.mshstats.dropped_frames_ttl++;
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
memset(&mesh_hdr, 0, sizeof(mesh_hdr));
@@ -1724,7 +1681,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
hdrlen = 24;
break;
default:
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -1766,7 +1723,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -1842,9 +1799,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos += hdrlen;
h_pos += hdrlen;
- skb->iif = dev->ifindex;
-
- skb->dev = local->mdev;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -1855,13 +1809,15 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
skb_set_network_header(skb, nh_pos);
skb_set_transport_header(skb, h_pos);
+ memset(info, 0, sizeof(*info));
+
dev->trans_start = jiffies;
- dev_queue_xmit(skb);
+ ieee80211_xmit(sdata, skb);
- return 0;
+ return NETDEV_TX_OK;
fail:
- if (!ret)
+ if (ret == NETDEV_TX_OK)
dev_kfree_skb(skb);
return ret;
@@ -1887,101 +1843,74 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct ieee80211_hdr *hdr;
- struct net_device *dev;
int ret;
bool result = true;
- /* does interface still exist? */
- dev = dev_get_by_index(&init_net, skb->iif);
- if (!dev) {
- dev_kfree_skb(skb);
- return true;
- }
-
- /* validate info->control.vif against skb->iif */
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
-
- if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) {
- dev_kfree_skb(skb);
- result = true;
- goto out;
- }
+ sdata = vif_to_sdata(info->control.vif);
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
- ieee80211_tx(dev, skb, true);
+ ieee80211_tx(sdata, skb, true);
} else {
hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(local, hdr->addr1);
- ret = __ieee80211_tx(local, &skb, sta);
+ ret = __ieee80211_tx(local, &skb, sta, true);
if (ret != IEEE80211_TX_OK)
result = false;
}
- out:
- dev_put(dev);
-
return result;
}
/*
- * Transmit all pending packets. Called from tasklet, locks master device
- * TX lock so that no new packets can come in.
+ * Transmit all pending packets. Called from tasklet.
*/
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
- struct net_device *dev = local->mdev;
unsigned long flags;
int i;
- bool next;
+ bool txok;
rcu_read_lock();
- netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < local->hw.queues; i++) {
/*
* If queue is stopped by something other than due to pending
* frames, or we have no pending frames, proceed to next queue.
*/
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- next = false;
- if (local->queue_stop_reasons[i] !=
- BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) ||
+ if (local->queue_stop_reasons[i] ||
skb_queue_empty(&local->pending[i]))
- next = true;
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- if (next)
continue;
- /*
- * start the queue now to allow processing our packets,
- * we're under the tx lock here anyway so nothing will
- * happen as a result of this
- */
- netif_start_subqueue(local->mdev, i);
-
while (!skb_queue_empty(&local->pending[i])) {
- struct sk_buff *skb = skb_dequeue(&local->pending[i]);
+ struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sub_if_data *sdata;
- if (!ieee80211_tx_pending_skb(local, skb)) {
- skb_queue_head(&local->pending[i], skb);
- break;
+ if (WARN_ON(!info->control.vif)) {
+ kfree_skb(skb);
+ continue;
}
- }
- /* Start regular packet processing again. */
- if (skb_queue_empty(&local->pending[i]))
- ieee80211_wake_queue_by_reason(&local->hw, i,
- IEEE80211_QUEUE_STOP_REASON_PENDING);
+ sdata = vif_to_sdata(info->control.vif);
+ dev_hold(sdata->dev);
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+ flags);
+
+ txok = ieee80211_tx_pending_skb(local, skb);
+ dev_put(sdata->dev);
+ if (!txok)
+ __skb_queue_head(&local->pending[i], skb);
+ spin_lock_irqsave(&local->queue_stop_reason_lock,
+ flags);
+ if (!txok)
+ break;
+ }
}
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- netif_tx_unlock_bh(dev);
rcu_read_unlock();
}
@@ -2156,8 +2085,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
- skb->do_not_encrypt = 1;
-
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
info->band = band;
/*
* XXX: For now, always use the lowest rate
@@ -2228,9 +2156,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
sdata = vif_to_sdata(vif);
bss = &sdata->u.ap;
- if (!bss)
- return NULL;
-
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
@@ -2256,7 +2181,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
- if (!ieee80211_tx_prepare(local, &tx, skb))
+ if (!ieee80211_tx_prepare(sdata, &tx, skb))
break;
dev_kfree_skb_any(skb);
}
@@ -2276,3 +2201,24 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
return skb;
}
EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+ int encrypt)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ skb_set_mac_header(skb, 0);
+ skb_set_network_header(skb, 0);
+ skb_set_transport_header(skb, 0);
+
+ if (!encrypt)
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ /*
+ * The other path calling ieee80211_xmit is from the tasklet,
+ * and while we can handle concurrent transmissions locking
+ * requirements are that we do not come into tx with bhs on.
+ */
+ local_bh_disable();
+ ieee80211_xmit(sdata, skb);
+ local_bh_enable();
+}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 915e77769312..8502936e5314 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -31,6 +31,7 @@
#include "mesh.h"
#include "wme.h"
#include "led.h"
+#include "wep.h"
/* privid for wiphys to determine whether they belong to us or not */
void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -274,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
__clear_bit(reason, &local->queue_stop_reasons[queue]);
- if (!skb_queue_empty(&local->pending[queue]) &&
- local->queue_stop_reasons[queue] ==
- BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
- tasklet_schedule(&local->tx_pending_tasklet);
-
if (local->queue_stop_reasons[queue] != 0)
/* someone still has this queue stopped */
return;
- netif_wake_subqueue(local->mdev, queue);
+ if (!skb_queue_empty(&local->pending[queue]))
+ tasklet_schedule(&local->tx_pending_tasklet);
}
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -312,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (WARN_ON(queue >= hw->queues))
return;
- /*
- * Only stop if it was previously running, this is necessary
- * for correct pending packets handling because there we may
- * start (but not wake) the queue and rely on that.
- */
- if (!local->queue_stop_reasons[queue])
- netif_stop_subqueue(local->mdev, queue);
-
__set_bit(reason, &local->queue_stop_reasons[queue]);
}
@@ -347,11 +336,16 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct ieee80211_hw *hw = &local->hw;
unsigned long flags;
int queue = skb_get_queue_mapping(skb);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if (WARN_ON(!info->control.vif)) {
+ kfree(skb);
+ return;
+ }
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
- __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
- skb_queue_tail(&local->pending[queue], skb);
+ __skb_queue_tail(&local->pending[queue], skb);
__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
@@ -370,18 +364,21 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
while ((skb = skb_dequeue(skbs))) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if (WARN_ON(!info->control.vif)) {
+ kfree(skb);
+ continue;
+ }
+
ret++;
queue = skb_get_queue_mapping(skb);
- skb_queue_tail(&local->pending[queue], skb);
+ __skb_queue_tail(&local->pending[queue], skb);
}
- for (i = 0; i < hw->queues; i++) {
- if (ret)
- __ieee80211_stop_queue(hw, i,
- IEEE80211_QUEUE_STOP_REASON_PENDING);
+ for (i = 0; i < hw->queues; i++)
__ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
- }
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return ret;
@@ -412,11 +409,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
+ unsigned long flags;
+ int ret;
if (WARN_ON(queue >= hw->queues))
return true;
- return __netif_subqueue_stopped(local->mdev, queue);
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ ret = !!local->queue_stop_reasons[queue];
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(ieee80211_queue_stopped);
@@ -760,20 +762,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
ieee80211_set_wmm_default(sdata);
}
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- int encrypt)
-{
- skb->dev = sdata->local->mdev;
- skb_set_mac_header(skb, 0);
- skb_set_network_header(skb, 0);
- skb_set_transport_header(skb, 0);
-
- skb->iif = sdata->dev->ifindex;
- skb->do_not_encrypt = !encrypt;
-
- dev_queue_xmit(skb);
-}
-
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band)
{
@@ -804,12 +792,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
- u8 *extra, size_t extra_len,
- const u8 *bssid, int encrypt)
+ u8 *extra, size_t extra_len, const u8 *bssid,
+ const u8 *key, u8 key_len, u8 key_idx)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
+ int err;
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + 6 + extra_len);
@@ -824,8 +813,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
memset(mgmt, 0, 24 + 6);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_AUTH);
- if (encrypt)
- mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
memcpy(mgmt->da, bssid, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -835,7 +822,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
if (extra)
memcpy(skb_put(skb, extra_len), extra, extra_len);
- ieee80211_tx_skb(sdata, skb, encrypt);
+ if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+ WARN_ON(err);
+ }
+
+ ieee80211_tx_skb(sdata, skb, 0);
}
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
@@ -1043,9 +1036,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
- netif_addr_lock_bh(local->mdev);
+ spin_lock_bh(&local->filter_lock);
ieee80211_configure_filter(local);
- netif_addr_unlock_bh(local->mdev);
+ spin_unlock_bh(&local->filter_lock);
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index ef73105b3061..8a980f136941 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -67,10 +67,10 @@ static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
static void ieee80211_wep_get_iv(struct ieee80211_local *local,
- struct ieee80211_key *key, u8 *iv)
+ int keylen, int keyidx, u8 *iv)
{
local->wep_iv++;
- if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen))
+ if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
local->wep_iv += 0x0100;
if (!iv)
@@ -79,13 +79,13 @@ static void ieee80211_wep_get_iv(struct ieee80211_local *local,
*iv++ = (local->wep_iv >> 16) & 0xff;
*iv++ = (local->wep_iv >> 8) & 0xff;
*iv++ = local->wep_iv & 0xff;
- *iv++ = key->conf.keyidx << 6;
+ *iv++ = keyidx << 6;
}
static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
struct sk_buff *skb,
- struct ieee80211_key *key)
+ int keylen, int keyidx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
unsigned int hdrlen;
@@ -100,7 +100,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
hdrlen = ieee80211_hdrlen(hdr->frame_control);
newhdr = skb_push(skb, WEP_IV_LEN);
memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
- ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
+ ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
return newhdr + hdrlen;
}
@@ -144,26 +144,17 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
-int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
- struct ieee80211_key *key)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ const u8 *key, int keylen, int keyidx)
{
- u32 klen;
- u8 *rc4key, *iv;
+ u8 *iv;
size_t len;
+ u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
- if (!key || key->conf.alg != ALG_WEP)
- return -1;
-
- klen = 3 + key->conf.keylen;
- rc4key = kmalloc(klen, GFP_ATOMIC);
- if (!rc4key)
- return -1;
-
- iv = ieee80211_wep_add_iv(local, skb, key);
- if (!iv) {
- kfree(rc4key);
+ iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
+ if (!iv)
return -1;
- }
len = skb->len - (iv + WEP_IV_LEN - skb->data);
@@ -171,16 +162,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
memcpy(rc4key, iv, 3);
/* Copy rest of the WEP key (the secret part) */
- memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
+ memcpy(rc4key + 3, key, keylen);
/* Add room for ICV */
skb_put(skb, WEP_ICV_LEN);
- ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen,
+ ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
iv + WEP_IV_LEN, len);
- kfree(rc4key);
-
return 0;
}
@@ -216,8 +205,9 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
* failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
* is moved to the beginning of the skb and skb length will be reduced.
*/
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
- struct ieee80211_key *key)
+static int ieee80211_wep_decrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key)
{
u32 klen;
u8 *rc4key;
@@ -314,12 +304,16 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
- if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+ if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
+ tx->key->conf.keylen,
+ tx->key->conf.keyidx))
return -1;
} else {
info->control.hw_key = &tx->key->conf;
if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
- if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
+ if (!ieee80211_wep_add_iv(tx->local, skb,
+ tx->key->conf.keylen,
+ tx->key->conf.keyidx))
return -1;
}
}
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index d3f0db48314e..fe29d7e5759f 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -20,12 +20,11 @@ int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_free(struct ieee80211_local *local);
void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ const u8 *key, int keylen, int keyidx);
int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
-int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
- struct ieee80211_key *key);
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
- struct ieee80211_key *key);
bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
ieee80211_rx_result
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
deleted file mode 100644
index 1da81f456744..000000000000
--- a/net/mac80211/wext.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <asm/uaccess.h>
-
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-#include "led.h"
-#include "rate.h"
-#include "wpa.h"
-#include "aes_ccm.h"
-
-
-static int ieee80211_ioctl_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
- if (ret && ret != -EALREADY)
- return ret;
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
- sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
- sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
- if (ret != -EALREADY)
- ieee80211_sta_req_auth(sdata);
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int ieee80211_ioctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_channel *chan;
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
- else if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
-
- /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
- if (freq->e == 0) {
- if (freq->m < 0) {
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sdata->u.mgd.flags |=
- IEEE80211_STA_AUTO_CHANNEL_SEL;
- return 0;
- } else
- chan = ieee80211_get_channel(local->hw.wiphy,
- ieee80211_channel_to_frequency(freq->m));
- } else {
- int i, div = 1000000;
- for (i = 0; i < freq->e; i++)
- div /= 10;
- if (div <= 0)
- return -EINVAL;
- chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div);
- }
-
- if (!chan)
- return -EINVAL;
-
- if (chan->flags & IEEE80211_CHAN_DISABLED)
- return -EINVAL;
-
- /*
- * no change except maybe auto -> fixed, ignore the HT
- * setting so you can fix a channel you're on already
- */
- if (local->oper_channel == chan)
- return 0;
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- ieee80211_sta_req_auth(sdata);
-
- local->oper_channel = chan;
- local->oper_channel_type = NL80211_CHAN_NO_HT;
- ieee80211_hw_config(local, 0);
-
- return 0;
-}
-
-
-static int ieee80211_ioctl_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->m = local->oper_channel->center_freq;
- freq->e = 6;
-
- return 0;
-}
-
-
-static int ieee80211_ioctl_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- size_t len = data->length;
- int ret;
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- /* iwconfig uses nul termination in SSID.. */
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (data->flags)
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
- else
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-
- ret = ieee80211_sta_set_ssid(sdata, ssid, len);
- if (ret)
- return ret;
-
- sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
- sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
- ieee80211_sta_req_auth(sdata);
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
-{
- size_t len;
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
- if (res == 0) {
- data->length = len;
- data->flags = 1;
- } else
- data->flags = 0;
- return res;
- }
-
- return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- int ret;
-
- if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL;
- else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
- sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
- else
- sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
- ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
- if (ret)
- return ret;
- sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
- sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
- ieee80211_sta_req_auth(sdata);
- return 0;
- } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
- /*
- * If it is necessary to update the WDS peer address
- * while the interface is running, then we need to do
- * more work here, namely if it is running we need to
- * add a new and remove the old STA entry, this is
- * normally handled by _open() and _stop().
- */
- if (netif_running(dev))
- return -EBUSY;
-
- memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
- ETH_ALEN);
-
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- return 0;
- } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int i, err = -EINVAL;
- u32 target_rate = rate->value / 100000;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_supported_band *sband;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
- * target_rate = X, rate->fixed = 1 means only rate X
- * target_rate = X, rate->fixed = 0 means all rates <= X */
- sdata->max_ratectrl_rateidx = -1;
- sdata->force_unicast_rateidx = -1;
- if (rate->value < 0)
- return 0;
-
- for (i=0; i< sband->n_bitrates; i++) {
- struct ieee80211_rate *brate = &sband->bitrates[i];
- int this_rate = brate->bitrate;
-
- if (target_rate == this_rate) {
- sdata->max_ratectrl_rateidx = i;
- if (rate->fixed)
- sdata->force_unicast_rateidx = i;
- err = 0;
- break;
- }
- }
- return err;
-}
-
-static int ieee80211_ioctl_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct sta_info *sta;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_supported_band *sband;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return -EOPNOTSUPP;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
- rcu_read_lock();
-
- sta = sta_info_get(local, sdata->u.mgd.bssid);
-
- if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
- rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
- else
- rate->value = 0;
-
- rcu_read_unlock();
-
- if (!sta)
- return -ENODEV;
-
- rate->value *= 100000;
-
- return 0;
-}
-
-static int ieee80211_ioctl_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_conf *conf = &local->hw.conf;
- int timeout = 0;
- bool ps;
-
- if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
- return -EOPNOTSUPP;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return -EINVAL;
-
- if (wrq->disabled) {
- ps = false;
- timeout = 0;
- goto set;
- }
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitely state all */
- ps = true;
- break;
- default: /* Otherwise we ignore */
- return -EINVAL;
- }
-
- if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
- return -EINVAL;
-
- if (wrq->flags & IW_POWER_TIMEOUT)
- timeout = wrq->value / 1000;
-
- set:
- if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
- return 0;
-
- sdata->u.mgd.powersave = ps;
- conf->dynamic_ps_timeout = timeout;
-
- if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-
- ieee80211_recalc_ps(local, -1);
-
- return 0;
-}
-
-static int ieee80211_ioctl_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- wrqu->power.disabled = !sdata->u.mgd.powersave;
-
- return 0;
-}
-
-static int ieee80211_ioctl_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- int ret = 0;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_WPA_ENABLED:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_KEY_MGMT:
- case IW_AUTH_CIPHER_GROUP_MGMT:
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (data->value & (IW_AUTH_CIPHER_WEP40 |
- IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
- sdata->u.mgd.flags |=
- IEEE80211_STA_TKIP_WEP_USED;
- else
- sdata->u.mgd.flags &=
- ~IEEE80211_STA_TKIP_WEP_USED;
- }
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- sdata->drop_unencrypted = !!data->value;
- break;
- case IW_AUTH_PRIVACY_INVOKED:
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- ret = -EINVAL;
- else {
- sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
- /*
- * Privacy invoked by wpa_supplicant, store the
- * value and allow associating to a protected
- * network without having a key up front.
- */
- if (data->value)
- sdata->u.mgd.flags |=
- IEEE80211_STA_PRIVACY_INVOKED;
- }
- break;
- case IW_AUTH_80211_AUTH_ALG:
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sdata->u.mgd.auth_algs = data->value;
- else
- ret = -EOPNOTSUPP;
- break;
- case IW_AUTH_MFP:
- if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
- ret = -EOPNOTSUPP;
- break;
- }
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- switch (data->value) {
- case IW_AUTH_MFP_DISABLED:
- sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
- break;
- case IW_AUTH_MFP_OPTIONAL:
- sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
- break;
- case IW_AUTH_MFP_REQUIRED:
- sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
- break;
- default:
- ret = -EINVAL;
- }
- } else
- ret = -EOPNOTSUPP;
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
- return ret;
-}
-
-/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
-static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct iw_statistics *wstats = &local->wstats;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sta_info *sta = NULL;
-
- rcu_read_lock();
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sta = sta_info_get(local, sdata->u.mgd.bssid);
-
- if (!sta) {
- wstats->discard.fragment = 0;
- wstats->discard.misc = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- } else {
- wstats->qual.updated = 0;
- /*
- * mirror what cfg80211 does for iwrange/scan results,
- * otherwise userspace gets confused.
- */
- if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
- IEEE80211_HW_SIGNAL_DBM)) {
- wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED;
- wstats->qual.updated |= IW_QUAL_QUAL_UPDATED;
- } else {
- wstats->qual.updated |= IW_QUAL_LEVEL_INVALID;
- wstats->qual.updated |= IW_QUAL_QUAL_INVALID;
- }
-
- if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
- wstats->qual.level = sta->last_signal;
- wstats->qual.qual = sta->last_signal;
- } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
- int sig = sta->last_signal;
-
- wstats->qual.updated |= IW_QUAL_DBM;
- wstats->qual.level = sig;
- if (sig < -110)
- sig = -110;
- else if (sig > -40)
- sig = -40;
- wstats->qual.qual = sig + 110;
- }
-
- if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
- /*
- * This assumes that if driver reports noise, it also
- * reports signal in dBm.
- */
- wstats->qual.noise = sta->last_noise;
- wstats->qual.updated |= IW_QUAL_NOISE_UPDATED;
- } else {
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
- }
- }
-
- rcu_read_unlock();
-
- return wstats;
-}
-
-static int ieee80211_ioctl_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- int ret = 0;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_80211_AUTH_ALG:
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- data->value = sdata->u.mgd.auth_algs;
- else
- ret = -EOPNOTSUPP;
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
- return ret;
-}
-
-
-/* Structures to export the Wireless Handlers */
-
-static const iw_handler ieee80211_handler[] =
-{
- (iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
- (iw_handler) NULL, /* SIOCSIWNWID */
- (iw_handler) NULL, /* SIOCGIWNWID */
- (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
- (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
- (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
- (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
- (iw_handler) NULL, /* SIOCSIWSENS */
- (iw_handler) NULL, /* SIOCGIWSENS */
- (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
- (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
- (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
- (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
- (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
- (iw_handler) NULL, /* SIOCSIWSPY */
- (iw_handler) NULL, /* SIOCGIWSPY */
- (iw_handler) NULL, /* SIOCSIWTHRSPY */
- (iw_handler) NULL, /* SIOCGIWTHRSPY */
- (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
- (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
- (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */
- (iw_handler) NULL, /* SIOCGIWAPLIST */
- (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
- (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
- (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
- (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
- (iw_handler) NULL, /* SIOCSIWNICKN */
- (iw_handler) NULL, /* SIOCGIWNICKN */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
- (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
- (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
- (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
- (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
- (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
- (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
- (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
- (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
- (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
- (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
- (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
- (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
- (iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
- (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
- (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
- (iw_handler) NULL, /* SIOCGIWENCODEEXT */
- (iw_handler) NULL, /* SIOCSIWPMKSA */
- (iw_handler) NULL, /* -- hole -- */
-};
-
-const struct iw_handler_def ieee80211_iw_handler_def =
-{
- .num_standard = ARRAY_SIZE(ieee80211_handler),
- .standard = (iw_handler *) ieee80211_handler,
- .get_wireless_stats = ieee80211_get_wireless_stats,
-};
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 116a923b14d6..b19b7696f3a2 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -85,10 +85,8 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
return ieee802_1d_to_ac[skb->priority];
}
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
+void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
{
- struct ieee80211_master_priv *mpriv = netdev_priv(dev);
- struct ieee80211_local *local = mpriv->local;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 queue;
u8 tid;
@@ -113,5 +111,5 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
*p = 0;
}
- return queue;
+ skb_set_queue_mapping(skb, queue);
}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 7520d2e014dc..d4fd87ca5118 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -20,6 +20,7 @@
extern const int ieee802_1d_to_ac[8];
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb);
+void ieee80211_select_queue(struct ieee80211_local *local,
+ struct sk_buff *skb);
#endif /* _WME_H */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index dcfae8884b86..70778694877b 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -122,7 +122,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
- (void *) skb->data, NULL);
+ (void *) skb->data, NULL,
+ GFP_ATOMIC);
return RX_DROP_UNUSABLE;
}
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index 201b8ea3020d..c1781f80daf2 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -18,6 +18,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 77bfdfeb966e..4173d7b1d4cc 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -22,6 +22,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/net.h>
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 8dddb17a947a..6811dcaca0f6 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -24,6 +24,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ip.h>
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 7c1333c67ff3..e6133ea1ea4c 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -18,6 +18,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -3231,7 +3234,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
}
genlmsg_end(msg, reply);
- ret = genlmsg_unicast(msg, info->snd_pid);
+ ret = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index a9dac74bb13f..d0c0594d1e2e 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -35,6 +35,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 2eb2860dabb5..702b53ca937c 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -11,6 +11,10 @@
* Changes:
*
*/
+
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 428edbf481cc..9c16a3f64c1b 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -22,6 +22,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 3eb5e2660c49..98fb185d890b 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -39,6 +39,9 @@
* me to write this module.
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index c04ce56c7f0f..5f5e5f4bad5e 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -37,6 +37,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
index d0dadc8a65fd..4ecd5e19c39a 100644
--- a/net/netfilter/ipvs/ip_vs_lc.c
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -14,6 +14,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c
index 694952db5026..2224478bdea8 100644
--- a/net/netfilter/ipvs/ip_vs_nq.c
+++ b/net/netfilter/ipvs/ip_vs_nq.c
@@ -31,6 +31,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index a01520e3d6b8..a95bc4021c90 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -13,6 +13,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -181,7 +184,7 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
&ih->daddr, ntohs(pptr[1]));
}
- printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+ pr_debug("%s: %s\n", msg, buf);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -215,7 +218,7 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
&ih->daddr, ntohs(pptr[1]));
}
- printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+ pr_debug("%s: %s\n", msg, buf);
}
#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
index 79f56c1e7c19..c30b43c36cd7 100644
--- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
@@ -10,6 +10,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/module.h>
@@ -138,7 +141,7 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
sprintf(buf, "%s %pI4->%pI4",
pp->name, &ih->saddr, &ih->daddr);
- printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+ pr_debug("%s: %s\n", msg, buf);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -156,7 +159,7 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
sprintf(buf, "%s %pI6->%pI6",
pp->name, &ih->saddr, &ih->daddr);
- printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
+ pr_debug("%s: %s\n", msg, buf);
}
#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 8cba41802850..c36c80d3a2b4 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -13,6 +13,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/kernel.h>
#include <linux/ip.h>
#include <linux/tcp.h> /* for tcphdr */
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index d2930a71084b..96ebe40bc537 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -13,6 +13,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c
index 2d16ab7f8c1e..b01007e1c11e 100644
--- a/net/netfilter/ipvs/ip_vs_rr.c
+++ b/net/netfilter/ipvs/ip_vs_rr.c
@@ -19,6 +19,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c
index a46ad9e35016..87bc5ea0ef29 100644
--- a/net/netfilter/ipvs/ip_vs_sched.c
+++ b/net/netfilter/ipvs/ip_vs_sched.c
@@ -17,6 +17,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c
index 20e4657d2f3b..4f745dd86dd8 100644
--- a/net/netfilter/ipvs/ip_vs_sed.c
+++ b/net/netfilter/ipvs/ip_vs_sed.c
@@ -35,6 +35,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index 75709ebeb630..fb4d2d23f2fe 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -32,6 +32,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 5c48378a852f..cc04c99815fd 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -17,6 +17,9 @@
* Justin Ossevoort : Fix endian problem on sync message size.
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/inetdevice.h>
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c
index 8e942565b47d..bbddfdb10db2 100644
--- a/net/netfilter/ipvs/ip_vs_wlc.c
+++ b/net/netfilter/ipvs/ip_vs_wlc.c
@@ -19,6 +19,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c
index f7d74ef1ecf9..c39ebb6c5a54 100644
--- a/net/netfilter/ipvs/ip_vs_wrr.c
+++ b/net/netfilter/ipvs/ip_vs_wrr.c
@@ -18,6 +18,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/net.h>
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 5874657af7f2..061e76dfdad9 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -13,6 +13,9 @@
*
*/
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#include <linux/kernel.h>
#include <linux/tcp.h> /* for tcphdr */
#include <net/ip.h>
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index b0e582f2d37a..6ce00205f342 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -151,7 +151,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
addr6 = addr;
mask6 = mask;
map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
- if (map4 == NULL)
+ if (map6 == NULL)
goto cfg_unlbl_map_add_failure;
map6->type = NETLBL_NLTYPE_UNLABELED;
ipv6_addr_copy(&map6->list.addr, addr6);
@@ -185,8 +185,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
return 0;
cfg_unlbl_map_add_failure:
- if (entry != NULL)
- kfree(entry->domain);
+ kfree(entry->domain);
kfree(entry);
kfree(addrmap);
kfree(map4);
@@ -385,8 +384,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
cfg_cipsov4_map_add_failure:
cipso_v4_doi_putdef(doi_def);
- if (entry != NULL)
- kfree(entry->domain);
+ kfree(entry->domain);
kfree(entry);
kfree(addrmap);
kfree(addrinfo);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 2936fa3b6dc8..da3163d15ef0 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -83,6 +83,11 @@ struct netlink_sock {
struct module *module;
};
+struct listeners_rcu_head {
+ struct rcu_head rcu_head;
+ void *ptr;
+};
+
#define NETLINK_KERNEL_SOCKET 0x1
#define NETLINK_RECV_PKTINFO 0x2
#define NETLINK_BROADCAST_SEND_ERROR 0x4
@@ -1356,7 +1361,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
struct netlink_sock *nlk = nlk_sk(sk);
int noblock = flags&MSG_DONTWAIT;
size_t copied;
- struct sk_buff *skb;
+ struct sk_buff *skb, *frag __maybe_unused = NULL;
int err;
if (flags&MSG_OOB)
@@ -1368,6 +1373,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
if (skb == NULL)
goto out;
+#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
+ if (unlikely(skb_shinfo(skb)->frag_list)) {
+ bool need_compat = !!(flags & MSG_CMSG_COMPAT);
+
+ /*
+ * If this skb has a frag_list, then here that means that
+ * we will have to use the frag_list skb for compat tasks
+ * and the regular skb for non-compat tasks.
+ *
+ * The skb might (and likely will) be cloned, so we can't
+ * just reset frag_list and go on with things -- we need to
+ * keep that. For the compat case that's easy -- simply get
+ * a reference to the compat skb and free the regular one
+ * including the frag. For the non-compat case, we need to
+ * avoid sending the frag to the user -- so assign NULL but
+ * restore it below before freeing the skb.
+ */
+ if (need_compat) {
+ struct sk_buff *compskb = skb_shinfo(skb)->frag_list;
+ skb_get(compskb);
+ kfree_skb(skb);
+ skb = compskb;
+ } else {
+ frag = skb_shinfo(skb)->frag_list;
+ skb_shinfo(skb)->frag_list = NULL;
+ }
+ }
+#endif
+
msg->msg_namelen = 0;
copied = skb->len;
@@ -1398,6 +1432,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
siocb->scm->creds = *NETLINK_CREDS(skb);
if (flags & MSG_TRUNC)
copied = skb->len;
+
+#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
+ skb_shinfo(skb)->frag_list = frag;
+#endif
+
skb_free_datagram(sk, skb);
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
@@ -1453,7 +1492,8 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
if (groups < 32)
groups = 32;
- listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
+ listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
+ GFP_KERNEL);
if (!listeners)
goto out_sock_release;
@@ -1501,6 +1541,14 @@ netlink_kernel_release(struct sock *sk)
EXPORT_SYMBOL(netlink_kernel_release);
+static void netlink_free_old_listeners(struct rcu_head *rcu_head)
+{
+ struct listeners_rcu_head *lrh;
+
+ lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head);
+ kfree(lrh->ptr);
+}
+
/**
* netlink_change_ngroups - change number of multicast groups
*
@@ -1516,6 +1564,7 @@ EXPORT_SYMBOL(netlink_kernel_release);
int netlink_change_ngroups(struct sock *sk, unsigned int groups)
{
unsigned long *listeners, *old = NULL;
+ struct listeners_rcu_head *old_rcu_head;
struct netlink_table *tbl = &nl_table[sk->sk_protocol];
int err = 0;
@@ -1524,7 +1573,9 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups)
netlink_table_grab();
if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
- listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+ listeners = kzalloc(NLGRPSZ(groups) +
+ sizeof(struct listeners_rcu_head),
+ GFP_ATOMIC);
if (!listeners) {
err = -ENOMEM;
goto out_ungrab;
@@ -1532,16 +1583,24 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups)
old = tbl->listeners;
memcpy(listeners, old, NLGRPSZ(tbl->groups));
rcu_assign_pointer(tbl->listeners, listeners);
+ /*
+ * Free the old memory after an RCU grace period so we
+ * don't leak it. We use call_rcu() here in order to be
+ * able to call this function from atomic contexts. The
+ * allocation of this memory will have reserved enough
+ * space for struct listeners_rcu_head at the end.
+ */
+ old_rcu_head = (void *)(tbl->listeners +
+ NLGRPLONGS(tbl->groups));
+ old_rcu_head->ptr = old;
+ call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners);
}
tbl->groups = groups;
out_ungrab:
netlink_table_ungrab();
- synchronize_rcu();
- kfree(old);
return err;
}
-EXPORT_SYMBOL(netlink_change_ngroups);
/**
* netlink_clear_multicast_users - kick off multicast listeners
@@ -1564,7 +1623,6 @@ void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
netlink_table_ungrab();
}
-EXPORT_SYMBOL(netlink_clear_multicast_users);
void netlink_set_nonroot(int protocol, unsigned int flags)
{
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index eed4c6a8afc0..575c64341508 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -18,8 +18,6 @@
#include <net/sock.h>
#include <net/genetlink.h>
-struct sock *genl_sock = NULL;
-
static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
static inline void genl_lock(void)
@@ -175,10 +173,31 @@ int genl_register_mc_group(struct genl_family *family,
mc_groups_longs++;
}
- err = netlink_change_ngroups(genl_sock,
- mc_groups_longs * BITS_PER_LONG);
- if (err)
- goto out;
+ if (family->netnsok) {
+ struct net *net;
+
+ rcu_read_lock();
+ for_each_net_rcu(net) {
+ err = netlink_change_ngroups(net->genl_sock,
+ mc_groups_longs * BITS_PER_LONG);
+ if (err) {
+ /*
+ * No need to roll back, can only fail if
+ * memory allocation fails and then the
+ * number of _possible_ groups has been
+ * increased on some sockets which is ok.
+ */
+ rcu_read_unlock();
+ goto out;
+ }
+ }
+ rcu_read_unlock();
+ } else {
+ err = netlink_change_ngroups(init_net.genl_sock,
+ mc_groups_longs * BITS_PER_LONG);
+ if (err)
+ goto out;
+ }
grp->id = id;
set_bit(id, mc_groups);
@@ -195,8 +214,14 @@ EXPORT_SYMBOL(genl_register_mc_group);
static void __genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
+ struct net *net;
BUG_ON(grp->family != family);
- netlink_clear_multicast_users(genl_sock, grp->id);
+
+ rcu_read_lock();
+ for_each_net_rcu(net)
+ netlink_clear_multicast_users(net->genl_sock, grp->id);
+ rcu_read_unlock();
+
clear_bit(grp->id, mc_groups);
list_del(&grp->list);
genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
@@ -467,6 +492,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct genl_ops *ops;
struct genl_family *family;
+ struct net *net = sock_net(skb->sk);
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
int hdrlen, err;
@@ -475,6 +501,10 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (family == NULL)
return -ENOENT;
+ /* this family doesn't exist in this netns */
+ if (!family->netnsok && !net_eq(net, &init_net))
+ return -ENOENT;
+
hdrlen = GENL_HDRLEN + family->hdrsize;
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
return -EINVAL;
@@ -492,7 +522,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EOPNOTSUPP;
genl_unlock();
- err = netlink_dump_start(genl_sock, skb, nlh,
+ err = netlink_dump_start(net->genl_sock, skb, nlh,
ops->dumpit, ops->done);
genl_lock();
return err;
@@ -514,6 +544,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
info.genlhdr = nlmsg_data(nlh);
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
+ genl_info_net_set(&info, net);
return ops->doit(skb, &info);
}
@@ -534,6 +565,7 @@ static struct genl_family genl_ctrl = {
.name = "nlctrl",
.version = 0x2,
.maxattr = CTRL_ATTR_MAX,
+ .netnsok = true,
};
static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
@@ -650,6 +682,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
int i, n = 0;
struct genl_family *rt;
+ struct net *net = sock_net(skb->sk);
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
@@ -658,6 +691,8 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
continue;
n = 0;
list_for_each_entry(rt, genl_family_chain(i), family_list) {
+ if (!rt->netnsok && !net_eq(net, &init_net))
+ continue;
if (++n < fams_to_skip)
continue;
if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
@@ -729,6 +764,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
res = genl_family_find_byid(id);
+ err = -ENOENT;
}
if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
@@ -736,49 +772,61 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
res = genl_family_find_byname(name);
+ err = -ENOENT;
}
- if (res == NULL) {
- err = -ENOENT;
- goto errout;
+ if (res == NULL)
+ return err;
+
+ if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) {
+ /* family doesn't exist here */
+ return -ENOENT;
}
msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
CTRL_CMD_NEWFAMILY);
- if (IS_ERR(msg)) {
- err = PTR_ERR(msg);
- goto errout;
- }
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
- err = genlmsg_reply(msg, info);
-errout:
- return err;
+ return genlmsg_reply(msg, info);
}
static int genl_ctrl_event(int event, void *data)
{
struct sk_buff *msg;
+ struct genl_family *family;
+ struct genl_multicast_group *grp;
- if (genl_sock == NULL)
+ /* genl is still initialising */
+ if (!init_net.genl_sock)
return 0;
switch (event) {
case CTRL_CMD_NEWFAMILY:
case CTRL_CMD_DELFAMILY:
- msg = ctrl_build_family_msg(data, 0, 0, event);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+ family = data;
+ msg = ctrl_build_family_msg(family, 0, 0, event);
break;
case CTRL_CMD_NEWMCAST_GRP:
case CTRL_CMD_DELMCAST_GRP:
+ grp = data;
+ family = grp->family;
msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
break;
+ default:
+ return -EINVAL;
+ }
+
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ if (!family->netnsok) {
+ genlmsg_multicast_netns(&init_net, msg, 0,
+ GENL_ID_CTRL, GFP_KERNEL);
+ } else {
+ rcu_read_lock();
+ genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC);
+ rcu_read_unlock();
}
return 0;
@@ -795,6 +843,33 @@ static struct genl_multicast_group notify_grp = {
.name = "notify",
};
+static int __net_init genl_pernet_init(struct net *net)
+{
+ /* we'll bump the group number right afterwards */
+ net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
+ genl_rcv, &genl_mutex,
+ THIS_MODULE);
+
+ if (!net->genl_sock && net_eq(net, &init_net))
+ panic("GENL: Cannot initialize generic netlink\n");
+
+ if (!net->genl_sock)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __net_exit genl_pernet_exit(struct net *net)
+{
+ netlink_kernel_release(net->genl_sock);
+ net->genl_sock = NULL;
+}
+
+static struct pernet_operations genl_pernet_ops = {
+ .init = genl_pernet_init,
+ .exit = genl_pernet_exit,
+};
+
static int __init genl_init(void)
{
int i, err;
@@ -804,36 +879,67 @@ static int __init genl_init(void)
err = genl_register_family(&genl_ctrl);
if (err < 0)
- goto errout;
+ goto problem;
err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
if (err < 0)
- goto errout_register;
+ goto problem;
netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
- /* we'll bump the group number right afterwards */
- genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0,
- genl_rcv, &genl_mutex, THIS_MODULE);
- if (genl_sock == NULL)
- panic("GENL: Cannot initialize generic netlink\n");
+ err = register_pernet_subsys(&genl_pernet_ops);
+ if (err)
+ goto problem;
err = genl_register_mc_group(&genl_ctrl, &notify_grp);
if (err < 0)
- goto errout_register;
+ goto problem;
return 0;
-errout_register:
- genl_unregister_family(&genl_ctrl);
-errout:
+problem:
panic("GENL: Cannot register controller: %d\n", err);
}
subsys_initcall(genl_init);
-EXPORT_SYMBOL(genl_sock);
EXPORT_SYMBOL(genl_register_ops);
EXPORT_SYMBOL(genl_unregister_ops);
EXPORT_SYMBOL(genl_register_family);
EXPORT_SYMBOL(genl_unregister_family);
+
+static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
+ gfp_t flags)
+{
+ struct sk_buff *tmp;
+ struct net *net, *prev = NULL;
+ int err;
+
+ for_each_net_rcu(net) {
+ if (prev) {
+ tmp = skb_clone(skb, flags);
+ if (!tmp) {
+ err = -ENOMEM;
+ goto error;
+ }
+ err = nlmsg_multicast(prev->genl_sock, tmp,
+ pid, group, flags);
+ if (err)
+ goto error;
+ }
+
+ prev = net;
+ }
+
+ return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
+ error:
+ kfree_skb(skb);
+ return err;
+}
+
+int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, unsigned int group,
+ gfp_t flags)
+{
+ return genlmsg_mcast(skb, pid, group, flags);
+}
+EXPORT_SYMBOL(genlmsg_multicast_allns);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 351372463fed..c7b7838a0519 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -177,13 +177,13 @@ static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
if (!nr_route_frame(skb, NULL)) {
kfree_skb(skb);
stats->tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
stats->tx_packets++;
stats->tx_bytes += len;
- return 0;
+ return NETDEV_TX_OK;
}
static const struct header_ops nr_header_ops = {
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ebe5718baa31..d3d52c66cdc2 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -137,8 +137,7 @@ dev->hard_header == NULL (ll header is added by device, we cannot control it)
/* Private packet socket structures. */
-struct packet_mclist
-{
+struct packet_mclist {
struct packet_mclist *next;
int ifindex;
int count;
@@ -149,8 +148,7 @@ struct packet_mclist
/* identical to struct packet_mreq except it has
* a longer address field.
*/
-struct packet_mreq_max
-{
+struct packet_mreq_max {
int mr_ifindex;
unsigned short mr_type;
unsigned short mr_alen;
@@ -162,7 +160,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
int closing, int tx_ring);
struct packet_ring_buffer {
- char * *pg_vec;
+ char **pg_vec;
unsigned int head;
unsigned int frames_per_block;
unsigned int frame_size;
@@ -239,7 +237,7 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
flush_dcache_page(virt_to_page(&h.h2->tp_status));
break;
default:
- printk(KERN_ERR "TPACKET version not supported\n");
+ pr_err("TPACKET version not supported\n");
BUG();
}
@@ -265,7 +263,7 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
flush_dcache_page(virt_to_page(&h.h2->tp_status));
return h.h2->tp_status;
default:
- printk(KERN_ERR "TPACKET version not supported\n");
+ pr_err("TPACKET version not supported\n");
BUG();
return 0;
}
@@ -327,7 +325,7 @@ static void packet_sock_destruct(struct sock *sk)
WARN_ON(atomic_read(&sk->sk_wmem_alloc));
if (!sock_flag(sk, SOCK_DEAD)) {
- printk("Attempt to release alive packet socket: %p\n", sk);
+ pr_err("Attempt to release alive packet socket: %p\n", sk);
return;
}
@@ -339,7 +337,8 @@ static const struct proto_ops packet_ops;
static const struct proto_ops packet_ops_spkt;
-static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
{
struct sock *sk;
struct sockaddr_pkt *spkt;
@@ -368,7 +367,8 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
if (dev_net(dev) != sock_net(sk))
goto out;
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (skb == NULL)
goto oom;
/* drop any routing info */
@@ -394,7 +394,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
* to prevent sockets using all the memory up.
*/
- if (sock_queue_rcv_skb(sk,skb) == 0)
+ if (sock_queue_rcv_skb(sk, skb) == 0)
return 0;
out:
@@ -413,25 +413,23 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
+ struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name;
struct sk_buff *skb;
struct net_device *dev;
- __be16 proto=0;
+ __be16 proto = 0;
int err;
/*
* Get and verify the address.
*/
- if (saddr)
- {
+ if (saddr) {
if (msg->msg_namelen < sizeof(struct sockaddr))
- return(-EINVAL);
- if (msg->msg_namelen==sizeof(struct sockaddr_pkt))
- proto=saddr->spkt_protocol;
- }
- else
- return(-ENOTCONN); /* SOCK_PACKET must be sent giving an address */
+ return -EINVAL;
+ if (msg->msg_namelen == sizeof(struct sockaddr_pkt))
+ proto = saddr->spkt_protocol;
+ } else
+ return -ENOTCONN; /* SOCK_PACKET must be sent giving an address */
/*
* Find the device first to size check it
@@ -448,8 +446,8 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
goto out_unlock;
/*
- * You may not queue a frame bigger than the mtu. This is the lowest level
- * raw protocol and you must do your own fragmentation at this level.
+ * You may not queue a frame bigger than the mtu. This is the lowest level
+ * raw protocol and you must do your own fragmentation at this level.
*/
err = -EMSGSIZE;
@@ -460,9 +458,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
skb = sock_wmalloc(sk, len + LL_RESERVED_SPACE(dev), 0, GFP_KERNEL);
/*
- * If the write buffer is full, then tough. At this level the user gets to
- * deal with the problem - do your own algorithmic backoffs. That's far
- * more flexible.
+ * If the write buffer is full, then tough. At this level the user
+ * gets to deal with the problem - do your own algorithmic backoffs.
+ * That's far more flexible.
*/
if (skb == NULL)
@@ -488,7 +486,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
}
/* Returns -EFAULT on error */
- err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->sk_priority;
@@ -501,7 +499,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
dev_queue_xmit(skb);
dev_put(dev);
- return(len);
+ return len;
out_free:
kfree_skb(skb);
@@ -537,12 +535,13 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
we will not harm anyone.
*/
-static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
{
struct sock *sk;
struct sockaddr_ll *sll;
struct packet_sock *po;
- u8 * skb_head = skb->data;
+ u8 *skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;
@@ -648,7 +647,8 @@ drop:
}
#ifdef CONFIG_PACKET_MMAP
-static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
{
struct sock *sk;
struct packet_sock *po;
@@ -658,7 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
struct tpacket2_hdr *h2;
void *raw;
} h;
- u8 * skb_head = skb->data;
+ u8 *skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;
unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
@@ -821,7 +821,7 @@ ring_is_full:
static void tpacket_destruct_skb(struct sk_buff *skb)
{
struct packet_sock *po = pkt_sk(skb->sk);
- void * ph;
+ void *ph;
BUG_ON(skb == NULL);
@@ -836,9 +836,9 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
sock_wfree(skb);
}
-static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
- void * frame, struct net_device *dev, int size_max,
- __be16 proto, unsigned char * addr)
+static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
+ void *frame, struct net_device *dev, int size_max,
+ __be16 proto, unsigned char *addr)
{
union {
struct tpacket_hdr *h1;
@@ -867,8 +867,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
break;
}
if (unlikely(tp_len > size_max)) {
- printk(KERN_ERR "packet size is too long (%d > %d)\n",
- tp_len, size_max);
+ pr_err("packet size is too long (%d > %d)\n", tp_len, size_max);
return -EMSGSIZE;
}
@@ -883,12 +882,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
NULL, tp_len);
if (unlikely(err < 0))
return -EINVAL;
- } else if (dev->hard_header_len ) {
+ } else if (dev->hard_header_len) {
/* net device doesn't like empty head */
if (unlikely(tp_len <= dev->hard_header_len)) {
- printk(KERN_ERR "packet size is too short "
- "(%d < %d)\n", tp_len,
- dev->hard_header_len);
+ pr_err("packet size is too short (%d < %d)\n",
+ tp_len, dev->hard_header_len);
return -EINVAL;
}
@@ -917,9 +915,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
nr_frags = skb_shinfo(skb)->nr_frags;
if (unlikely(nr_frags >= MAX_SKB_FRAGS)) {
- printk(KERN_ERR "Packet exceed the number "
- "of skb frags(%lu)\n",
- MAX_SKB_FRAGS);
+ pr_err("Packet exceed the number of skb frags(%lu)\n",
+ MAX_SKB_FRAGS);
return -EFAULT;
}
@@ -944,8 +941,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
struct net_device *dev;
__be16 proto;
int ifindex, err, reserve = 0;
- void * ph;
- struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
+ void *ph;
+ struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
int tp_len, size_max;
unsigned char *addr;
int len_sum = 0;
@@ -1038,8 +1035,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
goto out_xmit;
packet_increment_head(&po->tx_ring);
len_sum += tp_len;
- }
- while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT))
+ } while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT))
&& (atomic_read(&po->tx_ring.pending))))
);
@@ -1064,7 +1060,7 @@ static int packet_snd(struct socket *sock,
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
+ struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
struct sk_buff *skb;
struct net_device *dev;
__be16 proto;
@@ -1110,7 +1106,7 @@ static int packet_snd(struct socket *sock,
skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
msg->msg_flags & MSG_DONTWAIT, &err);
- if (skb==NULL)
+ if (skb == NULL)
goto out_unlock;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -1122,7 +1118,7 @@ static int packet_snd(struct socket *sock,
goto out_free;
/* Returns -EFAULT on error */
- err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (err)
goto out_free;
@@ -1140,7 +1136,7 @@ static int packet_snd(struct socket *sock,
dev_put(dev);
- return(len);
+ return len;
out_free:
kfree_skb(skb);
@@ -1283,9 +1279,10 @@ out_unlock:
* Bind a packet socket to a device
*/
-static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
+ int addr_len)
{
- struct sock *sk=sock->sk;
+ struct sock *sk = sock->sk;
char name[15];
struct net_device *dev;
int err = -ENODEV;
@@ -1296,7 +1293,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
if (addr_len != sizeof(struct sockaddr))
return -EINVAL;
- strlcpy(name,uaddr->sa_data,sizeof(name));
+ strlcpy(name, uaddr->sa_data, sizeof(name));
dev = dev_get_by_name(sock_net(sk), name);
if (dev) {
@@ -1308,8 +1305,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
- struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;
- struct sock *sk=sock->sk;
+ struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
+ struct sock *sk = sock->sk;
struct net_device *dev = NULL;
int err;
@@ -1404,7 +1401,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol)
sk_add_node(sk, &net->packet.sklist);
sock_prot_inuse_add(net, &packet_proto, 1);
write_unlock_bh(&net->packet.sklist_lock);
- return(0);
+ return 0;
out:
return err;
}
@@ -1441,7 +1438,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
* but then it will block.
*/
- skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
+ skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
/*
* An error occurred so return it. Because skb_recv_datagram()
@@ -1469,10 +1466,9 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
*/
copied = skb->len;
- if (copied > len)
- {
- copied=len;
- msg->msg_flags|=MSG_TRUNC;
+ if (copied > len) {
+ copied = len;
+ msg->msg_flags |= MSG_TRUNC;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
@@ -1539,7 +1535,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
struct net_device *dev;
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
- struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;
+ struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
if (peer)
return -EOPNOTSUPP;
@@ -1584,14 +1580,15 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
else
return dev_unicast_delete(dev, i->addr);
break;
- default:;
+ default:
+ break;
}
return 0;
}
static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
{
- for ( ; i; i=i->next) {
+ for ( ; i; i = i->next) {
if (i->ifindex == dev->ifindex)
packet_dev_mc(dev, i, what);
}
@@ -1693,7 +1690,8 @@ static void packet_flush_mclist(struct sock *sk)
struct net_device *dev;
po->mclist = ml->next;
- if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) {
+ dev = dev_get_by_index(sock_net(sk), ml->ifindex);
+ if (dev != NULL) {
packet_dev_mc(dev, ml, -1);
dev_put(dev);
}
@@ -1723,7 +1721,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
return -EINVAL;
if (len > sizeof(mreq))
len = sizeof(mreq);
- if (copy_from_user(&mreq,optval,len))
+ if (copy_from_user(&mreq, optval, len))
return -EFAULT;
if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
return -EINVAL;
@@ -1740,9 +1738,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
{
struct tpacket_req req;
- if (optlen<sizeof(req))
+ if (optlen < sizeof(req))
return -EINVAL;
- if (copy_from_user(&req,optval,sizeof(req)))
+ if (copy_from_user(&req, optval, sizeof(req)))
return -EFAULT;
return packet_set_ring(sk, &req, 0, optname == PACKET_TX_RING);
}
@@ -1750,9 +1748,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
{
int val;
- if (optlen!=sizeof(val))
+ if (optlen != sizeof(val))
return -EINVAL;
- if (copy_from_user(&val,optval,sizeof(val)))
+ if (copy_from_user(&val, optval, sizeof(val)))
return -EFAULT;
pkt_sk(sk)->copy_thresh = val;
@@ -1985,51 +1983,51 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
struct sock *sk = sock->sk;
switch (cmd) {
- case SIOCOUTQ:
- {
- int amount = sk_wmem_alloc_get(sk);
+ case SIOCOUTQ:
+ {
+ int amount = sk_wmem_alloc_get(sk);
- return put_user(amount, (int __user *)arg);
- }
- case SIOCINQ:
- {
- struct sk_buff *skb;
- int amount = 0;
-
- spin_lock_bh(&sk->sk_receive_queue.lock);
- skb = skb_peek(&sk->sk_receive_queue);
- if (skb)
- amount = skb->len;
- spin_unlock_bh(&sk->sk_receive_queue.lock);
- return put_user(amount, (int __user *)arg);
- }
- case SIOCGSTAMP:
- return sock_get_timestamp(sk, (struct timeval __user *)arg);
- case SIOCGSTAMPNS:
- return sock_get_timestampns(sk, (struct timespec __user *)arg);
+ return put_user(amount, (int __user *)arg);
+ }
+ case SIOCINQ:
+ {
+ struct sk_buff *skb;
+ int amount = 0;
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ skb = skb_peek(&sk->sk_receive_queue);
+ if (skb)
+ amount = skb->len;
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ return put_user(amount, (int __user *)arg);
+ }
+ case SIOCGSTAMP:
+ return sock_get_timestamp(sk, (struct timeval __user *)arg);
+ case SIOCGSTAMPNS:
+ return sock_get_timestampns(sk, (struct timespec __user *)arg);
#ifdef CONFIG_INET
- case SIOCADDRT:
- case SIOCDELRT:
- case SIOCDARP:
- case SIOCGARP:
- case SIOCSARP:
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCSIFFLAGS:
- if (!net_eq(sock_net(sk), &init_net))
- return -ENOIOCTLCMD;
- return inet_dgram_ops.ioctl(sock, cmd, arg);
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCDARP:
+ case SIOCGARP:
+ case SIOCSARP:
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCSIFFLAGS:
+ if (!net_eq(sock_net(sk), &init_net))
+ return -ENOIOCTLCMD;
+ return inet_dgram_ops.ioctl(sock, cmd, arg);
#endif
- default:
- return -ENOIOCTLCMD;
+ default:
+ return -ENOIOCTLCMD;
}
return 0;
}
@@ -2039,7 +2037,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
#define packet_poll datagram_poll
#else
-static unsigned int packet_poll(struct file * file, struct socket *sock,
+static unsigned int packet_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
struct sock *sk = sock->sk;
@@ -2069,7 +2067,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock,
static void packet_mm_open(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
- struct socket * sock = file->private_data;
+ struct socket *sock = file->private_data;
struct sock *sk = sock->sk;
if (sk)
@@ -2079,7 +2077,7 @@ static void packet_mm_open(struct vm_area_struct *vma)
static void packet_mm_close(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
- struct socket * sock = file->private_data;
+ struct socket *sock = file->private_data;
struct sock *sk = sock->sk;
if (sk)
@@ -2087,8 +2085,8 @@ static void packet_mm_close(struct vm_area_struct *vma)
}
static struct vm_operations_struct packet_mmap_ops = {
- .open = packet_mm_open,
- .close =packet_mm_close,
+ .open = packet_mm_open,
+ .close = packet_mm_close,
};
static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
@@ -2239,8 +2237,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
skb_queue_purge(rb_queue);
#undef XC
if (atomic_read(&po->mapped))
- printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n",
- atomic_read(&po->mapped));
+ pr_err("packet_mmap: vma is busy: %d\n",
+ atomic_read(&po->mapped));
}
mutex_unlock(&po->pg_vec_lock);
@@ -2303,7 +2301,7 @@ static int packet_mmap(struct file *file, struct socket *sock,
int pg_num;
for (pg_num = 0; pg_num < rb->pg_vec_pages;
- pg_num++,page++) {
+ pg_num++, page++) {
err = vm_insert_page(vma, start, page);
if (unlikely(err))
goto out;
@@ -2372,7 +2370,7 @@ static struct net_proto_family packet_family_ops = {
};
static struct notifier_block packet_netdev_notifier = {
- .notifier_call =packet_notifier,
+ .notifier_call = packet_notifier,
};
#ifdef CONFIG_PROC_FS
@@ -2402,7 +2400,7 @@ static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++*pos;
return (v == SEQ_START_TOKEN)
? sk_head(&net->packet.sklist)
- : sk_next((struct sock*)v) ;
+ : sk_next((struct sock *)v) ;
}
static void packet_seq_stop(struct seq_file *seq, void *v)
@@ -2430,7 +2428,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
po->running,
atomic_read(&s->sk_rmem_alloc),
sock_i_uid(s),
- sock_i_ino(s) );
+ sock_i_ino(s));
}
return 0;
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index e087862ed7e4..ef5c75c372e4 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -159,8 +159,11 @@ 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-gprs.c b/net/phonet/pep-gprs.c
index 480839dfc560..4667af51ed71 100644
--- a/net/phonet/pep-gprs.c
+++ b/net/phonet/pep-gprs.c
@@ -195,7 +195,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
break;
default:
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_orphan(skb);
@@ -215,7 +215,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
if (pep_writeable(sk))
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static int gprs_set_mtu(struct net_device *dev, int new_mtu)
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index eef833ea6d7b..b8252d289cd7 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -346,8 +346,10 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
break;
case PNS_PEP_CTRL_REQ:
- if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
+ if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
+ atomic_inc(&sk->sk_drops);
break;
+ }
__skb_pull(skb, 4);
queue = &pn->ctrlreq_queue;
goto queue;
@@ -358,10 +360,13 @@ 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;
}
if (pn->rx_credits == 0) {
+ atomic_inc(&sk->sk_drops);
err = -ENOBUFS;
break;
}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index b0d6ddd82a9d..5ae4c01e8388 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -27,6 +27,7 @@
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/phonet.h>
+#include <linux/proc_fs.h>
#include <net/sock.h>
#include <net/netns/generic.h>
#include <net/phonet/pn_dev.h>
@@ -96,7 +97,7 @@ struct net_device *phonet_device_get(struct net *net)
{
struct phonet_device_list *pndevs = phonet_device_list(net);
struct phonet_device *pnd;
- struct net_device *dev;
+ struct net_device *dev = NULL;
spin_lock_bh(&pndevs->lock);
list_for_each_entry(pnd, &pndevs->list, list) {
@@ -218,6 +219,11 @@ static int phonet_init_net(struct net *net)
if (!pnn)
return -ENOMEM;
+ if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) {
+ kfree(pnn);
+ return -ENOMEM;
+ }
+
INIT_LIST_HEAD(&pnn->pndevs.list);
spin_lock_init(&pnn->pndevs.lock);
net_assign_generic(net, phonet_net_id, pnn);
@@ -233,6 +239,8 @@ static void phonet_exit_net(struct net *net)
for_each_netdev(net, dev)
phonet_device_destroy(dev);
rtnl_unlock();
+
+ proc_net_remove(net, "phonet");
kfree(pnn);
}
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index ada2a35bf7a2..aa1617a7f265 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -412,3 +412,99 @@ found:
return 0;
}
EXPORT_SYMBOL(pn_sock_get_port);
+
+static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct net *net = seq_file_net(seq);
+ struct hlist_node *node;
+ struct sock *sknode;
+
+ sk_for_each(sknode, node, &pnsocks.hlist) {
+ if (!net_eq(net, sock_net(sknode)))
+ continue;
+ if (!pos)
+ return sknode;
+ pos--;
+ }
+ return NULL;
+}
+
+static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
+{
+ struct net *net = seq_file_net(seq);
+
+ do
+ sk = sk_next(sk);
+ while (sk && !net_eq(net, sock_net(sk)));
+
+ return sk;
+}
+
+static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(pnsocks.lock)
+{
+ spin_lock_bh(&pnsocks.lock);
+ return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct sock *sk;
+
+ if (v == SEQ_START_TOKEN)
+ sk = pn_sock_get_idx(seq, 0);
+ else
+ sk = pn_sock_get_next(seq, v);
+ (*pos)++;
+ return sk;
+}
+
+static void pn_sock_seq_stop(struct seq_file *seq, void *v)
+ __releases(pnsocks.lock)
+{
+ spin_unlock_bh(&pnsocks.lock);
+}
+
+static int pn_sock_seq_show(struct seq_file *seq, void *v)
+{
+ int len;
+
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue "
+ " uid inode ref pointer drops", &len);
+ else {
+ struct sock *sk = v;
+ struct pn_sock *pn = pn_sk(sk);
+
+ seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
+ "%d %p %d%n",
+ sk->sk_protocol, pn->sobject, 0, pn->resource,
+ sk->sk_state,
+ sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
+ sock_i_uid(sk), sock_i_ino(sk),
+ atomic_read(&sk->sk_refcnt), sk,
+ atomic_read(&sk->sk_drops), &len);
+ }
+ seq_printf(seq, "%*s\n", 127 - len, "");
+ return 0;
+}
+
+static const struct seq_operations pn_sock_seq_ops = {
+ .start = pn_sock_seq_start,
+ .next = pn_sock_seq_next,
+ .stop = pn_sock_seq_stop,
+ .show = pn_sock_seq_show,
+};
+
+static int pn_sock_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &pn_sock_seq_ops);
+}
+
+const struct file_operations pn_sock_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = pn_sock_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
diff --git a/net/rds/connection.c b/net/rds/connection.c
index d14445c48304..b420a20d84fd 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -126,7 +126,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
struct rds_transport *trans, gfp_t gfp,
int is_outgoing)
{
- struct rds_connection *conn, *tmp, *parent = NULL;
+ struct rds_connection *conn, *parent = NULL;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
unsigned long flags;
int ret;
@@ -155,7 +155,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
}
INIT_HLIST_NODE(&conn->c_hash_node);
- conn->c_version = RDS_PROTOCOL_3_0;
conn->c_laddr = laddr;
conn->c_faddr = faddr;
spin_lock_init(&conn->c_lock);
@@ -211,26 +210,40 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
trans->t_name ? trans->t_name : "[unknown]",
is_outgoing ? "(outgoing)" : "");
+ /*
+ * Since we ran without holding the conn lock, someone could
+ * have created the same conn (either normal or passive) in the
+ * interim. We check while holding the lock. If we won, we complete
+ * init and return our conn. If we lost, we rollback and return the
+ * other one.
+ */
spin_lock_irqsave(&rds_conn_lock, flags);
- if (parent == NULL) {
- tmp = rds_conn_lookup(head, laddr, faddr, trans);
- if (tmp == NULL)
- hlist_add_head(&conn->c_hash_node, head);
- } else {
- tmp = parent->c_passive;
- if (!tmp)
+ if (parent) {
+ /* Creating passive conn */
+ if (parent->c_passive) {
+ trans->conn_free(conn->c_transport_data);
+ kmem_cache_free(rds_conn_slab, conn);
+ conn = parent->c_passive;
+ } else {
parent->c_passive = conn;
- }
-
- if (tmp) {
- trans->conn_free(conn->c_transport_data);
- kmem_cache_free(rds_conn_slab, conn);
- conn = tmp;
+ rds_cong_add_conn(conn);
+ rds_conn_count++;
+ }
} else {
- rds_cong_add_conn(conn);
- rds_conn_count++;
+ /* Creating normal conn */
+ struct rds_connection *found;
+
+ found = rds_conn_lookup(head, laddr, faddr, trans);
+ if (found) {
+ trans->conn_free(conn->c_transport_data);
+ kmem_cache_free(rds_conn_slab, conn);
+ conn = found;
+ } else {
+ hlist_add_head(&conn->c_hash_node, head);
+ rds_cong_add_conn(conn);
+ rds_conn_count++;
+ }
}
-
spin_unlock_irqrestore(&rds_conn_lock, flags);
out:
diff --git a/net/rds/ib.c b/net/rds/ib.c
index b9bcd32431e1..868559ac42d7 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -43,11 +43,14 @@
unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */
+unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
module_param(fmr_pool_size, int, 0444);
MODULE_PARM_DESC(fmr_pool_size, " Max number of fmr per HCA");
module_param(fmr_message_size, int, 0444);
MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
+module_param(rds_ib_retry_count, int, 0444);
+MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
struct list_head rds_ib_devices;
@@ -82,9 +85,6 @@ void rds_ib_add_one(struct ib_device *device)
rds_ibdev->max_wrs = dev_attr->max_qp_wr;
rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
- rds_ibdev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
- rds_ibdev->fmr_page_size = 1 << rds_ibdev->fmr_page_shift;
- rds_ibdev->fmr_page_mask = ~((u64) rds_ibdev->fmr_page_size - 1);
rds_ibdev->fmr_max_remaps = dev_attr->max_map_per_fmr?: 32;
rds_ibdev->max_fmrs = dev_attr->max_fmr ?
min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) :
diff --git a/net/rds/ib.h b/net/rds/ib.h
index 455ae73047fe..1378b854cac0 100644
--- a/net/rds/ib.h
+++ b/net/rds/ib.h
@@ -15,6 +15,8 @@
#define RDS_IB_DEFAULT_RECV_WR 1024
#define RDS_IB_DEFAULT_SEND_WR 256
+#define RDS_IB_DEFAULT_RETRY_COUNT 2
+
#define RDS_IB_SUPPORTED_PROTOCOLS 0x00000003 /* minor versions supported */
extern struct list_head rds_ib_devices;
@@ -157,9 +159,6 @@ struct rds_ib_device {
struct ib_pd *pd;
struct ib_mr *mr;
struct rds_ib_mr_pool *mr_pool;
- int fmr_page_shift;
- int fmr_page_size;
- u64 fmr_page_mask;
unsigned int fmr_max_remaps;
unsigned int max_fmrs;
int max_sge;
@@ -247,6 +246,7 @@ extern struct ib_client rds_ib_client;
extern unsigned int fmr_pool_size;
extern unsigned int fmr_message_size;
+extern unsigned int rds_ib_retry_count;
extern spinlock_t ib_nodev_conns_lock;
extern struct list_head ib_nodev_conns;
@@ -355,17 +355,25 @@ extern ctl_table rds_ib_sysctl_table[];
/*
* Helper functions for getting/setting the header and data SGEs in
* RDS packets (not RDMA)
+ *
+ * From version 3.1 onwards, header is in front of data in the sge.
*/
static inline struct ib_sge *
rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
{
- return &sge[0];
+ if (ic->conn->c_version > RDS_PROTOCOL_3_0)
+ return &sge[0];
+ else
+ return &sge[1];
}
static inline struct ib_sge *
rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
{
- return &sge[1];
+ if (ic->conn->c_version > RDS_PROTOCOL_3_0)
+ return &sge[1];
+ else
+ return &sge[0];
}
#endif
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index f8e40e1a6038..c2d372f13dbb 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -98,21 +98,34 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
struct ib_qp_attr qp_attr;
int err;
- if (event->param.conn.private_data_len) {
+ if (event->param.conn.private_data_len >= sizeof(*dp)) {
dp = event->param.conn.private_data;
- rds_ib_set_protocol(conn,
+ /* make sure it isn't empty data */
+ if (dp->dp_protocol_major) {
+ rds_ib_set_protocol(conn,
RDS_PROTOCOL(dp->dp_protocol_major,
- dp->dp_protocol_minor));
- rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+ dp->dp_protocol_minor));
+ rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+ }
}
printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
- &conn->c_laddr,
+ &conn->c_faddr,
RDS_PROTOCOL_MAJOR(conn->c_version),
RDS_PROTOCOL_MINOR(conn->c_version),
ic->i_flowctl ? ", flow control" : "");
+ /*
+ * Init rings and fill recv. this needs to wait until protocol negotiation
+ * is complete, since ring layout is different from 3.0 to 3.1.
+ */
+ rds_ib_send_init_ring(ic);
+ rds_ib_recv_init_ring(ic);
+ /* Post receive buffers - as a side effect, this will update
+ * the posted credit count. */
+ rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
+
/* Tune RNR behavior */
rds_ib_tune_rnr(ic, &qp_attr);
@@ -145,7 +158,7 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
/* XXX tune these? */
conn_param->responder_resources = 1;
conn_param->initiator_depth = 1;
- conn_param->retry_count = 7;
+ conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7);
conn_param->rnr_retry_count = 7;
if (dp) {
@@ -190,9 +203,9 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
break;
default:
- printk(KERN_WARNING "RDS/ib: unhandled QP event %u "
- "on connection to %pI4\n", event->event,
- &conn->c_faddr);
+ rds_ib_conn_error(conn, "RDS/IB: Fatal QP Event %u "
+ "- connection %pI4->%pI4, reconnecting\n",
+ event->event, &conn->c_laddr, &conn->c_faddr);
break;
}
}
@@ -321,7 +334,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
rdsdebug("send allocation failed\n");
goto out;
}
- rds_ib_send_init_ring(ic);
+ memset(ic->i_sends, 0, ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
if (ic->i_recvs == NULL) {
@@ -329,14 +342,10 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
rdsdebug("recv allocation failed\n");
goto out;
}
+ memset(ic->i_recvs, 0, ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
- rds_ib_recv_init_ring(ic);
rds_ib_recv_init_ack(ic);
- /* Post receive buffers - as a side effect, this will update
- * the posted credit count. */
- rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
-
rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr,
ic->i_send_cq, ic->i_recv_cq);
@@ -344,19 +353,32 @@ out:
return ret;
}
-static u32 rds_ib_protocol_compatible(const struct rds_ib_connect_private *dp)
+static u32 rds_ib_protocol_compatible(struct rdma_cm_event *event)
{
+ const struct rds_ib_connect_private *dp = event->param.conn.private_data;
u16 common;
u32 version = 0;
- /* rdma_cm private data is odd - when there is any private data in the
+ /*
+ * rdma_cm private data is odd - when there is any private data in the
* request, we will be given a pretty large buffer without telling us the
* original size. The only way to tell the difference is by looking at
* the contents, which are initialized to zero.
* If the protocol version fields aren't set, this is a connection attempt
* from an older version. This could could be 3.0 or 2.0 - we can't tell.
- * We really should have changed this for OFED 1.3 :-( */
- if (dp->dp_protocol_major == 0)
+ * We really should have changed this for OFED 1.3 :-(
+ */
+
+ /* Be paranoid. RDS always has privdata */
+ if (!event->param.conn.private_data_len) {
+ printk(KERN_NOTICE "RDS incoming connection has no private data, "
+ "rejecting\n");
+ return 0;
+ }
+
+ /* Even if len is crap *now* I still want to check it. -ASG */
+ if (event->param.conn.private_data_len < sizeof (*dp)
+ || dp->dp_protocol_major == 0)
return RDS_PROTOCOL_3_0;
common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IB_SUPPORTED_PROTOCOLS;
@@ -388,7 +410,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
int err, destroy = 1;
/* Check whether the remote protocol version matches ours. */
- version = rds_ib_protocol_compatible(dp);
+ version = rds_ib_protocol_compatible(event);
if (!version)
goto out;
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index 81033af93020..ef3ab5b7283e 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -211,7 +211,7 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
pool->fmr_attr.max_pages = fmr_message_size;
pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
- pool->fmr_attr.page_shift = rds_ibdev->fmr_page_shift;
+ pool->fmr_attr.page_shift = PAGE_SHIFT;
pool->max_free_pinned = rds_ibdev->max_fmrs * fmr_message_size / 4;
/* We never allow more than max_items MRs to be allocated.
@@ -349,13 +349,13 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
- if (dma_addr & ~rds_ibdev->fmr_page_mask) {
+ if (dma_addr & ~PAGE_MASK) {
if (i > 0)
return -EINVAL;
else
++page_cnt;
}
- if ((dma_addr + dma_len) & ~rds_ibdev->fmr_page_mask) {
+ if ((dma_addr + dma_len) & ~PAGE_MASK) {
if (i < sg_dma_len - 1)
return -EINVAL;
else
@@ -365,7 +365,7 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
len += dma_len;
}
- page_cnt += len >> rds_ibdev->fmr_page_shift;
+ page_cnt += len >> PAGE_SHIFT;
if (page_cnt > fmr_message_size)
return -EINVAL;
@@ -378,9 +378,9 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
- for (j = 0; j < dma_len; j += rds_ibdev->fmr_page_size)
+ for (j = 0; j < dma_len; j += PAGE_SIZE)
dma_pages[page_cnt++] =
- (dma_addr & rds_ibdev->fmr_page_mask) + j;
+ (dma_addr & PAGE_MASK) + j;
}
ret = ib_map_phys_fmr(ibmr->fmr,
diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
index 5709bad28329..cd7a6cfcab03 100644
--- a/net/rds/ib_recv.c
+++ b/net/rds/ib_recv.c
@@ -555,6 +555,47 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic)
return rds_ib_get_ack(ic);
}
+static struct rds_header *rds_ib_get_header(struct rds_connection *conn,
+ struct rds_ib_recv_work *recv,
+ u32 data_len)
+{
+ struct rds_ib_connection *ic = conn->c_transport_data;
+ void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs];
+ void *addr;
+ u32 misplaced_hdr_bytes;
+
+ /*
+ * Support header at the front (RDS 3.1+) as well as header-at-end.
+ *
+ * Cases:
+ * 1) header all in header buff (great!)
+ * 2) header all in data page (copy all to header buff)
+ * 3) header split across hdr buf + data page
+ * (move bit in hdr buff to end before copying other bit from data page)
+ */
+ if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE)
+ return hdr_buff;
+
+ if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) {
+ addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
+ memcpy(hdr_buff,
+ addr + recv->r_frag->f_offset + data_len,
+ sizeof(struct rds_header));
+ kunmap_atomic(addr, KM_SOFTIRQ0);
+ return hdr_buff;
+ }
+
+ misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len));
+
+ memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes);
+
+ addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
+ memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len,
+ sizeof(struct rds_header) - misplaced_hdr_bytes);
+ kunmap_atomic(addr, KM_SOFTIRQ0);
+ return hdr_buff;
+}
+
/*
* It's kind of lame that we're copying from the posted receive pages into
* long-lived bitmaps. We could have posted the bitmaps and rdma written into
@@ -645,7 +686,7 @@ struct rds_ib_ack_state {
};
static void rds_ib_process_recv(struct rds_connection *conn,
- struct rds_ib_recv_work *recv, u32 byte_len,
+ struct rds_ib_recv_work *recv, u32 data_len,
struct rds_ib_ack_state *state)
{
struct rds_ib_connection *ic = conn->c_transport_data;
@@ -655,9 +696,9 @@ static void rds_ib_process_recv(struct rds_connection *conn,
/* XXX shut down the connection if port 0,0 are seen? */
rdsdebug("ic %p ibinc %p recv %p byte len %u\n", ic, ibinc, recv,
- byte_len);
+ data_len);
- if (byte_len < sizeof(struct rds_header)) {
+ if (data_len < sizeof(struct rds_header)) {
rds_ib_conn_error(conn, "incoming message "
"from %pI4 didn't inclue a "
"header, disconnecting and "
@@ -665,9 +706,9 @@ static void rds_ib_process_recv(struct rds_connection *conn,
&conn->c_faddr);
return;
}
- byte_len -= sizeof(struct rds_header);
+ data_len -= sizeof(struct rds_header);
- ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
+ ihdr = rds_ib_get_header(conn, recv, data_len);
/* Validate the checksum. */
if (!rds_message_verify_checksum(ihdr)) {
@@ -687,7 +728,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
if (ihdr->h_credit)
rds_ib_send_add_credits(conn, ihdr->h_credit);
- if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) {
+ if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && data_len == 0) {
/* This is an ACK-only packet. The fact that it gets
* special treatment here is that historically, ACKs
* were rather special beasts.
diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c
index 02e3e3d50d4a..301ae51ae409 100644
--- a/net/rds/ib_stats.c
+++ b/net/rds/ib_stats.c
@@ -37,7 +37,7 @@
#include "rds.h"
#include "ib.h"
-DEFINE_PER_CPU(struct rds_ib_statistics, rds_ib_stats) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats);
static char *rds_ib_stat_names[] = {
"ib_connect_raced",
diff --git a/net/rds/ib_sysctl.c b/net/rds/ib_sysctl.c
index d87830db93a0..84b5ffcb280f 100644
--- a/net/rds/ib_sysctl.c
+++ b/net/rds/ib_sysctl.c
@@ -53,7 +53,17 @@ unsigned long rds_ib_sysctl_max_unsig_bytes = (16 << 20);
static unsigned long rds_ib_sysctl_max_unsig_bytes_min = 1;
static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL;
-unsigned int rds_ib_sysctl_flow_control = 1;
+/*
+ * This sysctl does nothing.
+ *
+ * Backwards compatibility with RDS 3.0 wire protocol
+ * disables initial FC credit exchange.
+ * If it's ever possible to drop 3.0 support,
+ * setting this to 1 and moving init/refill of send/recv
+ * rings from ib_cm_connect_complete() back into ib_setup_qp()
+ * will cause credits to be added before protocol negotiation.
+ */
+unsigned int rds_ib_sysctl_flow_control = 0;
ctl_table rds_ib_sysctl_table[] = {
{
diff --git a/net/rds/iw.c b/net/rds/iw.c
index d16e1cbc8e83..f5e9a29a80a7 100644
--- a/net/rds/iw.c
+++ b/net/rds/iw.c
@@ -83,23 +83,16 @@ void rds_iw_add_one(struct ib_device *device)
rds_iwdev->max_wrs = dev_attr->max_qp_wr;
rds_iwdev->max_sge = min(dev_attr->max_sge, RDS_IW_MAX_SGE);
- rds_iwdev->page_shift = max(PAGE_SHIFT, ffs(dev_attr->page_size_cap) - 1);
-
rds_iwdev->dev = device;
rds_iwdev->pd = ib_alloc_pd(device);
if (IS_ERR(rds_iwdev->pd))
goto free_dev;
if (!rds_iwdev->dma_local_lkey) {
- if (device->node_type != RDMA_NODE_RNIC) {
- rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
- IB_ACCESS_LOCAL_WRITE);
- } else {
- rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
- IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE |
- IB_ACCESS_LOCAL_WRITE);
- }
+ rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
+ IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_LOCAL_WRITE);
if (IS_ERR(rds_iwdev->mr))
goto err_pd;
} else
diff --git a/net/rds/iw.h b/net/rds/iw.h
index 0715dde323e7..dd72b62bd506 100644
--- a/net/rds/iw.h
+++ b/net/rds/iw.h
@@ -181,7 +181,6 @@ struct rds_iw_device {
struct ib_pd *pd;
struct ib_mr *mr;
struct rds_iw_mr_pool *mr_pool;
- int page_shift;
int max_sge;
unsigned int max_wrs;
unsigned int dma_local_lkey:1;
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
index dcdb37da80f2..de4a1b16bf7b 100644
--- a/net/rds/iw_rdma.c
+++ b/net/rds/iw_rdma.c
@@ -263,18 +263,12 @@ static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg,
}
static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
- struct rds_iw_scatterlist *sg,
- unsigned int dma_page_shift)
+ struct rds_iw_scatterlist *sg)
{
struct ib_device *dev = rds_iwdev->dev;
u64 *dma_pages = NULL;
- u64 dma_mask;
- unsigned int dma_page_size;
int i, j, ret;
- dma_page_size = 1 << dma_page_shift;
- dma_mask = dma_page_size - 1;
-
WARN_ON(sg->dma_len);
sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
@@ -295,18 +289,18 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
sg->bytes += dma_len;
end_addr = dma_addr + dma_len;
- if (dma_addr & dma_mask) {
+ if (dma_addr & PAGE_MASK) {
if (i > 0)
goto out_unmap;
- dma_addr &= ~dma_mask;
+ dma_addr &= ~PAGE_MASK;
}
- if (end_addr & dma_mask) {
+ if (end_addr & PAGE_MASK) {
if (i < sg->dma_len - 1)
goto out_unmap;
- end_addr = (end_addr + dma_mask) & ~dma_mask;
+ end_addr = (end_addr + PAGE_MASK) & ~PAGE_MASK;
}
- sg->dma_npages += (end_addr - dma_addr) >> dma_page_shift;
+ sg->dma_npages += (end_addr - dma_addr) >> PAGE_SHIFT;
}
/* Now gather the dma addrs into one list */
@@ -325,8 +319,8 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
u64 end_addr;
end_addr = dma_addr + dma_len;
- dma_addr &= ~dma_mask;
- for (; dma_addr < end_addr; dma_addr += dma_page_size)
+ dma_addr &= ~PAGE_MASK;
+ for (; dma_addr < end_addr; dma_addr += PAGE_SIZE)
dma_pages[j++] = dma_addr;
BUG_ON(j > sg->dma_npages);
}
@@ -727,7 +721,7 @@ static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping)
f_wr.wr.fast_reg.rkey = mapping->m_rkey;
f_wr.wr.fast_reg.page_list = ibmr->page_list;
f_wr.wr.fast_reg.page_list_len = mapping->m_sg.dma_len;
- f_wr.wr.fast_reg.page_shift = ibmr->device->page_shift;
+ f_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE |
IB_ACCESS_REMOTE_READ |
IB_ACCESS_REMOTE_WRITE;
@@ -780,9 +774,7 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len);
- dma_pages = rds_iw_map_scatterlist(rds_iwdev,
- &mapping->m_sg,
- rds_iwdev->page_shift);
+ dma_pages = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
if (IS_ERR(dma_pages)) {
ret = PTR_ERR(dma_pages);
dma_pages = NULL;
diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c
index 44a6a0551f28..1f5abe3cf2b4 100644
--- a/net/rds/iw_send.c
+++ b/net/rds/iw_send.c
@@ -779,7 +779,7 @@ static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rd
send->s_wr.wr.fast_reg.rkey = send->s_mr->rkey;
send->s_wr.wr.fast_reg.page_list = send->s_page_list;
send->s_wr.wr.fast_reg.page_list_len = nent;
- send->s_wr.wr.fast_reg.page_shift = rds_iwdev->page_shift;
+ send->s_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
send->s_wr.wr.fast_reg.access_flags = IB_ACCESS_REMOTE_WRITE;
send->s_wr.wr.fast_reg.iova_start = sg_addr;
diff --git a/net/rds/iw_stats.c b/net/rds/iw_stats.c
index ccc7e8f0bf0e..fafea3cc92d7 100644
--- a/net/rds/iw_stats.c
+++ b/net/rds/iw_stats.c
@@ -37,7 +37,7 @@
#include "rds.h"
#include "iw.h"
-DEFINE_PER_CPU(struct rds_iw_statistics, rds_iw_stats) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_iw_statistics, rds_iw_stats);
static char *rds_iw_stat_names[] = {
"iw_connect_raced",
diff --git a/net/rds/page.c b/net/rds/page.c
index c460743a89ad..de7bb84bcd78 100644
--- a/net/rds/page.c
+++ b/net/rds/page.c
@@ -39,7 +39,7 @@ struct rds_page_remainder {
unsigned long r_offset;
};
-DEFINE_PER_CPU(struct rds_page_remainder, rds_page_remainders) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_page_remainder, rds_page_remainders);
/*
* returns 0 on success or -errno on failure.
diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c
index 7d0f901c93d5..981a5e6ea5bc 100644
--- a/net/rds/rdma_transport.c
+++ b/net/rds/rdma_transport.c
@@ -101,7 +101,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
break;
case RDMA_CM_EVENT_DISCONNECTED:
- printk(KERN_WARNING "RDS/IW: DISCONNECT event - dropping connection "
+ printk(KERN_WARNING "RDS/RDMA: DISCONNECT event - dropping connection "
"%pI4->%pI4\n", &conn->c_laddr,
&conn->c_faddr);
rds_conn_drop(conn);
@@ -132,7 +132,7 @@ static int __init rds_rdma_listen_init(void)
cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP);
if (IS_ERR(cm_id)) {
ret = PTR_ERR(cm_id);
- printk(KERN_ERR "RDS/IW: failed to setup listener, "
+ printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
"rdma_create_id() returned %d\n", ret);
goto out;
}
@@ -147,14 +147,14 @@ static int __init rds_rdma_listen_init(void)
*/
ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
if (ret) {
- printk(KERN_ERR "RDS/IW: failed to setup listener, "
+ printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
"rdma_bind_addr() returned %d\n", ret);
goto out;
}
ret = rdma_listen(cm_id, 128);
if (ret) {
- printk(KERN_ERR "RDS/IW: failed to setup listener, "
+ printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
"rdma_listen() returned %d\n", ret);
goto out;
}
diff --git a/net/rds/recv.c b/net/rds/recv.c
index f2118c51cfa3..86bc1a06ebbd 100644
--- a/net/rds/recv.c
+++ b/net/rds/recv.c
@@ -409,18 +409,18 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
if (msg_flags & MSG_OOB)
goto out;
- /* If there are pending notifications, do those - and nothing else */
- if (!list_empty(&rs->rs_notify_queue)) {
- ret = rds_notify_queue_get(rs, msg);
- goto out;
- }
+ while (1) {
+ /* If there are pending notifications, do those - and nothing else */
+ if (!list_empty(&rs->rs_notify_queue)) {
+ ret = rds_notify_queue_get(rs, msg);
+ break;
+ }
- if (rs->rs_cong_notify) {
- ret = rds_notify_cong(rs, msg);
- goto out;
- }
+ if (rs->rs_cong_notify) {
+ ret = rds_notify_cong(rs, msg);
+ break;
+ }
- while (1) {
if (!rds_next_incoming(rs, &inc)) {
if (nonblock) {
ret = -EAGAIN;
@@ -428,7 +428,9 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
}
timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
- rds_next_incoming(rs, &inc),
+ (!list_empty(&rs->rs_notify_queue)
+ || rs->rs_cong_notify
+ || rds_next_incoming(rs, &inc)),
timeo);
rdsdebug("recvmsg woke inc %p timeo %ld\n", inc,
timeo);
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 79693fe2001e..044de1c6af3d 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -549,6 +549,10 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
swprev = !!(rfkill->state & RFKILL_BLOCK_SW);
hwprev = !!(rfkill->state & RFKILL_BLOCK_HW);
__rfkill_set_sw_state(rfkill, sw);
+ if (hw)
+ rfkill->state |= RFKILL_BLOCK_HW;
+ else
+ rfkill->state &= ~RFKILL_BLOCK_HW;
spin_unlock_irqrestore(&rfkill->lock, flags);
@@ -648,15 +652,26 @@ static ssize_t rfkill_state_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- /*
- * The intention was that userspace can only take control over
- * a given device when/if rfkill-input doesn't control it due
- * to user_claim. Since user_claim is currently unsupported,
- * we never support changing the state from userspace -- this
- * can be implemented again later.
- */
+ struct rfkill *rfkill = to_rfkill(dev);
+ unsigned long state;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
- return -EPERM;
+ err = strict_strtoul(buf, 0, &state);
+ if (err)
+ return err;
+
+ if (state != RFKILL_USER_STATE_SOFT_BLOCKED &&
+ state != RFKILL_USER_STATE_UNBLOCKED)
+ return -EINVAL;
+
+ mutex_lock(&rfkill_global_mutex);
+ rfkill_set_block(rfkill, state == RFKILL_USER_STATE_SOFT_BLOCKED);
+ mutex_unlock(&rfkill_global_mutex);
+
+ return err ?: count;
}
static ssize_t rfkill_claim_show(struct device *dev,
@@ -1076,10 +1091,16 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
struct rfkill_event ev;
/* we don't need the 'hard' variable but accept it */
- if (count < sizeof(ev) - 1)
+ if (count < RFKILL_EVENT_SIZE_V1 - 1)
return -EINVAL;
- if (copy_from_user(&ev, buf, sizeof(ev) - 1))
+ /*
+ * Copy as much data as we can accept into our 'ev' buffer,
+ * but tell userspace how much we've copied so it can determine
+ * our API version even in a write() call, if it cares.
+ */
+ count = min(count, sizeof(ev));
+ if (copy_from_user(&ev, buf, count))
return -EFAULT;
if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL)
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 6bd8e93869ed..f0a76f6bca71 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -92,23 +92,21 @@ static void rose_set_lockdep_key(struct net_device *dev)
/*
* Convert a ROSE address into text.
*/
-const char *rose2asc(const rose_address *addr)
+char *rose2asc(char *buf, const rose_address *addr)
{
- static char buffer[11];
-
if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 &&
addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 &&
addr->rose_addr[4] == 0x00) {
- strcpy(buffer, "*");
+ strcpy(buf, "*");
} else {
- sprintf(buffer, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
+ sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
addr->rose_addr[1] & 0xFF,
addr->rose_addr[2] & 0xFF,
addr->rose_addr[3] & 0xFF,
addr->rose_addr[4] & 0xFF);
}
- return buffer;
+ return buf;
}
/*
@@ -1437,7 +1435,7 @@ static void rose_info_stop(struct seq_file *seq, void *v)
static int rose_info_show(struct seq_file *seq, void *v)
{
- char buf[11];
+ char buf[11], rsbuf[11];
if (v == SEQ_START_TOKEN)
seq_puts(seq,
@@ -1455,8 +1453,8 @@ static int rose_info_show(struct seq_file *seq, void *v)
devname = dev->name;
seq_printf(seq, "%-10s %-9s ",
- rose2asc(&rose->dest_addr),
- ax2asc(buf, &rose->dest_call));
+ rose2asc(rsbuf, &rose->dest_addr),
+ ax2asc(buf, &rose->dest_call));
if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
callsign = "??????-?";
@@ -1465,7 +1463,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
- rose2asc(&rose->source_addr),
+ rose2asc(rsbuf, &rose->source_addr),
callsign,
devname,
rose->lci & 0x0FFF,
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 389d6e0d7740..c711e2edf5ce 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -141,7 +141,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb(skb);
stats->tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
static const struct header_ops rose_header_ops = {
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index a81066a1010a..9478d9b3d977 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -1104,6 +1104,7 @@ static void rose_node_stop(struct seq_file *seq, void *v)
static int rose_node_show(struct seq_file *seq, void *v)
{
+ char rsbuf[11];
int i;
if (v == SEQ_START_TOKEN)
@@ -1112,13 +1113,13 @@ static int rose_node_show(struct seq_file *seq, void *v)
const struct rose_node *rose_node = v;
/* if (rose_node->loopback) {
seq_printf(seq, "%-10s %04d 1 loopback\n",
- rose2asc(&rose_node->address),
- rose_node->mask);
+ rose2asc(rsbuf, &rose_node->address),
+ rose_node->mask);
} else { */
seq_printf(seq, "%-10s %04d %d",
- rose2asc(&rose_node->address),
- rose_node->mask,
- rose_node->count);
+ rose2asc(rsbuf, &rose_node->address),
+ rose_node->mask,
+ rose_node->count);
for (i = 0; i < rose_node->count; i++)
seq_printf(seq, " %05d",
@@ -1267,7 +1268,7 @@ static void rose_route_stop(struct seq_file *seq, void *v)
static int rose_route_show(struct seq_file *seq, void *v)
{
- char buf[11];
+ char buf[11], rsbuf[11];
if (v == SEQ_START_TOKEN)
seq_puts(seq,
@@ -1279,7 +1280,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%3.3X %-10s %-9s %05d ",
rose_route->lci1,
- rose2asc(&rose_route->src_addr),
+ rose2asc(rsbuf, &rose_route->src_addr),
ax2asc(buf, &rose_route->src_call),
rose_route->neigh1->number);
else
@@ -1289,10 +1290,10 @@ static int rose_route_show(struct seq_file *seq, void *v)
if (rose_route->neigh2)
seq_printf(seq,
"%3.3X %-10s %-9s %05d\n",
- rose_route->lci2,
- rose2asc(&rose_route->dest_addr),
- ax2asc(buf, &rose_route->dest_call),
- rose_route->neigh2->number);
+ rose_route->lci2,
+ rose2asc(rsbuf, &rose_route->dest_addr),
+ ax2asc(buf, &rose_route->dest_call),
+ rose_route->neigh2->number);
else
seq_puts(seq,
"000 * * 00000\n");
diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c
index d9231245a79a..bc0019f704fe 100644
--- a/net/rxrpc/ar-call.c
+++ b/net/rxrpc/ar-call.c
@@ -96,7 +96,7 @@ static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)
}
/*
- * allocate a new client call and attempt to to get a connection slot for it
+ * allocate a new client call and attempt to get a connection slot for it
*/
static struct rxrpc_call *rxrpc_alloc_client_call(
struct rxrpc_sock *rx,
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 362c2811b2df..4ee3170803f8 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -77,7 +77,7 @@
* The service curve parameters are converted to the internal
* representation. The slope values are scaled to avoid overflow.
* the inverse slope values as well as the y-projection of the 1st
- * segment are kept in order to to avoid 64-bit divide operations
+ * segment are kept in order to avoid 64-bit divide operations
* that are expensive on 32-bit architectures.
*/
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 9c002b6e0533..12434b6c2042 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -314,7 +314,7 @@ restart:
netif_wake_queue(dev);
txq->tx_packets++;
txq->tx_bytes += length;
- return 0;
+ return NETDEV_TX_OK;
}
__netif_tx_unlock(slave_txq);
}
@@ -323,7 +323,7 @@ restart:
break;
case 1:
master->slaves = NEXT_SLAVE(q);
- return 0;
+ return NETDEV_TX_OK;
default:
nores = 1;
break;
@@ -345,7 +345,7 @@ restart:
drop:
txq->tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int teql_master_open(struct net_device *dev)
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 23128ee191ae..99a826dcc32e 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -432,29 +432,49 @@ static void svc_tcp_write_space(struct sock *sk)
}
/*
+ * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
+ */
+static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
+ struct cmsghdr *cmh)
+{
+ struct in_pktinfo *pki = CMSG_DATA(cmh);
+ if (cmh->cmsg_type != IP_PKTINFO)
+ return 0;
+ rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
+ return 1;
+}
+
+/*
+ * See net/ipv6/datagram.c : datagram_recv_ctl
+ */
+static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
+ struct cmsghdr *cmh)
+{
+ struct in6_pktinfo *pki = CMSG_DATA(cmh);
+ if (cmh->cmsg_type != IPV6_PKTINFO)
+ return 0;
+ ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
+ return 1;
+}
+
+/*
* Copy the UDP datagram's destination address to the rqstp structure.
* The 'destination' address in this case is the address to which the
* peer sent the datagram, i.e. our local address. For multihomed
* hosts, this can change from msg to msg. Note that only the IP
* address changes, the port number should remain the same.
*/
-static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
- struct cmsghdr *cmh)
+static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
+ struct cmsghdr *cmh)
{
- struct svc_sock *svsk =
- container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
- switch (svsk->sk_sk->sk_family) {
- case AF_INET: {
- struct in_pktinfo *pki = CMSG_DATA(cmh);
- rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
- break;
- }
- case AF_INET6: {
- struct in6_pktinfo *pki = CMSG_DATA(cmh);
- ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
- break;
- }
+ switch (cmh->cmsg_level) {
+ case SOL_IP:
+ return svc_udp_get_dest_address4(rqstp, cmh);
+ case SOL_IPV6:
+ return svc_udp_get_dest_address6(rqstp, cmh);
}
+
+ return 0;
}
/*
@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
rqstp->rq_prot = IPPROTO_UDP;
- if (cmh->cmsg_level != IPPROTO_IP ||
- cmh->cmsg_type != IP_PKTINFO) {
+ if (!svc_udp_get_dest_address(rqstp, cmh)) {
if (net_ratelimit())
- printk("rpcsvc: received unknown control message:"
- "%d/%d\n",
- cmh->cmsg_level, cmh->cmsg_type);
+ printk(KERN_WARNING
+ "svc: received unknown control message %d/%d; "
+ "dropping RPC reply datagram\n",
+ cmh->cmsg_level, cmh->cmsg_type);
skb_free_datagram(svsk->sk_sk, skb);
return 0;
}
- svc_udp_get_dest_address(rqstp, cmh);
if (skb_is_nonlinear(skb)) {
/* we have to copy */
@@ -651,8 +670,7 @@ static struct svc_xprt_class svc_udp_class = {
static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
{
- int one = 1;
- mm_segment_t oldfs;
+ int err, level, optname, one = 1;
svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
@@ -671,12 +689,22 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
- oldfs = get_fs();
- set_fs(KERNEL_DS);
/* make sure we get destination address info */
- svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO,
- (char __user *)&one, sizeof(one));
- set_fs(oldfs);
+ switch (svsk->sk_sk->sk_family) {
+ case AF_INET:
+ level = SOL_IP;
+ optname = IP_PKTINFO;
+ break;
+ case AF_INET6:
+ level = SOL_IPV6;
+ optname = IPV6_RECVPKTINFO;
+ break;
+ default:
+ BUG();
+ }
+ err = kernel_setsockopt(svsk->sk_sock, level, optname,
+ (char *)&one, sizeof(one));
+ dprintk("svc: kernel_setsockopt returned %d\n", err);
}
/*
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 5151f9f6c573..0cf5e8c27a10 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -730,12 +730,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
goto err;
mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
- if (!mr)
+ if (IS_ERR(mr))
goto err_free_frmr;
pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
RPCSVC_MAXPAGES);
- if (!pl)
+ if (IS_ERR(pl))
goto err_free_mr;
frmr->mr = mr;
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 3c57005e44d1..7bda8e3d1398 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -62,7 +62,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
rep_nlh = nlmsg_hdr(rep_buf);
memcpy(rep_nlh, req_nlh, hdr_space);
rep_nlh->nlmsg_len = rep_buf->len;
- genlmsg_unicast(rep_buf, NETLINK_CB(skb).pid);
+ genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid);
}
return 0;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 1848693ebb82..e8254e809b79 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1748,6 +1748,12 @@ static int getsockopt(struct socket *sock,
value = jiffies_to_msecs(sk->sk_rcvtimeo);
/* no need to set "res", since already 0 at this point */
break;
+ case TIPC_NODE_RECVQ_DEPTH:
+ value = (u32)atomic_read(&tipc_queue_size);
+ break;
+ case TIPC_SOCK_RECVQ_DEPTH:
+ value = skb_queue_len(&sk->sk_receive_queue);
+ break;
default:
res = -EINVAL;
}
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 4428dd5e911d..c6031d5b135f 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -2,6 +2,21 @@ config CFG80211
tristate "Improved wireless configuration API"
depends on RFKILL || !RFKILL
+config NL80211_TESTMODE
+ bool "nl80211 testmode command"
+ depends on CFG80211
+ help
+ The nl80211 testmode command helps implementing things like
+ factory calibration or validation tools for wireless chips.
+
+ Select this option ONLY for kernels that are specifically
+ built for such purposes.
+
+ Debugging tools that are supposed to end up in the hands of
+ users should better be implemented with debugfs.
+
+ Say N.
+
config CFG80211_REG_DEBUG
bool "cfg80211 regulatory debugging"
depends on CFG80211
@@ -11,6 +26,22 @@ config CFG80211_REG_DEBUG
If unsure, say N.
+config CFG80211_DEFAULT_PS
+ bool "enable powersave by default"
+ depends on CFG80211
+ default y
+ help
+ This option enables powersave mode by default.
+
+ If this causes your applications to misbehave you should fix your
+ 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
@@ -35,19 +66,13 @@ config WIRELESS_OLD_REGULATORY
config WIRELESS_EXT
bool "Wireless extensions"
- default n
+ default y
---help---
This option enables the legacy wireless extensions
(wireless network interface configuration via ioctls.)
- Wireless extensions will be replaced by cfg80211 and
- will be required only by legacy drivers that implement
- wireless extension handlers. This option does not
- affect the wireless-extension backward compatibility
- code in cfg80211.
-
- Say N (if you can) unless you know you need wireless
- extensions for external modules.
+ Say Y unless you've upgraded all your userspace to use
+ nl80211 instead of wireless extensions.
config WIRELESS_EXT_SYSFS
bool "Wireless extensions sysfs files"
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index f78c4832a9ca..d74cc77fa57a 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,8 +5,8 @@ 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
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
-cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
+cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d5850292b3df..f9fee65dc06a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -19,6 +19,7 @@
#include "core.h"
#include "sysfs.h"
#include "debugfs.h"
+#include "wext-compat.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -30,10 +31,10 @@ MODULE_DESCRIPTION("wireless configuration support");
/* RCU might be appropriate here since we usually
* only read the list, and that can happen quite
* often because we need to do it for each command */
-LIST_HEAD(cfg80211_drv_list);
+LIST_HEAD(cfg80211_rdev_list);
/*
- * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
+ * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain,
* country_ie_regdomain, the reg_beacon_list and the the last regulatory
* request receipt (last_request).
*/
@@ -43,18 +44,18 @@ DEFINE_MUTEX(cfg80211_mutex);
static struct dentry *ieee80211_debugfs_dir;
/* requires cfg80211_mutex to be held! */
-struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
+struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
{
- struct cfg80211_registered_device *result = NULL, *drv;
+ struct cfg80211_registered_device *result = NULL, *rdev;
if (!wiphy_idx_valid(wiphy_idx))
return NULL;
assert_cfg80211_lock();
- list_for_each_entry(drv, &cfg80211_drv_list, list) {
- if (drv->wiphy_idx == wiphy_idx) {
- result = drv;
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (rdev->wiphy_idx == wiphy_idx) {
+ result = rdev;
break;
}
}
@@ -64,32 +65,32 @@ struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
int get_wiphy_idx(struct wiphy *wiphy)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
if (!wiphy)
return WIPHY_IDX_STALE;
- drv = wiphy_to_dev(wiphy);
- return drv->wiphy_idx;
+ rdev = wiphy_to_dev(wiphy);
+ return rdev->wiphy_idx;
}
-/* requires cfg80211_drv_mutex to be held! */
+/* requires cfg80211_rdev_mutex to be held! */
struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
if (!wiphy_idx_valid(wiphy_idx))
return NULL;
assert_cfg80211_lock();
- drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);
- if (!drv)
+ rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
+ if (!rdev)
return NULL;
- return &drv->wiphy;
+ return &rdev->wiphy;
}
/* requires cfg80211_mutex to be held! */
struct cfg80211_registered_device *
-__cfg80211_drv_from_info(struct genl_info *info)
+__cfg80211_rdev_from_info(struct genl_info *info)
{
int ifindex;
struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
@@ -99,14 +100,14 @@ __cfg80211_drv_from_info(struct genl_info *info)
assert_cfg80211_lock();
if (info->attrs[NL80211_ATTR_WIPHY]) {
- bywiphyidx = cfg80211_drv_by_wiphy_idx(
+ bywiphyidx = cfg80211_rdev_by_wiphy_idx(
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
err = -ENODEV;
}
if (info->attrs[NL80211_ATTR_IFINDEX]) {
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(genl_info_net(info), ifindex);
if (dev) {
if (dev->ieee80211_ptr)
byifidx =
@@ -134,54 +135,48 @@ __cfg80211_drv_from_info(struct genl_info *info)
struct cfg80211_registered_device *
cfg80211_get_dev_from_info(struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
mutex_lock(&cfg80211_mutex);
- drv = __cfg80211_drv_from_info(info);
+ rdev = __cfg80211_rdev_from_info(info);
/* if it is not an error we grab the lock on
* it to assure it won't be going away while
* we operate on it */
- if (!IS_ERR(drv))
- mutex_lock(&drv->mtx);
+ if (!IS_ERR(rdev))
+ mutex_lock(&rdev->mtx);
mutex_unlock(&cfg80211_mutex);
- return drv;
+ return rdev;
}
struct cfg80211_registered_device *
-cfg80211_get_dev_from_ifindex(int ifindex)
+cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
{
- struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
+ struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
struct net_device *dev;
mutex_lock(&cfg80211_mutex);
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(net, ifindex);
if (!dev)
goto out;
if (dev->ieee80211_ptr) {
- drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
- mutex_lock(&drv->mtx);
+ rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+ mutex_lock(&rdev->mtx);
} else
- drv = ERR_PTR(-ENODEV);
+ rdev = ERR_PTR(-ENODEV);
dev_put(dev);
out:
mutex_unlock(&cfg80211_mutex);
- return drv;
-}
-
-void cfg80211_put_dev(struct cfg80211_registered_device *drv)
-{
- BUG_ON(IS_ERR(drv));
- mutex_unlock(&drv->mtx);
+ return rdev;
}
/* requires cfg80211_mutex to be held */
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev2;
int wiphy_idx, taken = -1, result, digits;
assert_cfg80211_lock();
@@ -207,8 +202,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
return 0;
/* Ensure another device does not already have this name. */
- list_for_each_entry(drv, &cfg80211_drv_list, list)
- if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+ list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+ if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
return -EINVAL;
result = device_rename(&rdev->wiphy.dev, newname);
@@ -228,28 +223,64 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
return 0;
}
+int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
+ struct net *net)
+{
+ struct wireless_dev *wdev;
+ int err = 0;
+
+ if (!rdev->wiphy.netnsok)
+ return -EOPNOTSUPP;
+
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
+ err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
+ if (err)
+ break;
+ wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
+ }
+
+ if (err) {
+ /* failed -- clean up to old netns */
+ net = wiphy_net(&rdev->wiphy);
+
+ list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list,
+ list) {
+ wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
+ err = dev_change_net_namespace(wdev->netdev, net,
+ "wlan%d");
+ WARN_ON(err);
+ wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
+ }
+ }
+
+ wiphy_net_set(&rdev->wiphy, net);
+
+ return err;
+}
+
static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
{
- struct cfg80211_registered_device *drv = data;
+ struct cfg80211_registered_device *rdev = data;
- drv->ops->rfkill_poll(&drv->wiphy);
+ rdev->ops->rfkill_poll(&rdev->wiphy);
}
static int cfg80211_rfkill_set_block(void *data, bool blocked)
{
- struct cfg80211_registered_device *drv = data;
+ struct cfg80211_registered_device *rdev = data;
struct wireless_dev *wdev;
if (!blocked)
return 0;
rtnl_lock();
- mutex_lock(&drv->devlist_mtx);
+ mutex_lock(&rdev->devlist_mtx);
- list_for_each_entry(wdev, &drv->netdev_list, list)
+ list_for_each_entry(wdev, &rdev->netdev_list, list)
dev_close(wdev->netdev);
- mutex_unlock(&drv->devlist_mtx);
+ mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();
return 0;
@@ -257,10 +288,75 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
static void cfg80211_rfkill_sync_work(struct work_struct *work)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync);
+ cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
+}
+
+static void cfg80211_process_events(struct wireless_dev *wdev)
+{
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ while (!list_empty(&wdev->event_list)) {
+ ev = list_first_entry(&wdev->event_list,
+ struct cfg80211_event, list);
+ list_del(&ev->list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+
+ wdev_lock(wdev);
+ switch (ev->type) {
+ case EVENT_CONNECT_RESULT:
+ __cfg80211_connect_result(
+ wdev->netdev, ev->cr.bssid,
+ ev->cr.req_ie, ev->cr.req_ie_len,
+ ev->cr.resp_ie, ev->cr.resp_ie_len,
+ ev->cr.status,
+ ev->cr.status == WLAN_STATUS_SUCCESS);
+ break;
+ case EVENT_ROAMED:
+ __cfg80211_roamed(wdev, ev->rm.bssid,
+ ev->rm.req_ie, ev->rm.req_ie_len,
+ ev->rm.resp_ie, ev->rm.resp_ie_len);
+ break;
+ case EVENT_DISCONNECTED:
+ __cfg80211_disconnected(wdev->netdev,
+ ev->dc.ie, ev->dc.ie_len,
+ ev->dc.reason, true);
+ break;
+ case EVENT_IBSS_JOINED:
+ __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
+ break;
+ }
+ wdev_unlock(wdev);
+
+ kfree(ev);
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ }
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+}
+
+static void cfg80211_event_work(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
- drv = container_of(work, struct cfg80211_registered_device, rfkill_sync);
- cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
+ rdev = container_of(work, struct cfg80211_registered_device,
+ event_work);
+
+ rtnl_lock();
+ cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->devlist_mtx);
+
+ list_for_each_entry(wdev, &rdev->netdev_list, list)
+ cfg80211_process_events(wdev);
+
+ mutex_unlock(&rdev->devlist_mtx);
+ cfg80211_unlock_rdev(rdev);
+ rtnl_unlock();
}
/* exported functions */
@@ -269,76 +365,86 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
{
static int wiphy_counter;
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int alloc_size;
- WARN_ON(!ops->add_key && ops->del_key);
- WARN_ON(ops->add_key && !ops->del_key);
+ WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
+ WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
+ WARN_ON(ops->connect && !ops->disconnect);
+ WARN_ON(ops->join_ibss && !ops->leave_ibss);
+ WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
+ WARN_ON(ops->add_station && !ops->del_station);
+ WARN_ON(ops->add_mpath && !ops->del_mpath);
- alloc_size = sizeof(*drv) + sizeof_priv;
+ alloc_size = sizeof(*rdev) + sizeof_priv;
- drv = kzalloc(alloc_size, GFP_KERNEL);
- if (!drv)
+ rdev = kzalloc(alloc_size, GFP_KERNEL);
+ if (!rdev)
return NULL;
- drv->ops = ops;
+ rdev->ops = ops;
mutex_lock(&cfg80211_mutex);
- drv->wiphy_idx = wiphy_counter++;
+ rdev->wiphy_idx = wiphy_counter++;
- if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
+ if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
wiphy_counter--;
mutex_unlock(&cfg80211_mutex);
/* ugh, wrapped! */
- kfree(drv);
+ kfree(rdev);
return NULL;
}
mutex_unlock(&cfg80211_mutex);
/* give it a proper name */
- dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
+ dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+
+ mutex_init(&rdev->mtx);
+ mutex_init(&rdev->devlist_mtx);
+ INIT_LIST_HEAD(&rdev->netdev_list);
+ spin_lock_init(&rdev->bss_lock);
+ INIT_LIST_HEAD(&rdev->bss_list);
+ INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
- mutex_init(&drv->mtx);
- mutex_init(&drv->devlist_mtx);
- INIT_LIST_HEAD(&drv->netdev_list);
- spin_lock_init(&drv->bss_lock);
- INIT_LIST_HEAD(&drv->bss_list);
+ device_initialize(&rdev->wiphy.dev);
+ rdev->wiphy.dev.class = &ieee80211_class;
+ rdev->wiphy.dev.platform_data = rdev;
- device_initialize(&drv->wiphy.dev);
- drv->wiphy.dev.class = &ieee80211_class;
- drv->wiphy.dev.platform_data = drv;
+ wiphy_net_set(&rdev->wiphy, &init_net);
- drv->rfkill_ops.set_block = cfg80211_rfkill_set_block;
- drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev),
- &drv->wiphy.dev, RFKILL_TYPE_WLAN,
- &drv->rfkill_ops, drv);
+ rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
+ rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
+ &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
+ &rdev->rfkill_ops, rdev);
- if (!drv->rfkill) {
- kfree(drv);
+ if (!rdev->rfkill) {
+ kfree(rdev);
return NULL;
}
- INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
+ INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
+ INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
+ INIT_WORK(&rdev->event_work, cfg80211_event_work);
/*
* Initialize wiphy parameters to IEEE 802.11 MIB default values.
* Fragmentation and RTS threshold are disabled by default with the
* special -1 value.
*/
- drv->wiphy.retry_short = 7;
- drv->wiphy.retry_long = 4;
- drv->wiphy.frag_threshold = (u32) -1;
- drv->wiphy.rts_threshold = (u32) -1;
+ rdev->wiphy.retry_short = 7;
+ rdev->wiphy.retry_long = 4;
+ rdev->wiphy.frag_threshold = (u32) -1;
+ rdev->wiphy.rts_threshold = (u32) -1;
- return &drv->wiphy;
+ return &rdev->wiphy;
}
EXPORT_SYMBOL(wiphy_new);
int wiphy_register(struct wiphy *wiphy)
{
- struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
int res;
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
@@ -346,9 +452,6 @@ int wiphy_register(struct wiphy *wiphy)
int i;
u16 ifmodes = wiphy->interface_modes;
- if (WARN_ON(wiphy->max_scan_ssids < 1))
- return -EINVAL;
-
/* sanity check ifmodes */
WARN_ON(!ifmodes);
ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -395,11 +498,11 @@ int wiphy_register(struct wiphy *wiphy)
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
- res = device_add(&drv->wiphy.dev);
+ res = device_add(&rdev->wiphy.dev);
if (res)
return res;
- res = rfkill_register(drv->rfkill);
+ res = rfkill_register(rdev->rfkill);
if (res)
goto out_rm_dev;
@@ -408,16 +511,16 @@ int wiphy_register(struct wiphy *wiphy)
/* set up regulatory info */
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
- list_add(&drv->list, &cfg80211_drv_list);
+ list_add(&rdev->list, &cfg80211_rdev_list);
mutex_unlock(&cfg80211_mutex);
/* add to debugfs */
- drv->wiphy.debugfsdir =
- debugfs_create_dir(wiphy_name(&drv->wiphy),
+ rdev->wiphy.debugfsdir =
+ debugfs_create_dir(wiphy_name(&rdev->wiphy),
ieee80211_debugfs_dir);
- if (IS_ERR(drv->wiphy.debugfsdir))
- drv->wiphy.debugfsdir = NULL;
+ if (IS_ERR(rdev->wiphy.debugfsdir))
+ rdev->wiphy.debugfsdir = NULL;
if (wiphy->custom_regulatory) {
struct regulatory_request request;
@@ -430,48 +533,48 @@ int wiphy_register(struct wiphy *wiphy)
nl80211_send_reg_change_event(&request);
}
- cfg80211_debugfs_drv_add(drv);
+ cfg80211_debugfs_rdev_add(rdev);
return 0;
out_rm_dev:
- device_del(&drv->wiphy.dev);
+ device_del(&rdev->wiphy.dev);
return res;
}
EXPORT_SYMBOL(wiphy_register);
void wiphy_rfkill_start_polling(struct wiphy *wiphy)
{
- struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- if (!drv->ops->rfkill_poll)
+ if (!rdev->ops->rfkill_poll)
return;
- drv->rfkill_ops.poll = cfg80211_rfkill_poll;
- rfkill_resume_polling(drv->rfkill);
+ rdev->rfkill_ops.poll = cfg80211_rfkill_poll;
+ rfkill_resume_polling(rdev->rfkill);
}
EXPORT_SYMBOL(wiphy_rfkill_start_polling);
void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
{
- struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- rfkill_pause_polling(drv->rfkill);
+ rfkill_pause_polling(rdev->rfkill);
}
EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
void wiphy_unregister(struct wiphy *wiphy)
{
- struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- rfkill_unregister(drv->rfkill);
+ rfkill_unregister(rdev->rfkill);
/* protect the device list */
mutex_lock(&cfg80211_mutex);
- BUG_ON(!list_empty(&drv->netdev_list));
+ BUG_ON(!list_empty(&rdev->netdev_list));
/*
- * Try to grab drv->mtx. If a command is still in progress,
+ * Try to grab rdev->mtx. If a command is still in progress,
* hopefully the driver will refuse it since it's tearing
* down the device already. We wait for this command to complete
* before unlinking the item from the list.
@@ -480,33 +583,38 @@ void wiphy_unregister(struct wiphy *wiphy)
* get to lock contention here if userspace issues a command
* that identified the hardware by wiphy index.
*/
- mutex_lock(&drv->mtx);
+ mutex_lock(&rdev->mtx);
/* unlock again before freeing */
- mutex_unlock(&drv->mtx);
+ mutex_unlock(&rdev->mtx);
- cfg80211_debugfs_drv_del(drv);
+ cfg80211_debugfs_rdev_del(rdev);
/* If this device got a regulatory hint tell core its
* free to listen now to a new shiny device regulatory hint */
reg_device_remove(wiphy);
- list_del(&drv->list);
- device_del(&drv->wiphy.dev);
- debugfs_remove(drv->wiphy.debugfsdir);
+ list_del(&rdev->list);
+ device_del(&rdev->wiphy.dev);
+ debugfs_remove(rdev->wiphy.debugfsdir);
mutex_unlock(&cfg80211_mutex);
+
+ cancel_work_sync(&rdev->conn_work);
+ cancel_work_sync(&rdev->scan_done_wk);
+ kfree(rdev->scan_req);
+ flush_work(&rdev->event_work);
}
EXPORT_SYMBOL(wiphy_unregister);
-void cfg80211_dev_free(struct cfg80211_registered_device *drv)
+void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
{
struct cfg80211_internal_bss *scan, *tmp;
- rfkill_destroy(drv->rfkill);
- mutex_destroy(&drv->mtx);
- mutex_destroy(&drv->devlist_mtx);
- list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
+ rfkill_destroy(rdev->rfkill);
+ mutex_destroy(&rdev->mtx);
+ mutex_destroy(&rdev->devlist_mtx);
+ list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&scan->pub);
- kfree(drv);
+ kfree(rdev);
}
void wiphy_free(struct wiphy *wiphy)
@@ -517,10 +625,10 @@ EXPORT_SYMBOL(wiphy_free);
void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
{
- struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- if (rfkill_set_hw_state(drv->rfkill, blocked))
- schedule_work(&drv->rfkill_sync);
+ if (rfkill_set_hw_state(rdev->rfkill, blocked))
+ schedule_work(&rdev->rfkill_sync);
}
EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
@@ -529,56 +637,106 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
void *ndev)
{
struct net_device *dev = ndev;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
- if (!dev->ieee80211_ptr)
+ if (!wdev)
return NOTIFY_DONE;
- rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+ rdev = wiphy_to_dev(wdev->wiphy);
- WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
+ WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
switch (state) {
case NETDEV_REGISTER:
+ mutex_init(&wdev->mtx);
+ INIT_LIST_HEAD(&wdev->event_list);
+ spin_lock_init(&wdev->event_lock);
mutex_lock(&rdev->devlist_mtx);
- list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
+ list_add(&wdev->list, &rdev->netdev_list);
+ /* can only change netns with wiphy */
+ dev->features |= NETIF_F_NETNS_LOCAL;
+
if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211")) {
printk(KERN_ERR "wireless: failed to add phy80211 "
"symlink to netdev!\n");
}
- dev->ieee80211_ptr->netdev = dev;
+ wdev->netdev = dev;
+ wdev->sme_state = CFG80211_SME_IDLE;
+ mutex_unlock(&rdev->devlist_mtx);
#ifdef CONFIG_WIRELESS_EXT
- dev->ieee80211_ptr->wext.default_key = -1;
- dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+ if (!dev->wireless_handlers)
+ dev->wireless_handlers = &cfg80211_wext_handler;
+ wdev->wext.default_key = -1;
+ wdev->wext.default_mgmt_key = -1;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+ wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE;
+ wdev->wext.ps_timeout = 500;
+ if (rdev->ops->set_power_mgmt)
+ if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
+ wdev->wext.ps,
+ wdev->wext.ps_timeout)) {
+ /* assume this means it's off */
+ wdev->wext.ps = false;
+ }
#endif
- mutex_unlock(&rdev->devlist_mtx);
break;
case NETDEV_GOING_DOWN:
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ cfg80211_leave_ibss(rdev, dev, true);
break;
- if (!dev->ieee80211_ptr->ssid_len)
+ case NL80211_IFTYPE_STATION:
+ wdev_lock(wdev);
+#ifdef CONFIG_WIRELESS_EXT
+ kfree(wdev->wext.ie);
+ wdev->wext.ie = NULL;
+ wdev->wext.ie_len = 0;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+#endif
+ __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, true);
+ cfg80211_mlme_down(rdev, dev);
+ wdev_unlock(wdev);
break;
- cfg80211_leave_ibss(rdev, dev, true);
+ default:
+ break;
+ }
break;
case NETDEV_UP:
#ifdef CONFIG_WIRELESS_EXT
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ cfg80211_lock_rdev(rdev);
+ wdev_lock(wdev);
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ cfg80211_ibss_wext_join(rdev, wdev);
break;
- if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
+ case NL80211_IFTYPE_STATION:
+ cfg80211_mgd_wext_connect(rdev, wdev);
break;
- cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
- break;
+ default:
+ break;
+ }
+ wdev_unlock(wdev);
+ cfg80211_unlock_rdev(rdev);
#endif
+ break;
case NETDEV_UNREGISTER:
mutex_lock(&rdev->devlist_mtx);
- if (!list_empty(&dev->ieee80211_ptr->list)) {
+ if (!list_empty(&wdev->list)) {
sysfs_remove_link(&dev->dev.kobj, "phy80211");
- list_del_init(&dev->ieee80211_ptr->list);
+ list_del_init(&wdev->list);
}
mutex_unlock(&rdev->devlist_mtx);
+ mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+ kfree(wdev->wext.keys);
+#endif
break;
case NETDEV_PRE_UP:
+ if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
+ return notifier_from_errno(-EOPNOTSUPP);
if (rfkill_blocked(rdev->rfkill))
return notifier_from_errno(-ERFKILL);
break;
@@ -591,10 +749,32 @@ static struct notifier_block cfg80211_netdev_notifier = {
.notifier_call = cfg80211_netdev_notifier_call,
};
-static int cfg80211_init(void)
+static void __net_exit cfg80211_pernet_exit(struct net *net)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rtnl_lock();
+ mutex_lock(&cfg80211_mutex);
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (net_eq(wiphy_net(&rdev->wiphy), net))
+ WARN_ON(cfg80211_switch_netns(rdev, &init_net));
+ }
+ mutex_unlock(&cfg80211_mutex);
+ rtnl_unlock();
+}
+
+static struct pernet_operations cfg80211_pernet_ops = {
+ .exit = cfg80211_pernet_exit,
+};
+
+static int __init cfg80211_init(void)
{
int err;
+ err = register_pernet_device(&cfg80211_pernet_ops);
+ if (err)
+ goto out_fail_pernet;
+
err = wiphy_sysfs_init();
if (err)
goto out_fail_sysfs;
@@ -622,9 +802,10 @@ out_fail_nl80211:
out_fail_notifier:
wiphy_sysfs_exit();
out_fail_sysfs:
+ unregister_pernet_device(&cfg80211_pernet_ops);
+out_fail_pernet:
return err;
}
-
subsys_initcall(cfg80211_init);
static void cfg80211_exit(void)
@@ -634,5 +815,6 @@ static void cfg80211_exit(void)
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
wiphy_sysfs_exit();
regulatory_exit();
+ unregister_pernet_device(&cfg80211_pernet_ops);
}
module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index bfa340c7abb5..6d903c1d721d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -57,6 +57,17 @@ struct cfg80211_registered_device {
u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
unsigned long suspend_at;
+ struct work_struct scan_done_wk;
+
+#ifdef CONFIG_NL80211_TESTMODE
+ struct genl_info *testmode_info;
+#endif
+
+ struct work_struct conn_work;
+ struct work_struct event_work;
+
+ /* current channel */
+ struct ieee80211_channel *channel;
#ifdef CONFIG_CFG80211_DEBUGFS
/* Debugfs entries */
@@ -89,13 +100,13 @@ bool wiphy_idx_valid(int wiphy_idx)
}
extern struct mutex cfg80211_mutex;
-extern struct list_head cfg80211_drv_list;
+extern struct list_head cfg80211_rdev_list;
#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex))
/*
* You can use this to mark a wiphy_idx as not having an associated wiphy.
- * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL
+ * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL
*/
#define WIPHY_IDX_STALE -1
@@ -104,17 +115,35 @@ struct cfg80211_internal_bss {
struct rb_node rbn;
unsigned long ts;
struct kref ref;
- bool hold, ies_allocated;
+ atomic_t hold;
+ bool ies_allocated;
/* must be last because of priv member */
struct cfg80211_bss pub;
};
-struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
+static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub)
+{
+ return container_of(pub, struct cfg80211_internal_bss, pub);
+}
+
+static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
+{
+ atomic_inc(&bss->hold);
+}
+
+static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
+{
+ int r = atomic_dec_return(&bss->hold);
+ WARN_ON(r < 0);
+}
+
+
+struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx);
int get_wiphy_idx(struct wiphy *wiphy);
struct cfg80211_registered_device *
-__cfg80211_drv_from_info(struct genl_info *info);
+__cfg80211_rdev_from_info(struct genl_info *info);
/*
* This function returns a pointer to the driver
@@ -122,12 +151,12 @@ __cfg80211_drv_from_info(struct genl_info *info);
* If successful, it returns non-NULL and also locks
* the driver's mutex!
*
- * This means that you need to call cfg80211_put_dev()
+ * This means that you need to call cfg80211_unlock_rdev()
* before being allowed to acquire &cfg80211_mutex!
*
* This is necessary because we need to lock the global
* mutex to get an item off the list safely, and then
- * we lock the drv mutex so it doesn't go away under us.
+ * we lock the rdev mutex so it doesn't go away under us.
*
* We don't want to keep cfg80211_mutex locked
* for all the time in order to allow requests on
@@ -139,19 +168,93 @@ __cfg80211_drv_from_info(struct genl_info *info);
extern struct cfg80211_registered_device *
cfg80211_get_dev_from_info(struct genl_info *info);
-/* requires cfg80211_drv_mutex to be held! */
+/* requires cfg80211_rdev_mutex to be held! */
struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
/* identical to cfg80211_get_dev_from_info but only operate on ifindex */
extern struct cfg80211_registered_device *
-cfg80211_get_dev_from_ifindex(int ifindex);
+cfg80211_get_dev_from_ifindex(struct net *net, int ifindex);
+
+int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
+ struct net *net);
+
+static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev)
+{
+ mutex_lock(&rdev->mtx);
+}
+
+static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev)
+{
+ BUG_ON(IS_ERR(rdev) || !rdev);
+ mutex_unlock(&rdev->mtx);
+}
+
+static inline void wdev_lock(struct wireless_dev *wdev)
+ __acquires(wdev)
+{
+ mutex_lock(&wdev->mtx);
+ __acquire(wdev->mtx);
+}
+
+static inline void wdev_unlock(struct wireless_dev *wdev)
+ __releases(wdev)
+{
+ __release(wdev->mtx);
+ mutex_unlock(&wdev->mtx);
+}
+
+#define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx));
+#define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx));
+
+enum cfg80211_event_type {
+ EVENT_CONNECT_RESULT,
+ EVENT_ROAMED,
+ EVENT_DISCONNECTED,
+ EVENT_IBSS_JOINED,
+};
+
+struct cfg80211_event {
+ struct list_head list;
+ enum cfg80211_event_type type;
+
+ union {
+ struct {
+ u8 bssid[ETH_ALEN];
+ const u8 *req_ie;
+ const u8 *resp_ie;
+ size_t req_ie_len;
+ size_t resp_ie_len;
+ u16 status;
+ } cr;
+ struct {
+ u8 bssid[ETH_ALEN];
+ const u8 *req_ie;
+ const u8 *resp_ie;
+ size_t req_ie_len;
+ size_t resp_ie_len;
+ } rm;
+ struct {
+ const u8 *ie;
+ size_t ie_len;
+ u16 reason;
+ } dc;
+ struct {
+ u8 bssid[ETH_ALEN];
+ } ij;
+ };
+};
+
+struct cfg80211_cached_keys {
+ struct key_params params[6];
+ u8 data[6][WLAN_MAX_KEY_LEN];
+ int def, defmgmt;
+};
-extern void cfg80211_put_dev(struct cfg80211_registered_device *drv);
/* free object */
-extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
+extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
-extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
+extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname);
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
@@ -163,15 +266,98 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
unsigned long age_secs);
/* IBSS */
+int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params,
+ struct cfg80211_cached_keys *connkeys);
int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- struct cfg80211_ibss_params *params);
+ struct cfg80211_ibss_params *params,
+ struct cfg80211_cached_keys *connkeys);
void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext);
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
+/* MLME */
+int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_auth_type auth_type,
+ const u8 *bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len,
+ const u8 *key, int key_len, int key_idx);
+int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, struct ieee80211_channel *chan,
+ enum nl80211_auth_type auth_type, const u8 *bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len,
+ const u8 *key, int key_len, int key_idx);
+int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ const u8 *bssid, const u8 *prev_bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len, bool use_mfp,
+ struct cfg80211_crypto_settings *crypt);
+int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, struct ieee80211_channel *chan,
+ const u8 *bssid, const u8 *prev_bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len, bool use_mfp,
+ struct cfg80211_crypto_settings *crypt);
+int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason);
+int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason);
+int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason);
+void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
+ struct net_device *dev);
+void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, bool wextev);
+
+/* SME */
+int __cfg80211_connect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_connect_params *connect,
+ struct cfg80211_cached_keys *connkeys);
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_connect_params *connect,
+ struct cfg80211_cached_keys *connkeys);
+int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u16 reason,
+ bool wextev);
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u16 reason,
+ bool wextev);
+void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len);
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
+void cfg80211_conn_work(struct work_struct *work);
/* internal helpers */
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ struct key_params *params, int key_idx,
const u8 *mac_addr);
+void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
+ size_t ie_len, u16 reason, bool from_ap);
+void cfg80211_sme_scan_done(struct net_device *dev);
+void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_sme_disassoc(struct net_device *dev, int idx);
+void __cfg80211_scan_done(struct work_struct *wk);
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 679ddfcec1ee..13d93d84f902 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -104,15 +104,15 @@ static const struct file_operations ht40allow_map_ops = {
};
#define DEBUGFS_ADD(name) \
- drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \
- &drv->wiphy, &name## _ops);
+ rdev->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \
+ &rdev->wiphy, &name## _ops);
#define DEBUGFS_DEL(name) \
- debugfs_remove(drv->debugfs.name); \
- drv->debugfs.name = NULL;
+ debugfs_remove(rdev->debugfs.name); \
+ rdev->debugfs.name = NULL;
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
{
- struct dentry *phyd = drv->wiphy.debugfsdir;
+ struct dentry *phyd = rdev->wiphy.debugfsdir;
DEBUGFS_ADD(rts_threshold);
DEBUGFS_ADD(fragmentation_threshold);
@@ -121,7 +121,7 @@ void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
DEBUGFS_ADD(ht40allow_map);
}
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv)
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev)
{
DEBUGFS_DEL(rts_threshold);
DEBUGFS_DEL(fragmentation_threshold);
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h
index c226983ae66b..6419b6d6ce3e 100644
--- a/net/wireless/debugfs.h
+++ b/net/wireless/debugfs.h
@@ -2,13 +2,13 @@
#define __CFG80211_DEBUGFS_H
#ifdef CONFIG_CFG80211_DEBUGFS
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv);
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv);
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev);
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev);
#else
static inline
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {}
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {}
static inline
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {}
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) {}
#endif
#endif /* __CFG80211_DEBUGFS_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index a4a1c3498ff2..4d7a084b35e2 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -7,10 +7,11 @@
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <net/cfg80211.h>
+#include "wext-compat.h"
#include "nl80211.h"
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_bss *bss;
@@ -24,9 +25,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
if (WARN_ON(!wdev->ssid_len))
return;
- if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
- return;
-
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
wdev->ssid, wdev->ssid_len,
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
@@ -36,39 +34,69 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
}
- cfg80211_hold_bss(bss);
- wdev->current_bss = bss;
- memcpy(wdev->bssid, bssid, ETH_ALEN);
+ cfg80211_hold_bss(bss_from_pub(bss));
+ wdev->current_bss = bss_from_pub(bss);
- nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp);
+ cfg80211_upload_connect_keys(wdev);
+
+ nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
+ GFP_KERNEL);
#ifdef CONFIG_WIRELESS_EXT
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
#endif
}
+
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev), gfp);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_IBSS_JOINED;
+ memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ schedule_work(&rdev->event_work);
+}
EXPORT_SYMBOL(cfg80211_ibss_joined);
-int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
- struct net_device *dev,
- struct cfg80211_ibss_params *params)
+int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params,
+ struct cfg80211_cached_keys *connkeys)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
+ ASSERT_WDEV_LOCK(wdev);
+
if (wdev->ssid_len)
return -EALREADY;
+ if (WARN_ON(wdev->connect_keys))
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = connkeys;
+
#ifdef CONFIG_WIRELESS_EXT
wdev->wext.ibss.channel = params->channel;
#endif
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
-
- if (err)
+ if (err) {
+ wdev->connect_keys = NULL;
return err;
+ }
memcpy(wdev->ssid, params->ssid, params->ssid_len);
wdev->ssid_len = params->ssid_len;
@@ -76,45 +104,105 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
return 0;
}
-void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
+int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *params,
+ struct cfg80211_cached_keys *connkeys)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
+static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int i;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = NULL;
+
+ /*
+ * Delete all the keys ... pairwise keys can't really
+ * exist any more anyway, but default keys might.
+ */
+ if (rdev->ops->del_key)
+ for (i = 0; i < 6; i++)
+ rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
}
wdev->current_bss = NULL;
wdev->ssid_len = 0;
- memset(wdev->bssid, 0, ETH_ALEN);
#ifdef CONFIG_WIRELESS_EXT
if (!nowext)
wdev->wext.ibss.ssid_len = 0;
#endif
}
-int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
- struct net_device *dev, bool nowext)
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ wdev_lock(wdev);
+ __cfg80211_clear_ibss(dev, nowext);
+ wdev_unlock(wdev);
+}
+
+static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, bool nowext)
{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!wdev->ssid_len)
+ return -ENOLINK;
+
err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
if (err)
return err;
- cfg80211_clear_ibss(dev, nowext);
+ __cfg80211_clear_ibss(dev, nowext);
return 0;
}
+int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, bool nowext)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_leave_ibss(rdev, dev, nowext);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
#ifdef CONFIG_WIRELESS_EXT
-static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev)
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
{
+ struct cfg80211_cached_keys *ck = NULL;
enum ieee80211_band band;
- int i;
+ int i, err;
+
+ ASSERT_WDEV_LOCK(wdev);
if (!wdev->wext.ibss.beacon_interval)
wdev->wext.ibss.beacon_interval = 100;
@@ -154,8 +242,24 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
if (!netif_running(wdev->netdev))
return 0;
- return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
- wdev->netdev, &wdev->wext.ibss);
+ if (wdev->wext.keys)
+ wdev->wext.keys->def = wdev->wext.default_key;
+
+ wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
+
+ if (wdev->wext.keys) {
+ ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+ if (!ck)
+ return -ENOMEM;
+ for (i = 0; i < 6; i++)
+ ck->params[i].key = ck->data[i];
+ }
+ err = __cfg80211_join_ibss(rdev, wdev->netdev,
+ &wdev->wext.ibss, ck);
+ if (err)
+ kfree(ck);
+
+ return err;
}
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -185,12 +289,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
if (wdev->wext.ibss.channel == chan)
return 0;
- if (wdev->ssid_len) {
- err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
- dev, true);
- if (err)
- return err;
- }
+ wdev_lock(wdev);
+ err = 0;
+ if (wdev->ssid_len)
+ err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ wdev_unlock(wdev);
+
+ if (err)
+ return err;
if (chan) {
wdev->wext.ibss.channel = chan;
@@ -200,10 +307,12 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
wdev->wext.ibss.channel_fixed = false;
}
- return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_lock(wdev);
+ err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_unlock(wdev);
+
+ return err;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
@@ -216,10 +325,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
return -EINVAL;
+ wdev_lock(wdev);
if (wdev->current_bss)
- chan = wdev->current_bss->channel;
+ chan = wdev->current_bss->pub.channel;
else if (wdev->wext.ibss.channel)
chan = wdev->wext.ibss.channel;
+ wdev_unlock(wdev);
if (chan) {
freq->m = chan->center_freq;
@@ -230,8 +341,6 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
/* no channel if not joining */
return -EINVAL;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
int cfg80211_ibss_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
@@ -248,12 +357,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
return -EOPNOTSUPP;
- if (wdev->ssid_len) {
- err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
- dev, true);
- if (err)
- return err;
- }
+ wdev_lock(wdev);
+ err = 0;
+ if (wdev->ssid_len)
+ err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ wdev_unlock(wdev);
+
+ if (err)
+ return err;
/* iwconfig uses nul termination in SSID.. */
if (len > 0 && ssid[len - 1] == '\0')
@@ -263,10 +375,12 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
memcpy(wdev->wext.ibss.ssid, ssid, len);
wdev->wext.ibss.ssid_len = len;
- return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_lock(wdev);
+ err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_unlock(wdev);
+
+ return err;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
int cfg80211_ibss_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
@@ -280,6 +394,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
data->flags = 0;
+ wdev_lock(wdev);
if (wdev->ssid_len) {
data->flags = 1;
data->length = wdev->ssid_len;
@@ -289,11 +404,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
data->length = wdev->wext.ibss.ssid_len;
memcpy(ssid, wdev->wext.ibss.ssid, data->length);
}
+ wdev_unlock(wdev);
return 0;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
int cfg80211_ibss_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
@@ -326,12 +440,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
return 0;
- if (wdev->ssid_len) {
- err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
- dev, true);
- if (err)
- return err;
- }
+ wdev_lock(wdev);
+ err = 0;
+ if (wdev->ssid_len)
+ err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+ dev, true);
+ wdev_unlock(wdev);
+
+ if (err)
+ return err;
if (bssid) {
memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
@@ -339,10 +456,12 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
} else
wdev->wext.ibss.bssid = NULL;
- return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_lock(wdev);
+ err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+ wdev_unlock(wdev);
+
+ return err;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
int cfg80211_ibss_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
@@ -356,14 +475,16 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
ap_addr->sa_family = ARPHRD_ETHER;
- if (wdev->wext.ibss.bssid) {
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
+ else if (wdev->wext.ibss.bssid)
memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
- return 0;
- }
+ else
+ memset(ap_addr->sa_data, 0, ETH_ALEN);
+
+ wdev_unlock(wdev);
- memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
return 0;
}
-/* temporary symbol - mark GPL - in the future the handler won't be */
-EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
#endif
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 42184361a109..097a87d7bae1 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -8,75 +8,622 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/nl80211.h>
+#include <linux/wireless.h>
#include <net/cfg80211.h>
+#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_rx_auth(rdev, dev, buf, len);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ u8 *bssid = mgmt->bssid;
+ int i;
+ u16 status = le16_to_cpu(mgmt->u.auth.status_code);
+ bool done = false;
+
+ wdev_lock(wdev);
+
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->authtry_bsses[i] &&
+ memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
+ ETH_ALEN) == 0) {
+ if (status == WLAN_STATUS_SUCCESS) {
+ wdev->auth_bsses[i] = wdev->authtry_bsses[i];
+ } else {
+ 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);
+
+ nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
+ cfg80211_sme_rx_auth(dev, buf, len);
+
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_rx_auth);
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ u16 status_code;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_rx_assoc(rdev, dev, buf, len);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ u8 *ie = mgmt->u.assoc_resp.variable;
+ int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+ bool done;
+
+ wdev_lock(wdev);
+
+ status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
+ nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
+
+ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
+ status_code,
+ status_code == WLAN_STATUS_SUCCESS);
+
+ if (status_code == WLAN_STATUS_SUCCESS) {
+ for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
+ if (wdev->auth_bsses[i] == wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->auth_bsses[i]);
+ cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+ wdev->auth_bsses[i] = NULL;
+ done = true;
+ break;
+ }
+ }
+
+ WARN_ON(!done);
+ }
+
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
+static void __cfg80211_send_deauth(struct net_device *dev,
+ const u8 *buf, size_t len)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_deauth(rdev, dev, buf, len);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ const u8 *bssid = mgmt->bssid;
+ int i;
+ bool done = false;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
+
+ 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;
+ } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->auth_bsses[i] &&
+ memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
+ 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] &&
+ memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
+ 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;
+
+ reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
+ from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
+ __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
+ } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
+ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ false);
+ }
+}
+
+
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
+ void *cookie)
+{
+ 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);
+ }
}
EXPORT_SYMBOL(cfg80211_send_deauth);
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
+static void __cfg80211_send_disassoc(struct net_device *dev,
+ const u8 *buf, size_t len)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_disassoc(rdev, dev, buf, len);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ const u8 *bssid = mgmt->bssid;
+ int i;
+ u16 reason_code;
+ bool from_ap;
+ bool done = false;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
+
+ if (wdev->sme_state != CFG80211_SME_CONNECTED)
+ return;
+
+ if (wdev->current_bss &&
+ memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
+ continue;
+ wdev->auth_bsses[i] = wdev->current_bss;
+ wdev->current_bss = NULL;
+ done = true;
+ cfg80211_sme_disassoc(dev, i);
+ break;
+ }
+ WARN_ON(!done);
+ } else
+ WARN_ON(1);
+
+
+ reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+ from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
+ __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
}
-EXPORT_SYMBOL(cfg80211_send_disassoc);
-static void cfg80211_wext_disconnected(struct net_device *dev)
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
+ void *cookie)
{
-#ifdef CONFIG_WIRELESS_EXT
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-#endif
+ 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);
+ }
}
+EXPORT_SYMBOL(cfg80211_send_disassoc);
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_auth_timeout(rdev, dev, addr);
- cfg80211_wext_disconnected(dev);
+ int i;
+ bool done = false;
+
+ wdev_lock(wdev);
+
+ nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
+ if (wdev->sme_state == CFG80211_SME_CONNECTING)
+ __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ false);
+
+ for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
+ if (wdev->authtry_bsses[i] &&
+ memcmp(wdev->authtry_bsses[i]->pub.bssid,
+ addr, ETH_ALEN) == 0) {
+ 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);
+
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_auth_timeout);
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_send_assoc_timeout(rdev, dev, addr);
- cfg80211_wext_disconnected(dev);
+ int i;
+ bool done = false;
+
+ wdev_lock(wdev);
+
+ nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
+ if (wdev->sme_state == CFG80211_SME_CONNECTING)
+ __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ false);
+
+ for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
+ if (wdev->auth_bsses[i] &&
+ memcmp(wdev->auth_bsses[i]->pub.bssid,
+ addr, ETH_ALEN) == 0) {
+ cfg80211_unhold_bss(wdev->auth_bsses[i]);
+ cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+ wdev->auth_bsses[i] = NULL;
+ done = true;
+ break;
+ }
+ }
+
+ WARN_ON(!done);
+
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
- const u8 *tsc)
+ const u8 *tsc, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc);
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+ char *buf = kmalloc(128, gfp);
+
+ if (buf) {
+ sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+ "keyid=%d %scast addr=%pM)", key_id,
+ key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
+ addr);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+ kfree(buf);
+ }
+#endif
+
+ nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
}
EXPORT_SYMBOL(cfg80211_michael_mic_failure);
+
+/* some MLME handling for userspace SME */
+int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_auth_type auth_type,
+ const u8 *bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len,
+ const u8 *key, int key_len, int key_idx)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_auth_request req;
+ struct cfg80211_internal_bss *bss;
+ int i, err, slot = -1, nfree = 0;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ if (!key || !key_len || key_idx < 0 || key_idx > 4)
+ return -EINVAL;
+
+ if (wdev->current_bss &&
+ memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
+ return -EALREADY;
+
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->authtry_bsses[i] &&
+ memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
+ ETH_ALEN) == 0)
+ return -EALREADY;
+ if (wdev->auth_bsses[i] &&
+ memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
+ ETH_ALEN) == 0)
+ return -EALREADY;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.ie = ie;
+ req.ie_len = ie_len;
+ req.auth_type = auth_type;
+ req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ req.key = key;
+ req.key_len = key_len;
+ req.key_idx = key_idx;
+ if (!req.bss)
+ return -ENOENT;
+
+ bss = bss_from_pub(req.bss);
+
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
+ slot = i;
+ nfree++;
+ }
+ }
+
+ /* we need one free slot for disassoc and one for this auth */
+ if (nfree < 2) {
+ err = -ENOSPC;
+ goto out;
+ }
+
+ wdev->authtry_bsses[slot] = bss;
+ cfg80211_hold_bss(bss);
+
+ err = rdev->ops->auth(&rdev->wiphy, dev, &req);
+ if (err) {
+ wdev->authtry_bsses[slot] = NULL;
+ cfg80211_unhold_bss(bss);
+ }
+
+ out:
+ if (err)
+ cfg80211_put_bss(req.bss);
+ return err;
+}
+
+int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, struct ieee80211_channel *chan,
+ enum nl80211_auth_type auth_type, const u8 *bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len,
+ const u8 *key, int key_len, int key_idx)
+{
+ int err;
+
+ wdev_lock(dev->ieee80211_ptr);
+ err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+ ssid, ssid_len, ie, ie_len,
+ key, key_len, key_idx);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return err;
+}
+
+int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ const u8 *bssid, const u8 *prev_bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len, bool use_mfp,
+ struct cfg80211_crypto_settings *crypt)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_assoc_request req;
+ struct cfg80211_internal_bss *bss;
+ int i, err, slot = -1;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ memset(&req, 0, sizeof(req));
+
+ if (wdev->current_bss)
+ return -EALREADY;
+
+ req.ie = ie;
+ req.ie_len = ie_len;
+ memcpy(&req.crypto, crypt, sizeof(req.crypto));
+ req.use_mfp = use_mfp;
+ req.prev_bssid = prev_bssid;
+ req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ if (!req.bss)
+ return -ENOENT;
+
+ bss = bss_from_pub(req.bss);
+
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (bss == wdev->auth_bsses[i]) {
+ slot = i;
+ break;
+ }
+ }
+
+ if (slot < 0) {
+ err = -ENOTCONN;
+ goto out;
+ }
+
+ err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
+ out:
+ /* still a reference in wdev->auth_bsses[slot] */
+ cfg80211_put_bss(req.bss);
+ return err;
+}
+
+int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ const u8 *bssid, const u8 *prev_bssid,
+ const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len, bool use_mfp,
+ struct cfg80211_crypto_settings *crypt)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+ ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
+int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_deauth_request req;
+ int i;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ memset(&req, 0, sizeof(req));
+ req.reason_code = reason;
+ req.ie = ie;
+ req.ie_len = ie_len;
+ if (wdev->current_bss &&
+ memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+ req.bss = &wdev->current_bss->pub;
+ } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->auth_bsses[i] &&
+ memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
+ req.bss = &wdev->auth_bsses[i]->pub;
+ break;
+ }
+ if (wdev->authtry_bsses[i] &&
+ memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
+ req.bss = &wdev->authtry_bsses[i]->pub;
+ break;
+ }
+ }
+
+ if (!req.bss)
+ return -ENOTCONN;
+
+ return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+}
+
+int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
+static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_disassoc_request req;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (wdev->sme_state != CFG80211_SME_CONNECTED)
+ return -ENOTCONN;
+
+ if (WARN_ON(!wdev->current_bss))
+ return -ENOTCONN;
+
+ memset(&req, 0, sizeof(req));
+ req.reason_code = reason;
+ req.ie = ie;
+ req.ie_len = ie_len;
+ if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
+ req.bss = &wdev->current_bss->pub;
+ else
+ return -ENOTCONN;
+
+ return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+}
+
+int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *bssid,
+ const u8 *ie, int ie_len, u16 reason)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
+void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_deauth_request req;
+ int i;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!rdev->ops->deauth)
+ return;
+
+ memset(&req, 0, sizeof(req));
+ req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
+ req.ie = NULL;
+ req.ie_len = 0;
+
+ if (wdev->current_bss) {
+ req.bss = &wdev->current_bss->pub;
+ rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
+ }
+ }
+
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (wdev->auth_bsses[i]) {
+ req.bss = &wdev->auth_bsses[i]->pub;
+ rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+ if (wdev->auth_bsses[i]) {
+ cfg80211_unhold_bss(wdev->auth_bsses[i]);
+ cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+ wdev->auth_bsses[i] = NULL;
+ }
+ }
+ if (wdev->authtry_bsses[i]) {
+ req.bss = &wdev->authtry_bsses[i]->pub;
+ rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+ if (wdev->authtry_bsses[i]) {
+ cfg80211_unhold_bss(wdev->authtry_bsses[i]);
+ cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
+ wdev->authtry_bsses[i] = NULL;
+ }
+ }
+ }
+}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 43bdb1372cae..0cd548267d4a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -14,8 +14,10 @@
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <linux/etherdevice.h>
+#include <net/net_namespace.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
+#include <net/sock.h>
#include "core.h"
#include "nl80211.h"
#include "reg.h"
@@ -27,27 +29,29 @@ static struct genl_family nl80211_fam = {
.hdrsize = 0, /* no private header */
.version = 1, /* no particular meaning now */
.maxattr = NL80211_ATTR_MAX,
+ .netnsok = true,
};
-/* internal helper: get drv and dev */
-static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
- struct cfg80211_registered_device **drv,
+/* internal helper: get rdev and dev */
+static int get_rdev_dev_by_info_ifindex(struct genl_info *info,
+ struct cfg80211_registered_device **rdev,
struct net_device **dev)
{
+ struct nlattr **attrs = info->attrs;
int ifindex;
if (!attrs[NL80211_ATTR_IFINDEX])
return -EINVAL;
ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
- *dev = dev_get_by_index(&init_net, ifindex);
+ *dev = dev_get_by_index(genl_info_net(info), ifindex);
if (!*dev)
return -ENODEV;
- *drv = cfg80211_get_dev_from_ifindex(ifindex);
- if (IS_ERR(*drv)) {
+ *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex);
+ if (IS_ERR(*rdev)) {
dev_put(*dev);
- return PTR_ERR(*drv);
+ return PTR_ERR(*rdev);
}
return 0;
@@ -71,7 +75,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+ [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
+ [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
@@ -128,6 +134,21 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
.len = sizeof(struct nl80211_sta_flag_update),
},
[NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
+ [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
+ [NL80211_ATTR_PID] = { .type = NLA_U32 },
+};
+
+/* policy for the attributes */
+static struct nla_policy
+nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
+ [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
+ [NL80211_KEY_IDX] = { .type = NLA_U8 },
+ [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
+ [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
+ [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
};
/* IE validation */
@@ -194,6 +215,177 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
/* netlink command implementations */
+struct key_parse {
+ struct key_params p;
+ int idx;
+ bool def, defmgmt;
+};
+
+static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
+{
+ struct nlattr *tb[NL80211_KEY_MAX + 1];
+ int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
+ nl80211_key_policy);
+ if (err)
+ return err;
+
+ k->def = !!tb[NL80211_KEY_DEFAULT];
+ k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
+
+ if (tb[NL80211_KEY_IDX])
+ k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
+
+ if (tb[NL80211_KEY_DATA]) {
+ k->p.key = nla_data(tb[NL80211_KEY_DATA]);
+ k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
+ }
+
+ if (tb[NL80211_KEY_SEQ]) {
+ k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
+ k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
+ }
+
+ if (tb[NL80211_KEY_CIPHER])
+ k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
+
+ return 0;
+}
+
+static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
+{
+ if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+ k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+ k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+ }
+
+ if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+ k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ }
+
+ if (info->attrs[NL80211_ATTR_KEY_IDX])
+ k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+ if (info->attrs[NL80211_ATTR_KEY_CIPHER])
+ k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+ k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
+ k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
+
+ return 0;
+}
+
+static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
+{
+ int err;
+
+ memset(k, 0, sizeof(*k));
+ k->idx = -1;
+
+ if (info->attrs[NL80211_ATTR_KEY])
+ err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
+ else
+ err = nl80211_parse_key_old(info, k);
+
+ if (err)
+ return err;
+
+ if (k->def && k->defmgmt)
+ return -EINVAL;
+
+ if (k->idx != -1) {
+ if (k->defmgmt) {
+ if (k->idx < 4 || k->idx > 5)
+ return -EINVAL;
+ } else if (k->def) {
+ if (k->idx < 0 || k->idx > 3)
+ return -EINVAL;
+ } else {
+ if (k->idx < 0 || k->idx > 5)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static struct cfg80211_cached_keys *
+nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+ struct nlattr *keys)
+{
+ struct key_parse parse;
+ struct nlattr *key;
+ struct cfg80211_cached_keys *result;
+ int rem, err, def = 0;
+
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return ERR_PTR(-ENOMEM);
+
+ result->def = -1;
+ result->defmgmt = -1;
+
+ nla_for_each_nested(key, keys, rem) {
+ memset(&parse, 0, sizeof(parse));
+ parse.idx = -1;
+
+ err = nl80211_parse_key_new(key, &parse);
+ if (err)
+ goto error;
+ err = -EINVAL;
+ if (!parse.p.key)
+ goto error;
+ if (parse.idx < 0 || parse.idx > 4)
+ goto error;
+ if (parse.def) {
+ if (def)
+ goto error;
+ def = 1;
+ result->def = parse.idx;
+ } else if (parse.defmgmt)
+ goto error;
+ err = cfg80211_validate_key_settings(rdev, &parse.p,
+ parse.idx, NULL);
+ if (err)
+ goto error;
+ result->params[parse.idx].cipher = parse.p.cipher;
+ result->params[parse.idx].key_len = parse.p.key_len;
+ result->params[parse.idx].key = result->data[parse.idx];
+ memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+ }
+
+ return result;
+ error:
+ kfree(result);
+ return ERR_PTR(err);
+}
+
+static int nl80211_key_allowed(struct wireless_dev *wdev)
+{
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!netif_running(wdev->netdev))
+ return -ENETDOWN;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (!wdev->current_bss)
+ return -ENOLINK;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (wdev->sme_state != CFG80211_SME_CONNECTED)
+ return -ENOLINK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *dev)
{
@@ -345,8 +537,23 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(deauth, DEAUTHENTICATE);
CMD(disassoc, DISASSOCIATE);
CMD(join_ibss, JOIN_IBSS);
+ if (dev->wiphy.netnsok) {
+ i++;
+ NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
+ }
#undef CMD
+
+ if (dev->ops->connect || dev->ops->auth) {
+ i++;
+ NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
+ }
+
+ if (dev->ops->disconnect || dev->ops->deauth) {
+ i++;
+ NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
+ }
+
nla_nest_end(msg, nl_cmds);
return genlmsg_end(msg, hdr);
@@ -363,7 +570,9 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
struct cfg80211_registered_device *dev;
mutex_lock(&cfg80211_mutex);
- list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ list_for_each_entry(dev, &cfg80211_rdev_list, list) {
+ if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
+ continue;
if (++idx <= start)
continue;
if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
@@ -396,14 +605,14 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
goto out_free;
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
- return genlmsg_unicast(msg, info->snd_pid);
+ return genlmsg_reply(msg, info);
out_free:
nlmsg_free(msg);
out_err:
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
return -ENOBUFS;
}
@@ -445,7 +654,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&cfg80211_mutex);
- rdev = __cfg80211_drv_from_info(info);
+ rdev = __cfg80211_rdev_from_info(info);
if (IS_ERR(rdev)) {
mutex_unlock(&cfg80211_mutex);
result = PTR_ERR(rdev);
@@ -548,6 +757,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
channel_type);
if (result)
goto bad_res;
+
+ rdev->channel = chan;
}
changed = 0;
@@ -668,7 +879,9 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
struct wireless_dev *wdev;
mutex_lock(&cfg80211_mutex);
- list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ list_for_each_entry(dev, &cfg80211_rdev_list, list) {
+ if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
+ continue;
if (wp_idx < wp_start) {
wp_idx++;
continue;
@@ -709,7 +922,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
struct net_device *netdev;
int err;
- err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev);
+ err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
if (err)
return err;
@@ -722,15 +935,15 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
goto out_free;
dev_put(netdev);
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
- return genlmsg_unicast(msg, info->snd_pid);
+ return genlmsg_reply(msg, info);
out_free:
nlmsg_free(msg);
out_err:
dev_put(netdev);
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
return -ENOBUFS;
}
@@ -765,9 +978,9 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct vif_params params;
- int err, ifindex;
+ int err;
enum nl80211_iftype otype, ntype;
struct net_device *dev;
u32 _flags, *flags = NULL;
@@ -777,13 +990,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- ifindex = dev->ifindex;
otype = ntype = dev->ieee80211_ptr->iftype;
- dev_put(dev);
if (info->attrs[NL80211_ATTR_IFTYPE]) {
ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -795,8 +1006,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
}
- if (!drv->ops->change_virtual_intf ||
- !(drv->wiphy.interface_modes & (1 << ntype))) {
+ if (!rdev->ops->change_virtual_intf ||
+ !(rdev->wiphy.interface_modes & (1 << ntype))) {
err = -EOPNOTSUPP;
goto unlock;
}
@@ -826,21 +1037,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
if (change)
- err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+ err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
ntype, flags, &params);
else
err = 0;
- dev = __dev_get_by_index(&init_net, ifindex);
- WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype));
+ WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
- if (dev && !err && (ntype != otype)) {
+ if (!err && (ntype != otype)) {
if (otype == NL80211_IFTYPE_ADHOC)
cfg80211_clear_ibss(dev, false);
}
unlock:
- cfg80211_put_dev(drv);
+ dev_put(dev);
+ cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err;
@@ -848,7 +1059,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct vif_params params;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -867,14 +1078,14 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- drv = cfg80211_get_dev_from_info(info);
- if (IS_ERR(drv)) {
- err = PTR_ERR(drv);
+ rdev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(rdev)) {
+ err = PTR_ERR(rdev);
goto unlock_rtnl;
}
- if (!drv->ops->add_virtual_intf ||
- !(drv->wiphy.interface_modes & (1 << type))) {
+ if (!rdev->ops->add_virtual_intf ||
+ !(rdev->wiphy.interface_modes & (1 << type))) {
err = -EOPNOTSUPP;
goto unlock;
}
@@ -888,12 +1099,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
- err = drv->ops->add_virtual_intf(&drv->wiphy,
+ err = rdev->ops->add_virtual_intf(&rdev->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
unlock:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err;
@@ -901,27 +1112,26 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
- int ifindex, err;
+ struct cfg80211_registered_device *rdev;
+ int err;
struct net_device *dev;
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- ifindex = dev->ifindex;
- dev_put(dev);
- if (!drv->ops->del_virtual_intf) {
+ if (!rdev->ops->del_virtual_intf) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
+ err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
+ dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
@@ -930,10 +1140,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
struct get_key_cookie {
struct sk_buff *msg;
int error;
+ int idx;
};
static void get_key_callback(void *c, struct key_params *params)
{
+ struct nlattr *key;
struct get_key_cookie *cookie = c;
if (params->key)
@@ -948,6 +1160,26 @@ static void get_key_callback(void *c, struct key_params *params)
NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
params->cipher);
+ key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
+ if (!key)
+ goto nla_put_failure;
+
+ if (params->key)
+ NLA_PUT(cookie->msg, NL80211_KEY_DATA,
+ params->key_len, params->key);
+
+ if (params->seq)
+ NLA_PUT(cookie->msg, NL80211_KEY_SEQ,
+ params->seq_len, params->seq);
+
+ if (params->cipher)
+ NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER,
+ params->cipher);
+
+ NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx);
+
+ nla_nest_end(cookie->msg, key);
+
return;
nla_put_failure:
cookie->error = 1;
@@ -955,7 +1187,7 @@ static void get_key_callback(void *c, struct key_params *params)
static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
u8 key_idx = 0;
@@ -977,11 +1209,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->get_key) {
+ if (!rdev->ops->get_key) {
err = -EOPNOTSUPP;
goto out;
}
@@ -997,34 +1229,36 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (IS_ERR(hdr)) {
err = PTR_ERR(hdr);
- goto out;
+ goto free_msg;
}
cookie.msg = msg;
+ cookie.idx = key_idx;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
if (mac_addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
- err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+ err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
&cookie, get_key_callback);
if (err)
- goto out;
+ goto free_msg;
if (cookie.error)
goto nla_put_failure;
genlmsg_end(msg, hdr);
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
err = -ENOBUFS;
+ free_msg:
nlmsg_free(msg);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -1034,57 +1268,57 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
+ struct key_parse key;
int err;
struct net_device *dev;
- u8 key_idx;
int (*func)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index);
- if (!info->attrs[NL80211_ATTR_KEY_IDX])
- return -EINVAL;
-
- key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+ err = nl80211_parse_key(info, &key);
+ if (err)
+ return err;
- if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
- if (key_idx < 4 || key_idx > 5)
- return -EINVAL;
- } else if (key_idx > 3)
+ if (key.idx < 0)
return -EINVAL;
- /* currently only support setting default key */
- if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
- !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
+ /* only support setting default key */
+ if (!key.def && !key.defmgmt)
return -EINVAL;
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
- func = drv->ops->set_default_key;
+ if (key.def)
+ func = rdev->ops->set_default_key;
else
- func = drv->ops->set_default_mgmt_key;
+ func = rdev->ops->set_default_mgmt_key;
if (!func) {
err = -EOPNOTSUPP;
goto out;
}
- err = func(&drv->wiphy, dev, key_idx);
+ wdev_lock(dev->ieee80211_ptr);
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
+ if (!err)
+ err = func(&rdev->wiphy, dev, key.idx);
+
#ifdef CONFIG_WIRELESS_EXT
if (!err) {
- if (func == drv->ops->set_default_key)
- dev->ieee80211_ptr->wext.default_key = key_idx;
+ if (func == rdev->ops->set_default_key)
+ dev->ieee80211_ptr->wext.default_key = key.idx;
else
- dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+ dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
}
#endif
+ wdev_unlock(dev->ieee80211_ptr);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
@@ -1095,62 +1329,47 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
- int err, i;
+ struct cfg80211_registered_device *rdev;
+ int err;
struct net_device *dev;
- struct key_params params;
- u8 key_idx = 0;
+ struct key_parse key;
u8 *mac_addr = NULL;
- memset(&params, 0, sizeof(params));
+ err = nl80211_parse_key(info, &key);
+ if (err)
+ return err;
- if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+ if (!key.p.key)
return -EINVAL;
- if (info->attrs[NL80211_ATTR_KEY_DATA]) {
- params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
- params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
- }
-
- if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
- params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
- params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
- }
-
- if (info->attrs[NL80211_ATTR_KEY_IDX])
- key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
- params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
- return -EINVAL;
-
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- for (i = 0; i < drv->wiphy.n_cipher_suites; i++)
- if (params.cipher == drv->wiphy.cipher_suites[i])
- break;
- if (i == drv->wiphy.n_cipher_suites) {
- err = -EINVAL;
+ if (!rdev->ops->add_key) {
+ err = -EOPNOTSUPP;
goto out;
}
- if (!drv->ops->add_key) {
- err = -EOPNOTSUPP;
+ if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
+ err = -EINVAL;
goto out;
}
- err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+ wdev_lock(dev->ieee80211_ptr);
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
+ if (!err)
+ err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+ mac_addr, &key.p);
+ wdev_unlock(dev->ieee80211_ptr);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -1160,45 +1379,47 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
- u8 key_idx = 0;
u8 *mac_addr = NULL;
+ struct key_parse key;
- if (info->attrs[NL80211_ATTR_KEY_IDX])
- key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
- if (key_idx > 5)
- return -EINVAL;
+ err = nl80211_parse_key(info, &key);
+ if (err)
+ return err;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->del_key) {
+ if (!rdev->ops->del_key) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+ wdev_lock(dev->ieee80211_ptr);
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
+ if (!err)
+ err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
#ifdef CONFIG_WIRELESS_EXT
if (!err) {
- if (key_idx == dev->ieee80211_ptr->wext.default_key)
+ if (key.idx == dev->ieee80211_ptr->wext.default_key)
dev->ieee80211_ptr->wext.default_key = -1;
- else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+ else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
dev->ieee80211_ptr->wext.default_mgmt_key = -1;
}
#endif
+ wdev_unlock(dev->ieee80211_ptr);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
@@ -1211,7 +1432,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
{
int (*call)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct beacon_parameters params;
@@ -1222,7 +1443,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
@@ -1241,10 +1462,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- call = drv->ops->add_beacon;
+ call = rdev->ops->add_beacon;
break;
case NL80211_CMD_SET_BEACON:
- call = drv->ops->set_beacon;
+ call = rdev->ops->set_beacon;
break;
default:
WARN_ON(1);
@@ -1290,10 +1511,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = call(&drv->wiphy, dev, &params);
+ err = call(&rdev->wiphy, dev, &params);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -1303,17 +1524,17 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->del_beacon) {
+ if (!rdev->ops->del_beacon) {
err = -EOPNOTSUPP;
goto out;
}
@@ -1322,10 +1543,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->del_beacon(&drv->wiphy, dev);
+ err = rdev->ops->del_beacon(&rdev->wiphy, dev);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -1519,13 +1740,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
rtnl_lock();
- netdev = __dev_get_by_index(&init_net, ifidx);
+ netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev) {
err = -ENODEV;
goto out_rtnl;
}
- dev = cfg80211_get_dev_from_ifindex(ifidx);
+ dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
goto out_rtnl;
@@ -1559,7 +1780,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
cb->args[1] = sta_idx;
err = skb->len;
out_err:
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
out_rtnl:
rtnl_unlock();
@@ -1568,7 +1789,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct station_info sinfo;
@@ -1584,16 +1805,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->get_station) {
+ if (!rdev->ops->get_station) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
+ err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
if (err)
goto out;
@@ -1605,13 +1826,13 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
dev, mac_addr, &sinfo) < 0)
goto out_free;
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
goto out;
out_free:
nlmsg_free(msg);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -1622,14 +1843,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
/*
* Get vlan interface making sure it is on the right wiphy.
*/
-static int get_vlan(struct nlattr *vlanattr,
+static int get_vlan(struct genl_info *info,
struct cfg80211_registered_device *rdev,
struct net_device **vlan)
{
+ struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
*vlan = NULL;
if (vlanattr) {
- *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
+ *vlan = dev_get_by_index(genl_info_net(info),
+ nla_get_u32(vlanattr));
if (!*vlan)
return -ENODEV;
if (!(*vlan)->ieee80211_ptr)
@@ -1642,7 +1865,7 @@ static int get_vlan(struct nlattr *vlanattr,
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct station_parameters params;
@@ -1684,11 +1907,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ err = get_vlan(info, rdev, &params.vlan);
if (err)
goto out;
@@ -1737,17 +1960,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out;
- if (!drv->ops->change_station) {
+ if (!rdev->ops->change_station) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+ err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);
out:
if (params.vlan)
dev_put(params.vlan);
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -1757,7 +1980,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct station_parameters params;
@@ -1797,11 +2020,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+ err = get_vlan(info, rdev, &params.vlan);
if (err)
goto out;
@@ -1837,7 +2060,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out;
- if (!drv->ops->add_station) {
+ if (!rdev->ops->add_station) {
err = -EOPNOTSUPP;
goto out;
}
@@ -1847,12 +2070,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+ err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
out:
if (params.vlan)
dev_put(params.vlan);
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -1862,7 +2085,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
u8 *mac_addr = NULL;
@@ -1872,7 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
@@ -1883,15 +2106,15 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!drv->ops->del_station) {
+ if (!rdev->ops->del_station) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+ err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -1978,13 +2201,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
rtnl_lock();
- netdev = __dev_get_by_index(&init_net, ifidx);
+ netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev) {
err = -ENODEV;
goto out_rtnl;
}
- dev = cfg80211_get_dev_from_ifindex(ifidx);
+ dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
goto out_rtnl;
@@ -2022,7 +2245,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
cb->args[1] = path_idx;
err = skb->len;
out_err:
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(dev);
out_rtnl:
rtnl_unlock();
@@ -2031,7 +2254,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct mpath_info pinfo;
@@ -2048,11 +2271,11 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->get_mpath) {
+ if (!rdev->ops->get_mpath) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2062,7 +2285,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
+ err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
if (err)
goto out;
@@ -2074,13 +2297,13 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
dev, dst, next_hop, &pinfo) < 0)
goto out_free;
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
goto out;
out_free:
nlmsg_free(msg);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2090,7 +2313,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
u8 *dst = NULL;
@@ -2107,11 +2330,11 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->change_mpath) {
+ if (!rdev->ops->change_mpath) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2126,10 +2349,10 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
+ err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2138,7 +2361,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
}
static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
u8 *dst = NULL;
@@ -2155,11 +2378,11 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->add_mpath) {
+ if (!rdev->ops->add_mpath) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2174,10 +2397,10 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
+ err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2187,7 +2410,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
u8 *dst = NULL;
@@ -2197,19 +2420,19 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->del_mpath) {
+ if (!rdev->ops->del_mpath) {
err = -EOPNOTSUPP;
goto out;
}
- err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
+ err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2219,7 +2442,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
int err;
struct net_device *dev;
struct bss_parameters params;
@@ -2248,11 +2471,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->change_bss) {
+ if (!rdev->ops->change_bss) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2262,10 +2485,10 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = drv->ops->change_bss(&drv->wiphy, dev, &params);
+ err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2356,7 +2579,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
static int nl80211_get_mesh_params(struct sk_buff *skb,
struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct mesh_config cur_params;
int err;
struct net_device *dev;
@@ -2367,17 +2590,17 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
rtnl_lock();
/* Look up our device */
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->get_mesh_params) {
+ if (!rdev->ops->get_mesh_params) {
err = -EOPNOTSUPP;
goto out;
}
/* Get the mesh params */
- err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
+ err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
if (err)
goto out;
@@ -2423,7 +2646,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
cur_params.dot11MeshHWMPnetDiameterTraversalTime);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
@@ -2431,7 +2654,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
err = -EMSGSIZE;
out:
/* Cleanup */
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2469,7 +2692,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
{
int err;
u32 mask;
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
struct mesh_config cfg;
struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
@@ -2484,11 +2707,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- if (!drv->ops->set_mesh_params) {
+ if (!rdev->ops->set_mesh_params) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2533,11 +2756,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
nla_get_u16);
/* Apply changes */
- err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
+ err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
out:
/* cleanup */
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2611,7 +2834,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
nla_nest_end(msg, nl_reg_rules);
genlmsg_end(msg, hdr);
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
@@ -2697,16 +2920,41 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
return r;
}
+static int validate_scan_freqs(struct nlattr *freqs)
+{
+ struct nlattr *attr1, *attr2;
+ int n_channels = 0, tmp1, tmp2;
+
+ nla_for_each_nested(attr1, freqs, tmp1) {
+ n_channels++;
+ /*
+ * Some hardware has a limited channel list for
+ * scanning, and it is pretty much nonsensical
+ * to scan for a channel twice, so disallow that
+ * and don't require drivers to check that the
+ * channel list they get isn't longer than what
+ * they can scan, as long as they can scan all
+ * the channels they registered at once.
+ */
+ nla_for_each_nested(attr2, freqs, tmp2)
+ if (attr1 != attr2 &&
+ nla_get_u32(attr1) == nla_get_u32(attr2))
+ return 0;
+ }
+
+ return n_channels;
+}
+
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
struct cfg80211_scan_request *request;
struct cfg80211_ssid *ssid;
struct ieee80211_channel *channel;
struct nlattr *attr;
struct wiphy *wiphy;
- int err, tmp, n_ssids = 0, n_channels = 0, i;
+ int err, tmp, n_ssids = 0, n_channels, i;
enum ieee80211_band band;
size_t ie_len;
@@ -2715,13 +2963,13 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
- wiphy = &drv->wiphy;
+ wiphy = &rdev->wiphy;
- if (!drv->ops->scan) {
+ if (!rdev->ops->scan) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2731,19 +2979,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (drv->scan_req) {
+ if (rdev->scan_req) {
err = -EBUSY;
goto out;
}
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
- nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
- n_channels++;
+ n_channels = validate_scan_freqs(
+ info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
if (!n_channels) {
err = -EINVAL;
goto out;
}
} else {
+ n_channels = 0;
+
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
if (wiphy->bands[band])
n_channels += wiphy->bands[band]->n_channels;
@@ -2835,19 +3085,24 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->ie_len);
}
- request->ifidx = dev->ifindex;
- request->wiphy = &drv->wiphy;
+ request->dev = dev;
+ request->wiphy = &rdev->wiphy;
- drv->scan_req = request;
- err = drv->ops->scan(&drv->wiphy, dev, request);
+ rdev->scan_req = request;
+ err = rdev->ops->scan(&rdev->wiphy, dev, request);
+
+ if (!err) {
+ nl80211_send_scan_start(rdev, dev);
+ dev_hold(dev);
+ }
out_free:
if (err) {
- drv->scan_req = NULL;
+ rdev->scan_req = NULL;
kfree(request);
}
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
@@ -2857,11 +3112,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *rdev,
- struct net_device *dev,
- struct cfg80211_bss *res)
+ struct wireless_dev *wdev,
+ struct cfg80211_internal_bss *intbss)
{
+ struct cfg80211_bss *res = &intbss->pub;
void *hdr;
struct nlattr *bss;
+ int i;
+
+ ASSERT_WDEV_LOCK(wdev);
hdr = nl80211hdr_put(msg, pid, seq, flags,
NL80211_CMD_NEW_SCAN_RESULTS);
@@ -2870,7 +3129,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
rdev->bss_generation);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex);
bss = nla_nest_start(msg, NL80211_ATTR_BSS);
if (!bss)
@@ -2899,6 +3158,28 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
break;
}
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ if (intbss == wdev->current_bss)
+ NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+ NL80211_BSS_STATUS_ASSOCIATED);
+ else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (intbss != wdev->auth_bsses[i])
+ continue;
+ NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+ NL80211_BSS_STATUS_AUTHENTICATED);
+ break;
+ }
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (intbss == wdev->current_bss)
+ NLA_PUT_U32(msg, NL80211_BSS_STATUS,
+ NL80211_BSS_STATUS_IBSS_JOINED);
+ break;
+ default:
+ break;
+ }
+
nla_nest_end(msg, bss);
return genlmsg_end(msg, hdr);
@@ -2911,9 +3192,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
static int nl80211_dump_scan(struct sk_buff *skb,
struct netlink_callback *cb)
{
- struct cfg80211_registered_device *dev;
- struct net_device *netdev;
+ struct cfg80211_registered_device *rdev;
+ struct net_device *dev;
struct cfg80211_internal_bss *scan;
+ struct wireless_dev *wdev;
int ifidx = cb->args[0];
int start = cb->args[1], idx = 0;
int err;
@@ -2934,58 +3216,83 @@ static int nl80211_dump_scan(struct sk_buff *skb,
cb->args[0] = ifidx;
}
- netdev = dev_get_by_index(&init_net, ifidx);
- if (!netdev)
+ dev = dev_get_by_index(sock_net(skb->sk), ifidx);
+ if (!dev)
return -ENODEV;
- dev = cfg80211_get_dev_from_ifindex(ifidx);
- if (IS_ERR(dev)) {
- err = PTR_ERR(dev);
+ rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
+ if (IS_ERR(rdev)) {
+ err = PTR_ERR(rdev);
goto out_put_netdev;
}
- spin_lock_bh(&dev->bss_lock);
- cfg80211_bss_expire(dev);
+ wdev = dev->ieee80211_ptr;
+
+ wdev_lock(wdev);
+ spin_lock_bh(&rdev->bss_lock);
+ cfg80211_bss_expire(rdev);
- list_for_each_entry(scan, &dev->bss_list, list) {
+ list_for_each_entry(scan, &rdev->bss_list, list) {
if (++idx <= start)
continue;
if (nl80211_send_bss(skb,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- dev, netdev, &scan->pub) < 0) {
+ rdev, wdev, scan) < 0) {
idx--;
goto out;
}
}
out:
- spin_unlock_bh(&dev->bss_lock);
+ spin_unlock_bh(&rdev->bss_lock);
+ wdev_unlock(wdev);
cb->args[1] = idx;
err = skb->len;
- cfg80211_put_dev(dev);
+ cfg80211_unlock_rdev(rdev);
out_put_netdev:
- dev_put(netdev);
+ dev_put(dev);
return err;
}
static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
{
- return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM ||
- auth_type == NL80211_AUTHTYPE_SHARED_KEY ||
- auth_type == NL80211_AUTHTYPE_FT ||
- auth_type == NL80211_AUTHTYPE_NETWORK_EAP;
+ return auth_type <= NL80211_AUTHTYPE_MAX;
}
+static bool nl80211_valid_wpa_versions(u32 wpa_versions)
+{
+ return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
+ NL80211_WPA_VERSION_2));
+}
+
+static bool nl80211_valid_akm_suite(u32 akm)
+{
+ return akm == WLAN_AKM_SUITE_8021X ||
+ akm == WLAN_AKM_SUITE_PSK;
+}
+
+static bool nl80211_valid_cipher_suite(u32 cipher)
+{
+ return cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ cipher == WLAN_CIPHER_SUITE_WEP104 ||
+ cipher == WLAN_CIPHER_SUITE_TKIP ||
+ cipher == WLAN_CIPHER_SUITE_CCMP ||
+ cipher == WLAN_CIPHER_SUITE_AES_CMAC;
+}
+
+
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
- struct cfg80211_auth_request req;
- struct wiphy *wiphy;
- int err;
+ struct ieee80211_channel *chan;
+ const u8 *bssid, *ssid, *ie = NULL;
+ int err, ssid_len, ie_len = 0;
+ enum nl80211_auth_type auth_type;
+ struct key_parse key;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -2996,13 +3303,38 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
return -EINVAL;
+ if (!info->attrs[NL80211_ATTR_SSID])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+ return -EINVAL;
+
+ err = nl80211_parse_key(info, &key);
+ if (err)
+ return err;
+
+ if (key.idx >= 0) {
+ if (!key.p.key || !key.p.key_len)
+ return -EINVAL;
+ if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
+ key.p.key_len != WLAN_KEY_LEN_WEP40) &&
+ (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
+ key.p.key_len != WLAN_KEY_LEN_WEP104))
+ return -EINVAL;
+ if (key.idx > 4)
+ return -EINVAL;
+ } else {
+ key.p.key_len = 0;
+ key.p.key = NULL;
+ }
+
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->auth) {
+ if (!rdev->ops->auth) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3017,69 +3349,130 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- wiphy = &drv->wiphy;
- memset(&req, 0, sizeof(req));
-
- req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-
- if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- req.chan = ieee80211_get_channel(
- wiphy,
- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
- if (!req.chan) {
- err = -EINVAL;
- goto out;
- }
+ bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ chan = ieee80211_get_channel(&rdev->wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
+ err = -EINVAL;
+ goto out;
}
- if (info->attrs[NL80211_ATTR_SSID]) {
- req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
- }
+ ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
if (info->attrs[NL80211_ATTR_IE]) {
- req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(req.auth_type)) {
+ auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(auth_type)) {
err = -EINVAL;
goto out;
}
- err = drv->ops->auth(&drv->wiphy, dev, &req);
+ err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+ ssid, ssid_len, ie, ie_len,
+ key.p.key, key.p.key_len, key.idx);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
}
+static int nl80211_crypto_settings(struct genl_info *info,
+ struct cfg80211_crypto_settings *settings,
+ int cipher_limit)
+{
+ memset(settings, 0, sizeof(*settings));
+
+ settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+
+ if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
+ void *data;
+ int len, i;
+
+ data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
+ len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
+ settings->n_ciphers_pairwise = len / sizeof(u32);
+
+ if (len % sizeof(u32))
+ return -EINVAL;
+
+ if (settings->n_ciphers_pairwise > cipher_limit)
+ return -EINVAL;
+
+ memcpy(settings->ciphers_pairwise, data, len);
+
+ for (i = 0; i < settings->n_ciphers_pairwise; i++)
+ if (!nl80211_valid_cipher_suite(
+ settings->ciphers_pairwise[i]))
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
+ settings->cipher_group =
+ nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
+ if (!nl80211_valid_cipher_suite(settings->cipher_group))
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
+ settings->wpa_versions =
+ nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
+ if (!nl80211_valid_wpa_versions(settings->wpa_versions))
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
+ void *data;
+ int len, i;
+
+ data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
+ len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
+ settings->n_akm_suites = len / sizeof(u32);
+
+ if (len % sizeof(u32))
+ return -EINVAL;
+
+ memcpy(settings->akm_suites, data, len);
+
+ for (i = 0; i < settings->n_ciphers_pairwise; i++)
+ if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
- struct cfg80211_assoc_request req;
- struct wiphy *wiphy;
- int err;
+ struct cfg80211_crypto_settings crypto;
+ struct ieee80211_channel *chan;
+ const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
+ int err, ssid_len, ie_len = 0;
+ bool use_mfp = false;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
if (!info->attrs[NL80211_ATTR_MAC] ||
- !info->attrs[NL80211_ATTR_SSID])
+ !info->attrs[NL80211_ATTR_SSID] ||
+ !info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->assoc) {
+ if (!rdev->ops->assoc) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3094,46 +3487,45 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- wiphy = &drv->wiphy;
- memset(&req, 0, sizeof(req));
+ bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-
- if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
- req.chan = ieee80211_get_channel(
- wiphy,
- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
- if (!req.chan) {
- err = -EINVAL;
- goto out;
- }
+ chan = ieee80211_get_channel(&rdev->wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
+ err = -EINVAL;
+ goto out;
}
- req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
if (info->attrs[NL80211_ATTR_IE]) {
- req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_USE_MFP]) {
- enum nl80211_mfp use_mfp =
+ enum nl80211_mfp mfp =
nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
- if (use_mfp == NL80211_MFP_REQUIRED)
- req.use_mfp = true;
- else if (use_mfp != NL80211_MFP_NO) {
+ if (mfp == NL80211_MFP_REQUIRED)
+ use_mfp = true;
+ else if (mfp != NL80211_MFP_NO) {
err = -EINVAL;
goto out;
}
}
- req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+ if (info->attrs[NL80211_ATTR_PREV_BSSID])
+ prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
- err = drv->ops->assoc(&drv->wiphy, dev, &req);
+ err = nl80211_crypto_settings(info, &crypto, 1);
+ if (!err)
+ err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+ ssid, ssid_len, ie, ie_len, use_mfp,
+ &crypto);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -3142,11 +3534,11 @@ unlock_rtnl:
static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
- struct cfg80211_deauth_request req;
- struct wiphy *wiphy;
- int err;
+ const u8 *ie = NULL, *bssid;
+ int err, ie_len = 0;
+ u16 reason_code;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -3159,11 +3551,11 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->deauth) {
+ if (!rdev->ops->deauth) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3178,27 +3570,24 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- wiphy = &drv->wiphy;
- memset(&req, 0, sizeof(req));
-
- req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
- if (req.reason_code == 0) {
+ reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ if (reason_code == 0) {
/* Reason Code 0 is reserved */
err = -EINVAL;
goto out;
}
if (info->attrs[NL80211_ATTR_IE]) {
- req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- err = drv->ops->deauth(&drv->wiphy, dev, &req);
+ err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -3207,11 +3596,11 @@ unlock_rtnl:
static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
- struct cfg80211_disassoc_request req;
- struct wiphy *wiphy;
- int err;
+ const u8 *ie = NULL, *bssid;
+ int err, ie_len = 0;
+ u16 reason_code;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -3224,11 +3613,11 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->disassoc) {
+ if (!rdev->ops->disassoc) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3243,27 +3632,24 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- wiphy = &drv->wiphy;
- memset(&req, 0, sizeof(req));
-
- req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
- if (req.reason_code == 0) {
+ reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ if (reason_code == 0) {
/* Reason Code 0 is reserved */
err = -EINVAL;
goto out;
}
if (info->attrs[NL80211_ATTR_IE]) {
- req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- err = drv->ops->disassoc(&drv->wiphy, dev, &req);
+ err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
@@ -3272,10 +3658,11 @@ unlock_rtnl:
static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
struct cfg80211_ibss_params ibss;
struct wiphy *wiphy;
+ struct cfg80211_cached_keys *connkeys = NULL;
int err;
memset(&ibss, 0, sizeof(ibss));
@@ -3299,11 +3686,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->join_ibss) {
+ if (!rdev->ops->join_ibss) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3318,7 +3705,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- wiphy = &drv->wiphy;
+ wiphy = &rdev->wiphy;
if (info->attrs[NL80211_ATTR_MAC])
ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -3340,30 +3727,43 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
}
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+ ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+ if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+ connkeys = nl80211_parse_connkeys(rdev,
+ info->attrs[NL80211_ATTR_KEYS]);
+ if (IS_ERR(connkeys)) {
+ err = PTR_ERR(connkeys);
+ connkeys = NULL;
+ goto out;
+ }
+ }
- err = cfg80211_join_ibss(drv, dev, &ibss);
+ err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
+ if (err)
+ kfree(connkeys);
rtnl_unlock();
return err;
}
static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct net_device *dev;
int err;
rtnl_lock();
- err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
- if (!drv->ops->leave_ibss) {
+ if (!rdev->ops->leave_ibss) {
err = -EOPNOTSUPP;
goto out;
}
@@ -3378,16 +3778,313 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- err = cfg80211_leave_ibss(drv, dev, false);
+ err = cfg80211_leave_ibss(rdev, dev, false);
+
+out:
+ cfg80211_unlock_rdev(rdev);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+#ifdef CONFIG_NL80211_TESTMODE
+static struct genl_multicast_group nl80211_testmode_mcgrp = {
+ .name = "testmode",
+};
+
+static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ int err;
+
+ if (!info->attrs[NL80211_ATTR_TESTDATA])
+ return -EINVAL;
+
+ rtnl_lock();
+
+ rdev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(rdev)) {
+ err = PTR_ERR(rdev);
+ goto unlock_rtnl;
+ }
+
+ err = -EOPNOTSUPP;
+ if (rdev->ops->testmode_cmd) {
+ rdev->testmode_info = info;
+ err = rdev->ops->testmode_cmd(&rdev->wiphy,
+ nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
+ nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
+ rdev->testmode_info = NULL;
+ }
+
+ cfg80211_unlock_rdev(rdev);
+
+ unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static struct sk_buff *
+__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
+ int approxlen, u32 pid, u32 seq, gfp_t gfp)
+{
+ struct sk_buff *skb;
+ void *hdr;
+ struct nlattr *data;
+
+ skb = nlmsg_new(approxlen + 100, gfp);
+ if (!skb)
+ return NULL;
+
+ hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE);
+ if (!hdr) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
+
+ ((void **)skb->cb)[0] = rdev;
+ ((void **)skb->cb)[1] = hdr;
+ ((void **)skb->cb)[2] = data;
+
+ return skb;
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return NULL;
+}
+
+struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
+ int approxlen)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ if (WARN_ON(!rdev->testmode_info))
+ return NULL;
+
+ return __cfg80211_testmode_alloc_skb(rdev, approxlen,
+ rdev->testmode_info->snd_pid,
+ rdev->testmode_info->snd_seq,
+ GFP_KERNEL);
+}
+EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
+
+int cfg80211_testmode_reply(struct sk_buff *skb)
+{
+ struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+ void *hdr = ((void **)skb->cb)[1];
+ struct nlattr *data = ((void **)skb->cb)[2];
+
+ if (WARN_ON(!rdev->testmode_info)) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ nla_nest_end(skb, data);
+ genlmsg_end(skb, hdr);
+ return genlmsg_reply(skb, rdev->testmode_info);
+}
+EXPORT_SYMBOL(cfg80211_testmode_reply);
+
+struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
+ int approxlen, gfp_t gfp)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
+}
+EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
+
+void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+ void *hdr = ((void **)skb->cb)[1];
+ struct nlattr *data = ((void **)skb->cb)[2];
+
+ nla_nest_end(skb, data);
+ genlmsg_end(skb, hdr);
+ genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+}
+EXPORT_SYMBOL(cfg80211_testmode_event);
+#endif
+
+static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ struct net_device *dev;
+ struct cfg80211_connect_params connect;
+ struct wiphy *wiphy;
+ struct cfg80211_cached_keys *connkeys = NULL;
+ int err;
+
+ memset(&connect, 0, sizeof(connect));
+
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_SSID] ||
+ !nla_len(info->attrs[NL80211_ATTR_SSID]))
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ connect.auth_type =
+ nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(connect.auth_type))
+ return -EINVAL;
+ } else
+ connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
+
+ err = nl80211_crypto_settings(info, &connect.crypto,
+ NL80211_MAX_NR_CIPHER_SUITES);
+ if (err)
+ return err;
+ rtnl_lock();
+
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ wiphy = &rdev->wiphy;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ connect.channel =
+ ieee80211_get_channel(wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!connect.channel ||
+ connect.channel->flags & IEEE80211_CHAN_DISABLED) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+ connkeys = nl80211_parse_connkeys(rdev,
+ info->attrs[NL80211_ATTR_KEYS]);
+ if (IS_ERR(connkeys)) {
+ err = PTR_ERR(connkeys);
+ connkeys = NULL;
+ goto out;
+ }
+ }
+
+ err = cfg80211_connect(rdev, dev, &connect, connkeys);
+
+out:
+ cfg80211_unlock_rdev(rdev);
+ dev_put(dev);
+unlock_rtnl:
+ if (err)
+ kfree(connkeys);
+ rtnl_unlock();
+ return err;
+}
+
+static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ struct net_device *dev;
+ int err;
+ u16 reason;
+
+ if (!info->attrs[NL80211_ATTR_REASON_CODE])
+ reason = WLAN_REASON_DEAUTH_LEAVING;
+ else
+ reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+
+ if (reason == 0)
+ return -EINVAL;
+
+ rtnl_lock();
+
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ err = cfg80211_disconnect(rdev, dev, reason, true);
out:
- cfg80211_put_dev(drv);
+ cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
}
+static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ struct net *net;
+ int err;
+ u32 pid;
+
+ if (!info->attrs[NL80211_ATTR_PID])
+ return -EINVAL;
+
+ pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
+
+ rtnl_lock();
+
+ rdev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(rdev)) {
+ err = PTR_ERR(rdev);
+ goto out;
+ }
+
+ net = get_net_ns_by_pid(pid);
+ if (IS_ERR(net)) {
+ err = PTR_ERR(net);
+ goto out;
+ }
+
+ err = 0;
+
+ /* check if anything to do */
+ if (net_eq(wiphy_net(&rdev->wiphy), net))
+ goto out_put_net;
+
+ err = cfg80211_switch_netns(rdev, net);
+ out_put_net:
+ put_net(net);
+ out:
+ cfg80211_unlock_rdev(rdev);
+ rtnl_unlock();
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -3601,6 +4298,32 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+#ifdef CONFIG_NL80211_TESTMODE
+ {
+ .cmd = NL80211_CMD_TESTMODE,
+ .doit = nl80211_testmode_do,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+#endif
+ {
+ .cmd = NL80211_CMD_CONNECT,
+ .doit = nl80211_connect,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DISCONNECT,
+ .doit = nl80211_disconnect,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_WIPHY_NETNS,
+ .doit = nl80211_wiphy_netns,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",
@@ -3632,7 +4355,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
return;
}
- genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_config_mcgrp.id, GFP_KERNEL);
}
static int nl80211_add_scan_req(struct sk_buff *msg,
@@ -3642,6 +4366,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
struct nlattr *nest;
int i;
+ ASSERT_RDEV_LOCK(rdev);
+
if (WARN_ON(!req))
return 0;
@@ -3667,11 +4393,11 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
return -ENOBUFS;
}
-static int nl80211_send_scan_donemsg(struct sk_buff *msg,
- struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- u32 pid, u32 seq, int flags,
- u32 cmd)
+static int nl80211_send_scan_msg(struct sk_buff *msg,
+ struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ u32 pid, u32 seq, int flags,
+ u32 cmd)
{
void *hdr;
@@ -3692,6 +4418,25 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
return -EMSGSIZE;
}
+void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev)
+{
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_TRIGGER_SCAN) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
{
@@ -3701,13 +4446,14 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
- NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
+ if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg);
return;
}
- genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
}
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
@@ -3719,13 +4465,14 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
- NL80211_CMD_SCAN_ABORTED) < 0) {
+ if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_SCAN_ABORTED) < 0) {
nlmsg_free(msg);
return;
}
- genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
}
/*
@@ -3774,7 +4521,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
return;
}
- genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
+ rcu_read_lock();
+ genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
+ GFP_ATOMIC);
+ rcu_read_unlock();
return;
@@ -3786,12 +4536,12 @@ nla_put_failure:
static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len,
- enum nl80211_commands cmd)
+ enum nl80211_commands cmd, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -3810,7 +4560,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
return;
}
- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
@@ -3819,42 +4570,45 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
}
void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf, size_t len)
+ struct net_device *netdev, const u8 *buf,
+ size_t len, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_AUTHENTICATE);
+ NL80211_CMD_AUTHENTICATE, gfp);
}
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len)
+ size_t len, gfp_t gfp)
{
- nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
+ nl80211_send_mlme_event(rdev, netdev, buf, len,
+ NL80211_CMD_ASSOCIATE, gfp);
}
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf, size_t len)
+ struct net_device *netdev, const u8 *buf,
+ size_t len, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DEAUTHENTICATE);
+ NL80211_CMD_DEAUTHENTICATE, gfp);
}
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len)
+ size_t len, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DISASSOCIATE);
+ NL80211_CMD_DISASSOCIATE, gfp);
}
static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev, int cmd,
- const u8 *addr)
+ const u8 *addr, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -3874,7 +4628,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
return;
}
- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
@@ -3883,16 +4638,145 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
}
void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *addr)
+ struct net_device *netdev, const u8 *addr,
+ gfp_t gfp)
{
nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
- addr);
+ addr, gfp);
}
void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *addr)
+ struct net_device *netdev, const u8 *addr,
+ gfp_t gfp)
+{
+ nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
+ addr, gfp);
+}
+
+void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (bssid)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status);
+ if (req_ie)
+ NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
+ if (resp_ie)
+ NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+
+}
+
+void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
{
- nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr);
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ if (req_ie)
+ NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
+ if (resp_ie)
+ NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+
+}
+
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u16 reason,
+ const u8 *ie, size_t ie_len, bool from_ap)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ if (from_ap && reason)
+ NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason);
+ if (from_ap)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP);
+ if (ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, GFP_KERNEL);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+
}
void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
@@ -3921,7 +4805,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
return;
}
- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
@@ -3932,12 +4817,12 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
- const u8 *tsc)
+ const u8 *tsc, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -3961,7 +4846,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
return;
}
- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
@@ -4014,7 +4900,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
return;
}
- genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+ rcu_read_lock();
+ genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
+ GFP_ATOMIC);
+ rcu_read_unlock();
return;
@@ -4050,6 +4939,12 @@ int nl80211_init(void)
if (err)
goto err_out;
+#ifdef CONFIG_NL80211_TESTMODE
+ err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp);
+ if (err)
+ goto err_out;
+#endif
+
return 0;
err_out:
genl_unregister_family(&nl80211_fam);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 5c12ad13499b..44cc2a76a1b0 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -3,39 +3,54 @@
#include "core.h"
-extern int nl80211_init(void);
-extern void nl80211_exit(void);
-extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
-extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
- struct net_device *netdev);
-extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
- struct net_device *netdev);
-extern void nl80211_send_reg_change_event(struct regulatory_request *request);
-extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len);
-extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len);
-extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+int nl80211_init(void);
+void nl80211_exit(void);
+void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
+void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
+void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
+void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
+void nl80211_send_reg_change_event(struct regulatory_request *request);
+void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *addr, gfp_t gfp);
+void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
- const u8 *buf, size_t len);
-extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len);
-extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *addr);
-extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *addr);
-extern void
+ const u8 *addr, gfp_t gfp);
+void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, gfp_t gfp);
+void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u16 reason,
+ const u8 *ie, size_t ie_len, bool from_ap);
+
+void
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type,
- int key_id, const u8 *tsc);
+ int key_id, const u8 *tsc, gfp_t gfp);
-extern void
+void
nl80211_send_beacon_hint_event(struct wiphy *wiphy,
struct ieee80211_channel *channel_before,
struct ieee80211_channel *channel_after);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 5e14371cda70..fb40428a5946 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -113,11 +113,7 @@ static const struct ieee80211_regdomain world_regdom = {
static const struct ieee80211_regdomain *cfg80211_world_regdom =
&world_regdom;
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-static char *ieee80211_regdom = "US";
-#else
static char *ieee80211_regdom = "00";
-#endif
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
@@ -1061,10 +1057,10 @@ static bool ignore_reg_update(struct wiphy *wiphy,
static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
- list_for_each_entry(drv, &cfg80211_drv_list, list)
- wiphy_update_regulatory(&drv->wiphy, initiator);
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+ wiphy_update_regulatory(&rdev->wiphy, initiator);
}
static void handle_reg_beacon(struct wiphy *wiphy,
@@ -1614,7 +1610,7 @@ static void reg_process_pending_hints(void)
/* Processes beacon hints -- this has nothing to do with country IEs */
static void reg_process_pending_beacon_hints(void)
{
- struct cfg80211_registered_device *drv;
+ struct cfg80211_registered_device *rdev;
struct reg_beacon *pending_beacon, *tmp;
mutex_lock(&cfg80211_mutex);
@@ -1633,8 +1629,8 @@ static void reg_process_pending_beacon_hints(void)
list_del_init(&pending_beacon->list);
/* Applies the beacon hint to current wiphys */
- list_for_each_entry(drv, &cfg80211_drv_list, list)
- wiphy_update_new_beacon(&drv->wiphy, pending_beacon);
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+ wiphy_update_new_beacon(&rdev->wiphy, pending_beacon);
/* Remembers the beacon hint for new wiphys or reg changes */
list_add_tail(&pending_beacon->list, &reg_beacon_list);
@@ -1814,23 +1810,23 @@ void regulatory_hint_11d(struct wiphy *wiphy,
if (likely(last_request->initiator ==
NL80211_REGDOM_SET_BY_COUNTRY_IE &&
wiphy_idx_valid(last_request->wiphy_idx))) {
- struct cfg80211_registered_device *drv_last_ie;
+ struct cfg80211_registered_device *rdev_last_ie;
- drv_last_ie =
- cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
+ rdev_last_ie =
+ cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx);
/*
* Lets keep this simple -- we trust the first AP
* after we intersect with CRDA
*/
- if (likely(&drv_last_ie->wiphy == wiphy)) {
+ if (likely(&rdev_last_ie->wiphy == wiphy)) {
/*
* Ignore IEs coming in on this wiphy with
* the same alpha2 and environment cap
*/
- if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+ if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
alpha2) &&
- env == drv_last_ie->env)) {
+ env == rdev_last_ie->env)) {
goto out;
}
/*
@@ -1846,9 +1842,9 @@ void regulatory_hint_11d(struct wiphy *wiphy,
* Ignore IEs coming in on two separate wiphys with
* the same alpha2 and environment cap
*/
- if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+ if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
alpha2) &&
- env == drv_last_ie->env)) {
+ env == rdev_last_ie->env)) {
goto out;
}
/* We could potentially intersect though */
@@ -1995,14 +1991,14 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
if (last_request->initiator ==
NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- struct cfg80211_registered_device *drv;
- drv = cfg80211_drv_by_wiphy_idx(
+ struct cfg80211_registered_device *rdev;
+ rdev = cfg80211_rdev_by_wiphy_idx(
last_request->wiphy_idx);
- if (drv) {
+ if (rdev) {
printk(KERN_INFO "cfg80211: Current regulatory "
"domain updated by AP to: %c%c\n",
- drv->country_ie_alpha2[0],
- drv->country_ie_alpha2[1]);
+ rdev->country_ie_alpha2[0],
+ rdev->country_ie_alpha2[1]);
} else
printk(KERN_INFO "cfg80211: Current regulatory "
"domain intersected: \n");
@@ -2063,7 +2059,7 @@ static inline void reg_country_ie_process_debug(
static int __set_regdom(const struct ieee80211_regdomain *rd)
{
const struct ieee80211_regdomain *intersected_rd = NULL;
- struct cfg80211_registered_device *drv = NULL;
+ struct cfg80211_registered_device *rdev = NULL;
struct wiphy *request_wiphy;
/* Some basic sanity checks first */
@@ -2202,11 +2198,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!intersected_rd)
return -EINVAL;
- drv = wiphy_to_dev(request_wiphy);
+ rdev = wiphy_to_dev(request_wiphy);
- drv->country_ie_alpha2[0] = rd->alpha2[0];
- drv->country_ie_alpha2[1] = rd->alpha2[1];
- drv->env = last_request->country_ie_env;
+ rdev->country_ie_alpha2[0] = rd->alpha2[0];
+ rdev->country_ie_alpha2[1] = rd->alpha2[1];
+ rdev->env = last_request->country_ie_env;
BUG_ON(intersected_rd == rd);
@@ -2287,22 +2283,12 @@ int regulatory_init(void)
printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
print_regdomain_info(cfg80211_regdomain);
- /*
- * The old code still requests for a new regdomain and if
- * you have CRDA you get it updated, otherwise you get
- * stuck with the static values. Since "EU" is not a valid
- * ISO / IEC 3166 alpha2 code we can't expect userpace to
- * give us a regulatory domain for it. We need last_request
- * iniitalized though so lets just send a request which we
- * know will be ignored... this crap will be removed once
- * OLD_REG dies.
- */
- err = regulatory_hint_core(ieee80211_regdom);
#else
cfg80211_regdomain = cfg80211_world_regdom;
- err = regulatory_hint_core(ieee80211_regdom);
#endif
+ /* We always try to get an update for the static regdomain */
+ err = regulatory_hint_core(cfg80211_regdomain->alpha2);
if (err) {
if (err == -ENOMEM)
return err;
@@ -2321,6 +2307,13 @@ int regulatory_init(void)
#endif
}
+ /*
+ * Finally, if the user set the module parameter treat it
+ * as a user hint.
+ */
+ if (!is_world_regdom(ieee80211_regdom))
+ regulatory_hint_user(ieee80211_regdom);
+
return 0;
}
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index f8e71b300001..67714d7ed5b4 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -14,31 +14,41 @@
#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
+#include "wext-compat.h"
-#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
-void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+void __cfg80211_scan_done(struct work_struct *wk)
{
+ struct cfg80211_registered_device *rdev;
+ struct cfg80211_scan_request *request;
struct net_device *dev;
#ifdef CONFIG_WIRELESS_EXT
union iwreq_data wrqu;
#endif
- dev = dev_get_by_index(&init_net, request->ifidx);
- if (!dev)
- goto out;
+ rdev = container_of(wk, struct cfg80211_registered_device,
+ scan_done_wk);
- WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+ mutex_lock(&rdev->mtx);
+ request = rdev->scan_req;
+
+ dev = request->dev;
- if (aborted)
+ /*
+ * This must be before sending the other events!
+ * Otherwise, wpa_supplicant gets completely confused with
+ * wext events.
+ */
+ cfg80211_sme_scan_done(dev);
+
+ if (request->aborted)
nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
else
nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
- wiphy_to_dev(request->wiphy)->scan_req = NULL;
-
#ifdef CONFIG_WIRELESS_EXT
- if (!aborted) {
+ if (!request->aborted) {
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -47,9 +57,18 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
dev_put(dev);
- out:
+ cfg80211_unlock_rdev(rdev);
+ wiphy_to_dev(request->wiphy)->scan_req = NULL;
kfree(request);
}
+
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+{
+ WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+
+ request->aborted = aborted;
+ schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
+}
EXPORT_SYMBOL(cfg80211_scan_done);
static void bss_release(struct kref *ref)
@@ -63,6 +82,8 @@ static void bss_release(struct kref *ref)
if (bss->ies_allocated)
kfree(bss->pub.information_elements);
+ BUG_ON(atomic_read(&bss->hold));
+
kfree(bss);
}
@@ -85,8 +106,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
bool expired = false;
list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
- if (bss->hold ||
- !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+ if (atomic_read(&bss->hold))
+ continue;
+ if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
continue;
list_del(&bss->list);
rb_erase(&bss->rbn, &dev->bss_tree);
@@ -546,30 +568,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
}
EXPORT_SYMBOL(cfg80211_unlink_bss);
-void cfg80211_hold_bss(struct cfg80211_bss *pub)
-{
- struct cfg80211_internal_bss *bss;
-
- if (!pub)
- return;
-
- bss = container_of(pub, struct cfg80211_internal_bss, pub);
- bss->hold = true;
-}
-EXPORT_SYMBOL(cfg80211_hold_bss);
-
-void cfg80211_unhold_bss(struct cfg80211_bss *pub)
-{
- struct cfg80211_internal_bss *bss;
-
- if (!pub)
- return;
-
- bss = container_of(pub, struct cfg80211_internal_bss, pub);
- bss->hold = false;
-}
-EXPORT_SYMBOL(cfg80211_unhold_bss);
-
#ifdef CONFIG_WIRELESS_EXT
int cfg80211_wext_siwscan(struct net_device *dev,
struct iw_request_info *info,
@@ -585,7 +583,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (!netif_running(dev))
return -ENETDOWN;
- rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+ rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
@@ -610,7 +608,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
}
creq->wiphy = wiphy;
- creq->ifidx = dev->ifindex;
+ creq->dev = dev;
creq->ssids = (void *)(creq + 1);
creq->channels = (void *)(creq->ssids + 1);
creq->n_channels = n_channels;
@@ -647,9 +645,12 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (err) {
rdev->scan_req = NULL;
kfree(creq);
+ } else {
+ nl80211_send_scan_start(rdev, dev);
+ dev_hold(dev);
}
out:
- cfg80211_put_dev(rdev);
+ cfg80211_unlock_rdev(rdev);
return err;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
@@ -940,7 +941,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
if (!netif_running(dev))
return -ENETDOWN;
- rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+ rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
@@ -958,7 +959,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
}
out:
- cfg80211_put_dev(rdev);
+ cfg80211_unlock_rdev(rdev);
return res;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
new file mode 100644
index 000000000000..d2b5d4ce0a00
--- /dev/null
+++ b/net/wireless/sme.c
@@ -0,0 +1,839 @@
+/*
+ * SME code for cfg80211's connect emulation.
+ *
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/workqueue.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include "nl80211.h"
+
+struct cfg80211_conn {
+ struct cfg80211_connect_params params;
+ /* these are sub-states of the _CONNECTING sme_state */
+ enum {
+ CFG80211_CONN_IDLE,
+ CFG80211_CONN_SCANNING,
+ CFG80211_CONN_SCAN_AGAIN,
+ CFG80211_CONN_AUTHENTICATE_NEXT,
+ CFG80211_CONN_AUTHENTICATING,
+ CFG80211_CONN_ASSOCIATE_NEXT,
+ CFG80211_CONN_ASSOCIATING,
+ } state;
+ u8 bssid[ETH_ALEN];
+ u8 *ie;
+ size_t ie_len;
+ bool auto_auth;
+};
+
+
+static int cfg80211_conn_scan(struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_scan_request *request;
+ int n_channels, err;
+
+ ASSERT_RTNL();
+ ASSERT_RDEV_LOCK(rdev);
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (rdev->scan_req)
+ return -EBUSY;
+
+ if (wdev->conn->params.channel) {
+ n_channels = 1;
+ } else {
+ enum ieee80211_band band;
+ n_channels = 0;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!wdev->wiphy->bands[band])
+ continue;
+ n_channels += wdev->wiphy->bands[band]->n_channels;
+ }
+ }
+ request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
+ sizeof(request->channels[0]) * n_channels,
+ GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->channels = (void *)((char *)request + sizeof(*request));
+ if (wdev->conn->params.channel)
+ request->channels[0] = wdev->conn->params.channel;
+ else {
+ int i = 0, j;
+ enum ieee80211_band band;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!wdev->wiphy->bands[band])
+ continue;
+ for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
+ i++, j++)
+ request->channels[i] =
+ &wdev->wiphy->bands[band]->channels[j];
+ }
+ }
+ request->n_channels = n_channels;
+ request->ssids = (void *)(request->channels + n_channels);
+ request->n_ssids = 1;
+
+ memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
+ wdev->conn->params.ssid_len);
+ request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
+
+ request->dev = wdev->netdev;
+ request->wiphy = &rdev->wiphy;
+
+ rdev->scan_req = request;
+
+ err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
+ if (!err) {
+ wdev->conn->state = CFG80211_CONN_SCANNING;
+ nl80211_send_scan_start(rdev, wdev->netdev);
+ dev_hold(wdev->netdev);
+ } else {
+ rdev->scan_req = NULL;
+ kfree(request);
+ }
+ return err;
+}
+
+static int cfg80211_conn_do_work(struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_connect_params *params;
+ int err;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!wdev->conn)
+ return 0;
+
+ params = &wdev->conn->params;
+
+ switch (wdev->conn->state) {
+ case CFG80211_CONN_SCAN_AGAIN:
+ return cfg80211_conn_scan(wdev);
+ case CFG80211_CONN_AUTHENTICATE_NEXT:
+ BUG_ON(!rdev->ops->auth);
+ wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
+ return __cfg80211_mlme_auth(rdev, wdev->netdev,
+ params->channel, params->auth_type,
+ params->bssid,
+ params->ssid, params->ssid_len,
+ NULL, 0,
+ params->key, params->key_len,
+ params->key_idx);
+ case CFG80211_CONN_ASSOCIATE_NEXT:
+ BUG_ON(!rdev->ops->assoc);
+ wdev->conn->state = CFG80211_CONN_ASSOCIATING;
+ /*
+ * We could, later, implement roaming here and then actually
+ * set prev_bssid to non-NULL. But then we need to be aware
+ * that some APs don't like that -- so we'd need to retry
+ * the association.
+ */
+ err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
+ params->channel, params->bssid,
+ NULL,
+ params->ssid, params->ssid_len,
+ params->ie, params->ie_len,
+ false, &params->crypto);
+ if (err)
+ __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+ NULL, 0,
+ WLAN_REASON_DEAUTH_LEAVING);
+ return err;
+ default:
+ return 0;
+ }
+}
+
+void cfg80211_conn_work(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev =
+ container_of(work, struct cfg80211_registered_device, conn_work);
+ struct wireless_dev *wdev;
+
+ rtnl_lock();
+ cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->devlist_mtx);
+
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ wdev_lock(wdev);
+ if (!netif_running(wdev->netdev)) {
+ wdev_unlock(wdev);
+ continue;
+ }
+ if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+ wdev_unlock(wdev);
+ continue;
+ }
+ if (cfg80211_conn_do_work(wdev))
+ __cfg80211_connect_result(
+ wdev->netdev,
+ wdev->conn->params.bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ false);
+ wdev_unlock(wdev);
+ }
+
+ mutex_unlock(&rdev->devlist_mtx);
+ cfg80211_unlock_rdev(rdev);
+ rtnl_unlock();
+}
+
+static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_bss *bss;
+ u16 capa = WLAN_CAPABILITY_ESS;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (wdev->conn->params.privacy)
+ capa |= WLAN_CAPABILITY_PRIVACY;
+
+ bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
+ wdev->conn->params.ssid,
+ wdev->conn->params.ssid_len,
+ WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
+ capa);
+ if (!bss)
+ return false;
+
+ memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
+ wdev->conn->params.bssid = wdev->conn->bssid;
+ wdev->conn->params.channel = bss->channel;
+ wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+ schedule_work(&rdev->conn_work);
+
+ cfg80211_put_bss(bss);
+ return true;
+}
+
+static void __cfg80211_sme_scan_done(struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (wdev->sme_state != CFG80211_SME_CONNECTING)
+ return;
+
+ if (!wdev->conn)
+ return;
+
+ if (wdev->conn->state != CFG80211_CONN_SCANNING &&
+ wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
+ return;
+
+ if (!cfg80211_get_conn_bss(wdev)) {
+ /* not found */
+ if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
+ schedule_work(&rdev->conn_work);
+ else
+ __cfg80211_connect_result(
+ wdev->netdev,
+ wdev->conn->params.bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ false);
+ }
+}
+
+void cfg80211_sme_scan_done(struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ wdev_lock(wdev);
+ __cfg80211_sme_scan_done(dev);
+ wdev_unlock(wdev);
+}
+
+void cfg80211_sme_rx_auth(struct net_device *dev,
+ const u8 *buf, size_t len)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+ u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ /* should only RX auth frames when connecting */
+ if (wdev->sme_state != CFG80211_SME_CONNECTING)
+ return;
+
+ if (WARN_ON(!wdev->conn))
+ return;
+
+ if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
+ wdev->conn->auto_auth &&
+ wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
+ /* select automatically between only open, shared, leap */
+ switch (wdev->conn->params.auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ if (wdev->connect_keys)
+ wdev->conn->params.auth_type =
+ NL80211_AUTHTYPE_SHARED_KEY;
+ else
+ wdev->conn->params.auth_type =
+ NL80211_AUTHTYPE_NETWORK_EAP;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ wdev->conn->params.auth_type =
+ NL80211_AUTHTYPE_NETWORK_EAP;
+ break;
+ default:
+ /* huh? */
+ wdev->conn->params.auth_type =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
+ break;
+ }
+ wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+ schedule_work(&rdev->conn_work);
+ } else if (status_code != WLAN_STATUS_SUCCESS) {
+ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+ status_code, false);
+ } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
+ wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
+ wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
+ schedule_work(&rdev->conn_work);
+ }
+}
+
+void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, bool wextev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+#endif
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return;
+
+ if (wdev->sme_state == CFG80211_SME_CONNECTED)
+ nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev,
+ bssid, req_ie, req_ie_len,
+ resp_ie, resp_ie_len, GFP_KERNEL);
+ else
+ nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
+ bssid, req_ie, req_ie_len,
+ resp_ie, resp_ie_len,
+ status, GFP_KERNEL);
+
+#ifdef CONFIG_WIRELESS_EXT
+ if (wextev) {
+ if (req_ie && status == WLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = req_ie_len;
+ wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
+ }
+
+ if (resp_ie && status == WLAN_STATUS_SUCCESS) {
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = resp_ie_len;
+ wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
+ }
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid && status == WLAN_STATUS_SUCCESS)
+ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+
+ if (status == WLAN_STATUS_SUCCESS &&
+ wdev->sme_state == CFG80211_SME_IDLE)
+ goto success;
+
+ if (wdev->sme_state != CFG80211_SME_CONNECTING)
+ return;
+
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
+ }
+
+ if (wdev->conn)
+ wdev->conn->state = CFG80211_CONN_IDLE;
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wdev->sme_state = CFG80211_SME_IDLE;
+ kfree(wdev->conn);
+ wdev->conn = NULL;
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = NULL;
+ return;
+ }
+
+ bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+ wdev->ssid, wdev->ssid_len,
+ WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+
+ if (WARN_ON(!bss))
+ return;
+
+ cfg80211_hold_bss(bss_from_pub(bss));
+ wdev->current_bss = bss_from_pub(bss);
+
+ success:
+ wdev->sme_state = CFG80211_SME_CONNECTED;
+ cfg80211_upload_connect_keys(wdev);
+}
+
+void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len,
+ u16 status, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_CONNECT_RESULT;
+ memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+ ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
+ ev->cr.req_ie_len = req_ie_len;
+ memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+ ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
+ ev->cr.resp_ie_len = resp_ie_len;
+ memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+ ev->cr.status = status;
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_connect_result);
+
+void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len)
+{
+ struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+#endif
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return;
+
+ if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
+ return;
+
+ /* internal error -- how did we get to CONNECTED w/o BSS? */
+ if (WARN_ON(!wdev->current_bss)) {
+ return;
+ }
+
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
+
+ bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+ wdev->ssid, wdev->ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+
+ if (WARN_ON(!bss))
+ return;
+
+ cfg80211_hold_bss(bss_from_pub(bss));
+ wdev->current_bss = bss_from_pub(bss);
+
+ nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid,
+ req_ie, req_ie_len, resp_ie, resp_ie_len,
+ GFP_KERNEL);
+
+#ifdef CONFIG_WIRELESS_EXT
+ if (req_ie) {
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = req_ie_len;
+ wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
+ &wrqu, req_ie);
+ }
+
+ if (resp_ie) {
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = resp_ie_len;
+ wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
+ &wrqu, resp_ie);
+ }
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+ wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_ROAMED;
+ memcpy(ev->rm.bssid, bssid, ETH_ALEN);
+ ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
+ ev->rm.req_ie_len = req_ie_len;
+ memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
+ ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
+ ev->rm.resp_ie_len = resp_ie_len;
+ memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_roamed);
+
+void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
+ size_t ie_len, u16 reason, bool from_ap)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int i;
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+#endif
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return;
+
+ if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
+ return;
+
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ }
+
+ wdev->current_bss = NULL;
+ wdev->sme_state = CFG80211_SME_IDLE;
+
+ if (wdev->conn) {
+ kfree(wdev->conn->ie);
+ wdev->conn->ie = NULL;
+ kfree(wdev->conn);
+ wdev->conn = NULL;
+ }
+
+ nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
+
+ /*
+ * Delete all the keys ... pairwise keys can't really
+ * exist any more anyway, but default keys might.
+ */
+ if (rdev->ops->del_key)
+ for (i = 0; i < 6; i++)
+ rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+
+#ifdef CONFIG_WIRELESS_EXT
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void cfg80211_disconnected(struct net_device *dev, u16 reason,
+ u8 *ie, size_t ie_len, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev) + ie_len, gfp);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_DISCONNECTED;
+ ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
+ ev->dc.ie_len = ie_len;
+ memcpy((void *)ev->dc.ie, ie, ie_len);
+ ev->dc.reason = reason;
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_disconnected);
+
+int __cfg80211_connect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_connect_params *connect,
+ struct cfg80211_cached_keys *connkeys)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (wdev->sme_state != CFG80211_SME_IDLE)
+ return -EALREADY;
+
+ if (WARN_ON(wdev->connect_keys)) {
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = NULL;
+ }
+
+ if (connkeys && connkeys->def >= 0) {
+ int idx;
+
+ idx = connkeys->def;
+ /* If given a WEP key we may need it for shared key auth */
+ if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
+ connect->key_idx = idx;
+ connect->key = connkeys->params[idx].key;
+ connect->key_len = connkeys->params[idx].key_len;
+ }
+ }
+
+ if (!rdev->ops->connect) {
+ if (!rdev->ops->auth || !rdev->ops->assoc)
+ return -EOPNOTSUPP;
+
+ if (WARN_ON(wdev->conn))
+ return -EINPROGRESS;
+
+ wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
+ if (!wdev->conn)
+ return -ENOMEM;
+
+ /*
+ * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
+ */
+ memcpy(&wdev->conn->params, connect, sizeof(*connect));
+ if (connect->bssid) {
+ wdev->conn->params.bssid = wdev->conn->bssid;
+ memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
+ }
+
+ if (connect->ie) {
+ wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
+ GFP_KERNEL);
+ wdev->conn->params.ie = wdev->conn->ie;
+ if (!wdev->conn->ie) {
+ kfree(wdev->conn);
+ wdev->conn = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
+ wdev->conn->auto_auth = true;
+ /* start with open system ... should mostly work */
+ wdev->conn->params.auth_type =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
+ } else {
+ wdev->conn->auto_auth = false;
+ }
+
+ memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+ wdev->ssid_len = connect->ssid_len;
+ wdev->conn->params.ssid = wdev->ssid;
+ wdev->conn->params.ssid_len = connect->ssid_len;
+
+ /* don't care about result -- but fill bssid & channel */
+ if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
+ cfg80211_get_conn_bss(wdev);
+
+ wdev->sme_state = CFG80211_SME_CONNECTING;
+ wdev->connect_keys = connkeys;
+
+ /* we're good if we have both BSSID and channel */
+ if (wdev->conn->params.bssid && wdev->conn->params.channel) {
+ wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+ err = cfg80211_conn_do_work(wdev);
+ } else {
+ /* otherwise we'll need to scan for the AP first */
+ err = cfg80211_conn_scan(wdev);
+ /*
+ * If we can't scan right now, then we need to scan again
+ * after the current scan finished, since the parameters
+ * changed (unless we find a good AP anyway).
+ */
+ if (err == -EBUSY) {
+ err = 0;
+ wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
+ }
+ }
+ if (err) {
+ kfree(wdev->conn);
+ wdev->conn = NULL;
+ wdev->sme_state = CFG80211_SME_IDLE;
+ wdev->connect_keys = NULL;
+ }
+
+ return err;
+ } else {
+ wdev->sme_state = CFG80211_SME_CONNECTING;
+ wdev->connect_keys = connkeys;
+ err = rdev->ops->connect(&rdev->wiphy, dev, connect);
+ if (err) {
+ wdev->connect_keys = NULL;
+ wdev->sme_state = CFG80211_SME_IDLE;
+ return err;
+ }
+
+ memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+ wdev->ssid_len = connect->ssid_len;
+
+ return 0;
+ }
+}
+
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_connect_params *connect,
+ struct cfg80211_cached_keys *connkeys)
+{
+ int err;
+
+ wdev_lock(dev->ieee80211_ptr);
+ err = __cfg80211_connect(rdev, dev, connect, connkeys);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return err;
+}
+
+int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u16 reason, bool wextev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (wdev->sme_state == CFG80211_SME_IDLE)
+ return -EINVAL;
+
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = NULL;
+
+ if (!rdev->ops->disconnect) {
+ if (!rdev->ops->deauth)
+ return -EOPNOTSUPP;
+
+ /* was it connected by userspace SME? */
+ if (!wdev->conn) {
+ cfg80211_mlme_down(rdev, dev);
+ return 0;
+ }
+
+ if (wdev->sme_state == CFG80211_SME_CONNECTING &&
+ (wdev->conn->state == CFG80211_CONN_SCANNING ||
+ wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
+ wdev->sme_state = CFG80211_SME_IDLE;
+ kfree(wdev->conn);
+ wdev->conn = NULL;
+ return 0;
+ }
+
+ /* wdev->conn->params.bssid must be set if > SCANNING */
+ err = __cfg80211_mlme_deauth(rdev, dev,
+ wdev->conn->params.bssid,
+ NULL, 0, reason);
+ if (err)
+ return err;
+ } else {
+ err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
+ if (err)
+ return err;
+ }
+
+ if (wdev->sme_state == CFG80211_SME_CONNECTED)
+ __cfg80211_disconnected(dev, NULL, 0, 0, false);
+ else if (wdev->sme_state == CFG80211_SME_CONNECTING)
+ __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ wextev);
+
+ return 0;
+}
+
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ u16 reason, bool wextev)
+{
+ int err;
+
+ wdev_lock(dev->ieee80211_ptr);
+ err = __cfg80211_disconnect(rdev, dev, reason, wextev);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return err;
+}
+
+void cfg80211_sme_disassoc(struct net_device *dev, int idx)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ u8 bssid[ETH_ALEN];
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!wdev->conn)
+ return;
+
+ if (wdev->conn->state == CFG80211_CONN_IDLE)
+ return;
+
+ /*
+ * Ok, so the association was made by this SME -- we don't
+ * want it any more so deauthenticate too.
+ */
+
+ if (!wdev->auth_bsses[idx])
+ return;
+
+ memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
+ if (__cfg80211_mlme_deauth(rdev, dev, bssid,
+ NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
+ /* whatever -- assume gone anyway */
+ cfg80211_unhold_bss(wdev->auth_bsses[idx]);
+ cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
+ wdev->auth_bsses[idx] = NULL;
+ }
+}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 25550692dda6..ba387d85dcfd 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
set_mandatory_flags_band(wiphy->bands[band], band);
}
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ struct key_params *params, int key_idx,
const u8 *mac_addr)
{
+ int i;
+
if (key_idx > 5)
return -EINVAL;
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
}
}
+ for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+ if (params->cipher == rdev->wiphy.cipher_suites[i])
+ break;
+ if (i == rdev->wiphy.n_cipher_suites)
+ return -EINVAL;
+
return 0;
}
@@ -502,3 +511,58 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
return dscp >> 5;
}
EXPORT_SYMBOL(cfg80211_classify8021d);
+
+const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
+{
+ u8 *end, *pos;
+
+ pos = bss->information_elements;
+ if (pos == NULL)
+ return NULL;
+ end = pos + bss->len_information_elements;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(ieee80211_bss_get_ie);
+
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct net_device *dev = wdev->netdev;
+ int i;
+
+ if (!wdev->connect_keys)
+ return;
+
+ for (i = 0; i < 6; i++) {
+ if (!wdev->connect_keys->params[i].cipher)
+ continue;
+ if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+ &wdev->connect_keys->params[i])) {
+ printk(KERN_ERR "%s: failed to set key %d\n",
+ dev->name, i);
+ continue;
+ }
+ if (wdev->connect_keys->def == i)
+ if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) {
+ printk(KERN_ERR "%s: failed to set defkey %d\n",
+ dev->name, i);
+ continue;
+ }
+ if (wdev->connect_keys->defmgmt == i)
+ if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+ printk(KERN_ERR "%s: failed to set mgtdef %d\n",
+ dev->name, i);
+ }
+
+ kfree(wdev->connect_keys);
+ wdev->connect_keys = NULL;
+}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index d030c5315672..e4e90e249bab 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -14,6 +14,7 @@
#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
+#include "wext-compat.h"
#include "core.h"
int cfg80211_wext_giwname(struct net_device *dev,
@@ -103,7 +104,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
memset(&vifparams, 0, sizeof(vifparams));
- ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
+ ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
NULL, &vifparams);
WARN_ON(!ret && wdev->iftype != type);
@@ -154,7 +155,7 @@ int cfg80211_wext_giwrange(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct iw_range *range = (struct iw_range *) extra;
enum ieee80211_band band;
- int c = 0;
+ int i, c = 0;
if (!wdev)
return -EOPNOTSUPP;
@@ -173,9 +174,6 @@ int cfg80211_wext_giwrange(struct net_device *dev,
range->min_frag = 256;
range->max_frag = 2346;
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
range->max_encoding_tokens = 4;
range->max_qual.updated = IW_QUAL_NOISE_INVALID;
@@ -204,11 +202,31 @@ int cfg80211_wext_giwrange(struct net_device *dev,
range->avg_qual.noise = range->max_qual.noise / 2;
range->avg_qual.updated = range->max_qual.updated;
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+ for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) {
+ switch (wdev->wiphy->cipher_suites[i]) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP |
+ IW_ENC_CAPA_WPA);
+ break;
+
+ case WLAN_CIPHER_SUITE_CCMP:
+ range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP |
+ IW_ENC_CAPA_WPA2);
+ break;
+
+ case WLAN_CIPHER_SUITE_WEP40:
+ range->encoding_size[range->num_encoding_sizes++] =
+ WLAN_KEY_LEN_WEP40;
+ break;
+
+ case WLAN_CIPHER_SUITE_WEP104:
+ range->encoding_size[range->num_encoding_sizes++] =
+ WLAN_KEY_LEN_WEP104;
+ break;
+ }
+ }
for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
- int i;
struct ieee80211_supported_band *sband;
sband = wdev->wiphy->bands[band];
@@ -236,56 +254,13 @@ int cfg80211_wext_giwrange(struct net_device *dev,
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
- range->scan_capa |= IW_SCAN_CAPA_ESSID;
+ if (wdev->wiphy->max_scan_ssids > 0)
+ range->scan_capa |= IW_SCAN_CAPA_ESSID;
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
-int cfg80211_wext_siwmlme(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- struct cfg80211_registered_device *rdev;
- union {
- struct cfg80211_disassoc_request disassoc;
- struct cfg80211_deauth_request deauth;
- } cmd;
-
- if (!wdev)
- return -EOPNOTSUPP;
-
- rdev = wiphy_to_dev(wdev->wiphy);
-
- if (wdev->iftype != NL80211_IFTYPE_STATION)
- return -EINVAL;
-
- if (mlme->addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- memset(&cmd, 0, sizeof(cmd));
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- if (!rdev->ops->deauth)
- return -EOPNOTSUPP;
- cmd.deauth.peer_addr = mlme->addr.sa_data;
- cmd.deauth.reason_code = mlme->reason_code;
- return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth);
- case IW_MLME_DISASSOC:
- if (!rdev->ops->disassoc)
- return -EOPNOTSUPP;
- cmd.disassoc.peer_addr = mlme->addr.sa_data;
- cmd.disassoc.reason_code = mlme->reason_code;
- return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc);
- default:
- return -EOPNOTSUPP;
- }
-}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
-
/**
* cfg80211_wext_freq - get wext frequency for non-"auto"
@@ -326,7 +301,6 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
return ERR_PTR(-EINVAL);
return chan;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_request_info *info,
@@ -479,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *addr,
- bool remove, bool tx_key, int idx,
- struct key_params *params)
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- int err;
+ int err, i;
+
+ if (!wdev->wext.keys) {
+ wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+ GFP_KERNEL);
+ if (!wdev->wext.keys)
+ return -ENOMEM;
+ for (i = 0; i < 6; i++)
+ wdev->wext.keys->params[i].key =
+ wdev->wext.keys->data[i];
+ }
+
+ if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+ wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (!wdev->current_bss)
+ return -ENOLINK;
+
if (!rdev->ops->set_default_mgmt_key)
return -EOPNOTSUPP;
@@ -497,8 +488,14 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
return -EINVAL;
if (remove) {
- err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+ err = 0;
+ if (wdev->current_bss)
+ err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
if (!err) {
+ if (!addr) {
+ wdev->wext.keys->params[idx].key_len = 0;
+ wdev->wext.keys->params[idx].cipher = 0;
+ }
if (idx == wdev->wext.default_key)
wdev->wext.default_key = -1;
else if (idx == wdev->wext.default_mgmt_key)
@@ -512,36 +509,65 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
return 0;
return err;
- } else {
- if (addr)
- tx_key = false;
+ }
- if (cfg80211_validate_key_settings(params, idx, addr))
- return -EINVAL;
+ if (addr)
+ tx_key = false;
+ if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+ return -EINVAL;
+
+ err = 0;
+ if (wdev->current_bss)
err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
- if (err)
- return err;
+ if (err)
+ return err;
- if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+ if (!addr) {
+ wdev->wext.keys->params[idx] = *params;
+ memcpy(wdev->wext.keys->data[idx],
+ params->key, params->key_len);
+ wdev->wext.keys->params[idx].key =
+ wdev->wext.keys->data[idx];
+ }
+
+ if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+ (tx_key || (!addr && wdev->wext.default_key == -1))) {
+ if (wdev->current_bss)
err = rdev->ops->set_default_key(&rdev->wiphy,
dev, idx);
- if (!err)
- wdev->wext.default_key = idx;
- return err;
- }
+ if (!err)
+ wdev->wext.default_key = idx;
+ return err;
+ }
- if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
- (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+ (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ if (wdev->current_bss)
err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
dev, idx);
- if (!err)
- wdev->wext.default_mgmt_key = idx;
- return err;
- }
-
- return 0;
+ if (!err)
+ wdev->wext.default_mgmt_key = idx;
+ return err;
}
+
+ return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
+{
+ int err;
+
+ wdev_lock(dev->ieee80211_ptr);
+ err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+ tx_key, idx, params);
+ wdev_unlock(dev->ieee80211_ptr);
+
+ return err;
}
int cfg80211_wext_siwencode(struct net_device *dev,
@@ -554,6 +580,10 @@ int cfg80211_wext_siwencode(struct net_device *dev,
bool remove = false;
struct key_params params;
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
+
/* no use -- only MFP (set_default_mgmt_key) is optional */
if (!rdev->ops->del_key ||
!rdev->ops->add_key ||
@@ -574,9 +604,14 @@ int cfg80211_wext_siwencode(struct net_device *dev,
remove = true;
else if (erq->length == 0) {
/* No key data - just set the default TX key index */
- err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+ err = 0;
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ err = rdev->ops->set_default_key(&rdev->wiphy,
+ dev, idx);
if (!err)
wdev->wext.default_key = idx;
+ wdev_unlock(wdev);
return err;
}
@@ -609,6 +644,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
struct key_params params;
u32 cipher;
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
+
/* no use -- only MFP (set_default_mgmt_key) is optional */
if (!rdev->ops->del_key ||
!rdev->ops->add_key ||
@@ -682,37 +721,15 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
-struct giwencode_cookie {
- size_t buflen;
- char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
- struct giwencode_cookie *data = cookie;
-
- if (!params->key) {
- data->buflen = 0;
- return;
- }
-
- data->buflen = min_t(size_t, data->buflen, params->key_len);
- memcpy(data->keybuf, params->key, data->buflen);
-}
-
int cfg80211_wext_giwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *keybuf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- int idx, err;
- struct giwencode_cookie data = {
- .keybuf = keybuf,
- .buflen = erq->length,
- };
+ int idx;
- if (!rdev->ops->get_key)
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
idx = erq->flags & IW_ENCODE_INDEX;
@@ -727,24 +744,73 @@ int cfg80211_wext_giwencode(struct net_device *dev,
erq->flags = idx + 1;
- err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
- giwencode_get_key_cb);
- if (!err) {
- erq->length = data.buflen;
- erq->flags |= IW_ENCODE_ENABLED;
- return 0;
- }
-
- if (err == -ENOENT) {
+ if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
erq->flags |= IW_ENCODE_DISABLED;
erq->length = 0;
return 0;
}
- return err;
+ erq->length = min_t(size_t, erq->length,
+ wdev->wext.keys->params[idx].key_len);
+ memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
+int cfg80211_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct ieee80211_channel *chan;
+ int err;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ default:
+ chan = cfg80211_wext_freq(wdev->wiphy, freq);
+ if (!chan)
+ return -EINVAL;
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+ err = rdev->ops->set_channel(wdev->wiphy, chan,
+ NL80211_CHAN_NO_HT);
+ if (err)
+ return err;
+ rdev->channel = chan;
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
+
+int cfg80211_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+ default:
+ if (!rdev->channel)
+ return -EINVAL;
+ freq->m = rdev->channel->center_freq;
+ freq->e = 6;
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq);
+
int cfg80211_wext_siwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
@@ -827,3 +893,547 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
+
+static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
+ s32 auth_alg)
+{
+ int nr_alg = 0;
+
+ if (!auth_alg)
+ return -EINVAL;
+
+ if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM |
+ IW_AUTH_ALG_SHARED_KEY |
+ IW_AUTH_ALG_LEAP))
+ return -EINVAL;
+
+ if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) {
+ nr_alg++;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ }
+
+ if (auth_alg & IW_AUTH_ALG_SHARED_KEY) {
+ nr_alg++;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+ }
+
+ if (auth_alg & IW_AUTH_ALG_LEAP) {
+ nr_alg++;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP;
+ }
+
+ if (nr_alg > 1)
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ return 0;
+}
+
+static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
+{
+ wdev->wext.connect.crypto.wpa_versions = 0;
+
+ if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
+ IW_AUTH_WPA_VERSION_WPA2|
+ IW_AUTH_WPA_VERSION_DISABLED))
+ return -EINVAL;
+
+ if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
+ (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
+ IW_AUTH_WPA_VERSION_WPA2)))
+ return -EINVAL;
+
+ if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
+ wdev->wext.connect.crypto.wpa_versions &=
+ ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+
+ if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
+ wdev->wext.connect.crypto.wpa_versions |=
+ NL80211_WPA_VERSION_1;
+
+ if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2)
+ wdev->wext.connect.crypto.wpa_versions |=
+ NL80211_WPA_VERSION_2;
+
+ return 0;
+}
+
+static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
+{
+ wdev->wext.connect.crypto.cipher_group = 0;
+
+ if (cipher & IW_AUTH_CIPHER_WEP40)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_WEP40;
+ else if (cipher & IW_AUTH_CIPHER_WEP104)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_WEP104;
+ else if (cipher & IW_AUTH_CIPHER_TKIP)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_TKIP;
+ else if (cipher & IW_AUTH_CIPHER_CCMP)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_CCMP;
+ else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_AES_CMAC;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
+{
+ int nr_ciphers = 0;
+ u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
+
+ if (cipher & IW_AUTH_CIPHER_WEP40) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40;
+ nr_ciphers++;
+ }
+
+ if (cipher & IW_AUTH_CIPHER_WEP104) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104;
+ nr_ciphers++;
+ }
+
+ if (cipher & IW_AUTH_CIPHER_TKIP) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP;
+ nr_ciphers++;
+ }
+
+ if (cipher & IW_AUTH_CIPHER_CCMP) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP;
+ nr_ciphers++;
+ }
+
+ if (cipher & IW_AUTH_CIPHER_AES_CMAC) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC;
+ nr_ciphers++;
+ }
+
+ BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
+
+ wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
+
+ return 0;
+}
+
+
+static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
+{
+ int nr_akm_suites = 0;
+
+ if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
+ IW_AUTH_KEY_MGMT_PSK))
+ return -EINVAL;
+
+ if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
+ wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+ WLAN_AKM_SUITE_8021X;
+ nr_akm_suites++;
+ }
+
+ if (key_mgt & IW_AUTH_KEY_MGMT_PSK) {
+ wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+ WLAN_AKM_SUITE_PSK;
+ nr_akm_suites++;
+ }
+
+ wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
+
+ return 0;
+}
+
+int cfg80211_wext_siwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ switch (data->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_PRIVACY_INVOKED:
+ wdev->wext.connect.privacy = data->value;
+ return 0;
+ case IW_AUTH_WPA_VERSION:
+ return cfg80211_set_wpa_version(wdev, data->value);
+ case IW_AUTH_CIPHER_GROUP:
+ return cfg80211_set_cipher_group(wdev, data->value);
+ case IW_AUTH_KEY_MGMT:
+ return cfg80211_set_key_mgt(wdev, data->value);
+ case IW_AUTH_CIPHER_PAIRWISE:
+ return cfg80211_set_cipher_pairwise(wdev, data->value);
+ case IW_AUTH_80211_AUTH_ALG:
+ return cfg80211_set_auth_alg(wdev, data->value);
+ case IW_AUTH_WPA_ENABLED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ case IW_AUTH_MFP:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth);
+
+int cfg80211_wext_giwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ /* XXX: what do we need? */
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);
+
+int cfg80211_wext_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ bool ps = wdev->wext.ps;
+ int timeout = wdev->wext.ps_timeout;
+ int err;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+ if (!rdev->ops->set_power_mgmt)
+ return -EOPNOTSUPP;
+
+ if (wrq->disabled) {
+ ps = false;
+ } else {
+ switch (wrq->flags & IW_POWER_MODE) {
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
+ ps = true;
+ break;
+ default: /* Otherwise we ignore */
+ return -EINVAL;
+ }
+
+ if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
+ return -EINVAL;
+
+ if (wrq->flags & IW_POWER_TIMEOUT)
+ timeout = wrq->value / 1000;
+ }
+
+ err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout);
+ if (err)
+ return err;
+
+ wdev->wext.ps = ps;
+ wdev->wext.ps_timeout = timeout;
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower);
+
+int cfg80211_wext_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ wrq->disabled = !wdev->wext.ps;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
+
+static int cfg80211_wds_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int err;
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+ return -EINVAL;
+
+ if (addr->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!rdev->ops->set_wds_peer)
+ return -EOPNOTSUPP;
+
+ err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data);
+ if (err)
+ return err;
+
+ memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+static int cfg80211_wds_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+ return -EINVAL;
+
+ addr->sa_family = ARPHRD_ETHER;
+ memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+
+ return 0;
+}
+
+int cfg80211_wext_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_bitrate_mask mask;
+
+ if (!rdev->ops->set_bitrate_mask)
+ return -EOPNOTSUPP;
+
+ mask.fixed = 0;
+ mask.maxrate = 0;
+
+ if (rate->value < 0) {
+ /* nothing */
+ } else if (rate->fixed) {
+ mask.fixed = rate->value / 1000; /* kbps */
+ } else {
+ mask.maxrate = rate->value / 1000; /* kbps */
+ }
+
+ return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
+
+int cfg80211_wext_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ /* we are under RTNL - globally locked - so can use a static struct */
+ static struct station_info sinfo;
+ u8 addr[ETH_ALEN];
+ int err;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->get_station)
+ return -EOPNOTSUPP;
+
+ err = 0;
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN);
+ else
+ err = -EOPNOTSUPP;
+ wdev_unlock(wdev);
+ if (err)
+ return err;
+
+ err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
+ if (err)
+ return err;
+
+ if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
+ return -EOPNOTSUPP;
+
+ rate->value = 0;
+
+ if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
+ rate->value = 100000 * sinfo.txrate.legacy;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);
+
+/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
+struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ /* we are under RTNL - globally locked - so can use static structs */
+ static struct iw_statistics wstats;
+ static struct station_info sinfo;
+ u8 bssid[ETH_ALEN];
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
+ return NULL;
+
+ if (!rdev->ops->get_station)
+ return NULL;
+
+ /* Grab BSSID of current BSS, if any */
+ wdev_lock(wdev);
+ if (!wdev->current_bss) {
+ wdev_unlock(wdev);
+ return NULL;
+ }
+ memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
+ wdev_unlock(wdev);
+
+ if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo))
+ return NULL;
+
+ memset(&wstats, 0, sizeof(wstats));
+
+ switch (rdev->wiphy.signal_type) {
+ case CFG80211_SIGNAL_TYPE_MBM:
+ if (sinfo.filled & STATION_INFO_SIGNAL) {
+ int sig = sinfo.signal;
+ wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
+ wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
+ wstats.qual.updated |= IW_QUAL_DBM;
+ wstats.qual.level = sig;
+ if (sig < -110)
+ sig = -110;
+ else if (sig > -40)
+ sig = -40;
+ wstats.qual.qual = sig + 110;
+ break;
+ }
+ case CFG80211_SIGNAL_TYPE_UNSPEC:
+ if (sinfo.filled & STATION_INFO_SIGNAL) {
+ wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
+ wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
+ wstats.qual.level = sinfo.signal;
+ wstats.qual.qual = sinfo.signal;
+ break;
+ }
+ default:
+ wstats.qual.updated |= IW_QUAL_LEVEL_INVALID;
+ wstats.qual.updated |= IW_QUAL_QUAL_INVALID;
+ }
+
+ wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
+
+ return &wstats;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);
+
+int cfg80211_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_WDS:
+ return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwap);
+
+int cfg80211_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
+ case NL80211_IFTYPE_WDS:
+ return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwap);
+
+int cfg80211_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid);
+
+int cfg80211_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+ case NL80211_IFTYPE_STATION:
+ return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
+
+static const iw_handler cfg80211_handlers[] = {
+ [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
+ [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,
+ [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq,
+ [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode,
+ [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode,
+ [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange,
+ [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap,
+ [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap,
+ [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme,
+ [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan,
+ [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan,
+ [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid,
+ [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid,
+ [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate,
+ [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate,
+ [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts,
+ [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts,
+ [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag,
+ [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag,
+ [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower,
+ [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower,
+ [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry,
+ [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry,
+ [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode,
+ [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode,
+ [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower,
+ [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower,
+ [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie,
+ [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth,
+ [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth,
+ [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,
+};
+
+const struct iw_handler_def cfg80211_wext_handler = {
+ .num_standard = ARRAY_SIZE(cfg80211_handlers),
+ .standard = cfg80211_handlers,
+ .get_wireless_stats = cfg80211_wireless_stats,
+};
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h
new file mode 100644
index 000000000000..9a3774749589
--- /dev/null
+++ b/net/wireless/wext-compat.h
@@ -0,0 +1,50 @@
+#ifndef __WEXT_COMPAT
+#define __WEXT_COMPAT
+
+#include <net/iw_handler.h>
+#include <linux/wireless.h>
+
+int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_ibss_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_ibss_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_ibss_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_ibss_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra);
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid);
+
+struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
+ struct iw_freq *freq);
+
+
+extern const struct iw_handler_def cfg80211_wext_handler;
+#endif /* __WEXT_COMPAT */
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
new file mode 100644
index 000000000000..7bacbd1c2af6
--- /dev/null
+++ b/net/wireless/wext-sme.c
@@ -0,0 +1,383 @@
+/*
+ * cfg80211 wext compat for managed mode.
+ *
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <net/cfg80211.h>
+#include "wext-compat.h"
+#include "nl80211.h"
+
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ struct cfg80211_cached_keys *ck = NULL;
+ int err, i;
+
+ ASSERT_RDEV_LOCK(rdev);
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (!netif_running(wdev->netdev))
+ return 0;
+
+ wdev->wext.connect.ie = wdev->wext.ie;
+ wdev->wext.connect.ie_len = wdev->wext.ie_len;
+ wdev->wext.connect.privacy = wdev->wext.default_key != -1;
+
+ if (wdev->wext.keys) {
+ wdev->wext.keys->def = wdev->wext.default_key;
+ wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+ }
+
+ if (!wdev->wext.connect.ssid_len)
+ return 0;
+
+ if (wdev->wext.keys) {
+ ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+ if (!ck)
+ return -ENOMEM;
+ for (i = 0; i < 6; i++)
+ ck->params[i].key = ck->data[i];
+ }
+ err = __cfg80211_connect(rdev, wdev->netdev,
+ &wdev->wext.connect, ck);
+ if (err)
+ kfree(ck);
+
+ return err;
+}
+
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct ieee80211_channel *chan;
+ int err;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ chan = cfg80211_wext_freq(wdev->wiphy, freq);
+ if (chan && IS_ERR(chan))
+ return PTR_ERR(chan);
+
+ if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+
+ cfg80211_lock_rdev(rdev);
+ wdev_lock(wdev);
+
+ if (wdev->sme_state != CFG80211_SME_IDLE) {
+ bool event = true;
+
+ if (wdev->wext.connect.channel == chan) {
+ err = 0;
+ goto out;
+ }
+
+ /* if SSID set, we'll try right again, avoid event */
+ if (wdev->wext.connect.ssid_len)
+ event = false;
+ err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+ dev, WLAN_REASON_DEAUTH_LEAVING,
+ event);
+ if (err)
+ goto out;
+ }
+
+
+ wdev->wext.connect.channel = chan;
+
+ /* SSID is not set, we just want to switch channel */
+ if (wdev->wext.connect.ssid_len && chan) {
+ err = -EOPNOTSUPP;
+ if (rdev->ops->set_channel)
+ err = rdev->ops->set_channel(wdev->wiphy, chan,
+ NL80211_CHAN_NO_HT);
+ goto out;
+ }
+
+ err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+ wdev_unlock(wdev);
+ cfg80211_unlock_rdev(rdev);
+ return err;
+}
+
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct ieee80211_channel *chan = NULL;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ chan = wdev->current_bss->pub.channel;
+ else if (wdev->wext.connect.channel)
+ chan = wdev->wext.connect.channel;
+ wdev_unlock(wdev);
+
+ if (chan) {
+ freq->m = chan->center_freq;
+ freq->e = 6;
+ return 0;
+ }
+
+ /* no channel if not joining */
+ return -EINVAL;
+}
+
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ size_t len = data->length;
+ int err;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ if (!data->flags)
+ len = 0;
+
+ /* iwconfig uses nul termination in SSID.. */
+ if (len > 0 && ssid[len - 1] == '\0')
+ len--;
+
+ cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+ wdev_lock(wdev);
+
+ err = 0;
+
+ if (wdev->sme_state != CFG80211_SME_IDLE) {
+ bool event = true;
+
+ if (wdev->wext.connect.ssid && len &&
+ len == wdev->wext.connect.ssid_len &&
+ memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
+ goto out;
+
+ /* if SSID set now, we'll try to connect, avoid event */
+ if (len)
+ event = false;
+ err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+ dev, WLAN_REASON_DEAUTH_LEAVING,
+ event);
+ if (err)
+ goto out;
+ }
+
+ wdev->wext.connect.ssid = wdev->wext.ssid;
+ memcpy(wdev->wext.ssid, ssid, len);
+ wdev->wext.connect.ssid_len = len;
+
+ wdev->wext.connect.crypto.control_port = false;
+
+ err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+ wdev_unlock(wdev);
+ cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+ return err;
+}
+
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ data->flags = 0;
+
+ wdev_lock(wdev);
+ if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
+ data->flags = 1;
+ data->length = wdev->wext.connect.ssid_len;
+ memcpy(ssid, wdev->wext.connect.ssid, data->length);
+ } else
+ data->flags = 0;
+ wdev_unlock(wdev);
+
+ return 0;
+}
+
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ u8 *bssid = ap_addr->sa_data;
+ int err;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ if (ap_addr->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ /* automatic mode */
+ if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
+ bssid = NULL;
+
+ cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+ wdev_lock(wdev);
+
+ if (wdev->sme_state != CFG80211_SME_IDLE) {
+ err = 0;
+ /* both automatic */
+ if (!bssid && !wdev->wext.connect.bssid)
+ goto out;
+
+ /* fixed already - and no change */
+ if (wdev->wext.connect.bssid && bssid &&
+ compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+ goto out;
+
+ err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+ dev, WLAN_REASON_DEAUTH_LEAVING,
+ false);
+ if (err)
+ goto out;
+ }
+
+ if (bssid) {
+ memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
+ wdev->wext.connect.bssid = wdev->wext.bssid;
+ } else
+ wdev->wext.connect.bssid = NULL;
+
+ err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+ wdev_unlock(wdev);
+ cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+ return err;
+}
+
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ /* call only for station! */
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+
+ wdev_lock(wdev);
+ if (wdev->current_bss)
+ memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
+ else if (wdev->wext.connect.bssid)
+ memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
+ else
+ memset(ap_addr->sa_data, 0, ETH_ALEN);
+ wdev_unlock(wdev);
+
+ return 0;
+}
+
+int cfg80211_wext_siwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ u8 *ie = extra;
+ int ie_len = data->length, err;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ if (!ie_len)
+ ie = NULL;
+
+ wdev_lock(wdev);
+
+ /* no change */
+ err = 0;
+ if (wdev->wext.ie_len == ie_len &&
+ memcmp(wdev->wext.ie, ie, ie_len) == 0)
+ goto out;
+
+ if (ie_len) {
+ ie = kmemdup(extra, ie_len, GFP_KERNEL);
+ if (!ie) {
+ err = -ENOMEM;
+ goto out;
+ }
+ } else
+ ie = NULL;
+
+ kfree(wdev->wext.ie);
+ wdev->wext.ie = ie;
+ wdev->wext.ie_len = ie_len;
+
+ if (wdev->sme_state != CFG80211_SME_IDLE) {
+ err = __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, false);
+ if (err)
+ goto out;
+ }
+
+ /* userspace better not think we'll reconnect */
+ err = 0;
+ out:
+ wdev_unlock(wdev);
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
+
+int cfg80211_wext_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ struct cfg80211_registered_device *rdev;
+ int err;
+
+ if (!wdev)
+ return -EOPNOTSUPP;
+
+ rdev = wiphy_to_dev(wdev->wiphy);
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+ if (mlme->addr.sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ wdev_lock(wdev);
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ case IW_MLME_DISASSOC:
+ err = __cfg80211_disconnect(rdev, dev, mlme->reason_code,
+ true);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+ wdev_unlock(wdev);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 252c2010c2e2..3fe3c2c0ce11 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -417,6 +417,21 @@ static const int event_type_size[] = {
IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
};
+#ifdef CONFIG_COMPAT
+static const int compat_event_type_size[] = {
+ IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */
+ 0,
+ IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
+ 0,
+ IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */
+ IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
+ IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
+ 0,
+ IW_EV_COMPAT_POINT_LEN, /* Without variable payload */
+ IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
+ IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
+};
+#endif
/************************ COMMON SUBROUTINES ************************/
/*
@@ -610,6 +625,11 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
{
/* 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 && dev->wireless_handlers)
+ stats = &nullstats;
if (stats) {
seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
@@ -628,7 +648,9 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
stats->discard.nwid, stats->discard.code,
stats->discard.fragment, stats->discard.retries,
stats->discard.misc, stats->miss.beacon);
- stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+
+ if (stats != &nullstats)
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
}
}
@@ -1250,65 +1272,58 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
}
#endif
-/************************* EVENT PROCESSING *************************/
-/*
- * Process events generated by the wireless layer or the driver.
- * Most often, the event will be propagated through rtnetlink
- */
+static int __net_init wext_pernet_init(struct net *net)
+{
+ skb_queue_head_init(&net->wext_nlevents);
+ return 0;
+}
-/* ---------------------------------------------------------------- */
-/*
- * Locking...
- * ----------
- *
- * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
- * the locking issue in here and implementing this code !
- *
- * The issue : wireless_send_event() is often called in interrupt context,
- * while the Netlink layer can never be called in interrupt context.
- * The fully formed RtNetlink events are queued, and then a tasklet is run
- * to feed those to Netlink.
- * The skb_queue is interrupt safe, and its lock is not held while calling
- * Netlink, so there is no possibility of dealock.
- * Jean II
- */
+static void __net_exit wext_pernet_exit(struct net *net)
+{
+ skb_queue_purge(&net->wext_nlevents);
+}
-static struct sk_buff_head wireless_nlevent_queue;
+static struct pernet_operations wext_pernet_ops = {
+ .init = wext_pernet_init,
+ .exit = wext_pernet_exit,
+};
static int __init wireless_nlevent_init(void)
{
- skb_queue_head_init(&wireless_nlevent_queue);
+ return register_pernet_subsys(&wext_pernet_ops);
return 0;
}
subsys_initcall(wireless_nlevent_init);
-static void wireless_nlevent_process(unsigned long data)
+/* 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);
+ }
- while ((skb = skb_dequeue(&wireless_nlevent_queue)))
- rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+ rtnl_unlock();
}
-static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
-/* ---------------------------------------------------------------- */
-/*
- * Fill a rtnetlink message with our event data.
- * Note that we propage only the specified event and don't dump the
- * current wireless config. Dumping the wireless config is far too
- * expensive (for each parameter, the driver need to query the hardware).
- */
-static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
- int type, char *event, int event_len)
+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, type, sizeof(*r), 0);
- if (nlh == NULL)
- return -EMSGSIZE;
+ nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
+ if (!nlh)
+ return NULL;
r = nlmsg_data(nlh);
r->ifi_family = AF_UNSPEC;
@@ -1319,48 +1334,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
r->ifi_change = 0; /* Wireless changes don't affect those flags */
NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
- /* Add the wireless events in the netlink packet */
- NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
- return nlmsg_end(skb, nlh);
-
-nla_put_failure:
+ return nlh;
+ nla_put_failure:
nlmsg_cancel(skb, nlh);
- return -EMSGSIZE;
+ return NULL;
}
-/* ---------------------------------------------------------------- */
-/*
- * Create and broadcast and send it on the standard rtnetlink socket
- * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
- * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
- * within a RTM_NEWLINK event.
- */
-static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
-{
- struct sk_buff *skb;
- int err;
-
- if (!net_eq(dev_net(dev), &init_net))
- return;
-
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
- if (!skb)
- return;
-
- err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
- if (err < 0) {
- WARN_ON(err == -EMSGSIZE);
- kfree_skb(skb);
- return;
- }
-
- NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
- skb_queue_tail(&wireless_nlevent_queue, skb);
- tasklet_schedule(&wireless_nlevent_tasklet);
-}
-/* ---------------------------------------------------------------- */
/*
* Main event dispatcher. Called from other parts and drivers.
* Send the event on the appropriate channels.
@@ -1369,7 +1350,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
void wireless_send_event(struct net_device * dev,
unsigned int cmd,
union iwreq_data * wrqu,
- char * extra)
+ const char * extra)
{
const struct iw_ioctl_description * descr = NULL;
int extra_len = 0;
@@ -1379,6 +1360,25 @@ void wireless_send_event(struct net_device * dev,
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) {
@@ -1426,25 +1426,107 @@ void wireless_send_event(struct net_device * dev,
hdr_len = event_type_size[descr->header_type];
event_len = hdr_len + extra_len;
- /* Create temporary buffer to hold the event */
- event = kmalloc(event_len, GFP_ATOMIC);
- if (event == NULL)
+ /*
+ * 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 */
+ /* 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)
+ 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 */
- rtmsg_iwinfo(dev, (char *) event, event_len);
+ nlh = rtnetlink_ifinfo_prep(dev, compskb);
+ if (WARN_ON(!nlh)) {
+ kfree_skb(skb);
+ kfree_skb(compskb);
+ return;
+ }
- /* Cleanup */
- kfree(event);
+ /* 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);
- return; /* Always success, I guess ;-) */
+ 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);
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/basic/fixdep.c b/scripts/basic/fixdep.c
index 72c15205bb2b..f9c1e5408318 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -16,8 +16,7 @@
* 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/config.h> which then again
- * includes <linux/autoconf.h>
+ * every file in the kernel includes <linux/autoconf.h>.
*
* If the user re-runs make *config, linux/autoconf.h will be
* regenerated. make notices that and will rebuild every file which
diff --git a/scripts/binoffset.c b/scripts/binoffset.c
deleted file mode 100644
index 1a2e39b8e3e5..000000000000
--- a/scripts/binoffset.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/***************************************************************************
- * binoffset.c
- * (C) 2002 Randy Dunlap <rdunlap@xenotime.net>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# binoffset.c:
-# - searches a (binary) file for a specified (binary) pattern
-# - returns the offset of the located pattern or ~0 if not found
-# - exits with exit status 0 normally or non-0 if pattern is not found
-# or any other error occurs.
-
-****************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#define VERSION "0.1"
-#define BUF_SIZE (16 * 1024)
-#define PAT_SIZE 100
-
-char *progname;
-char *inputname;
-int inputfd;
-unsigned int bix; /* buf index */
-unsigned char patterns [PAT_SIZE] = {0}; /* byte-sized pattern array */
-int pat_len; /* actual number of pattern bytes */
-unsigned char *madr; /* mmap address */
-size_t filesize;
-int num_matches = 0;
-off_t firstloc = 0;
-
-void usage (void)
-{
- fprintf (stderr, "%s ver. %s\n", progname, VERSION);
- fprintf (stderr, "usage: %s filename pattern_bytes\n",
- progname);
- fprintf (stderr, " [prints location of pattern_bytes in file]\n");
- exit (1);
-}
-
-void get_pattern (int pat_count, char *pats [])
-{
- int ix, err, tmp;
-
-#ifdef DEBUG
- fprintf (stderr,"get_pattern: count = %d\n", pat_count);
- for (ix = 0; ix < pat_count; ix++)
- fprintf (stderr, " pat # %d: [%s]\n", ix, pats[ix]);
-#endif
-
- for (ix = 0; ix < pat_count; ix++) {
- tmp = 0;
- err = sscanf (pats[ix], "%5i", &tmp);
- if (err != 1 || tmp > 0xff) {
- fprintf (stderr, "pattern or value error in pattern # %d [%s]\n",
- ix, pats[ix]);
- usage ();
- }
- patterns [ix] = tmp;
- }
- pat_len = pat_count;
-}
-
-void search_pattern (void)
-{
- for (bix = 0; bix < filesize; bix++) {
- if (madr[bix] == patterns[0]) {
- if (memcmp (&madr[bix], patterns, pat_len) == 0) {
- if (num_matches == 0)
- firstloc = bix;
- num_matches++;
- }
- }
- }
-}
-
-#ifdef NOTDEF
-size_t get_filesize (int fd)
-{
- off_t end_off = lseek (fd, 0, SEEK_END);
- lseek (fd, 0, SEEK_SET);
- return (size_t) end_off;
-}
-#endif
-
-size_t get_filesize (int fd)
-{
- int err;
- struct stat stat;
-
- err = fstat (fd, &stat);
- fprintf (stderr, "filesize: %ld\n", err < 0 ? (long)err : stat.st_size);
- if (err < 0)
- return err;
- return (size_t) stat.st_size;
-}
-
-int main (int argc, char *argv [])
-{
- progname = argv[0];
-
- if (argc < 3)
- usage ();
-
- get_pattern (argc - 2, argv + 2);
-
- inputname = argv[1];
-
- inputfd = open (inputname, O_RDONLY);
- if (inputfd == -1) {
- fprintf (stderr, "%s: cannot open '%s'\n",
- progname, inputname);
- exit (3);
- }
-
- filesize = get_filesize (inputfd);
-
- madr = mmap (0, filesize, PROT_READ, MAP_PRIVATE, inputfd, 0);
- if (madr == MAP_FAILED) {
- fprintf (stderr, "mmap error = %d\n", errno);
- close (inputfd);
- exit (4);
- }
-
- search_pattern ();
-
- if (munmap (madr, filesize))
- fprintf (stderr, "munmap error = %d\n", errno);
-
- if (close (inputfd))
- fprintf (stderr, "%s: error %d closing '%s'\n",
- progname, errno, inputname);
-
- fprintf (stderr, "number of pattern matches = %d\n", num_matches);
- if (num_matches == 0)
- firstloc = ~0;
- printf ("%ld\n", firstloc);
- fprintf (stderr, "%ld\n", firstloc);
-
- exit (num_matches ? 0 : 2);
-}
-
-/* end binoffset.c */
diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig
index 72997c353cb3..37f30d36c944 100755
--- a/scripts/extract-ikconfig
+++ b/scripts/extract-ikconfig
@@ -1,78 +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`
-
- 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()
+# ----------------------------------------------------------------------
+# 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()
{
- echo " usage: extract-ikconfig [b]zImage_filename"
-}
-
-clean_up()
-{
- 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"
-
-# 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"
-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/get_maintainer.pl b/scripts/get_maintainer.pl
index 3e733146cd51..278a45bd45a5 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -13,7 +13,7 @@
use strict;
my $P = $0;
-my $V = '0.16';
+my $V = '0.17';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -27,6 +27,7 @@ my $email_git = 1;
my $email_git_penguin_chiefs = 0;
my $email_git_min_signatures = 1;
my $email_git_max_maintainers = 5;
+my $email_git_min_percent = 5;
my $email_git_since = "1-year-ago";
my $output_multiline = 1;
my $output_separator = ", ";
@@ -65,6 +66,7 @@ if (!GetOptions(
'git-chief-penguins!' => \$email_git_penguin_chiefs,
'git-min-signatures=i' => \$email_git_min_signatures,
'git-max-maintainers=i' => \$email_git_max_maintainers,
+ 'git-min-percent=i' => \$email_git_min_percent,
'git-since=s' => \$email_git_since,
'm!' => \$email_maintainer,
'n!' => \$email_usename,
@@ -132,6 +134,10 @@ while (<MAINT>) {
$value =~ s@\.@\\\.@g; ##Convert . to \.
$value =~ s/\*/\.\*/g; ##Convert * to .*
$value =~ s/\?/\./g; ##Convert ? to .
+ ##if pattern is a directory and it lacks a trailing slash, add one
+ if ((-d $value)) {
+ $value =~ s@([^/])$@$1/@;
+ }
}
push(@typevalue, "$type:$value");
} elsif (!/^(\s)*$/) {
@@ -146,8 +152,10 @@ close(MAINT);
my @files = ();
foreach my $file (@ARGV) {
- next if ((-d $file));
- if (!(-f $file)) {
+ ##if $file is a directory and it lacks a trailing slash, add one
+ if ((-d $file)) {
+ $file =~ s@([^/])$@$1/@;
+ } elsif (!(-f $file)) {
die "$P: file '${file}' not found\n";
}
if ($from_filename) {
@@ -292,7 +300,7 @@ sub file_match_pattern {
sub usage {
print <<EOT;
usage: $P [options] patchfile
- $P [options] -f file
+ $P [options] -f file|directory
version: $V
MAINTAINER field selection options:
@@ -301,6 +309,7 @@ MAINTAINER field selection options:
--git-chief-penguins => include ${penguin_chiefs}
--git-min-signatures => number of signatures required (default: 1)
--git-max-maintainers => maximum maintainers to add (default: 5)
+ --git-min-percent => minimum percentage of commits required (default: 5)
--git-since => git history to use (default: 1-year-ago)
--m => include maintainer(s) if any
--n => include name 'Full Name <addr\@domain.tld>'
@@ -322,6 +331,15 @@ Other options:
--version => show version
--help => show this help information
+Notes:
+ Using "-f directory" may give unexpected results:
+
+ Used with "--git", git signators for _all_ files in and below
+ directory are examined as git recurses directories.
+ Any specified X: (exclude) pattern matches are _not_ ignored.
+ Used with "--nogit", directory is used as a pattern match,
+ no individual file within the directory or subdirectory
+ is matched.
EOT
}
@@ -482,6 +500,7 @@ sub recent_git_signoffs {
my $output = "";
my $count = 0;
my @lines = ();
+ my $total_sign_offs;
if (which("git") eq "") {
warn("$P: git not found. Add --nogit to options?\n");
@@ -505,17 +524,26 @@ sub recent_git_signoffs {
$output =~ s/^\s*//gm;
@lines = split("\n", $output);
+
+ $total_sign_offs = 0;
+ foreach my $line (@lines) {
+ if ($line =~ m/([0-9]+)\s+(.*)/) {
+ $total_sign_offs += $1;
+ } else {
+ die("$P: Unexpected git output: ${line}\n");
+ }
+ }
+
foreach my $line (@lines) {
if ($line =~ m/([0-9]+)\s+(.*)/) {
my $sign_offs = $1;
$line = $2;
$count++;
if ($sign_offs < $email_git_min_signatures ||
- $count > $email_git_max_maintainers) {
+ $count > $email_git_max_maintainers ||
+ $sign_offs * 100 / $total_sign_offs < $email_git_min_percent) {
last;
}
- } else {
- die("$P: Unexpected git output: ${line}\n");
}
if ($line =~ m/(.+)<(.+)>/) {
my $git_name = $1;
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 3baaaecd6b13..5de3303e65f5 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -38,14 +38,14 @@ static int conf_cnt;
static char line[128];
static struct menu *rootEntry;
-static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
-
-static const char *get_help(struct menu *menu)
+static void print_help(struct menu *menu)
{
- if (menu_has_help(menu))
- return _(menu_get_help(menu));
- else
- return nohelp_text;
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
}
static void strip(char *str)
@@ -140,7 +140,7 @@ int conf_string(struct menu *menu)
case '?':
/* print help */
if (line[1] == '\n') {
- printf("\n%s\n", get_help(menu));
+ print_help(menu);
def = NULL;
break;
}
@@ -220,7 +220,7 @@ static int conf_sym(struct menu *menu)
if (sym_set_tristate_value(sym, newval))
return 0;
help:
- printf("\n%s\n", get_help(menu));
+ print_help(menu);
}
}
@@ -307,7 +307,7 @@ static int conf_choice(struct menu *menu)
fgets(line, 128, stdin);
strip(line);
if (line[0] == '?') {
- printf("\n%s\n", get_help(menu));
+ print_help(menu);
continue;
}
if (!line[0])
@@ -331,7 +331,7 @@ static int conf_choice(struct menu *menu)
if (!child)
continue;
if (line[strlen(line) - 1] == '?') {
- printf("\n%s\n", get_help(child));
+ print_help(child);
continue;
}
sym_set_choice_value(sym, child->sym);
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index 579ece4fa584..cd8a2f00a97e 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1098,6 +1098,8 @@ void expr_fprint(struct expr *e, FILE *out)
static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
{
str_append((struct gstr*)data, str);
+ if (sym)
+ str_printf((struct gstr*)data, " [=%s]", sym_get_string_value(sym));
}
void expr_gstr_print(struct expr *e, struct gstr *gs)
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 199b22bb49e2..65464366fe38 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -456,19 +456,9 @@ static void text_insert_help(struct menu *menu)
GtkTextBuffer *buffer;
GtkTextIter start, end;
const char *prompt = _(menu_get_prompt(menu));
- gchar *name;
- const char *help;
+ struct gstr help = str_new();
- help = menu_get_help(menu);
-
- /* Gettextize if the help text not empty */
- if ((help != 0) && (help[0] != 0))
- help = _(help);
-
- if (menu->sym && menu->sym->name)
- name = g_strdup_printf(menu->sym->name);
- else
- name = g_strdup("");
+ menu_get_ext_help(menu, &help);
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
gtk_text_buffer_get_bounds(buffer, &start, &end);
@@ -478,14 +468,11 @@ static void text_insert_help(struct menu *menu)
gtk_text_buffer_get_end_iter(buffer, &end);
gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
NULL);
- gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
- gtk_text_buffer_get_end_iter(buffer, &end);
- gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
- NULL);
gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
gtk_text_buffer_get_end_iter(buffer, &end);
- gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
+ gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
NULL);
+ str_free(&help);
}
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 8e69461313d1..ffeb532b2cff 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -17,6 +17,8 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu));
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str,void,(struct gstr *r, struct symbol *sym));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
/* symbol.c */
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 25b60bc117f7..d82953573588 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -199,8 +199,6 @@ inputbox_instructions_string[] = N_(
setmod_text[] = N_(
"This feature depends on another which has been configured as a module.\n"
"As a result, this feature will be built as a module."),
-nohelp_text[] = N_(
- "There is no help available for this kernel option.\n"),
load_config_text[] = N_(
"Enter the name of the configuration file you wish to load. "
"Accept the name shown to restore the configuration you "
@@ -284,66 +282,6 @@ static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
-static void get_prompt_str(struct gstr *r, struct property *prop)
-{
- int i, j;
- struct menu *submenu[8], *menu;
-
- str_printf(r, _("Prompt: %s\n"), _(prop->text));
- str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
- prop->menu->lineno);
- if (!expr_is_yes(prop->visible.expr)) {
- str_append(r, _(" Depends on: "));
- expr_gstr_print(prop->visible.expr, r);
- str_append(r, "\n");
- }
- menu = prop->menu->parent;
- for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
- submenu[i++] = menu;
- if (i > 0) {
- str_printf(r, _(" Location:\n"));
- for (j = 4; --i >= 0; j += 2) {
- menu = submenu[i];
- str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
- if (menu->sym) {
- str_printf(r, " (%s [=%s])", menu->sym->name ?
- menu->sym->name : _("<choice>"),
- sym_get_string_value(menu->sym));
- }
- str_append(r, "\n");
- }
- }
-}
-
-static void get_symbol_str(struct gstr *r, struct symbol *sym)
-{
- bool hit;
- struct property *prop;
-
- if (sym && sym->name)
- str_printf(r, "Symbol: %s [=%s]\n", sym->name,
- sym_get_string_value(sym));
- for_all_prompts(sym, prop)
- get_prompt_str(r, prop);
- hit = false;
- for_all_properties(sym, prop, P_SELECT) {
- if (!hit) {
- str_append(r, " Selects: ");
- hit = true;
- } else
- str_printf(r, " && ");
- expr_gstr_print(prop->expr, r);
- }
- if (hit)
- str_append(r, "\n");
- if (sym->rev_dep.expr) {
- str_append(r, _(" Selected by: "));
- expr_gstr_print(sym->rev_dep.expr, r);
- str_append(r, "\n");
- }
- str_append(r, "\n\n");
-}
-
static struct gstr get_relations_str(struct symbol **sym_arr)
{
struct symbol *sym;
@@ -699,19 +637,9 @@ static void show_helptext(const char *title, const char *text)
static void show_help(struct menu *menu)
{
struct gstr help = str_new();
- struct symbol *sym = menu->sym;
-
- if (menu_has_help(menu))
- {
- if (sym->name) {
- str_printf(&help, "CONFIG_%s:\n\n", sym->name);
- str_append(&help, _(menu_get_help(menu)));
- str_append(&help, "\n");
- }
- } else {
- str_append(&help, nohelp_text);
- }
- get_symbol_str(&help, sym);
+
+ menu_get_ext_help(menu, &help);
+
show_helptext(_(menu_get_prompt(menu)), str_get(&help));
str_free(&help);
}
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 07ff8d105c9d..931d782a2392 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -9,6 +9,9 @@
#define LKC_DIRECT_LINK
#include "lkc.h"
+static const char nohelp_text[] = N_(
+ "There is no help available for this kernel option.\n");
+
struct menu rootmenu;
static struct menu **last_entry_ptr;
@@ -451,3 +454,79 @@ const char *menu_get_help(struct menu *menu)
else
return "";
}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+ int i, j;
+ struct menu *submenu[8], *menu;
+
+ str_printf(r, _("Prompt: %s\n"), _(prop->text));
+ str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, _(" Depends on: "));
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
+ menu = prop->menu->parent;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+ submenu[i++] = menu;
+ if (i > 0) {
+ str_printf(r, _(" Location:\n"));
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : _("<choice>"),
+ sym_get_string_value(menu->sym));
+ }
+ str_append(r, "\n");
+ }
+ }
+}
+
+void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+ bool hit;
+ struct property *prop;
+
+ if (sym && sym->name)
+ str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+ sym_get_string_value(sym));
+ for_all_prompts(sym, prop)
+ get_prompt_str(r, prop);
+ hit = false;
+ for_all_properties(sym, prop, P_SELECT) {
+ if (!hit) {
+ str_append(r, " Selects: ");
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+ if (sym->rev_dep.expr) {
+ str_append(r, _(" Selected by: "));
+ expr_gstr_print(sym->rev_dep.expr, r);
+ str_append(r, "\n");
+ }
+ str_append(r, "\n\n");
+}
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+ struct symbol *sym = menu->sym;
+
+ if (menu_has_help(menu)) {
+ if (sym->name) {
+ str_printf(help, "CONFIG_%s:\n\n", sym->name);
+ str_append(help, _(menu_get_help(menu)));
+ str_append(help, "\n");
+ }
+ } else {
+ str_append(help, nohelp_text);
+ }
+ get_symbol_str(help, sym);
+}
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index ce7d508c7520..00c51507cfcc 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1042,12 +1042,10 @@ void ConfigInfoView::menuInfo(void)
if (showDebug())
debug = debug_info(sym);
- help = menu_get_help(menu);
- /* Gettextize if the help text not empty */
- if (help.isEmpty())
- help = print_filter(menu_get_help(menu));
- else
- help = print_filter(_(menu_get_help(menu)));
+ struct gstr help_gstr = str_new();
+ menu_get_ext_help(menu, &help_gstr);
+ help = print_filter(str_get(&help_gstr));
+ str_free(&help_gstr);
} else if (menu->prompt) {
head += "<big><b>";
head += print_filter(_(menu->prompt->text));
diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl
index 528492bcba5b..89774011965d 100644
--- a/scripts/markup_oops.pl
+++ b/scripts/markup_oops.pl
@@ -1,6 +1,7 @@
#!/usr/bin/perl
use File::Basename;
+use Math::BigInt;
# Copyright 2008, Intel Corporation
#
@@ -172,8 +173,8 @@ while (<STDIN>) {
parse_x86_regs($line);
}
-my $decodestart = hex($target) - hex($func_offset);
-my $decodestop = hex($target) + 8192;
+my $decodestart = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$func_offset");
+my $decodestop = Math::BigInt->from_hex("0x$target") + 8192;
if ($target eq "0") {
print "No oops found!\n";
print "Usage: \n";
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index aadc5223dcdb..ecf9c7dc1825 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -334,8 +334,6 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
deps_drivers/net/dummy.o := \
drivers/net/dummy.c \
$(wildcard include/config/net/fastroute.h) \
- include/linux/config.h \
- $(wildcard include/config/h.h) \
include/linux/module.h \
Sum all files in the same dir or subdirs.
diff --git a/scripts/module-common.lds b/scripts/module-common.lds
new file mode 100644
index 000000000000..47a1f9ae0ede
--- /dev/null
+++ b/scripts/module-common.lds
@@ -0,0 +1,8 @@
+/*
+ * Common module linker script, always used when linking a module.
+ * Archs are free to supply their own linker scripts. ld will
+ * combine them automatically.
+ */
+SECTIONS {
+ /DISCARD/ : { *(.discard) }
+}
diff --git a/security/capability.c b/security/capability.c
index 21b6cead6a8e..f218dd361647 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -863,7 +863,7 @@ struct security_operations default_security_ops = {
void security_fixup_ops(struct security_operations *ops)
{
- set_to_cap_if_null(ops, ptrace_may_access);
+ set_to_cap_if_null(ops, ptrace_access_check);
set_to_cap_if_null(ops, ptrace_traceme);
set_to_cap_if_null(ops, capget);
set_to_cap_if_null(ops, capset);
diff --git a/security/commoncap.c b/security/commoncap.c
index 48b7e0228fa3..aa97704564d4 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -101,7 +101,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
}
/**
- * cap_ptrace_may_access - Determine whether the current process may access
+ * cap_ptrace_access_check - Determine whether the current process may access
* another
* @child: The process to be accessed
* @mode: The mode of attachment.
@@ -109,7 +109,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
* Determine whether a process may access another, returning 0 if permission
* granted, -ve if denied.
*/
-int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
+int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
int ret = 0;
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 769f9bdfd2b3..39793c774f33 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -120,6 +120,7 @@ static int proc_keys_open(struct inode *inode, struct file *file)
}
static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
+ __acquires(key_serial_lock)
{
struct rb_node *_p;
loff_t pos = *_pos;
@@ -144,6 +145,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
}
static void proc_keys_stop(struct seq_file *p, void *v)
+ __releases(key_serial_lock)
{
spin_unlock(&key_serial_lock);
}
@@ -257,6 +259,7 @@ static int proc_key_users_open(struct inode *inode, struct file *file)
}
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
+ __acquires(key_user_lock)
{
struct rb_node *_p;
loff_t pos = *_pos;
@@ -281,6 +284,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
}
static void proc_key_users_stop(struct seq_file *p, void *v)
+ __releases(key_user_lock)
{
spin_unlock(&key_user_lock);
}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 276d27882ce8..ed929af466d3 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -702,7 +702,7 @@ long join_session_keyring(const char *name)
/* only permit this if there's a single thread in the thread group -
* this avoids us having to adjust the creds on all threads and risking
* ENOMEM */
- if (!is_single_threaded(current))
+ if (!current_is_single_threaded())
return -EMLINK;
new = prepare_creds();
diff --git a/security/security.c b/security/security.c
index dc7674fbfc7a..4501c5e1f988 100644
--- a/security/security.c
+++ b/security/security.c
@@ -124,9 +124,9 @@ int register_security(struct security_operations *ops)
/* Security operations */
-int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
+int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
- return security_ops->ptrace_may_access(child, mode);
+ return security_ops->ptrace_access_check(child, mode);
}
int security_ptrace_traceme(struct task_struct *parent)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index b2ab60859832..236aaa2ea86d 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
* @tclass: target security class
* @av: access vector
*/
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{
const char **common_pts = NULL;
u32 common_base = 0;
@@ -970,3 +970,9 @@ u32 avc_policy_seqno(void)
{
return avc_cache.latest_notif;
}
+
+void avc_disable(void)
+{
+ if (avc_node_cachep)
+ kmem_cache_destroy(avc_node_cachep);
+}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 15c2a08a66f1..e65677da36bd 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1854,12 +1854,12 @@ static inline u32 open_file_to_av(struct file *file)
/* Hook functions begin here. */
-static int selinux_ptrace_may_access(struct task_struct *child,
+static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
int rc;
- rc = cap_ptrace_may_access(child, mode);
+ rc = cap_ptrace_access_check(child, mode);
if (rc)
return rc;
@@ -2938,11 +2938,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
const struct cred *cred = current_cred();
struct inode *inode = file->f_path.dentry->d_inode;
- if (!mask) {
- /* No permission to check. Existence test. */
- return 0;
- }
-
/* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
mask |= MAY_APPEND;
@@ -2953,10 +2948,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
static int selinux_file_permission(struct file *file, int mask)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct file_security_struct *fsec = file->f_security;
+ struct inode_security_struct *isec = inode->i_security;
+ u32 sid = current_sid();
+
if (!mask)
/* No permission to check. Existence test. */
return 0;
+ if (sid == fsec->sid && fsec->isid == isec->sid &&
+ fsec->pseqno == avc_policy_seqno())
+ /* No change since dentry_open check. */
+ return 0;
+
return selinux_revalidate_file_permission(file, mask);
}
@@ -5182,7 +5187,7 @@ static int selinux_setprocattr(struct task_struct *p,
/* Only allow single threaded processes to change context */
error = -EPERM;
- if (!is_single_threaded(p)) {
+ if (!current_is_single_threaded()) {
error = security_bounded_transition(tsec->sid, sid);
if (error)
goto abort_change;
@@ -5310,7 +5315,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
static struct security_operations selinux_ops = {
.name = "selinux",
- .ptrace_may_access = selinux_ptrace_may_access,
+ .ptrace_access_check = selinux_ptrace_access_check,
.ptrace_traceme = selinux_ptrace_traceme,
.capget = selinux_capget,
.capset = selinux_capset,
@@ -5678,6 +5683,9 @@ int selinux_disable(void)
selinux_disabled = 1;
selinux_enabled = 0;
+ /* Try to destroy the avc node cache */
+ avc_disable();
+
/* Reset security_ops to the secondary module, dummy or capability. */
security_ops = secondary_ops;
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index d12ff1a9c0aa..ae4c3a0e2c1a 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -127,13 +127,13 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
u32 events, u32 ssid, u32 tsid,
u16 tclass, u32 perms);
-/* Shows permission in human readable form */
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
-
/* Exported to selinuxfs */
int avc_get_hash_stats(char *page);
extern unsigned int avc_cache_threshold;
+/* Attempt to free avc node cache */
+void avc_disable(void);
+
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
#endif
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 500e6f78e115..ff17820d35ec 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -22,6 +22,11 @@
*
* Added validation of kernel classes and permissions
*
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * Added support for bounds domain and audit messaged on masked permissions
+ *
+ * Copyright (C) 2008, 2009 NEC Corporation
* Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
@@ -279,6 +284,95 @@ mls_ops:
}
/*
+ * security_dump_masked_av - dumps masked permissions during
+ * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
+ */
+static int dump_masked_av_helper(void *k, void *d, void *args)
+{
+ struct perm_datum *pdatum = d;
+ char **permission_names = args;
+
+ BUG_ON(pdatum->value < 1 || pdatum->value > 32);
+
+ permission_names[pdatum->value - 1] = (char *)k;
+
+ return 0;
+}
+
+static void security_dump_masked_av(struct context *scontext,
+ struct context *tcontext,
+ u16 tclass,
+ u32 permissions,
+ const char *reason)
+{
+ struct common_datum *common_dat;
+ struct class_datum *tclass_dat;
+ struct audit_buffer *ab;
+ char *tclass_name;
+ char *scontext_name = NULL;
+ char *tcontext_name = NULL;
+ char *permission_names[32];
+ int index, length;
+ bool need_comma = false;
+
+ if (!permissions)
+ return;
+
+ tclass_name = policydb.p_class_val_to_name[tclass - 1];
+ tclass_dat = policydb.class_val_to_struct[tclass - 1];
+ common_dat = tclass_dat->comdatum;
+
+ /* init permission_names */
+ if (common_dat &&
+ hashtab_map(common_dat->permissions.table,
+ dump_masked_av_helper, permission_names) < 0)
+ goto out;
+
+ if (hashtab_map(tclass_dat->permissions.table,
+ dump_masked_av_helper, permission_names) < 0)
+ goto out;
+
+ /* get scontext/tcontext in text form */
+ if (context_struct_to_string(scontext,
+ &scontext_name, &length) < 0)
+ goto out;
+
+ if (context_struct_to_string(tcontext,
+ &tcontext_name, &length) < 0)
+ goto out;
+
+ /* audit a message */
+ ab = audit_log_start(current->audit_context,
+ GFP_ATOMIC, AUDIT_SELINUX_ERR);
+ if (!ab)
+ goto out;
+
+ audit_log_format(ab, "op=security_compute_av reason=%s "
+ "scontext=%s tcontext=%s tclass=%s perms=",
+ reason, scontext_name, tcontext_name, tclass_name);
+
+ for (index = 0; index < 32; index++) {
+ u32 mask = (1 << index);
+
+ if ((mask & permissions) == 0)
+ continue;
+
+ audit_log_format(ab, "%s%s",
+ need_comma ? "," : "",
+ permission_names[index]
+ ? permission_names[index] : "????");
+ need_comma = true;
+ }
+ audit_log_end(ab);
+out:
+ /* release scontext/tcontext */
+ kfree(tcontext_name);
+ kfree(scontext_name);
+
+ return;
+}
+
+/*
* security_boundary_permission - drops violated permissions
* on boundary constraint.
*/
@@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext,
}
if (masked) {
- struct audit_buffer *ab;
- char *stype_name
- = policydb.p_type_val_to_name[source->value - 1];
- char *ttype_name
- = policydb.p_type_val_to_name[target->value - 1];
- char *tclass_name
- = policydb.p_class_val_to_name[tclass - 1];
-
/* mask violated permissions */
avd->allowed &= ~masked;
- /* notice to userspace via audit message */
- ab = audit_log_start(current->audit_context,
- GFP_ATOMIC, AUDIT_SELINUX_ERR);
- if (!ab)
- return;
-
- audit_log_format(ab, "av boundary violation: "
- "source=%s target=%s tclass=%s",
- stype_name, ttype_name, tclass_name);
- avc_dump_av(ab, tclass, masked);
- audit_log_end(ab);
+ /* audit masked permissions */
+ security_dump_masked_av(scontext, tcontext,
+ tclass, masked, "bounds");
}
}
@@ -480,7 +558,7 @@ static int context_struct_compute_av(struct context *scontext,
if ((constraint->permissions & (avd->allowed)) &&
!constraint_expr_eval(scontext, tcontext, NULL,
constraint->expr)) {
- avd->allowed = (avd->allowed) & ~(constraint->permissions);
+ avd->allowed &= ~(constraint->permissions);
}
constraint = constraint->next;
}
@@ -499,8 +577,8 @@ static int context_struct_compute_av(struct context *scontext,
break;
}
if (!ra)
- avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
- PROCESS__DYNTRANSITION);
+ avd->allowed &= ~(PROCESS__TRANSITION |
+ PROCESS__DYNTRANSITION);
}
/*
@@ -687,6 +765,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
}
index = type->bounds;
}
+
+ if (rc) {
+ char *old_name = NULL;
+ char *new_name = NULL;
+ int length;
+
+ if (!context_struct_to_string(old_context,
+ &old_name, &length) &&
+ !context_struct_to_string(new_context,
+ &new_name, &length)) {
+ audit_log(current->audit_context,
+ GFP_ATOMIC, AUDIT_SELINUX_ERR,
+ "op=security_bounded_transition "
+ "result=denied "
+ "oldcontext=%s newcontext=%s",
+ old_name, new_name);
+ }
+ kfree(new_name);
+ kfree(old_name);
+ }
out:
read_unlock(&policy_rwlock);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 243bec175be0..c6e9acae72e4 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
{
memset(a, 0, sizeof(*a));
a->a.type = type;
- a->a.function = func;
+ a->a.smack_audit_data.function = func;
}
static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 513dc1aa16dd..0f9ac8146900 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -240,8 +240,9 @@ static inline void smack_str_from_perm(char *string, int access)
static void smack_log_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
- struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data;
- audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function,
+ struct smack_audit_data *sad = &ad->smack_audit_data;
+ audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
+ ad->smack_audit_data.function,
sad->result ? "denied" : "granted");
audit_log_format(ab, " subject=");
audit_log_untrustedstring(ab, sad->subject);
@@ -274,11 +275,11 @@ void smack_log(char *subject_label, char *object_label, int request,
if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
return;
- if (a->function == NULL)
- a->function = "unknown";
+ if (a->smack_audit_data.function == NULL)
+ a->smack_audit_data.function = "unknown";
/* end preparing the audit data */
- sad = &a->lsm_priv.smack_audit_data;
+ sad = &a->smack_audit_data;
smack_str_from_perm(request_buffer, request);
sad->subject = subject_label;
sad->object = object_label;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0023182078c7..1c9bdbcbe3d2 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -91,7 +91,7 @@ struct inode_smack *new_inode_smack(char *smack)
*/
/**
- * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH
+ * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
* @ctp: child task pointer
* @mode: ptrace attachment mode
*
@@ -99,13 +99,13 @@ struct inode_smack *new_inode_smack(char *smack)
*
* Do the capability checks, and require read and write.
*/
-static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
+static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
int rc;
struct smk_audit_info ad;
char *sp, *tsp;
- rc = cap_ptrace_may_access(ctp, mode);
+ rc = cap_ptrace_access_check(ctp, mode);
if (rc != 0)
return rc;
@@ -3032,7 +3032,7 @@ static void smack_release_secctx(char *secdata, u32 seclen)
struct security_operations smack_ops = {
.name = "smack",
- .ptrace_may_access = smack_ptrace_may_access,
+ .ptrace_access_check = smack_ptrace_access_check,
.ptrace_traceme = smack_ptrace_traceme,
.syslog = smack_syslog,
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index fdd1f4b8c448..3c8bd8ee0b95 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -1285,6 +1285,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
}
/**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns 0.
+ */
+static int tomoyo_delete_domain(char *domainname)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_path_info name;
+
+ name.name = domainname;
+ tomoyo_fill_path_info(&name);
+ down_write(&tomoyo_domain_list_lock);
+ /* Is there an active domain? */
+ list_for_each_entry(domain, &tomoyo_domain_list, list) {
+ /* Never delete tomoyo_kernel_domain */
+ if (domain == &tomoyo_kernel_domain)
+ continue;
+ if (domain->is_deleted ||
+ tomoyo_pathcmp(domain->domainname, &name))
+ continue;
+ domain->is_deleted = true;
+ break;
+ }
+ up_write(&tomoyo_domain_list_lock);
+ return 0;
+}
+
+/**
* tomoyo_write_domain_policy - Write domain policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 6d6ba09af457..31df541911f7 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -339,8 +339,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
const char *tomoyo_get_msg(const bool is_enforce);
/* Convert single path operation to operation name. */
const char *tomoyo_sp2keyword(const u8 operation);
-/* Delete a domain. */
-int tomoyo_delete_domain(char *data);
/* Create "alias" entry in exception policy. */
int tomoyo_write_alias_policy(char *data, const bool is_delete);
/*
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 1d8b16960576..fcf52accce2b 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
return tomoyo_update_alias_entry(data, cp, is_delete);
}
-/* Domain create/delete handler. */
-
-/**
- * tomoyo_delete_domain - Delete a domain.
- *
- * @domainname: The name of domain.
- *
- * Returns 0.
- */
-int tomoyo_delete_domain(char *domainname)
-{
- struct tomoyo_domain_info *domain;
- struct tomoyo_path_info name;
-
- name.name = domainname;
- tomoyo_fill_path_info(&name);
- down_write(&tomoyo_domain_list_lock);
- /* Is there an active domain? */
- list_for_each_entry(domain, &tomoyo_domain_list, list) {
- /* Never delete tomoyo_kernel_domain */
- if (domain == &tomoyo_kernel_domain)
- continue;
- if (domain->is_deleted ||
- tomoyo_pathcmp(domain->domainname, &name))
- continue;
- domain->is_deleted = true;
- break;
- }
- up_write(&tomoyo_domain_list_lock);
- return 0;
-}
-
/**
* tomoyo_find_or_assign_new_domain - Create a domain.
*
@@ -818,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
/**
* tomoyo_find_next_domain - Find a domain.
*
- * @bprm: Pointer to "struct linux_binprm".
- * @next_domain: Pointer to pointer to "struct tomoyo_domain_info".
+ * @bprm: Pointer to "struct linux_binprm".
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
- struct tomoyo_domain_info **next_domain)
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
/*
* This function assumes that the size of buffer returned by
@@ -946,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm,
tomoyo_set_domain_flag(old_domain, false,
TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
out:
+ if (!domain)
+ domain = old_domain;
+ bprm->cred->security = domain;
tomoyo_free(real_program_name);
tomoyo_free(symlink_program_name);
- *next_domain = domain ? domain : old_domain;
tomoyo_free(tmp);
return retval;
}
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 3194d09fe0f4..35a13e7915e4 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -61,14 +61,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
* Execute permission is checked against pathname passed to do_execve()
* using current domain.
*/
- if (!domain) {
- struct tomoyo_domain_info *next_domain = NULL;
- int retval = tomoyo_find_next_domain(bprm, &next_domain);
-
- if (!retval)
- bprm->cred->security = next_domain;
- return retval;
- }
+ if (!domain)
+ return tomoyo_find_next_domain(bprm);
/*
* Read permission is checked against interpreters using next domain.
* '1' is the result of open_to_namei_flags(O_RDONLY).
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h
index 0fd588a629cf..cd6ba0bf7069 100644
--- a/security/tomoyo/tomoyo.h
+++ b/security/tomoyo/tomoyo.h
@@ -31,8 +31,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain,
struct path *path2);
int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
struct file *filp);
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
- struct tomoyo_domain_info **next_domain);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
/* Index numbers for Access Controls. */
diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
index 5ca2220eac7d..1dd0c28d1fb7 100644
--- a/sound/aoa/core/gpio-pmf.c
+++ b/sound/aoa/core/gpio-pmf.c
@@ -182,6 +182,10 @@ static int pmf_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
irq_client = kzalloc(sizeof(struct pmf_irq_client),
GFP_KERNEL);
+ if (!irq_client) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
irq_client->data = notif;
irq_client->handler = pmf_handle_notify_irq;
irq_client->owner = THIS_MODULE;
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index c570ebd9d177..9c12563db1c4 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -137,9 +137,9 @@ static int pxa2xx_ac97_do_resume(struct snd_card *card)
return 0;
}
-static int pxa2xx_ac97_suspend(struct platform_device *dev, pm_message_t state)
+static int pxa2xx_ac97_suspend(struct device *dev)
{
- struct snd_card *card = platform_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
int ret = 0;
if (card)
@@ -148,9 +148,9 @@ static int pxa2xx_ac97_suspend(struct platform_device *dev, pm_message_t state)
return ret;
}
-static int pxa2xx_ac97_resume(struct platform_device *dev)
+static int pxa2xx_ac97_resume(struct device *dev)
{
- struct snd_card *card = platform_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
int ret = 0;
if (card)
@@ -159,9 +159,10 @@ static int pxa2xx_ac97_resume(struct platform_device *dev)
return ret;
}
-#else
-#define pxa2xx_ac97_suspend NULL
-#define pxa2xx_ac97_resume NULL
+static struct dev_pm_ops pxa2xx_ac97_pm_ops = {
+ .suspend = pxa2xx_ac97_suspend,
+ .resume = pxa2xx_ac97_resume,
+};
#endif
static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
@@ -231,11 +232,12 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev)
static struct platform_driver pxa2xx_ac97_driver = {
.probe = pxa2xx_ac97_probe,
.remove = __devexit_p(pxa2xx_ac97_remove),
- .suspend = pxa2xx_ac97_suspend,
- .resume = pxa2xx_ac97_resume,
.driver = {
.name = "pxa2xx-ac97",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pxa2xx_ac97_pm_ops,
+#endif
},
};
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 6061fb5f4e1c..c15682a2f9db 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -206,4 +206,8 @@ config SND_PCM_XRUN_DEBUG
config SND_VMASTER
bool
+config SND_DMA_SGBUF
+ def_bool y
+ depends on X86
+
source "sound/core/seq/Kconfig"
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 4229052e7b91..350a08d277f4 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -13,7 +13,7 @@ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o
snd-page-alloc-y := memalloc.o
-snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o
+snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
diff --git a/sound/core/info.c b/sound/core/info.c
index 35df614f6c55..3d1f5137420a 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -88,12 +88,10 @@ static int resize_info_buffer(struct snd_info_buffer *buffer,
char *nbuf;
nsize = PAGE_ALIGN(nsize);
- nbuf = kmalloc(nsize, GFP_KERNEL);
+ nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL);
if (! nbuf)
return -ENOMEM;
- memcpy(nbuf, buffer->buffer, buffer->len);
- kfree(buffer->buffer);
buffer->buffer = nbuf;
buffer->len = nsize;
return 0;
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 1b3534d67686..9e92441f9b78 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -199,6 +199,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
case SNDRV_DMA_TYPE_DEV:
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
break;
+#endif
+#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
break;
@@ -269,6 +271,8 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
case SNDRV_DMA_TYPE_DEV:
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
break;
+#endif
+#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
snd_free_sgbuf_pages(dmab);
break;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 333e4dd29450..72cfd47af6b8 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -233,6 +233,18 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
xrun(substream);
return -EPIPE;
}
+ if (xrun_debug(substream, 8)) {
+ char name[16];
+ pcm_debug_name(substream, name, sizeof(name));
+ snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, "
+ "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
+ name, (unsigned int)pos,
+ (unsigned int)runtime->period_size,
+ (unsigned int)runtime->buffer_size,
+ (unsigned long)old_hw_ptr,
+ (unsigned long)runtime->hw_ptr_base,
+ (unsigned long)runtime->hw_ptr_interrupt);
+ }
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
@@ -244,18 +256,27 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
delta = new_hw_ptr - hw_ptr_interrupt;
}
if (delta < 0) {
- delta += runtime->buffer_size;
+ if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
+ delta += runtime->buffer_size;
if (delta < 0) {
hw_ptr_error(substream,
"Unexpected hw_pointer value "
"(stream=%i, pos=%ld, intr_ptr=%ld)\n",
substream->stream, (long)pos,
(long)hw_ptr_interrupt);
+#if 1
+ /* simply skipping the hwptr update seems more
+ * robust in some cases, e.g. on VMware with
+ * inaccurate timer source
+ */
+ return 0; /* skip this update */
+#else
/* rebase to interrupt position */
hw_base = new_hw_ptr = hw_ptr_interrupt;
/* align hw_base to buffer_size */
hw_base -= hw_base % runtime->buffer_size;
delta = 0;
+#endif
} else {
hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary)
@@ -344,6 +365,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
xrun(substream);
return -EPIPE;
}
+ if (xrun_debug(substream, 16)) {
+ char name[16];
+ pcm_debug_name(substream, name, sizeof(name));
+ snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
+ "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
+ name, (unsigned int)pos,
+ (unsigned int)runtime->period_size,
+ (unsigned int)runtime->buffer_size,
+ (unsigned long)old_hw_ptr,
+ (unsigned long)runtime->hw_ptr_base,
+ (unsigned long)runtime->hw_ptr_interrupt);
+ }
+
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index a6d42808828c..caa7796bc2f5 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -304,6 +304,7 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
+#ifdef CONFIG_SND_DMA_SGBUF
/**
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
@@ -349,6 +350,7 @@ unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
return size;
}
EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
+#endif /* CONFIG_SND_DMA_SGBUF */
/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 473247c8e6d3..c0adc14c91f0 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -274,7 +274,7 @@ static int open_substream(struct snd_rawmidi *rmidi,
return err;
substream->opened = 1;
if (substream->use_count++ == 0)
- substream->active_sensing = 1;
+ substream->active_sensing = 0;
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
substream->append = 1;
rmidi->streams[substream->stream].substream_opened++;
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 0a711d2d04f0..9dfb2f77be60 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <sound/asoundef.h>
#include "seq_oss_midi.h"
#include "seq_oss_readq.h"
#include "seq_oss_timer.h"
@@ -476,19 +477,20 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
ev.source.port = dp->port;
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
ev.type = SNDRV_SEQ_EVENT_SENSING;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
}
for (c = 0; c < 16; c++) {
ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
ev.data.control.channel = c;
- ev.data.control.param = 123;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */
+ ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
- ev.data.control.param = 121;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
+ ev.data.control.param =
+ MIDI_CTL_RESET_CONTROLLERS;
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
ev.data.control.value = 0;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
}
}
}
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 4d26146a62cc..ebaf1b541dcd 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -120,7 +120,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
return -EINVAL;
runtime = substream->runtime;
if ((tmp = runtime->avail) < count) {
- snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp);
+ if (printk_ratelimit())
+ snd_printk(KERN_ERR "MIDI output buffer overrun\n");
return -ENOMEM;
}
if (snd_rawmidi_kernel_write(substream, buf, count) < count)
@@ -236,6 +237,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
memset(&params, 0, sizeof(params));
params.avail_min = 1;
params.buffer_size = output_buffer_size;
+ params.no_active_sensing = 1;
if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
snd_rawmidi_kernel_release(&msynth->output_rfile);
return err;
@@ -248,12 +250,9 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
struct seq_midisynth *msynth = private_data;
- unsigned char buf = 0xff; /* MIDI reset */
if (snd_BUG_ON(!msynth->output_rfile.output))
return -EINVAL;
- /* sending single MIDI reset message to shut the device up */
- snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1);
snd_rawmidi_drain_output(msynth->output_rfile.output);
return snd_rawmidi_kernel_release(&msynth->output_rfile);
}
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 257624bd1997..3b9b550109cb 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -353,7 +353,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
*
* The optional argument @tlv can be used to specify the TLV information
* for dB scale of the master control. It should be a single element
- * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
+ * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
+ * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
*/
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
const unsigned int *tlv)
@@ -384,7 +385,10 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
kctl->private_free = master_free;
/* additional (constant) TLV read */
- if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
+ if (tlv &&
+ (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
+ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
+ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
memcpy(master->tlv, tlv, sizeof(master->tlv));
kctl->tlv.p = master->tlv;
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 3ee0269e5bd0..02f79d252718 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -1,5 +1,5 @@
/*
- * Driver for C-Media's CMI8330 soundcards.
+ * Driver for C-Media's CMI8330 and CMI8329 soundcards.
* Copyright (c) by George Talusan <gstalusan@uwaterloo.ca>
* http://www.undergrad.math.uwaterloo.ca/~gstalusa
*
@@ -35,7 +35,7 @@
*
* This card has two mixers and two PCM devices. I've cheesed it such
* that recording and playback can be done through the same device.
- * The driver "magically" routes the capturing to the CMI8330 codec,
+ * The driver "magically" routes the capturing to the AD1848 codec,
* and playback to the SB16 codec. This allows for full-duplex mode
* to some extent.
* The utilities in alsa-utils are aware of both devices, so passing
@@ -64,7 +64,7 @@
/*
*/
MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>");
-MODULE_DESCRIPTION("C-Media CMI8330");
+MODULE_DESCRIPTION("C-Media CMI8330/CMI8329");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}");
@@ -86,38 +86,38 @@ static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
+MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard.");
+MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard.");
+MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard.");
#ifdef CONFIG_PNP
module_param_array(isapnp, bool, NULL, 0444);
MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
#endif
module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver.");
module_param_array(sbirq, int, NULL, 0444);
-MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver.");
module_param_array(sbdma8, int, NULL, 0444);
-MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver.");
module_param_array(sbdma16, int, NULL, 0444);
-MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver.");
+MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver.");
module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver.");
+MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver.");
module_param_array(wssirq, int, NULL, 0444);
-MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
+MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver.");
module_param_array(wssdma, int, NULL, 0444);
-MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
+MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver.");
module_param_array(fmport, long, NULL, 0444);
-MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver.");
+MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver.");
module_param_array(mpuport, long, NULL, 0444);
-MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver.");
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver.");
module_param_array(mpuirq, int, NULL, 0444);
-MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port.");
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port.");
#ifdef CONFIG_PNP
static int isa_registered;
static int pnp_registered;
@@ -156,6 +156,11 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] =
typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *);
+enum card_type {
+ CMI8330,
+ CMI8329
+};
+
struct snd_cmi8330 {
#ifdef CONFIG_PNP
struct pnp_dev *cap;
@@ -172,11 +177,14 @@ struct snd_cmi8330 {
snd_pcm_open_callback_t open;
void *private_data; /* sb or wss */
} streams[2];
+
+ enum card_type type;
};
#ifdef CONFIG_PNP
static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
+ { .id = "CMI0001", .devs = { { "@X@0001" }, { "@@@0001" }, { "@H@0001" }, { "A@@0001" } } },
{ .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
{ .id = "" }
};
@@ -304,7 +312,7 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330
unsigned int idx;
int err;
- strcpy(card->mixername, "CMI8330/C3D");
+ strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
err = snd_ctl_add(card,
@@ -329,6 +337,9 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
struct pnp_dev *pdev;
int err;
+ /* CMI8329 has a device with ID A@@0001, CMI8330 does not */
+ acard->type = (id->devs[3].id[0]) ? CMI8329 : CMI8330;
+
acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
if (acard->cap == NULL)
return -EBUSY;
@@ -345,38 +356,45 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n");
+ snd_printk(KERN_ERR "AD1848 PnP configure failure\n");
return -EBUSY;
}
wssport[dev] = pnp_port_start(pdev, 0);
wssdma[dev] = pnp_dma(pdev, 0);
wssirq[dev] = pnp_irq(pdev, 0);
- fmport[dev] = pnp_port_start(pdev, 1);
+ if (pnp_port_start(pdev, 1))
+ fmport[dev] = pnp_port_start(pdev, 1);
/* allocate SB16 resources */
pdev = acard->play;
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n");
+ snd_printk(KERN_ERR "SB16 PnP configure failure\n");
return -EBUSY;
}
sbport[dev] = pnp_port_start(pdev, 0);
sbdma8[dev] = pnp_dma(pdev, 0);
sbdma16[dev] = pnp_dma(pdev, 1);
sbirq[dev] = pnp_irq(pdev, 0);
+ /* On CMI8239, the OPL3 port might be present in SB16 PnP resources */
+ if (fmport[dev] == SNDRV_AUTO_PORT) {
+ if (pnp_port_start(pdev, 1))
+ fmport[dev] = pnp_port_start(pdev, 1);
+ else
+ fmport[dev] = 0x388; /* Or hardwired */
+ }
/* allocate MPU-401 resources */
pdev = acard->mpu;
err = pnp_activate_dev(pdev);
- if (err < 0) {
- snd_printk(KERN_ERR
- "CMI8330/C3D (MPU-401) PnP configure failure\n");
- return -EBUSY;
+ if (err < 0)
+ snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n");
+ else {
+ mpuport[dev] = pnp_port_start(pdev, 0);
+ mpuirq[dev] = pnp_irq(pdev, 0);
}
- mpuport[dev] = pnp_port_start(pdev, 0);
- mpuirq[dev] = pnp_irq(pdev, 0);
return 0;
}
#endif
@@ -430,9 +448,9 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *
snd_cmi8330_capture_open
};
- if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0)
+ if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0)
return err;
- strcpy(pcm->name, "CMI8330");
+ strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330");
pcm->private_data = chip;
/* SB16 */
@@ -527,11 +545,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
wssdma[dev], -1,
WSS_HW_DETECT, 0, &acard->wss);
if (err < 0) {
- snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n");
+ snd_printk(KERN_ERR PFX "AD1848 device busy??\n");
return err;
}
if (acard->wss->hardware != WSS_HW_CMI8330) {
- snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n");
+ snd_printk(KERN_ERR PFX "AD1848 not found during probe\n");
return -ENODEV;
}
@@ -541,11 +559,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
sbdma8[dev],
sbdma16[dev],
SB_HW_AUTO, &acard->sb)) < 0) {
- snd_printk(KERN_ERR PFX "(SB16) device busy??\n");
+ snd_printk(KERN_ERR PFX "SB16 device busy??\n");
return err;
}
if (acard->sb->hardware != SB_HW_16) {
- snd_printk(KERN_ERR PFX "(SB16) not found during probe\n");
+ snd_printk(KERN_ERR PFX "SB16 not found during probe\n");
return err;
}
@@ -585,8 +603,8 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
mpuport[dev]);
}
- strcpy(card->driver, "CMI8330/C3D");
- strcpy(card->shortname, "C-Media CMI8330/C3D");
+ strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
+ strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D");
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
card->shortname,
acard->wss->port,
diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c
index 3ee9900ffd7b..35b5912cf3f8 100644
--- a/sound/oss/aedsp16.c
+++ b/sound/oss/aedsp16.c
@@ -325,8 +325,9 @@
/*
* Size of character arrays that store name and version of sound card
*/
-#define CARDNAMELEN 15 /* Size of the card's name in chars */
-#define CARDVERLEN 2 /* Size of the card's version in chars */
+#define CARDNAMELEN 15 /* Size of the card's name in chars */
+#define CARDVERLEN 10 /* Size of the card's version in chars */
+#define CARDVERDIGITS 2 /* Number of digits in the version */
#if defined(CONFIG_SC6600)
/*
@@ -410,7 +411,7 @@
static int soft_cfg __initdata = 0; /* bitmapped config */
static int soft_cfg_mss __initdata = 0; /* bitmapped mss config */
-static int ver[CARDVERLEN] __initdata = {0, 0}; /* DSP Ver:
+static int ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver:
hi->ver[0] lo->ver[1] */
#if defined(CONFIG_SC6600)
@@ -957,7 +958,7 @@ static int __init aedsp16_dsp_version(int port)
* string is finished.
*/
ver[len++] = ret;
- } while (len < CARDVERLEN);
+ } while (len < CARDVERDIGITS);
sprintf(DSPVersion, "%d.%d", ver[0], ver[1]);
DBG(("success.\n"));
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index 1b2316f35b1f..734b8f9e2f78 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1074,7 +1074,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
else
sprintf(mpu_synth_info[m].name,
- "MPU-401 %d.%d%c Midi interface #%d",
+ "MPU-401 %d.%d%c MIDI #%d",
(int) (devc->version & 0xf0) >> 4,
devc->version & 0x0f,
revision_char,
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 1edab7b4ea83..3136c88eacdf 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -110,9 +110,6 @@ static void start_adc(struct cs4297a_state *s);
// rather than 64k as some of the games work more responsively.
// log base 2( buff sz = 32k).
-//static unsigned long defaultorder = 3;
-//MODULE_PARM(defaultorder, "i");
-
//
// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
//
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 748f6b7d90b7..fb5ee3cc3968 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -135,11 +135,11 @@ config SND_AW2
config SND_AZT3328
- tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "Aztech AZF3328 / PCI168"
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
+ select SND_RAWMIDI
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index f290bc56178f..8451a0169f32 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1,6 +1,6 @@
/*
* azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
- * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr <andi AT lisas.de>
+ * Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de>
*
* Framework borrowed from Bart Hartgers's als4000.c.
* Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
@@ -10,6 +10,13 @@
* PCI168 A/AP, sub ID 8000
* Please give me feedback in case you try my driver with one of these!!
*
+ * Keywords: Windows XP Vista 168nt4-125.zip 168win95-125.zip PCI 168 download
+ * (XP/Vista do not support this card at all but every Linux distribution
+ * has very good support out of the box;
+ * just to make sure that the right people hit this and get to know that,
+ * despite the high level of Internet ignorance - as usual :-P -
+ * about very good support for this card - on Linux!)
+ *
* GPL LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -71,10 +78,11 @@
* - built-in General DirectX timer having a 20 bits counter
* with 1us resolution (see below!)
* - I2S serial output port for external DAC
+ * [FIXME: 3.3V or 5V level? maximum rate is 66.2kHz right?]
* - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI
* - supports hardware volume control
* - single chip low cost solution (128 pin QFP)
- * - supports programmable Sub-vendor and Sub-system ID
+ * - supports programmable Sub-vendor and Sub-system ID [24C02 SEEPROM chip]
* required for Microsoft's logo compliance (FIXME: where?)
* At least the Trident 4D Wave DX has one bit somewhere
* to enable writes to PCI subsystem VID registers, that should be it.
@@ -82,6 +90,7 @@
* some custom data starting at 0x80. What kind of config settings
* are located in our extended PCI space anyway??
* - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms
+ * [TDA1517P chip]
*
* Note that this driver now is actually *better* than the Windows driver,
* since it additionally supports the card's 1MHz DirectX timer - just try
@@ -146,10 +155,15 @@
* to read the Digital Enhanced Game Port. Not sure whether it is fixable.
*
* TODO
+ * - use PCI_VDEVICE
+ * - verify driver status on x86_64
+ * - test multi-card driver operation
+ * - (ab)use 1MHz DirectX timer as kernel clocksource
* - test MPU401 MIDI playback etc.
* - add more power micro-management (disable various units of the card
- * as long as they're unused). However this requires more I/O ports which I
- * haven't figured out yet and which thus might not even exist...
+ * as long as they're unused, to improve audio quality and save power).
+ * However this requires more I/O ports which I haven't figured out yet
+ * and which thus might not even exist...
* The standard suspend/resume functionality could probably make use of
* some improvement, too...
* - figure out what all unknown port bits are responsible for
@@ -185,25 +199,46 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
#define SUPPORT_GAMEPORT 1
#endif
+/* === Debug settings ===
+ Further diagnostic functionality than the settings below
+ does not need to be provided, since one can easily write a bash script
+ to dump the card's I/O ports (those listed in lspci -v -v):
+ function dump()
+ {
+ local descr=$1; local addr=$2; local count=$3
+
+ echo "${descr}: ${count} @ ${addr}:"
+ dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C
+ }
+ and then use something like
+ "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8",
+ "dump codec00 0xa800 32", "dump mixer 0xb800 64", "dump synth 0xbc00 8",
+ possibly within a "while true; do ... sleep 1; done" loop.
+ Tweaking ports could be done using
+ VALSTRING="`printf "%02x" $value`"
+ printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null
+*/
+
#define DEBUG_MISC 0
#define DEBUG_CALLS 0
#define DEBUG_MIXER 0
-#define DEBUG_PLAY_REC 0
+#define DEBUG_CODEC 0
#define DEBUG_IO 0
#define DEBUG_TIMER 0
#define DEBUG_GAME 0
+#define DEBUG_PM 0
#define MIXER_TESTING 0
#if DEBUG_MISC
-#define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args)
#else
#define snd_azf3328_dbgmisc(format, args...)
#endif
#if DEBUG_CALLS
#define snd_azf3328_dbgcalls(format, args...) printk(format, ##args)
-#define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
-#define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
+#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__)
+#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__)
#else
#define snd_azf3328_dbgcalls(format, args...)
#define snd_azf3328_dbgcallenter()
@@ -216,10 +251,10 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
#define snd_azf3328_dbgmixer(format, args...)
#endif
-#if DEBUG_PLAY_REC
-#define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args)
+#if DEBUG_CODEC
+#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args)
#else
-#define snd_azf3328_dbgplay(format, args...)
+#define snd_azf3328_dbgcodec(format, args...)
#endif
#if DEBUG_MISC
@@ -234,6 +269,12 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
#define snd_azf3328_dbggame(format, args...)
#endif
+#if DEBUG_PM
+#define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args)
+#else
+#define snd_azf3328_dbgpm(format, args...)
+#endif
+
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
@@ -250,22 +291,23 @@ static int seqtimer_scaling = 128;
module_param(seqtimer_scaling, int, 0444);
MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128.");
-struct snd_azf3328_audio_stream {
+struct snd_azf3328_codec_data {
+ unsigned long io_base;
struct snd_pcm_substream *substream;
- int enabled;
- int running;
- unsigned long portbase;
+ bool running;
+ const char *name;
};
-enum snd_azf3328_stream_index {
- AZF_PLAYBACK = 0,
- AZF_CAPTURE = 1,
+enum snd_azf3328_codec_type {
+ AZF_CODEC_PLAYBACK = 0,
+ AZF_CODEC_CAPTURE = 1,
+ AZF_CODEC_I2S_OUT = 2,
};
struct snd_azf3328 {
/* often-used fields towards beginning, then grouped */
- unsigned long codec_io; /* usually 0xb000, size 128 */
+ unsigned long ctrl_io; /* usually 0xb000, size 128 */
unsigned long game_io; /* usually 0xb400, size 8 */
unsigned long mpu_io; /* usually 0xb800, size 4 */
unsigned long opl3_io; /* usually 0xbc00, size 8 */
@@ -275,15 +317,17 @@ struct snd_azf3328 {
struct snd_timer *timer;
- struct snd_pcm *pcm;
- struct snd_azf3328_audio_stream audio_stream[2];
+ struct snd_pcm *pcm[3];
+
+ /* playback, recording and I2S out codecs */
+ struct snd_azf3328_codec_data codecs[3];
struct snd_card *card;
struct snd_rawmidi *rmidi;
#ifdef SUPPORT_GAMEPORT
struct gameport *gameport;
- int axes[4];
+ u16 axes[4];
#endif
struct pci_dev *pci;
@@ -293,16 +337,16 @@ struct snd_azf3328 {
* If we need to add more registers here, then we might try to fold this
* into some transparent combined shadow register handling with
* CONFIG_PM register storage below, but that's slightly difficult. */
- u16 shadow_reg_codec_6AH;
+ u16 shadow_reg_ctrl_6AH;
#ifdef CONFIG_PM
/* register value containers for power management
- * Note: not always full I/O range preserved (just like Win driver!) */
- u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2];
- u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2];
- u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2];
- u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2];
- u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
+ * Note: not always full I/O range preserved (similar to Win driver!) */
+ u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
+ u32 saved_regs_game[AZF_ALIGN(AZF_IO_SIZE_GAME_PM) / 4];
+ u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4];
+ u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4];
+ u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4];
#endif
};
@@ -316,7 +360,7 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
static int
-snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set)
+snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set)
{
u8 prev = inb(reg), new;
@@ -331,39 +375,72 @@ snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set)
}
static inline void
-snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
+snd_azf3328_codec_outb(const struct snd_azf3328_codec_data *codec,
+ unsigned reg,
+ u8 value
+)
{
- outb(value, chip->codec_io + reg);
+ outb(value, codec->io_base + reg);
}
static inline u8
-snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg)
+snd_azf3328_codec_inb(const struct snd_azf3328_codec_data *codec, unsigned reg)
{
- return inb(chip->codec_io + reg);
+ return inb(codec->io_base + reg);
}
static inline void
-snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
+snd_azf3328_codec_outw(const struct snd_azf3328_codec_data *codec,
+ unsigned reg,
+ u16 value
+)
{
- outw(value, chip->codec_io + reg);
+ outw(value, codec->io_base + reg);
}
static inline u16
-snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg)
+snd_azf3328_codec_inw(const struct snd_azf3328_codec_data *codec, unsigned reg)
{
- return inw(chip->codec_io + reg);
+ return inw(codec->io_base + reg);
}
static inline void
-snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value)
+snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec,
+ unsigned reg,
+ u32 value
+)
{
- outl(value, chip->codec_io + reg);
+ outl(value, codec->io_base + reg);
}
static inline u32
-snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg)
+snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg)
+{
+ return inl(codec->io_base + reg);
+}
+
+static inline void
+snd_azf3328_ctrl_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
+{
+ outb(value, chip->ctrl_io + reg);
+}
+
+static inline u8
+snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg)
+{
+ return inb(chip->ctrl_io + reg);
+}
+
+static inline void
+snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
+{
+ outw(value, chip->ctrl_io + reg);
+}
+
+static inline void
+snd_azf3328_ctrl_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value)
{
- return inl(chip->codec_io + reg);
+ outl(value, chip->ctrl_io + reg);
}
static inline void
@@ -404,13 +481,13 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg)
#define AZF_MUTE_BIT 0x80
-static int
+static bool
snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip,
- unsigned reg, int do_mute
+ unsigned reg, bool do_mute
)
{
unsigned long portbase = chip->mixer_io + reg + 1;
- int updated;
+ bool updated;
/* the mute bit is on the *second* (i.e. right) register of a
* left/right channel setting */
@@ -569,7 +646,7 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol,
{
struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol);
struct azf3328_mixer_reg reg;
- unsigned int oreg, val;
+ u16 oreg, val;
snd_azf3328_dbgcallenter();
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
@@ -600,7 +677,7 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol,
{
struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol);
struct azf3328_mixer_reg reg;
- unsigned int oreg, nreg, val;
+ u16 oreg, nreg, val;
snd_azf3328_dbgcallenter();
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
@@ -709,7 +786,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
{
struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol);
struct azf3328_mixer_reg reg;
- unsigned int oreg, nreg, val;
+ u16 oreg, nreg, val;
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
oreg = snd_azf3328_mixer_inw(chip, reg.reg);
@@ -867,14 +944,15 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
static void
snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
- unsigned reg,
+ enum snd_azf3328_codec_type codec_type,
enum azf_freq_t bitrate,
unsigned int format_width,
unsigned int channels
)
{
- u16 val = 0xff00;
unsigned long flags;
+ const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
+ u16 val = 0xff00;
snd_azf3328_dbgcallenter();
switch (bitrate) {
@@ -917,7 +995,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
spin_lock_irqsave(&chip->reg_lock, flags);
/* set bitrate/format */
- snd_azf3328_codec_outw(chip, reg, val);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val);
/* changing the bitrate/format settings switches off the
* audio output with an annoying click in case of 8/16bit format change
@@ -926,11 +1004,11 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
* (FIXME: yes, it works, but what exactly am I doing here?? :)
* FIXME: does this have some side effects for full-duplex
* or other dramatic side effects? */
- if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
- snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) |
- DMA_PLAY_SOMETHING1 |
- DMA_PLAY_SOMETHING2 |
+ if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) |
+ DMA_RUN_SOMETHING1 |
+ DMA_RUN_SOMETHING2 |
SOMETHING_ALMOST_ALWAYS_SET |
DMA_EPILOGUE_SOMETHING |
DMA_SOMETHING_ELSE
@@ -942,112 +1020,134 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
static inline void
snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
- unsigned reg
+ enum snd_azf3328_codec_type codec_type
)
{
/* choose lowest frequency for low power consumption.
* While this will cause louder noise due to rather coarse frequency,
* it should never matter since output should always
* get disabled properly when idle anyway. */
- snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1);
+ snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1);
}
static void
-snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip,
+snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip,
unsigned bitmask,
- int enable
+ bool enable
)
{
- if (enable)
- chip->shadow_reg_codec_6AH &= ~bitmask;
+ bool do_mask = !enable;
+ if (do_mask)
+ chip->shadow_reg_ctrl_6AH |= bitmask;
else
- chip->shadow_reg_codec_6AH |= bitmask;
- snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n",
- bitmask, enable, chip->shadow_reg_codec_6AH);
- snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH);
+ chip->shadow_reg_ctrl_6AH &= ~bitmask;
+ snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n",
+ bitmask, do_mask, chip->shadow_reg_ctrl_6AH);
+ snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH);
}
static inline void
-snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable)
+snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable)
{
- snd_azf3328_dbgplay("codec_enable %d\n", enable);
+ snd_azf3328_dbgcodec("codec_enable %d\n", enable);
/* no idea what exactly is being done here, but I strongly assume it's
* PM related */
- snd_azf3328_codec_reg_6AH_update(
+ snd_azf3328_ctrl_reg_6AH_update(
chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable
);
}
static void
-snd_azf3328_codec_activity(struct snd_azf3328 *chip,
- enum snd_azf3328_stream_index stream_type,
- int enable
+snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
+ enum snd_azf3328_codec_type codec_type,
+ bool enable
)
{
- int need_change = (chip->audio_stream[stream_type].running != enable);
+ struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
+ bool need_change = (codec->running != enable);
- snd_azf3328_dbgplay(
- "codec_activity: type %d, enable %d, need_change %d\n",
- stream_type, enable, need_change
+ snd_azf3328_dbgcodec(
+ "codec_activity: %s codec, enable %d, need_change %d\n",
+ codec->name, enable, need_change
);
if (need_change) {
- enum snd_azf3328_stream_index other =
- (stream_type == AZF_PLAYBACK) ?
- AZF_CAPTURE : AZF_PLAYBACK;
- /* small check to prevent shutting down the other party
- * in case it's active */
- if ((enable) || !(chip->audio_stream[other].running))
- snd_azf3328_codec_enable(chip, enable);
+ static const struct {
+ enum snd_azf3328_codec_type other1;
+ enum snd_azf3328_codec_type other2;
+ } peer_codecs[3] =
+ { { AZF_CODEC_CAPTURE, AZF_CODEC_I2S_OUT },
+ { AZF_CODEC_PLAYBACK, AZF_CODEC_I2S_OUT },
+ { AZF_CODEC_PLAYBACK, AZF_CODEC_CAPTURE } };
+ bool call_function;
+
+ if (enable)
+ /* if enable codec, call enable_codecs func
+ to enable codec supply... */
+ call_function = 1;
+ else {
+ /* ...otherwise call enable_codecs func
+ (which globally shuts down operation of codecs)
+ only in case the other codecs are currently
+ not active either! */
+ call_function =
+ ((!chip->codecs[peer_codecs[codec_type].other1]
+ .running)
+ && (!chip->codecs[peer_codecs[codec_type].other2]
+ .running));
+ }
+ if (call_function)
+ snd_azf3328_ctrl_enable_codecs(chip, enable);
/* ...and adjust clock, too
* (reduce noise and power consumption) */
if (!enable)
snd_azf3328_codec_setfmt_lowpower(
chip,
- chip->audio_stream[stream_type].portbase
- + IDX_IO_PLAY_SOUNDFORMAT
+ codec_type
);
+ codec->running = enable;
}
- chip->audio_stream[stream_type].running = enable;
}
static void
-snd_azf3328_setdmaa(struct snd_azf3328 *chip,
- long unsigned int addr,
- unsigned int count,
- unsigned int size,
- enum snd_azf3328_stream_index stream_type
+snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
+ enum snd_azf3328_codec_type codec_type,
+ unsigned long addr,
+ unsigned int count,
+ unsigned int size
)
{
+ const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
snd_azf3328_dbgcallenter();
- if (!chip->audio_stream[stream_type].running) {
- /* AZF3328 uses a two buffer pointer DMA playback approach */
+ if (!codec->running) {
+ /* AZF3328 uses a two buffer pointer DMA transfer approach */
- unsigned long flags, portbase, addr_area2;
+ unsigned long flags, addr_area2;
/* width 32bit (prevent overflow): */
- unsigned long count_areas, count_tmp;
+ u32 count_areas, lengths;
- portbase = chip->audio_stream[stream_type].portbase;
count_areas = size/2;
addr_area2 = addr+count_areas;
count_areas--; /* max. index */
- snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas);
+ snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
+ addr, count_areas, addr_area2, count_areas);
/* build combined I/O buffer length word */
- count_tmp = count_areas;
- count_areas |= (count_tmp << 16);
+ lengths = (count_areas << 16) | (count_areas);
spin_lock_irqsave(&chip->reg_lock, flags);
- outl(addr, portbase + IDX_IO_PLAY_DMA_START_1);
- outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2);
- outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1);
+ snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr);
+ snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2,
+ addr_area2);
+ snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS,
+ lengths);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
snd_azf3328_dbgcallleave();
}
static int
-snd_azf3328_playback_prepare(struct snd_pcm_substream *substream)
+snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
{
#if 0
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
@@ -1058,157 +1158,161 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream)
snd_azf3328_dbgcallenter();
#if 0
- snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
+ snd_azf3328_codec_setfmt(chip, AZF_CODEC_...,
runtime->rate,
snd_pcm_format_width(runtime->format),
runtime->channels);
- snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK);
+ snd_azf3328_codec_setdmaa(chip, AZF_CODEC_...,
+ runtime->dma_addr, count, size);
#endif
snd_azf3328_dbgcallleave();
return 0;
}
static int
-snd_azf3328_capture_prepare(struct snd_pcm_substream *substream)
-{
-#if 0
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int count = snd_pcm_lib_period_bytes(substream);
-#endif
-
- snd_azf3328_dbgcallenter();
-#if 0
- snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
- runtime->rate,
- snd_pcm_format_width(runtime->format),
- runtime->channels);
- snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE);
-#endif
- snd_azf3328_dbgcallleave();
- return 0;
-}
-
-static int
-snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
+ struct snd_pcm_substream *substream, int cmd)
{
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+ const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
struct snd_pcm_runtime *runtime = substream->runtime;
int result = 0;
- unsigned int status1;
- int previously_muted;
+ u16 flags1;
+ bool previously_muted = 0;
+ bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type);
- snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd);
+ snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_azf3328_dbgplay("START PLAYBACK\n");
-
- /* mute WaveOut (avoid clicking during setup) */
- previously_muted =
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+ snd_azf3328_dbgcodec("START %s\n", codec->name);
+
+ if (is_playback_codec) {
+ /* mute WaveOut (avoid clicking during setup) */
+ previously_muted =
+ snd_azf3328_mixer_set_mute(
+ chip, IDX_MIXER_WAVEOUT, 1
+ );
+ }
- snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
+ snd_azf3328_codec_setfmt(chip, codec_type,
runtime->rate,
snd_pcm_format_width(runtime->format),
runtime->channels);
spin_lock(&chip->reg_lock);
/* first, remember current value: */
- status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS);
+ flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
- /* stop playback */
- status1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ /* stop transfer */
+ flags1 &= ~DMA_RESUME;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
/* FIXME: clear interrupts or what??? */
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
spin_unlock(&chip->reg_lock);
- snd_azf3328_setdmaa(chip, runtime->dma_addr,
+ snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr,
snd_pcm_lib_period_bytes(substream),
- snd_pcm_lib_buffer_bytes(substream),
- AZF_PLAYBACK);
+ snd_pcm_lib_buffer_bytes(substream)
+ );
spin_lock(&chip->reg_lock);
#ifdef WIN9X
/* FIXME: enable playback/recording??? */
- status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- /* start playback again */
+ /* start transfer again */
/* FIXME: what is this value (0x0010)??? */
- status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
#else /* NT4 */
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
0x0000);
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
- DMA_PLAY_SOMETHING1);
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
- DMA_PLAY_SOMETHING1 |
- DMA_PLAY_SOMETHING2);
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ DMA_RUN_SOMETHING1);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ DMA_RUN_SOMETHING1 |
+ DMA_RUN_SOMETHING2);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
DMA_RESUME |
SOMETHING_ALMOST_ALWAYS_SET |
DMA_EPILOGUE_SOMETHING |
DMA_SOMETHING_ELSE);
#endif
spin_unlock(&chip->reg_lock);
- snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1);
-
- /* now unmute WaveOut */
- if (!previously_muted)
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
+ snd_azf3328_ctrl_codec_activity(chip, codec_type, 1);
+
+ if (is_playback_codec) {
+ /* now unmute WaveOut */
+ if (!previously_muted)
+ snd_azf3328_mixer_set_mute(
+ chip, IDX_MIXER_WAVEOUT, 0
+ );
+ }
- snd_azf3328_dbgplay("STARTED PLAYBACK\n");
+ snd_azf3328_dbgcodec("STARTED %s\n", codec->name);
break;
case SNDRV_PCM_TRIGGER_RESUME:
- snd_azf3328_dbgplay("RESUME PLAYBACK\n");
- /* resume playback if we were active */
+ snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
+ /* resume codec if we were active */
spin_lock(&chip->reg_lock);
- if (chip->audio_stream[AZF_PLAYBACK].running)
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
- snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
+ if (codec->running)
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ snd_azf3328_codec_inw(
+ codec, IDX_IO_CODEC_DMA_FLAGS
+ ) | DMA_RESUME
+ );
spin_unlock(&chip->reg_lock);
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_azf3328_dbgplay("STOP PLAYBACK\n");
-
- /* mute WaveOut (avoid clicking during setup) */
- previously_muted =
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+ snd_azf3328_dbgcodec("STOP %s\n", codec->name);
+
+ if (is_playback_codec) {
+ /* mute WaveOut (avoid clicking during setup) */
+ previously_muted =
+ snd_azf3328_mixer_set_mute(
+ chip, IDX_MIXER_WAVEOUT, 1
+ );
+ }
spin_lock(&chip->reg_lock);
/* first, remember current value: */
- status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS);
+ flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
- /* stop playback */
- status1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ /* stop transfer */
+ flags1 &= ~DMA_RESUME;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
/* hmm, is this really required? we're resetting the same bit
* immediately thereafter... */
- status1 |= DMA_PLAY_SOMETHING1;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ flags1 |= DMA_RUN_SOMETHING1;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- status1 &= ~DMA_PLAY_SOMETHING1;
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
+ flags1 &= ~DMA_RUN_SOMETHING1;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
spin_unlock(&chip->reg_lock);
- snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0);
-
- /* now unmute WaveOut */
- if (!previously_muted)
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
+ snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
+
+ if (is_playback_codec) {
+ /* now unmute WaveOut */
+ if (!previously_muted)
+ snd_azf3328_mixer_set_mute(
+ chip, IDX_MIXER_WAVEOUT, 0
+ );
+ }
- snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
+ snd_azf3328_dbgcodec("STOPPED %s\n", codec->name);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- snd_azf3328_dbgplay("SUSPEND PLAYBACK\n");
- /* make sure playback is stopped */
- snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
- snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME);
+ snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name);
+ /* make sure codec is stopped */
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ snd_azf3328_codec_inw(
+ codec, IDX_IO_CODEC_DMA_FLAGS
+ ) & ~DMA_RESUME
+ );
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
@@ -1217,7 +1321,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
- printk(KERN_ERR "FIXME: unknown trigger mode!\n");
+ snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n");
return -EINVAL;
}
@@ -1225,172 +1329,74 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
return result;
}
-/* this is just analogous to playback; I'm not quite sure whether recording
- * should actually be triggered like that */
static int
-snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int result = 0;
- unsigned int status1;
-
- snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-
- snd_azf3328_dbgplay("START CAPTURE\n");
-
- snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
- runtime->rate,
- snd_pcm_format_width(runtime->format),
- runtime->channels);
-
- spin_lock(&chip->reg_lock);
- /* first, remember current value: */
- status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS);
-
- /* stop recording */
- status1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-
- /* FIXME: clear interrupts or what??? */
- snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff);
- spin_unlock(&chip->reg_lock);
-
- snd_azf3328_setdmaa(chip, runtime->dma_addr,
- snd_pcm_lib_period_bytes(substream),
- snd_pcm_lib_buffer_bytes(substream),
- AZF_CAPTURE);
-
- spin_lock(&chip->reg_lock);
-#ifdef WIN9X
- /* FIXME: enable playback/recording??? */
- status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-
- /* start capture again */
- /* FIXME: what is this value (0x0010)??? */
- status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-#else
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- 0x0000);
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- DMA_PLAY_SOMETHING1);
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- DMA_PLAY_SOMETHING1 |
- DMA_PLAY_SOMETHING2);
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- DMA_RESUME |
- SOMETHING_ALMOST_ALWAYS_SET |
- DMA_EPILOGUE_SOMETHING |
- DMA_SOMETHING_ELSE);
-#endif
- spin_unlock(&chip->reg_lock);
- snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1);
-
- snd_azf3328_dbgplay("STARTED CAPTURE\n");
- break;
- case SNDRV_PCM_TRIGGER_RESUME:
- snd_azf3328_dbgplay("RESUME CAPTURE\n");
- /* resume recording if we were active */
- spin_lock(&chip->reg_lock);
- if (chip->audio_stream[AZF_CAPTURE].running)
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
- spin_unlock(&chip->reg_lock);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- snd_azf3328_dbgplay("STOP CAPTURE\n");
-
- spin_lock(&chip->reg_lock);
- /* first, remember current value: */
- status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS);
-
- /* stop recording */
- status1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-
- status1 |= DMA_PLAY_SOMETHING1;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-
- status1 &= ~DMA_PLAY_SOMETHING1;
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
- spin_unlock(&chip->reg_lock);
- snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0);
+ return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd);
+}
- snd_azf3328_dbgplay("STOPPED CAPTURE\n");
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- snd_azf3328_dbgplay("SUSPEND CAPTURE\n");
- /* make sure recording is stopped */
- snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
- snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME);
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
- break;
- default:
- printk(KERN_ERR "FIXME: unknown trigger mode!\n");
- return -EINVAL;
- }
+static int
+snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd);
+}
- snd_azf3328_dbgcallleave();
- return result;
+static int
+snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd);
}
static snd_pcm_uframes_t
-snd_azf3328_playback_pointer(struct snd_pcm_substream *substream)
+snd_azf3328_codec_pointer(struct snd_pcm_substream *substream,
+ enum snd_azf3328_codec_type codec_type
+)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+ const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+ const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
unsigned long bufptr, result;
snd_pcm_uframes_t frmres;
#ifdef QUERY_HARDWARE
- bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1);
+ bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
#else
bufptr = substream->runtime->dma_addr;
#endif
- result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS);
+ result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS);
/* calculate offset */
result -= bufptr;
frmres = bytes_to_frames( substream->runtime, result);
- snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres);
+ snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n",
+ codec->name, result, frmres);
return frmres;
}
static snd_pcm_uframes_t
-snd_azf3328_capture_pointer(struct snd_pcm_substream *substream)
+snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- unsigned long bufptr, result;
- snd_pcm_uframes_t frmres;
+ return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK);
+}
-#ifdef QUERY_HARDWARE
- bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1);
-#else
- bufptr = substream->runtime->dma_addr;
-#endif
- result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS);
+static snd_pcm_uframes_t
+snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE);
+}
- /* calculate offset */
- result -= bufptr;
- frmres = bytes_to_frames( substream->runtime, result);
- snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres);
- return frmres;
+static snd_pcm_uframes_t
+snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT);
}
/******************************************************************/
#ifdef SUPPORT_GAMEPORT
static inline void
-snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable)
+snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip,
+ bool enable
+)
{
snd_azf3328_io_reg_setb(
chip->game_io+IDX_GAME_HWCONFIG,
@@ -1400,7 +1406,9 @@ snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable)
}
static inline void
-snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable)
+snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip,
+ bool enable
+)
{
snd_azf3328_io_reg_setb(
chip->game_io+IDX_GAME_HWCONFIG,
@@ -1409,10 +1417,27 @@ snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable)
);
}
+static void
+snd_azf3328_gameport_set_counter_frequency(struct snd_azf3328 *chip,
+ unsigned int freq_cfg
+)
+{
+ snd_azf3328_io_reg_setb(
+ chip->game_io+IDX_GAME_HWCONFIG,
+ 0x02,
+ (freq_cfg & 1) != 0
+ );
+ snd_azf3328_io_reg_setb(
+ chip->game_io+IDX_GAME_HWCONFIG,
+ 0x04,
+ (freq_cfg & 2) != 0
+ );
+}
+
static inline void
-snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable)
+snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, bool enable)
{
- snd_azf3328_codec_reg_6AH_update(
+ snd_azf3328_ctrl_reg_6AH_update(
chip, IO_6A_SOMETHING2_GAMEPORT, enable
);
}
@@ -1447,6 +1472,8 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode)
break;
}
+ snd_azf3328_gameport_set_counter_frequency(chip,
+ GAME_HWCFG_ADC_COUNTER_FREQ_STD);
snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0));
return res;
@@ -1458,6 +1485,8 @@ snd_azf3328_gameport_close(struct gameport *gameport)
struct snd_azf3328 *chip = gameport_get_port_data(gameport);
snd_azf3328_dbggame("gameport_close\n");
+ snd_azf3328_gameport_set_counter_frequency(chip,
+ GAME_HWCFG_ADC_COUNTER_FREQ_1_200);
snd_azf3328_gameport_axis_circuit_enable(chip, 0);
}
@@ -1491,7 +1520,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG);
if (val & GAME_AXES_SAMPLING_READY) {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < ARRAY_SIZE(chip->axes); ++i) {
/* configure the axis to read */
val = (i << 4) | 0x0f;
snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val);
@@ -1514,7 +1543,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff);
spin_unlock_irqrestore(&chip->reg_lock, flags);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ARRAY_SIZE(chip->axes); i++) {
axes[i] = chip->axes[i];
if (axes[i] == 0xffff)
axes[i] = -1;
@@ -1552,6 +1581,8 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
/* DISABLE legacy address: we don't need it! */
snd_azf3328_gameport_legacy_address_enable(chip, 0);
+ snd_azf3328_gameport_set_counter_frequency(chip,
+ GAME_HWCFG_ADC_COUNTER_FREQ_1_200);
snd_azf3328_gameport_axis_circuit_enable(chip, 0);
gameport_register_port(chip->gameport);
@@ -1585,40 +1616,77 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
static inline void
snd_azf3328_irq_log_unknown_type(u8 which)
{
- snd_azf3328_dbgplay(
+ snd_azf3328_dbgcodec(
"azt3328: unknown IRQ type (%x) occurred, please report!\n",
which
);
}
+static inline void
+snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status)
+{
+ u8 which;
+ enum snd_azf3328_codec_type codec_type;
+ const struct snd_azf3328_codec_data *codec;
+
+ for (codec_type = AZF_CODEC_PLAYBACK;
+ codec_type <= AZF_CODEC_I2S_OUT;
+ ++codec_type) {
+
+ /* skip codec if there's no interrupt for it */
+ if (!(status & (1 << codec_type)))
+ continue;
+
+ codec = &chip->codecs[codec_type];
+
+ spin_lock(&chip->reg_lock);
+ which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
+ /* ack all IRQ types immediately */
+ snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
+ spin_unlock(&chip->reg_lock);
+
+ if ((chip->pcm[codec_type]) && (codec->substream)) {
+ snd_pcm_period_elapsed(codec->substream);
+ snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
+ codec->name,
+ which,
+ snd_azf3328_codec_inl(
+ codec, IDX_IO_CODEC_DMA_CURRPOS
+ )
+ );
+ } else
+ printk(KERN_WARNING "azt3328: irq handler problem!\n");
+ if (which & IRQ_SOMETHING)
+ snd_azf3328_irq_log_unknown_type(which);
+ }
+}
+
static irqreturn_t
snd_azf3328_interrupt(int irq, void *dev_id)
{
struct snd_azf3328 *chip = dev_id;
- u8 status, which;
-#if DEBUG_PLAY_REC
+ u8 status;
+#if DEBUG_CODEC
static unsigned long irq_count;
#endif
- status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS);
+ status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS);
/* fast path out, to ease interrupt sharing */
if (!(status &
- (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER)
+ (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT
+ |IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER)
))
return IRQ_NONE; /* must be interrupt for another device */
- snd_azf3328_dbgplay(
- "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, "
- "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n",
+ snd_azf3328_dbgcodec(
+ "irq_count %ld! IDX_IO_IRQSTATUS %04x\n",
irq_count++ /* debug-only */,
- snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS),
- snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
status
);
if (status & IRQ_TIMER) {
- /* snd_azf3328_dbgplay("timer %ld\n",
+ /* snd_azf3328_dbgcodec("timer %ld\n",
snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE)
& TIMER_VALUE_MASK
); */
@@ -1626,71 +1694,36 @@ snd_azf3328_interrupt(int irq, void *dev_id)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
/* ACK timer */
spin_lock(&chip->reg_lock);
- snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
+ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
spin_unlock(&chip->reg_lock);
- snd_azf3328_dbgplay("azt3328: timer IRQ\n");
+ snd_azf3328_dbgcodec("azt3328: timer IRQ\n");
}
- if (status & IRQ_PLAYBACK) {
- spin_lock(&chip->reg_lock);
- which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE);
- /* ack all IRQ types immediately */
- snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which);
- spin_unlock(&chip->reg_lock);
- if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) {
- snd_pcm_period_elapsed(
- chip->audio_stream[AZF_PLAYBACK].substream
- );
- snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n",
- which,
- snd_azf3328_codec_inl(
- chip, IDX_IO_PLAY_DMA_CURRPOS
- )
- );
- } else
- printk(KERN_WARNING "azt3328: irq handler problem!\n");
- if (which & IRQ_PLAY_SOMETHING)
- snd_azf3328_irq_log_unknown_type(which);
- }
- if (status & IRQ_RECORDING) {
- spin_lock(&chip->reg_lock);
- which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE);
- /* ack all IRQ types immediately */
- snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which);
- spin_unlock(&chip->reg_lock);
+ if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
+ snd_azf3328_codec_interrupt(chip, status);
- if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) {
- snd_pcm_period_elapsed(
- chip->audio_stream[AZF_CAPTURE].substream
- );
- snd_azf3328_dbgplay("REC period done (#%x), @ %x\n",
- which,
- snd_azf3328_codec_inl(
- chip, IDX_IO_REC_DMA_CURRPOS
- )
- );
- } else
- printk(KERN_WARNING "azt3328: irq handler problem!\n");
- if (which & IRQ_REC_SOMETHING)
- snd_azf3328_irq_log_unknown_type(which);
- }
if (status & IRQ_GAMEPORT)
snd_azf3328_gameport_interrupt(chip);
+
/* MPU401 has less critical IRQ requirements
* than timer and playback/recording, right? */
if (status & IRQ_MPU401) {
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
/* hmm, do we have to ack the IRQ here somehow?
- * If so, then I don't know how... */
- snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n");
+ * If so, then I don't know how yet... */
+ snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n");
}
return IRQ_HANDLED;
}
/*****************************************************************/
-static const struct snd_pcm_hardware snd_azf3328_playback =
+/* as long as we think we have identical snd_pcm_hardware parameters
+ for playback, capture and i2s out, we can use the same physical struct
+ since the struct is simply being copied into a member.
+*/
+static const struct snd_pcm_hardware snd_azf3328_hardware =
{
/* FIXME!! Correct? */
.info = SNDRV_PCM_INFO_MMAP |
@@ -1718,31 +1751,6 @@ static const struct snd_pcm_hardware snd_azf3328_playback =
.fifo_size = 0,
};
-static const struct snd_pcm_hardware snd_azf3328_capture =
-{
- /* FIXME */
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID,
- .formats = SNDRV_PCM_FMTBIT_S8 |
- SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE,
- .rates = SNDRV_PCM_RATE_5512 |
- SNDRV_PCM_RATE_8000_48000 |
- SNDRV_PCM_RATE_KNOT,
- .rate_min = AZF_FREQ_4000,
- .rate_max = AZF_FREQ_66200,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = 65536,
- .period_bytes_min = 64,
- .period_bytes_max = 65536,
- .periods_min = 1,
- .periods_max = 1024,
- .fifo_size = 0,
-};
-
static unsigned int snd_azf3328_fixed_rates[] = {
AZF_FREQ_4000,
@@ -1770,14 +1778,19 @@ static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = {
/*****************************************************************/
static int
-snd_azf3328_playback_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
+ enum snd_azf3328_codec_type codec_type
+)
{
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
snd_azf3328_dbgcallenter();
- chip->audio_stream[AZF_PLAYBACK].substream = substream;
- runtime->hw = snd_azf3328_playback;
+ chip->codecs[codec_type].substream = substream;
+
+ /* same parameters for all our codecs - at least we think so... */
+ runtime->hw = snd_azf3328_hardware;
+
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_azf3328_hw_constraints_rates);
snd_azf3328_dbgcallleave();
@@ -1785,40 +1798,52 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream)
}
static int
+snd_azf3328_playback_open(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK);
+}
+
+static int
snd_azf3328_capture_open(struct snd_pcm_substream *substream)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
+ return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE);
+}
- snd_azf3328_dbgcallenter();
- chip->audio_stream[AZF_CAPTURE].substream = substream;
- runtime->hw = snd_azf3328_capture;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- &snd_azf3328_hw_constraints_rates);
- snd_azf3328_dbgcallleave();
- return 0;
+static int
+snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT);
}
static int
-snd_azf3328_playback_close(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_close(struct snd_pcm_substream *substream,
+ enum snd_azf3328_codec_type codec_type
+)
{
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
snd_azf3328_dbgcallenter();
- chip->audio_stream[AZF_PLAYBACK].substream = NULL;
+ chip->codecs[codec_type].substream = NULL;
snd_azf3328_dbgcallleave();
return 0;
}
static int
+snd_azf3328_playback_close(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK);
+}
+
+static int
snd_azf3328_capture_close(struct snd_pcm_substream *substream)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+ return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE);
+}
- snd_azf3328_dbgcallenter();
- chip->audio_stream[AZF_CAPTURE].substream = NULL;
- snd_azf3328_dbgcallleave();
- return 0;
+static int
+snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream)
+{
+ return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT);
}
/******************************************************************/
@@ -1829,9 +1854,9 @@ static struct snd_pcm_ops snd_azf3328_playback_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_azf3328_hw_params,
.hw_free = snd_azf3328_hw_free,
- .prepare = snd_azf3328_playback_prepare,
- .trigger = snd_azf3328_playback_trigger,
- .pointer = snd_azf3328_playback_pointer
+ .prepare = snd_azf3328_codec_prepare,
+ .trigger = snd_azf3328_codec_playback_trigger,
+ .pointer = snd_azf3328_codec_playback_pointer
};
static struct snd_pcm_ops snd_azf3328_capture_ops = {
@@ -1840,30 +1865,67 @@ static struct snd_pcm_ops snd_azf3328_capture_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_azf3328_hw_params,
.hw_free = snd_azf3328_hw_free,
- .prepare = snd_azf3328_capture_prepare,
- .trigger = snd_azf3328_capture_trigger,
- .pointer = snd_azf3328_capture_pointer
+ .prepare = snd_azf3328_codec_prepare,
+ .trigger = snd_azf3328_codec_capture_trigger,
+ .pointer = snd_azf3328_codec_capture_pointer
+};
+
+static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
+ .open = snd_azf3328_i2s_out_open,
+ .close = snd_azf3328_i2s_out_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_azf3328_hw_params,
+ .hw_free = snd_azf3328_hw_free,
+ .prepare = snd_azf3328_codec_prepare,
+ .trigger = snd_azf3328_codec_i2s_out_trigger,
+ .pointer = snd_azf3328_codec_i2s_out_pointer
};
static int __devinit
-snd_azf3328_pcm(struct snd_azf3328 *chip, int device)
+snd_azf3328_pcm(struct snd_azf3328 *chip)
{
+enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
+
struct snd_pcm *pcm;
int err;
snd_azf3328_dbgcallenter();
- if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0)
+
+ err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD,
+ 1, 1, &pcm);
+ if (err < 0)
return err;
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_azf3328_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_azf3328_capture_ops);
pcm->private_data = chip;
pcm->info_flags = 0;
strcpy(pcm->name, chip->card->shortname);
- chip->pcm = pcm;
+ /* same pcm object for playback/capture (see snd_pcm_new() above) */
+ chip->pcm[AZF_CODEC_PLAYBACK] = pcm;
+ chip->pcm[AZF_CODEC_CAPTURE] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
+ snd_dma_pci_data(chip->pci),
+ 64*1024, 64*1024);
+
+ err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT,
+ 1, 0, &pcm);
+ if (err < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_azf3328_i2s_out_ops);
+
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, chip->card->shortname);
+ chip->pcm[AZF_CODEC_I2S_OUT] = pcm;
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci),
+ 64*1024, 64*1024);
snd_azf3328_dbgcallleave();
return 0;
@@ -1902,7 +1964,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);
delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay);
+ snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_azf3328_dbgcallleave();
return 0;
@@ -1919,7 +1981,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
spin_lock_irqsave(&chip->reg_lock, flags);
/* disable timer countdown and interrupt */
/* FIXME: should we write TIMER_IRQ_ACK here? */
- snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
+ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_azf3328_dbgcallleave();
return 0;
@@ -2035,7 +2097,7 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit)
outb(val, reg);
- printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n",
+ printk(KERN_DEBUG "reg %04x bit %d: %02x %02x %02x\n",
reg, bit, val, valoff, valon
);
}
@@ -2048,9 +2110,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
u16 tmp;
snd_azf3328_dbgmisc(
- "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, "
+ "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, "
"opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n",
- chip->codec_io, chip->game_io, chip->mpu_io,
+ chip->ctrl_io, chip->game_io, chip->mpu_io,
chip->opl3_io, chip->mixer_io, chip->irq
);
@@ -2083,9 +2145,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
inb(0x38c + tmp)
);
- for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2)
- snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n",
- tmp, snd_azf3328_codec_inw(chip, tmp)
+ for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2)
+ snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n",
+ tmp, snd_azf3328_ctrl_inw(chip, tmp)
);
for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2)
@@ -2106,7 +2168,8 @@ snd_azf3328_create(struct snd_card *card,
static struct snd_device_ops ops = {
.dev_free = snd_azf3328_dev_free,
};
- u16 tmp;
+ u8 dma_init;
+ enum snd_azf3328_codec_type codec_type;
*rchip = NULL;
@@ -2138,14 +2201,21 @@ snd_azf3328_create(struct snd_card *card,
if (err < 0)
goto out_err;
- chip->codec_io = pci_resource_start(pci, 0);
+ chip->ctrl_io = pci_resource_start(pci, 0);
chip->game_io = pci_resource_start(pci, 1);
chip->mpu_io = pci_resource_start(pci, 2);
- chip->opl3_io = pci_resource_start(pci, 3);
+ chip->opl3_io = pci_resource_start(pci, 3);
chip->mixer_io = pci_resource_start(pci, 4);
- chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00;
- chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20;
+ chip->codecs[AZF_CODEC_PLAYBACK].io_base =
+ chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
+ chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK";
+ chip->codecs[AZF_CODEC_CAPTURE].io_base =
+ chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
+ chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE";
+ chip->codecs[AZF_CODEC_I2S_OUT].io_base =
+ chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
+ chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT";
if (request_irq(pci->irq, snd_azf3328_interrupt,
IRQF_SHARED, card->shortname, chip)) {
@@ -2168,20 +2238,25 @@ snd_azf3328_create(struct snd_card *card,
if (err < 0)
goto out_err;
- /* shutdown codecs to save power */
- /* have snd_azf3328_codec_activity() act properly */
- chip->audio_stream[AZF_PLAYBACK].running = 1;
- snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0);
+ /* standard codec init stuff */
+ /* default DMA init value */
+ dma_init = DMA_RUN_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE;
- /* standard chip init stuff */
- /* default IRQ init value */
- tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE;
+ for (codec_type = AZF_CODEC_PLAYBACK;
+ codec_type <= AZF_CODEC_I2S_OUT; ++codec_type) {
+ struct snd_azf3328_codec_data *codec =
+ &chip->codecs[codec_type];
- spin_lock_irq(&chip->reg_lock);
- snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp);
- snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp);
- snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp);
- spin_unlock_irq(&chip->reg_lock);
+ /* shutdown codecs to save power */
+ /* have ...ctrl_codec_activity() act properly */
+ codec->running = 1;
+ snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
+
+ spin_lock_irq(&chip->reg_lock);
+ snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS,
+ dma_init);
+ spin_unlock_irq(&chip->reg_lock);
+ }
snd_card_set_dev(card, &pci->dev);
@@ -2229,8 +2304,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
card->private_data = chip;
+ /* chose to use MPU401_HW_AZT2320 ID instead of MPU401_HW_MPU401,
+ since our hardware ought to be similar, thus use same ID. */
err = snd_mpu401_uart_new(
- card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED,
+ card, 0,
+ MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED,
pci->irq, 0, &chip->rmidi
);
if (err < 0) {
@@ -2244,7 +2322,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (err < 0)
goto out_err;
- err = snd_azf3328_pcm(chip, 0);
+ err = snd_azf3328_pcm(chip);
if (err < 0)
goto out_err;
@@ -2266,14 +2344,14 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
opl3->private_data = chip;
sprintf(card->longname, "%s at 0x%lx, irq %i",
- card->shortname, chip->codec_io, chip->irq);
+ card->shortname, chip->ctrl_io, chip->irq);
err = snd_card_register(card);
if (err < 0)
goto out_err;
#ifdef MODULE
- printk(
+ printk(KERN_INFO
"azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n"
"azt3328: Hardware was completely undocumented, unfortunately.\n"
"azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n"
@@ -2308,36 +2386,52 @@ snd_azf3328_remove(struct pci_dev *pci)
}
#ifdef CONFIG_PM
+static inline void
+snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
+{
+ unsigned reg;
+
+ for (reg = 0; reg < count; ++reg) {
+ *saved_regs = inl(io_addr);
+ snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n",
+ io_addr, *saved_regs);
+ ++saved_regs;
+ io_addr += sizeof(*saved_regs);
+ }
+}
+
static int
snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_azf3328 *chip = card->private_data;
- unsigned reg;
+ u16 *saved_regs_ctrl_u16;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
+ snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
+ snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
- for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg)
- chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2);
+ snd_azf3328_suspend_regs(chip->mixer_io,
+ ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
/* make sure to disable master volume etc. to prevent looping sound */
snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
- for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg)
- chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2);
+ snd_azf3328_suspend_regs(chip->ctrl_io,
+ ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl);
/* manually store the one currently relevant write-only reg, too */
- chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH;
+ saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl;
+ saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH;
- for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg)
- chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg)
- chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg)
- chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2);
+ snd_azf3328_suspend_regs(chip->game_io,
+ ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game);
+ snd_azf3328_suspend_regs(chip->mpu_io,
+ ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
+ snd_azf3328_suspend_regs(chip->opl3_io,
+ ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
pci_disable_device(pci);
pci_save_state(pci);
@@ -2345,12 +2439,28 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
return 0;
}
+static inline void
+snd_azf3328_resume_regs(const u32 *saved_regs,
+ unsigned long io_addr,
+ unsigned count
+)
+{
+ unsigned reg;
+
+ for (reg = 0; reg < count; ++reg) {
+ outl(*saved_regs, io_addr);
+ snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
+ io_addr, *saved_regs, inl(io_addr));
+ ++saved_regs;
+ io_addr += sizeof(*saved_regs);
+ }
+}
+
static int
snd_azf3328_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
- struct snd_azf3328 *chip = card->private_data;
- unsigned reg;
+ const struct snd_azf3328 *chip = card->private_data;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
@@ -2362,16 +2472,24 @@ snd_azf3328_resume(struct pci_dev *pci)
}
pci_set_master(pci);
- for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg)
- outw(chip->saved_regs_game[reg], chip->game_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg)
- outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg)
- outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg)
- outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2);
- for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg)
- outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2);
+ snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io,
+ ARRAY_SIZE(chip->saved_regs_game));
+ snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io,
+ ARRAY_SIZE(chip->saved_regs_mpu));
+ snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io,
+ ARRAY_SIZE(chip->saved_regs_opl3));
+
+ snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
+ ARRAY_SIZE(chip->saved_regs_mixer));
+
+ /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
+ and IDX_MIXER_RESET (offset 0x00) get touched at the same time,
+ resulting in a mixer reset condition persisting until _after_
+ master vol was restored. Thus master vol needs an extra restore. */
+ outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2);
+
+ snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io,
+ ARRAY_SIZE(chip->saved_regs_ctrl));
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h
index 974e05122f00..6f46b97650cc 100644
--- a/sound/pci/azt3328.h
+++ b/sound/pci/azt3328.h
@@ -6,50 +6,59 @@
/*** main I/O area port indices ***/
/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
-#define AZF_IO_SIZE_CODEC 0x80
-#define AZF_IO_SIZE_CODEC_PM 0x70
+#define AZF_IO_SIZE_CTRL 0x80
+#define AZF_IO_SIZE_CTRL_PM 0x70
-/* the driver initialisation suggests a layout of 4 main areas:
- * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??).
+/* the driver initialisation suggests a layout of 4 areas
+ * within the main card control I/O:
+ * from 0x00 (playback codec), from 0x20 (recording codec)
+ * and from 0x40 (most certainly I2S out codec).
* And another area from 0x60 to 0x6f (DirectX timer, IRQ management,
* power management etc.???). */
-/** playback area **/
-#define IDX_IO_PLAY_FLAGS 0x00 /* PU:0x0000 */
+#define AZF_IO_OFFS_CODEC_PLAYBACK 0x00
+#define AZF_IO_OFFS_CODEC_CAPTURE 0x20
+#define AZF_IO_OFFS_CODEC_I2S_OUT 0x40
+
+#define IDX_IO_CODEC_DMA_FLAGS 0x00 /* PU:0x0000 */
/* able to reactivate output after output muting due to 8/16bit
* output change, just like 0x0002.
* 0x0001 is the only bit that's able to start the DMA counter */
- #define DMA_RESUME 0x0001 /* paused if cleared ? */
+ #define DMA_RESUME 0x0001 /* paused if cleared? */
/* 0x0002 *temporarily* set during DMA stopping. hmm
* both 0x0002 and 0x0004 set in playback setup. */
/* able to reactivate output after output muting due to 8/16bit
* output change, just like 0x0001. */
- #define DMA_PLAY_SOMETHING1 0x0002 /* \ alternated (toggled) */
+ #define DMA_RUN_SOMETHING1 0x0002 /* \ alternated (toggled) */
/* 0x0004: NOT able to reactivate output */
- #define DMA_PLAY_SOMETHING2 0x0004 /* / bits */
+ #define DMA_RUN_SOMETHING2 0x0004 /* / bits */
#define SOMETHING_ALMOST_ALWAYS_SET 0x0008 /* ???; can be modified */
#define DMA_EPILOGUE_SOMETHING 0x0010
#define DMA_SOMETHING_ELSE 0x0020 /* ??? */
- #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused ? not modifiable */
-#define IDX_IO_PLAY_IRQTYPE 0x02 /* PU:0x0001 */
+ #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused? not modifiable */
+#define IDX_IO_CODEC_IRQTYPE 0x02 /* PU:0x0001 */
/* write back to flags in case flags are set, in order to ACK IRQ in handler
* (bit 1 of port 0x64 indicates interrupt for one of these three types)
* sometimes in this case it just writes 0xffff to globally ACK all IRQs
* settings written are not reflected when reading back, though.
- * seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows ? */
- #define IRQ_PLAY_SOMETHING 0x0001 /* something & ACK */
- #define IRQ_FINISHED_PLAYBUF_1 0x0002 /* 1st dmabuf finished & ACK */
- #define IRQ_FINISHED_PLAYBUF_2 0x0004 /* 2nd dmabuf finished & ACK */
+ * seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows? */
+ #define IRQ_SOMETHING 0x0001 /* something & ACK */
+ #define IRQ_FINISHED_DMABUF_1 0x0002 /* 1st dmabuf finished & ACK */
+ #define IRQ_FINISHED_DMABUF_2 0x0004 /* 2nd dmabuf finished & ACK */
#define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */
#define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */
- #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused ? not modifiable */
-#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area, PU:0x00000000 */
-#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area, PU:0x00000000 */
-#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area, PU:0x0000 */
-#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area, PU:0x0000 */
-#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position, PU:0x00000000 */
-#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area, PU:0x0000 */
-#define IDX_IO_PLAY_SOUNDFORMAT 0x16 /* PU:0x0010 */
+ #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused? not modifiable */
+ /* start address of 1st DMA transfer area, PU:0x00000000 */
+#define IDX_IO_CODEC_DMA_START_1 0x04
+ /* start address of 2nd DMA transfer area, PU:0x00000000 */
+#define IDX_IO_CODEC_DMA_START_2 0x08
+ /* both lengths of DMA transfer areas, PU:0x00000000
+ length1: offset 0x0c, length2: offset 0x0e */
+#define IDX_IO_CODEC_DMA_LENGTHS 0x0c
+#define IDX_IO_CODEC_DMA_CURRPOS 0x10 /* current DMA position, PU:0x00000000 */
+ /* offset within current DMA transfer area, PU:0x0000 */
+#define IDX_IO_CODEC_DMA_CURROFS 0x14
+#define IDX_IO_CODEC_SOUNDFORMAT 0x16 /* PU:0x0010 */
/* all unspecified bits can't be modified */
#define SOUNDFORMAT_FREQUENCY_MASK 0x000f
#define SOUNDFORMAT_XTAL1 0x00
@@ -76,6 +85,7 @@
#define SOUNDFORMAT_FLAG_16BIT 0x0010
#define SOUNDFORMAT_FLAG_2CHANNELS 0x0020
+
/* define frequency helpers, for maximum value safety */
enum azf_freq_t {
#define AZF_FREQ(rate) AZF_FREQ_##rate = rate
@@ -96,29 +106,6 @@ enum azf_freq_t {
#undef AZF_FREQ
};
-/** recording area (see also: playback bit flag definitions) **/
-#define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */
-#define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */
- #define IRQ_REC_SOMETHING 0x0001 /* something & ACK */
- #define IRQ_FINISHED_RECBUF_1 0x0002 /* 1st dmabuf finished & ACK */
- #define IRQ_FINISHED_RECBUF_2 0x0004 /* 2nd dmabuf finished & ACK */
- /* hmm, maybe these are just the corresponding *recording* flags ?
- * but OTOH they are most likely at port 0x22 instead */
- #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */
- #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */
-#define IDX_IO_REC_DMA_START_1 0x24 /* PU:0x00000000 */
-#define IDX_IO_REC_DMA_START_2 0x28 /* PU:0x00000000 */
-#define IDX_IO_REC_DMA_LEN_1 0x2c /* PU:0x0000 */
-#define IDX_IO_REC_DMA_LEN_2 0x2e /* PU:0x0000 */
-#define IDX_IO_REC_DMA_CURRPOS 0x30 /* PU:0x00000000 */
-#define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */
-#define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */
-
-/** hmm, what is this I/O area for? MPU401?? or external DAC via I2S?? (after playback, recording, ???, timer) **/
-#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */
-/* general */
-#define IDX_IO_42H 0x42 /* PU:0x0001 */
-
/** DirectX timer, main interrupt area (FIXME: and something else?) **/
#define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */
/* timer countdown value; triggers IRQ when timer is finished */
@@ -133,17 +120,19 @@ enum azf_freq_t {
#define IDX_IO_IRQSTATUS 0x64
/* some IRQ bit in here might also be used to signal a power-management timer
* timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing).
- * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which
- * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */
+ * OPL3 hardware contains several timers which confusingly in most cases
+ * are NOT routed to an IRQ, but some designs (e.g. LM4560) DO support that,
+ * so I wouldn't be surprised at all to discover that AZF3328
+ * supports that thing as well... */
#define IRQ_PLAYBACK 0x0001
#define IRQ_RECORDING 0x0002
- #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */
+ #define IRQ_I2S_OUT 0x0004 /* this IS I2S, right!? (untested) */
#define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */
#define IRQ_MPU401 0x0010
#define IRQ_TIMER 0x0020 /* DirectX timer */
- #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */
- #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */
+ #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly OPL3 timer? */
+ #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly OPL3 timer? */
#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */
/* this is set to e.g. 0x3ff or 0x300, and writable;
* maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */
@@ -206,7 +195,7 @@ enum azf_freq_t {
/*** Gameport area port indices ***/
/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
#define AZF_IO_SIZE_GAME 0x08
-#define AZF_IO_SIZE_GAME_PM 0x06
+#define AZF_IO_SIZE_GAME_PM 0x06
enum {
AZF_GAME_LEGACY_IO_PORT = 0x200
@@ -272,6 +261,12 @@ enum {
* 11 --> 1/200: */
#define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06
+ /* FIXME: these values might be reversed... */
+ #define GAME_HWCFG_ADC_COUNTER_FREQ_STD 0
+ #define GAME_HWCFG_ADC_COUNTER_FREQ_1_2 1
+ #define GAME_HWCFG_ADC_COUNTER_FREQ_1_20 2
+ #define GAME_HWCFG_ADC_COUNTER_FREQ_1_200 3
+
/* enable gameport legacy I/O address (0x200)
* I was unable to locate any configurability for a different address: */
#define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08
@@ -281,6 +276,7 @@ enum {
#define AZF_IO_SIZE_MPU_PM 0x04
/*** OPL3 synth ***/
+/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
#define AZF_IO_SIZE_OPL3 0x08
#define AZF_IO_SIZE_OPL3_PM 0x06
/* hmm, given that a standard OPL3 has 4 registers only,
@@ -340,4 +336,7 @@ enum {
#define SET_CHAN_LEFT 1
#define SET_CHAN_RIGHT 2
+/* helper macro to align I/O port ranges to 32bit I/O width */
+#define AZF_ALIGN(x) (((x) + 3) & (~3))
+
#endif /* __SOUND_AZT3328_H */
diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h
index 2d07986f57cc..e0394e3996e8 100644
--- a/sound/pci/ctxfi/ct20k2reg.h
+++ b/sound/pci/ctxfi/ct20k2reg.h
@@ -11,9 +11,12 @@
/* Timer Registers */
-#define TIMER_TIMR 0x1B7004
-#define INTERRUPT_GIP 0x1B7010
-#define INTERRUPT_GIE 0x1B7014
+#define WC 0x1b7000
+#define TIMR 0x1b7004
+# define TIMR_IE (1<<15)
+# define TIMR_IP (1<<14)
+#define GIP 0x1b7010
+#define GIE 0x1b7014
/* I2C Registers */
#define I2C_IF_ADDRESS 0x1B9000
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
index a1db51b3ead8..fee35cfc0c7f 100644
--- a/sound/pci/ctxfi/ctamixer.c
+++ b/sound/pci/ctxfi/ctamixer.c
@@ -63,7 +63,7 @@ static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
hw = amixer->rsc.hw;
hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
amixer->input = rsc;
- if (NULL == rsc)
+ if (!rsc)
hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
else
hw->amixer_set_x(amixer->rsc.ctrl_blk,
@@ -99,7 +99,7 @@ static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
hw = amixer->rsc.hw;
amixer->sum = sum;
- if (NULL == sum) {
+ if (!sum) {
hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
} else {
hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
@@ -124,20 +124,20 @@ static int amixer_commit_write(struct amixer *amixer)
/* Program master and conjugate resources */
amixer->rsc.ops->master(&amixer->rsc);
- if (NULL != input)
+ if (input)
input->ops->master(input);
- if (NULL != sum)
+ if (sum)
sum->rsc.ops->master(&sum->rsc);
for (i = 0; i < amixer->rsc.msr; i++) {
hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
- if (NULL != input) {
+ if (input) {
hw->amixer_set_x(amixer->rsc.ctrl_blk,
input->ops->output_slot(input));
input->ops->next_conj(input);
}
- if (NULL != sum) {
+ if (sum) {
hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
sum->rsc.ops->index(&sum->rsc));
sum->rsc.ops->next_conj(&sum->rsc);
@@ -147,10 +147,10 @@ static int amixer_commit_write(struct amixer *amixer)
amixer->rsc.ops->next_conj(&amixer->rsc);
}
amixer->rsc.ops->master(&amixer->rsc);
- if (NULL != input)
+ if (input)
input->ops->master(input);
- if (NULL != sum)
+ if (sum)
sum->rsc.ops->master(&sum->rsc);
return 0;
@@ -242,13 +242,12 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
/* Allocate mem for amixer resource */
amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
- if (NULL == amixer) {
- err = -ENOMEM;
- return err;
- }
+ if (!amixer)
+ return -ENOMEM;
/* Check whether there are sufficient
* amixer resources to meet request. */
+ err = 0;
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < desc->msr; i++) {
err = mgr_get_resource(&mgr->mgr, 1, &idx);
@@ -304,7 +303,7 @@ int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
*ramixer_mgr = NULL;
amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
- if (NULL == amixer_mgr)
+ if (!amixer_mgr)
return -ENOMEM;
err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
@@ -397,12 +396,11 @@ static int get_sum_rsc(struct sum_mgr *mgr,
/* Allocate mem for sum resource */
sum = kzalloc(sizeof(*sum), GFP_KERNEL);
- if (NULL == sum) {
- err = -ENOMEM;
- return err;
- }
+ if (!sum)
+ return -ENOMEM;
/* Check whether there are sufficient sum resources to meet request. */
+ err = 0;
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < desc->msr; i++) {
err = mgr_get_resource(&mgr->mgr, 1, &idx);
@@ -458,7 +456,7 @@ int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
*rsum_mgr = NULL;
sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
- if (NULL == sum_mgr)
+ if (!sum_mgr)
return -ENOMEM;
err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index a49c76647307..b1b3a644f738 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -136,7 +136,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
struct snd_pcm_runtime *runtime;
struct ct_vm *vm;
- if (NULL == apcm->substream)
+ if (!apcm->substream)
return 0;
runtime = apcm->substream->runtime;
@@ -144,7 +144,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
- if (NULL == apcm->vm_block)
+ if (!apcm->vm_block)
return -ENOENT;
return 0;
@@ -154,7 +154,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
struct ct_vm *vm;
- if (NULL == apcm->vm_block)
+ if (!apcm->vm_block)
return;
vm = atc->vm;
@@ -231,16 +231,16 @@ atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
static int select_rom(unsigned int pitch)
{
- if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) {
+ if (pitch > 0x00428f5c && pitch < 0x01b851ec) {
/* 0.26 <= pitch <= 1.72 */
return 1;
- } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) {
+ } else if (pitch == 0x01d66666 || pitch == 0x01d66667) {
/* pitch == 1.8375 */
return 2;
- } else if (0x02000000 == pitch) {
+ } else if (pitch == 0x02000000) {
/* pitch == 2 */
return 3;
- } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) {
+ } else if (pitch >= 0x0 && pitch <= 0x08000000) {
/* 0 <= pitch <= 8 */
return 0;
} else {
@@ -283,7 +283,7 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
/* Get AMIXER resource */
n_amixer = (n_amixer < 2) ? 2 : n_amixer;
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
@@ -311,7 +311,7 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
INIT_VOL, atc->pcm[i+device*2]);
mutex_unlock(&atc->atc_mutex);
src = src->ops->next_interleave(src);
- if (NULL == src)
+ if (!src)
src = apcm->src;
}
@@ -334,7 +334,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
struct srcimp *srcimp;
int i;
- if (NULL != apcm->srcimps) {
+ if (apcm->srcimps) {
for (i = 0; i < apcm->n_srcimp; i++) {
srcimp = apcm->srcimps[i];
srcimp->ops->unmap(srcimp);
@@ -345,7 +345,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
apcm->srcimps = NULL;
}
- if (NULL != apcm->srccs) {
+ if (apcm->srccs) {
for (i = 0; i < apcm->n_srcc; i++) {
src_mgr->put_src(src_mgr, apcm->srccs[i]);
apcm->srccs[i] = NULL;
@@ -354,7 +354,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
apcm->srccs = NULL;
}
- if (NULL != apcm->amixers) {
+ if (apcm->amixers) {
for (i = 0; i < apcm->n_amixer; i++) {
amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
apcm->amixers[i] = NULL;
@@ -363,17 +363,17 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
apcm->amixers = NULL;
}
- if (NULL != apcm->mono) {
+ if (apcm->mono) {
sum_mgr->put_sum(sum_mgr, apcm->mono);
apcm->mono = NULL;
}
- if (NULL != apcm->src) {
+ if (apcm->src) {
src_mgr->put_src(src_mgr, apcm->src);
apcm->src = NULL;
}
- if (NULL != apcm->vm_block) {
+ if (apcm->vm_block) {
/* Undo device virtual mem map */
ct_unmap_audio_buffer(atc, apcm);
apcm->vm_block = NULL;
@@ -419,7 +419,7 @@ static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
src->ops->set_state(src, SRC_STATE_OFF);
src->ops->commit_write(src);
- if (NULL != apcm->srccs) {
+ if (apcm->srccs) {
for (i = 0; i < apcm->n_srcc; i++) {
src = apcm->srccs[i];
src->ops->set_bm(src, 0);
@@ -544,18 +544,18 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
if (n_srcc) {
apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
- if (NULL == apcm->srccs)
+ if (!apcm->srccs)
return -ENOMEM;
}
if (n_amixer) {
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
}
apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
- if (NULL == apcm->srcimps) {
+ if (!apcm->srcimps) {
err = -ENOMEM;
goto error1;
}
@@ -818,7 +818,7 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
/* Get AMIXER resource */
n_amixer = (n_amixer < 2) ? 2 : n_amixer;
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
@@ -919,7 +919,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
amixer = apcm->amixers[i];
amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
src = src->ops->next_interleave(src);
- if (NULL == src)
+ if (!src)
src = apcm->src;
}
/* Connect to SPDIFOO */
@@ -1121,7 +1121,7 @@ static int atc_release_resources(struct ct_atc *atc)
struct ct_mixer *mixer = NULL;
/* disconnect internal mixer objects */
- if (NULL != atc->mixer) {
+ if (atc->mixer) {
mixer = atc->mixer;
mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
@@ -1131,7 +1131,7 @@ static int atc_release_resources(struct ct_atc *atc)
mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
}
- if (NULL != atc->daios) {
+ if (atc->daios) {
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
for (i = 0; i < atc->n_daio; i++) {
daio = atc->daios[i];
@@ -1149,7 +1149,7 @@ static int atc_release_resources(struct ct_atc *atc)
atc->daios = NULL;
}
- if (NULL != atc->pcm) {
+ if (atc->pcm) {
sum_mgr = atc->rsc_mgrs[SUM];
for (i = 0; i < atc->n_pcm; i++)
sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
@@ -1158,7 +1158,7 @@ static int atc_release_resources(struct ct_atc *atc)
atc->pcm = NULL;
}
- if (NULL != atc->srcs) {
+ if (atc->srcs) {
src_mgr = atc->rsc_mgrs[SRC];
for (i = 0; i < atc->n_src; i++)
src_mgr->put_src(src_mgr, atc->srcs[i]);
@@ -1167,7 +1167,7 @@ static int atc_release_resources(struct ct_atc *atc)
atc->srcs = NULL;
}
- if (NULL != atc->srcimps) {
+ if (atc->srcimps) {
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
for (i = 0; i < atc->n_srcimp; i++) {
srcimp = atc->srcimps[i];
@@ -1185,7 +1185,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
{
int i = 0;
- if (NULL == atc)
+ if (!atc)
return 0;
if (atc->timer) {
@@ -1196,21 +1196,20 @@ static int ct_atc_destroy(struct ct_atc *atc)
atc_release_resources(atc);
/* Destroy internal mixer objects */
- if (NULL != atc->mixer)
+ if (atc->mixer)
ct_mixer_destroy(atc->mixer);
for (i = 0; i < NUM_RSCTYP; i++) {
- if ((NULL != rsc_mgr_funcs[i].destroy) &&
- (NULL != atc->rsc_mgrs[i]))
+ if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i])
rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
}
- if (NULL != atc->hw)
+ if (atc->hw)
destroy_hw_obj((struct hw *)atc->hw);
/* Destroy device virtual memory manager object */
- if (NULL != atc->vm) {
+ if (atc->vm) {
ct_vm_destroy(atc->vm);
atc->vm = NULL;
}
@@ -1275,7 +1274,7 @@ int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc)
alsa_dev_funcs[MIXER].public_name = atc->chip_name;
for (i = 0; i < NUM_CTALSADEVS; i++) {
- if (NULL == alsa_dev_funcs[i].create)
+ if (!alsa_dev_funcs[i].create)
continue;
err = alsa_dev_funcs[i].create(atc, i,
@@ -1312,7 +1311,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
return err;
for (i = 0; i < NUM_RSCTYP; i++) {
- if (NULL == rsc_mgr_funcs[i].create)
+ if (!rsc_mgr_funcs[i].create)
continue;
err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
@@ -1339,19 +1338,19 @@ static int atc_get_resources(struct ct_atc *atc)
int err, i;
atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
- if (NULL == atc->daios)
+ if (!atc->daios)
return -ENOMEM;
atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
- if (NULL == atc->srcs)
+ if (!atc->srcs)
return -ENOMEM;
atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
- if (NULL == atc->srcimps)
+ if (!atc->srcimps)
return -ENOMEM;
atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
- if (NULL == atc->pcm)
+ if (!atc->pcm)
return -ENOMEM;
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
@@ -1648,7 +1647,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
*ratc = NULL;
atc = kzalloc(sizeof(*atc), GFP_KERNEL);
- if (NULL == atc)
+ if (!atc)
return -ENOMEM;
/* Set operations */
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index deb6cfa73600..af56eb949bde 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -173,7 +173,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input)
int i;
entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
- if (NULL == entry)
+ if (!entry)
return -ENOMEM;
/* Program master and conjugate resources */
@@ -201,7 +201,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input)
int i;
entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
- if (NULL == entry)
+ if (!entry)
return -ENOMEM;
/* Program master and conjugate resources */
@@ -228,7 +228,7 @@ static int dao_clear_left_input(struct dao *dao)
struct daio *daio = &dao->daio;
int i;
- if (NULL == dao->imappers[0])
+ if (!dao->imappers[0])
return 0;
entry = dao->imappers[0];
@@ -252,7 +252,7 @@ static int dao_clear_right_input(struct dao *dao)
struct daio *daio = &dao->daio;
int i;
- if (NULL == dao->imappers[daio->rscl.msr])
+ if (!dao->imappers[daio->rscl.msr])
return 0;
entry = dao->imappers[daio->rscl.msr];
@@ -408,7 +408,7 @@ static int dao_rsc_init(struct dao *dao,
return err;
dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
- if (NULL == dao->imappers) {
+ if (!dao->imappers) {
err = -ENOMEM;
goto error1;
}
@@ -442,11 +442,11 @@ error1:
static int dao_rsc_uninit(struct dao *dao)
{
- if (NULL != dao->imappers) {
- if (NULL != dao->imappers[0])
+ if (dao->imappers) {
+ if (dao->imappers[0])
dao_clear_left_input(dao);
- if (NULL != dao->imappers[dao->daio.rscl.msr])
+ if (dao->imappers[dao->daio.rscl.msr])
dao_clear_right_input(dao);
kfree(dao->imappers);
@@ -555,7 +555,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
/* Allocate mem for daio resource */
if (desc->type <= DAIO_OUT_MAX) {
dao = kzalloc(sizeof(*dao), GFP_KERNEL);
- if (NULL == dao) {
+ if (!dao) {
err = -ENOMEM;
goto error;
}
@@ -566,7 +566,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
*rdaio = &dao->daio;
} else {
dai = kzalloc(sizeof(*dai), GFP_KERNEL);
- if (NULL == dai) {
+ if (!dai) {
err = -ENOMEM;
goto error;
}
@@ -583,9 +583,9 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return 0;
error:
- if (NULL != dao)
+ if (dao)
kfree(dao);
- else if (NULL != dai)
+ else if (dai)
kfree(dai);
spin_lock_irqsave(&mgr->mgr_lock, flags);
@@ -663,7 +663,7 @@ static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
int err;
spin_lock_irqsave(&mgr->imap_lock, flags);
- if ((0 == entry->addr) && (mgr->init_imap_added)) {
+ if (!entry->addr && mgr->init_imap_added) {
input_mapper_delete(&mgr->imappers, mgr->init_imap,
daio_map_op, mgr);
mgr->init_imap_added = 0;
@@ -707,7 +707,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
*rdaio_mgr = NULL;
daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
- if (NULL == daio_mgr)
+ if (!daio_mgr)
return -ENOMEM;
err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
@@ -718,7 +718,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
spin_lock_init(&daio_mgr->imap_lock);
INIT_LIST_HEAD(&daio_mgr->imappers);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (NULL == entry) {
+ if (!entry) {
err = -ENOMEM;
goto error2;
}
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index ad3e1d144464..0cf400f879f9 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -168,7 +168,7 @@ static int src_get_rsc_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -494,7 +494,7 @@ static int src_mgr_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -515,7 +515,7 @@ static int srcimp_mgr_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -702,7 +702,7 @@ static int amixer_rsc_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -723,7 +723,7 @@ static int amixer_mgr_get_ctrl_blk(void **rblk)
*rblk = NULL;
/*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;*/
@@ -909,7 +909,7 @@ static int dai_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -958,7 +958,7 @@ static int dao_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -1152,7 +1152,7 @@ static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
blk->i2sctl = hw_read_20kx(hw, I2SCTL);
@@ -1808,7 +1808,7 @@ static int uaa_to_xfi(struct pci_dev *pci)
/* By default, Hendrix card UAA Bar0 should be using memory... */
io_base = pci_resource_start(pci, 0);
mem_base = ioremap(io_base, pci_resource_len(pci, 0));
- if (NULL == mem_base)
+ if (!mem_base)
return -ENOENT;
/* Read current mode from Mode Change Register */
@@ -1977,7 +1977,7 @@ static int hw_card_shutdown(struct hw *hw)
hw->irq = -1;
- if (NULL != ((void *)hw->mem_base))
+ if (hw->mem_base)
iounmap((void *)hw->mem_base);
hw->mem_base = (unsigned long)NULL;
@@ -2274,7 +2274,7 @@ int __devinit create_20k1_hw_obj(struct hw **rhw)
*rhw = NULL;
hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
- if (NULL == hw20k1)
+ if (!hw20k1)
return -ENOMEM;
spin_lock_init(&hw20k1->reg_20k1_lock);
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index dec46d04b041..b6b11bfe7574 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -166,7 +166,7 @@ static int src_get_rsc_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -492,7 +492,7 @@ static int src_mgr_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -513,7 +513,7 @@ static int srcimp_mgr_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -702,7 +702,7 @@ static int amixer_rsc_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -891,7 +891,7 @@ static int dai_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -941,7 +941,7 @@ static int dao_get_ctrl_blk(void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
*rblk = blk;
@@ -1092,7 +1092,7 @@ static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
*rblk = NULL;
blk = kzalloc(sizeof(*blk), GFP_KERNEL);
- if (NULL == blk)
+ if (!blk)
return -ENOMEM;
for (i = 0; i < 8; i++) {
@@ -1112,6 +1112,26 @@ static int daio_mgr_put_ctrl_blk(void *blk)
return 0;
}
+/* Timer interrupt */
+static int set_timer_irq(struct hw *hw, int enable)
+{
+ hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
+ return 0;
+}
+
+static int set_timer_tick(struct hw *hw, unsigned int ticks)
+{
+ if (ticks)
+ ticks |= TIMR_IE | TIMR_IP;
+ hw_write_20kx(hw, TIMR, ticks);
+ return 0;
+}
+
+static unsigned int get_wc(struct hw *hw)
+{
+ return hw_read_20kx(hw, WC);
+}
+
/* Card hardware initialization block */
struct dac_conf {
unsigned int msr; /* master sample rate in rsrs */
@@ -1841,6 +1861,22 @@ static int hw_have_digit_io_switch(struct hw *hw)
return 0;
}
+static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
+{
+ struct hw *hw = dev_id;
+ unsigned int status;
+
+ status = hw_read_20kx(hw, GIP);
+ if (!status)
+ return IRQ_NONE;
+
+ if (hw->irq_callback)
+ hw->irq_callback(hw->irq_callback_data, status);
+
+ hw_write_20kx(hw, GIP, status);
+ return IRQ_HANDLED;
+}
+
static int hw_card_start(struct hw *hw)
{
int err = 0;
@@ -1868,7 +1904,7 @@ static int hw_card_start(struct hw *hw)
hw->io_base = pci_resource_start(hw->pci, 2);
hw->mem_base = (unsigned long)ioremap(hw->io_base,
pci_resource_len(hw->pci, 2));
- if (NULL == (void *)hw->mem_base) {
+ if (!hw->mem_base) {
err = -ENOENT;
goto error2;
}
@@ -1879,12 +1915,15 @@ static int hw_card_start(struct hw *hw)
set_field(&gctl, GCTL_UAA, 0);
hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
- /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
- atc->chip_details->nm_card, hw))) {
- goto error3;
+ if (hw->irq < 0) {
+ err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
+ "ctxfi", hw);
+ if (err < 0) {
+ printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+ goto error2;
+ }
+ hw->irq = pci->irq;
}
- hw->irq = pci->irq;
- */
pci_set_master(pci);
@@ -1923,7 +1962,7 @@ static int hw_card_shutdown(struct hw *hw)
hw->irq = -1;
- if (NULL != ((void *)hw->mem_base))
+ if (hw->mem_base)
iounmap((void *)hw->mem_base);
hw->mem_base = (unsigned long)NULL;
@@ -1972,7 +2011,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
/* Reset all global pending interrupts */
- hw_write_20kx(hw, INTERRUPT_GIE, 0);
+ hw_write_20kx(hw, GIE, 0);
/* Reset all SRC pending interrupts */
hw_write_20kx(hw, SRC_IP, 0);
@@ -2149,6 +2188,10 @@ static struct hw ct20k2_preset __devinitdata = {
.daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
.daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
.daio_mgr_commit_write = daio_mgr_commit_write,
+
+ .set_timer_irq = set_timer_irq,
+ .set_timer_tick = set_timer_tick,
+ .get_wc = get_wc,
};
int __devinit create_20k2_hw_obj(struct hw **rhw)
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index f26d7cd9db9f..15c1e7271ea8 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -654,7 +654,7 @@ ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
int err;
kctl = snd_ctl_new1(new, mixer->atc);
- if (NULL == kctl)
+ if (!kctl)
return -ENOMEM;
if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
@@ -837,17 +837,17 @@ static int ct_mixer_get_mem(struct ct_mixer **rmixer)
*rmixer = NULL;
/* Allocate mem for mixer obj */
mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
- if (NULL == mixer)
+ if (!mixer)
return -ENOMEM;
mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
GFP_KERNEL);
- if (NULL == mixer->amixers) {
+ if (!mixer->amixers) {
err = -ENOMEM;
goto error1;
}
mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
- if (NULL == mixer->sums) {
+ if (!mixer->sums) {
err = -ENOMEM;
goto error2;
}
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index 60ea23180acb..d0dc227fbdd3 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -97,7 +97,7 @@ static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
{
struct ct_atc_pcm *apcm = atc_pcm;
- if (NULL == apcm->substream)
+ if (!apcm->substream)
return;
snd_pcm_period_elapsed(apcm->substream);
@@ -123,7 +123,7 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
int err;
apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
- if (NULL == apcm)
+ if (!apcm)
return -ENOMEM;
apcm->substream = substream;
@@ -271,7 +271,7 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
int err;
apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
- if (NULL == apcm)
+ if (!apcm)
return -ENOMEM;
apcm->started = 0;
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
index 889c495bb7d1..7dfaf67344d4 100644
--- a/sound/pci/ctxfi/ctresource.c
+++ b/sound/pci/ctxfi/ctresource.c
@@ -144,7 +144,7 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
rsc->msr = msr;
rsc->hw = hw;
rsc->ops = &rsc_generic_ops;
- if (NULL == hw) {
+ if (!hw) {
rsc->ctrl_blk = NULL;
return 0;
}
@@ -216,7 +216,7 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
mgr->type = NUM_RSCTYP;
mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
- if (NULL == mgr->rscs)
+ if (!mgr->rscs)
return -ENOMEM;
switch (type) {
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
index e1c145d8b702..c749fa720889 100644
--- a/sound/pci/ctxfi/ctsrc.c
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -441,7 +441,7 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
else
src = kzalloc(sizeof(*src), GFP_KERNEL);
- if (NULL == src) {
+ if (!src) {
err = -ENOMEM;
goto error1;
}
@@ -550,7 +550,7 @@ int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
*rsrc_mgr = NULL;
src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL);
- if (NULL == src_mgr)
+ if (!src_mgr)
return -ENOMEM;
err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw);
@@ -679,7 +679,7 @@ static int srcimp_rsc_init(struct srcimp *srcimp,
/* Reserve memory for imapper nodes */
srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr,
GFP_KERNEL);
- if (NULL == srcimp->imappers) {
+ if (!srcimp->imappers) {
err = -ENOMEM;
goto error1;
}
@@ -724,12 +724,11 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
/* Allocate mem for SRCIMP resource */
srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
- if (NULL == srcimp) {
- err = -ENOMEM;
- return err;
- }
+ if (!srcimp)
+ return -ENOMEM;
/* Check whether there are sufficient SRCIMP resources. */
+ err = 0;
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < desc->msr; i++) {
err = mgr_get_resource(&mgr->mgr, 1, &idx);
@@ -834,7 +833,7 @@ int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
*rsrcimp_mgr = NULL;
srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL);
- if (NULL == srcimp_mgr)
+ if (!srcimp_mgr)
return -ENOMEM;
err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw);
@@ -845,7 +844,7 @@ int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
spin_lock_init(&srcimp_mgr->imap_lock);
INIT_LIST_HEAD(&srcimp_mgr->imappers);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (NULL == entry) {
+ if (!entry) {
err = -ENOMEM;
goto error2;
}
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index 67665a7e43c6..6b78752e9503 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -60,7 +60,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
}
block = kzalloc(sizeof(*block), GFP_KERNEL);
- if (NULL == block)
+ if (!block)
goto out;
block->addr = entry->addr;
@@ -181,7 +181,7 @@ int ct_vm_create(struct ct_vm **rvm)
*rvm = NULL;
vm = kzalloc(sizeof(*vm), GFP_KERNEL);
- if (NULL == vm)
+ if (!vm)
return -ENOMEM;
mutex_init(&vm->lock);
@@ -189,7 +189,7 @@ int ct_vm_create(struct ct_vm **rvm)
/* Allocate page table pages */
for (i = 0; i < CT_PTP_NUM; i++) {
vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (NULL == vm->ptp[i])
+ if (!vm->ptp[i])
break;
}
if (!i) {
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 04438f1d682d..55545e0818b5 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK
Say Y here to enable the jack plugging notification via
input layer.
+config SND_HDA_PATCH_LOADER
+ bool "Support initialization patch loading for HD-audio"
+ depends on EXPERIMENTAL
+ select FW_LOADER
+ select SND_HDA_HWDEP
+ select SND_HDA_RECONFIG
+ help
+ Say Y here to allow the HD-audio driver to load a pseudo
+ firmware file ("patch") for overriding the BIOS setup at
+ start up. The "patch" file can be specified via patch module
+ option, such as patch=hda-init.
+
+ This option turns on hwdep and reconfig features automatically.
+
config SND_HDA_CODEC_REALTEK
bool "Build Realtek HD-audio codec support"
default y
@@ -134,6 +148,19 @@ config SND_HDA_ELD
def_bool y
depends on SND_HDA_CODEC_INTELHDMI
+config SND_HDA_CODEC_CIRRUS
+ bool "Build Cirrus Logic codec support"
+ depends on SND_HDA_INTEL
+ default y
+ help
+ Say Y here to include Cirrus Logic codec support in
+ snd-hda-intel driver, such as CS4206.
+
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-cirrus.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_CONEXANT
bool "Build Conexant HD-audio codec support"
default y
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index e3081d4586cc..315a1c4f8998 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o
snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o
snd-hda-codec-atihdmi-objs := patch_atihdmi.o
+snd-hda-codec-cirrus-objs := patch_cirrus.o
snd-hda-codec-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o
@@ -41,6 +42,9 @@ endif
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
endif
+ifdef CONFIG_SND_HDA_CODEC_CIRRUS
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
+endif
ifdef CONFIG_SND_HDA_CODEC_CA0110
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
endif
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index b0275a050870..3f51a981e604 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -24,6 +24,7 @@
#include <linux/workqueue.h>
#include <sound/core.h>
#include "hda_beep.h"
+#include "hda_local.h"
enum {
DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */
@@ -118,6 +119,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
struct hda_beep *beep;
int err;
+ if (!snd_hda_get_bool_hint(codec, "beep"))
+ return 0; /* disabled explicitly */
+
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
if (beep == NULL)
return -ENOMEM;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 88480c0c58a0..a23c27d2fb2f 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -44,6 +44,7 @@ struct hda_vendor_id {
/* codec vendor labels */
static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x1002, "ATI" },
+ { 0x1013, "Cirrus Logic" },
{ 0x1057, "Motorola" },
{ 0x1095, "Silicon Image" },
{ 0x10de, "Nvidia" },
@@ -150,7 +151,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
{
u32 val;
- val = (u32)(codec->addr & 0x0f) << 28;
+ if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
+ (verb & ~0xfff) || (parm & ~0xffff)) {
+ printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
+ codec->addr, direct, nid, verb, parm);
+ return ~0;
+ }
+
+ val = (u32)codec->addr << 28;
val |= (u32)direct << 27;
val |= (u32)nid << 20;
val |= verb << 8;
@@ -167,6 +175,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
struct hda_bus *bus = codec->bus;
int err;
+ if (cmd == ~0)
+ return -1;
+
if (res)
*res = -1;
again:
@@ -291,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
int i, conn_len, conns;
unsigned int shift, num_elems, mask;
+ unsigned int wcaps;
hda_nid_t prev_nid;
if (snd_BUG_ON(!conn_list || max_conns <= 0))
return -EINVAL;
+ wcaps = get_wcaps(codec, nid);
+ if (!(wcaps & AC_WCAP_CONN_LIST) &&
+ get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
+ snd_printk(KERN_WARNING "hda_codec: "
+ "connection list not available for 0x%x\n", nid);
+ return -EINVAL;
+ }
+
parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
if (parm & AC_CLIST_LONG) {
/* long form */
@@ -316,6 +336,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
/* single connection */
parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_LIST, 0);
+ if (parm == -1 && codec->bus->rirb_error)
+ return -EIO;
conn_list[0] = parm & mask;
return 1;
}
@@ -327,9 +349,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
int range_val;
hda_nid_t val, n;
- if (i % num_elems == 0)
+ if (i % num_elems == 0) {
parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_LIST, i);
+ if (parm == -1 && codec->bus->rirb_error)
+ return -EIO;
+ }
range_val = !!(parm & (1 << (shift-1))); /* ranges */
val = parm & mask;
if (val == 0) {
@@ -727,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec)
for (i = 0; i < codec->num_nodes; i++, nid++) {
struct hda_pincfg *pin;
unsigned int wcaps = get_wcaps(codec, nid);
- unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
- AC_WCAP_TYPE_SHIFT;
+ unsigned int wid_type = get_wcaps_type(wcaps);
if (wid_type != AC_WID_PIN)
continue;
pin = snd_array_new(&codec->init_pins);
@@ -891,7 +915,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
* Returns 0 if successful, or a negative error code.
*/
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
- int do_init, struct hda_codec **codecp)
+ struct hda_codec **codecp)
{
struct hda_codec *codec;
char component[31];
@@ -984,11 +1008,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D0);
- if (do_init) {
- err = snd_hda_codec_configure(codec);
- if (err < 0)
- goto error;
- }
snd_hda_codec_proc_new(codec);
snd_hda_create_hwdep(codec);
@@ -1042,6 +1061,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
err = init_unsol_queue(codec->bus);
return err;
}
+EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
/**
* snd_hda_codec_setup_stream - set up the codec for streaming
@@ -2356,16 +2376,20 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
hda_nid_t nid;
int i;
- snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ /* this delay seems necessary to avoid click noise at power-down */
+ if (power_state == AC_PWRST_D3)
+ msleep(100);
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
power_state);
- msleep(10); /* partial workaround for "azx_get_response timeout" */
+ /* partial workaround for "azx_get_response timeout" */
+ if (power_state == AC_PWRST_D0)
+ msleep(10);
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid);
if (wcaps & AC_WCAP_POWER) {
- unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
- AC_WCAP_TYPE_SHIFT;
+ unsigned int wid_type = get_wcaps_type(wcaps);
if (power_state == AC_PWRST_D3 &&
wid_type == AC_WID_PIN) {
unsigned int pincap;
@@ -2573,7 +2597,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
case 20:
case 24:
case 32:
- if (maxbps >= 32)
+ if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
val |= 0x40;
else if (maxbps >= 24)
val |= 0x30;
@@ -2700,11 +2724,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
bps = 20;
}
}
- else if (streams == AC_SUPFMT_FLOAT32) {
- /* should be exclusive */
+ if (streams & AC_SUPFMT_FLOAT32) {
formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
- bps = 32;
- } else if (streams == AC_SUPFMT_AC3) {
+ if (!bps)
+ bps = 32;
+ }
+ if (streams == AC_SUPFMT_AC3) {
/* should be exclusive */
/* temporary hack: we have still no proper support
* for the direct AC3 stream...
@@ -3655,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
end_nid = codec->start_nid + codec->num_nodes;
for (nid = codec->start_nid; nid < end_nid; nid++) {
unsigned int wid_caps = get_wcaps(codec, nid);
- unsigned int wid_type =
- (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ unsigned int wid_type = get_wcaps_type(wid_caps);
unsigned int def_conf;
short assoc, loc;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index cad79efaabc9..72c997592eed 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -830,7 +830,8 @@ enum {
int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
struct hda_bus **busp);
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
- int do_init, struct hda_codec **codecp);
+ struct hda_codec **codecp);
+int snd_hda_codec_configure(struct hda_codec *codec);
/*
* low level functions
@@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {}
#define snd_hda_codec_needs_resume(codec) 1
#endif
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+/*
+ * patch firmware
+ */
+int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
+#endif
+
/*
* Codec modularization
*/
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index fcad5ec31773..9446a5abea13 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -508,7 +508,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
char name[64];
char *sname;
long long val;
- int n;
+ unsigned int n;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%s %llx", name, &val) != 2)
@@ -539,7 +539,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
sname++;
n = 10 * n + name[4] - '0';
}
- if (n < 0 || n > 31) /* double the CEA limit */
+ if (n >= ELD_MAX_SAD)
continue;
if (!strcmp(sname, "_coding_type"))
e->sad[n].format = val;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 1d5797a96682..b36f6c5a92df 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
if (node == NULL)
return -ENOMEM;
node->nid = nid;
- nconns = snd_hda_get_connections(codec, nid, conn_list,
- HDA_MAX_CONNECTIONS);
- if (nconns < 0) {
- kfree(node);
- return nconns;
+ node->wid_caps = get_wcaps(codec, nid);
+ node->type = get_wcaps_type(node->wid_caps);
+ if (node->wid_caps & AC_WCAP_CONN_LIST) {
+ nconns = snd_hda_get_connections(codec, nid, conn_list,
+ HDA_MAX_CONNECTIONS);
+ if (nconns < 0) {
+ kfree(node);
+ return nconns;
+ }
+ } else {
+ nconns = 0;
}
if (nconns <= ARRAY_SIZE(node->slist))
node->conn_list = node->slist;
@@ -140,8 +146,6 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
}
memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
node->nconns = nconns;
- node->wid_caps = get_wcaps(codec, nid);
- node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
if (node->type == AC_WID_PIN) {
node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6812fbe80fa4..cc24e6721d74 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -24,6 +24,7 @@
#include <linux/compat.h>
#include <linux/mutex.h>
#include <linux/ctype.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev,
return len;
}
-static ssize_t init_verbs_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int parse_init_verbs(struct hda_codec *codec, const char *buf)
{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
struct hda_verb *v;
int nid, verb, param;
@@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev,
v->nid = nid;
v->verb = verb;
v->param = param;
+ return 0;
+}
+
+static ssize_t init_verbs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+ struct hda_codec *codec = hwdep->private_data;
+ int err = parse_init_verbs(codec, buf);
+ if (err < 0)
+ return err;
return count;
}
@@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str)
#define MAX_HINTS 1024
-static ssize_t hints_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int parse_hints(struct hda_codec *codec, const char *buf)
{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
char *key, *val;
struct hda_hint *hint;
while (isspace(*buf))
buf++;
if (!*buf || *buf == '#' || *buf == '\n')
- return count;
+ return 0;
if (*buf == '=')
return -EINVAL;
key = kstrndup_noeol(buf, 1024);
@@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev,
kfree(hint->key);
hint->key = key;
hint->val = val;
- return count;
+ return 0;
}
/* allocate a new hint entry */
if (codec->hints.used >= MAX_HINTS)
@@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev,
}
hint->key = key;
hint->val = val;
+ return 0;
+}
+
+static ssize_t hints_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+ struct hda_codec *codec = hwdep->private_data;
+ int err = parse_hints(codec, buf);
+ if (err < 0)
+ return err;
return count;
}
@@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev,
#define MAX_PIN_CONFIGS 32
-static ssize_t user_pin_configs_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
int nid, cfg;
- int err;
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
return -EINVAL;
if (!nid)
return -EINVAL;
- err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
+ return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
+}
+
+static ssize_t user_pin_configs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+ struct hda_codec *codec = hwdep->private_data;
+ int err = parse_user_pin_configs(codec, buf);
if (err < 0)
return err;
return count;
@@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+
+/* parser mode */
+enum {
+ LINE_MODE_NONE,
+ LINE_MODE_CODEC,
+ LINE_MODE_MODEL,
+ LINE_MODE_PINCFG,
+ LINE_MODE_VERB,
+ LINE_MODE_HINT,
+ NUM_LINE_MODES,
+};
+
+static inline int strmatch(const char *a, const char *b)
+{
+ return strnicmp(a, b, strlen(b)) == 0;
+}
+
+/* parse the contents after the line "[codec]"
+ * accept only the line with three numbers, and assign the current codec
+ */
+static void parse_codec_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ unsigned int vendorid, subid, caddr;
+ struct hda_codec *codec;
+
+ *codecp = NULL;
+ if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
+ list_for_each_entry(codec, &bus->codec_list, list) {
+ if (codec->addr == caddr) {
+ *codecp = codec;
+ break;
+ }
+ }
+ }
+}
+
+/* parse the contents after the other command tags, [pincfg], [verb],
+ * [hint] and [model]
+ * just pass to the sysfs helper (only when any codec was specified)
+ */
+static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ if (!*codecp)
+ return;
+ parse_user_pin_configs(*codecp, buf);
+}
+
+static void parse_verb_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ if (!*codecp)
+ return;
+ parse_init_verbs(*codecp, buf);
+}
+
+static void parse_hint_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ if (!*codecp)
+ return;
+ parse_hints(*codecp, buf);
+}
+
+static void parse_model_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ if (!*codecp)
+ return;
+ kfree((*codecp)->modelname);
+ (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
+}
+
+struct hda_patch_item {
+ const char *tag;
+ void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
+};
+
+static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
+ [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
+ [LINE_MODE_MODEL] = { "[model]", parse_model_mode },
+ [LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
+ [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
+ [LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
+};
+
+/* check the line starting with '[' -- change the parser mode accodingly */
+static int parse_line_mode(char *buf, struct hda_bus *bus)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
+ if (!patch_items[i].tag)
+ continue;
+ if (strmatch(buf, patch_items[i].tag))
+ return i;
+ }
+ return LINE_MODE_NONE;
+}
+
+/* copy one line from the buffer in fw, and update the fields in fw
+ * return zero if it reaches to the end of the buffer, or non-zero
+ * if successfully copied a line
+ *
+ * the spaces at the beginning and the end of the line are stripped
+ */
+static int get_line_from_fw(char *buf, int size, struct firmware *fw)
+{
+ int len;
+ const char *p = fw->data;
+ while (isspace(*p) && fw->size) {
+ p++;
+ fw->size--;
+ }
+ if (!fw->size)
+ return 0;
+ if (size < fw->size)
+ size = fw->size;
+
+ for (len = 0; len < fw->size; len++) {
+ if (!*p)
+ break;
+ if (*p == '\n') {
+ p++;
+ len++;
+ break;
+ }
+ if (len < size)
+ *buf++ = *p++;
+ }
+ *buf = 0;
+ fw->size -= len;
+ fw->data = p;
+ remove_trail_spaces(buf);
+ return 1;
+}
+
+/*
+ * load a "patch" firmware file and parse it
+ */
+int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
+{
+ int err;
+ const struct firmware *fw;
+ struct firmware tmp;
+ char buf[128];
+ struct hda_codec *codec;
+ int line_mode;
+ struct device *dev = bus->card->dev;
+
+ if (snd_BUG_ON(!dev))
+ return -ENODEV;
+ err = request_firmware(&fw, patch, dev);
+ if (err < 0) {
+ printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
+ patch);
+ return err;
+ }
+
+ tmp = *fw;
+ line_mode = LINE_MODE_NONE;
+ codec = NULL;
+ while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
+ if (!*buf || *buf == '#' || *buf == '\n')
+ continue;
+ if (*buf == '[')
+ line_mode = parse_line_mode(buf, bus);
+ else if (patch_items[line_mode].parser)
+ patch_items[line_mode].parser(buf, bus, &codec);
+ }
+ release_firmware(fw);
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_load_patch);
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 77c1b840ca8b..4db854b43e6b 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -61,6 +61,9 @@ 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;
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+static char *patch[SNDRV_CARDS];
+#endif
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
"(for debugging only).");
module_param(enable_msi, int, 0444);
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+module_param_array(patch, charp, NULL, 0444);
+MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
+#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
@@ -1286,8 +1293,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
[AZX_DRIVER_TERA] = 1,
};
-static int __devinit azx_codec_create(struct azx *chip, const char *model,
- int no_init)
+static int __devinit azx_codec_create(struct azx *chip, const char *model)
{
struct hda_bus_template bus_temp;
int c, codecs, err;
@@ -1346,7 +1352,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
for (c = 0; c < max_slots; c++) {
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
struct hda_codec *codec;
- err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
+ err = snd_hda_codec_new(chip->bus, c, &codec);
if (err < 0)
continue;
codecs++;
@@ -1356,7 +1362,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
snd_printk(KERN_ERR SFX "no codecs initialized\n");
return -ENXIO;
}
+ return 0;
+}
+/* configure each codec instance */
+static int __devinit azx_codec_configure(struct azx *chip)
+{
+ struct hda_codec *codec;
+ list_for_each_entry(codec, &chip->bus->codec_list, list) {
+ snd_hda_codec_configure(codec);
+ }
return 0;
}
@@ -2481,15 +2496,32 @@ static int __devinit azx_probe(struct pci_dev *pci,
return err;
}
+ /* set this here since it's referred in snd_hda_load_patch() */
+ snd_card_set_dev(card, &pci->dev);
+
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
if (err < 0)
goto out_free;
card->private_data = chip;
/* create codec instances */
- err = azx_codec_create(chip, model[dev], probe_only[dev]);
+ err = azx_codec_create(chip, model[dev]);
if (err < 0)
goto out_free;
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ if (patch[dev]) {
+ snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
+ patch[dev]);
+ err = snd_hda_load_patch(chip->bus, patch[dev]);
+ if (err < 0)
+ goto out_free;
+ }
+#endif
+ if (!probe_only[dev]) {
+ err = azx_codec_configure(chip);
+ if (err < 0)
+ goto out_free;
+ }
/* create PCM streams */
err = snd_hda_build_pcms(chip->bus);
@@ -2501,8 +2533,6 @@ static int __devinit azx_probe(struct pci_dev *pci,
if (err < 0)
goto out_free;
- snd_card_set_dev(card, &pci->dev);
-
err = snd_card_register(card);
if (err < 0)
goto out_free;
@@ -2604,11 +2634,15 @@ static struct pci_device_id azx_ids[] = {
/* this entry seems still valid -- i.e. without emu20kx chip */
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
#endif
- /* AMD Generic, PCI class code and Vendor ID for HD Audio */
+ /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_GENERIC },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
+ .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+ .class_mask = 0xffffff,
+ .driver_data = AZX_DRIVER_GENERIC },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 83349013b4df..fa57cb93b443 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves);
int snd_hda_codec_reset(struct hda_codec *codec);
-int snd_hda_codec_configure(struct hda_codec *codec);
/* amp value bits */
#define HDA_AMP_MUTE 0x80
@@ -408,6 +407,9 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
return codec->wcaps[nid - codec->start_nid];
}
+/* get the widget type from widget capability bits */
+#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT)
+
u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 418c5d1badaa..a721eb08a290 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -508,8 +508,7 @@ static void print_codec_info(struct snd_info_entry *entry,
unsigned int wid_caps =
snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
- unsigned int wid_type =
- (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ unsigned int wid_type = get_wcaps_type(wid_caps);
hda_nid_t conn[HDA_MAX_CONNECTIONS];
int conn_len = 0;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index be7d25fa7f35..ab3bcb78ace9 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
ad1988_models, ad1988_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = AD1988_AUTO;
}
@@ -3754,7 +3755,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
int mute = (!ucontrol->value.integer.value[0] &&
!ucontrol->value.integer.value[1]);
/* toggle GPIO1 according to the mute state */
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
mute ? 0x02 : 0x0);
return ret;
}
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 019ca7cb56d7..d08353d3bb7f 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec)
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid);
- unsigned int type = (wcaps & AC_WCAP_TYPE) >>
- AC_WCAP_TYPE_SHIFT;
+ unsigned int type = get_wcaps_type(wcaps);
if (type != AC_WID_AUD_IN)
continue;
if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
new file mode 100644
index 000000000000..8ba306856d38
--- /dev/null
+++ b/sound/pci/hda/patch_cirrus.c
@@ -0,0 +1,1194 @@
+/*
+ * HD audio interface patch for Cirrus Logic CS420x chip
+ *
+ * Copyright (c) 2009 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ */
+
+struct cs_spec {
+ int board_config;
+ struct auto_pin_cfg autocfg;
+ struct hda_multi_out multiout;
+ struct snd_kcontrol *vmaster_sw;
+ struct snd_kcontrol *vmaster_vol;
+
+ hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS];
+ hda_nid_t slave_dig_outs[2];
+
+ unsigned int input_idx[AUTO_PIN_LAST];
+ unsigned int capsrc_idx[AUTO_PIN_LAST];
+ hda_nid_t adc_nid[AUTO_PIN_LAST];
+ unsigned int adc_idx[AUTO_PIN_LAST];
+ unsigned int num_inputs;
+ unsigned int cur_input;
+ unsigned int automic_idx;
+ hda_nid_t cur_adc;
+ unsigned int cur_adc_stream_tag;
+ unsigned int cur_adc_format;
+ hda_nid_t dig_in;
+
+ struct hda_bind_ctls *capture_bind[2];
+
+ unsigned int gpio_mask;
+ unsigned int gpio_dir;
+ unsigned int gpio_data;
+
+ struct hda_pcm pcm_rec[2]; /* PCM information */
+
+ unsigned int hp_detect:1;
+ unsigned int mic_detect:1;
+};
+
+/* available models */
+enum {
+ CS420X_MBP55,
+ CS420X_AUTO,
+ CS420X_MODELS
+};
+
+/* Vendor-specific processing widget */
+#define CS420X_VENDOR_NID 0x11
+#define CS_DIG_OUT1_PIN_NID 0x10
+#define CS_DIG_OUT2_PIN_NID 0x15
+#define CS_DMIC1_PIN_NID 0x12
+#define CS_DMIC2_PIN_NID 0x0e
+
+/* coef indices */
+#define IDX_SPDIF_STAT 0x0000
+#define IDX_SPDIF_CTL 0x0001
+#define IDX_ADC_CFG 0x0002
+/* SZC bitmask, 4 modes below:
+ * 0 = immediate,
+ * 1 = digital immediate, analog zero-cross
+ * 2 = digtail & analog soft-ramp
+ * 3 = digital soft-ramp, analog zero-cross
+ */
+#define CS_COEF_ADC_SZC_MASK (3 << 0)
+#define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */
+#define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */
+/* PGA mode: 0 = differential, 1 = signle-ended */
+#define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */
+#define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */
+#define IDX_DAC_CFG 0x0003
+/* SZC bitmask, 4 modes below:
+ * 0 = Immediate
+ * 1 = zero-cross
+ * 2 = soft-ramp
+ * 3 = soft-ramp on zero-cross
+ */
+#define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */
+#define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */
+#define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */
+
+#define IDX_BEEP_CFG 0x0004
+/* 0x0008 - test reg key */
+/* 0x0009 - 0x0014 -> 12 test regs */
+/* 0x0015 - visibility reg */
+
+
+static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
+{
+ snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ AC_VERB_SET_COEF_INDEX, idx);
+ return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0,
+ AC_VERB_GET_PROC_COEF, 0);
+}
+
+static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
+ unsigned int coef)
+{
+ snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ AC_VERB_SET_COEF_INDEX, idx);
+ snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ AC_VERB_SET_PROC_COEF, coef);
+}
+
+
+#define HP_EVENT 1
+#define MIC_EVENT 2
+
+/*
+ * PCM callbacks
+ */
+static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+ hinfo);
+}
+
+static int cs_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 cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+ stream_tag, format, substream);
+}
+
+static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int cs_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+}
+
+static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ spec->cur_adc = spec->adc_nid[spec->cur_input];
+ spec->cur_adc_stream_tag = stream_tag;
+ spec->cur_adc_format = format;
+ snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+ return 0;
+}
+
+static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct cs_spec *spec = codec->spec;
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+ spec->cur_adc = 0;
+ return 0;
+}
+
+/*
+ */
+static struct hda_pcm_stream cs_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .ops = {
+ .open = cs_playback_pcm_open,
+ .prepare = cs_playback_pcm_prepare,
+ .cleanup = cs_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream cs_pcm_analog_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .ops = {
+ .prepare = cs_capture_pcm_prepare,
+ .cleanup = cs_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream cs_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .ops = {
+ .open = cs_dig_playback_pcm_open,
+ .close = cs_dig_playback_pcm_close,
+ .prepare = cs_dig_playback_pcm_prepare,
+ .cleanup = cs_dig_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream cs_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int cs_build_pcms(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->pcm_info = info;
+ codec->num_pcms = 0;
+
+ info->name = "Cirrus Analog";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0];
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->adc_nid[spec->cur_input];
+ codec->num_pcms++;
+
+ if (!spec->multiout.dig_out_nid && !spec->dig_in)
+ return 0;
+
+ info++;
+ info->name = "Cirrus Digital";
+ info->pcm_type = spec->autocfg.dig_out_type[0];
+ if (!info->pcm_type)
+ info->pcm_type = HDA_PCM_TYPE_SPDIF;
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ cs_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dig_out_nid;
+ }
+ if (spec->dig_in) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ cs_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+ }
+ codec->num_pcms++;
+
+ return 0;
+}
+
+/*
+ * parse codec topology
+ */
+
+static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+ hda_nid_t dac;
+ if (!pin)
+ return 0;
+ if (snd_hda_get_connections(codec, pin, &dac, 1) != 1)
+ return 0;
+ return dac;
+}
+
+static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t pin = cfg->input_pins[idx];
+ unsigned int val = snd_hda_query_pin_caps(codec, pin);
+ if (!(val & AC_PINCAP_PRES_DETECT))
+ return 0;
+ val = snd_hda_codec_get_pincfg(codec, pin);
+ return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
+}
+
+static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
+ unsigned int *idxp)
+{
+ int i;
+ hda_nid_t nid;
+
+ nid = codec->start_nid;
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ hda_nid_t pins[2];
+ unsigned int type;
+ int j, nums;
+ type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
+ >> AC_WCAP_TYPE_SHIFT;
+ if (type != AC_WID_AUD_IN)
+ continue;
+ nums = snd_hda_get_connections(codec, nid, pins,
+ ARRAY_SIZE(pins));
+ if (nums <= 0)
+ continue;
+ for (j = 0; j < nums; j++) {
+ if (pins[j] == pin) {
+ *idxp = j;
+ return nid;
+ }
+ }
+ }
+ return 0;
+}
+
+static int is_active_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int val;
+ val = snd_hda_codec_get_pincfg(codec, nid);
+ return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
+}
+
+static int parse_output(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, extra_nids;
+ hda_nid_t dac;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ dac = get_dac(codec, cfg->line_out_pins[i]);
+ if (!dac)
+ break;
+ spec->dac_nid[i] = dac;
+ }
+ spec->multiout.num_dacs = i;
+ spec->multiout.dac_nids = spec->dac_nid;
+ spec->multiout.max_channels = i * 2;
+
+ /* add HP and speakers */
+ extra_nids = 0;
+ for (i = 0; i < cfg->hp_outs; i++) {
+ dac = get_dac(codec, cfg->hp_pins[i]);
+ if (!dac)
+ break;
+ if (!i)
+ spec->multiout.hp_nid = dac;
+ else
+ spec->multiout.extra_out_nid[extra_nids++] = dac;
+ }
+ for (i = 0; i < cfg->speaker_outs; i++) {
+ dac = get_dac(codec, cfg->speaker_pins[i]);
+ if (!dac)
+ break;
+ spec->multiout.extra_out_nid[extra_nids++] = dac;
+ }
+
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+ cfg->speaker_outs = cfg->line_outs;
+ memcpy(cfg->speaker_pins, cfg->line_out_pins,
+ sizeof(cfg->speaker_pins));
+ cfg->line_outs = 0;
+ }
+
+ return 0;
+}
+
+static int parse_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t pin = cfg->input_pins[i];
+ if (!pin)
+ continue;
+ spec->input_idx[spec->num_inputs] = i;
+ spec->capsrc_idx[i] = spec->num_inputs++;
+ spec->cur_input = i;
+ spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]);
+ }
+ if (!spec->num_inputs)
+ return 0;
+
+ /* check whether the automatic mic switch is available */
+ if (spec->num_inputs == 2 &&
+ spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
+ if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
+ if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+ spec->mic_detect = 1;
+ spec->automic_idx = AUTO_PIN_FRONT_MIC;
+ }
+ } else {
+ if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+ spec->mic_detect = 1;
+ spec->automic_idx = AUTO_PIN_MIC;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int parse_digital_output(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
+
+ if (!cfg->dig_outs)
+ return 0;
+ if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1)
+ return 0;
+ spec->multiout.dig_out_nid = nid;
+ spec->multiout.share_spdif = 1;
+ if (cfg->dig_outs > 1 &&
+ snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) {
+ spec->slave_dig_outs[0] = nid;
+ codec->slave_dig_outs = spec->slave_dig_outs;
+ }
+ return 0;
+}
+
+static int parse_digital_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int idx;
+
+ if (cfg->dig_in_pin)
+ spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx);
+ return 0;
+}
+
+/*
+ * create mixer controls
+ */
+
+static const char *dir_sfx[2] = { "Playback", "Capture" };
+
+static int add_mute(struct hda_codec *codec, const char *name, int index,
+ unsigned int pval, int dir, struct snd_kcontrol **kctlp)
+{
+ char tmp[44];
+ struct snd_kcontrol_new knew =
+ HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT);
+ knew.private_value = pval;
+ snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]);
+ *kctlp = snd_ctl_new1(&knew, codec);
+ return snd_hda_ctl_add(codec, *kctlp);
+}
+
+static int add_volume(struct hda_codec *codec, const char *name,
+ int index, unsigned int pval, int dir,
+ struct snd_kcontrol **kctlp)
+{
+ char tmp[32];
+ struct snd_kcontrol_new knew =
+ HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT);
+ knew.private_value = pval;
+ snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]);
+ *kctlp = snd_ctl_new1(&knew, codec);
+ return snd_hda_ctl_add(codec, *kctlp);
+}
+
+static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
+{
+ unsigned int caps;
+
+ /* set the upper-limit for mixer amp to 0dB */
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
+ caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
+ << AC_AMPCAP_NUM_STEPS_SHIFT;
+ snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
+}
+
+static int add_vmaster(struct hda_codec *codec, hda_nid_t dac)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int tlv[4];
+ int err;
+
+ spec->vmaster_sw =
+ snd_ctl_make_virtual_master("Master Playback Switch", NULL);
+ err = snd_hda_ctl_add(codec, spec->vmaster_sw);
+ if (err < 0)
+ return err;
+
+ snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv);
+ spec->vmaster_vol =
+ snd_ctl_make_virtual_master("Master Playback Volume", tlv);
+ err = snd_hda_ctl_add(codec, spec->vmaster_vol);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
+ int num_ctls, int type)
+{
+ struct cs_spec *spec = codec->spec;
+ const char *name;
+ int err, index;
+ struct snd_kcontrol *kctl;
+ static char *speakers[] = {
+ "Front Speaker", "Surround Speaker", "Bass Speaker"
+ };
+ static char *line_outs[] = {
+ "Front Line-Out", "Surround Line-Out", "Bass Line-Out"
+ };
+
+ fix_volume_caps(codec, dac);
+ if (!spec->vmaster_sw) {
+ err = add_vmaster(codec, dac);
+ if (err < 0)
+ return err;
+ }
+
+ index = 0;
+ switch (type) {
+ case AUTO_PIN_HP_OUT:
+ name = "Headphone";
+ index = idx;
+ break;
+ case AUTO_PIN_SPEAKER_OUT:
+ if (num_ctls > 1)
+ name = speakers[idx];
+ else
+ name = "Speaker";
+ break;
+ default:
+ if (num_ctls > 1)
+ name = line_outs[idx];
+ else
+ name = "Line-Out";
+ break;
+ }
+
+ err = add_mute(codec, name, index,
+ HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add_slave(spec->vmaster_sw, kctl);
+ if (err < 0)
+ return err;
+
+ err = add_volume(codec, name, index,
+ HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add_slave(spec->vmaster_vol, kctl);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int build_output(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, err;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]),
+ i, cfg->line_outs, cfg->line_out_type);
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < cfg->hp_outs; i++) {
+ err = add_output(codec, get_dac(codec, cfg->hp_pins[i]),
+ i, cfg->hp_outs, AUTO_PIN_HP_OUT);
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < cfg->speaker_outs; i++) {
+ err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]),
+ i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/*
+ */
+
+static struct snd_kcontrol_new cs_capture_ctls[] = {
+ HDA_BIND_SW("Capture Switch", 0),
+ HDA_BIND_VOL("Capture Volume", 0),
+};
+
+static int change_cur_input(struct hda_codec *codec, unsigned int idx,
+ int force)
+{
+ struct cs_spec *spec = codec->spec;
+
+ if (spec->cur_input == idx && !force)
+ return 0;
+ if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) {
+ /* stream is running, let's swap the current ADC */
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+ spec->cur_adc = spec->adc_nid[idx];
+ snd_hda_codec_setup_stream(codec, spec->cur_adc,
+ spec->cur_adc_stream_tag, 0,
+ spec->cur_adc_format);
+ }
+ snd_hda_codec_write(codec, spec->cur_adc, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ spec->adc_idx[idx]);
+ spec->cur_input = idx;
+ return 1;
+}
+
+static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ unsigned int idx;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = spec->num_inputs;
+ if (uinfo->value.enumerated.item >= spec->num_inputs)
+ uinfo->value.enumerated.item = spec->num_inputs - 1;
+ idx = spec->input_idx[uinfo->value.enumerated.item];
+ strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+ return 0;
+}
+
+static int cs_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input];
+ return 0;
+}
+
+static int cs_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ unsigned int idx = ucontrol->value.enumerated.item[0];
+
+ if (idx >= spec->num_inputs)
+ return -EINVAL;
+ idx = spec->input_idx[idx];
+ return change_cur_input(codec, idx, 0);
+}
+
+static struct snd_kcontrol_new cs_capture_source = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = cs_capture_source_info,
+ .get = cs_capture_source_get,
+ .put = cs_capture_source_put,
+};
+
+static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
+ struct hda_ctl_ops *ops)
+{
+ struct cs_spec *spec = codec->spec;
+ struct hda_bind_ctls *bind;
+ int i, n;
+
+ bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1),
+ GFP_KERNEL);
+ if (!bind)
+ return NULL;
+ bind->ops = ops;
+ n = 0;
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (!spec->adc_nid[i])
+ continue;
+ bind->values[n++] =
+ HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3,
+ spec->adc_idx[i], HDA_INPUT);
+ }
+ return bind;
+}
+
+static int build_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ int i, err;
+
+ if (!spec->num_inputs)
+ return 0;
+
+ /* make bind-capture */
+ spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw);
+ spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
+ for (i = 0; i < 2; i++) {
+ struct snd_kcontrol *kctl;
+ if (!spec->capture_bind[i])
+ return -ENOMEM;
+ kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->private_value = (long)spec->capture_bind[i];
+ err = snd_hda_ctl_add(codec, kctl);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->num_inputs > 1 && !spec->mic_detect) {
+ err = snd_hda_ctl_add(codec,
+ snd_ctl_new1(&cs_capture_source, codec));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ */
+
+static int build_digital_output(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ int err;
+
+ if (!spec->multiout.dig_out_nid)
+ return 0;
+
+ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int build_digital_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ if (spec->dig_in)
+ return snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+ return 0;
+}
+
+/*
+ * auto-mute and auto-mic switching
+ */
+
+static void cs_automute(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int caps, present, hp_present;
+ hda_nid_t nid;
+ int i;
+
+ hp_present = 0;
+ for (i = 0; i < cfg->hp_outs; i++) {
+ nid = cfg->hp_pins[i];
+ caps = snd_hda_query_pin_caps(codec, nid);
+ if (!(caps & AC_PINCAP_PRES_DETECT))
+ continue;
+ if (caps & AC_PINCAP_TRIG_REQ)
+ snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ hp_present |= (present & AC_PINSENSE_PRESENCE) != 0;
+ if (hp_present)
+ break;
+ }
+ for (i = 0; i < cfg->speaker_outs; i++) {
+ nid = cfg->speaker_pins[i];
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ hp_present ? 0 : PIN_OUT);
+ }
+ if (spec->board_config == CS420X_MBP55) {
+ unsigned int gpio = hp_present ? 0x02 : 0x08;
+ snd_hda_codec_write(codec, 0x01, 0,
+ AC_VERB_SET_GPIO_DATA, gpio);
+ }
+}
+
+static void cs_automic(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
+ unsigned int caps, present;
+
+ nid = cfg->input_pins[spec->automic_idx];
+ caps = snd_hda_query_pin_caps(codec, nid);
+ if (caps & AC_PINCAP_TRIG_REQ)
+ snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ if (present & AC_PINSENSE_PRESENCE)
+ change_cur_input(codec, spec->automic_idx, 0);
+ else {
+ unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
+ AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
+ change_cur_input(codec, imic, 0);
+ }
+}
+
+/*
+ */
+
+static void init_output(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ /* mute first */
+ for (i = 0; i < spec->multiout.num_dacs; i++)
+ snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ if (spec->multiout.hp_nid)
+ snd_hda_codec_write(codec, spec->multiout.hp_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
+ if (!spec->multiout.extra_out_nid[i])
+ break;
+ snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ }
+
+ /* set appropriate pin controls */
+ for (i = 0; i < cfg->line_outs; i++)
+ snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ for (i = 0; i < cfg->hp_outs; i++) {
+ hda_nid_t nid = cfg->hp_pins[i];
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ if (!cfg->speaker_outs)
+ continue;
+ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | HP_EVENT);
+ spec->hp_detect = 1;
+ }
+ }
+ for (i = 0; i < cfg->speaker_outs; i++)
+ snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ if (spec->hp_detect)
+ cs_automute(codec);
+}
+
+static void init_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int coef;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ unsigned int ctl;
+ hda_nid_t pin = cfg->input_pins[i];
+ if (!pin || !spec->adc_nid[i])
+ continue;
+ /* set appropriate pin control and mute first */
+ ctl = PIN_IN;
+ if (i <= AUTO_PIN_FRONT_MIC) {
+ unsigned int caps = snd_hda_query_pin_caps(codec, pin);
+ caps >>= AC_PINCAP_VREF_SHIFT;
+ if (caps & AC_PINCAP_VREF_80)
+ ctl = PIN_VREF80;
+ }
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+ snd_hda_codec_write(codec, spec->adc_nid[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_MUTE(spec->adc_idx[i]));
+ if (spec->mic_detect && spec->automic_idx == i)
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | MIC_EVENT);
+ }
+ change_cur_input(codec, spec->cur_input, 1);
+ if (spec->mic_detect)
+ cs_automic(codec);
+
+ coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+ if (is_active_pin(codec, CS_DMIC2_PIN_NID))
+ coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
+ if (is_active_pin(codec, CS_DMIC1_PIN_NID))
+ coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0
+ * No effect if SPDIF_OUT2 is slected in
+ * IDX_SPDIF_CTL.
+ */
+ cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+}
+
+static struct hda_verb cs_coef_init_verbs[] = {
+ {0x11, AC_VERB_SET_PROC_STATE, 1},
+ {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+ {0x11, AC_VERB_SET_PROC_COEF,
+ (0x002a /* DAC1/2/3 SZCMode Soft Ramp */
+ | 0x0040 /* Mute DACs on FIFO error */
+ | 0x1000 /* Enable DACs High Pass Filter */
+ | 0x0400 /* Disable Coefficient Auto increment */
+ )},
+ /* Beep */
+ {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+ {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
+
+ {} /* terminator */
+};
+
+/* SPDIF setup */
+static void init_digital(struct hda_codec *codec)
+{
+ unsigned int coef;
+
+ coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
+ coef |= 0x0008; /* Replace with mute on error */
+ if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID))
+ coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2
+ * SPDIF_OUT2 is shared with GPIO1 and
+ * DMIC_SDA2.
+ */
+ cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef);
+}
+
+static int cs_init(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ snd_hda_sequence_write(codec, cs_coef_init_verbs);
+
+ if (spec->gpio_mask) {
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+ spec->gpio_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+ spec->gpio_dir);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+ }
+
+ init_output(codec);
+ init_input(codec);
+ init_digital(codec);
+ return 0;
+}
+
+static int cs_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = build_output(codec);
+ if (err < 0)
+ return err;
+ err = build_input(codec);
+ if (err < 0)
+ return err;
+ err = build_digital_output(codec);
+ if (err < 0)
+ return err;
+ err = build_digital_input(codec);
+ if (err < 0)
+ return err;
+ return cs_init(codec);
+}
+
+static void cs_free(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ kfree(spec->capture_bind[0]);
+ kfree(spec->capture_bind[1]);
+ kfree(codec->spec);
+}
+
+static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ switch ((res >> 26) & 0x7f) {
+ case HP_EVENT:
+ cs_automute(codec);
+ break;
+ case MIC_EVENT:
+ cs_automic(codec);
+ break;
+ }
+}
+
+static struct hda_codec_ops cs_patch_ops = {
+ .build_controls = cs_build_controls,
+ .build_pcms = cs_build_pcms,
+ .init = cs_init,
+ .free = cs_free,
+ .unsol_event = cs_unsol_event,
+};
+
+static int cs_parse_auto_config(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+
+ err = parse_output(codec);
+ if (err < 0)
+ return err;
+ err = parse_input(codec);
+ if (err < 0)
+ return err;
+ err = parse_digital_output(codec);
+ if (err < 0)
+ return err;
+ err = parse_digital_input(codec);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static const char *cs420x_models[CS420X_MODELS] = {
+ [CS420X_MBP55] = "mbp55",
+ [CS420X_AUTO] = "auto",
+};
+
+
+static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+ {} /* terminator */
+};
+
+struct cs_pincfg {
+ hda_nid_t nid;
+ u32 val;
+};
+
+static struct cs_pincfg mbp55_pincfgs[] = {
+ { 0x09, 0x012b4030 },
+ { 0x0a, 0x90100121 },
+ { 0x0b, 0x90100120 },
+ { 0x0c, 0x400000f0 },
+ { 0x0d, 0x90a00110 },
+ { 0x0e, 0x400000f0 },
+ { 0x0f, 0x400000f0 },
+ { 0x10, 0x014be040 },
+ { 0x12, 0x400000f0 },
+ { 0x15, 0x400000f0 },
+ {} /* terminator */
+};
+
+static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+ [CS420X_MBP55] = mbp55_pincfgs,
+};
+
+static void fix_pincfg(struct hda_codec *codec, int model)
+{
+ const struct cs_pincfg *cfg = cs_pincfgs[model];
+ if (!cfg)
+ return;
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+}
+
+
+static int patch_cs420x(struct hda_codec *codec)
+{
+ struct cs_spec *spec;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+
+ spec->board_config =
+ snd_hda_check_board_config(codec, CS420X_MODELS,
+ cs420x_models, cs420x_cfg_tbl);
+ if (spec->board_config >= 0)
+ fix_pincfg(codec, spec->board_config);
+
+ switch (spec->board_config) {
+ case CS420X_MBP55:
+ /* GPIO1 = headphones */
+ /* GPIO3 = speakers */
+ spec->gpio_mask = 0x0a;
+ spec->gpio_dir = 0x0a;
+ break;
+ }
+
+ err = cs_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ codec->patch_ops = cs_patch_ops;
+
+ return 0;
+
+ error:
+ kfree(codec->spec);
+ codec->spec = NULL;
+ return err;
+}
+
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_cirrus[] = {
+ { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
+ { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
+ {} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:10134206");
+MODULE_ALIAS("snd-hda-codec-id:10134207");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
+
+static struct hda_codec_preset_list cirrus_list = {
+ .preset = snd_hda_preset_cirrus,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_cirrus_init(void)
+{
+ return snd_hda_add_codec_preset(&cirrus_list);
+}
+
+static void __exit patch_cirrus_exit(void)
+{
+ snd_hda_delete_codec_preset(&cirrus_list);
+}
+
+module_init(patch_cirrus_init)
+module_exit(patch_cirrus_exit)
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index c921264bbd71..780e1a72114a 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec)
cmi9880_models,
cmi9880_cfg_tbl);
if (spec->board_config < 0) {
- snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
spec->board_config = CMI_AUTO; /* try everything */
}
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ac868c59f9e3..9d899eda44d7 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -108,6 +108,8 @@ struct conexant_spec {
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+ unsigned int dell_automute;
+ unsigned int port_d_mode;
};
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -1908,6 +1910,480 @@ static int patch_cxt5051(struct hda_codec *codec)
return 0;
}
+/* Conexant 5066 specific */
+
+static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
+static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
+#define CXT5066_SPDIF_OUT 0x21
+
+static struct hda_channel_mode cxt5066_modes[1] = {
+ { 2, NULL },
+};
+
+static void cxt5066_update_speaker(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int pinctl;
+
+ snd_printdd("CXT5066: update speaker, hp_present=%d\n",
+ spec->hp_present);
+
+ /* Port A (HP) */
+ pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl);
+
+ /* Port D (HP/LO) */
+ pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
+ ? spec->port_d_mode : 0;
+ snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl);
+
+ /* CLASS_D AMP */
+ pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
+ snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl);
+
+ if (spec->dell_automute) {
+ /* DELL AIO Port Rule: PortA > PortD > IntSpk */
+ pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
+ ? PIN_OUT : 0;
+ snd_hda_codec_write(codec, 0x1c, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+ }
+}
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (!cxt_eapd_put(kcontrol, ucontrol))
+ return 0;
+
+ cxt5066_update_speaker(codec);
+ return 1;
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5066_automic(struct hda_codec *codec)
+{
+ static struct hda_verb ext_mic_present[] = {
+ /* enable external mic, port B */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+ /* switch to external mic input */
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* disable internal mic, port C */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+ {}
+ };
+ static struct hda_verb ext_mic_absent[] = {
+ /* enable internal mic, port C */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+ /* switch to internal mic input */
+ {0x17, AC_VERB_SET_CONNECT_SEL, 1},
+
+ /* disable external mic, port B */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+ {}
+ };
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x1a, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ if (present) {
+ snd_printdd("CXT5066: external microphone detected\n");
+ snd_hda_sequence_write(codec, ext_mic_present);
+ } else {
+ snd_printdd("CXT5066: external microphone absent\n");
+ snd_hda_sequence_write(codec, ext_mic_absent);
+ }
+}
+
+/* mute internal speaker if HP is plugged */
+static void cxt5066_hp_automute(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int portA, portD;
+
+ /* Port A */
+ portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+
+ /* Port D */
+ portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE) << 1;
+
+ spec->hp_present = !!(portA | portD);
+ snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
+ portA, portD, spec->hp_present);
+ cxt5066_update_speaker(codec);
+}
+
+/* unsolicited event for jack sensing */
+static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
+ switch (res >> 26) {
+ case CONEXANT_HP_EVENT:
+ cxt5066_hp_automute(codec);
+ break;
+ case CONEXANT_MIC_EVENT:
+ cxt5066_automic(codec);
+ break;
+ }
+}
+
+static const struct hda_input_mux cxt5066_analog_mic_boost = {
+ .num_items = 5,
+ .items = {
+ { "0dB", 0 },
+ { "10dB", 1 },
+ { "20dB", 2 },
+ { "30dB", 3 },
+ { "40dB", 4 },
+ },
+};
+
+static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo);
+}
+
+static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ int val;
+
+ val = snd_hda_codec_read(codec, 0x17, 0,
+ AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT);
+
+ ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN;
+ return 0;
+}
+
+static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
+ unsigned int idx;
+
+ if (!imux->num_items)
+ return 0;
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+
+ snd_hda_codec_write_cache(codec, 0x17, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
+ imux->items[idx].index);
+
+ return 1;
+}
+
+static struct hda_input_mux cxt5066_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic B", 0 },
+ { "Mic C", 1 },
+ { "Mic E", 2 },
+ { "Mic F", 3 },
+ },
+};
+
+static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
+ .ops = &snd_hda_bind_vol,
+ .values = {
+ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
+ 0
+ },
+};
+
+static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
+ .ops = &snd_hda_bind_sw,
+ .values = {
+ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
+ 0
+ },
+};
+
+static struct snd_kcontrol_new cxt5066_mixer_master[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+ {}
+};
+
+static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = snd_hda_mixer_amp_volume_put,
+ .tlv = { .c = snd_hda_mixer_amp_tlv },
+ /* offset by 28 volume steps to limit minimum gain to -46dB */
+ .private_value =
+ HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
+ },
+ {}
+};
+
+static struct snd_kcontrol_new cxt5066_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = cxt_eapd_info,
+ .get = cxt_eapd_get,
+ .put = cxt5066_hp_master_sw_put,
+ .private_value = 0x1d,
+ },
+
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Mic Boost Capture Enum",
+ .info = cxt5066_mic_boost_mux_enum_info,
+ .get = cxt5066_mic_boost_mux_enum_get,
+ .put = cxt5066_mic_boost_mux_enum_put,
+ },
+
+ HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
+ HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others),
+ {}
+};
+
+static struct hda_verb cxt5066_init_verbs[] = {
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
+ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
+
+ /* Speakers */
+ {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+ /* HP, Amp */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+ /* DAC1 */
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+ /* no digital microphone support yet */
+ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+ /* Audio input selector */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
+
+ /* SPDIF route: PCM */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
+ {0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ /* EAPD */
+ {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+ /* not handling these yet */
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+ { } /* end */
+};
+
+static struct hda_verb cxt5066_init_verbs_olpc[] = {
+ /* Port A: headphones */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+ /* Port B: external microphone */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+ /* Port C: internal microphone */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+ /* Port D: unused */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+ /* Port E: unused, but has primary EAPD */
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+ {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+ /* Port F: unused */
+ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+ /* Port G: internal speakers */
+ {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+ /* DAC1 */
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* DAC2: unused */
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {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)},
+
+ /* Disable digital microphone port */
+ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+ /* Audio input selectors */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+
+ /* Disable SPDIF */
+ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+ {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+ /* enable unsolicited events for Port A and B */
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+ { } /* end */
+};
+
+static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ { } /* end */
+};
+
+/* initialize jack-sensing, too */
+static int cxt5066_init(struct hda_codec *codec)
+{
+ snd_printdd("CXT5066: init\n");
+ conexant_init(codec);
+ if (codec->patch_ops.unsol_event) {
+ cxt5066_hp_automute(codec);
+ cxt5066_automic(codec);
+ }
+ return 0;
+}
+
+enum {
+ CXT5066_LAPTOP, /* Laptops w/ EAPD support */
+ CXT5066_DELL_LAPTOP, /* Dell Laptop */
+ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
+ CXT5066_MODELS
+};
+
+static const char *cxt5066_models[CXT5066_MODELS] = {
+ [CXT5066_LAPTOP] = "laptop",
+ [CXT5066_DELL_LAPTOP] = "dell-laptop",
+ [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
+};
+
+static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+ CXT5066_LAPTOP),
+ SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
+ CXT5066_DELL_LAPTOP),
+ {}
+};
+
+static int patch_cxt5066(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+
+ codec->patch_ops = conexant_patch_ops;
+ codec->patch_ops.init = cxt5066_init;
+
+ spec->dell_automute = 0;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
+ spec->multiout.dac_nids = cxt5066_dac_nids;
+ spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT;
+ spec->num_adc_nids = 1;
+ spec->adc_nids = cxt5066_adc_nids;
+ spec->capsrc_nids = cxt5066_capsrc_nids;
+ spec->input_mux = &cxt5066_capture_source;
+
+ spec->port_d_mode = PIN_HP;
+
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = cxt5066_init_verbs;
+ spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes);
+ spec->channel_mode = cxt5066_modes;
+ spec->cur_adc = 0;
+ spec->cur_adc_idx = 0;
+
+ board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
+ cxt5066_models, cxt5066_cfg_tbl);
+ switch (board_config) {
+ default:
+ case CXT5066_LAPTOP:
+ spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+ spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+ break;
+ case CXT5066_DELL_LAPTOP:
+ spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+ spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+
+ spec->port_d_mode = PIN_OUT;
+ spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo;
+ spec->num_init_verbs++;
+ spec->dell_automute = 1;
+ break;
+ case CXT5066_OLPC_XO_1_5:
+ codec->patch_ops.unsol_event = cxt5066_unsol_event;
+ spec->init_verbs[0] = cxt5066_init_verbs_olpc;
+ spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+ spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+ spec->port_d_mode = 0;
+
+ /* no S/PDIF out */
+ spec->multiout.dig_out_nid = 0;
+
+ /* input source automatically selected */
+ spec->input_mux = NULL;
+ break;
+ }
+
+ return 0;
+}
/*
*/
@@ -1919,12 +2395,15 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_cxt5047 },
{ .id = 0x14f15051, .name = "CX20561 (Hermosa)",
.patch = patch_cxt5051 },
+ { .id = 0x14f15066, .name = "CX20582 (Pebble)",
+ .patch = patch_cxt5066 },
{} /* terminator */
};
MODULE_ALIAS("snd-hda-codec-id:14f15045");
MODULE_ALIAS("snd-hda-codec-id:14f15047");
MODULE_ALIAS("snd-hda-codec-id:14f15051");
+MODULE_ALIAS("snd-hda-codec-id:14f15066");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
index fcc77fec4487..032850eba369 100644
--- a/sound/pci/hda/patch_intelhdmi.c
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -685,6 +685,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
{ .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
+ { .id = 0x80860054, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */
};
@@ -694,6 +695,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801");
MODULE_ALIAS("snd-hda-codec-id:80862802");
MODULE_ALIAS("snd-hda-codec-id:80862803");
MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80860054");
MODULE_ALIAS("snd-hda-codec-id:10951392");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7e99763ca527..afa184451691 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -208,12 +208,6 @@ enum {
ALC885_MBP3,
ALC885_MB5,
ALC885_IMAC24,
- ALC882_AUTO,
- ALC882_MODEL_LAST,
-};
-
-/* ALC883 models */
-enum {
ALC883_3ST_2ch_DIG,
ALC883_3ST_6ch_DIG,
ALC883_3ST_6ch,
@@ -241,13 +235,15 @@ enum {
ALC883_FUJITSU_PI2515,
ALC888_FUJITSU_XA3530,
ALC883_3ST_6ch_INTEL,
+ ALC889A_INTEL,
+ ALC889_INTEL,
ALC888_ASUS_M90V,
ALC888_ASUS_EEE1601,
ALC889A_MB31,
ALC1200_ASUS_P5Q,
ALC883_SONY_VAIO_TT,
- ALC883_AUTO,
- ALC883_MODEL_LAST,
+ ALC882_AUTO,
+ ALC882_MODEL_LAST,
};
/* for GPIO Poll */
@@ -275,13 +271,13 @@ struct alc_spec {
*/
unsigned int num_init_verbs;
- char stream_name_analog[16]; /* analog PCM stream */
+ char stream_name_analog[32]; /* analog PCM stream */
struct hda_pcm_stream *stream_analog_playback;
struct hda_pcm_stream *stream_analog_capture;
struct hda_pcm_stream *stream_analog_alt_playback;
struct hda_pcm_stream *stream_analog_alt_capture;
- char stream_name_digital[16]; /* digital PCM stream */
+ char stream_name_digital[32]; /* digital PCM stream */
struct hda_pcm_stream *stream_digital_playback;
struct hda_pcm_stream *stream_digital_capture;
@@ -320,6 +316,8 @@ struct alc_spec {
struct snd_array kctls;
struct hda_input_mux private_imux[3];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+ hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
+ hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
/* hooks */
void (*init_hook)(struct hda_codec *codec);
@@ -417,7 +415,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
imux = &spec->input_mux[mux_idx];
- type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ type = get_wcaps_type(get_wcaps(codec, nid));
if (type == AC_WID_AUD_MIX) {
/* Matrix-mixer style (e.g. ALC882) */
unsigned int *cur_val = &spec->cur_mux[adc_idx];
@@ -1031,6 +1029,16 @@ static void alc888_coef_init(struct hda_codec *codec)
AC_VERB_SET_PROC_COEF, 0x3030);
}
+static void alc889_coef_init(struct hda_codec *codec)
+{
+ unsigned int tmp;
+
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+ tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
+}
+
static void alc_auto_init_amp(struct hda_codec *codec, int type)
{
unsigned int tmp;
@@ -1088,15 +1096,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
case 0x10ec0885:
case 0x10ec0887:
case 0x10ec0889:
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_COEF_INDEX, 7);
- tmp = snd_hda_codec_read(codec, 0x20, 0,
- AC_VERB_GET_PROC_COEF, 0);
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_COEF_INDEX, 7);
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_PROC_COEF,
- tmp | 0x2010);
+ alc889_coef_init(codec);
break;
case 0x10ec0888:
alc888_coef_init(codec);
@@ -1436,6 +1436,25 @@ static void alc_automute_amp_unsol_event(struct hda_codec *codec,
alc_automute_amp(codec);
}
+static void alc889_automute_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->autocfg.hp_pins[0] = 0x15;
+ spec->autocfg.speaker_pins[0] = 0x14;
+ spec->autocfg.speaker_pins[1] = 0x16;
+ spec->autocfg.speaker_pins[2] = 0x17;
+ spec->autocfg.speaker_pins[3] = 0x19;
+ spec->autocfg.speaker_pins[4] = 0x1a;
+ alc_automute_amp(codec);
+}
+
+static void alc889_intel_init_hook(struct hda_codec *codec)
+{
+ alc889_coef_init(codec);
+ alc889_automute_init(codec);
+}
+
static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4505,12 +4524,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
&dig_nid, 1);
if (err < 0)
continue;
- if (dig_nid > 0x7f) {
- printk(KERN_ERR "alc880_auto: invalid dig_nid "
- "connection 0x%x for NID 0x%x\n", dig_nid,
- spec->autocfg.dig_out_pins[i]);
- continue;
- }
if (!i)
spec->multiout.dig_out_nid = dig_nid;
else {
@@ -4590,8 +4603,8 @@ static int patch_alc880(struct hda_codec *codec)
alc880_models,
alc880_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC880_AUTO;
}
@@ -4629,7 +4642,7 @@ static int patch_alc880(struct hda_codec *codec)
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
/* get type */
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ wcap = get_wcaps_type(wcap);
if (wcap != AC_WID_AUD_IN) {
spec->adc_nids = alc880_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
@@ -6234,8 +6247,7 @@ static int patch_alc260(struct hda_codec *codec)
alc260_models,
alc260_cfg_tbl);
if (board_config < 0) {
- snd_printd(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n",
+ snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
codec->chip_name);
board_config = ALC260_AUTO;
}
@@ -6272,7 +6284,7 @@ static int patch_alc260(struct hda_codec *codec)
if (!spec->adc_nids && spec->input_mux) {
/* check whether NID 0x04 is valid */
unsigned int wcap = get_wcaps(codec, 0x04);
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ wcap = get_wcaps_type(wcap);
/* get type */
if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
spec->adc_nids = alc260_adc_nids_alt;
@@ -6301,7 +6313,7 @@ static int patch_alc260(struct hda_codec *codec)
/*
- * ALC882 support
+ * ALC882/883/885/888/889 support
*
* ALC882 is almost identical with ALC880 but has cleaner and more flexible
* configuration. Each pin widget can choose any input DACs and a mixer.
@@ -6313,22 +6325,35 @@ static int patch_alc260(struct hda_codec *codec)
*/
#define ALC882_DIGOUT_NID 0x06
#define ALC882_DIGIN_NID 0x0a
+#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
+#define ALC883_DIGIN_NID ALC882_DIGIN_NID
+#define ALC1200_DIGOUT_NID 0x10
+
static struct hda_channel_mode alc882_ch_modes[1] = {
{ 8, NULL }
};
+/* DACs */
static hda_nid_t alc882_dac_nids[4] = {
/* front, rear, clfe, rear_surr */
0x02, 0x03, 0x04, 0x05
};
+#define alc883_dac_nids alc882_dac_nids
-/* identical with ALC880 */
+/* ADCs */
#define alc882_adc_nids alc880_adc_nids
#define alc882_adc_nids_alt alc880_adc_nids_alt
+#define alc883_adc_nids alc882_adc_nids_alt
+static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
+static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
+#define alc889_adc_nids alc880_adc_nids
static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+#define alc883_capsrc_nids alc882_capsrc_nids_alt
+static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+#define alc889_capsrc_nids alc882_capsrc_nids
/* input MUX */
/* FIXME: should be a matrix-type input source selection */
@@ -6343,6 +6368,17 @@ static struct hda_input_mux alc882_capture_source = {
},
};
+#define alc883_capture_source alc882_capture_source
+
+static struct hda_input_mux alc889_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Front Mic", 0x0 },
+ { "Mic", 0x3 },
+ { "Line", 0x2 },
+ },
+};
+
static struct hda_input_mux mb5_capture_source = {
.num_items = 3,
.items = {
@@ -6352,6 +6388,77 @@ static struct hda_input_mux mb5_capture_source = {
},
};
+static struct hda_input_mux alc883_3stack_6ch_intel = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x1 },
+ { "Front Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+static struct hda_input_mux alc883_lenovo_101e_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x1 },
+ { "Line", 0x2 },
+ },
+};
+
+static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "iMic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ { "Int Mic", 0x1 },
+ },
+};
+
+static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x4 },
+ },
+};
+
+static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ { "Line", 0x2 },
+ },
+};
+
+static struct hda_input_mux alc889A_mb31_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ /* Front Mic (0x01) unused */
+ { "Line", 0x2 },
+ /* Line 2 (0x03) unused */
+ /* CD (0x04) unsused? */
+ },
+};
+
+/*
+ * 2ch mode
+ */
+static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+ { 2, NULL }
+};
+
/*
* 2ch mode
*/
@@ -6364,6 +6471,18 @@ static struct hda_verb alc882_3ST_ch2_init[] = {
};
/*
+ * 4ch mode
+ */
+static struct hda_verb alc882_3ST_ch4_init[] = {
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+/*
* 6ch mode
*/
static struct hda_verb alc882_3ST_ch6_init[] = {
@@ -6376,11 +6495,14 @@ static struct hda_verb alc882_3ST_ch6_init[] = {
{ } /* end */
};
-static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
+static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
{ 2, alc882_3ST_ch2_init },
+ { 4, alc882_3ST_ch4_init },
{ 6, alc882_3ST_ch6_init },
};
+#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
+
/*
* 6ch mode
*/
@@ -6468,6 +6590,189 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
{ 6, alc885_mb5_ch6_init },
};
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_4ST_ch2_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_4ST_ch4_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_4ST_ch6_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc883_4ST_ch8_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+ { 2, alc883_4ST_ch2_init },
+ { 4, alc883_4ST_ch4_init },
+ { 6, alc883_4ST_ch6_init },
+ { 8, alc883_4ST_ch8_init },
+};
+
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+ { 2, alc883_3ST_ch2_intel_init },
+ { 4, alc883_3ST_ch4_intel_init },
+ { 6, alc883_3ST_ch6_intel_init },
+};
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc889_ch2_intel_init[] = {
+ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc889_ch6_intel_init[] = {
+ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc889_ch8_intel_init[] = {
+ { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+ { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+ { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
+ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
+ { 2, alc889_ch2_intel_init },
+ { 6, alc889_ch6_intel_init },
+ { 8, alc889_ch8_intel_init },
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_sixstack_ch6_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc883_sixstack_ch8_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc883_sixstack_modes[2] = {
+ { 6, alc883_sixstack_ch6_init },
+ { 8, alc883_sixstack_ch8_init },
+};
+
+
/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
*/
@@ -6603,7 +6908,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = {
{ } /* end */
};
-static struct hda_verb alc882_init_verbs[] = {
+static struct hda_verb alc882_base_init_verbs[] = {
/* Front mixer: unmute input/output amp left and right (volume = 0) */
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -6621,6 +6926,13 @@ static struct hda_verb alc882_init_verbs[] = {
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* mute analog input loopbacks */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
/* Front Pin: output 0 (0x0c) */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -6655,11 +6967,6 @@ static struct hda_verb alc882_init_verbs[] = {
/* FIXME: use matrix-type input source selection */
/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
/* Input mixer2 */
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
@@ -6670,9 +6977,6 @@ static struct hda_verb alc882_init_verbs[] = {
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* ADC1: mute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
/* ADC2: mute amp left and right */
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -6683,6 +6987,18 @@ static struct hda_verb alc882_init_verbs[] = {
{ }
};
+static struct hda_verb alc882_adc1_init_verbs[] = {
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* ADC1: mute amp left and right */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ { }
+};
+
static struct hda_verb alc882_eapd_verbs[] = {
/* change to EAPD mode */
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -6690,6 +7006,110 @@ static struct hda_verb alc882_eapd_verbs[] = {
{ }
};
+static struct hda_verb alc889_eapd_verbs[] = {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ { }
+};
+
+static struct hda_verb alc_hp15_unsol_verbs[] = {
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {}
+};
+
+static struct hda_verb alc885_init_verbs[] = {
+ /* Front mixer: unmute input/output amp left and right (volume = 0) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Rear mixer */
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* CLFE mixer */
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Side mixer */
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* mute analog input loopbacks */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+ /* Front HP Pin: output 0 (0x0c) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Front Pin: output 0 (0x0c) */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Rear Pin: output 1 (0x0d) */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
+ /* CLFE Pin: output 2 (0x0e) */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+ /* Side Pin: output 3 (0x0f) */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+ /* Mic (rear) pin: input vref at 80% */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+ /* Mixer elements: 0x18, , 0x1a, 0x1b */
+ /* Input mixer1 */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ /* Input mixer3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ /* ADC3: mute amp left and right */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+ { }
+};
+
+static struct hda_verb alc885_init_input_verbs[] = {
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ { }
+};
+
+
+/* Unmute Selector 24h and set the default input to front mic */
+static struct hda_verb alc889_init_input_verbs[] = {
+ {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ { }
+};
+
+
+#define alc883_init_verbs alc882_base_init_verbs
+
/* Mac Pro test */
static struct snd_kcontrol_new alc882_macpro_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -7037,12 +7457,10 @@ static void alc885_imac24_init_hook(struct hda_codec *codec)
/*
* generic initialization of ADC, input mixers and output mixers
*/
-static struct hda_verb alc882_auto_init_verbs[] = {
+static struct hda_verb alc883_auto_init_verbs[] = {
/*
* Unmute ADC0-2 and set the default input to mic-in
*/
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -7083,11 +7501,6 @@ static struct hda_verb alc882_auto_init_verbs[] = {
/* FIXME: use matrix-type input source selection */
/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
/* Input mixer2 */
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
@@ -7102,820 +7515,6 @@ static struct hda_verb alc882_auto_init_verbs[] = {
{ }
};
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc882_loopbacks alc880_loopbacks
-#endif
-
-/* pcm configuration: identical with ALC880 */
-#define alc882_pcm_analog_playback alc880_pcm_analog_playback
-#define alc882_pcm_analog_capture alc880_pcm_analog_capture
-#define alc882_pcm_digital_playback alc880_pcm_digital_playback
-#define alc882_pcm_digital_capture alc880_pcm_digital_capture
-
-/*
- * configuration and preset
- */
-static const char *alc882_models[ALC882_MODEL_LAST] = {
- [ALC882_3ST_DIG] = "3stack-dig",
- [ALC882_6ST_DIG] = "6stack-dig",
- [ALC882_ARIMA] = "arima",
- [ALC882_W2JC] = "w2jc",
- [ALC882_TARGA] = "targa",
- [ALC882_ASUS_A7J] = "asus-a7j",
- [ALC882_ASUS_A7M] = "asus-a7m",
- [ALC885_MACPRO] = "macpro",
- [ALC885_MB5] = "mb5",
- [ALC885_MBP3] = "mbp3",
- [ALC885_IMAC24] = "imac24",
- [ALC882_AUTO] = "auto",
-};
-
-static struct snd_pci_quirk alc882_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
- SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
- SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
- SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
- SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
- SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
- {}
-};
-
-static struct alc_config_preset alc882_presets[] = {
- [ALC882_3ST_DIG] = {
- .mixers = { alc882_base_mixer },
- .init_verbs = { alc882_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_6ST_DIG] = {
- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
- .channel_mode = alc882_sixstack_modes,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_ARIMA] = {
- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
- .channel_mode = alc882_sixstack_modes,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_W2JC] = {
- .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- },
- [ALC885_MBP3] = {
- .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
- .init_verbs = { alc885_mbp3_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_mbp_6ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
- .input_mux = &alc882_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .unsol_event = alc_automute_amp_unsol_event,
- .init_hook = alc885_mbp3_init_hook,
- },
- [ALC885_MB5] = {
- .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
- .init_verbs = { alc885_mb5_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_mb5_6ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
- .input_mux = &mb5_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- },
- [ALC885_MACPRO] = {
- .mixers = { alc882_macpro_mixer },
- .init_verbs = { alc882_macpro_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .input_mux = &alc882_capture_source,
- .init_hook = alc885_macpro_init_hook,
- },
- [ALC885_IMAC24] = {
- .mixers = { alc885_imac24_mixer },
- .init_verbs = { alc885_imac24_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .input_mux = &alc882_capture_source,
- .unsol_event = alc_automute_amp_unsol_event,
- .init_hook = alc885_imac24_init_hook,
- },
- [ALC882_TARGA] = {
- .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs, alc880_gpio3_init_verbs,
- alc882_targa_verbs},
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
- .capsrc_nids = alc882_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
- .channel_mode = alc882_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- .unsol_event = alc882_targa_unsol_event,
- .init_hook = alc882_targa_init_hook,
- },
- [ALC882_ASUS_A7J] = {
- .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
- .capsrc_nids = alc882_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
- .channel_mode = alc882_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_ASUS_A7M] = {
- .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
- alc880_gpio1_init_verbs,
- alc882_asus_a7m_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
-};
-
-
-/*
- * Pin config fixes
- */
-enum {
- PINFIX_ABIT_AW9D_MAX
-};
-
-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
- { 0x15, 0x01080104 }, /* side */
- { 0x16, 0x01011012 }, /* rear */
- { 0x17, 0x01016011 }, /* clfe */
- { }
-};
-
-static const struct alc_pincfg *alc882_pin_fixes[] = {
- [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
-};
-
-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
- SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
- {}
-};
-
-/*
- * BIOS auto configuration
- */
-static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- int dac_idx)
-{
- /* set as output */
- struct alc_spec *spec = codec->spec;
- int idx;
-
- alc_set_pin_output(codec, nid, pin_type);
- if (spec->multiout.dac_nids[dac_idx] == 0x25)
- idx = 4;
- else
- idx = spec->multiout.dac_nids[dac_idx] - 2;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-
-}
-
-static void alc882_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i <= HDA_SIDE; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- if (nid)
- alc882_auto_set_output_and_unmute(codec, nid, pin_type,
- i);
- }
-}
-
-static void alc882_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) /* connect to front */
- /* use dac 0 */
- alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
-}
-
-#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
-#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
-
-static void alc882_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
- if (!nid)
- continue;
- alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
- }
-}
-
-static void alc882_auto_init_input_src(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int c;
-
- for (c = 0; c < spec->num_adc_nids; c++) {
- hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
- hda_nid_t nid = spec->capsrc_nids[c];
- unsigned int mux_idx;
- const struct hda_input_mux *imux;
- int conns, mute, idx, item;
-
- conns = snd_hda_get_connections(codec, nid, conn_list,
- ARRAY_SIZE(conn_list));
- if (conns < 0)
- continue;
- mux_idx = c >= spec->num_mux_defs ? 0 : c;
- imux = &spec->input_mux[mux_idx];
- for (idx = 0; idx < conns; idx++) {
- /* if the current connection is the selected one,
- * unmute it as default - otherwise mute it
- */
- mute = AMP_IN_MUTE(idx);
- for (item = 0; item < imux->num_items; item++) {
- if (imux->items[item].index == idx) {
- if (spec->cur_mux[c] == item)
- mute = AMP_IN_UNMUTE(idx);
- break;
- }
- }
- /* check if we have a selector or mixer
- * we could check for the widget type instead, but
- * just check for Amp-In presence (in case of mixer
- * without amp-in there is something wrong, this
- * function shouldn't be used or capsrc nid is wrong)
- */
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- mute);
- else if (mute != AMP_IN_MUTE(idx))
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- idx);
- }
- }
-}
-
-/* add mic boosts if needed */
-static int alc_auto_add_mic_boost(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int err;
- hda_nid_t nid;
-
- nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Mic Boost",
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- }
- nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Front Mic Boost",
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-/* almost identical with ALC880 parser... */
-static int alc882_parse_auto_config(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int err = alc880_parse_auto_config(codec);
-
- if (err < 0)
- return err;
- else if (!err)
- return 0; /* no config found */
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- /* hack - override the init verbs */
- spec->init_verbs[0] = alc882_auto_init_verbs;
-
- return 1; /* config found */
-}
-
-/* additional initialization for auto-configuration model */
-static void alc882_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc882_auto_init_multi_out(codec);
- alc882_auto_init_hp_out(codec);
- alc882_auto_init_analog_input(codec);
- alc882_auto_init_input_src(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
-}
-
-static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
-
-static int patch_alc882(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err, board_config;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
- board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
- alc882_models,
- alc882_cfg_tbl);
-
- if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
- /* Pick up systems that don't supply PCI SSID */
- switch (codec->subsystem_id) {
- case 0x106b0c00: /* Mac Pro */
- board_config = ALC885_MACPRO;
- break;
- case 0x106b1000: /* iMac 24 */
- case 0x106b2800: /* AppleTV */
- case 0x106b3e00: /* iMac 24 Aluminium */
- board_config = ALC885_IMAC24;
- break;
- case 0x106b00a0: /* MacBookPro3,1 - Another revision */
- case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
- case 0x106b00a4: /* MacbookPro4,1 */
- case 0x106b2c00: /* Macbook Pro rev3 */
- /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
- case 0x106b3800: /* MacbookPro4,1 - latter revision */
- board_config = ALC885_MBP3;
- break;
- case 0x106b3f00: /* Macbook 5,1 */
- case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
- * seems not working, so apparently
- * no perfect solution yet
- */
- board_config = ALC885_MB5;
- break;
- default:
- /* ALC889A is handled better as ALC888-compatible */
- if (codec->revision_id == 0x100101 ||
- codec->revision_id == 0x100103) {
- alc_free(codec);
- return patch_alc883(codec);
- }
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n",
- codec->chip_name);
- board_config = ALC882_AUTO;
- }
- }
-
- alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
-
- if (board_config == ALC882_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc882_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC882_3ST_DIG;
- }
- }
-
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
-
- if (board_config != ALC882_AUTO)
- setup_preset(spec, &alc882_presets[board_config]);
-
- spec->stream_analog_playback = &alc882_pcm_analog_playback;
- spec->stream_analog_capture = &alc882_pcm_analog_capture;
- /* FIXME: setup DAC5 */
- /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
- spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
-
- spec->stream_digital_playback = &alc882_pcm_digital_playback;
- spec->stream_digital_capture = &alc882_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- /* check whether NID 0x07 is valid */
- unsigned int wcap = get_wcaps(codec, 0x07);
- /* get type */
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
- if (wcap != AC_WID_AUD_IN) {
- spec->adc_nids = alc882_adc_nids_alt;
- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
- spec->capsrc_nids = alc882_capsrc_nids_alt;
- } else {
- spec->adc_nids = alc882_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
- spec->capsrc_nids = alc882_capsrc_nids;
- }
- }
- set_capture_mixer(spec);
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
- spec->vmaster_nid = 0x0c;
-
- codec->patch_ops = alc_patch_ops;
- if (board_config == ALC882_AUTO)
- spec->init_hook = alc882_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (!spec->loopback.amplist)
- spec->loopback.amplist = alc882_loopbacks;
-#endif
- codec->proc_widget_hook = print_realtek_coef;
-
- return 0;
-}
-
-/*
- * ALC883 support
- *
- * ALC883 is almost identical with ALC880 but has cleaner and more flexible
- * configuration. Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs. This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-#define ALC883_DIGOUT_NID 0x06
-#define ALC883_DIGIN_NID 0x0a
-
-#define ALC1200_DIGOUT_NID 0x10
-
-static hda_nid_t alc883_dac_nids[4] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x03, 0x04, 0x05
-};
-
-static hda_nid_t alc883_adc_nids[2] = {
- /* ADC1-2 */
- 0x08, 0x09,
-};
-
-static hda_nid_t alc883_adc_nids_alt[1] = {
- /* ADC1 */
- 0x08,
-};
-
-static hda_nid_t alc883_adc_nids_rev[2] = {
- /* ADC2-1 */
- 0x09, 0x08
-};
-
-#define alc889_adc_nids alc880_adc_nids
-
-static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
-
-static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
-
-#define alc889_capsrc_nids alc882_capsrc_nids
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-
-static struct hda_input_mux alc883_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static struct hda_input_mux alc883_3stack_6ch_intel = {
- .num_items = 4,
- .items = {
- { "Mic", 0x1 },
- { "Front Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static struct hda_input_mux alc883_lenovo_101e_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "Line", 0x2 },
- },
-};
-
-static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "iMic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Int Mic", 0x1 },
- },
-};
-
-static struct hda_input_mux alc883_lenovo_sky_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x4 },
- },
-};
-
-static struct hda_input_mux alc883_asus_eee1601_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- },
-};
-
-static struct hda_input_mux alc889A_mb31_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- /* Front Mic (0x01) unused */
- { "Line", 0x2 },
- /* Line 2 (0x03) unused */
- /* CD (0x04) unsused? */
- },
-};
-
-/*
- * 2ch mode
- */
-static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
- { 2, NULL }
-};
-
-/*
- * 2ch mode
- */
-static struct hda_verb alc883_3ST_ch2_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static struct hda_verb alc883_3ST_ch4_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static struct hda_verb alc883_3ST_ch6_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
- { 2, alc883_3ST_ch2_init },
- { 4, alc883_3ST_ch4_init },
- { 6, alc883_3ST_ch6_init },
-};
-
-
-/*
- * 2ch mode
- */
-static struct hda_verb alc883_4ST_ch2_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static struct hda_verb alc883_4ST_ch4_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static struct hda_verb alc883_4ST_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static struct hda_verb alc883_4ST_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
- { 2, alc883_4ST_ch2_init },
- { 4, alc883_4ST_ch4_init },
- { 6, alc883_4ST_ch6_init },
- { 8, alc883_4ST_ch8_init },
-};
-
-
-/*
- * 2ch mode
- */
-static struct hda_verb alc883_3ST_ch2_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static struct hda_verb alc883_3ST_ch4_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static struct hda_verb alc883_3ST_ch6_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
- { 2, alc883_3ST_ch2_intel_init },
- { 4, alc883_3ST_ch4_intel_init },
- { 6, alc883_3ST_ch6_intel_init },
-};
-
-/*
- * 6ch mode
- */
-static struct hda_verb alc883_sixstack_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static struct hda_verb alc883_sixstack_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-static struct hda_channel_mode alc883_sixstack_modes[2] = {
- { 6, alc883_sixstack_ch6_init },
- { 8, alc883_sixstack_ch8_init },
-};
-
/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
static struct hda_verb alc889A_mb31_ch2_init[] = {
{0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
@@ -7966,34 +7565,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = {
{ }
};
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-
-static struct snd_kcontrol_new alc883_base_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
+#define alc883_base_mixer alc882_base_mixer
static struct snd_kcontrol_new alc883_mitac_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -8104,6 +7676,30 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -8344,84 +7940,6 @@ static struct snd_kcontrol_new alc883_chmode_mixer[] = {
{ } /* end */
};
-static struct hda_verb alc883_init_verbs[] = {
- /* ADC1: mute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC2: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* CLFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Side mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- /* mute analog input loopbacks */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* Front Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Rear Pin: output 1 (0x0d) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* CLFE Pin: output 2 (0x0e) */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* Side Pin: output 3 (0x0f) */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line-2 In: Headphone output (output 0 - 0x0c) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- { }
-};
-
/* toggle speaker-output according to the hp-jack state */
static void alc883_mitac_init_hook(struct hda_codec *codec)
{
@@ -8854,69 +8372,6 @@ static void alc883_vaiott_init_hook(struct hda_codec *codec)
alc_automute_amp(codec);
}
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static struct hda_verb alc883_auto_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, 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
- * Note: PASD motherboards uses the Line In 2 as the input for
- * front panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /*
- * Set up output mixers (0x0c - 0x0f)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
- /* Input mixer2 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- { }
-};
-
static struct hda_verb alc888_asus_m90v_verbs[] = {
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -9027,25 +8482,44 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
alc889A_mb31_automute(codec);
}
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc883_loopbacks alc880_loopbacks
+#define alc882_loopbacks alc880_loopbacks
#endif
/* pcm configuration: identical with ALC880 */
-#define alc883_pcm_analog_playback alc880_pcm_analog_playback
-#define alc883_pcm_analog_capture alc880_pcm_analog_capture
-#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
-#define alc883_pcm_digital_playback alc880_pcm_digital_playback
-#define alc883_pcm_digital_capture alc880_pcm_digital_capture
+#define alc882_pcm_analog_playback alc880_pcm_analog_playback
+#define alc882_pcm_analog_capture alc880_pcm_analog_capture
+#define alc882_pcm_digital_playback alc880_pcm_digital_playback
+#define alc882_pcm_digital_capture alc880_pcm_digital_capture
+
+static hda_nid_t alc883_slave_dig_outs[] = {
+ ALC1200_DIGOUT_NID, 0,
+};
+
+static hda_nid_t alc1200_slave_dig_outs[] = {
+ ALC883_DIGOUT_NID, 0,
+};
/*
* configuration and preset
*/
-static const char *alc883_models[ALC883_MODEL_LAST] = {
- [ALC883_3ST_2ch_DIG] = "3stack-dig",
+static const char *alc882_models[ALC882_MODEL_LAST] = {
+ [ALC882_3ST_DIG] = "3stack-dig",
+ [ALC882_6ST_DIG] = "6stack-dig",
+ [ALC882_ARIMA] = "arima",
+ [ALC882_W2JC] = "w2jc",
+ [ALC882_TARGA] = "targa",
+ [ALC882_ASUS_A7J] = "asus-a7j",
+ [ALC882_ASUS_A7M] = "asus-a7m",
+ [ALC885_MACPRO] = "macpro",
+ [ALC885_MB5] = "mb5",
+ [ALC885_MBP3] = "mbp3",
+ [ALC885_IMAC24] = "imac24",
+ [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
[ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
[ALC883_3ST_6ch] = "3stack-6ch",
- [ALC883_6ST_DIG] = "6stack-dig",
+ [ALC883_6ST_DIG] = "alc883-6stack-dig",
[ALC883_TARGA_DIG] = "targa-dig",
[ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
[ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
@@ -9069,14 +8543,17 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
[ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
[ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
+ [ALC889A_INTEL] = "intel-alc889a",
+ [ALC889_INTEL] = "intel-x58",
[ALC1200_ASUS_P5Q] = "asus-p5q",
[ALC889A_MB31] = "mb31",
[ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
- [ALC883_AUTO] = "auto",
+ [ALC882_AUTO] = "auto",
};
-static struct snd_pci_quirk alc883_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+static struct snd_pci_quirk alc882_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+
SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
@@ -9091,8 +8568,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
ALC888_ACER_ASPIRE_8930G),
SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
ALC888_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
- SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
+ SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
+ SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
ALC888_ACER_ASPIRE_6530G),
SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
@@ -9101,30 +8578,44 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
* model=auto should work fine now
*/
/* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
+
SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
+
SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
+
+ SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+ SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
+ SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
+ SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+ SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
+
+ SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
- SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+
SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
@@ -9133,6 +8624,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
@@ -9146,11 +8638,14 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
+
SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
+ /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
ALC883_FUJITSU_PI2515),
@@ -9165,24 +8660,182 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
+
SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
- SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
- SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
- {}
-};
-static hda_nid_t alc883_slave_dig_outs[] = {
- ALC1200_DIGOUT_NID, 0,
+ {}
};
-static hda_nid_t alc1200_slave_dig_outs[] = {
- ALC883_DIGOUT_NID, 0,
+/* codec SSID table for Intel Mac */
+static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
+ SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
+ SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
+ SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
+ SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
+ SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
+ /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently
+ * no perfect solution yet
+ */
+ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
+ {} /* terminator */
};
-static struct alc_config_preset alc883_presets[] = {
+static struct alc_config_preset alc882_presets[] = {
+ [ALC882_3ST_DIG] = {
+ .mixers = { alc882_base_mixer },
+ .init_verbs = { alc882_base_init_verbs,
+ alc882_adc1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ },
+ [ALC882_6ST_DIG] = {
+ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs,
+ alc882_adc1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+ .channel_mode = alc882_sixstack_modes,
+ .input_mux = &alc882_capture_source,
+ },
+ [ALC882_ARIMA] = {
+ .mixers = { alc882_base_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+ alc882_eapd_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
+ .channel_mode = alc882_sixstack_modes,
+ .input_mux = &alc882_capture_source,
+ },
+ [ALC882_W2JC] = {
+ .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+ alc882_eapd_verbs, alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ },
+ [ALC885_MBP3] = {
+ .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc885_mbp3_init_verbs,
+ alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .channel_mode = alc885_mbp_6ch_modes,
+ .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
+ .input_mux = &alc882_capture_source,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .unsol_event = alc_automute_amp_unsol_event,
+ .init_hook = alc885_mbp3_init_hook,
+ },
+ [ALC885_MB5] = {
+ .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc885_mb5_init_verbs,
+ alc880_gpio1_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .channel_mode = alc885_mb5_6ch_modes,
+ .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
+ .input_mux = &mb5_capture_source,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ },
+ [ALC885_MACPRO] = {
+ .mixers = { alc882_macpro_mixer },
+ .init_verbs = { alc882_macpro_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .input_mux = &alc882_capture_source,
+ .init_hook = alc885_macpro_init_hook,
+ },
+ [ALC885_IMAC24] = {
+ .mixers = { alc885_imac24_mixer },
+ .init_verbs = { alc885_imac24_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .input_mux = &alc882_capture_source,
+ .unsol_event = alc_automute_amp_unsol_event,
+ .init_hook = alc885_imac24_init_hook,
+ },
+ [ALC882_TARGA] = {
+ .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+ alc880_gpio3_init_verbs, alc882_targa_verbs},
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+ .adc_nids = alc882_adc_nids,
+ .capsrc_nids = alc882_capsrc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+ .channel_mode = alc882_3ST_6ch_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ .unsol_event = alc882_targa_unsol_event,
+ .init_hook = alc882_targa_init_hook,
+ },
+ [ALC882_ASUS_A7J] = {
+ .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+ alc882_asus_a7j_verbs},
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
+ .adc_nids = alc882_adc_nids,
+ .capsrc_nids = alc882_capsrc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
+ .channel_mode = alc882_3ST_6ch_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ },
+ [ALC882_ASUS_A7M] = {
+ .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
+ .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+ alc882_eapd_verbs, alc880_gpio1_init_verbs,
+ alc882_asus_a7m_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc882_capture_source,
+ },
[ALC883_3ST_2ch_DIG] = {
.mixers = { alc883_3ST_2ch_mixer },
.init_verbs = { alc883_init_verbs },
@@ -9229,6 +8882,44 @@ static struct alc_config_preset alc883_presets[] = {
.need_dac_fix = 1,
.input_mux = &alc883_3stack_6ch_intel,
},
+ [ALC889A_INTEL] = {
+ .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
+ alc_hp15_unsol_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+ .adc_nids = alc889_adc_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .dig_in_nid = ALC883_DIGIN_NID,
+ .slave_dig_outs = alc883_slave_dig_outs,
+ .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+ .channel_mode = alc889_8ch_intel_modes,
+ .capsrc_nids = alc889_capsrc_nids,
+ .input_mux = &alc889_capture_source,
+ .init_hook = alc889_automute_init,
+ .unsol_event = alc_automute_amp_unsol_event,
+ .need_dac_fix = 1,
+ },
+ [ALC889_INTEL] = {
+ .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
+ alc889_eapd_verbs, alc_hp15_unsol_verbs},
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+ .adc_nids = alc889_adc_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .dig_in_nid = ALC883_DIGIN_NID,
+ .slave_dig_outs = alc883_slave_dig_outs,
+ .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+ .channel_mode = alc889_8ch_intel_modes,
+ .capsrc_nids = alc889_capsrc_nids,
+ .input_mux = &alc889_capture_source,
+ .init_hook = alc889_intel_init_hook,
+ .unsol_event = alc_automute_amp_unsol_event,
+ .need_dac_fix = 1,
+ },
[ALC883_6ST_DIG] = {
.mixers = { alc883_base_mixer, alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs },
@@ -9619,9 +9310,32 @@ static struct alc_config_preset alc883_presets[] = {
/*
+ * Pin config fixes
+ */
+enum {
+ PINFIX_ABIT_AW9D_MAX
+};
+
+static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+ { 0x15, 0x01080104 }, /* side */
+ { 0x16, 0x01011012 }, /* rear */
+ { 0x17, 0x01016011 }, /* clfe */
+ { }
+};
+
+static const struct alc_pincfg *alc882_pin_fixes[] = {
+ [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+};
+
+static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+ SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+ {}
+};
+
+/*
* BIOS auto configuration
*/
-static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
+static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid, int pin_type,
int dac_idx)
{
@@ -9638,7 +9352,7 @@ static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
}
-static void alc883_auto_init_multi_out(struct hda_codec *codec)
+static void alc882_auto_init_multi_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
@@ -9647,12 +9361,12 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec)
hda_nid_t nid = spec->autocfg.line_out_pins[i];
int pin_type = get_pin_type(spec->autocfg.line_out_type);
if (nid)
- alc883_auto_set_output_and_unmute(codec, nid, pin_type,
+ alc882_auto_set_output_and_unmute(codec, nid, pin_type,
i);
}
}
-static void alc883_auto_init_hp_out(struct hda_codec *codec)
+static void alc882_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin;
@@ -9660,42 +9374,111 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec)
pin = spec->autocfg.hp_pins[0];
if (pin) /* connect to front */
/* use dac 0 */
- alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
pin = spec->autocfg.speaker_pins[0];
if (pin)
- alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+ alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
}
-#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
-#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
-
-static void alc883_auto_init_analog_input(struct hda_codec *codec)
+static void alc882_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
for (i = 0; i < AUTO_PIN_LAST; i++) {
hda_nid_t nid = spec->autocfg.input_pins[i];
- if (alc883_is_input_pin(nid)) {
- alc_set_input_pin(codec, nid, i);
- if (nid != ALC883_PIN_CD_NID &&
- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+ if (!nid)
+ continue;
+ alc_set_input_pin(codec, nid, i);
+ if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE);
+ }
+}
+
+static void alc882_auto_init_input_src(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int c;
+
+ for (c = 0; c < spec->num_adc_nids; c++) {
+ hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
+ hda_nid_t nid = spec->capsrc_nids[c];
+ unsigned int mux_idx;
+ const struct hda_input_mux *imux;
+ int conns, mute, idx, item;
+
+ conns = snd_hda_get_connections(codec, nid, conn_list,
+ ARRAY_SIZE(conn_list));
+ if (conns < 0)
+ continue;
+ mux_idx = c >= spec->num_mux_defs ? 0 : c;
+ imux = &spec->input_mux[mux_idx];
+ for (idx = 0; idx < conns; idx++) {
+ /* if the current connection is the selected one,
+ * unmute it as default - otherwise mute it
+ */
+ mute = AMP_IN_MUTE(idx);
+ for (item = 0; item < imux->num_items; item++) {
+ if (imux->items[item].index == idx) {
+ if (spec->cur_mux[c] == item)
+ mute = AMP_IN_UNMUTE(idx);
+ break;
+ }
+ }
+ /* check if we have a selector or mixer
+ * we could check for the widget type instead, but
+ * just check for Amp-In presence (in case of mixer
+ * without amp-in there is something wrong, this
+ * function shouldn't be used or capsrc nid is wrong)
+ */
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
+ mute);
+ else if (mute != AMP_IN_MUTE(idx))
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ idx);
}
}
}
-#define alc883_auto_init_input_src alc882_auto_init_input_src
+/* add mic boosts if needed */
+static int alc_auto_add_mic_boost(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ hda_nid_t nid;
+
+ nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
+ if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+ err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "Mic Boost",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ }
+ nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
+ if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
+ err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "Front Mic Boost",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
/* almost identical with ALC880 parser... */
-static int alc883_parse_auto_config(struct hda_codec *codec)
+static int alc882_parse_auto_config(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- int err = alc880_parse_auto_config(codec);
- struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct auto_pin_cfg *autocfg = &spec->autocfg;
+ unsigned int wcap;
int i;
+ int err = alc880_parse_auto_config(codec);
if (err < 0)
return err;
@@ -9708,43 +9491,45 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
/* hack - override the init verbs */
spec->init_verbs[0] = alc883_auto_init_verbs;
+ /* if ADC 0x07 is available, initialize it, too */
+ wcap = get_wcaps(codec, 0x07);
+ wcap = get_wcaps_type(wcap);
+ if (wcap == AC_WID_AUD_IN)
+ add_verb(spec, alc882_adc1_init_verbs);
- /* setup input_mux for ALC889 */
- if (codec->vendor_id == 0x10ec0889) {
- /* digital-mic input pin is excluded in alc880_auto_create..()
- * because it's under 0x18
- */
- if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
- cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
- struct hda_input_mux *imux = &spec->private_imux[0];
- for (i = 1; i < 3; i++)
- memcpy(&spec->private_imux[i],
- &spec->private_imux[0],
- sizeof(spec->private_imux[0]));
- imux->items[imux->num_items].label = "Int DMic";
- imux->items[imux->num_items].index = 0x0b;
- imux->num_items++;
- spec->num_mux_defs = 3;
- spec->input_mux = spec->private_imux;
- }
+ /* digital-mic input pin is excluded in alc880_auto_create..()
+ * because it's under 0x18
+ */
+ if (autocfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+ autocfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+ struct hda_input_mux *imux = &spec->private_imux[0];
+ for (i = 1; i < 3; i++)
+ memcpy(&spec->private_imux[i],
+ &spec->private_imux[0],
+ sizeof(spec->private_imux[0]));
+ imux->items[imux->num_items].label = "Int DMic";
+ imux->items[imux->num_items].index = 0x0b;
+ imux->num_items++;
+ spec->num_mux_defs = 3;
+ spec->input_mux = spec->private_imux;
}
return 1; /* config found */
}
/* additional initialization for auto-configuration model */
-static void alc883_auto_init(struct hda_codec *codec)
+static void alc882_auto_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- alc883_auto_init_multi_out(codec);
- alc883_auto_init_hp_out(codec);
- alc883_auto_init_analog_input(codec);
- alc883_auto_init_input_src(codec);
+ alc882_auto_init_multi_out(codec);
+ alc882_auto_init_hp_out(codec);
+ alc882_auto_init_analog_input(codec);
+ alc882_auto_init_input_src(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
-static int patch_alc883(struct hda_codec *codec)
+static int patch_alc882(struct hda_codec *codec)
{
struct alc_spec *spec;
int err, board_config;
@@ -9755,28 +9540,35 @@ static int patch_alc883(struct hda_codec *codec)
codec->spec = spec;
- alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+ switch (codec->vendor_id) {
+ case 0x10ec0882:
+ case 0x10ec0885:
+ break;
+ default:
+ /* ALC883 and variants */
+ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+ break;
+ }
- board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
- alc883_models,
- alc883_cfg_tbl);
- if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
- /* Pick up systems that don't supply PCI SSID */
- switch (codec->subsystem_id) {
- case 0x106b3600: /* Macbook 3.1 */
- board_config = ALC889A_MB31;
- break;
- default:
- printk(KERN_INFO
- "hda_codec: Unknown model for %s, trying "
- "auto-probe from BIOS...\n", codec->chip_name);
- board_config = ALC883_AUTO;
- }
+ board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+ alc882_models,
+ alc882_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
+ board_config = snd_hda_check_board_codec_sid_config(codec,
+ ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
+ board_config = ALC882_AUTO;
}
- if (board_config == ALC883_AUTO) {
+ alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+
+ if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
- err = alc883_parse_auto_config(codec);
+ err = alc882_parse_auto_config(codec);
if (err < 0) {
alc_free(codec);
return err;
@@ -9784,7 +9576,7 @@ static int patch_alc883(struct hda_codec *codec)
printk(KERN_INFO
"hda_codec: Cannot set up configuration "
"from BIOS. Using base mode...\n");
- board_config = ALC883_3ST_2ch_DIG;
+ board_config = ALC882_3ST_DIG;
}
}
@@ -9794,63 +9586,61 @@ static int patch_alc883(struct hda_codec *codec)
return err;
}
- if (board_config != ALC883_AUTO)
- setup_preset(spec, &alc883_presets[board_config]);
+ if (board_config != ALC882_AUTO)
+ setup_preset(spec, &alc882_presets[board_config]);
- switch (codec->vendor_id) {
- case 0x10ec0888:
- if (!spec->num_adc_nids) {
- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
- spec->adc_nids = alc883_adc_nids;
- }
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc883_capsrc_nids;
+ spec->stream_analog_playback = &alc882_pcm_analog_playback;
+ spec->stream_analog_capture = &alc882_pcm_analog_capture;
+ /* FIXME: setup DAC5 */
+ /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+ spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
+
+ spec->stream_digital_playback = &alc882_pcm_digital_playback;
+ spec->stream_digital_capture = &alc882_pcm_digital_capture;
+
+ if (codec->vendor_id == 0x10ec0888)
spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
- break;
- case 0x10ec0889:
- if (!spec->num_adc_nids) {
- spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
- spec->adc_nids = alc889_adc_nids;
- }
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc889_capsrc_nids;
- break;
- default:
- if (!spec->num_adc_nids) {
- spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
- spec->adc_nids = alc883_adc_nids;
+
+ if (!spec->adc_nids && spec->input_mux) {
+ int i;
+ spec->num_adc_nids = 0;
+ for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
+ hda_nid_t cap;
+ hda_nid_t nid = alc882_adc_nids[i];
+ unsigned int wcap = get_wcaps(codec, nid);
+ /* get type */
+ wcap = get_wcaps_type(wcap);
+ if (wcap != AC_WID_AUD_IN)
+ continue;
+ spec->private_adc_nids[spec->num_adc_nids] = nid;
+ err = snd_hda_get_connections(codec, nid, &cap, 1);
+ if (err < 0)
+ continue;
+ spec->private_capsrc_nids[spec->num_adc_nids] = cap;
+ spec->num_adc_nids++;
}
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc883_capsrc_nids;
- break;
+ spec->adc_nids = spec->private_adc_nids;
+ spec->capsrc_nids = spec->private_capsrc_nids;
}
- spec->stream_analog_playback = &alc883_pcm_analog_playback;
- spec->stream_analog_capture = &alc883_pcm_analog_capture;
- spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
-
- spec->stream_digital_playback = &alc883_pcm_digital_playback;
- spec->stream_digital_capture = &alc883_pcm_digital_capture;
-
- if (!spec->cap_mixer)
- set_capture_mixer(spec);
+ set_capture_mixer(spec);
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
spec->vmaster_nid = 0x0c;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC883_AUTO)
- spec->init_hook = alc883_auto_init;
-
+ if (board_config == ALC882_AUTO)
+ spec->init_hook = alc882_auto_init;
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
- spec->loopback.amplist = alc883_loopbacks;
+ spec->loopback.amplist = alc882_loopbacks;
#endif
codec->proc_widget_hook = print_realtek_coef;
return 0;
}
+
/*
* ALC262 support
*/
@@ -10359,12 +10149,6 @@ static struct hda_verb alc262_eapd_verbs[] = {
{ }
};
-static struct hda_verb alc262_hippo_unsol_verbs[] = {
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
static struct hda_verb alc262_hippo1_unsol_verbs[] = {
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -10631,6 +10415,18 @@ static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
alc262_lenovo_3000_automute(codec, 1);
}
+static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
+ int dir, int idx, long *valp)
+{
+ int i, change = 0;
+
+ for (i = 0; i < 2; i++, valp++)
+ change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
+ HDA_AMP_MUTE,
+ *valp ? 0 : HDA_AMP_MUTE);
+ return change;
+}
+
/* bind hp and internal speaker mute (with plug check) */
static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -10639,13 +10435,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
long *valp = ucontrol->value.integer.value;
int change;
- change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
- HDA_AMP_MUTE,
- valp ? 0 : HDA_AMP_MUTE);
- change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
- HDA_AMP_MUTE,
- valp ? 0 : HDA_AMP_MUTE);
-
+ change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
+ change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
if (change)
alc262_fujitsu_automute(codec, 0);
return change;
@@ -10680,10 +10471,7 @@ static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
long *valp = ucontrol->value.integer.value;
int change;
- change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
- HDA_AMP_MUTE,
- valp ? 0 : HDA_AMP_MUTE);
-
+ change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
if (change)
alc262_lenovo_3000_automute(codec, 0);
return change;
@@ -11402,7 +11190,7 @@ static struct alc_config_preset alc262_presets[] = {
},
[ALC262_HIPPO] = {
.mixers = { alc262_hippo_mixer },
- .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
+ .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
.num_dacs = ARRAY_SIZE(alc262_dac_nids),
.dac_nids = alc262_dac_nids,
.hp_nid = 0x03,
@@ -11522,7 +11310,8 @@ static struct alc_config_preset alc262_presets[] = {
},
[ALC262_BENQ_T31] = {
.mixers = { alc262_benq_t31_mixer },
- .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+ .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
+ alc_hp15_unsol_verbs },
.num_dacs = ARRAY_SIZE(alc262_dac_nids),
.dac_nids = alc262_dac_nids,
.hp_nid = 0x03,
@@ -11644,8 +11433,8 @@ static int patch_alc262(struct hda_codec *codec)
alc262_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC262_AUTO;
}
@@ -11698,7 +11487,7 @@ static int patch_alc262(struct hda_codec *codec)
unsigned int wcap = get_wcaps(codec, 0x07);
/* get type */
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ wcap = get_wcaps_type(wcap);
if (wcap != AC_WID_AUD_IN) {
spec->adc_nids = alc262_adc_nids_alt;
spec->num_adc_nids =
@@ -11854,12 +11643,7 @@ static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
long *valp = ucontrol->value.integer.value;
int change;
- change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
- HDA_AMP_MUTE,
- valp[0] ? 0 : HDA_AMP_MUTE);
- change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
- HDA_AMP_MUTE,
- valp[1] ? 0 : HDA_AMP_MUTE);
+ change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
if (change)
alc268_acer_automute(codec, 0);
return change;
@@ -12270,26 +12054,38 @@ 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);
- if (nid == 0x14) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (nid == 0x15) {
+ switch (nid) {
+ case 0x14:
+ case 0x16:
+ dac = 0x02;
+ break;
+ case 0x15:
+ dac = 0x03;
+ break;
+ default:
+ return 0;
+ }
+ if (spec->multiout.dac_nids[0] != dac &&
+ spec->multiout.dac_nids[1] != dac) {
err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+ HDA_COMPOSE_AMP_VAL(dac, 3, idx,
HDA_OUTPUT));
if (err < 0)
return err;
- } else
- return -1;
+ spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+ }
+
sprintf(name, "%s Playback Switch", ctlname);
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ if (nid != 0x16)
+ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+ else /* mono */
+ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
if (err < 0)
return err;
return 0;
@@ -12302,14 +12098,19 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
hda_nid_t nid;
int err;
- spec->multiout.num_dacs = 2; /* only use one dac */
spec->multiout.dac_nids = spec->private_dac_nids;
- spec->multiout.dac_nids[0] = 2;
- spec->multiout.dac_nids[1] = 3;
nid = cfg->line_out_pins[0];
- if (nid)
- alc268_new_analog_output(spec, nid, "Front", 0);
+ if (nid) {
+ const char *name;
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+ name = "Speaker";
+ else
+ name = "Front";
+ err = alc268_new_analog_output(spec, nid, name, 0);
+ if (err < 0)
+ return err;
+ }
nid = cfg->speaker_pins[0];
if (nid == 0x1d) {
@@ -12318,16 +12119,23 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
if (err < 0)
return err;
+ } else {
+ err = alc268_new_analog_output(spec, nid, "Speaker", 0);
+ if (err < 0)
+ return err;
}
nid = cfg->hp_pins[0];
- if (nid)
- alc268_new_analog_output(spec, nid, "Headphone", 0);
+ if (nid) {
+ err = alc268_new_analog_output(spec, nid, "Headphone", 0);
+ if (err < 0)
+ return err;
+ }
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",
- HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
if (err < 0)
return err;
}
@@ -12698,8 +12506,8 @@ static int patch_alc268(struct hda_codec *codec)
alc268_cfg_tbl);
if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC268_AUTO;
}
@@ -12755,7 +12563,7 @@ static int patch_alc268(struct hda_codec *codec)
int i;
/* get type */
- wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ wcap = get_wcaps_type(wcap);
if (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);
@@ -13516,8 +13324,8 @@ static int patch_alc269(struct hda_codec *codec)
alc269_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC269_AUTO;
}
@@ -14109,23 +13917,23 @@ static struct hda_verb alc861_auto_init_verbs[] = {
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, 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(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
@@ -14197,64 +14005,96 @@ static struct hda_input_mux alc861_capture_source = {
},
};
+static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t mix, srcs[5];
+ int i, j, num;
+
+ if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
+ return 0;
+ num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
+ if (num < 0)
+ return 0;
+ for (i = 0; i < num; i++) {
+ unsigned int type;
+ type = get_wcaps_type(get_wcaps(codec, srcs[i]));
+ if (type != AC_WID_AUD_OUT)
+ continue;
+ for (j = 0; j < spec->multiout.num_dacs; j++)
+ if (spec->multiout.dac_nids[j] == srcs[i])
+ break;
+ if (j >= spec->multiout.num_dacs)
+ return srcs[i];
+ }
+ return 0;
+}
+
/* fill in the dac_nids table from the parsed pin configuration */
-static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
+static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
+ struct alc_spec *spec = codec->spec;
int i;
- hda_nid_t nid;
+ hda_nid_t nid, dac;
spec->multiout.dac_nids = spec->private_dac_nids;
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
- if (nid) {
- if (i >= ARRAY_SIZE(alc861_dac_nids))
- continue;
- spec->multiout.dac_nids[i] = alc861_dac_nids[i];
- }
+ dac = alc861_look_for_dac(codec, nid);
+ if (!dac)
+ continue;
+ spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
}
- spec->multiout.num_dacs = cfg->line_outs;
return 0;
}
+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,
+ HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+
/* add playback controls from the parsed DAC table */
-static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
+static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- char name[32];
+ struct alc_spec *spec = codec->spec;
static const char *chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
hda_nid_t nid;
- int i, idx, err;
+ int i, err;
+
+ if (cfg->line_outs == 1) {
+ const char *pfx = NULL;
+ if (!cfg->hp_outs)
+ pfx = "Master";
+ else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+ pfx = "Speaker";
+ if (pfx) {
+ nid = spec->multiout.dac_nids[0];
+ return alc861_create_out_sw(codec, pfx, nid, 3);
+ }
+ }
for (i = 0; i < cfg->line_outs; i++) {
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
- if (nid == 0x05) {
+ if (i == 2) {
/* Center/LFE */
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0,
- HDA_OUTPUT));
+ err = alc861_create_out_sw(codec, "Center", nid, 1);
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid, 2, 0,
- HDA_OUTPUT));
+ err = alc861_create_out_sw(codec, "LFE", nid, 2);
if (err < 0)
return err;
} else {
- for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
- idx++)
- if (nid == alc861_dac_nids[idx])
- break;
- sprintf(name, "%s Playback Switch", chname[idx]);
- err = add_control(spec, ALC_CTL_BIND_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
+ err = alc861_create_out_sw(codec, chname[i], nid, 3);
if (err < 0)
return err;
}
@@ -14262,8 +14102,9 @@ static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
return 0;
}
-static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
+static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
{
+ struct alc_spec *spec = codec->spec;
int err;
hda_nid_t nid;
@@ -14271,21 +14112,22 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
return 0;
if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
- nid = 0x03;
- err = add_control(spec, ALC_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- spec->multiout.hp_nid = nid;
+ nid = alc861_look_for_dac(codec, pin);
+ if (nid) {
+ err = alc861_create_out_sw(codec, "Headphone", nid, 3);
+ if (err < 0)
+ return err;
+ spec->multiout.hp_nid = nid;
+ }
}
return 0;
}
/* create playback/capture controls for input pins */
-static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
+ struct alc_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
int i, err, idx, idx1;
@@ -14329,12 +14171,29 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid,
- int pin_type, int dac_idx)
+ int pin_type, hda_nid_t dac)
{
+ hda_nid_t mix, srcs[5];
+ int i, num;
+
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_type);
- snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
+ if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
+ return;
+ num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
+ if (num < 0)
+ return;
+ for (i = 0; i < num; i++) {
+ unsigned int mute;
+ if (srcs[i] == dac || srcs[i] == 0x15)
+ mute = AMP_IN_UNMUTE(i);
+ else
+ mute = AMP_IN_MUTE(i);
+ snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ mute);
+ }
}
static void alc861_auto_init_multi_out(struct hda_codec *codec)
@@ -14357,12 +14216,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
hda_nid_t pin;
pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
+ if (pin)
alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
- spec->multiout.dac_nids[0]);
+ spec->multiout.hp_nid);
pin = spec->autocfg.speaker_pins[0];
if (pin)
- alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+ alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+ spec->multiout.dac_nids[0]);
}
static void alc861_auto_init_analog_input(struct hda_codec *codec)
@@ -14394,16 +14254,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if (!spec->autocfg.line_outs)
return 0; /* can't find valid BIOS pin config */
- err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
+ err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
if (err < 0)
return err;
- err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
- err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -14615,8 +14475,8 @@ static int patch_alc861(struct hda_codec *codec)
alc861_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC861_AUTO;
}
@@ -15539,8 +15399,8 @@ static int patch_alc861vd(struct hda_codec *codec)
alc861vd_cfg_tbl);
if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC861VD_AUTO;
}
@@ -17463,8 +17323,8 @@ static int patch_alc662(struct hda_codec *codec)
alc662_models,
alc662_cfg_tbl);
if (board_config < 0) {
- printk(KERN_INFO "hda_codec: Unknown model for %s, "
- "trying auto-probe from BIOS...\n", codec->chip_name);
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
board_config = ALC662_AUTO;
}
@@ -17538,23 +17398,23 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
{ .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
{ .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
- .patch = patch_alc883 },
+ .patch = patch_alc882 },
{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
.patch = patch_alc662 },
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
- { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
+ { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
{ .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
- .patch = patch_alc882 }, /* should be patch_alc883() in future */
+ .patch = patch_alc882 },
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
- .patch = patch_alc882 }, /* should be patch_alc883() in future */
+ .patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
+ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
- .patch = patch_alc883 },
- { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
- { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
+ .patch = patch_alc882 },
+ { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
+ { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index da7f9f65c047..556328310572 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -40,6 +40,8 @@ enum {
STAC_INSERT_EVENT,
STAC_PWR_EVENT,
STAC_HP_EVENT,
+ STAC_LO_EVENT,
+ STAC_MIC_EVENT,
};
enum {
@@ -176,6 +178,12 @@ struct sigmatel_jack {
struct snd_jack *jack;
};
+struct sigmatel_mic_route {
+ hda_nid_t pin;
+ unsigned char mux_idx;
+ unsigned char dmux_idx;
+};
+
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
@@ -187,6 +195,7 @@ struct sigmatel_spec {
unsigned int hp_detect: 1;
unsigned int spdif_mute: 1;
unsigned int check_volume_offset:1;
+ unsigned int auto_mic:1;
/* gpio lines */
unsigned int eapd_mask;
@@ -238,6 +247,15 @@ struct sigmatel_spec {
unsigned int num_dmuxes;
hda_nid_t *smux_nids;
unsigned int num_smuxes;
+ unsigned int num_analog_muxes;
+
+ unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
+ unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
+ unsigned int num_caps; /* number of capture volume/switch elements */
+
+ struct sigmatel_mic_route ext_mic;
+ struct sigmatel_mic_route int_mic;
+
const char **spdif_labels;
hda_nid_t dig_in_nid;
@@ -334,6 +352,13 @@ static hda_nid_t stac92hd73xx_smux_nids[2] = {
0x22, 0x23,
};
+#define STAC92HD73XX_NUM_CAPS 2
+static unsigned long stac92hd73xx_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd73xx_capsws stac92hd73xx_capvols
+
#define STAC92HD83XXX_NUM_DMICS 2
static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
0x11, 0x12, 0
@@ -365,6 +390,13 @@ static hda_nid_t stac92hd83xxx_amp_nids[1] = {
0xc,
};
+#define STAC92HD83XXX_NUM_CAPS 2
+static unsigned long stac92hd83xxx_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd83xxx_capsws stac92hd83xxx_capvols
+
static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
};
@@ -394,6 +426,13 @@ static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
0x22, 0
};
+#define STAC92HD71BXX_NUM_CAPS 2
+static unsigned long stac92hd71bxx_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd71bxx_capsws stac92hd71bxx_capvols
+
static hda_nid_t stac925x_adc_nids[1] = {
0x03,
};
@@ -415,6 +454,13 @@ static hda_nid_t stac925x_dmux_nids[1] = {
0x14,
};
+static unsigned long stac925x_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+};
+static unsigned long stac925x_capsws[] = {
+ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+};
+
static hda_nid_t stac922x_adc_nids[2] = {
0x06, 0x07,
};
@@ -423,6 +469,13 @@ static hda_nid_t stac922x_mux_nids[2] = {
0x12, 0x13,
};
+#define STAC922X_NUM_CAPS 2
+static unsigned long stac922x_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+};
+#define stac922x_capsws stac922x_capvols
+
static hda_nid_t stac927x_slave_dig_outs[2] = {
0x1f, 0,
};
@@ -452,6 +505,18 @@ static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
0x13, 0x14, 0
};
+#define STAC927X_NUM_CAPS 3
+static unsigned long stac927x_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
+};
+static unsigned long stac927x_capsws[] = {
+ HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+
static const char *stac927x_spdif_labels[5] = {
"Digital Playback", "ADAT", "Analog Mux 1",
"Analog Mux 2", "Analog Mux 3"
@@ -478,6 +543,16 @@ static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
0x17, 0x18, 0
};
+#define STAC9205_NUM_CAPS 2
+static unsigned long stac9205_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
+ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
+};
+static unsigned long stac9205_capsws[] = {
+ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
+};
+
static hda_nid_t stac9200_pin_nids[8] = {
0x08, 0x09, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12,
@@ -692,9 +767,35 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
- return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
- spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
+ const struct hda_input_mux *imux = spec->input_mux;
+ unsigned int idx, prev_idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ prev_idx = spec->cur_mux[adc_idx];
+ if (prev_idx == idx)
+ return 0;
+ if (idx < spec->num_analog_muxes) {
+ snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[idx].index);
+ if (prev_idx >= spec->num_analog_muxes) {
+ imux = spec->dinput_mux;
+ /* 0 = analog */
+ snd_hda_codec_write_cache(codec,
+ spec->dmux_nids[adc_idx], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[0].index);
+ }
+ } else {
+ imux = spec->dinput_mux;
+ snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[idx - 1].index);
+ }
+ spec->cur_mux[adc_idx] = idx;
+ return 1;
}
static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
@@ -924,19 +1025,6 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
{}
};
-#define HD_DISABLE_PORTF 1
-static struct hda_verb stac92hd71bxx_analog_core_init[] = {
- /* start of config #1 */
-
- /* connect port 0f to audio mixer */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
- /* start of config #2 */
-
- /* set master volume and direct control */
- { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- {}
-};
-
static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1069,12 +1157,6 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
{ } /* end */
};
@@ -1094,12 +1176,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
};
static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
@@ -1118,12 +1194,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
};
static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
@@ -1143,12 +1213,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
-
HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
@@ -1168,59 +1232,13 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
{ } /* end */
};
-static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- /* analog pc-beep replaced with digital beep support */
- /*
- HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
- */
-
- HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
-
- HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
-
- HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
- HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
-
- HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
- HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
- { } /* end */
-};
-
static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
};
-static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
static struct snd_kcontrol_new stac925x_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
- { } /* end */
-};
-
-static struct snd_kcontrol_new stac9205_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
{ } /* end */
};
@@ -1229,29 +1247,6 @@ static struct snd_kcontrol_new stac9205_loopback[] = {
{}
};
-/* This needs to be generated dynamically based on sequence */
-static struct snd_kcontrol_new stac922x_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-
-static struct snd_kcontrol_new stac927x_mixer[] = {
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
static struct snd_kcontrol_new stac927x_loopback[] = {
STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
{}
@@ -1309,16 +1304,19 @@ static int stac92xx_build_controls(struct hda_codec *codec)
int err;
int i;
- err = snd_hda_add_new_ctls(codec, spec->mixer);
- if (err < 0)
- return err;
+ if (spec->mixer) {
+ err = snd_hda_add_new_ctls(codec, spec->mixer);
+ if (err < 0)
+ return err;
+ }
for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
if (err < 0)
return err;
}
- if (spec->num_dmuxes > 0) {
+ if (!spec->auto_mic && spec->num_dmuxes > 0 &&
+ snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
stac_dmux_mixer.count = spec->num_dmuxes;
err = snd_hda_ctl_add(codec,
snd_ctl_new1(&stac_dmux_mixer, codec));
@@ -1809,6 +1807,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
"Dell Studio 1537", STAC_DELL_M6_DMIC),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
"Dell Studio 17", STAC_DELL_M6_DMIC),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be,
+ "Dell Studio 1555", STAC_DELL_M6_DMIC),
{} /* terminator */
};
@@ -2634,8 +2634,7 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
- unsigned char type);
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid);
static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2649,7 +2648,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
/* check to be sure that the ports are upto date with
* switch changes
*/
- stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
+ stac_issue_unsol_event(codec, nid);
return 1;
}
@@ -2782,7 +2781,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
* appropriately according to the pin direction
*/
if (spec->hp_detect)
- stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
+ stac_issue_unsol_event(codec, nid);
return 1;
}
@@ -2965,6 +2964,8 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec)
struct snd_kcontrol_new *knew;
struct hda_input_mux *imux = &spec->private_imux;
+ if (spec->auto_mic)
+ return 0; /* no need for input source */
if (!spec->num_adcs || imux->num_items <= 1)
return 0; /* no need for input source control */
knew = stac_control_new(spec, &stac_input_src_temp,
@@ -3058,7 +3059,7 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
HDA_MAX_CONNECTIONS);
for (j = 0; j < conn_len; j++) {
wcaps = get_wcaps(codec, conn[j]);
- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ wtype = get_wcaps_type(wcaps);
/* we check only analog outputs */
if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
continue;
@@ -3317,6 +3318,21 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
return 0;
}
+static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
+ unsigned long sw, int idx)
+{
+ int err;
+ err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
+ "Capture Volume", vol);
+ if (err < 0)
+ return err;
+ err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
+ "Capture Switch", sw);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
/* add playback controls from the parsed DAC table */
static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
@@ -3390,7 +3406,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
spec->mono_nid,
con_lst,
HDA_MAX_NUM_INPUTS);
- if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+ if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
return -EINVAL;
for (i = 0; i < num_cons; i++) {
@@ -3536,7 +3552,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
spec->smux_nids[0],
con_lst,
HDA_MAX_NUM_INPUTS);
- if (!num_cons)
+ if (num_cons <= 0)
return -EINVAL;
if (!labels)
@@ -3557,49 +3573,66 @@ static const char *stac92xx_dmic_labels[5] = {
"Digital Mic 3", "Digital Mic 4"
};
+static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
+ hda_nid_t nid)
+{
+ hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+ int i, nums;
+
+ nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+ for (i = 0; i < nums; i++)
+ if (conn[i] == nid)
+ return i;
+ return -1;
+}
+
/* create playback/capture controls for input pins on dmic capable codecs */
static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct sigmatel_spec *spec = codec->spec;
+ struct hda_input_mux *imux = &spec->private_imux;
struct hda_input_mux *dimux = &spec->private_dimux;
- hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
- int err, i, j;
+ int err, i, active_mics;
+ unsigned int def_conf;
char name[32];
dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
dimux->items[dimux->num_items].index = 0;
dimux->num_items++;
+ active_mics = 0;
+ for (i = 0; i < spec->num_dmics; i++) {
+ def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
+ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
+ active_mics++;
+ }
+
for (i = 0; i < spec->num_dmics; i++) {
hda_nid_t nid;
int index;
- int num_cons;
unsigned int wcaps;
- unsigned int def_conf;
+ const char *label;
def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
continue;
nid = spec->dmic_nids[i];
- num_cons = snd_hda_get_connections(codec,
- spec->dmux_nids[0],
- con_lst,
- HDA_MAX_NUM_INPUTS);
- for (j = 0; j < num_cons; j++)
- if (con_lst[j] == nid) {
- index = j;
- goto found;
- }
- continue;
-found:
+ index = get_connection_index(codec, spec->dmux_nids[0], nid);
+ if (index < 0)
+ continue;
+
+ if (active_mics == 1)
+ label = "Digital Mic";
+ else
+ label = stac92xx_dmic_labels[dimux->num_items];
+
wcaps = get_wcaps(codec, nid) &
(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
if (wcaps) {
- sprintf(name, "%s Capture Volume",
- stac92xx_dmic_labels[dimux->num_items]);
+ sprintf(name, "%s Capture Volume", label);
err = stac92xx_add_control(spec,
STAC_CTL_WIDGET_VOL,
@@ -3611,15 +3644,101 @@ found:
return err;
}
- dimux->items[dimux->num_items].label =
- stac92xx_dmic_labels[dimux->num_items];
+ dimux->items[dimux->num_items].label = label;
dimux->items[dimux->num_items].index = index;
dimux->num_items++;
+ if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
+ imux->items[imux->num_items].label = label;
+ imux->items[imux->num_items].index = index;
+ imux->num_items++;
+ }
}
return 0;
}
+static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t *fixed, hda_nid_t *ext)
+{
+ unsigned int cfg;
+
+ if (!nid)
+ return 0;
+ cfg = snd_hda_codec_get_pincfg(codec, nid);
+ switch (get_defcfg_connect(cfg)) {
+ case AC_JACK_PORT_FIXED:
+ if (*fixed)
+ return 1; /* already occupied */
+ *fixed = nid;
+ break;
+ case AC_JACK_PORT_COMPLEX:
+ if (*ext)
+ return 1; /* already occupied */
+ *ext = nid;
+ break;
+ }
+ return 0;
+}
+
+static int set_mic_route(struct hda_codec *codec,
+ struct sigmatel_mic_route *mic,
+ hda_nid_t pin)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ mic->pin = pin;
+ for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
+ if (pin == cfg->input_pins[i])
+ break;
+ if (i <= AUTO_PIN_FRONT_MIC) {
+ /* analog pin */
+ mic->dmux_idx = 0;
+ i = get_connection_index(codec, spec->mux_nids[0], pin);
+ if (i < 0)
+ return -1;
+ mic->mux_idx = i;
+ } else {
+ /* digital pin */
+ mic->mux_idx = 0;
+ i = get_connection_index(codec, spec->dmux_nids[0], pin);
+ if (i < 0)
+ return -1;
+ mic->dmux_idx = i;
+ }
+ return 0;
+}
+
+/* return non-zero if the device is for automatic mic switch */
+static int stac_check_auto_mic(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t fixed, ext;
+ int i;
+
+ for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
+ if (cfg->input_pins[i])
+ return 0; /* must be exclusively mics */
+ }
+ fixed = ext = 0;
+ for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
+ if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+ return 0;
+ for (i = 0; i < spec->num_dmics; i++)
+ if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+ return 0;
+ if (!fixed || !ext)
+ return 0;
+ if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+ return 0; /* no unsol support */
+ if (set_mic_route(codec, &spec->ext_mic, ext) ||
+ set_mic_route(codec, &spec->int_mic, fixed))
+ return 0; /* something is wrong */
+ return 1;
+}
+
/* create playback/capture controls for input pins */
static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
@@ -3652,6 +3771,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
imux->items[imux->num_items].index = index;
imux->num_items++;
}
+ spec->num_analog_muxes = imux->num_items;
if (imux->num_items) {
/*
@@ -3703,7 +3823,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
{
struct sigmatel_spec *spec = codec->spec;
int hp_swap = 0;
- int err;
+ int i, err;
if ((err = snd_hda_parse_pin_def_config(codec,
&spec->autocfg,
@@ -3743,11 +3863,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if (snd_hda_get_connections(codec,
spec->autocfg.mono_out_pin, conn_list, 1) &&
snd_hda_get_connections(codec, conn_list[0],
- conn_list, 1)) {
+ conn_list, 1) > 0) {
int wcaps = get_wcaps(codec, conn_list[0]);
- int wid_type = (wcaps & AC_WCAP_TYPE)
- >> AC_WCAP_TYPE_SHIFT;
+ int wid_type = get_wcaps_type(wcaps);
/* LR swap check, some stac925x have a mux that
* changes the DACs output path instead of the
* mono-mux path.
@@ -3838,6 +3957,21 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
spec->autocfg.line_outs = 0;
}
+ if (stac_check_auto_mic(codec)) {
+ spec->auto_mic = 1;
+ /* only one capture for auto-mic */
+ spec->num_adcs = 1;
+ spec->num_caps = 1;
+ spec->num_muxes = 1;
+ }
+
+ for (i = 0; i < spec->num_caps; i++) {
+ err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
+ spec->capsws[i], i);
+ if (err < 0)
+ return err;
+ }
+
err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -4066,7 +4200,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
jack->nid = nid;
jack->type = type;
- sprintf(name, "%s at %s %s Jack",
+ snprintf(name, sizeof(name), "%s at %s %s Jack",
snd_hda_get_jack_type(def_conf),
snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf));
@@ -4100,14 +4234,14 @@ static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
}
static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
- hda_nid_t nid, unsigned char type)
+ hda_nid_t nid)
{
struct sigmatel_spec *spec = codec->spec;
struct sigmatel_event *event = spec->events.list;
int i;
for (i = 0; i < spec->events.used; i++, event++) {
- if (event->nid == nid && event->type == type)
+ if (event->nid == nid)
return event;
}
return NULL;
@@ -4127,24 +4261,32 @@ static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
return NULL;
}
-static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
- unsigned int type)
+/* check if given nid is a valid pin and no other events are assigned
+ * to it. If OK, assign the event, set the unsol flag, and returns 1.
+ * Otherwise, returns zero.
+ */
+static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int type)
{
struct sigmatel_event *event;
int tag;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
- return;
- event = stac_get_event(codec, nid, type);
- if (event)
+ return 0;
+ event = stac_get_event(codec, nid);
+ if (event) {
+ if (event->type != type)
+ return 0;
tag = event->tag;
- else
+ } else {
tag = stac_add_event(codec->spec, nid, type, 0);
- if (tag < 0)
- return;
+ if (tag < 0)
+ return 0;
+ }
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | tag);
+ return 1;
}
static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -4237,20 +4379,34 @@ static int stac92xx_init(struct hda_codec *codec)
hda_nid_t nid = cfg->hp_pins[i];
enable_pin_detect(codec, nid, STAC_HP_EVENT);
}
+ if (cfg->line_out_type == AUTO_PIN_LINE_OUT) {
+ /* enable pin-detect for line-outs as well */
+ for (i = 0; i < cfg->hp_outs; i++) {
+ hda_nid_t nid = cfg->hp_pins[i];
+ enable_pin_detect(codec, nid, STAC_LO_EVENT);
+ }
+ }
+
/* force to enable the first line-out; the others are set up
* in unsol_event
*/
stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
AC_PINCTL_OUT_EN);
/* fake event to set up pins */
- stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
- STAC_HP_EVENT);
+ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
} else {
stac92xx_auto_init_multi_out(codec);
stac92xx_auto_init_hp_out(codec);
for (i = 0; i < cfg->hp_outs; i++)
stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
}
+ if (spec->auto_mic) {
+ /* initialize connection to analog input */
+ snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
+ AC_VERB_SET_CONNECT_SEL, 0);
+ if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
+ stac_issue_unsol_event(codec, spec->ext_mic.pin);
+ }
for (i = 0; i < AUTO_PIN_LAST; i++) {
hda_nid_t nid = cfg->input_pins[i];
if (nid) {
@@ -4277,10 +4433,9 @@ static int stac92xx_init(struct hda_codec *codec)
}
conf = snd_hda_codec_get_pincfg(codec, nid);
if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
- enable_pin_detect(codec, nid,
- STAC_INSERT_EVENT);
- stac_issue_unsol_event(codec, nid,
- STAC_INSERT_EVENT);
+ if (enable_pin_detect(codec, nid,
+ STAC_INSERT_EVENT))
+ stac_issue_unsol_event(codec, nid);
}
}
}
@@ -4325,10 +4480,8 @@ static int stac92xx_init(struct hda_codec *codec)
stac_toggle_power_map(codec, nid, 1);
continue;
}
- if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
- enable_pin_detect(codec, nid, STAC_PWR_EVENT);
- stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
- }
+ if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
+ stac_issue_unsol_event(codec, nid);
}
if (spec->dac_list)
stac92xx_power_down(codec);
@@ -4432,6 +4585,48 @@ static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
return 0;
}
+static void stac92xx_line_out_detect(struct hda_codec *codec,
+ int presence)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (presence)
+ break;
+ presence = get_pin_presence(codec, cfg->line_out_pins[i]);
+ if (presence) {
+ unsigned int pinctl;
+ pinctl = snd_hda_codec_read(codec,
+ cfg->line_out_pins[i], 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (pinctl & AC_PINCTL_IN_EN)
+ presence = 0; /* mic- or line-input */
+ }
+ }
+
+ if (presence) {
+ /* disable speakers */
+ for (i = 0; i < cfg->speaker_outs; i++)
+ stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
+ AC_PINCTL_OUT_EN);
+ if (spec->eapd_mask && spec->eapd_switch)
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data &
+ ~spec->eapd_mask);
+ } else {
+ /* enable speakers */
+ for (i = 0; i < cfg->speaker_outs; i++)
+ stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
+ AC_PINCTL_OUT_EN);
+ if (spec->eapd_mask && spec->eapd_switch)
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data |
+ spec->eapd_mask);
+ }
+}
+
/* return non-zero if the hp-pin of the given array index isn't
* a jack-detection target
*/
@@ -4484,13 +4679,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
for (i = 0; i < cfg->line_outs; i++)
stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
AC_PINCTL_OUT_EN);
- for (i = 0; i < cfg->speaker_outs; i++)
- stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
- AC_PINCTL_OUT_EN);
- if (spec->eapd_mask && spec->eapd_switch)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data &
- ~spec->eapd_mask);
} else {
/* enable lineouts */
if (spec->hp_switch)
@@ -4499,14 +4687,8 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
for (i = 0; i < cfg->line_outs; i++)
stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
AC_PINCTL_OUT_EN);
- for (i = 0; i < cfg->speaker_outs; i++)
- stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
- AC_PINCTL_OUT_EN);
- if (spec->eapd_mask && spec->eapd_switch)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data |
- spec->eapd_mask);
}
+ stac92xx_line_out_detect(codec, presence);
/* toggle hp outs */
for (i = 0; i < cfg->hp_outs; i++) {
unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
@@ -4591,10 +4773,28 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
}
}
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
- unsigned char type)
+static void stac92xx_mic_detect(struct hda_codec *codec)
{
- struct sigmatel_event *event = stac_get_event(codec, nid, type);
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_mic_route *mic;
+
+ if (get_pin_presence(codec, spec->ext_mic.pin))
+ mic = &spec->ext_mic;
+ else
+ mic = &spec->int_mic;
+ if (mic->dmux_idx)
+ snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mic->dmux_idx);
+ else
+ snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mic->mux_idx);
+}
+
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_event *event = stac_get_event(codec, nid);
if (!event)
return;
codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
@@ -4614,7 +4814,19 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
switch (event->type) {
case STAC_HP_EVENT:
stac92xx_hp_detect(codec);
- /* fallthru */
+ break;
+ case STAC_LO_EVENT:
+ stac92xx_line_out_detect(codec, 0);
+ break;
+ case STAC_MIC_EVENT:
+ stac92xx_mic_detect(codec);
+ break;
+ }
+
+ switch (event->type) {
+ case STAC_HP_EVENT:
+ case STAC_LO_EVENT:
+ case STAC_MIC_EVENT:
case STAC_INSERT_EVENT:
case STAC_PWR_EVENT:
if (spec->num_pwrs > 0)
@@ -4705,8 +4917,7 @@ static int stac92xx_resume(struct hda_codec *codec)
snd_hda_codec_resume_cache(codec);
/* fake event to set up pins again to override cached values */
if (spec->hp_detect)
- stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
- STAC_HP_EVENT);
+ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
return 0;
}
@@ -4746,6 +4957,19 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
{
struct sigmatel_spec *spec = codec->spec;
+ int i;
+ hda_nid_t nid;
+
+ /* reset each pin before powering down DAC/ADC to avoid click noise */
+ nid = codec->start_nid;
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ unsigned int wcaps = get_wcaps(codec, nid);
+ unsigned int wid_type = get_wcaps_type(wcaps);
+ if (wid_type == AC_WID_PIN)
+ snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ }
+
if (spec->eapd_mask)
stac_gpio_set(codec, spec->gpio_mask,
spec->gpio_dir, spec->gpio_data &
@@ -4782,7 +5006,8 @@ static int patch_stac9200(struct hda_codec *codec)
stac9200_models,
stac9200_cfg_tbl);
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac9200_brd_tbl[spec->board_config]);
@@ -4854,8 +5079,8 @@ static int patch_stac925x(struct hda_codec *codec)
stac925x_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
- "using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac925x_brd_tbl[spec->board_config]);
@@ -4885,6 +5110,9 @@ static int patch_stac925x(struct hda_codec *codec)
spec->init = stac925x_core_init;
spec->mixer = stac925x_mixer;
+ spec->num_caps = 1;
+ spec->capvols = stac925x_capvols;
+ spec->capsws = stac925x_capsws;
err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
if (!err) {
@@ -4906,16 +5134,6 @@ static int patch_stac925x(struct hda_codec *codec)
return 0;
}
-static struct hda_input_mux stac92hd73xx_dmux = {
- .num_items = 4,
- .items = {
- { "Analog Inputs", 0x0b },
- { "Digital Mic 1", 0x09 },
- { "Digital Mic 2", 0x0a },
- { "CD", 0x08 },
- }
-};
-
static int patch_stac92hd73xx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -4937,8 +5155,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
stac92hd73xx_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for"
- " STAC92HD73XX, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac92hd73xx_brd_tbl[spec->board_config]);
@@ -4985,8 +5203,10 @@ again:
spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
- memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
- sizeof(stac92hd73xx_dmux));
+
+ spec->num_caps = STAC92HD73XX_NUM_CAPS;
+ spec->capvols = stac92hd73xx_capvols;
+ spec->capsws = stac92hd73xx_capsws;
switch (spec->board_config) {
case STAC_DELL_EQ:
@@ -5007,18 +5227,15 @@ again:
case STAC_DELL_M6_AMIC: /* Analog Mics */
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
spec->num_dmics = 0;
- spec->private_dimux.num_items = 1;
break;
case STAC_DELL_M6_DMIC: /* Digital Mics */
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
spec->num_dmics = 1;
- spec->private_dimux.num_items = 2;
break;
case STAC_DELL_M6_BOTH: /* Both */
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
spec->num_dmics = 1;
- spec->private_dimux.num_items = 2;
break;
}
break;
@@ -5026,13 +5243,13 @@ again:
spec->num_dmics = STAC92HD73XX_NUM_DMICS;
spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
spec->eapd_switch = 1;
+ break;
}
if (spec->board_config > STAC_92HD73XX_REF) {
/* GPIO0 High = Enable EAPD */
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
spec->gpio_data = 0x01;
}
- spec->dinput_mux = &spec->private_dimux;
spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
spec->pwr_nids = stac92hd73xx_pwr_nids;
@@ -5064,15 +5281,6 @@ again:
return 0;
}
-static struct hda_input_mux stac92hd83xxx_dmux = {
- .num_items = 3,
- .items = {
- { "Analog Inputs", 0x03 },
- { "Digital Mic 1", 0x04 },
- { "Digital Mic 2", 0x05 },
- }
-};
-
static int patch_stac92hd83xxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -5105,16 +5313,19 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
- spec->dinput_mux = &stac92hd83xxx_dmux;
spec->pin_nids = stac92hd83xxx_pin_nids;
+ spec->num_caps = STAC92HD83XXX_NUM_CAPS;
+ spec->capvols = stac92hd83xxx_capvols;
+ spec->capsws = stac92hd83xxx_capsws;
+
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD83XXX_MODELS,
stac92hd83xxx_models,
stac92hd83xxx_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for"
- " STAC92HD83XXX, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac92hd83xxx_brd_tbl[spec->board_config]);
@@ -5156,6 +5367,8 @@ again:
num_dacs = snd_hda_get_connections(codec, nid,
conn, STAC92HD83_DAC_COUNT + 1) - 1;
+ if (num_dacs < 0)
+ num_dacs = STAC92HD83_DAC_COUNT;
/* set port X to select the last DAC
*/
@@ -5169,25 +5382,6 @@ again:
return 0;
}
-static struct hda_input_mux stac92hd71bxx_dmux_nomixer = {
- .num_items = 3,
- .items = {
- { "Analog Inputs", 0x00 },
- { "Digital Mic 1", 0x02 },
- { "Digital Mic 2", 0x03 },
- }
-};
-
-static struct hda_input_mux stac92hd71bxx_dmux_amixer = {
- .num_items = 4,
- .items = {
- { "Analog Inputs", 0x00 },
- { "Mixer", 0x01 },
- { "Digital Mic 1", 0x02 },
- { "Digital Mic 2", 0x03 },
- }
-};
-
/* get the pin connection (fixed, none, etc) */
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
{
@@ -5248,7 +5442,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
struct sigmatel_spec *spec;
struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
int err = 0;
- unsigned int ndmic_nids = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -5277,8 +5470,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
stac92hd71bxx_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for"
- " STAC92HD71BXX, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac92hd71bxx_brd_tbl[spec->board_config]);
@@ -5293,6 +5486,10 @@ again:
spec->dmic_nids = stac92hd71bxx_dmic_nids;
spec->dmux_nids = stac92hd71bxx_dmux_nids;
+ spec->num_caps = STAC92HD71BXX_NUM_CAPS;
+ spec->capvols = stac92hd71bxx_capvols;
+ spec->capsws = stac92hd71bxx_capsws;
+
switch (codec->vendor_id) {
case 0x111d76b6: /* 4 Port without Analog Mixer */
case 0x111d76b7:
@@ -5300,24 +5497,13 @@ again:
/* fallthru */
case 0x111d76b4: /* 6 Port without Analog Mixer */
case 0x111d76b5:
- memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
- sizeof(stac92hd71bxx_dmux_nomixer));
- spec->mixer = stac92hd71bxx_mixer;
spec->init = stac92hd71bxx_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS);
- if (spec->num_dmics) {
- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
- spec->dinput_mux = &spec->private_dimux;
- ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
- }
break;
case 0x111d7608: /* 5 Port with Analog Mixer */
- memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
- sizeof(stac92hd71bxx_dmux_amixer));
- spec->private_dimux.num_items--;
switch (spec->board_config) {
case STAC_HP_M4:
/* Enable VREF power saving on GPIO1 detect */
@@ -5339,11 +5525,8 @@ again:
/* no output amps */
spec->num_pwrs = 0;
- spec->mixer = stac92hd71bxx_analog_mixer;
- spec->dinput_mux = &spec->private_dimux;
-
/* disable VSW */
- spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+ spec->init = stac92hd71bxx_core_init;
unmute_init++;
snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
@@ -5351,8 +5534,6 @@ again:
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS - 1);
- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
- ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2;
break;
case 0x111d7603: /* 6 Port with Analog Mixer */
if ((codec->revision_id & 0xf) == 1)
@@ -5362,17 +5543,12 @@ again:
spec->num_pwrs = 0;
/* fallthru */
default:
- memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
- sizeof(stac92hd71bxx_dmux_amixer));
- spec->dinput_mux = &spec->private_dimux;
- spec->mixer = stac92hd71bxx_analog_mixer;
- spec->init = stac92hd71bxx_analog_core_init;
+ spec->init = stac92hd71bxx_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS);
- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
- ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
+ break;
}
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
@@ -5400,6 +5576,7 @@ again:
spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+ spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
switch (spec->board_config) {
@@ -5454,8 +5631,6 @@ again:
#endif
spec->multiout.dac_nids = spec->dac_nids;
- if (spec->dinput_mux)
- spec->private_dimux.num_items += spec->num_dmics - ndmic_nids;
err = stac92xx_parse_auto_config(codec, 0x21, 0);
if (!err) {
@@ -5533,8 +5708,8 @@ static int patch_stac922x(struct hda_codec *codec)
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
- "using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac922x_brd_tbl[spec->board_config]);
@@ -5547,7 +5722,10 @@ static int patch_stac922x(struct hda_codec *codec)
spec->num_pwrs = 0;
spec->init = stac922x_core_init;
- spec->mixer = stac922x_mixer;
+
+ spec->num_caps = STAC922X_NUM_CAPS;
+ spec->capvols = stac922x_capvols;
+ spec->capsws = stac922x_capsws;
spec->multiout.dac_nids = spec->dac_nids;
@@ -5596,8 +5774,8 @@ static int patch_stac927x(struct hda_codec *codec)
stac927x_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for"
- "STAC927x, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac927x_brd_tbl[spec->board_config]);
@@ -5622,7 +5800,6 @@ static int patch_stac927x(struct hda_codec *codec)
spec->num_dmics = 0;
spec->init = d965_core_init;
- spec->mixer = stac927x_mixer;
break;
case STAC_DELL_BIOS:
switch (codec->subsystem_id) {
@@ -5647,7 +5824,6 @@ static int patch_stac927x(struct hda_codec *codec)
spec->num_dmics = STAC927X_NUM_DMICS;
spec->init = d965_core_init;
- spec->mixer = stac927x_mixer;
spec->dmux_nids = stac927x_dmux_nids;
spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
break;
@@ -5660,9 +5836,12 @@ static int patch_stac927x(struct hda_codec *codec)
spec->num_dmics = 0;
spec->init = stac927x_core_init;
- spec->mixer = stac927x_mixer;
}
+ spec->num_caps = STAC927X_NUM_CAPS;
+ spec->capvols = stac927x_capvols;
+ spec->capsws = stac927x_capsws;
+
spec->num_pwrs = 0;
spec->aloopback_ctl = stac927x_loopback;
spec->aloopback_mask = 0x40;
@@ -5724,7 +5903,8 @@ static int patch_stac9205(struct hda_codec *codec)
stac9205_cfg_tbl);
again:
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac9205_brd_tbl[spec->board_config]);
@@ -5743,9 +5923,12 @@ static int patch_stac9205(struct hda_codec *codec)
spec->num_pwrs = 0;
spec->init = stac9205_core_init;
- spec->mixer = stac9205_mixer;
spec->aloopback_ctl = stac9205_loopback;
+ spec->num_caps = STAC9205_NUM_CAPS;
+ spec->capvols = stac9205_capvols;
+ spec->capsws = stac9205_capsws;
+
spec->aloopback_mask = 0x40;
spec->aloopback_shift = 0;
/* Turn on/off EAPD per HP plugging */
@@ -5820,12 +6003,6 @@ static struct hda_verb stac9872_core_init[] = {
{}
};
-static struct snd_kcontrol_new stac9872_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
- { } /* end */
-};
-
static hda_nid_t stac9872_pin_nids[] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x11, 0x13, 0x14,
@@ -5839,6 +6016,11 @@ static hda_nid_t stac9872_mux_nids[] = {
0x15
};
+static unsigned long stac9872_capvols[] = {
+ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+};
+#define stac9872_capsws stac9872_capvols
+
static unsigned int stac9872_vaio_pin_configs[9] = {
0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
@@ -5876,8 +6058,8 @@ static int patch_stac9872(struct hda_codec *codec)
stac9872_models,
stac9872_cfg_tbl);
if (spec->board_config < 0)
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, "
- "using BIOS defaults\n");
+ snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
else
stac92xx_set_config_regs(codec,
stac9872_brd_tbl[spec->board_config]);
@@ -5887,8 +6069,10 @@ static int patch_stac9872(struct hda_codec *codec)
spec->adc_nids = stac9872_adc_nids;
spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
spec->mux_nids = stac9872_mux_nids;
- spec->mixer = stac9872_mixer;
spec->init = stac9872_core_init;
+ spec->num_caps = 1;
+ spec->capvols = stac9872_capvols;
+ spec->capsws = stac9872_capsws;
err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
if (err < 0) {
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 9008b4b013aa..ab90abb04ccd 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1339,8 +1339,7 @@ static int get_mux_nids(struct hda_codec *codec)
for (i = 0; i < spec->num_adc_nids; i++) {
nid = spec->adc_nids[i];
while (nid) {
- type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
- >> AC_WCAP_TYPE_SHIFT;
+ type = get_wcaps_type(get_wcaps(codec, nid));
if (type == AC_WID_PIN)
break;
n = snd_hda_get_connections(codec, nid, conn,
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index adc909ec125c..9da2dae64c5b 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -379,6 +379,15 @@ struct snd_ice1712 {
unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
void (*set_spdif_clock)(struct snd_ice1712 *ice);
+#ifdef CONFIG_PM
+ int (*pm_suspend)(struct snd_ice1712 *);
+ int (*pm_resume)(struct snd_ice1712 *);
+ int pm_suspend_enabled:1;
+ int pm_saved_is_spdif_master:1;
+ unsigned int pm_saved_spdif_ctrl;
+ unsigned char pm_saved_spdif_cfg;
+ unsigned int pm_saved_route;
+#endif
};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index cc84a831eb21..af6e00148621 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -560,6 +560,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&ice->reg_lock);
old = inb(ICEMT1724(ice, DMA_CONTROL));
if (cmd == SNDRV_PCM_TRIGGER_START)
@@ -570,6 +571,10 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock(&ice->reg_lock);
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* apps will have to restart stream */
+ break;
+
default:
return -EINVAL;
}
@@ -2262,7 +2267,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
-static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice)
+static void snd_vt1724_chip_reset(struct snd_ice1712 *ice)
{
outb(VT1724_RESET , ICEREG1724(ice, CONTROL));
inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */
@@ -2272,7 +2277,7 @@ static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice)
msleep(10);
}
-static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice)
+static int snd_vt1724_chip_init(struct snd_ice1712 *ice)
{
outb(ice->eeprom.data[ICE_EEP2_SYSCONF], ICEREG1724(ice, SYS_CFG));
outb(ice->eeprom.data[ICE_EEP2_ACLINK], ICEREG1724(ice, AC97_CFG));
@@ -2287,6 +2292,14 @@ static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice)
outb(0, ICEREG1724(ice, POWERDOWN));
+ /* MPU_RX and TX irq masks are cleared later dynamically */
+ outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
+
+ /* don't handle FIFO overrun/underruns (just yet),
+ * since they cause machine lockups
+ */
+ outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
+
return 0;
}
@@ -2431,6 +2444,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
snd_vt1724_proc_init(ice);
synchronize_irq(pci->irq);
+ card->private_data = ice;
+
err = pci_request_regions(pci, "ICE1724");
if (err < 0) {
kfree(ice);
@@ -2459,14 +2474,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
return -EIO;
}
- /* MPU_RX and TX irq masks are cleared later dynamically */
- outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
-
- /* don't handle FIFO overrun/underruns (just yet),
- * since they cause machine lockups
- */
- outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
-
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
if (err < 0) {
snd_vt1724_free(ice);
@@ -2650,11 +2657,96 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
+#ifdef CONFIG_PM
+static int snd_vt1724_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ snd_pcm_suspend_all(ice->pcm);
+ snd_pcm_suspend_all(ice->pcm_pro);
+ snd_pcm_suspend_all(ice->pcm_ds);
+ snd_ac97_suspend(ice->ac97);
+
+ spin_lock_irq(&ice->reg_lock);
+ ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice);
+ ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL));
+ ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG));
+ ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
+ spin_unlock_irq(&ice->reg_lock);
+
+ if (ice->pm_suspend)
+ ice->pm_suspend(ice);
+
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+}
+
+static int snd_vt1724_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+
+ if (pci_enable_device(pci) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ pci_set_master(pci);
+
+ snd_vt1724_chip_reset(ice);
+
+ if (snd_vt1724_chip_init(ice) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ if (ice->pm_resume)
+ ice->pm_resume(ice);
+
+ if (ice->pm_saved_is_spdif_master) {
+ /* switching to external clock via SPDIF */
+ ice->set_spdif_clock(ice);
+ } else {
+ /* internal on-card clock */
+ snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+ }
+
+ update_spdif_bits(ice, ice->pm_saved_spdif_ctrl);
+
+ outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG));
+ outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK));
+
+ if (ice->ac97)
+ snd_ac97_resume(ice->ac97);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
static struct pci_driver driver = {
.name = "ICE1724",
.id_table = snd_vt1724_ids,
.probe = snd_vt1724_probe,
.remove = __devexit_p(snd_vt1724_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_vt1724_suspend,
+ .resume = snd_vt1724_resume,
+#endif
};
static int __init alsa_card_ice1724_init(void)
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 043a93879bd5..c75515f5be6f 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -1077,7 +1077,7 @@ static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice)
/*
* initialize the chip
*/
-static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
+static void ak4396_init(struct snd_ice1712 *ice)
{
static unsigned short ak4396_inits[] = {
AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */
@@ -1087,9 +1087,37 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
AK4396_RCH_ATT, 0x00,
};
- struct prodigy_hifi_spec *spec;
unsigned int i;
+ /* initialize ak4396 codec */
+ /* reset codec */
+ ak4396_write(ice, AK4396_CTRL1, 0x86);
+ msleep(100);
+ ak4396_write(ice, AK4396_CTRL1, 0x87);
+
+ for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
+ ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
+}
+
+#ifdef CONFIG_PM
+static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice)
+{
+ /* initialize ak4396 codec and restore previous mixer volumes */
+ struct prodigy_hifi_spec *spec = ice->spec;
+ int i;
+ mutex_lock(&ice->gpio_mutex);
+ ak4396_init(ice);
+ for (i = 0; i < 2; i++)
+ ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
+ mutex_unlock(&ice->gpio_mutex);
+ return 0;
+}
+#endif
+
+static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
+{
+ struct prodigy_hifi_spec *spec;
+
ice->vt1720 = 0;
ice->vt1724 = 1;
@@ -1112,14 +1140,12 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
return -ENOMEM;
ice->spec = spec;
- /* initialize ak4396 codec */
- /* reset codec */
- ak4396_write(ice, AK4396_CTRL1, 0x86);
- msleep(100);
- ak4396_write(ice, AK4396_CTRL1, 0x87);
-
- for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
- ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
+#ifdef CONFIG_PM
+ ice->pm_resume = &prodigy_hd2_resume;
+ ice->pm_suspend_enabled = 1;
+#endif
+
+ ak4396_init(ice);
return 0;
}
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 173a239a541c..885ba012557e 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -56,30 +56,14 @@
#define MCLK_RATE 12000000
-static struct clk *mclk;
-
-static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
- MCLK_RATE, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- clk_disable(mclk);
- return ret;
- }
-
- return 0;
-}
-
-static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+/*
+ * As shipped the board does not have inputs. However, it is relatively
+ * straightforward to modify the board to hook them up so support is left
+ * in the driver.
+ */
+#undef ENABLE_MIC_INPUT
- dev_dbg(rtd->socdev->dev, "shutdown");
-}
+static struct clk *mclk;
static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -87,102 +71,17 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct atmel_ssc_info *ssc_p = cpu_dai->private_data;
- struct ssc_device *ssc = ssc_p->ssc;
int ret;
- unsigned int rate;
- int cmr_div, period;
-
- if (ssc == NULL) {
- printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n");
- return -EINVAL;
- }
-
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /*
- * The SSC clock dividers depend on the sample rate. The CMR.DIV
- * field divides the system master clock MCK to drive the SSC TK
- * signal which provides the codec BCLK. The TCMR.PERIOD and
- * RCMR.PERIOD fields further divide the BCLK signal to drive
- * the SSC TF and RF signals which provide the codec DACLRC and
- * ADCLRC clocks.
- *
- * The dividers were determined through trial and error, where a
- * CMR.DIV value is chosen such that the resulting BCLK value is
- * divisible, or almost divisible, by (2 * sample rate), and then
- * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
- */
- rate = params_rate(params);
-
- switch (rate) {
- case 8000:
- cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */
- period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */
- break;
- case 11025:
- cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */
- period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */
- break;
- case 16000:
- cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */
- period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */
- break;
- case 22050:
- cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */
- period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */
- break;
- case 32000:
- cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */
- period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */
- break;
- case 44100:
- cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */
- period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */
- break;
- case 48000:
- cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */
- period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */
- break;
- case 88200:
- cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */
- period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */
- break;
- case 96000:
- cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */
- period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */
- break;
- default:
- printk(KERN_WARNING "unsupported rate %d"
- " on at91sam9g20ek board\n", rate);
- return -EINVAL;
- }
-
- /* set the MCK divider for BCLK */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div);
- if (ret < 0)
- return ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* set the BCLK divider for DACLRC */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- ATMEL_SSC_TCMR_PERIOD, period);
- } else {
- /* set the BCLK divider for ADCLRC */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- ATMEL_SSC_RCMR_PERIOD, period);
- }
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
@@ -190,9 +89,7 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
}
static struct snd_soc_ops at91sam9g20ek_ops = {
- .startup = at91sam9g20ek_startup,
.hw_params = at91sam9g20ek_hw_params,
- .shutdown = at91sam9g20ek_shutdown,
};
static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
@@ -241,10 +138,20 @@ static const struct snd_soc_dapm_route intercon[] = {
*/
static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
{
+ struct snd_soc_dai *codec_dai = &codec->dai[0];
+ int ret;
+
printk(KERN_DEBUG
"at91sam9g20ek_wm8731 "
": at91sam9g20ek_wm8731_init() called\n");
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+ MCLK_RATE, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
+ return ret;
+ }
+
/* Add specific widgets */
snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
@@ -255,8 +162,13 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
snd_soc_dapm_nc_pin(codec, "RLINEIN");
snd_soc_dapm_nc_pin(codec, "LLINEIN");
- /* always connected */
+#ifdef ENABLE_MIC_INPUT
snd_soc_dapm_enable_pin(codec, "Int Mic");
+#else
+ snd_soc_dapm_nc_pin(codec, "Int Mic");
+#endif
+
+ /* always connected */
snd_soc_dapm_enable_pin(codec, "Ext Spk");
snd_soc_dapm_sync(codec);
@@ -281,38 +193,6 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.set_bias_level = at91sam9g20ek_set_bias_level,
};
-/*
- * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
- * New drivers should register the wm8731 I2C device in the machine
- * setup code (under arch/arm for ARM systems).
- */
-static int wm8731_i2c_register(void)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = 0x1b;
- strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(0);
- if (!adapter) {
- printk(KERN_ERR "can't get i2c adapter 0\n");
- return -ENODEV;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- printk(KERN_ERR "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- return -ENODEV;
- }
-
- return 0;
-}
-
static struct snd_soc_device at91sam9g20ek_snd_devdata = {
.card = &snd_soc_at91sam9g20ek,
.codec_dev = &soc_codec_dev_wm8731,
@@ -367,10 +247,6 @@ static int __init at91sam9g20ek_init(void)
}
ssc_p->ssc = ssc;
- ret = wm8731_i2c_register();
- if (ret != 0)
- goto err_ssc;
-
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
if (!at91sam9g20ek_snd_device) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 811596f4c092..8a4de4de30f2 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -7,6 +7,15 @@ config SND_BF5XX_I2S
mode (supports single stereo In/Out).
You will also need to select the audio interfaces to support below.
+config SND_BF5XX_TDM
+ tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
+ depends on (BLACKFIN && SND_SOC)
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Blackfin SPORT (synchronous serial ports) interface in TDM
+ mode.
+ You will also need to select the audio interfaces to support below.
+
config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio support for BF52x ezkit"
depends on SND_BF5XX_I2S
@@ -69,6 +78,10 @@ config SND_BF5XX_SOC_I2S
tristate
select SND_BF5XX_SOC_SPORT
+config SND_BF5XX_SOC_TDM
+ tristate
+ select SND_BF5XX_SOC_SPORT
+
config SND_BF5XX_SOC_AC97
tristate
select AC97_BUS
@@ -83,9 +96,17 @@ config SND_BF5XX_SOC_AD1980
help
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
+config SND_BF5XX_SOC_AD1938
+ tristate "SoC AD1938 Audio support for Blackfin"
+ depends on SND_BF5XX_TDM
+ select SND_BF5XX_SOC_TDM
+ select SND_SOC_AD1938
+ help
+ Say Y if you want to add support for AD1938 codec on Blackfin.
+
config SND_BF5XX_SPORT_NUM
int "Set a SPORT for Sound chip"
- depends on (SND_BF5XX_I2S || SND_BF5XX_AC97)
+ depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM)
range 0 3 if BF54x
range 0 1 if !BF54x
default 0
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 97bb37a6359c..f4d760741fab 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -1,21 +1,27 @@
# Blackfin Platform Support
snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
+snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
snd-soc-bf5xx-sport-objs := bf5xx-sport.o
snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
+snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
+obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
+obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
# Blackfin Machine Support
snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
+snd-ad1938-objs := bf5xx-ad1938.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD1938) += snd-ad1938.o
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index b1ed423fabd5..2758b9017a7f 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -277,28 +277,24 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
if (!dai->active)
return 0;
- ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+ ret = sport_set_multichannel(sport, 16, 0x1F, 1);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
+ ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
+ ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1));
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- if (dai->capture.active)
- sport_rx_start(sport);
- if (dai->playback.active)
- sport_tx_start(sport);
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c
new file mode 100644
index 000000000000..08269e91810c
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad1938.c
@@ -0,0 +1,142 @@
+/*
+ * File: sound/soc/blackfin/bf5xx-ad1938.c
+ * Author: Barry Song <Barry.Song@analog.com>
+ *
+ * Created: Thur June 4 2009
+ * Description: Board driver for ad1938 sound chip
+ *
+ * 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>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad1938.h"
+#include "bf5xx-sport.h"
+
+#include "bf5xx-tdm-pcm.h"
+#include "bf5xx-tdm.h"
+
+static struct snd_soc_card bf5xx_ad1938;
+
+static int bf5xx_ad1938_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ cpu_dai->private_data = sport_handle;
+ return 0;
+}
+
+static int bf5xx_ad1938_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;
+ int ret = 0;
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI slots, 8 channels, all channels are enabled */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops bf5xx_ad1938_ops = {
+ .startup = bf5xx_ad1938_startup,
+ .hw_params = bf5xx_ad1938_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad1938_dai = {
+ .name = "ad1938",
+ .stream_name = "AD1938",
+ .cpu_dai = &bf5xx_tdm_dai,
+ .codec_dai = &ad1938_dai,
+ .ops = &bf5xx_ad1938_ops,
+};
+
+static struct snd_soc_card bf5xx_ad1938 = {
+ .name = "bf5xx_ad1938",
+ .platform = &bf5xx_tdm_soc_platform,
+ .dai_link = &bf5xx_ad1938_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad1938_snd_devdata = {
+ .card = &bf5xx_ad1938,
+ .codec_dev = &soc_codec_dev_ad1938,
+};
+
+static struct platform_device *bfxx_ad1938_snd_device;
+
+static int __init bf5xx_ad1938_init(void)
+{
+ int ret;
+
+ bfxx_ad1938_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!bfxx_ad1938_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(bfxx_ad1938_snd_device, &bf5xx_ad1938_snd_devdata);
+ bf5xx_ad1938_snd_devdata.dev = &bfxx_ad1938_snd_device->dev;
+ ret = platform_device_add(bfxx_ad1938_snd_device);
+
+ if (ret)
+ platform_device_put(bfxx_ad1938_snd_device);
+
+ return ret;
+}
+
+static void __exit bf5xx_ad1938_exit(void)
+{
+ platform_device_unregister(bfxx_ad1938_snd_device);
+}
+
+module_init(bf5xx_ad1938_init);
+module_exit(bf5xx_ad1938_exit);
+
+/* Module information */
+MODULE_AUTHOR("Barry Song");
+MODULE_DESCRIPTION("ALSA SoC AD1938 board driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index edfbdc024e66..9825b71d0e28 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -203,23 +203,23 @@ static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
.codec_dev = &soc_codec_dev_ad73311,
};
-static struct platform_device *bf52x_ad73311_snd_device;
+static struct platform_device *bf5xx_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
- bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
- if (!bf52x_ad73311_snd_device)
+ bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!bf5xx_ad73311_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
- bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
- ret = platform_device_add(bf52x_ad73311_snd_device);
+ platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+ bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+ ret = platform_device_add(bf5xx_ad73311_snd_device);
if (ret)
- platform_device_put(bf52x_ad73311_snd_device);
+ platform_device_put(bf5xx_ad73311_snd_device);
return ret;
}
@@ -227,7 +227,7 @@ static int __init bf5xx_ad73311_init(void)
static void __exit bf5xx_ad73311_exit(void)
{
pr_debug("%s enter\n", __func__);
- platform_device_unregister(bf52x_ad73311_snd_device);
+ platform_device_unregister(bf5xx_ad73311_snd_device);
}
module_init(bf5xx_ad73311_init);
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index af06904bab0f..876abade27e1 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -259,22 +259,18 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
if (!dai->active)
return 0;
- ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0);
+ ret = sport_config_rx(sport, RFSR | RCKFE, RSFSE|0x1f, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0);
+ ret = sport_config_tx(sport, TFSR | TCKFE, TSFSE|0x1f, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- if (dai->capture.active)
- sport_rx_start(sport);
- if (dai->playback.active)
- sport_tx_start(sport);
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index bc0cdded7116..3a00fa4dbe6d 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -148,24 +148,24 @@ static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
.codec_data = &bf5xx_ssm2602_setup,
};
-static struct platform_device *bf52x_ssm2602_snd_device;
+static struct platform_device *bf5xx_ssm2602_snd_device;
static int __init bf5xx_ssm2602_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
- bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
- if (!bf52x_ssm2602_snd_device)
+ bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!bf5xx_ssm2602_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf52x_ssm2602_snd_device,
+ platform_set_drvdata(bf5xx_ssm2602_snd_device,
&bf5xx_ssm2602_snd_devdata);
- bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev;
- ret = platform_device_add(bf52x_ssm2602_snd_device);
+ bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+ ret = platform_device_add(bf5xx_ssm2602_snd_device);
if (ret)
- platform_device_put(bf52x_ssm2602_snd_device);
+ platform_device_put(bf5xx_ssm2602_snd_device);
return ret;
}
@@ -173,7 +173,7 @@ static int __init bf5xx_ssm2602_init(void)
static void __exit bf5xx_ssm2602_exit(void)
{
pr_debug("%s enter\n", __func__);
- platform_device_unregister(bf52x_ssm2602_snd_device);
+ platform_device_unregister(bf5xx_ssm2602_snd_device);
}
module_init(bf5xx_ssm2602_init);
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
new file mode 100644
index 000000000000..af7fa8d7ff0d
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -0,0 +1,330 @@
+/*
+ * File: sound/soc/blackfin/bf5xx-tdm-pcm.c
+ * Author: Barry Song <Barry.Song@analog.com>
+ *
+ * Created: Tue June 06 2009
+ * Description: DMA driver for tdm codec
+ *
+ * Modified:
+ * Copyright 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "bf5xx-tdm-pcm.h"
+#include "bf5xx-tdm.h"
+#include "bf5xx-sport.h"
+
+#define PCM_BUFFER_MAX 0x10000
+#define FRAGMENT_SIZE_MIN (4*1024)
+#define FRAGMENTS_MIN 2
+#define FRAGMENTS_MAX 32
+
+static void bf5xx_dma_irq(void *data)
+{
+ struct snd_pcm_substream *pcm = data;
+ snd_pcm_period_elapsed(pcm);
+}
+
+static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .channels_min = 2,
+ .channels_max = 8,
+ .buffer_bytes_max = PCM_BUFFER_MAX,
+ .period_bytes_min = FRAGMENT_SIZE_MIN,
+ .period_bytes_max = PCM_BUFFER_MAX/2,
+ .periods_min = FRAGMENTS_MIN,
+ .periods_max = FRAGMENTS_MAX,
+};
+
+static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+ snd_pcm_lib_malloc_pages(substream, size * 4);
+
+ return 0;
+}
+
+static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+
+ return 0;
+}
+
+static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sport_device *sport = runtime->private_data;
+ int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
+
+ fragsize_bytes /= runtime->channels;
+ /* inflate the fragsize to match the dma width of SPORT */
+ fragsize_bytes *= 8;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
+ sport_config_tx_dma(sport, runtime->dma_area,
+ runtime->periods, fragsize_bytes);
+ } else {
+ sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
+ sport_config_rx_dma(sport, runtime->dma_area,
+ runtime->periods, fragsize_bytes);
+ }
+
+ return 0;
+}
+
+static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sport_device *sport = runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sport_tx_start(sport);
+ else
+ sport_rx_start(sport);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sport_tx_stop(sport);
+ else
+ sport_rx_stop(sport);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sport_device *sport = runtime->private_data;
+ unsigned int diff;
+ snd_pcm_uframes_t frames;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ diff = sport_curr_offset_tx(sport);
+ frames = diff / (8*4); /* 32 bytes per frame */
+ } else {
+ diff = sport_curr_offset_rx(sport);
+ frames = diff / (8*4);
+ }
+ return frames;
+}
+
+static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret = 0;
+
+ snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ goto out;
+
+ if (sport_handle != NULL)
+ runtime->private_data = sport_handle;
+ else {
+ pr_err("sport_handle is NULL\n");
+ ret = -ENODEV;
+ }
+out:
+ return ret;
+}
+
+static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+ snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
+{
+ unsigned int *src;
+ unsigned int *dst;
+ int i;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ src = buf;
+ dst = (unsigned int *)substream->runtime->dma_area;
+
+ dst += pos * 8;
+ while (count--) {
+ for (i = 0; i < substream->runtime->channels; i++)
+ *(dst + i) = *src++;
+ dst += 8;
+ }
+ } else {
+ src = (unsigned int *)substream->runtime->dma_area;
+ dst = buf;
+
+ src += pos * 8;
+ while (count--) {
+ for (i = 0; i < substream->runtime->channels; i++)
+ *dst++ = *(src+i);
+ src += 8;
+ }
+ }
+
+ return 0;
+}
+
+static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+ unsigned char *buf = substream->runtime->dma_area;
+ buf += pos * 8 * 4;
+ memset(buf, '\0', count * 8 * 4);
+
+ return 0;
+}
+
+
+struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
+ .open = bf5xx_pcm_open,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = bf5xx_pcm_hw_params,
+ .hw_free = bf5xx_pcm_hw_free,
+ .prepare = bf5xx_pcm_prepare,
+ .trigger = bf5xx_pcm_trigger,
+ .pointer = bf5xx_pcm_pointer,
+ .copy = bf5xx_pcm_copy,
+ .silence = bf5xx_pcm_silence,
+};
+
+static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area) {
+ pr_err("Failed to allocate dma memory \
+ Please increase uncached DMA memory region\n");
+ return -ENOMEM;
+ }
+ buf->bytes = size;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sport_handle->tx_buf = buf->area;
+ else
+ sport_handle->rx_buf = buf->area;
+
+ return 0;
+}
+
+static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+ dma_free_coherent(NULL, buf->bytes, buf->area, 0);
+ buf->area = NULL;
+ }
+ if (sport_handle)
+ sport_done(sport_handle);
+}
+
+static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK;
+
+static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &bf5xx_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+ if (dai->playback.channels_min) {
+ ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+struct snd_soc_platform bf5xx_tdm_soc_platform = {
+ .name = "bf5xx-audio",
+ .pcm_ops = &bf5xx_pcm_tdm_ops,
+ .pcm_new = bf5xx_pcm_tdm_new,
+ .pcm_free = bf5xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
+
+static int __init bfin_pcm_tdm_init(void)
+{
+ return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+}
+module_init(bfin_pcm_tdm_init);
+
+static void __exit bfin_pcm_tdm_exit(void)
+{
+ snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+}
+module_exit(bfin_pcm_tdm_exit);
+
+MODULE_AUTHOR("Barry Song");
+MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
new file mode 100644
index 000000000000..9e8473d1c389
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h
@@ -0,0 +1,21 @@
+/*
+ * linux/sound/arm/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin
+ *
+ * Copyright 2009 Analog Device Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _BF5XX_TDM_PCM_H
+#define _BF5XX_TDM_PCM_H
+
+struct bf5xx_pcm_dma_params {
+ char *name; /* stream identifier */
+};
+
+/* platform data */
+extern struct snd_soc_platform bf5xx_tdm_soc_platform;
+
+#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
new file mode 100644
index 000000000000..3096badf09a5
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -0,0 +1,343 @@
+/*
+ * File: sound/soc/blackfin/bf5xx-tdm.c
+ * Author: Barry Song <Barry.Song@analog.com>
+ *
+ * Created: Thurs June 04 2009
+ * Description: Blackfin I2S(TDM) CPU DAI driver
+ * Even though TDM mode can be as part of I2S DAI, but there
+ * are so much difference in configuration and data flow,
+ * it's very ugly to integrate I2S and TDM into a module
+ *
+ * Modified:
+ * Copyright 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <asm/portmux.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#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;
+
+static struct sport_param sport_params[2] = {
+ {
+ .dma_rx_chan = CH_SPORT0_RX,
+ .dma_tx_chan = CH_SPORT0_TX,
+ .err_irq = IRQ_SPORT0_ERROR,
+ .regs = (struct sport_register *)SPORT0_TCR1,
+ },
+ {
+ .dma_rx_chan = CH_SPORT1_RX,
+ .dma_tx_chan = CH_SPORT1_TX,
+ .err_irq = IRQ_SPORT1_ERROR,
+ .regs = (struct sport_register *)SPORT1_TCR1,
+ }
+};
+
+/*
+ * Setting the TFS pin selector for SPORT 0 based on whether the selected
+ * port id F or G. If the port is F then no conflict should exist for the
+ * TFS. When Port G is selected and EMAC then there is a conflict between
+ * the PHY interrupt line and TFS. Current settings prevent the conflict
+ * by ignoring the TFS pin when Port G is selected. This allows both
+ * ssm2602 using Port G and EMAC concurrently.
+ */
+#ifdef CONFIG_BF527_SPORT0_PORTF
+#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
+#else
+#define LOCAL_SPORT0_TFS (0)
+#endif
+
+static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
+ {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
+ P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
+
+static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ int ret = 0;
+
+ /* interface format:support TDM,slave mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ break;
+ default:
+ printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ ret = -EINVAL;
+ break;
+ default:
+ printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ bf5xx_tdm.tcr2 &= ~0x1f;
+ bf5xx_tdm.rcr2 &= ~0x1f;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bf5xx_tdm.tcr2 |= 31;
+ bf5xx_tdm.rcr2 |= 31;
+ sport_handle->wdsize = 4;
+ break;
+ /* at present, we only support 32bit transfer */
+ default:
+ pr_err("not supported PCM format yet\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (!bf5xx_tdm.configured) {
+ /*
+ * TX and RX are not independent,they are enabled at the
+ * same time, even if only one side is running. So, we
+ * need to configure both of them at the time when the first
+ * stream is opened.
+ *
+ * CPU DAI:slave mode.
+ */
+ ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
+ bf5xx_tdm.rcr2, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ return -EBUSY;
+ }
+
+ ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
+ bf5xx_tdm.tcr2, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ return -EBUSY;
+ }
+
+ bf5xx_tdm.configured = 1;
+ }
+
+ return 0;
+}
+
+static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ /* No active stream, SPORT is allowed to be configured again. */
+ if (!dai->active)
+ bf5xx_tdm.configured = 0;
+}
+
+#ifdef CONFIG_PM
+static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
+{
+ struct sport_device *sport =
+ (struct sport_device *)dai->private_data;
+
+ if (!dai->active)
+ return 0;
+ if (dai->capture.active)
+ sport_rx_stop(sport);
+ if (dai->playback.active)
+ sport_tx_stop(sport);
+ return 0;
+}
+
+static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
+{
+ int ret;
+ struct sport_device *sport =
+ (struct sport_device *)dai->private_data;
+
+ if (!dai->active)
+ return 0;
+
+ ret = sport_set_multichannel(sport, 8, 0xFF, 1);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ }
+
+ ret = sport_config_rx(sport, IRFS, 0x1F, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ }
+
+ ret = sport_config_tx(sport, ITFS, 0x1F, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ }
+
+ return 0;
+}
+
+#else
+#define bf5xx_tdm_suspend NULL
+#define bf5xx_tdm_resume NULL
+#endif
+
+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,
+};
+
+struct snd_soc_dai bf5xx_tdm_dai = {
+ .name = "bf5xx-tdm",
+ .id = 0,
+ .suspend = bf5xx_tdm_suspend,
+ .resume = bf5xx_tdm_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,},
+ .ops = &bf5xx_tdm_dai_ops,
+};
+EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
+
+static int __devinit bfin_tdm_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+ pr_err("Requesting Peripherals failed\n");
+ return -EFAULT;
+ }
+
+ /* request DMA for SPORT */
+ sport_handle = sport_init(&sport_params[sport_num], 4, \
+ 8 * sizeof(u32), NULL);
+ if (!sport_handle) {
+ peripheral_free_list(&sport_req[sport_num][0]);
+ return -ENODEV;
+ }
+
+ /* SPORT works in TDM mode */
+ ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ goto sport_config_err;
+ }
+
+ ret = sport_config_rx(sport_handle, IRFS, 0x1F, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ goto sport_config_err;
+ }
+
+ ret = sport_config_tx(sport_handle, ITFS, 0x1F, 0, 0);
+ if (ret) {
+ pr_err("SPORT is busy!\n");
+ ret = -EBUSY;
+ goto sport_config_err;
+ }
+
+ ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+ if (ret) {
+ pr_err("Failed to register DAI: %d\n", ret);
+ goto sport_config_err;
+ }
+ return 0;
+
+sport_config_err:
+ peripheral_free_list(&sport_req[sport_num][0]);
+ return ret;
+}
+
+static int __devexit bfin_tdm_remove(struct platform_device *pdev)
+{
+ peripheral_free_list(&sport_req[sport_num][0]);
+ snd_soc_unregister_dai(&bf5xx_tdm_dai);
+
+ return 0;
+}
+
+static struct platform_driver bfin_tdm_driver = {
+ .probe = bfin_tdm_probe,
+ .remove = __devexit_p(bfin_tdm_remove),
+ .driver = {
+ .name = "bfin-tdm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bfin_tdm_init(void)
+{
+ return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(bfin_tdm_init);
+
+static void __exit bfin_tdm_exit(void)
+{
+ platform_driver_unregister(&bfin_tdm_driver);
+}
+module_exit(bfin_tdm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Barry Song");
+MODULE_DESCRIPTION("TDM driver for ADI Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
new file mode 100644
index 000000000000..e5157cd81c5e
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-tdm.h
@@ -0,0 +1,14 @@
+/*
+ * linux/sound/arm/bf5xx-i2s.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _BF5XX_TDM_H
+#define _BF5XX_TDM_H
+
+extern struct snd_soc_dai bf5xx_tdm_dai;
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bbc97fd76648..fdfc5024e404 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -12,11 +12,13 @@ config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
select SND_SOC_L3
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+ select SND_SOC_AD1938 if SPI_MASTER
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311 if I2C
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_CS4270 if I2C
+ select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
select SND_SOC_SSM2602 if I2C
@@ -30,6 +32,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400
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_WM8728 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
@@ -39,9 +42,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8940 if I2C
select SND_SOC_WM8960 if I2C
+ select SND_SOC_WM8961 if I2C
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
+ select SND_SOC_WM8993 if I2C
select SND_SOC_WM9081 if I2C
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
@@ -62,6 +67,9 @@ config SND_SOC_AC97_CODEC
tristate
select SND_AC97_CODEC
+config SND_SOC_AD1938
+ tristate
+
config SND_SOC_AD1980
tristate
@@ -86,6 +94,9 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_CX20442
+ tristate
+
config SND_SOC_L3
tristate
@@ -129,6 +140,9 @@ config SND_SOC_WM8400
config SND_SOC_WM8510
tristate
+config SND_SOC_WM8523
+ tristate
+
config SND_SOC_WM8580
tristate
@@ -156,6 +170,9 @@ config SND_SOC_WM8940
config SND_SOC_WM8960
tristate
+config SND_SOC_WM8961
+ tristate
+
config SND_SOC_WM8971
tristate
@@ -165,6 +182,9 @@ config SND_SOC_WM8988
config SND_SOC_WM8990
tristate
+config SND_SOC_WM8993
+ tristate
+
config SND_SOC_WM9081
tristate
@@ -176,3 +196,7 @@ config SND_SOC_WM9712
config SND_SOC_WM9713
tristate
+
+# Amp
+config SND_SOC_MAX9877
+ tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8b7530546f4d..1131d6dc761b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,9 +1,11 @@
snd-soc-ac97-objs := ac97.o
+snd-soc-ad1938-objs := ad1938.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-cx20442-objs := cx20442.o
snd-soc-l3-objs := l3.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
@@ -18,6 +20,7 @@ snd-soc-uda1380-objs := uda1380.o
snd-soc-wm8350-objs := wm8350.o
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-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
@@ -27,20 +30,27 @@ snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8940-objs := wm8940.o
snd-soc-wm8960-objs := wm8960.o
+snd-soc-wm8961-objs := wm8961.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm8993-objs := wm8993.o
snd-soc-wm9081-objs := wm9081.o
snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
+# Amp
+snd-soc-max9877-objs := max9877.o
+
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
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_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
@@ -55,6 +65,7 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
+obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
@@ -65,9 +76,14 @@ obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
+obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
+
+# Amp
+obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
new file mode 100644
index 000000000000..ffc97c9b797f
--- /dev/null
+++ b/sound/soc/codecs/ad1938.c
@@ -0,0 +1,652 @@
+/*
+ * File: sound/soc/codecs/ad1938.c
+ * Author: Barry Song <Barry.Song@analog.com>
+ *
+ * Created: June 04 2009
+ * Description: Driver for AD1938 sound chip
+ *
+ * Modified:
+ * Copyright 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include <linux/spi/spi.h>
+#include "ad1938.h"
+
+/* codec private data */
+struct ad1938_priv {
+ struct snd_soc_codec codec;
+ u8 reg_cache[AD1938_NUM_REGS];
+};
+
+static struct snd_soc_codec *ad1938_codec;
+struct snd_soc_codec_device soc_codec_dev_ad1938;
+static int ad1938_register(struct ad1938_priv *ad1938);
+static void ad1938_unregister(struct ad1938_priv *ad1938);
+
+/*
+ * AD1938 volume/mute/de-emphasis etc. controls
+ */
+static const char *ad1938_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
+
+static const struct soc_enum ad1938_deemp_enum =
+ SOC_ENUM_SINGLE(AD1938_DAC_CTRL2, 1, 4, ad1938_deemp);
+
+static const struct snd_kcontrol_new ad1938_snd_controls[] = {
+ /* DAC volume control */
+ SOC_DOUBLE_R("DAC1 Volume", AD1938_DAC_L1_VOL,
+ AD1938_DAC_R1_VOL, 0, 0xFF, 1),
+ SOC_DOUBLE_R("DAC2 Volume", AD1938_DAC_L2_VOL,
+ AD1938_DAC_R2_VOL, 0, 0xFF, 1),
+ SOC_DOUBLE_R("DAC3 Volume", AD1938_DAC_L3_VOL,
+ AD1938_DAC_R3_VOL, 0, 0xFF, 1),
+ SOC_DOUBLE_R("DAC4 Volume", AD1938_DAC_L4_VOL,
+ AD1938_DAC_R4_VOL, 0, 0xFF, 1),
+
+ /* ADC switch control */
+ SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE, AD1938_ADCR1_MUTE, 1, 1),
+ SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE, AD1938_ADCR2_MUTE, 1, 1),
+
+ /* DAC switch control */
+ SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE, AD1938_DACR1_MUTE, 1, 1),
+ SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE, AD1938_DACR2_MUTE, 1, 1),
+ SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE, AD1938_DACR3_MUTE, 1, 1),
+ SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE, AD1938_DACR4_MUTE, 1, 1),
+
+ /* ADC high-pass filter */
+ SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0,
+ AD1938_ADC_HIGHPASS_FILTER, 1, 0),
+
+ /* DAC de-emphasis */
+ SOC_ENUM("Playback Deemphasis", ad1938_deemp_enum),
+};
+
+static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
+ SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+ { "DAC", NULL, "ADC_PWR" },
+ { "ADC", NULL, "ADC_PWR" },
+};
+
+/*
+ * DAI ops entries
+ */
+
+static int ad1938_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int reg;
+
+ reg = codec->read(codec, AD1938_DAC_CTRL2);
+ reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & (~AD1938_DAC_MASTER_MUTE);
+ codec->write(codec, AD1938_DAC_CTRL2, reg);
+
+ return 0;
+}
+
+static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
+{
+ int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
+ reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | AD1938_PLL_POWERDOWN;
+ codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
+
+ return 0;
+}
+
+static int ad1938_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int mask, int slots)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
+ int adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
+
+ dac_reg &= ~AD1938_DAC_CHAN_MASK;
+ adc_reg &= ~AD1938_ADC_CHAN_MASK;
+
+ switch (slots) {
+ case 2:
+ dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT;
+ adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT;
+ break;
+ case 4:
+ dac_reg |= AD1938_DAC_4_CHANNELS << AD1938_DAC_CHAN_SHFT;
+ adc_reg |= AD1938_ADC_4_CHANNELS << AD1938_ADC_CHAN_SHFT;
+ break;
+ case 8:
+ dac_reg |= AD1938_DAC_8_CHANNELS << AD1938_DAC_CHAN_SHFT;
+ adc_reg |= AD1938_ADC_8_CHANNELS << AD1938_ADC_CHAN_SHFT;
+ break;
+ case 16:
+ dac_reg |= AD1938_DAC_16_CHANNELS << AD1938_DAC_CHAN_SHFT;
+ adc_reg |= AD1938_ADC_16_CHANNELS << AD1938_ADC_CHAN_SHFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
+ codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
+
+ return 0;
+}
+
+static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int adc_reg, dac_reg;
+
+ adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
+ dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
+
+ /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S with TDM)
+ * and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
+ */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ adc_reg &= ~AD1938_ADC_SERFMT_MASK;
+ adc_reg |= AD1938_ADC_SERFMT_TDM;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ adc_reg &= ~AD1938_ADC_SERFMT_MASK;
+ adc_reg |= AD1938_ADC_SERFMT_AUX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+ adc_reg &= ~AD1938_ADC_LEFT_HIGH;
+ adc_reg &= ~AD1938_ADC_BCLK_INV;
+ dac_reg &= ~AD1938_DAC_LEFT_HIGH;
+ dac_reg &= ~AD1938_DAC_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
+ adc_reg |= AD1938_ADC_LEFT_HIGH;
+ adc_reg &= ~AD1938_ADC_BCLK_INV;
+ dac_reg |= AD1938_DAC_LEFT_HIGH;
+ dac_reg &= ~AD1938_DAC_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
+ adc_reg &= ~AD1938_ADC_LEFT_HIGH;
+ adc_reg |= AD1938_ADC_BCLK_INV;
+ dac_reg &= ~AD1938_DAC_LEFT_HIGH;
+ dac_reg |= AD1938_DAC_BCLK_INV;
+ break;
+
+ case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
+ adc_reg |= AD1938_ADC_LEFT_HIGH;
+ adc_reg |= AD1938_ADC_BCLK_INV;
+ dac_reg |= AD1938_DAC_LEFT_HIGH;
+ dac_reg |= AD1938_DAC_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
+ adc_reg |= AD1938_ADC_LCR_MASTER;
+ adc_reg |= AD1938_ADC_BCLK_MASTER;
+ dac_reg |= AD1938_DAC_LCR_MASTER;
+ dac_reg |= AD1938_DAC_BCLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
+ adc_reg |= AD1938_ADC_LCR_MASTER;
+ adc_reg &= ~AD1938_ADC_BCLK_MASTER;
+ dac_reg |= AD1938_DAC_LCR_MASTER;
+ dac_reg &= ~AD1938_DAC_BCLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+ adc_reg &= ~AD1938_ADC_LCR_MASTER;
+ adc_reg |= AD1938_ADC_BCLK_MASTER;
+ dac_reg &= ~AD1938_DAC_LCR_MASTER;
+ dac_reg |= AD1938_DAC_BCLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
+ adc_reg &= ~AD1938_ADC_LCR_MASTER;
+ adc_reg &= ~AD1938_ADC_BCLK_MASTER;
+ dac_reg &= ~AD1938_DAC_LCR_MASTER;
+ dac_reg &= ~AD1938_DAC_BCLK_MASTER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
+ codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
+
+ return 0;
+}
+
+static int ad1938_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int word_len = 0, reg = 0;
+
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word_len = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ word_len = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
+ word_len = 0;
+ break;
+ }
+
+ reg = codec->read(codec, AD1938_DAC_CTRL2);
+ reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
+ codec->write(codec, AD1938_DAC_CTRL2, reg);
+
+ reg = codec->read(codec, AD1938_ADC_CTRL1);
+ reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
+ codec->write(codec, AD1938_ADC_CTRL1, reg);
+
+ return 0;
+}
+
+static int ad1938_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ad1938_pll_powerctrl(codec, 1);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ ad1938_pll_powerctrl(codec, 0);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+/*
+ * interface to read/write ad1938 register
+ */
+
+#define AD1938_SPI_ADDR 0x4
+#define AD1938_SPI_READ 0x1
+#define AD1938_SPI_BUFLEN 3
+
+/*
+ * write to the ad1938 register space
+ */
+
+static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 *reg_cache = codec->reg_cache;
+ int ret = 0;
+
+ if (value != reg_cache[reg]) {
+ uint8_t buf[AD1938_SPI_BUFLEN];
+ struct spi_transfer t = {
+ .tx_buf = buf,
+ .len = AD1938_SPI_BUFLEN,
+ };
+ struct spi_message m;
+
+ buf[0] = AD1938_SPI_ADDR << 1;
+ buf[1] = reg;
+ buf[2] = value;
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ ret = spi_sync(codec->control_data, &m);
+ if (ret == 0)
+ reg_cache[reg] = value;
+ }
+
+ return ret;
+}
+
+/*
+ * read from the ad1938 register space cache
+ */
+
+static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 *reg_cache = codec->reg_cache;
+
+ if (reg >= codec->reg_cache_size)
+ return -EINVAL;
+
+ return reg_cache[reg];
+}
+
+/*
+ * read from the ad1938 register space
+ */
+
+static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, unsigned int reg)
+{
+ char w_buf[AD1938_SPI_BUFLEN];
+ char r_buf[AD1938_SPI_BUFLEN];
+ int ret;
+
+ struct spi_transfer t = {
+ .tx_buf = w_buf,
+ .rx_buf = r_buf,
+ .len = AD1938_SPI_BUFLEN,
+ };
+ struct spi_message m;
+
+ w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ;
+ w_buf[1] = reg;
+ w_buf[2] = 0;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ ret = spi_sync(codec->control_data, &m);
+ if (ret == 0)
+ return r_buf[2];
+ else
+ return -EIO;
+}
+
+static int ad1938_fill_cache(struct snd_soc_codec *codec)
+{
+ int i;
+ u8 *reg_cache = codec->reg_cache;
+ struct spi_device *spi = codec->control_data;
+
+ for (i = 0; i < codec->reg_cache_size; i++) {
+ int ret = ad1938_read_reg(codec, i);
+ if (ret == -EIO) {
+ dev_err(&spi->dev, "AD1938 SPI read failure\n");
+ return ret;
+ }
+ reg_cache[i] = ret;
+ }
+
+ return 0;
+}
+
+static int __devinit ad1938_spi_probe(struct spi_device *spi)
+{
+ struct snd_soc_codec *codec;
+ struct ad1938_priv *ad1938;
+
+ ad1938 = kzalloc(sizeof(struct ad1938_priv), GFP_KERNEL);
+ if (ad1938 == NULL)
+ return -ENOMEM;
+
+ codec = &ad1938->codec;
+ codec->control_data = spi;
+ codec->dev = &spi->dev;
+
+ dev_set_drvdata(&spi->dev, ad1938);
+
+ return ad1938_register(ad1938);
+}
+
+static int __devexit ad1938_spi_remove(struct spi_device *spi)
+{
+ struct ad1938_priv *ad1938 = dev_get_drvdata(&spi->dev);
+
+ ad1938_unregister(ad1938);
+ return 0;
+}
+
+static struct spi_driver ad1938_spi_driver = {
+ .driver = {
+ .name = "ad1938-spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad1938_spi_probe,
+ .remove = __devexit_p(ad1938_spi_remove),
+};
+
+static struct snd_soc_dai_ops ad1938_dai_ops = {
+ .hw_params = ad1938_hw_params,
+ .digital_mute = ad1938_mute,
+ .set_tdm_slot = ad1938_set_tdm_slot,
+ .set_fmt = ad1938_set_dai_fmt,
+};
+
+/* codec DAI instance */
+struct snd_soc_dai ad1938_dai = {
+ .name = "AD1938",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &ad1938_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ad1938_dai);
+
+static int ad1938_register(struct ad1938_priv *ad1938)
+{
+ int ret;
+ struct snd_soc_codec *codec = &ad1938->codec;
+
+ if (ad1938_codec) {
+ dev_err(codec->dev, "Another ad1938 is registered\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ codec->private_data = ad1938;
+ codec->reg_cache = ad1938->reg_cache;
+ codec->reg_cache_size = AD1938_NUM_REGS;
+ codec->name = "AD1938";
+ codec->owner = THIS_MODULE;
+ codec->dai = &ad1938_dai;
+ codec->num_dai = 1;
+ codec->write = ad1938_write_reg;
+ codec->read = ad1938_read_reg_cache;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ ad1938_dai.dev = codec->dev;
+ ad1938_codec = codec;
+
+ /* default setting for ad1938 */
+ codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); /* unmute dac channels */
+ codec->write(codec, AD1938_DAC_CTRL2, 0x1A); /* de-emphasis: 48kHz, powedown dac */
+ codec->write(codec, AD1938_DAC_CTRL0, 0x21); /* powerdown dac, dac tdm mode */
+ codec->write(codec, AD1938_ADC_CTRL0, 0x3); /* high-pass filter enable */
+ codec->write(codec, AD1938_ADC_CTRL1, 0x43); /* sata delay=1, adc aux mode */
+ codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); /* pll input:mclki/xi */
+ codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
+
+ ad1938_fill_cache(codec);
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&ad1938_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ad1938_unregister(struct ad1938_priv *ad1938)
+{
+ ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_dai(&ad1938_dai);
+ snd_soc_unregister_codec(&ad1938->codec);
+ kfree(ad1938);
+ ad1938_codec = NULL;
+}
+
+static int ad1938_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (ad1938_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = ad1938_codec;
+ codec = ad1938_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, ad1938_snd_controls,
+ ARRAY_SIZE(ad1938_snd_controls));
+ snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
+ ARRAY_SIZE(ad1938_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+ snd_soc_dapm_new_widgets(codec);
+
+ ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card: %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 ad1938_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ad1938_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;
+
+ ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int ad1938_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+ ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+ return 0;
+}
+#else
+#define ad1938_suspend NULL
+#define ad1938_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_ad1938 = {
+ .probe = ad1938_probe,
+ .remove = ad1938_remove,
+ .suspend = ad1938_suspend,
+ .resume = ad1938_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
+
+static int __init ad1938_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&ad1938_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register ad1938 SPI driver: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+module_init(ad1938_init);
+
+static void __exit ad1938_exit(void)
+{
+ spi_unregister_driver(&ad1938_spi_driver);
+}
+module_exit(ad1938_exit);
+
+MODULE_DESCRIPTION("ASoC ad1938 driver");
+MODULE_AUTHOR("Barry Song ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1938.h b/sound/soc/codecs/ad1938.h
new file mode 100644
index 000000000000..fe3c48cd2d5b
--- /dev/null
+++ b/sound/soc/codecs/ad1938.h
@@ -0,0 +1,100 @@
+/*
+ * File: sound/soc/codecs/ad1836.h
+ * Based on:
+ * Author: Barry Song <Barry.Song@analog.com>
+ *
+ * Created: May 25, 2009
+ * Description: definitions for AD1938 registers
+ *
+ * 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 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
+ */
+
+#ifndef __AD1938_H__
+#define __AD1938_H__
+
+#define AD1938_PLL_CLK_CTRL0 0
+#define AD1938_PLL_POWERDOWN 0x01
+#define AD1938_PLL_CLK_CTRL1 1
+#define AD1938_DAC_CTRL0 2
+#define AD1938_DAC_POWERDOWN 0x01
+#define AD1938_DAC_SERFMT_MASK 0xC0
+#define AD1938_DAC_SERFMT_STEREO (0 << 6)
+#define AD1938_DAC_SERFMT_TDM (1 << 6)
+#define AD1938_DAC_CTRL1 3
+#define AD1938_DAC_2_CHANNELS 0
+#define AD1938_DAC_4_CHANNELS 1
+#define AD1938_DAC_8_CHANNELS 2
+#define AD1938_DAC_16_CHANNELS 3
+#define AD1938_DAC_CHAN_SHFT 1
+#define AD1938_DAC_CHAN_MASK (3 << AD1938_DAC_CHAN_SHFT)
+#define AD1938_DAC_LCR_MASTER (1 << 4)
+#define AD1938_DAC_BCLK_MASTER (1 << 5)
+#define AD1938_DAC_LEFT_HIGH (1 << 3)
+#define AD1938_DAC_BCLK_INV (1 << 7)
+#define AD1938_DAC_CTRL2 4
+#define AD1938_DAC_WORD_LEN_MASK 0xC
+#define AD1938_DAC_MASTER_MUTE 1
+#define AD1938_DAC_CHNL_MUTE 5
+#define AD1938_DACL1_MUTE 0
+#define AD1938_DACR1_MUTE 1
+#define AD1938_DACL2_MUTE 2
+#define AD1938_DACR2_MUTE 3
+#define AD1938_DACL3_MUTE 4
+#define AD1938_DACR3_MUTE 5
+#define AD1938_DACL4_MUTE 6
+#define AD1938_DACR4_MUTE 7
+#define AD1938_DAC_L1_VOL 6
+#define AD1938_DAC_R1_VOL 7
+#define AD1938_DAC_L2_VOL 8
+#define AD1938_DAC_R2_VOL 9
+#define AD1938_DAC_L3_VOL 10
+#define AD1938_DAC_R3_VOL 11
+#define AD1938_DAC_L4_VOL 12
+#define AD1938_DAC_R4_VOL 13
+#define AD1938_ADC_CTRL0 14
+#define AD1938_ADC_POWERDOWN 0x01
+#define AD1938_ADC_HIGHPASS_FILTER 1
+#define AD1938_ADCL1_MUTE 2
+#define AD1938_ADCR1_MUTE 3
+#define AD1938_ADCL2_MUTE 4
+#define AD1938_ADCR2_MUTE 5
+#define AD1938_ADC_CTRL1 15
+#define AD1938_ADC_SERFMT_MASK 0x60
+#define AD1938_ADC_SERFMT_STEREO (0 << 5)
+#define AD1938_ADC_SERFMT_TDM (1 << 2)
+#define AD1938_ADC_SERFMT_AUX (2 << 5)
+#define AD1938_ADC_WORD_LEN_MASK 0x3
+#define AD1938_ADC_CTRL2 16
+#define AD1938_ADC_2_CHANNELS 0
+#define AD1938_ADC_4_CHANNELS 1
+#define AD1938_ADC_8_CHANNELS 2
+#define AD1938_ADC_16_CHANNELS 3
+#define AD1938_ADC_CHAN_SHFT 4
+#define AD1938_ADC_CHAN_MASK (3 << AD1938_ADC_CHAN_SHFT)
+#define AD1938_ADC_LCR_MASTER (1 << 3)
+#define AD1938_ADC_BCLK_MASTER (1 << 6)
+#define AD1938_ADC_LEFT_HIGH (1 << 2)
+#define AD1938_ADC_BCLK_INV (1 << 1)
+
+#define AD1938_NUM_REGS 17
+
+extern struct snd_soc_dai ad1938_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad1938;
+#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index dd3380202766..0abec0d29a96 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -59,21 +59,6 @@ static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec,
return cache[reg];
}
-static inline unsigned int ak4535_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u8 data;
- data = reg;
-
- if (codec->hw_write(codec->control_data, &data, 1) != 1)
- return -EIO;
-
- if (codec->hw_read(codec->control_data, &data, 1) != 1)
- return -EIO;
-
- return data;
-};
-
/*
* write ak4535 register cache
*/
@@ -635,7 +620,6 @@ static int ak4535_probe(struct platform_device *pdev)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
- codec->hw_read = (hw_read_t)i2c_master_recv;
ret = ak4535_add_i2c_device(pdev, setup);
}
#endif
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
new file mode 100644
index 000000000000..7bbb77baa231
--- /dev/null
+++ b/sound/soc/codecs/cx20442.c
@@ -0,0 +1,398 @@
+/*
+ * cx20442.c -- CX20442 ALSA Soc Audio driver
+ *
+ * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Initially based on sound/soc/codecs/wm8400.c
+ * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+
+#include "cx20442.h"
+
+
+struct cx20442_priv {
+ struct snd_soc_codec codec;
+ u8 reg_cache[1];
+};
+
+#define CX20442_PM 0x0
+
+#define CX20442_TELIN 0
+#define CX20442_TELOUT 1
+#define CX20442_MIC 2
+#define CX20442_SPKOUT 3
+#define CX20442_AGC 4
+
+static const struct snd_soc_dapm_widget cx20442_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("TELOUT"),
+ SND_SOC_DAPM_OUTPUT("SPKOUT"),
+ SND_SOC_DAPM_OUTPUT("AGCOUT"),
+
+ SND_SOC_DAPM_MIXER("SPKOUT Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("TELOUT Amp", CX20442_PM, CX20442_TELOUT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPKOUT Amp", CX20442_PM, CX20442_SPKOUT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPKOUT AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MICBIAS("TELIN Bias", CX20442_PM, CX20442_TELIN, 0),
+ SND_SOC_DAPM_MICBIAS("MIC Bias", CX20442_PM, CX20442_MIC, 0),
+
+ SND_SOC_DAPM_PGA("MIC AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("TELIN"),
+ SND_SOC_DAPM_INPUT("MIC"),
+ SND_SOC_DAPM_INPUT("AGCIN"),
+};
+
+static const struct snd_soc_dapm_route cx20442_audio_map[] = {
+ {"TELOUT", NULL, "TELOUT Amp"},
+
+ {"SPKOUT", NULL, "SPKOUT Mixer"},
+ {"SPKOUT Mixer", NULL, "SPKOUT Amp"},
+
+ {"TELOUT Amp", NULL, "DAC"},
+ {"SPKOUT Amp", NULL, "DAC"},
+
+ {"SPKOUT Mixer", NULL, "SPKOUT AGC"},
+ {"SPKOUT AGC", NULL, "AGCIN"},
+
+ {"AGCOUT", NULL, "MIC AGC"},
+ {"MIC AGC", NULL, "MIC"},
+
+ {"MIC Bias", NULL, "MIC"},
+ {"Input Mixer", NULL, "MIC Bias"},
+
+ {"TELIN Bias", NULL, "TELIN"},
+ {"Input Mixer", NULL, "TELIN Bias"},
+
+ {"ADC", NULL, "Input Mixer"},
+};
+
+static int cx20442_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets,
+ ARRAY_SIZE(cx20442_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, cx20442_audio_map,
+ ARRAY_SIZE(cx20442_audio_map));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 *reg_cache = codec->reg_cache;
+
+ if (reg >= codec->reg_cache_size)
+ return -EINVAL;
+
+ return reg_cache[reg];
+}
+
+enum v253_vls {
+ V253_VLS_NONE = 0,
+ V253_VLS_T,
+ V253_VLS_L,
+ V253_VLS_LT,
+ V253_VLS_S,
+ V253_VLS_ST,
+ V253_VLS_M,
+ V253_VLS_MST,
+ V253_VLS_S1,
+ V253_VLS_S1T,
+ V253_VLS_MS1T,
+ V253_VLS_M1,
+ V253_VLS_M1ST,
+ V253_VLS_M1S1T,
+ V253_VLS_H,
+ V253_VLS_HT,
+ V253_VLS_MS,
+ V253_VLS_MS1,
+ V253_VLS_M1S,
+ V253_VLS_M1S1,
+ V253_VLS_TEST,
+};
+
+static int cx20442_pm_to_v253_vls(u8 value)
+{
+ switch (value & ~(1 << CX20442_AGC)) {
+ case 0:
+ return V253_VLS_T;
+ case (1 << CX20442_SPKOUT):
+ return V253_VLS_S1;
+ case (1 << CX20442_MIC):
+ return V253_VLS_M1;
+ case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
+ return V253_VLS_M1S1;
+ case (1 << CX20442_TELOUT):
+ case (1 << CX20442_TELIN):
+ case (1 << CX20442_TELOUT) | (1 << CX20442_TELIN):
+ return V253_VLS_L;
+ case (1 << CX20442_TELOUT) | (1 << CX20442_MIC):
+ return V253_VLS_NONE;
+ }
+ return -EINVAL;
+}
+static int cx20442_pm_to_v253_vsp(u8 value)
+{
+ switch (value & ~(1 << CX20442_AGC)) {
+ case (1 << CX20442_SPKOUT):
+ case (1 << CX20442_MIC):
+ case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
+ return (bool)(value & (1 << CX20442_AGC));
+ }
+ return (value & (1 << CX20442_AGC)) ? -EINVAL : 0;
+}
+
+static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 *reg_cache = codec->reg_cache;
+ int vls, vsp, old, len;
+ char buf[18];
+
+ if (reg >= codec->reg_cache_size)
+ return -EINVAL;
+
+ /* hw_write and control_data pointers required for talking to the modem
+ * are expected to be set by the machine driver's line discipline
+ * initialization code */
+ if (!codec->hw_write || !codec->control_data)
+ return -EIO;
+
+ old = reg_cache[reg];
+ reg_cache[reg] = value;
+
+ vls = cx20442_pm_to_v253_vls(value);
+ if (vls < 0)
+ return vls;
+
+ vsp = cx20442_pm_to_v253_vsp(value);
+ if (vsp < 0)
+ return vsp;
+
+ if ((vls == V253_VLS_T) ||
+ (vls == cx20442_pm_to_v253_vls(old))) {
+ if (vsp == cx20442_pm_to_v253_vsp(old))
+ return 0;
+ len = snprintf(buf, ARRAY_SIZE(buf), "at+vsp=%d\r", vsp);
+ } else if (vsp == cx20442_pm_to_v253_vsp(old))
+ len = snprintf(buf, ARRAY_SIZE(buf), "at+vls=%d\r", vls);
+ else
+ len = snprintf(buf, ARRAY_SIZE(buf),
+ "at+vls=%d;+vsp=%d\r", vls, vsp);
+
+ if (unlikely(len > (ARRAY_SIZE(buf) - 1)))
+ return -ENOMEM;
+
+ if (codec->hw_write(codec->control_data, buf, len) != len)
+ return -EIO;
+
+ return 0;
+}
+
+struct snd_soc_dai cx20442_dai = {
+ .name = "CX20442",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+};
+EXPORT_SYMBOL_GPL(cx20442_dai);
+
+static struct snd_soc_codec *cx20442_codec;
+
+static int cx20442_codec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (!cx20442_codec) {
+ dev_err(&pdev->dev, "cx20442 not yet discovered\n");
+ return -ENODEV;
+ }
+ codec = cx20442_codec;
+
+ socdev->card->codec = codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ cx20442_add_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ return ret;
+}
+
+/* power down chip */
+static int cx20442_codec_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 cx20442_codec_dev = {
+ .probe = cx20442_codec_probe,
+ .remove = cx20442_codec_remove,
+};
+EXPORT_SYMBOL_GPL(cx20442_codec_dev);
+
+static int cx20442_register(struct cx20442_priv *cx20442)
+{
+ struct snd_soc_codec *codec = &cx20442->codec;
+ int ret;
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "CX20442";
+ codec->owner = THIS_MODULE;
+ codec->private_data = cx20442;
+
+ codec->dai = &cx20442_dai;
+ codec->num_dai = 1;
+
+ codec->reg_cache = &cx20442->reg_cache;
+ codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
+ codec->read = cx20442_read_reg_cache;
+ codec->write = cx20442_write;
+
+ codec->bias_level = SND_SOC_BIAS_OFF;
+
+ cx20442_dai.dev = codec->dev;
+
+ cx20442_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(&codec->dev, "Failed to register codec: %d\n", ret);
+ goto err;
+ }
+
+ ret = snd_soc_register_dai(&cx20442_dai);
+ if (ret != 0) {
+ dev_err(&codec->dev, "Failed to register DAI: %d\n", ret);
+ goto err_codec;
+ }
+
+ return 0;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ cx20442_codec = NULL;
+ kfree(cx20442);
+ return ret;
+}
+
+static void cx20442_unregister(struct cx20442_priv *cx20442)
+{
+ snd_soc_unregister_dai(&cx20442_dai);
+ snd_soc_unregister_codec(&cx20442->codec);
+
+ cx20442_codec = NULL;
+ kfree(cx20442);
+}
+
+static int cx20442_platform_probe(struct platform_device *pdev)
+{
+ struct cx20442_priv *cx20442;
+ struct snd_soc_codec *codec;
+
+ cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+ if (cx20442 == NULL)
+ return -ENOMEM;
+
+ codec = &cx20442->codec;
+
+ codec->control_data = NULL;
+ codec->hw_write = NULL;
+ codec->pop_time = 0;
+
+ codec->dev = &pdev->dev;
+ platform_set_drvdata(pdev, cx20442);
+
+ return cx20442_register(cx20442);
+}
+
+static int __exit cx20442_platform_remove(struct platform_device *pdev)
+{
+ struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
+
+ cx20442_unregister(cx20442);
+ return 0;
+}
+
+static struct platform_driver cx20442_platform_driver = {
+ .driver = {
+ .name = "cx20442",
+ .owner = THIS_MODULE,
+ },
+ .probe = cx20442_platform_probe,
+ .remove = __exit_p(cx20442_platform_remove),
+};
+
+static int __init cx20442_init(void)
+{
+ return platform_driver_register(&cx20442_platform_driver);
+}
+module_init(cx20442_init);
+
+static void __exit cx20442_exit(void)
+{
+ platform_driver_unregister(&cx20442_platform_driver);
+}
+module_exit(cx20442_exit);
+
+MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
+MODULE_AUTHOR("Janusz Krzysztofik");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cx20442");
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
new file mode 100644
index 000000000000..d0a4f297aef4
--- /dev/null
+++ b/sound/soc/codecs/cx20442.h
@@ -0,0 +1,19 @@
+/*
+ * cx20442.h -- audio driver for CX20442
+ *
+ * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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 _CX20442_CODEC_H
+#define _CX20442_CODEC_H
+
+extern struct snd_soc_dai cx20442_dai;
+extern struct snd_soc_codec_device cx20442_codec_dev;
+
+#endif
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
new file mode 100644
index 000000000000..9e7e964a5fa3
--- /dev/null
+++ b/sound/soc/codecs/max9877.c
@@ -0,0 +1,308 @@
+/*
+ * max9877.c -- amp driver for max9877
+ *
+ * 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 <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "max9877.h"
+
+static struct i2c_client *i2c;
+
+static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 };
+
+static void max9877_write_regs(void)
+{
+ unsigned int i;
+ u8 data[6];
+
+ data[0] = MAX9877_INPUT_MODE;
+ for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
+ data[i + 1] = max9877_regs[i];
+
+ if (i2c_master_send(i2c, data, 6) != 6)
+ dev_err(&i2c->dev, "i2c write failed\n");
+}
+
+static int max9877_get_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = mc->max;
+ unsigned int invert = mc->invert;
+
+ ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
+
+ if (invert)
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int max9877_set_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ 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);
+
+ if (invert)
+ val = mask - val;
+
+ if (((max9877_regs[reg] >> shift) & mask) == val)
+ return 0;
+
+ max9877_regs[reg] &= ~(mask << shift);
+ max9877_regs[reg] |= val << shift;
+ max9877_write_regs();
+
+ return 1;
+}
+
+static int max9877_get_2reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = mc->max;
+
+ ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
+ ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask;
+
+ return 0;
+}
+
+static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = mc->max;
+ unsigned int val = (ucontrol->value.integer.value[0] & mask);
+ unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
+ unsigned int change = 1;
+
+ if (((max9877_regs[reg] >> shift) & mask) == val)
+ change = 0;
+
+ if (((max9877_regs[reg2] >> shift) & mask) == val2)
+ change = 0;
+
+ if (change) {
+ max9877_regs[reg] &= ~(mask << shift);
+ max9877_regs[reg] |= val << shift;
+ max9877_regs[reg2] &= ~(mask << shift);
+ max9877_regs[reg2] |= val2 << shift;
+ max9877_write_regs();
+ }
+
+ return change;
+}
+
+static int max9877_get_out_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK;
+
+ if (value)
+ value -= 1;
+
+ ucontrol->value.integer.value[0] = value;
+ return 0;
+}
+
+static int max9877_set_out_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = ucontrol->value.integer.value[0];
+
+ value += 1;
+
+ if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value)
+ return 0;
+
+ max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK;
+ max9877_regs[MAX9877_OUTPUT_MODE] |= value;
+ max9877_write_regs();
+ return 1;
+}
+
+static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK);
+
+ value = value >> MAX9877_OSC_OFFSET;
+
+ ucontrol->value.integer.value[0] = value;
+ return 0;
+}
+
+static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = ucontrol->value.integer.value[0];
+
+ value = value << MAX9877_OSC_OFFSET;
+ if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value)
+ return 0;
+
+ max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK;
+ max9877_regs[MAX9877_OUTPUT_MODE] |= value;
+ max9877_write_regs();
+ return 1;
+}
+
+static const unsigned int max9877_pgain_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0),
+};
+
+static const unsigned int max9877_output_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
+ 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
+ 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
+ 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
+};
+
+static const char *max9877_out_mode[] = {
+ "INA -> SPK",
+ "INA -> HP",
+ "INA -> SPK and HP",
+ "INB -> SPK",
+ "INB -> HP",
+ "INB -> SPK and HP",
+ "INA + INB -> SPK",
+ "INA + INB -> HP",
+ "INA + INB -> SPK and HP",
+};
+
+static const char *max9877_osc_mode[] = {
+ "1176KHz",
+ "1100KHz",
+ "700KHz",
+};
+
+static const struct soc_enum max9877_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
+};
+
+static const struct snd_kcontrol_new max9877_controls[] = {
+ SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
+ MAX9877_INPUT_MODE, 0, 2, 0,
+ max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
+ SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
+ MAX9877_INPUT_MODE, 2, 2, 0,
+ max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
+ SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
+ MAX9877_SPK_VOLUME, 0, 31, 0,
+ max9877_get_reg, max9877_set_reg, max9877_output_tlv),
+ SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
+ MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
+ max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
+ SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
+ MAX9877_INPUT_MODE, 4, 1, 1,
+ max9877_get_reg, max9877_set_reg),
+ SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
+ MAX9877_INPUT_MODE, 5, 1, 1,
+ max9877_get_reg, max9877_set_reg),
+ SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
+ MAX9877_INPUT_MODE, 6, 1, 0,
+ max9877_get_reg, max9877_set_reg),
+ SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch",
+ MAX9877_OUTPUT_MODE, 6, 1, 0,
+ max9877_get_reg, max9877_set_reg),
+ SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch",
+ MAX9877_OUTPUT_MODE, 7, 1, 1,
+ max9877_get_reg, max9877_set_reg),
+ SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0],
+ max9877_get_out_mode, max9877_set_out_mode),
+ SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1],
+ max9877_get_osc_mode, max9877_set_osc_mode),
+};
+
+/* This function is called from ASoC machine driver */
+int max9877_add_controls(struct snd_soc_codec *codec)
+{
+ return snd_soc_add_controls(codec, max9877_controls,
+ ARRAY_SIZE(max9877_controls));
+}
+EXPORT_SYMBOL_GPL(max9877_add_controls);
+
+static int __devinit max9877_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ i2c = client;
+
+ max9877_write_regs();
+
+ return 0;
+}
+
+static __devexit int max9877_i2c_remove(struct i2c_client *client)
+{
+ i2c = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id max9877_i2c_id[] = {
+ { "max9877", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
+
+static struct i2c_driver max9877_i2c_driver = {
+ .driver = {
+ .name = "max9877",
+ .owner = THIS_MODULE,
+ },
+ .probe = max9877_i2c_probe,
+ .remove = __devexit_p(max9877_i2c_remove),
+ .id_table = max9877_i2c_id,
+};
+
+static int __init max9877_init(void)
+{
+ return i2c_add_driver(&max9877_i2c_driver);
+}
+module_init(max9877_init);
+
+static void __exit max9877_exit(void)
+{
+ i2c_del_driver(&max9877_i2c_driver);
+}
+module_exit(max9877_exit);
+
+MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9877.h b/sound/soc/codecs/max9877.h
new file mode 100644
index 000000000000..6da72290ac58
--- /dev/null
+++ b/sound/soc/codecs/max9877.h
@@ -0,0 +1,37 @@
+/*
+ * max9877.h -- amp driver for max9877
+ *
+ * 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 _MAX9877_H
+#define _MAX9877_H
+
+#define MAX9877_INPUT_MODE 0x00
+#define MAX9877_SPK_VOLUME 0x01
+#define MAX9877_HPL_VOLUME 0x02
+#define MAX9877_HPR_VOLUME 0x03
+#define MAX9877_OUTPUT_MODE 0x04
+
+/* MAX9877_INPUT_MODE */
+#define MAX9877_INB (1 << 4)
+#define MAX9877_INA (1 << 5)
+#define MAX9877_ZCD (1 << 6)
+
+/* MAX9877_OUTPUT_MODE */
+#define MAX9877_OUTMODE_MASK (15 << 0)
+#define MAX9877_OSC_MASK (3 << 4)
+#define MAX9877_OSC_OFFSET 4
+#define MAX9877_BYPASS (1 << 6)
+#define MAX9877_SHDN (1 << 7)
+
+extern int max9877_add_controls(struct snd_soc_codec *codec);
+
+#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 218b33adad90..a63191141052 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -21,6 +21,8 @@
#include "spdif_transciever.h"
+MODULE_LICENSE("GPL");
+
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
@@ -34,6 +36,7 @@ struct snd_soc_dai dit_stub_dai = {
.formats = STUB_FORMATS,
},
};
+EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 8ad4b7b3e3ba..befc6488c39a 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -149,7 +149,7 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return 0;
}
- if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+ if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;
soc_ac97_ops.write(codec->ac97, reg, val);
@@ -168,7 +168,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
- if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+ if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index ab099f482487..cb0d1bf34b57 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -767,6 +767,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
u16 pll_d = 1;
+ u8 reg;
/* select data word length */
data =
@@ -801,8 +802,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
pll_q &= 0xf;
aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
- } else
+ /* disable PLL if it is bypassed */
+ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+ aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+
+ } else {
aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+ /* enable PLL when it is used */
+ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+ aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+ }
/* Route Left DAC to left channel input and
* right DAC to right channel input */
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 4dbb853eef5a..818fb37bd7f7 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -620,6 +620,9 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
{
+ struct snd_soc_device *socdev = codec->socdev;
+ struct twl4030_setup_data *setup = socdev->codec_data;
+
unsigned char hs_gain, hs_pop;
struct twl4030_priv *twl4030 = codec->private_data;
/* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -629,6 +632,17 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+ /* Enable external mute control, this dramatically reduces
+ * the pop-noise */
+ if (setup && setup->hs_extmute) {
+ if (setup->set_hs_extmute) {
+ setup->set_hs_extmute(1);
+ } else {
+ hs_pop |= TWL4030_EXTMUTE;
+ twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ }
+ }
+
if (ramp) {
/* Headset ramp-up according to the TRM */
hs_pop |= TWL4030_VMID_EN;
@@ -636,6 +650,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
hs_pop |= TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ /* Wait ramp delay time + 1, so the VMID can settle */
+ mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
+ twl4030->sysclk) + 1);
} else {
/* Headset ramp-down _not_ according to
* the TRM, but in a way that it is working */
@@ -652,6 +669,16 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
hs_pop &= ~TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
}
+
+ /* Disable external mute */
+ if (setup && setup->hs_extmute) {
+ if (setup->set_hs_extmute) {
+ setup->set_hs_extmute(0);
+ } else {
+ hs_pop &= ~TWL4030_EXTMUTE;
+ twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ }
+ }
}
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
@@ -712,7 +739,19 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
reg = twl4030_read_reg_cache(w->codec, m->reg);
- if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
+ /*
+ * bypass_state[0:3] - analog HiFi bypass
+ * bypass_state[4] - analog voice bypass
+ * bypass_state[5] - digital voice bypass
+ * bypass_state[6:7] - digital HiFi bypass
+ */
+ if (m->reg == TWL4030_REG_VSTPGA) {
+ /* Voice digital bypass */
+ if (reg)
+ twl4030->bypass_state |= (1 << 5);
+ else
+ twl4030->bypass_state &= ~(1 << 5);
+ } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
/* Analog bypass */
if (reg & (1 << m->shift))
twl4030->bypass_state |=
@@ -726,12 +765,6 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
twl4030->bypass_state |= (1 << 4);
else
twl4030->bypass_state &= ~(1 << 4);
- } else if (m->reg == TWL4030_REG_VSTPGA) {
- /* Voice digital bypass */
- if (reg)
- twl4030->bypass_state |= (1 << 5);
- else
- twl4030->bypass_state &= ~(1 << 5);
} else {
/* Digital bypass */
if (reg & (0x7 << m->shift))
@@ -924,7 +957,7 @@ static const struct soc_enum twl4030_op_modes_enum =
ARRAY_SIZE(twl4030_op_modes_texts),
twl4030_op_modes_texts);
-int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
+static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -1005,6 +1038,16 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
*/
static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
+/* AVADC clock priority */
+static const char *twl4030_avadc_clk_priority_texts[] = {
+ "Voice high priority", "HiFi high priority"
+};
+
+static const struct soc_enum twl4030_avadc_clk_priority_enum =
+ SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2,
+ ARRAY_SIZE(twl4030_avadc_clk_priority_texts),
+ twl4030_avadc_clk_priority_texts);
+
static const char *twl4030_rampdelay_texts[] = {
"27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
"437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
@@ -1106,6 +1149,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
0, 3, 5, 0, input_gain_tlv),
+ SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum),
+
SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
@@ -1240,14 +1285,14 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
/* HandsfreeL/R */
SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_handsfreel_control),
- SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_SWITCH("HandsfreeL", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_handsfreelmute_control),
SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM,
0, 0, NULL, 0, handsfreelpga_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0,
&twl4030_dapm_handsfreer_control),
- SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_SWITCH("HandsfreeR", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_handsfreermute_control),
SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM,
0, 0, NULL, 0, handsfreerpga_event,
@@ -1359,15 +1404,15 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"},
{"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"},
{"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"},
- {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"},
- {"HandsfreeL PGA", NULL, "HandsfreeL Switch"},
+ {"HandsfreeL", "Switch", "HandsfreeL Mux"},
+ {"HandsfreeL PGA", NULL, "HandsfreeL"},
/* HandsfreeR */
{"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"},
{"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"},
{"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"},
{"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"},
- {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"},
- {"HandsfreeR PGA", NULL, "HandsfreeR Switch"},
+ {"HandsfreeR", "Switch", "HandsfreeR Mux"},
+ {"HandsfreeR PGA", NULL, "HandsfreeR"},
/* Vibra */
{"Vibra Mux", "AudioL1", "DAC Left1"},
{"Vibra Mux", "AudioR1", "DAC Right1"},
@@ -1609,8 +1654,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
/* If the substream has 4 channel, do the necessary setup */
if (params_channels(params) == 4) {
- u8 format, mode;
-
format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
@@ -1806,6 +1849,19 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+
+ if (tristate)
+ reg |= TWL4030_AIF_TRI_EN;
+ else
+ reg &= ~TWL4030_AIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg);
+}
+
/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
* (VTXL, VTXR) for uplink has to be enabled/disabled. */
static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
@@ -1948,7 +2004,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFM:
format &= ~(TWL4030_VIF_SLAVE_EN);
break;
case SND_SOC_DAIFMT_CBS_CFS:
@@ -1980,6 +2036,19 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+
+ if (tristate)
+ reg |= TWL4030_VIF_TRI_EN;
+ else
+ reg &= ~TWL4030_VIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
+}
+
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
@@ -1989,6 +2058,7 @@ static struct snd_soc_dai_ops twl4030_dai_ops = {
.hw_params = twl4030_hw_params,
.set_sysclk = twl4030_set_dai_sysclk,
.set_fmt = twl4030_set_dai_fmt,
+ .set_tristate = twl4030_set_tristate,
};
static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
@@ -1997,6 +2067,7 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
.hw_params = twl4030_voice_hw_params,
.set_sysclk = twl4030_voice_set_dai_sysclk,
.set_fmt = twl4030_voice_set_dai_fmt,
+ .set_tristate = twl4030_voice_set_tristate,
};
struct snd_soc_dai twl4030_dai[] = {
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index fe5f395d9e4f..2b4bfa23f985 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -274,6 +274,8 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030;
struct twl4030_setup_data {
unsigned int ramp_delay_value;
unsigned int sysclk;
+ unsigned int hs_extmute:1;
+ void (*set_hs_extmute)(int mute);
};
#endif /* End of __TWL4030_AUDIO_H__ */
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 5b21594e0e58..92ec03442154 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -5,9 +5,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
- * Improved support for DAPM and audio routing/mixing capabilities,
- * added TLV support.
+ * Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com>
*
* Modified by Richard Purdie <richard@openedhand.com> to fit into SoC
* codec model.
@@ -19,26 +17,32 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
-#include <linux/ioctl.h>
+#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
-#include <sound/info.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
+#include <sound/uda1380.h>
#include "uda1380.h"
-static struct work_struct uda1380_work;
static struct snd_soc_codec *uda1380_codec;
+/* codec private data */
+struct uda1380_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[UDA1380_CACHEREGNUM];
+ unsigned int dac_clk;
+ struct work_struct work;
+};
+
/*
* uda1380 register cache
*/
@@ -473,6 +477,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct uda1380_priv *uda1380 = codec->private_data;
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
switch (cmd) {
@@ -480,13 +485,13 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
mixer & ~R14_SILENCE);
- schedule_work(&uda1380_work);
+ schedule_work(&uda1380->work);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
mixer | R14_SILENCE);
- schedule_work(&uda1380_work);
+ schedule_work(&uda1380->work);
break;
}
return 0;
@@ -670,44 +675,33 @@ static int uda1380_resume(struct platform_device *pdev)
return 0;
}
-/*
- * initialise the UDA1380 driver
- * register mixer and dsp interfaces with the kernel
- */
-static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
+static int uda1380_probe(struct platform_device *pdev)
{
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct uda1380_platform_data *pdata;
int ret = 0;
- codec->name = "UDA1380";
- codec->owner = THIS_MODULE;
- codec->read = uda1380_read_reg_cache;
- codec->write = uda1380_write;
- codec->set_bias_level = uda1380_set_bias_level;
- codec->dai = uda1380_dai;
- codec->num_dai = ARRAY_SIZE(uda1380_dai);
- codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
- codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
- codec->reg_cache_step = 1;
- uda1380_reset(codec);
+ if (uda1380_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
- uda1380_codec = codec;
- INIT_WORK(&uda1380_work, uda1380_flush_work);
+ socdev->card->codec = uda1380_codec;
+ codec = uda1380_codec;
+ pdata = codec->dev->platform_data;
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
- pr_err("uda1380: failed to create pcms\n");
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
goto pcm_err;
}
/* power on device */
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set clock input */
- switch (dac_clk) {
+ switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
uda1380_write(codec, UDA1380_CLK, 0);
break;
@@ -716,13 +710,12 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
break;
}
- /* uda1380 init */
snd_soc_add_controls(codec, uda1380_snd_controls,
ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
- pr_err("uda1380: failed to register card\n");
+ dev_err(codec->dev, "failed to register card: %d\n", ret);
goto card_err;
}
@@ -732,165 +725,201 @@ card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
- kfree(codec->reg_cache);
return ret;
}
-static struct snd_soc_device *uda1380_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int uda1380_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+/* power down chip */
+static int uda1380_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = uda1380_socdev;
- struct uda1380_setup_data *setup = socdev->codec_data;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
-
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
- ret = uda1380_init(socdev, setup->dac_clk);
- if (ret < 0)
- pr_err("uda1380: failed to initialise UDA1380\n");
+ if (codec->control_data)
+ uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return ret;
-}
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
-static int uda1380_i2c_remove(struct i2c_client *client)
-{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
return 0;
}
-static const struct i2c_device_id uda1380_i2c_id[] = {
- { "uda1380", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
-
-static struct i2c_driver uda1380_i2c_driver = {
- .driver = {
- .name = "UDA1380 I2C Codec",
- .owner = THIS_MODULE,
- },
- .probe = uda1380_i2c_probe,
- .remove = uda1380_i2c_remove,
- .id_table = uda1380_i2c_id,
+struct snd_soc_codec_device soc_codec_dev_uda1380 = {
+ .probe = uda1380_probe,
+ .remove = uda1380_remove,
+ .suspend = uda1380_suspend,
+ .resume = uda1380_resume,
};
+EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
-static int uda1380_add_i2c_device(struct platform_device *pdev,
- const struct uda1380_setup_data *setup)
+static int uda1380_register(struct uda1380_priv *uda1380)
{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
+ int ret, i;
+ struct snd_soc_codec *codec = &uda1380->codec;
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
- ret = i2c_add_driver(&uda1380_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
+ if (uda1380_codec) {
+ dev_err(codec->dev, "Another UDA1380 is registered\n");
+ return -EINVAL;
+ }
+
+ if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
+ return -EINVAL;
+
+ ret = gpio_request(pdata->gpio_power, "uda1380 power");
+ if (ret)
+ goto err_out;
+ ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+ if (ret)
+ goto err_gpio;
+
+ gpio_direction_output(pdata->gpio_power, 1);
+
+ /* we may need to have the clock running here - pH5 */
+ gpio_direction_output(pdata->gpio_reset, 1);
+ udelay(5);
+ gpio_set_value(pdata->gpio_reset, 0);
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->private_data = uda1380;
+ codec->name = "UDA1380";
+ codec->owner = THIS_MODULE;
+ codec->read = uda1380_read_reg_cache;
+ codec->write = uda1380_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = uda1380_set_bias_level;
+ codec->dai = uda1380_dai;
+ codec->num_dai = ARRAY_SIZE(uda1380_dai);
+ codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
+ codec->reg_cache = &uda1380->reg_cache;
+ codec->reg_cache_step = 1;
+
+ memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
+
+ ret = uda1380_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_reset;
}
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
+ INIT_WORK(&uda1380->work, uda1380_flush_work);
+
+ for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
+ uda1380_dai[i].dev = codec->dev;
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
+ uda1380_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto err_reset;
}
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
+ ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+ goto err_dai;
}
return 0;
-err_driver:
- i2c_del_driver(&uda1380_i2c_driver);
- return -ENODEV;
+err_dai:
+ snd_soc_unregister_codec(codec);
+err_reset:
+ gpio_set_value(pdata->gpio_power, 0);
+ gpio_free(pdata->gpio_reset);
+err_gpio:
+ gpio_free(pdata->gpio_power);
+err_out:
+ return ret;
}
-#endif
-static int uda1380_probe(struct platform_device *pdev)
+static void uda1380_unregister(struct uda1380_priv *uda1380)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct uda1380_setup_data *setup;
+ struct snd_soc_codec *codec = &uda1380->codec;
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+ snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+ snd_soc_unregister_codec(&uda1380->codec);
+
+ gpio_set_value(pdata->gpio_power, 0);
+ gpio_free(pdata->gpio_reset);
+ gpio_free(pdata->gpio_power);
+
+ kfree(uda1380);
+ uda1380_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct uda1380_priv *uda1380;
struct snd_soc_codec *codec;
int ret;
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
+ uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
+ if (uda1380 == NULL)
return -ENOMEM;
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+ codec = &uda1380->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
- uda1380_socdev = socdev;
- ret = -ENODEV;
+ i2c_set_clientdata(i2c, uda1380);
+ codec->control_data = i2c;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = uda1380_add_i2c_device(pdev, setup);
- }
-#endif
+ codec->dev = &i2c->dev;
+ ret = uda1380_register(uda1380);
if (ret != 0)
- kfree(codec);
+ kfree(uda1380);
+
return ret;
}
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
+static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&uda1380_i2c_driver);
-#endif
- kfree(codec);
-
+ struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
+ uda1380_unregister(uda1380);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
- .probe = uda1380_probe,
- .remove = uda1380_remove,
- .suspend = uda1380_suspend,
- .resume = uda1380_resume,
+static const struct i2c_device_id uda1380_i2c_id[] = {
+ { "uda1380", 0 },
+ { }
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
+MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
+
+static struct i2c_driver uda1380_i2c_driver = {
+ .driver = {
+ .name = "UDA1380 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = uda1380_i2c_probe,
+ .remove = __devexit_p(uda1380_i2c_remove),
+ .id_table = uda1380_i2c_id,
+};
+#endif
static int __init uda1380_modinit(void)
{
- return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&uda1380_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
+#endif
+ return 0;
}
module_init(uda1380_modinit);
static void __exit uda1380_exit(void)
{
- snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&uda1380_i2c_driver);
+#endif
}
module_exit(uda1380_exit);
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index c55c17a52a12..9cefa8a54770 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -72,14 +72,6 @@
#define R22_SKIP_DCFIL 0x0002
#define R23_AGC_EN 0x0001
-struct uda1380_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
- int dac_clk;
-#define UDA1380_DAC_CLK_SYSCLK 0
-#define UDA1380_DAC_CLK_WSPLL 1
-};
-
#define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */
#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */
#define UDA1380_DAI_CAPTURE 2 /* capture DAI */
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index e7348d341b76..4ded0e3a35e0 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -406,7 +406,6 @@ static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
static const char *wm8350_dacmutes[] = { "Fast", "Slow" };
-static const char *wm8350_dacfilter[] = { "Normal", "Sloping" };
static const char *wm8350_adcfilter[] = { "None", "High Pass" };
static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" };
static const char *wm8350_lr[] = { "Left", "Right" };
@@ -416,7 +415,6 @@ static const struct soc_enum wm8350_enum[] = {
SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol),
SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem),
SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes),
- SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol),
@@ -444,10 +442,9 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = {
0, 255, 0, dac_pcm_tlv),
SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
- SOC_ENUM("Playback PCM Filter", wm8350_enum[4]),
- SOC_ENUM("Capture PCM Filter", wm8350_enum[5]),
- SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]),
- SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]),
+ SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
+ SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
+ SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume",
WM8350_ADC_DIGITAL_VOLUME_L,
WM8350_ADC_DIGITAL_VOLUME_R,
@@ -993,6 +990,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8350 *wm8350 = codec->control_data;
u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
~WM8350_AIF_WL_MASK;
@@ -1012,6 +1010,19 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
}
wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+
+ /* The sloping stopband filter is recommended for use with
+ * lower sample rates to improve performance.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (params_rate(params) < 24000)
+ wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
+ WM8350_DAC_SB_FILT);
+ else
+ wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
+ WM8350_DAC_SB_FILT);
+ }
+
return 0;
}
@@ -1660,6 +1671,21 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m)
+{
+ return snd_soc_suspend_device(&pdev->dev);
+}
+
+static int wm8350_codec_resume(struct platform_device *pdev)
+{
+ return snd_soc_resume_device(&pdev->dev);
+}
+#else
+#define wm8350_codec_suspend NULL
+#define wm8350_codec_resume NULL
+#endif
+
static struct platform_driver wm8350_codec_driver = {
.driver = {
.name = "wm8350-codec",
@@ -1667,6 +1693,8 @@ static struct platform_driver wm8350_codec_driver = {
},
.probe = wm8350_codec_probe,
.remove = __devexit_p(wm8350_codec_remove),
+ .suspend = wm8350_codec_suspend,
+ .resume = wm8350_codec_resume,
};
static __init int wm8350_init(void)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 502eefac1ecd..b9ef4d915221 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1022,10 +1022,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
return 0;
- if (freq_out != 0) {
+ if (freq_out) {
ret = fll_factors(wm8400, &factors, freq_in, freq_out);
if (ret != 0)
return ret;
+ } else {
+ /* Bodge GCC 4.4.0 uninitialised variable warning - it
+ * doesn't seem capable of working out that we exit if
+ * freq_out is 0 before any of the uses. */
+ memset(&factors, 0, sizeof(factors));
}
wm8400->fll_out = freq_out;
@@ -1040,7 +1045,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
reg &= ~WM8400_FLL_OSC_ENA;
wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
- if (freq_out == 0)
+ if (!freq_out)
return 0;
reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
@@ -1553,6 +1558,21 @@ static int __exit wm8400_codec_remove(struct platform_device *dev)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&pdev->dev);
+}
+
+static int wm8400_pdev_resume(struct platform_device *pdev)
+{
+ return snd_soc_resume_device(&pdev->dev);
+}
+#else
+#define wm8400_pdev_suspend NULL
+#define wm8400_pdev_resume NULL
+#endif
+
static struct platform_driver wm8400_codec_driver = {
.driver = {
.name = "wm8400-codec",
@@ -1560,6 +1580,8 @@ static struct platform_driver wm8400_codec_driver = {
},
.probe = wm8400_codec_probe,
.remove = __exit_p(wm8400_codec_remove),
+ .suspend = wm8400_pdev_suspend,
+ .resume = wm8400_pdev_resume,
};
static int __init wm8400_codec_init(void)
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index c8b8dba85890..261d4cb75964 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -577,6 +577,7 @@ struct snd_soc_dai wm8510_dai = {
.rates = WM8510_RATES,
.formats = WM8510_FORMATS,},
.ops = &wm8510_dai_ops,
+ .symmetric_rates = 1,
};
EXPORT_SYMBOL_GPL(wm8510_dai);
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
new file mode 100644
index 000000000000..3b499ae7ce6c
--- /dev/null
+++ b/sound/soc/codecs/wm8523.c
@@ -0,0 +1,755 @@
+/*
+ * wm8523.c -- WM8523 ALSA SoC Audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8523.h"
+
+static struct snd_soc_codec *wm8523_codec;
+struct snd_soc_codec_device soc_codec_dev_wm8523;
+
+#define WM8523_NUM_SUPPLIES 2
+static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
+ "AVDD",
+ "LINEVDD",
+};
+
+#define WM8523_NUM_RATES 7
+
+/* codec private data */
+struct wm8523_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[WM8523_REGISTER_COUNT];
+ struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int rate_constraint_list[WM8523_NUM_RATES];
+ struct snd_pcm_hw_constraint_list rate_constraint;
+};
+
+static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = {
+ 0x8523, /* R0 - DEVICE_ID */
+ 0x0001, /* R1 - REVISION */
+ 0x0000, /* R2 - PSCTRL1 */
+ 0x1812, /* R3 - AIF_CTRL1 */
+ 0x0000, /* R4 - AIF_CTRL2 */
+ 0x0001, /* R5 - DAC_CTRL3 */
+ 0x0190, /* R6 - DAC_GAINL */
+ 0x0190, /* R7 - DAC_GAINR */
+ 0x0000, /* R8 - ZERO_DETECT */
+};
+
+static int wm8523_volatile(unsigned int reg)
+{
+ switch (reg) {
+ case WM8523_DEVICE_ID:
+ case WM8523_REVISION:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct wm8523_priv *wm8523 = codec->private_data;
+ u8 data[3];
+
+ BUG_ON(reg > WM8523_MAX_REGISTER);
+
+ data[0] = reg;
+ data[1] = (value >> 8) & 0x00ff;
+ data[2] = value & 0x00ff;
+
+ if (!wm8523_volatile(reg))
+ wm8523->reg_cache[reg] = value;
+ if (codec->hw_write(codec->control_data, data, 3) == 3)
+ return 0;
+ else
+ return -EIO;
+}
+
+static int wm8523_reset(struct snd_soc_codec *codec)
+{
+ return wm8523_write(codec, WM8523_DEVICE_ID, 0);
+}
+
+static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg)
+{
+ struct i2c_msg xfer[2];
+ u16 data;
+ int ret;
+ struct i2c_client *i2c = codec->control_data;
+
+ /* Write register */
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = 2;
+ xfer[1].buf = (u8 *)&data;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret != 2) {
+ dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
+ return 0;
+ }
+
+ return (data >> 8) | ((data & 0xff) << 8);
+}
+
+
+static unsigned int wm8523_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *reg_cache = codec->reg_cache;
+
+ BUG_ON(reg > WM8523_MAX_REGISTER);
+
+ if (wm8523_volatile(reg))
+ return wm8523_read_hw(codec, reg);
+ else
+ return reg_cache[reg];
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
+
+static const char *wm8523_zd_count_text[] = {
+ "1024",
+ "2048",
+};
+
+static const struct soc_enum wm8523_zc_count =
+ SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text);
+
+static const struct snd_kcontrol_new wm8523_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
+ 0, 448, 0, dac_tlv),
+SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0),
+SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0),
+SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1),
+SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0),
+SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0),
+SOC_ENUM("Zero Detect Count", wm8523_zc_count),
+};
+
+static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ { "LINEVOUTL", NULL, "DAC" },
+ { "LINEVOUTR", NULL, "DAC" },
+};
+
+static int wm8523_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets,
+ ARRAY_SIZE(wm8523_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static struct {
+ int value;
+ int ratio;
+} lrclk_ratios[WM8523_NUM_RATES] = {
+ { 1, 128 },
+ { 2, 192 },
+ { 3, 256 },
+ { 4, 384 },
+ { 5, 512 },
+ { 6, 768 },
+ { 7, 1152 },
+};
+
+static int wm8523_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8523_priv *wm8523 = codec->private_data;
+
+ /* The set of sample rates that can be supported depends on the
+ * MCLK supplied to the CODEC - enforce this.
+ */
+ if (!wm8523->sysclk) {
+ dev_err(codec->dev,
+ "No MCLK configured, call set_sysclk() on init\n");
+ return -EINVAL;
+ }
+
+ return 0;
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &wm8523->rate_constraint);
+
+ return 0;
+}
+
+static int wm8523_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8523_priv *wm8523 = codec->private_data;
+ int i;
+ u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1);
+ u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2);
+
+ /* Find a supported LRCLK ratio */
+ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+ if (wm8523->sysclk / params_rate(params) ==
+ lrclk_ratios[i].ratio)
+ break;
+ }
+
+ /* Should never happen, should be handled by constraints */
+ if (i == ARRAY_SIZE(lrclk_ratios)) {
+ dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n",
+ wm8523->sysclk / params_rate(params));
+ return -EINVAL;
+ }
+
+ aifctrl2 &= ~WM8523_SR_MASK;
+ aifctrl2 |= lrclk_ratios[i].value;
+
+ aifctrl1 &= ~WM8523_WL_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ aifctrl1 |= 0x8;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ aifctrl1 |= 0x10;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ aifctrl1 |= 0x18;
+ break;
+ }
+
+ wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1);
+ wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2);
+
+ return 0;
+}
+
+static int wm8523_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 wm8523_priv *wm8523 = codec->private_data;
+ unsigned int val;
+ int i;
+
+ wm8523->sysclk = freq;
+
+ wm8523->rate_constraint.count = 0;
+ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+ val = freq / lrclk_ratios[i].ratio;
+ /* Check that it's a standard rate since core can't
+ * cope with others and having the odd rates confuses
+ * constraint matching.
+ */
+ switch (val) {
+ case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 64000:
+ case 88200:
+ case 96000:
+ case 176400:
+ case 192000:
+ dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
+ val);
+ wm8523->rate_constraint_list[i] = val;
+ wm8523->rate_constraint.count++;
+ break;
+ default:
+ dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
+ val);
+ }
+ }
+
+ /* Need at least one supported rate... */
+ if (wm8523->rate_constraint.count == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1);
+
+ aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
+ WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aifctrl1 |= WM8523_AIF_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ aifctrl1 |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aifctrl1 |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ aifctrl1 |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ aifctrl1 |= 0x0023;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aifctrl1 |= WM8523_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aifctrl1 |= WM8523_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1);
+
+ return 0;
+}
+
+static int wm8523_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8523_priv *wm8523 = codec->private_data;
+ int ret, i;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* Full power on */
+ snd_soc_update_bits(codec, WM8523_PSCTRL1,
+ WM8523_SYS_ENA_MASK, 3);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
+ wm8523->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Initial power up */
+ snd_soc_update_bits(codec, WM8523_PSCTRL1,
+ WM8523_SYS_ENA_MASK, 1);
+
+ /* Sync back default/cached values */
+ for (i = WM8523_AIF_CTRL1;
+ i < WM8523_MAX_REGISTER; i++)
+ wm8523_write(codec, i, wm8523->reg_cache[i]);
+
+
+ msleep(100);
+ }
+
+ /* Power up to mute */
+ snd_soc_update_bits(codec, WM8523_PSCTRL1,
+ WM8523_SYS_ENA_MASK, 2);
+
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ /* The chip runs through the power down sequence for us. */
+ snd_soc_update_bits(codec, WM8523_PSCTRL1,
+ WM8523_SYS_ENA_MASK, 0);
+ msleep(100);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies),
+ wm8523->supplies);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define WM8523_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8523_dai_ops = {
+ .startup = wm8523_startup,
+ .hw_params = wm8523_hw_params,
+ .set_sysclk = wm8523_set_dai_sysclk,
+ .set_fmt = wm8523_set_dai_fmt,
+};
+
+struct snd_soc_dai wm8523_dai = {
+ .name = "WM8523",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2, /* Mono modes not yet supported */
+ .channels_max = 2,
+ .rates = WM8523_RATES,
+ .formats = WM8523_FORMATS,
+ },
+ .ops = &wm8523_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8523_dai);
+
+#ifdef CONFIG_PM
+static int wm8523_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;
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8523_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define wm8523_suspend NULL
+#define wm8523_resume NULL
+#endif
+
+static int wm8523_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (wm8523_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = wm8523_codec;
+ codec = wm8523_codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, wm8523_snd_controls,
+ ARRAY_SIZE(wm8523_snd_controls));
+ wm8523_add_widgets(codec);
+ 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;
+}
+
+static int wm8523_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8523 = {
+ .probe = wm8523_probe,
+ .remove = wm8523_remove,
+ .suspend = wm8523_suspend,
+ .resume = wm8523_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
+
+static int wm8523_register(struct wm8523_priv *wm8523)
+{
+ int ret;
+ struct snd_soc_codec *codec = &wm8523->codec;
+ int i;
+
+ if (wm8523_codec) {
+ dev_err(codec->dev, "Another WM8523 is registered\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->private_data = wm8523;
+ codec->name = "WM8523";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8523_read;
+ codec->write = wm8523_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8523_set_bias_level;
+ codec->dai = &wm8523_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = WM8523_REGISTER_COUNT;
+ codec->reg_cache = &wm8523->reg_cache;
+
+ wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
+ wm8523->rate_constraint.count =
+ ARRAY_SIZE(wm8523->rate_constraint_list);
+
+ memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
+
+ for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
+ wm8523->supplies[i].supply = wm8523_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies),
+ wm8523->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
+ wm8523->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ ret = wm8523_read(codec, WM8523_DEVICE_ID);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read ID register\n");
+ goto err_enable;
+ }
+ if (ret != wm8523_reg[WM8523_DEVICE_ID]) {
+ dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ ret = wm8523_read(codec, WM8523_REVISION);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read revision register\n");
+ goto err_enable;
+ }
+ dev_info(codec->dev, "revision %c\n",
+ (ret & WM8523_CHIP_REV_MASK) + 'A');
+
+ ret = wm8523_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_enable;
+ }
+
+ wm8523_dai.dev = codec->dev;
+
+ /* Change some default settings - latch VU and enable ZC */
+ wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
+ wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Bias level configuration will have done an extra enable */
+ regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+
+ wm8523_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&wm8523_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
+
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+err:
+ kfree(wm8523);
+ return ret;
+}
+
+static void wm8523_unregister(struct wm8523_priv *wm8523)
+{
+ wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+ snd_soc_unregister_dai(&wm8523_dai);
+ snd_soc_unregister_codec(&wm8523->codec);
+ kfree(wm8523);
+ wm8523_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8523_priv *wm8523;
+ struct snd_soc_codec *codec;
+
+ wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
+ if (wm8523 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8523->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ i2c_set_clientdata(i2c, wm8523);
+ codec->control_data = i2c;
+
+ codec->dev = &i2c->dev;
+
+ return wm8523_register(wm8523);
+}
+
+static __devexit int wm8523_i2c_remove(struct i2c_client *client)
+{
+ struct wm8523_priv *wm8523 = i2c_get_clientdata(client);
+ wm8523_unregister(wm8523);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&i2c->dev);
+}
+
+static int wm8523_i2c_resume(struct i2c_client *i2c)
+{
+ return snd_soc_resume_device(&i2c->dev);
+}
+#else
+#define wm8523_i2c_suspend NULL
+#define wm8523_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id wm8523_i2c_id[] = {
+ { "wm8523", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
+
+static struct i2c_driver wm8523_i2c_driver = {
+ .driver = {
+ .name = "WM8523",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8523_i2c_probe,
+ .remove = __devexit_p(wm8523_i2c_remove),
+ .suspend = wm8523_i2c_suspend,
+ .resume = wm8523_i2c_resume,
+ .id_table = wm8523_i2c_id,
+};
+#endif
+
+static int __init wm8523_modinit(void)
+{
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8523_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
+}
+module_init(wm8523_modinit);
+
+static void __exit wm8523_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8523_i2c_driver);
+#endif
+}
+module_exit(wm8523_exit);
+
+MODULE_DESCRIPTION("ASoC WM8523 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h
new file mode 100644
index 000000000000..1aa9ce3e1357
--- /dev/null
+++ b/sound/soc/codecs/wm8523.h
@@ -0,0 +1,160 @@
+/*
+ * wm8523.h -- WM8423 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8753.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 _WM8523_H
+#define _WM8523_H
+
+/*
+ * Register values.
+ */
+#define WM8523_DEVICE_ID 0x00
+#define WM8523_REVISION 0x01
+#define WM8523_PSCTRL1 0x02
+#define WM8523_AIF_CTRL1 0x03
+#define WM8523_AIF_CTRL2 0x04
+#define WM8523_DAC_CTRL3 0x05
+#define WM8523_DAC_GAINL 0x06
+#define WM8523_DAC_GAINR 0x07
+#define WM8523_ZERO_DETECT 0x08
+
+#define WM8523_REGISTER_COUNT 9
+#define WM8523_MAX_REGISTER 0x08
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - DEVICE_ID
+ */
+#define WM8523_CHIP_ID_MASK 0xFFFF /* CHIP_ID - [15:0] */
+#define WM8523_CHIP_ID_SHIFT 0 /* CHIP_ID - [15:0] */
+#define WM8523_CHIP_ID_WIDTH 16 /* CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - REVISION
+ */
+#define WM8523_CHIP_REV_MASK 0x0007 /* CHIP_REV - [2:0] */
+#define WM8523_CHIP_REV_SHIFT 0 /* CHIP_REV - [2:0] */
+#define WM8523_CHIP_REV_WIDTH 3 /* CHIP_REV - [2:0] */
+
+/*
+ * R2 (0x02) - PSCTRL1
+ */
+#define WM8523_SYS_ENA_MASK 0x0003 /* SYS_ENA - [1:0] */
+#define WM8523_SYS_ENA_SHIFT 0 /* SYS_ENA - [1:0] */
+#define WM8523_SYS_ENA_WIDTH 2 /* SYS_ENA - [1:0] */
+
+/*
+ * R3 (0x03) - AIF_CTRL1
+ */
+#define WM8523_TDM_MODE_MASK 0x1800 /* TDM_MODE - [12:11] */
+#define WM8523_TDM_MODE_SHIFT 11 /* TDM_MODE - [12:11] */
+#define WM8523_TDM_MODE_WIDTH 2 /* TDM_MODE - [12:11] */
+#define WM8523_TDM_SLOT_MASK 0x0600 /* TDM_SLOT - [10:9] */
+#define WM8523_TDM_SLOT_SHIFT 9 /* TDM_SLOT - [10:9] */
+#define WM8523_TDM_SLOT_WIDTH 2 /* TDM_SLOT - [10:9] */
+#define WM8523_DEEMPH 0x0100 /* DEEMPH */
+#define WM8523_DEEMPH_MASK 0x0100 /* DEEMPH */
+#define WM8523_DEEMPH_SHIFT 8 /* DEEMPH */
+#define WM8523_DEEMPH_WIDTH 1 /* DEEMPH */
+#define WM8523_AIF_MSTR 0x0080 /* AIF_MSTR */
+#define WM8523_AIF_MSTR_MASK 0x0080 /* AIF_MSTR */
+#define WM8523_AIF_MSTR_SHIFT 7 /* AIF_MSTR */
+#define WM8523_AIF_MSTR_WIDTH 1 /* AIF_MSTR */
+#define WM8523_LRCLK_INV 0x0040 /* LRCLK_INV */
+#define WM8523_LRCLK_INV_MASK 0x0040 /* LRCLK_INV */
+#define WM8523_LRCLK_INV_SHIFT 6 /* LRCLK_INV */
+#define WM8523_LRCLK_INV_WIDTH 1 /* LRCLK_INV */
+#define WM8523_BCLK_INV 0x0020 /* BCLK_INV */
+#define WM8523_BCLK_INV_MASK 0x0020 /* BCLK_INV */
+#define WM8523_BCLK_INV_SHIFT 5 /* BCLK_INV */
+#define WM8523_BCLK_INV_WIDTH 1 /* BCLK_INV */
+#define WM8523_WL_MASK 0x0018 /* WL - [4:3] */
+#define WM8523_WL_SHIFT 3 /* WL - [4:3] */
+#define WM8523_WL_WIDTH 2 /* WL - [4:3] */
+#define WM8523_FMT_MASK 0x0007 /* FMT - [2:0] */
+#define WM8523_FMT_SHIFT 0 /* FMT - [2:0] */
+#define WM8523_FMT_WIDTH 3 /* FMT - [2:0] */
+
+/*
+ * R4 (0x04) - AIF_CTRL2
+ */
+#define WM8523_DAC_OP_MUX_MASK 0x00C0 /* DAC_OP_MUX - [7:6] */
+#define WM8523_DAC_OP_MUX_SHIFT 6 /* DAC_OP_MUX - [7:6] */
+#define WM8523_DAC_OP_MUX_WIDTH 2 /* DAC_OP_MUX - [7:6] */
+#define WM8523_BCLKDIV_MASK 0x0038 /* BCLKDIV - [5:3] */
+#define WM8523_BCLKDIV_SHIFT 3 /* BCLKDIV - [5:3] */
+#define WM8523_BCLKDIV_WIDTH 3 /* BCLKDIV - [5:3] */
+#define WM8523_SR_MASK 0x0007 /* SR - [2:0] */
+#define WM8523_SR_SHIFT 0 /* SR - [2:0] */
+#define WM8523_SR_WIDTH 3 /* SR - [2:0] */
+
+/*
+ * R5 (0x05) - DAC_CTRL3
+ */
+#define WM8523_ZC 0x0010 /* ZC */
+#define WM8523_ZC_MASK 0x0010 /* ZC */
+#define WM8523_ZC_SHIFT 4 /* ZC */
+#define WM8523_ZC_WIDTH 1 /* ZC */
+#define WM8523_DACR 0x0008 /* DACR */
+#define WM8523_DACR_MASK 0x0008 /* DACR */
+#define WM8523_DACR_SHIFT 3 /* DACR */
+#define WM8523_DACR_WIDTH 1 /* DACR */
+#define WM8523_DACL 0x0004 /* DACL */
+#define WM8523_DACL_MASK 0x0004 /* DACL */
+#define WM8523_DACL_SHIFT 2 /* DACL */
+#define WM8523_DACL_WIDTH 1 /* DACL */
+#define WM8523_VOL_UP_RAMP 0x0002 /* VOL_UP_RAMP */
+#define WM8523_VOL_UP_RAMP_MASK 0x0002 /* VOL_UP_RAMP */
+#define WM8523_VOL_UP_RAMP_SHIFT 1 /* VOL_UP_RAMP */
+#define WM8523_VOL_UP_RAMP_WIDTH 1 /* VOL_UP_RAMP */
+#define WM8523_VOL_DOWN_RAMP 0x0001 /* VOL_DOWN_RAMP */
+#define WM8523_VOL_DOWN_RAMP_MASK 0x0001 /* VOL_DOWN_RAMP */
+#define WM8523_VOL_DOWN_RAMP_SHIFT 0 /* VOL_DOWN_RAMP */
+#define WM8523_VOL_DOWN_RAMP_WIDTH 1 /* VOL_DOWN_RAMP */
+
+/*
+ * R6 (0x06) - DAC_GAINL
+ */
+#define WM8523_DACL_VU 0x0200 /* DACL_VU */
+#define WM8523_DACL_VU_MASK 0x0200 /* DACL_VU */
+#define WM8523_DACL_VU_SHIFT 9 /* DACL_VU */
+#define WM8523_DACL_VU_WIDTH 1 /* DACL_VU */
+#define WM8523_DACL_VOL_MASK 0x01FF /* DACL_VOL - [8:0] */
+#define WM8523_DACL_VOL_SHIFT 0 /* DACL_VOL - [8:0] */
+#define WM8523_DACL_VOL_WIDTH 9 /* DACL_VOL - [8:0] */
+
+/*
+ * R7 (0x07) - DAC_GAINR
+ */
+#define WM8523_DACR_VU 0x0200 /* DACR_VU */
+#define WM8523_DACR_VU_MASK 0x0200 /* DACR_VU */
+#define WM8523_DACR_VU_SHIFT 9 /* DACR_VU */
+#define WM8523_DACR_VU_WIDTH 1 /* DACR_VU */
+#define WM8523_DACR_VOL_MASK 0x01FF /* DACR_VOL - [8:0] */
+#define WM8523_DACR_VOL_SHIFT 0 /* DACR_VOL - [8:0] */
+#define WM8523_DACR_VOL_WIDTH 9 /* DACR_VOL - [8:0] */
+
+/*
+ * R8 (0x08) - ZERO_DETECT
+ */
+#define WM8523_ZD_COUNT_MASK 0x0003 /* ZD_COUNT - [1:0] */
+#define WM8523_ZD_COUNT_SHIFT 0 /* ZD_COUNT - [1:0] */
+#define WM8523_ZD_COUNT_WIDTH 2 /* ZD_COUNT - [1:0] */
+
+extern struct snd_soc_dai wm8523_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8523;
+
+#endif
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 86c4b24db817..97b9ed95d289 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -24,6 +24,8 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -187,15 +189,22 @@ struct pll_state {
unsigned int out;
};
+#define WM8580_NUM_SUPPLIES 3
+static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
+ "AVDD",
+ "DVDD",
+ "PVDD",
+};
+
/* codec private data */
struct wm8580_priv {
struct snd_soc_codec codec;
+ struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
u16 reg_cache[WM8580_MAX_REGISTER + 1];
struct pll_state a;
struct pll_state b;
};
-
/*
* read wm8580 register cache
*/
@@ -922,11 +931,28 @@ static int wm8580_register(struct wm8580_priv *wm8580)
memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+ for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
+ wm8580->supplies[i].supply = wm8580_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies),
+ wm8580->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
+ wm8580->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_regulator_get;
+ }
+
/* Get the codec into a known state */
ret = wm8580_write(codec, WM8580_RESET, 0);
if (ret != 0) {
dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
- goto err;
+ goto err_regulator_enable;
}
for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
@@ -939,7 +965,7 @@ static int wm8580_register(struct wm8580_priv *wm8580)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
+ goto err_regulator_enable;
}
ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
@@ -952,6 +978,10 @@ static int wm8580_register(struct wm8580_priv *wm8580)
err_codec:
snd_soc_unregister_codec(codec);
+err_regulator_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
+err_regulator_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
err:
kfree(wm8580);
return ret;
@@ -962,6 +992,8 @@ static void wm8580_unregister(struct wm8580_priv *wm8580)
wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
snd_soc_unregister_codec(&wm8580->codec);
+ regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
+ regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
kfree(wm8580);
wm8580_codec = NULL;
}
@@ -995,6 +1027,21 @@ static int wm8580_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8580_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8580_i2c_suspend NULL
+#define wm8580_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8580_i2c_id[] = {
{ "wm8580", 0 },
{ }
@@ -1008,6 +1055,8 @@ static struct i2c_driver wm8580_i2c_driver = {
},
.probe = wm8580_i2c_probe,
.remove = wm8580_i2c_remove,
+ .suspend = wm8580_i2c_suspend,
+ .resume = wm8580_i2c_resume,
.id_table = wm8580_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7a205876ef4f..156002852078 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -26,6 +26,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include "wm8731.h"
@@ -113,20 +114,26 @@ static const struct soc_enum wm8731_enum[] = {
SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
};
+static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
static const struct snd_kcontrol_new wm8731_snd_controls[] = {
-SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
- 0, 127, 0),
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+ 0, 127, 0, out_tlv),
SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
7, 1, 0),
-SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
+ in_tlv),
SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
-SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
+SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
-SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
+SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
+ sidetone_tlv),
SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
@@ -457,9 +464,11 @@ struct snd_soc_dai wm8731_dai = {
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
.ops = &wm8731_dai_ops,
+ .symmetric_rates = 1,
};
EXPORT_SYMBOL_GPL(wm8731_dai);
+#ifdef CONFIG_PM
static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -488,6 +497,10 @@ static int wm8731_resume(struct platform_device *pdev)
wm8731_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
+#else
+#define wm8731_suspend NULL
+#define wm8731_resume NULL
+#endif
static int wm8731_probe(struct platform_device *pdev)
{
@@ -555,7 +568,8 @@ static int wm8731_register(struct wm8731_priv *wm8731)
if (wm8731_codec) {
dev_err(codec->dev, "Another WM8731 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
@@ -578,8 +592,8 @@ static int wm8731_register(struct wm8731_priv *wm8731)
ret = wm8731_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ goto err;
}
wm8731_dai.dev = codec->dev;
@@ -605,17 +619,23 @@ static int wm8731_register(struct wm8731_priv *wm8731)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err;
}
ret = snd_soc_register_dai(&wm8731_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ kfree(wm8731);
+ return ret;
}
static void wm8731_unregister(struct wm8731_priv *wm8731)
@@ -680,6 +700,21 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&spi->dev);
+}
+
+static int wm8731_spi_resume(struct spi_device *spi)
+{
+ return snd_soc_resume_device(&spi->dev);
+}
+#else
+#define wm8731_spi_suspend NULL
+#define wm8731_spi_resume NULL
+#endif
+
static struct spi_driver wm8731_spi_driver = {
.driver = {
.name = "wm8731",
@@ -687,6 +722,8 @@ static struct spi_driver wm8731_spi_driver = {
.owner = THIS_MODULE,
},
.probe = wm8731_spi_probe,
+ .suspend = wm8731_spi_suspend,
+ .resume = wm8731_spi_resume,
.remove = __devexit_p(wm8731_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */
@@ -720,6 +757,21 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&i2c->dev);
+}
+
+static int wm8731_i2c_resume(struct i2c_client *i2c)
+{
+ return snd_soc_resume_device(&i2c->dev);
+}
+#else
+#define wm8731_i2c_suspend NULL
+#define wm8731_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8731_i2c_id[] = {
{ "wm8731", 0 },
{ }
@@ -733,6 +785,8 @@ static struct i2c_driver wm8731_i2c_driver = {
},
.probe = wm8731_i2c_probe,
.remove = __devexit_p(wm8731_i2c_remove),
+ .suspend = wm8731_i2c_suspend,
+ .resume = wm8731_i2c_resume,
.id_table = wm8731_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 49c4b2898aff..d80d414cfbbd 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1766,6 +1766,21 @@ static int wm8753_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8753_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8753_i2c_suspend NULL
+#define wm8753_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8753_i2c_id[] = {
{ "wm8753", 0 },
{ }
@@ -1779,6 +1794,8 @@ static struct i2c_driver wm8753_i2c_driver = {
},
.probe = wm8753_i2c_probe,
.remove = wm8753_i2c_remove,
+ .suspend = wm8753_i2c_suspend,
+ .resume = wm8753_i2c_resume,
.id_table = wm8753_i2c_id,
};
#endif
@@ -1834,6 +1851,22 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&spi->dev);
+}
+
+static int wm8753_spi_resume(struct spi_device *spi)
+{
+ return snd_soc_resume_device(&spi->dev);
+}
+
+#else
+#define wm8753_spi_suspend NULL
+#define wm8753_spi_resume NULL
+#endif
+
static struct spi_driver wm8753_spi_driver = {
.driver = {
.name = "wm8753",
@@ -1842,6 +1875,8 @@ static struct spi_driver wm8753_spi_driver = {
},
.probe = wm8753_spi_probe,
.remove = __devexit_p(wm8753_spi_remove),
+ .suspend = wm8753_spi_suspend,
+ .resume = wm8753_spi_resume,
};
#endif
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 3c78945244b8..ac308993ac5a 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -116,6 +116,7 @@
#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
#define WM8900_REG_DACCTRL_MUTE 0x004
+#define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100
#define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
#define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800
@@ -439,7 +440,6 @@ SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
SOC_ENUM("DAC Mute Rate", dac_mute_rate),
SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
SOC_ENUM("DAC Deemphasis", dac_deemphasis),
-SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0),
SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
12, 1, 0),
@@ -743,6 +743,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
wm8900_write(codec, WM8900_REG_AUDIO1, reg);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg = wm8900_read(codec, WM8900_REG_DACCTRL);
+
+ if (params_rate(params) <= 24000)
+ reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
+ else
+ reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
+
+ wm8900_write(codec, WM8900_REG_DACCTRL, reg);
+ }
+
return 0;
}
@@ -1388,6 +1399,21 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8900_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8900_i2c_suspend NULL
+#define wm8900_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8900_i2c_id[] = {
{ "wm8900", 0 },
{ }
@@ -1401,6 +1427,8 @@ static struct i2c_driver wm8900_i2c_driver = {
},
.probe = wm8900_i2c_probe,
.remove = __devexit_p(wm8900_i2c_remove),
+ .suspend = wm8900_i2c_suspend,
+ .resume = wm8900_i2c_resume,
.id_table = wm8900_i2c_id,
};
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index e8d2e3e14c45..c9baeae3e275 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -715,8 +715,6 @@ SOC_ENUM("DAC Soft Mute Rate", soft_mute),
SOC_ENUM("DAC Mute Mode", mute_mode),
SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
SOC_ENUM("DAC De-emphasis", dac_deemphasis),
-SOC_SINGLE("DAC Sloping Stopband Filter Switch",
- WM8903_DAC_DIGITAL_1, 11, 1, 0),
SOC_ENUM("DAC Companding Mode", dac_companding),
SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
@@ -1373,12 +1371,19 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3);
u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0);
u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1);
+ u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
if (substream == wm8903->slave_substream) {
dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
+ /* Enable sloping stopband filter for low sample rates */
+ if (fs <= 24000)
+ dac_digital1 |= WM8903_DAC_SB_FILT;
+ else
+ dac_digital1 &= ~WM8903_DAC_SB_FILT;
+
/* Configure sample rate logic for DSP - choose nearest rate */
dsp_config = 0;
best_val = abs(sample_rates[dsp_config].rate - fs);
@@ -1503,6 +1508,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
+ wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
return 0;
}
@@ -1721,6 +1727,21 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8903_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8903_i2c_suspend NULL
+#define wm8903_i2c_resume NULL
+#endif
+
/* i2c codec control layer */
static const struct i2c_device_id wm8903_i2c_id[] = {
{ "wm8903", 0 },
@@ -1735,6 +1756,8 @@ static struct i2c_driver wm8903_i2c_driver = {
},
.probe = wm8903_i2c_probe,
.remove = __devexit_p(wm8903_i2c_remove),
+ .suspend = wm8903_i2c_suspend,
+ .resume = wm8903_i2c_resume,
.id_table = wm8903_i2c_id,
};
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b8e17d6bc1f7..b69210a77423 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -916,6 +916,21 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8940_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8940_i2c_suspend NULL
+#define wm8940_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8940_i2c_id[] = {
{ "wm8940", 0 },
{ }
@@ -929,6 +944,8 @@ static struct i2c_driver wm8940_i2c_driver = {
},
.probe = wm8940_i2c_probe,
.remove = __devexit_p(wm8940_i2c_remove),
+ .suspend = wm8940_i2c_suspend,
+ .resume = wm8940_i2c_resume,
.id_table = wm8940_i2c_id,
};
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index e224d8add170..d1769e6c0c44 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -810,7 +810,8 @@ static int wm8960_register(struct wm8960_priv *wm8960)
if (wm8960_codec) {
dev_err(codec->dev, "Another WM8960 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
if (!pdata) {
@@ -843,7 +844,7 @@ static int wm8960_register(struct wm8960_priv *wm8960)
ret = wm8960_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ goto err;
}
wm8960_dai.dev = codec->dev;
@@ -877,17 +878,22 @@ static int wm8960_register(struct wm8960_priv *wm8960)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err;
}
ret = snd_soc_register_dai(&wm8960_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ kfree(wm8960);
+ return ret;
}
static void wm8960_unregister(struct wm8960_priv *wm8960)
@@ -927,6 +933,21 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8960_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8960_i2c_suspend NULL
+#define wm8960_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8960_i2c_id[] = {
{ "wm8960", 0 },
{ }
@@ -940,6 +961,8 @@ static struct i2c_driver wm8960_i2c_driver = {
},
.probe = wm8960_i2c_probe,
.remove = __devexit_p(wm8960_i2c_remove),
+ .suspend = wm8960_i2c_suspend,
+ .resume = wm8960_i2c_resume,
.id_table = wm8960_i2c_id,
};
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
new file mode 100644
index 000000000000..bd1af92a122f
--- /dev/null
+++ b/sound/soc/codecs/wm8961.c
@@ -0,0 +1,1326 @@
+/*
+ * wm8961.c -- WM8961 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * 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.
+ *
+ * Currently unimplemented features:
+ * - ALC
+ */
+
+#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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8961.h"
+
+#define WM8961_MAX_REGISTER 0xFC
+
+static u16 wm8961_reg_defaults[] = {
+ 0x009F, /* R0 - Left Input volume */
+ 0x009F, /* R1 - Right Input volume */
+ 0x0000, /* R2 - LOUT1 volume */
+ 0x0000, /* R3 - ROUT1 volume */
+ 0x0020, /* R4 - Clocking1 */
+ 0x0008, /* R5 - ADC & DAC Control 1 */
+ 0x0000, /* R6 - ADC & DAC Control 2 */
+ 0x000A, /* R7 - Audio Interface 0 */
+ 0x01F4, /* R8 - Clocking2 */
+ 0x0000, /* R9 - Audio Interface 1 */
+ 0x00FF, /* R10 - Left DAC volume */
+ 0x00FF, /* R11 - Right DAC volume */
+ 0x0000, /* R12 */
+ 0x0000, /* R13 */
+ 0x0040, /* R14 - Audio Interface 2 */
+ 0x0000, /* R15 - Software Reset */
+ 0x0000, /* R16 */
+ 0x007B, /* R17 - ALC1 */
+ 0x0000, /* R18 - ALC2 */
+ 0x0032, /* R19 - ALC3 */
+ 0x0000, /* R20 - Noise Gate */
+ 0x00C0, /* R21 - Left ADC volume */
+ 0x00C0, /* R22 - Right ADC volume */
+ 0x0120, /* R23 - Additional control(1) */
+ 0x0000, /* R24 - Additional control(2) */
+ 0x0000, /* R25 - Pwr Mgmt (1) */
+ 0x0000, /* R26 - Pwr Mgmt (2) */
+ 0x0000, /* R27 - Additional Control (3) */
+ 0x0000, /* R28 - Anti-pop */
+ 0x0000, /* R29 */
+ 0x005F, /* R30 - Clocking 3 */
+ 0x0000, /* R31 */
+ 0x0000, /* R32 - ADCL signal path */
+ 0x0000, /* R33 - ADCR signal path */
+ 0x0000, /* R34 */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 */
+ 0x0000, /* R37 */
+ 0x0000, /* R38 */
+ 0x0000, /* R39 */
+ 0x0000, /* R40 - LOUT2 volume */
+ 0x0000, /* R41 - ROUT2 volume */
+ 0x0000, /* R42 */
+ 0x0000, /* R43 */
+ 0x0000, /* R44 */
+ 0x0000, /* R45 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 - Pwr Mgmt (3) */
+ 0x0023, /* R48 - Additional Control (4) */
+ 0x0000, /* R49 - Class D Control 1 */
+ 0x0000, /* R50 */
+ 0x0003, /* R51 - Class D Control 2 */
+ 0x0000, /* R52 */
+ 0x0000, /* R53 */
+ 0x0000, /* R54 */
+ 0x0000, /* R55 */
+ 0x0106, /* R56 - Clocking 4 */
+ 0x0000, /* R57 - DSP Sidetone 0 */
+ 0x0000, /* R58 - DSP Sidetone 1 */
+ 0x0000, /* R59 */
+ 0x0000, /* R60 - DC Servo 0 */
+ 0x0000, /* R61 - DC Servo 1 */
+ 0x0000, /* R62 */
+ 0x015E, /* R63 - DC Servo 3 */
+ 0x0010, /* R64 */
+ 0x0010, /* R65 - DC Servo 5 */
+ 0x0000, /* R66 */
+ 0x0001, /* R67 */
+ 0x0003, /* R68 - Analogue PGA Bias */
+ 0x0000, /* R69 - Analogue HP 0 */
+ 0x0060, /* R70 */
+ 0x01FB, /* R71 - Analogue HP 2 */
+ 0x0000, /* R72 - Charge Pump 1 */
+ 0x0065, /* R73 */
+ 0x005F, /* R74 */
+ 0x0059, /* R75 */
+ 0x006B, /* R76 */
+ 0x0038, /* R77 */
+ 0x000C, /* R78 */
+ 0x000A, /* R79 */
+ 0x006B, /* R80 */
+ 0x0000, /* R81 */
+ 0x0000, /* R82 - Charge Pump B */
+ 0x0087, /* R83 */
+ 0x0000, /* R84 */
+ 0x005C, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 - Write Sequencer 1 */
+ 0x0000, /* R88 - Write Sequencer 2 */
+ 0x0000, /* R89 - Write Sequencer 3 */
+ 0x0000, /* R90 - Write Sequencer 4 */
+ 0x0000, /* R91 - Write Sequencer 5 */
+ 0x0000, /* R92 - Write Sequencer 6 */
+ 0x0000, /* R93 - Write Sequencer 7 */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 */
+ 0x0000, /* R97 */
+ 0x0000, /* R98 */
+ 0x0000, /* R99 */
+ 0x0000, /* R100 */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x0000, /* R104 */
+ 0x0000, /* R105 */
+ 0x0000, /* R106 */
+ 0x0000, /* R107 */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 */
+ 0x0000, /* R112 */
+ 0x0000, /* R113 */
+ 0x0000, /* R114 */
+ 0x0000, /* R115 */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x0000, /* R128 */
+ 0x0000, /* R129 */
+ 0x0000, /* R130 */
+ 0x0000, /* R131 */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 */
+ 0x0000, /* R134 */
+ 0x0000, /* R135 */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0000, /* R140 */
+ 0x0000, /* R141 */
+ 0x0000, /* R142 */
+ 0x0000, /* R143 */
+ 0x0000, /* R144 */
+ 0x0000, /* R145 */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x0000, /* R152 */
+ 0x0000, /* R153 */
+ 0x0000, /* R154 */
+ 0x0000, /* R155 */
+ 0x0000, /* R156 */
+ 0x0000, /* R157 */
+ 0x0000, /* R158 */
+ 0x0000, /* R159 */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 */
+ 0x0000, /* R164 */
+ 0x0000, /* R165 */
+ 0x0000, /* R166 */
+ 0x0000, /* R167 */
+ 0x0000, /* R168 */
+ 0x0000, /* R169 */
+ 0x0000, /* R170 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 */
+ 0x0000, /* R173 */
+ 0x0000, /* R174 */
+ 0x0000, /* R175 */
+ 0x0000, /* R176 */
+ 0x0000, /* R177 */
+ 0x0000, /* R178 */
+ 0x0000, /* R179 */
+ 0x0000, /* R180 */
+ 0x0000, /* R181 */
+ 0x0000, /* R182 */
+ 0x0000, /* R183 */
+ 0x0000, /* R184 */
+ 0x0000, /* R185 */
+ 0x0000, /* R186 */
+ 0x0000, /* R187 */
+ 0x0000, /* R188 */
+ 0x0000, /* R189 */
+ 0x0000, /* R190 */
+ 0x0000, /* R191 */
+ 0x0000, /* R192 */
+ 0x0000, /* R193 */
+ 0x0000, /* R194 */
+ 0x0000, /* R195 */
+ 0x0030, /* R196 */
+ 0x0006, /* R197 */
+ 0x0000, /* R198 */
+ 0x0060, /* R199 */
+ 0x0000, /* R200 */
+ 0x003F, /* R201 */
+ 0x0000, /* R202 */
+ 0x0000, /* R203 */
+ 0x0000, /* R204 */
+ 0x0001, /* R205 */
+ 0x0000, /* R206 */
+ 0x0181, /* R207 */
+ 0x0005, /* R208 */
+ 0x0008, /* R209 */
+ 0x0008, /* R210 */
+ 0x0000, /* R211 */
+ 0x013B, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 */
+ 0x0000, /* R216 */
+ 0x0070, /* R217 */
+ 0x0000, /* R218 */
+ 0x0000, /* R219 */
+ 0x0000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0003, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 */
+ 0x0001, /* R226 */
+ 0x0008, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0x0000, /* R230 */
+ 0x0000, /* R231 */
+ 0x0004, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0080, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0052, /* R245 */
+ 0x0110, /* R246 */
+ 0x0040, /* R247 */
+ 0x0000, /* R248 */
+ 0x0030, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0001, /* R252 - General test 1 */
+};
+
+struct wm8961_priv {
+ struct snd_soc_codec codec;
+ int sysclk;
+ u16 reg_cache[WM8961_MAX_REGISTER];
+};
+
+static int wm8961_reg_is_volatile(int reg)
+{
+ switch (reg) {
+ case WM8961_WRITE_SEQUENCER_7:
+ case WM8961_DC_SERVO_1:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+ BUG_ON(reg > WM8961_MAX_REGISTER);
+ return cache[reg];
+}
+
+static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg)
+{
+ struct i2c_msg xfer[2];
+ u16 data;
+ int ret;
+ struct i2c_client *client = codec->control_data;
+
+ BUG_ON(reg > WM8961_MAX_REGISTER);
+
+ /* Write register */
+ xfer[0].addr = client->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = client->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = 2;
+ xfer[1].buf = (u8 *)&data;
+
+ ret = i2c_transfer(client->adapter, xfer, 2);
+ if (ret != 2) {
+ dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+ return 0;
+ }
+
+ return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ if (wm8961_reg_is_volatile(reg))
+ return wm8961_read_hw(codec, reg);
+ else
+ return wm8961_read_reg_cache(codec, reg);
+}
+
+static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u16 *cache = codec->reg_cache;
+ u8 data[3];
+
+ BUG_ON(reg > WM8961_MAX_REGISTER);
+
+ if (!wm8961_reg_is_volatile(reg))
+ cache[reg] = value;
+
+ data[0] = reg;
+ data[1] = value >> 8;
+ data[2] = value & 0x00ff;
+
+ if (codec->hw_write(codec->control_data, data, 3) == 3)
+ return 0;
+ else
+ return -EIO;
+}
+
+static int wm8961_reset(struct snd_soc_codec *codec)
+{
+ return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0);
+}
+
+/*
+ * The headphone output supports special anti-pop sequences giving
+ * silent power up and power down.
+ */
+static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0);
+ u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1);
+ u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2);
+ u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1);
+ int timeout = 500;
+
+ if (event & SND_SOC_DAPM_POST_PMU) {
+ /* Make sure the output is shorted */
+ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Enable the charge pump */
+ cp_reg |= WM8961_CP_ENA;
+ wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
+ mdelay(5);
+
+ /* Enable the PGA */
+ pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
+ wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+
+ /* Enable the amplifier */
+ hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Second stage enable */
+ hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Enable the DC servo & trigger startup */
+ dcs_reg |=
+ WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR |
+ WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
+ dev_dbg(codec->dev, "Enabling DC servo\n");
+
+ wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+ do {
+ msleep(1);
+ dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1);
+ } while (--timeout &&
+ dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
+ WM8961_DCS_TRIG_STARTUP_HPL));
+ if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
+ WM8961_DCS_TRIG_STARTUP_HPL))
+ dev_err(codec->dev, "DC servo timed out\n");
+ else
+ dev_dbg(codec->dev, "DC servo startup complete\n");
+
+ /* Enable the output stage */
+ hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Remove the short on the output stage */
+ hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+ }
+
+ if (event & SND_SOC_DAPM_PRE_PMD) {
+ /* Short the output */
+ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Disable the output stage */
+ hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Disable DC offset cancellation */
+ dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
+ WM8961_DCS_ENA_CHAN_HPL);
+ wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+
+ /* Finish up */
+ hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
+ WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
+ wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+
+ /* Disable the PGA */
+ pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
+ wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+
+ /* Disable the charge pump */
+ dev_dbg(codec->dev, "Disabling charge pump\n");
+ wm8961_write(codec, WM8961_CHARGE_PUMP_1,
+ cp_reg & ~WM8961_CP_ENA);
+ }
+
+ return 0;
+}
+
+static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2);
+ u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1);
+
+ if (event & SND_SOC_DAPM_POST_PMU) {
+ /* Enable the PGA */
+ pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA;
+ wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+
+ /* Enable the amplifier */
+ spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA;
+ wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+ }
+
+ if (event & SND_SOC_DAPM_PRE_PMD) {
+ /* Enable the amplifier */
+ spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
+ wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+
+ /* Enable the PGA */
+ pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
+ wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+ }
+
+ return 0;
+}
+
+static const char *adc_hpf_text[] = {
+ "Hi-fi", "Voice 1", "Voice 2", "Voice 3",
+};
+
+static const struct soc_enum adc_hpf =
+ SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text);
+
+static const char *dac_deemph_text[] = {
+ "None", "32kHz", "44.1kHz", "48kHz",
+};
+
+static const struct soc_enum dac_deemph =
+ SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static unsigned int boost_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(13, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(20, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0);
+
+static const struct snd_kcontrol_new wm8961_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME,
+ 0, 127, 0, out_tlv),
+SOC_DOUBLE_TLV("Headphone Secondary Volume", WM8961_ANALOGUE_HP_2,
+ 6, 3, 7, 0, hp_sec_tlv),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME,
+ 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME,
+ 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME,
+ 7, 1, 0),
+SOC_SINGLE("Speaker AC Gain", WM8961_CLASS_D_CONTROL_2, 0, 7, 0),
+
+SOC_SINGLE("DAC x128 OSR Switch", WM8961_ADC_DAC_CONTROL_2, 0, 1, 0),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+SOC_SINGLE("DAC Soft Mute Switch", WM8961_ADC_DAC_CONTROL_2, 3, 1, 0),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8961_DSP_SIDETONE_0,
+ WM8961_DSP_SIDETONE_1, 4, 12, 0, sidetone_tlv),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8961_ADC_DAC_CONTROL_1, 0, 1, 0),
+SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
+
+SOC_DOUBLE_R_TLV("Capture Volume",
+ WM8961_LEFT_ADC_VOLUME, WM8961_RIGHT_ADC_VOLUME,
+ 1, 119, 0, adc_tlv),
+SOC_DOUBLE_R_TLV("Capture Boost Volume",
+ WM8961_ADCL_SIGNAL_PATH, WM8961_ADCR_SIGNAL_PATH,
+ 4, 3, 0, boost_tlv),
+SOC_DOUBLE_R_TLV("Capture PGA Volume",
+ WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+ 0, 62, 0, pga_tlv),
+SOC_DOUBLE_R("Capture PGA ZC Switch",
+ WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+ 6, 1, 1),
+SOC_DOUBLE_R("Capture PGA Switch",
+ WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+ 7, 1, 1),
+};
+
+static const char *sidetone_text[] = {
+ "None", "Left", "Right"
+};
+
+static const struct soc_enum dacl_sidetone =
+ SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text);
+
+static const struct soc_enum dacr_sidetone =
+ SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text);
+
+static const struct snd_kcontrol_new dacl_mux =
+ SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone);
+
+static const struct snd_kcontrol_new dacr_mux =
+ SOC_DAPM_ENUM("DACR Sidetone", dacr_sidetone);
+
+static const struct snd_soc_dapm_widget wm8961_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT"),
+SND_SOC_DAPM_INPUT("RINPUT"),
+
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8961_CLOCKING2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Input", WM8961_PWR_MGMT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Input", WM8961_PWR_MGMT_1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", WM8961_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", WM8961_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8961_PWR_MGMT_1, 1, 0),
+
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &dacl_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &dacr_mux),
+
+SND_SOC_DAPM_DAC("DACL", "HiFi Playback", WM8961_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "HiFi Playback", WM8961_PWR_MGMT_2, 7, 0),
+
+/* Handle as a mono path for DCS */
+SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM,
+ 4, 0, NULL, 0, wm8961_hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("Speaker Output", SND_SOC_NOPM,
+ 4, 0, NULL, 0, wm8961_spk_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+SND_SOC_DAPM_OUTPUT("SPK_LN"),
+SND_SOC_DAPM_OUTPUT("SPK_LP"),
+SND_SOC_DAPM_OUTPUT("SPK_RN"),
+SND_SOC_DAPM_OUTPUT("SPK_RP"),
+};
+
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+ { "DACL", NULL, "CLK_DSP" },
+ { "DACL", NULL, "DACL Sidetone" },
+ { "DACR", NULL, "CLK_DSP" },
+ { "DACR", NULL, "DACR Sidetone" },
+
+ { "DACL Sidetone", "Left", "ADCL" },
+ { "DACL Sidetone", "Right", "ADCR" },
+
+ { "DACR Sidetone", "Left", "ADCL" },
+ { "DACR Sidetone", "Right", "ADCR" },
+
+ { "HP_L", NULL, "Headphone Output" },
+ { "HP_R", NULL, "Headphone Output" },
+ { "Headphone Output", NULL, "DACL" },
+ { "Headphone Output", NULL, "DACR" },
+
+ { "SPK_LN", NULL, "Speaker Output" },
+ { "SPK_LP", NULL, "Speaker Output" },
+ { "SPK_RN", NULL, "Speaker Output" },
+ { "SPK_RP", NULL, "Speaker Output" },
+
+ { "Speaker Output", NULL, "DACL" },
+ { "Speaker Output", NULL, "DACR" },
+
+ { "ADCL", NULL, "Left Input" },
+ { "ADCL", NULL, "CLK_DSP" },
+ { "ADCR", NULL, "Right Input" },
+ { "ADCR", NULL, "CLK_DSP" },
+
+ { "Left Input", NULL, "LINPUT" },
+ { "Right Input", NULL, "RINPUT" },
+
+};
+
+/* Values for CLK_SYS_RATE */
+static struct {
+ int ratio;
+ u16 val;
+} wm8961_clk_sys_ratio[] = {
+ { 64, 0 },
+ { 128, 1 },
+ { 192, 2 },
+ { 256, 3 },
+ { 384, 4 },
+ { 512, 5 },
+ { 768, 6 },
+ { 1024, 7 },
+ { 1408, 8 },
+ { 1536, 9 },
+};
+
+/* Values for SAMPLE_RATE */
+static struct {
+ int rate;
+ u16 val;
+} wm8961_srate[] = {
+ { 48000, 0 },
+ { 44100, 0 },
+ { 32000, 1 },
+ { 22050, 2 },
+ { 24000, 2 },
+ { 16000, 3 },
+ { 11250, 4 },
+ { 12000, 4 },
+ { 8000, 5 },
+};
+
+static int wm8961_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 wm8961_priv *wm8961 = codec->private_data;
+ int i, best, target, fs;
+ u16 reg;
+
+ fs = params_rate(params);
+
+ if (!wm8961->sysclk) {
+ dev_err(codec->dev, "MCLK has not been specified\n");
+ return -EINVAL;
+ }
+
+ /* Find the closest sample rate for the filters */
+ best = 0;
+ for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) {
+ if (abs(wm8961_srate[i].rate - fs) <
+ abs(wm8961_srate[best].rate - fs))
+ best = i;
+ }
+ reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3);
+ reg &= ~WM8961_SAMPLE_RATE_MASK;
+ reg |= wm8961_srate[best].val;
+ wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
+ dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n",
+ wm8961_srate[best].rate, fs);
+
+ /* Select a CLK_SYS/fs ratio equal to or higher than required */
+ target = wm8961->sysclk / fs;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) {
+ dev_err(codec->dev,
+ "SYSCLK must be at least 64*fs for DAC\n");
+ return -EINVAL;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) {
+ dev_err(codec->dev,
+ "SYSCLK must be at least 256*fs for ADC\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) {
+ if (wm8961_clk_sys_ratio[i].ratio >= target)
+ break;
+ }
+ if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) {
+ dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n");
+ return -EINVAL;
+ }
+ dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n",
+ wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
+ wm8961->sysclk / fs);
+
+ reg = wm8961_read(codec, WM8961_CLOCKING_4);
+ reg &= ~WM8961_CLK_SYS_RATE_MASK;
+ reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
+ wm8961_write(codec, WM8961_CLOCKING_4, reg);
+
+ reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0);
+ reg &= ~WM8961_WL_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ reg |= 1 << WM8961_WL_SHIFT;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ reg |= 2 << WM8961_WL_SHIFT;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ reg |= 3 << WM8961_WL_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg);
+
+ /* Sloping stop-band filter is recommended for <= 24kHz */
+ reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2);
+ if (fs <= 24000)
+ reg |= WM8961_DACSLOPE;
+ else
+ reg &= WM8961_DACSLOPE;
+ wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+
+ return 0;
+}
+
+static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq,
+ int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8961_priv *wm8961 = codec->private_data;
+ u16 reg = wm8961_read(codec, WM8961_CLOCKING1);
+
+ if (freq > 33000000) {
+ dev_err(codec->dev, "MCLK must be <33MHz\n");
+ return -EINVAL;
+ }
+
+ if (freq > 16500000) {
+ dev_dbg(codec->dev, "Using MCLK/2 for %dHz MCLK\n", freq);
+ reg |= WM8961_MCLKDIV;
+ freq /= 2;
+ } else {
+ dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq);
+ reg &= WM8961_MCLKDIV;
+ }
+
+ wm8961_write(codec, WM8961_CLOCKING1, reg);
+
+ wm8961->sysclk = freq;
+
+ return 0;
+}
+
+static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0);
+
+ aif &= ~(WM8961_BCLKINV | WM8961_LRP |
+ WM8961_MS | WM8961_FORMAT_MASK);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aif |= WM8961_MS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ aif |= 1;
+ break;
+
+ case SND_SOC_DAIFMT_I2S:
+ aif |= 2;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ aif |= WM8961_LRP;
+ case SND_SOC_DAIFMT_DSP_A:
+ aif |= 3;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aif |= WM8961_LRP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif |= WM8961_BCLKINV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aif |= WM8961_BCLKINV | WM8961_LRP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
+}
+
+static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2);
+
+ if (tristate)
+ reg |= WM8961_TRIS;
+ else
+ reg &= ~WM8961_TRIS;
+
+ return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg);
+}
+
+static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1);
+
+ if (mute)
+ reg |= WM8961_DACMU;
+ else
+ reg &= ~WM8961_DACMU;
+
+ msleep(17);
+
+ return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg);
+}
+
+static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg;
+
+ switch (div_id) {
+ case WM8961_BCLK:
+ reg = wm8961_read(codec, WM8961_CLOCKING2);
+ reg &= ~WM8961_BCLKDIV_MASK;
+ reg |= div;
+ wm8961_write(codec, WM8961_CLOCKING2, reg);
+ break;
+
+ case WM8961_LRCLK:
+ reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2);
+ reg &= ~WM8961_LRCLK_RATE_MASK;
+ reg |= div;
+ wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8961_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u16 reg;
+
+ /* This is all slightly unusual since we have no bypass paths
+ * and the output amplifier structure means we can just slam
+ * the biases straight up rather than having to ramp them
+ * slowly.
+ */
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ if (codec->bias_level == SND_SOC_BIAS_STANDBY) {
+ /* Enable bias generation */
+ reg = wm8961_read(codec, WM8961_ANTI_POP);
+ reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
+ wm8961_write(codec, WM8961_ANTI_POP, reg);
+
+ /* VMID=2*50k, VREF */
+ reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+ reg &= ~WM8961_VMIDSEL_MASK;
+ reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF;
+ wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+ }
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_PREPARE) {
+ /* VREF off */
+ reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+ reg &= ~WM8961_VREF;
+ wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+
+ /* Bias generation off */
+ reg = wm8961_read(codec, WM8961_ANTI_POP);
+ reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN);
+ wm8961_write(codec, WM8961_ANTI_POP, reg);
+
+ /* VMID off */
+ reg = wm8961_read(codec, WM8961_PWR_MGMT_1);
+ reg &= ~WM8961_VMIDSEL_MASK;
+ wm8961_write(codec, WM8961_PWR_MGMT_1, reg);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+
+ codec->bias_level = level;
+
+ return 0;
+}
+
+
+#define WM8961_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8961_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8961_dai_ops = {
+ .hw_params = wm8961_hw_params,
+ .set_sysclk = wm8961_set_sysclk,
+ .set_fmt = wm8961_set_fmt,
+ .digital_mute = wm8961_digital_mute,
+ .set_tristate = wm8961_set_tristate,
+ .set_clkdiv = wm8961_set_clkdiv,
+};
+
+struct snd_soc_dai wm8961_dai = {
+ .name = "WM8961",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8961_RATES,
+ .formats = WM8961_FORMATS,},
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8961_RATES,
+ .formats = WM8961_FORMATS,},
+ .ops = &wm8961_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8961_dai);
+
+
+static struct snd_soc_codec *wm8961_codec;
+
+static int wm8961_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (wm8961_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = wm8961_codec;
+ codec = wm8961_codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, wm8961_snd_controls,
+ ARRAY_SIZE(wm8961_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+ ARRAY_SIZE(wm8961_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+ snd_soc_dapm_new_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;
+}
+
+static int wm8961_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8961_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int wm8961_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ for (i = 0; i < codec->reg_cache_size; i++) {
+ if (i == WM8961_SOFTWARE_RESET)
+ continue;
+
+ wm8961_write(codec, i, reg_cache[i]);
+ }
+
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define wm8961_suspend NULL
+#define wm8961_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_wm8961 = {
+ .probe = wm8961_probe,
+ .remove = wm8961_remove,
+ .suspend = wm8961_suspend,
+ .resume = wm8961_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961);
+
+static int wm8961_register(struct wm8961_priv *wm8961)
+{
+ struct snd_soc_codec *codec = &wm8961->codec;
+ int ret;
+ u16 reg;
+
+ if (wm8961_codec) {
+ dev_err(codec->dev, "Another WM8961 is registered\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->private_data = wm8961;
+ codec->name = "WM8961";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8961_read;
+ codec->write = wm8961_write;
+ codec->dai = &wm8961_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
+ codec->reg_cache = &wm8961->reg_cache;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8961_set_bias_level;
+
+ memcpy(codec->reg_cache, wm8961_reg_defaults,
+ sizeof(wm8961_reg_defaults));
+
+ reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET);
+ if (reg != 0x1801) {
+ dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME);
+ dev_info(codec->dev, "WM8961 family %d revision %c\n",
+ (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
+ ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
+ + 'A');
+
+ ret = wm8961_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
+ }
+
+ /* Enable class W */
+ reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B);
+ reg |= WM8961_CP_DYN_PWR_MASK;
+ wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg);
+
+ /* Latch volume update bits (right channel only, we always
+ * write both out) and default ZC on. */
+ reg = wm8961_read(codec, WM8961_ROUT1_VOLUME);
+ wm8961_write(codec, WM8961_ROUT1_VOLUME,
+ reg | WM8961_LO1ZC | WM8961_OUT1VU);
+ wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
+ reg = wm8961_read(codec, WM8961_ROUT2_VOLUME);
+ wm8961_write(codec, WM8961_ROUT2_VOLUME,
+ reg | WM8961_SPKRZC | WM8961_SPKVU);
+ wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
+
+ reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME);
+ wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
+ reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME);
+ wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
+
+ /* Use soft mute by default */
+ reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2);
+ reg |= WM8961_DACSMM;
+ wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+
+ /* Use automatic clocking mode by default; for now this is all
+ * we support.
+ */
+ reg = wm8961_read(codec, WM8961_CLOCKING_3);
+ reg &= ~WM8961_MANUAL_MODE;
+ wm8961_write(codec, WM8961_CLOCKING_3, reg);
+
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ wm8961_dai.dev = codec->dev;
+
+ wm8961_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&wm8961_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
+
+ return 0;
+
+err:
+ kfree(wm8961);
+ return ret;
+}
+
+static void wm8961_unregister(struct wm8961_priv *wm8961)
+{
+ wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_dai(&wm8961_dai);
+ snd_soc_unregister_codec(&wm8961->codec);
+ kfree(wm8961);
+ wm8961_codec = NULL;
+}
+
+static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8961_priv *wm8961;
+ struct snd_soc_codec *codec;
+
+ wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
+ if (wm8961 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8961->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ i2c_set_clientdata(i2c, wm8961);
+ codec->control_data = i2c;
+
+ codec->dev = &i2c->dev;
+
+ return wm8961_register(wm8961);
+}
+
+static __devexit int wm8961_i2c_remove(struct i2c_client *client)
+{
+ struct wm8961_priv *wm8961 = i2c_get_clientdata(client);
+ wm8961_unregister(wm8961);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8961_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8961_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8961_i2c_suspend NULL
+#define wm8961_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id wm8961_i2c_id[] = {
+ { "wm8961", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
+
+static struct i2c_driver wm8961_i2c_driver = {
+ .driver = {
+ .name = "wm8961",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8961_i2c_probe,
+ .remove = __devexit_p(wm8961_i2c_remove),
+ .suspend = wm8961_i2c_suspend,
+ .resume = wm8961_i2c_resume,
+ .id_table = wm8961_i2c_id,
+};
+
+static int __init wm8961_modinit(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&wm8961_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+module_init(wm8961_modinit);
+
+static void __exit wm8961_exit(void)
+{
+ i2c_del_driver(&wm8961_i2c_driver);
+}
+module_exit(wm8961_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8961 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h
new file mode 100644
index 000000000000..5513bfd720d6
--- /dev/null
+++ b/sound/soc/codecs/wm8961.h
@@ -0,0 +1,866 @@
+/*
+ * wm8961.h -- WM8961 Soc Audio driver
+ *
+ * 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 _WM8961_H
+#define _WM8961_H
+
+#include <sound/soc.h>
+
+extern struct snd_soc_codec_device soc_codec_dev_wm8961;
+extern struct snd_soc_dai wm8961_dai;
+
+#define WM8961_BCLK 1
+#define WM8961_LRCLK 2
+
+#define WM8961_BCLK_DIV_1 0
+#define WM8961_BCLK_DIV_1_5 1
+#define WM8961_BCLK_DIV_2 2
+#define WM8961_BCLK_DIV_3 3
+#define WM8961_BCLK_DIV_4 4
+#define WM8961_BCLK_DIV_5_5 5
+#define WM8961_BCLK_DIV_6 6
+#define WM8961_BCLK_DIV_8 7
+#define WM8961_BCLK_DIV_11 8
+#define WM8961_BCLK_DIV_12 9
+#define WM8961_BCLK_DIV_16 10
+#define WM8961_BCLK_DIV_24 11
+#define WM8961_BCLK_DIV_32 13
+
+
+/*
+ * Register values.
+ */
+#define WM8961_LEFT_INPUT_VOLUME 0x00
+#define WM8961_RIGHT_INPUT_VOLUME 0x01
+#define WM8961_LOUT1_VOLUME 0x02
+#define WM8961_ROUT1_VOLUME 0x03
+#define WM8961_CLOCKING1 0x04
+#define WM8961_ADC_DAC_CONTROL_1 0x05
+#define WM8961_ADC_DAC_CONTROL_2 0x06
+#define WM8961_AUDIO_INTERFACE_0 0x07
+#define WM8961_CLOCKING2 0x08
+#define WM8961_AUDIO_INTERFACE_1 0x09
+#define WM8961_LEFT_DAC_VOLUME 0x0A
+#define WM8961_RIGHT_DAC_VOLUME 0x0B
+#define WM8961_AUDIO_INTERFACE_2 0x0E
+#define WM8961_SOFTWARE_RESET 0x0F
+#define WM8961_ALC1 0x11
+#define WM8961_ALC2 0x12
+#define WM8961_ALC3 0x13
+#define WM8961_NOISE_GATE 0x14
+#define WM8961_LEFT_ADC_VOLUME 0x15
+#define WM8961_RIGHT_ADC_VOLUME 0x16
+#define WM8961_ADDITIONAL_CONTROL_1 0x17
+#define WM8961_ADDITIONAL_CONTROL_2 0x18
+#define WM8961_PWR_MGMT_1 0x19
+#define WM8961_PWR_MGMT_2 0x1A
+#define WM8961_ADDITIONAL_CONTROL_3 0x1B
+#define WM8961_ANTI_POP 0x1C
+#define WM8961_CLOCKING_3 0x1E
+#define WM8961_ADCL_SIGNAL_PATH 0x20
+#define WM8961_ADCR_SIGNAL_PATH 0x21
+#define WM8961_LOUT2_VOLUME 0x28
+#define WM8961_ROUT2_VOLUME 0x29
+#define WM8961_PWR_MGMT_3 0x2F
+#define WM8961_ADDITIONAL_CONTROL_4 0x30
+#define WM8961_CLASS_D_CONTROL_1 0x31
+#define WM8961_CLASS_D_CONTROL_2 0x33
+#define WM8961_CLOCKING_4 0x38
+#define WM8961_DSP_SIDETONE_0 0x39
+#define WM8961_DSP_SIDETONE_1 0x3A
+#define WM8961_DC_SERVO_0 0x3C
+#define WM8961_DC_SERVO_1 0x3D
+#define WM8961_DC_SERVO_3 0x3F
+#define WM8961_DC_SERVO_5 0x41
+#define WM8961_ANALOGUE_PGA_BIAS 0x44
+#define WM8961_ANALOGUE_HP_0 0x45
+#define WM8961_ANALOGUE_HP_2 0x47
+#define WM8961_CHARGE_PUMP_1 0x48
+#define WM8961_CHARGE_PUMP_B 0x52
+#define WM8961_WRITE_SEQUENCER_1 0x57
+#define WM8961_WRITE_SEQUENCER_2 0x58
+#define WM8961_WRITE_SEQUENCER_3 0x59
+#define WM8961_WRITE_SEQUENCER_4 0x5A
+#define WM8961_WRITE_SEQUENCER_5 0x5B
+#define WM8961_WRITE_SEQUENCER_6 0x5C
+#define WM8961_WRITE_SEQUENCER_7 0x5D
+#define WM8961_GENERAL_TEST_1 0xFC
+
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8961_IPVU 0x0100 /* IPVU */
+#define WM8961_IPVU_MASK 0x0100 /* IPVU */
+#define WM8961_IPVU_SHIFT 8 /* IPVU */
+#define WM8961_IPVU_WIDTH 1 /* IPVU */
+#define WM8961_LINMUTE 0x0080 /* LINMUTE */
+#define WM8961_LINMUTE_MASK 0x0080 /* LINMUTE */
+#define WM8961_LINMUTE_SHIFT 7 /* LINMUTE */
+#define WM8961_LINMUTE_WIDTH 1 /* LINMUTE */
+#define WM8961_LIZC 0x0040 /* LIZC */
+#define WM8961_LIZC_MASK 0x0040 /* LIZC */
+#define WM8961_LIZC_SHIFT 6 /* LIZC */
+#define WM8961_LIZC_WIDTH 1 /* LIZC */
+#define WM8961_LINVOL_MASK 0x003F /* LINVOL - [5:0] */
+#define WM8961_LINVOL_SHIFT 0 /* LINVOL - [5:0] */
+#define WM8961_LINVOL_WIDTH 6 /* LINVOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8961_DEVICE_ID_MASK 0xF000 /* DEVICE_ID - [15:12] */
+#define WM8961_DEVICE_ID_SHIFT 12 /* DEVICE_ID - [15:12] */
+#define WM8961_DEVICE_ID_WIDTH 4 /* DEVICE_ID - [15:12] */
+#define WM8961_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */
+#define WM8961_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */
+#define WM8961_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */
+#define WM8961_IPVU 0x0100 /* IPVU */
+#define WM8961_IPVU_MASK 0x0100 /* IPVU */
+#define WM8961_IPVU_SHIFT 8 /* IPVU */
+#define WM8961_IPVU_WIDTH 1 /* IPVU */
+#define WM8961_RINMUTE 0x0080 /* RINMUTE */
+#define WM8961_RINMUTE_MASK 0x0080 /* RINMUTE */
+#define WM8961_RINMUTE_SHIFT 7 /* RINMUTE */
+#define WM8961_RINMUTE_WIDTH 1 /* RINMUTE */
+#define WM8961_RIZC 0x0040 /* RIZC */
+#define WM8961_RIZC_MASK 0x0040 /* RIZC */
+#define WM8961_RIZC_SHIFT 6 /* RIZC */
+#define WM8961_RIZC_WIDTH 1 /* RIZC */
+#define WM8961_RINVOL_MASK 0x003F /* RINVOL - [5:0] */
+#define WM8961_RINVOL_SHIFT 0 /* RINVOL - [5:0] */
+#define WM8961_RINVOL_WIDTH 6 /* RINVOL - [5:0] */
+
+/*
+ * R2 (0x02) - LOUT1 volume
+ */
+#define WM8961_OUT1VU 0x0100 /* OUT1VU */
+#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8961_LO1ZC 0x0080 /* LO1ZC */
+#define WM8961_LO1ZC_MASK 0x0080 /* LO1ZC */
+#define WM8961_LO1ZC_SHIFT 7 /* LO1ZC */
+#define WM8961_LO1ZC_WIDTH 1 /* LO1ZC */
+#define WM8961_LOUT1VOL_MASK 0x007F /* LOUT1VOL - [6:0] */
+#define WM8961_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [6:0] */
+#define WM8961_LOUT1VOL_WIDTH 7 /* LOUT1VOL - [6:0] */
+
+/*
+ * R3 (0x03) - ROUT1 volume
+ */
+#define WM8961_OUT1VU 0x0100 /* OUT1VU */
+#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8961_RO1ZC 0x0080 /* RO1ZC */
+#define WM8961_RO1ZC_MASK 0x0080 /* RO1ZC */
+#define WM8961_RO1ZC_SHIFT 7 /* RO1ZC */
+#define WM8961_RO1ZC_WIDTH 1 /* RO1ZC */
+#define WM8961_ROUT1VOL_MASK 0x007F /* ROUT1VOL - [6:0] */
+#define WM8961_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [6:0] */
+#define WM8961_ROUT1VOL_WIDTH 7 /* ROUT1VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8961_ADCDIV_MASK 0x01C0 /* ADCDIV - [8:6] */
+#define WM8961_ADCDIV_SHIFT 6 /* ADCDIV - [8:6] */
+#define WM8961_ADCDIV_WIDTH 3 /* ADCDIV - [8:6] */
+#define WM8961_DACDIV_MASK 0x0038 /* DACDIV - [5:3] */
+#define WM8961_DACDIV_SHIFT 3 /* DACDIV - [5:3] */
+#define WM8961_DACDIV_WIDTH 3 /* DACDIV - [5:3] */
+#define WM8961_MCLKDIV 0x0004 /* MCLKDIV */
+#define WM8961_MCLKDIV_MASK 0x0004 /* MCLKDIV */
+#define WM8961_MCLKDIV_SHIFT 2 /* MCLKDIV */
+#define WM8961_MCLKDIV_WIDTH 1 /* MCLKDIV */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8961_ADCPOL_MASK 0x0060 /* ADCPOL - [6:5] */
+#define WM8961_ADCPOL_SHIFT 5 /* ADCPOL - [6:5] */
+#define WM8961_ADCPOL_WIDTH 2 /* ADCPOL - [6:5] */
+#define WM8961_DACMU 0x0008 /* DACMU */
+#define WM8961_DACMU_MASK 0x0008 /* DACMU */
+#define WM8961_DACMU_SHIFT 3 /* DACMU */
+#define WM8961_DACMU_WIDTH 1 /* DACMU */
+#define WM8961_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */
+#define WM8961_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */
+#define WM8961_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */
+#define WM8961_ADCHPD 0x0001 /* ADCHPD */
+#define WM8961_ADCHPD_MASK 0x0001 /* ADCHPD */
+#define WM8961_ADCHPD_SHIFT 0 /* ADCHPD */
+#define WM8961_ADCHPD_WIDTH 1 /* ADCHPD */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8961_ADC_HPF_CUT_MASK 0x0180 /* ADC_HPF_CUT - [8:7] */
+#define WM8961_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [8:7] */
+#define WM8961_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [8:7] */
+#define WM8961_DACPOL_MASK 0x0060 /* DACPOL - [6:5] */
+#define WM8961_DACPOL_SHIFT 5 /* DACPOL - [6:5] */
+#define WM8961_DACPOL_WIDTH 2 /* DACPOL - [6:5] */
+#define WM8961_DACSMM 0x0008 /* DACSMM */
+#define WM8961_DACSMM_MASK 0x0008 /* DACSMM */
+#define WM8961_DACSMM_SHIFT 3 /* DACSMM */
+#define WM8961_DACSMM_WIDTH 1 /* DACSMM */
+#define WM8961_DACMR 0x0004 /* DACMR */
+#define WM8961_DACMR_MASK 0x0004 /* DACMR */
+#define WM8961_DACMR_SHIFT 2 /* DACMR */
+#define WM8961_DACMR_WIDTH 1 /* DACMR */
+#define WM8961_DACSLOPE 0x0002 /* DACSLOPE */
+#define WM8961_DACSLOPE_MASK 0x0002 /* DACSLOPE */
+#define WM8961_DACSLOPE_SHIFT 1 /* DACSLOPE */
+#define WM8961_DACSLOPE_WIDTH 1 /* DACSLOPE */
+#define WM8961_DAC_OSR128 0x0001 /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8961_ALRSWAP 0x0100 /* ALRSWAP */
+#define WM8961_ALRSWAP_MASK 0x0100 /* ALRSWAP */
+#define WM8961_ALRSWAP_SHIFT 8 /* ALRSWAP */
+#define WM8961_ALRSWAP_WIDTH 1 /* ALRSWAP */
+#define WM8961_BCLKINV 0x0080 /* BCLKINV */
+#define WM8961_BCLKINV_MASK 0x0080 /* BCLKINV */
+#define WM8961_BCLKINV_SHIFT 7 /* BCLKINV */
+#define WM8961_BCLKINV_WIDTH 1 /* BCLKINV */
+#define WM8961_MS 0x0040 /* MS */
+#define WM8961_MS_MASK 0x0040 /* MS */
+#define WM8961_MS_SHIFT 6 /* MS */
+#define WM8961_MS_WIDTH 1 /* MS */
+#define WM8961_DLRSWAP 0x0020 /* DLRSWAP */
+#define WM8961_DLRSWAP_MASK 0x0020 /* DLRSWAP */
+#define WM8961_DLRSWAP_SHIFT 5 /* DLRSWAP */
+#define WM8961_DLRSWAP_WIDTH 1 /* DLRSWAP */
+#define WM8961_LRP 0x0010 /* LRP */
+#define WM8961_LRP_MASK 0x0010 /* LRP */
+#define WM8961_LRP_SHIFT 4 /* LRP */
+#define WM8961_LRP_WIDTH 1 /* LRP */
+#define WM8961_WL_MASK 0x000C /* WL - [3:2] */
+#define WM8961_WL_SHIFT 2 /* WL - [3:2] */
+#define WM8961_WL_WIDTH 2 /* WL - [3:2] */
+#define WM8961_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
+#define WM8961_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
+#define WM8961_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8961_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */
+#define WM8961_DCLKDIV_SHIFT 6 /* DCLKDIV - [8:6] */
+#define WM8961_DCLKDIV_WIDTH 3 /* DCLKDIV - [8:6] */
+#define WM8961_CLK_SYS_ENA 0x0020 /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_MASK 0x0020 /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_SHIFT 5 /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */
+#define WM8961_CLK_DSP_ENA 0x0010 /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_MASK 0x0010 /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_SHIFT 4 /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */
+#define WM8961_BCLKDIV_MASK 0x000F /* BCLKDIV - [3:0] */
+#define WM8961_BCLKDIV_SHIFT 0 /* BCLKDIV - [3:0] */
+#define WM8961_BCLKDIV_WIDTH 4 /* BCLKDIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8961_DACCOMP_MASK 0x0018 /* DACCOMP - [4:3] */
+#define WM8961_DACCOMP_SHIFT 3 /* DACCOMP - [4:3] */
+#define WM8961_DACCOMP_WIDTH 2 /* DACCOMP - [4:3] */
+#define WM8961_ADCCOMP_MASK 0x0006 /* ADCCOMP - [2:1] */
+#define WM8961_ADCCOMP_SHIFT 1 /* ADCCOMP - [2:1] */
+#define WM8961_ADCCOMP_WIDTH 2 /* ADCCOMP - [2:1] */
+#define WM8961_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8961_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8961_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8961_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8961_DACVU 0x0100 /* DACVU */
+#define WM8961_DACVU_MASK 0x0100 /* DACVU */
+#define WM8961_DACVU_SHIFT 8 /* DACVU */
+#define WM8961_DACVU_WIDTH 1 /* DACVU */
+#define WM8961_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */
+#define WM8961_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */
+#define WM8961_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8961_DACVU 0x0100 /* DACVU */
+#define WM8961_DACVU_MASK 0x0100 /* DACVU */
+#define WM8961_DACVU_SHIFT 8 /* DACVU */
+#define WM8961_DACVU_WIDTH 1 /* DACVU */
+#define WM8961_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */
+#define WM8961_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */
+#define WM8961_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8961_LRCLK_RATE_MASK 0x01FF /* LRCLK_RATE - [8:0] */
+#define WM8961_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [8:0] */
+#define WM8961_LRCLK_RATE_WIDTH 9 /* LRCLK_RATE - [8:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8961_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8961_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8961_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8961_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
+#define WM8961_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
+#define WM8961_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
+#define WM8961_MAXGAIN_MASK 0x0070 /* MAXGAIN - [6:4] */
+#define WM8961_MAXGAIN_SHIFT 4 /* MAXGAIN - [6:4] */
+#define WM8961_MAXGAIN_WIDTH 3 /* MAXGAIN - [6:4] */
+#define WM8961_ALCL_MASK 0x000F /* ALCL - [3:0] */
+#define WM8961_ALCL_SHIFT 0 /* ALCL - [3:0] */
+#define WM8961_ALCL_WIDTH 4 /* ALCL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8961_ALCZC 0x0080 /* ALCZC */
+#define WM8961_ALCZC_MASK 0x0080 /* ALCZC */
+#define WM8961_ALCZC_SHIFT 7 /* ALCZC */
+#define WM8961_ALCZC_WIDTH 1 /* ALCZC */
+#define WM8961_MINGAIN_MASK 0x0070 /* MINGAIN - [6:4] */
+#define WM8961_MINGAIN_SHIFT 4 /* MINGAIN - [6:4] */
+#define WM8961_MINGAIN_WIDTH 3 /* MINGAIN - [6:4] */
+#define WM8961_HLD_MASK 0x000F /* HLD - [3:0] */
+#define WM8961_HLD_SHIFT 0 /* HLD - [3:0] */
+#define WM8961_HLD_WIDTH 4 /* HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8961_ALCMODE 0x0100 /* ALCMODE */
+#define WM8961_ALCMODE_MASK 0x0100 /* ALCMODE */
+#define WM8961_ALCMODE_SHIFT 8 /* ALCMODE */
+#define WM8961_ALCMODE_WIDTH 1 /* ALCMODE */
+#define WM8961_DCY_MASK 0x00F0 /* DCY - [7:4] */
+#define WM8961_DCY_SHIFT 4 /* DCY - [7:4] */
+#define WM8961_DCY_WIDTH 4 /* DCY - [7:4] */
+#define WM8961_ATK_MASK 0x000F /* ATK - [3:0] */
+#define WM8961_ATK_SHIFT 0 /* ATK - [3:0] */
+#define WM8961_ATK_WIDTH 4 /* ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8961_NGTH_MASK 0x00F8 /* NGTH - [7:3] */
+#define WM8961_NGTH_SHIFT 3 /* NGTH - [7:3] */
+#define WM8961_NGTH_WIDTH 5 /* NGTH - [7:3] */
+#define WM8961_NGG 0x0002 /* NGG */
+#define WM8961_NGG_MASK 0x0002 /* NGG */
+#define WM8961_NGG_SHIFT 1 /* NGG */
+#define WM8961_NGG_WIDTH 1 /* NGG */
+#define WM8961_NGAT 0x0001 /* NGAT */
+#define WM8961_NGAT_MASK 0x0001 /* NGAT */
+#define WM8961_NGAT_SHIFT 0 /* NGAT */
+#define WM8961_NGAT_WIDTH 1 /* NGAT */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8961_ADCVU 0x0100 /* ADCVU */
+#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8961_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8961_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8961_LADCVOL_MASK 0x00FF /* LADCVOL - [7:0] */
+#define WM8961_LADCVOL_SHIFT 0 /* LADCVOL - [7:0] */
+#define WM8961_LADCVOL_WIDTH 8 /* LADCVOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8961_ADCVU 0x0100 /* ADCVU */
+#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8961_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8961_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8961_RADCVOL_MASK 0x00FF /* RADCVOL - [7:0] */
+#define WM8961_RADCVOL_SHIFT 0 /* RADCVOL - [7:0] */
+#define WM8961_RADCVOL_WIDTH 8 /* RADCVOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8961_TSDEN 0x0100 /* TSDEN */
+#define WM8961_TSDEN_MASK 0x0100 /* TSDEN */
+#define WM8961_TSDEN_SHIFT 8 /* TSDEN */
+#define WM8961_TSDEN_WIDTH 1 /* TSDEN */
+#define WM8961_DMONOMIX 0x0010 /* DMONOMIX */
+#define WM8961_DMONOMIX_MASK 0x0010 /* DMONOMIX */
+#define WM8961_DMONOMIX_SHIFT 4 /* DMONOMIX */
+#define WM8961_DMONOMIX_WIDTH 1 /* DMONOMIX */
+#define WM8961_TOEN 0x0001 /* TOEN */
+#define WM8961_TOEN_MASK 0x0001 /* TOEN */
+#define WM8961_TOEN_SHIFT 0 /* TOEN */
+#define WM8961_TOEN_WIDTH 1 /* TOEN */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8961_TRIS 0x0008 /* TRIS */
+#define WM8961_TRIS_MASK 0x0008 /* TRIS */
+#define WM8961_TRIS_SHIFT 3 /* TRIS */
+#define WM8961_TRIS_WIDTH 1 /* TRIS */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8961_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */
+#define WM8961_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */
+#define WM8961_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */
+#define WM8961_VREF 0x0040 /* VREF */
+#define WM8961_VREF_MASK 0x0040 /* VREF */
+#define WM8961_VREF_SHIFT 6 /* VREF */
+#define WM8961_VREF_WIDTH 1 /* VREF */
+#define WM8961_AINL 0x0020 /* AINL */
+#define WM8961_AINL_MASK 0x0020 /* AINL */
+#define WM8961_AINL_SHIFT 5 /* AINL */
+#define WM8961_AINL_WIDTH 1 /* AINL */
+#define WM8961_AINR 0x0010 /* AINR */
+#define WM8961_AINR_MASK 0x0010 /* AINR */
+#define WM8961_AINR_SHIFT 4 /* AINR */
+#define WM8961_AINR_WIDTH 1 /* AINR */
+#define WM8961_ADCL 0x0008 /* ADCL */
+#define WM8961_ADCL_MASK 0x0008 /* ADCL */
+#define WM8961_ADCL_SHIFT 3 /* ADCL */
+#define WM8961_ADCL_WIDTH 1 /* ADCL */
+#define WM8961_ADCR 0x0004 /* ADCR */
+#define WM8961_ADCR_MASK 0x0004 /* ADCR */
+#define WM8961_ADCR_SHIFT 2 /* ADCR */
+#define WM8961_ADCR_WIDTH 1 /* ADCR */
+#define WM8961_MICB 0x0002 /* MICB */
+#define WM8961_MICB_MASK 0x0002 /* MICB */
+#define WM8961_MICB_SHIFT 1 /* MICB */
+#define WM8961_MICB_WIDTH 1 /* MICB */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8961_DACL 0x0100 /* DACL */
+#define WM8961_DACL_MASK 0x0100 /* DACL */
+#define WM8961_DACL_SHIFT 8 /* DACL */
+#define WM8961_DACL_WIDTH 1 /* DACL */
+#define WM8961_DACR 0x0080 /* DACR */
+#define WM8961_DACR_MASK 0x0080 /* DACR */
+#define WM8961_DACR_SHIFT 7 /* DACR */
+#define WM8961_DACR_WIDTH 1 /* DACR */
+#define WM8961_LOUT1_PGA 0x0040 /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_MASK 0x0040 /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_SHIFT 6 /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_WIDTH 1 /* LOUT1_PGA */
+#define WM8961_ROUT1_PGA 0x0020 /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_MASK 0x0020 /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_SHIFT 5 /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_WIDTH 1 /* ROUT1_PGA */
+#define WM8961_SPKL_PGA 0x0010 /* SPKL_PGA */
+#define WM8961_SPKL_PGA_MASK 0x0010 /* SPKL_PGA */
+#define WM8961_SPKL_PGA_SHIFT 4 /* SPKL_PGA */
+#define WM8961_SPKL_PGA_WIDTH 1 /* SPKL_PGA */
+#define WM8961_SPKR_PGA 0x0008 /* SPKR_PGA */
+#define WM8961_SPKR_PGA_MASK 0x0008 /* SPKR_PGA */
+#define WM8961_SPKR_PGA_SHIFT 3 /* SPKR_PGA */
+#define WM8961_SPKR_PGA_WIDTH 1 /* SPKR_PGA */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8961_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */
+#define WM8961_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */
+#define WM8961_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8961_BUFDCOPEN 0x0010 /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_MASK 0x0010 /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_SHIFT 4 /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */
+#define WM8961_BUFIOEN 0x0008 /* BUFIOEN */
+#define WM8961_BUFIOEN_MASK 0x0008 /* BUFIOEN */
+#define WM8961_BUFIOEN_SHIFT 3 /* BUFIOEN */
+#define WM8961_BUFIOEN_WIDTH 1 /* BUFIOEN */
+#define WM8961_SOFT_ST 0x0004 /* SOFT_ST */
+#define WM8961_SOFT_ST_MASK 0x0004 /* SOFT_ST */
+#define WM8961_SOFT_ST_SHIFT 2 /* SOFT_ST */
+#define WM8961_SOFT_ST_WIDTH 1 /* SOFT_ST */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8961_CLK_TO_DIV_MASK 0x0180 /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_TO_DIV_SHIFT 7 /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */
+#define WM8961_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */
+#define WM8961_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */
+#define WM8961_MANUAL_MODE 0x0001 /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_MASK 0x0001 /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_SHIFT 0 /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_WIDTH 1 /* MANUAL_MODE */
+
+/*
+ * R32 (0x20) - ADCL signal path
+ */
+#define WM8961_LMICBOOST_MASK 0x0030 /* LMICBOOST - [5:4] */
+#define WM8961_LMICBOOST_SHIFT 4 /* LMICBOOST - [5:4] */
+#define WM8961_LMICBOOST_WIDTH 2 /* LMICBOOST - [5:4] */
+
+/*
+ * R33 (0x21) - ADCR signal path
+ */
+#define WM8961_RMICBOOST_MASK 0x0030 /* RMICBOOST - [5:4] */
+#define WM8961_RMICBOOST_SHIFT 4 /* RMICBOOST - [5:4] */
+#define WM8961_RMICBOOST_WIDTH 2 /* RMICBOOST - [5:4] */
+
+/*
+ * R40 (0x28) - LOUT2 volume
+ */
+#define WM8961_SPKVU 0x0100 /* SPKVU */
+#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */
+#define WM8961_SPKVU_SHIFT 8 /* SPKVU */
+#define WM8961_SPKVU_WIDTH 1 /* SPKVU */
+#define WM8961_SPKLZC 0x0080 /* SPKLZC */
+#define WM8961_SPKLZC_MASK 0x0080 /* SPKLZC */
+#define WM8961_SPKLZC_SHIFT 7 /* SPKLZC */
+#define WM8961_SPKLZC_WIDTH 1 /* SPKLZC */
+#define WM8961_SPKLVOL_MASK 0x007F /* SPKLVOL - [6:0] */
+#define WM8961_SPKLVOL_SHIFT 0 /* SPKLVOL - [6:0] */
+#define WM8961_SPKLVOL_WIDTH 7 /* SPKLVOL - [6:0] */
+
+/*
+ * R41 (0x29) - ROUT2 volume
+ */
+#define WM8961_SPKVU 0x0100 /* SPKVU */
+#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */
+#define WM8961_SPKVU_SHIFT 8 /* SPKVU */
+#define WM8961_SPKVU_WIDTH 1 /* SPKVU */
+#define WM8961_SPKRZC 0x0080 /* SPKRZC */
+#define WM8961_SPKRZC_MASK 0x0080 /* SPKRZC */
+#define WM8961_SPKRZC_SHIFT 7 /* SPKRZC */
+#define WM8961_SPKRZC_WIDTH 1 /* SPKRZC */
+#define WM8961_SPKRVOL_MASK 0x007F /* SPKRVOL - [6:0] */
+#define WM8961_SPKRVOL_SHIFT 0 /* SPKRVOL - [6:0] */
+#define WM8961_SPKRVOL_WIDTH 7 /* SPKRVOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Pwr Mgmt (3)
+ */
+#define WM8961_TEMP_SHUT 0x0002 /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_MASK 0x0002 /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_SHIFT 1 /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */
+#define WM8961_TEMP_WARN 0x0001 /* TEMP_WARN */
+#define WM8961_TEMP_WARN_MASK 0x0001 /* TEMP_WARN */
+#define WM8961_TEMP_WARN_SHIFT 0 /* TEMP_WARN */
+#define WM8961_TEMP_WARN_WIDTH 1 /* TEMP_WARN */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8961_TSENSEN 0x0002 /* TSENSEN */
+#define WM8961_TSENSEN_MASK 0x0002 /* TSENSEN */
+#define WM8961_TSENSEN_SHIFT 1 /* TSENSEN */
+#define WM8961_TSENSEN_WIDTH 1 /* TSENSEN */
+#define WM8961_MBSEL 0x0001 /* MBSEL */
+#define WM8961_MBSEL_MASK 0x0001 /* MBSEL */
+#define WM8961_MBSEL_SHIFT 0 /* MBSEL */
+#define WM8961_MBSEL_WIDTH 1 /* MBSEL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8961_SPKR_ENA 0x0080 /* SPKR_ENA */
+#define WM8961_SPKR_ENA_MASK 0x0080 /* SPKR_ENA */
+#define WM8961_SPKR_ENA_SHIFT 7 /* SPKR_ENA */
+#define WM8961_SPKR_ENA_WIDTH 1 /* SPKR_ENA */
+#define WM8961_SPKL_ENA 0x0040 /* SPKL_ENA */
+#define WM8961_SPKL_ENA_MASK 0x0040 /* SPKL_ENA */
+#define WM8961_SPKL_ENA_SHIFT 6 /* SPKL_ENA */
+#define WM8961_SPKL_ENA_WIDTH 1 /* SPKL_ENA */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8961_CLASSD_ACGAIN_MASK 0x0007 /* CLASSD_ACGAIN - [2:0] */
+#define WM8961_CLASSD_ACGAIN_SHIFT 0 /* CLASSD_ACGAIN - [2:0] */
+#define WM8961_CLASSD_ACGAIN_WIDTH 3 /* CLASSD_ACGAIN - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8961_CLK_DCS_DIV_MASK 0x01E0 /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_DCS_DIV_SHIFT 5 /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */
+#define WM8961_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */
+#define WM8961_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DSP Sidetone 0
+ */
+#define WM8961_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */
+#define WM8961_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */
+#define WM8961_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DSP Sidetone 1
+ */
+#define WM8961_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
+#define WM8961_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
+#define WM8961_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8961_DCS_ENA_CHAN_INL 0x0080 /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_MASK 0x0080 /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_SHIFT 7 /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_WIDTH 1 /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL 0x0040 /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_MASK 0x0040 /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_SHIFT 6 /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_WIDTH 1 /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_SERIES_INL 0x0010 /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_MASK 0x0010 /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_SHIFT 4 /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_WIDTH 1 /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_ENA_CHAN_INR 0x0008 /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_MASK 0x0008 /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_SHIFT 3 /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_WIDTH 1 /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR 0x0004 /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_MASK 0x0004 /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_SHIFT 2 /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_WIDTH 1 /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_SERIES_INR 0x0001 /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_MASK 0x0001 /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_SHIFT 0 /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_WIDTH 1 /* DCS_TRIG_SERIES_INR */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8961_DCS_ENA_CHAN_HPL 0x0080 /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_MASK 0x0080 /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_SHIFT 7 /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_WIDTH 1 /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL 0x0040 /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_MASK 0x0040 /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_SHIFT 6 /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_WIDTH 1 /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL 0x0010 /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_MASK 0x0010 /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_SHIFT 4 /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_WIDTH 1 /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_ENA_CHAN_HPR 0x0008 /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_MASK 0x0008 /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_SHIFT 3 /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_WIDTH 1 /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR 0x0004 /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_MASK 0x0004 /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_SHIFT 2 /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_WIDTH 1 /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR 0x0001 /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_MASK 0x0001 /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_SHIFT 0 /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_WIDTH 1 /* DCS_TRIG_SERIES_HPR */
+
+/*
+ * R63 (0x3F) - DC Servo 3
+ */
+#define WM8961_DCS_FILT_BW_SERIES_MASK 0x0030 /* DCS_FILT_BW_SERIES - [5:4] */
+#define WM8961_DCS_FILT_BW_SERIES_SHIFT 4 /* DCS_FILT_BW_SERIES - [5:4] */
+#define WM8961_DCS_FILT_BW_SERIES_WIDTH 2 /* DCS_FILT_BW_SERIES - [5:4] */
+
+/*
+ * R65 (0x41) - DC Servo 5
+ */
+#define WM8961_DCS_SERIES_NO_HP_MASK 0x007F /* DCS_SERIES_NO_HP - [6:0] */
+#define WM8961_DCS_SERIES_NO_HP_SHIFT 0 /* DCS_SERIES_NO_HP - [6:0] */
+#define WM8961_DCS_SERIES_NO_HP_WIDTH 7 /* DCS_SERIES_NO_HP - [6:0] */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8961_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */
+#define WM8961_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */
+#define WM8961_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8961_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */
+#define WM8961_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA 0x0010 /* HPL_ENA */
+#define WM8961_HPL_ENA_MASK 0x0010 /* HPL_ENA */
+#define WM8961_HPL_ENA_SHIFT 4 /* HPL_ENA */
+#define WM8961_HPL_ENA_WIDTH 1 /* HPL_ENA */
+#define WM8961_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */
+#define WM8961_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA 0x0001 /* HPR_ENA */
+#define WM8961_HPR_ENA_MASK 0x0001 /* HPR_ENA */
+#define WM8961_HPR_ENA_SHIFT 0 /* HPR_ENA */
+#define WM8961_HPR_ENA_WIDTH 1 /* HPR_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8961_HPL_VOL_MASK 0x01C0 /* HPL_VOL - [8:6] */
+#define WM8961_HPL_VOL_SHIFT 6 /* HPL_VOL - [8:6] */
+#define WM8961_HPL_VOL_WIDTH 3 /* HPL_VOL - [8:6] */
+#define WM8961_HPR_VOL_MASK 0x0038 /* HPR_VOL - [5:3] */
+#define WM8961_HPR_VOL_SHIFT 3 /* HPR_VOL - [5:3] */
+#define WM8961_HPR_VOL_WIDTH 3 /* HPR_VOL - [5:3] */
+#define WM8961_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */
+#define WM8961_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */
+#define WM8961_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8961_CP_ENA 0x0001 /* CP_ENA */
+#define WM8961_CP_ENA_MASK 0x0001 /* CP_ENA */
+#define WM8961_CP_ENA_SHIFT 0 /* CP_ENA */
+#define WM8961_CP_ENA_WIDTH 1 /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8961_CP_DYN_PWR_MASK 0x0003 /* CP_DYN_PWR - [1:0] */
+#define WM8961_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR - [1:0] */
+#define WM8961_CP_DYN_PWR_WIDTH 2 /* CP_DYN_PWR - [1:0] */
+
+/*
+ * R87 (0x57) - Write Sequencer 1
+ */
+#define WM8961_WSEQ_ENA 0x0020 /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
+#define WM8961_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8961_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8961_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R88 (0x58) - Write Sequencer 2
+ */
+#define WM8961_WSEQ_EOS 0x0100 /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_MASK 0x0100 /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_SHIFT 8 /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
+#define WM8961_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
+#define WM8961_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
+#define WM8961_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R89 (0x59) - Write Sequencer 3
+ */
+#define WM8961_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
+#define WM8961_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
+#define WM8961_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
+
+/*
+ * R90 (0x5A) - Write Sequencer 4
+ */
+#define WM8961_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
+#define WM8961_WSEQ_START 0x0080 /* WSEQ_START */
+#define WM8961_WSEQ_START_MASK 0x0080 /* WSEQ_START */
+#define WM8961_WSEQ_START_SHIFT 7 /* WSEQ_START */
+#define WM8961_WSEQ_START_WIDTH 1 /* WSEQ_START */
+#define WM8961_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
+#define WM8961_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
+#define WM8961_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R91 (0x5B) - Write Sequencer 5
+ */
+#define WM8961_WSEQ_DATA_WIDTH_MASK 0x0070 /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_WIDTH_SHIFT 4 /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_START_MASK 0x000F /* WSEQ_DATA_START - [3:0] */
+#define WM8961_WSEQ_DATA_START_SHIFT 0 /* WSEQ_DATA_START - [3:0] */
+#define WM8961_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [3:0] */
+
+/*
+ * R92 (0x5C) - Write Sequencer 6
+ */
+#define WM8961_WSEQ_DELAY_MASK 0x000F /* WSEQ_DELAY - [3:0] */
+#define WM8961_WSEQ_DELAY_SHIFT 0 /* WSEQ_DELAY - [3:0] */
+#define WM8961_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [3:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer 7
+ */
+#define WM8961_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8961_ARA_ENA 0x0002 /* ARA_ENA */
+#define WM8961_ARA_ENA_MASK 0x0002 /* ARA_ENA */
+#define WM8961_ARA_ENA_SHIFT 1 /* ARA_ENA */
+#define WM8961_ARA_ENA_WIDTH 1 /* ARA_ENA */
+#define WM8961_AUTO_INC 0x0001 /* AUTO_INC */
+#define WM8961_AUTO_INC_MASK 0x0001 /* AUTO_INC */
+#define WM8961_AUTO_INC_SHIFT 0 /* AUTO_INC */
+#define WM8961_AUTO_INC_WIDTH 1 /* AUTO_INC */
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 8c0fdf84aac3..f9c3b80da5d0 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -902,7 +902,7 @@ static int wm8988_register(struct wm8988_priv *wm8988)
ret = wm8988_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ goto err;
}
/* set the update bits (we always update left then right) */
@@ -926,18 +926,20 @@ static int wm8988_register(struct wm8988_priv *wm8988)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err;
}
ret = snd_soc_register_dai(&wm8988_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err:
kfree(wm8988);
return ret;
@@ -981,6 +983,21 @@ static int wm8988_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm8988_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm8988_i2c_suspend NULL
+#define wm8988_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm8988_i2c_id[] = {
{ "wm8988", 0 },
{ }
@@ -994,6 +1011,8 @@ static struct i2c_driver wm8988_i2c_driver = {
},
.probe = wm8988_i2c_probe,
.remove = wm8988_i2c_remove,
+ .suspend = wm8988_i2c_suspend,
+ .resume = wm8988_i2c_resume,
.id_table = wm8988_i2c_id,
};
#endif
@@ -1051,6 +1070,21 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
return 0;
}
+#ifdef CONFIG_PM
+static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&spi->dev);
+}
+
+static int wm8988_spi_resume(struct spi_device *spi)
+{
+ return snd_soc_resume_device(&spi->dev);
+}
+#else
+#define wm8988_spi_suspend NULL
+#define wm8988_spi_resume NULL
+#endif
+
static struct spi_driver wm8988_spi_driver = {
.driver = {
.name = "wm8988",
@@ -1059,6 +1093,8 @@ static struct spi_driver wm8988_spi_driver = {
},
.probe = wm8988_spi_probe,
.remove = __devexit_p(wm8988_spi_remove),
+ .suspend = wm8988_spi_suspend,
+ .resume = wm8988_spi_resume,
};
#endif
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
new file mode 100644
index 000000000000..e246ca079897
--- /dev/null
+++ b/sound/soc/codecs/wm8993.c
@@ -0,0 +1,2206 @@
+/*
+ * wm8993.c -- WM8993 ALSA SoC audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/wm8993.h>
+
+#include "wm8993.h"
+
+static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = {
+ 0x8993, /* R0 - Software Reset */
+ 0x0000, /* R1 - Power Management (1) */
+ 0x6000, /* R2 - Power Management (2) */
+ 0x0000, /* R3 - Power Management (3) */
+ 0x4050, /* R4 - Audio Interface (1) */
+ 0x4000, /* R5 - Audio Interface (2) */
+ 0x01C8, /* R6 - Clocking 1 */
+ 0x0000, /* R7 - Clocking 2 */
+ 0x0000, /* R8 - Audio Interface (3) */
+ 0x0040, /* R9 - Audio Interface (4) */
+ 0x0004, /* R10 - DAC CTRL */
+ 0x00C0, /* R11 - Left DAC Digital Volume */
+ 0x00C0, /* R12 - Right DAC Digital Volume */
+ 0x0000, /* R13 - Digital Side Tone */
+ 0x0300, /* R14 - ADC CTRL */
+ 0x00C0, /* R15 - Left ADC Digital Volume */
+ 0x00C0, /* R16 - Right ADC Digital Volume */
+ 0x0000, /* R17 */
+ 0x0000, /* R18 - GPIO CTRL 1 */
+ 0x0010, /* R19 - GPIO1 */
+ 0x0000, /* R20 - IRQ_DEBOUNCE */
+ 0x0000, /* R21 */
+ 0x8000, /* R22 - GPIOCTRL 2 */
+ 0x0800, /* R23 - GPIO_POL */
+ 0x008B, /* R24 - Left Line Input 1&2 Volume */
+ 0x008B, /* R25 - Left Line Input 3&4 Volume */
+ 0x008B, /* R26 - Right Line Input 1&2 Volume */
+ 0x008B, /* R27 - Right Line Input 3&4 Volume */
+ 0x006D, /* R28 - Left Output Volume */
+ 0x006D, /* R29 - Right Output Volume */
+ 0x0066, /* R30 - Line Outputs Volume */
+ 0x0020, /* R31 - HPOUT2 Volume */
+ 0x0079, /* R32 - Left OPGA Volume */
+ 0x0079, /* R33 - Right OPGA Volume */
+ 0x0003, /* R34 - SPKMIXL Attenuation */
+ 0x0003, /* R35 - SPKMIXR Attenuation */
+ 0x0011, /* R36 - SPKOUT Mixers */
+ 0x0100, /* R37 - SPKOUT Boost */
+ 0x0079, /* R38 - Speaker Volume Left */
+ 0x0079, /* R39 - Speaker Volume Right */
+ 0x0000, /* R40 - Input Mixer2 */
+ 0x0000, /* R41 - Input Mixer3 */
+ 0x0000, /* R42 - Input Mixer4 */
+ 0x0000, /* R43 - Input Mixer5 */
+ 0x0000, /* R44 - Input Mixer6 */
+ 0x0000, /* R45 - Output Mixer1 */
+ 0x0000, /* R46 - Output Mixer2 */
+ 0x0000, /* R47 - Output Mixer3 */
+ 0x0000, /* R48 - Output Mixer4 */
+ 0x0000, /* R49 - Output Mixer5 */
+ 0x0000, /* R50 - Output Mixer6 */
+ 0x0000, /* R51 - HPOUT2 Mixer */
+ 0x0000, /* R52 - Line Mixer1 */
+ 0x0000, /* R53 - Line Mixer2 */
+ 0x0000, /* R54 - Speaker Mixer */
+ 0x0000, /* R55 - Additional Control */
+ 0x0000, /* R56 - AntiPOP1 */
+ 0x0000, /* R57 - AntiPOP2 */
+ 0x0000, /* R58 - MICBIAS */
+ 0x0000, /* R59 */
+ 0x0000, /* R60 - FLL Control 1 */
+ 0x0000, /* R61 - FLL Control 2 */
+ 0x0000, /* R62 - FLL Control 3 */
+ 0x2EE0, /* R63 - FLL Control 4 */
+ 0x0002, /* R64 - FLL Control 5 */
+ 0x2287, /* R65 - Clocking 3 */
+ 0x025F, /* R66 - Clocking 4 */
+ 0x0000, /* R67 - MW Slave Control */
+ 0x0000, /* R68 */
+ 0x0002, /* R69 - Bus Control 1 */
+ 0x0000, /* R70 - Write Sequencer 0 */
+ 0x0000, /* R71 - Write Sequencer 1 */
+ 0x0000, /* R72 - Write Sequencer 2 */
+ 0x0000, /* R73 - Write Sequencer 3 */
+ 0x0000, /* R74 - Write Sequencer 4 */
+ 0x0000, /* R75 - Write Sequencer 5 */
+ 0x1F25, /* R76 - Charge Pump 1 */
+ 0x0000, /* R77 */
+ 0x0000, /* R78 */
+ 0x0000, /* R79 */
+ 0x0000, /* R80 */
+ 0x0000, /* R81 - Class W 0 */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 - DC Servo 0 */
+ 0x054A, /* R85 - DC Servo 1 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 - DC Servo 3 */
+ 0x0000, /* R88 - DC Servo Readback 0 */
+ 0x0000, /* R89 - DC Servo Readback 1 */
+ 0x0000, /* R90 - DC Servo Readback 2 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 */
+ 0x0000, /* R93 */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0100, /* R96 - Analogue HP 0 */
+ 0x0000, /* R97 */
+ 0x0000, /* R98 - EQ1 */
+ 0x000C, /* R99 - EQ2 */
+ 0x000C, /* R100 - EQ3 */
+ 0x000C, /* R101 - EQ4 */
+ 0x000C, /* R102 - EQ5 */
+ 0x000C, /* R103 - EQ6 */
+ 0x0FCA, /* R104 - EQ7 */
+ 0x0400, /* R105 - EQ8 */
+ 0x00D8, /* R106 - EQ9 */
+ 0x1EB5, /* R107 - EQ10 */
+ 0xF145, /* R108 - EQ11 */
+ 0x0B75, /* R109 - EQ12 */
+ 0x01C5, /* R110 - EQ13 */
+ 0x1C58, /* R111 - EQ14 */
+ 0xF373, /* R112 - EQ15 */
+ 0x0A54, /* R113 - EQ16 */
+ 0x0558, /* R114 - EQ17 */
+ 0x168E, /* R115 - EQ18 */
+ 0xF829, /* R116 - EQ19 */
+ 0x07AD, /* R117 - EQ20 */
+ 0x1103, /* R118 - EQ21 */
+ 0x0564, /* R119 - EQ22 */
+ 0x0559, /* R120 - EQ23 */
+ 0x4000, /* R121 - EQ24 */
+ 0x0000, /* R122 - Digital Pulls */
+ 0x0F08, /* R123 - DRC Control 1 */
+ 0x0000, /* R124 - DRC Control 2 */
+ 0x0080, /* R125 - DRC Control 3 */
+ 0x0000, /* R126 - DRC Control 4 */
+};
+
+static struct {
+ int ratio;
+ int clk_sys_rate;
+} clk_sys_rates[] = {
+ { 64, 0 },
+ { 128, 1 },
+ { 192, 2 },
+ { 256, 3 },
+ { 384, 4 },
+ { 512, 5 },
+ { 768, 6 },
+ { 1024, 7 },
+ { 1408, 8 },
+ { 1536, 9 },
+};
+
+static struct {
+ int rate;
+ int sample_rate;
+} sample_rates[] = {
+ { 8000, 0 },
+ { 11025, 1 },
+ { 12000, 1 },
+ { 16000, 2 },
+ { 22050, 3 },
+ { 24000, 3 },
+ { 32000, 4 },
+ { 44100, 5 },
+ { 48000, 5 },
+};
+
+static struct {
+ int div; /* *10 due to .5s */
+ int bclk_div;
+} bclk_divs[] = {
+ { 10, 0 },
+ { 15, 1 },
+ { 20, 2 },
+ { 30, 3 },
+ { 40, 4 },
+ { 55, 5 },
+ { 60, 6 },
+ { 80, 7 },
+ { 110, 8 },
+ { 120, 9 },
+ { 160, 10 },
+ { 220, 11 },
+ { 240, 12 },
+ { 320, 13 },
+ { 440, 14 },
+ { 480, 15 },
+};
+
+struct wm8993_priv {
+ u16 reg_cache[WM8993_REGISTER_COUNT];
+ struct wm8993_platform_data pdata;
+ struct snd_soc_codec codec;
+ int master;
+ int sysclk_source;
+ unsigned int mclk_rate;
+ unsigned int sysclk_rate;
+ unsigned int fs;
+ unsigned int bclk;
+ int class_w_users;
+ unsigned int fll_fref;
+ unsigned int fll_fout;
+};
+
+static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg)
+{
+ struct i2c_msg xfer[2];
+ u16 data;
+ int ret;
+ struct i2c_client *i2c = codec->control_data;
+
+ /* Write register */
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = 2;
+ xfer[1].buf = (u8 *)&data;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret != 2) {
+ dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
+ return 0;
+ }
+
+ return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static int wm8993_volatile(unsigned int reg)
+{
+ switch (reg) {
+ case WM8993_SOFTWARE_RESET:
+ case WM8993_DC_SERVO_0:
+ case WM8993_DC_SERVO_READBACK_0:
+ case WM8993_DC_SERVO_READBACK_1:
+ case WM8993_DC_SERVO_READBACK_2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int wm8993_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *reg_cache = codec->reg_cache;
+
+ BUG_ON(reg > WM8993_MAX_REGISTER);
+
+ if (wm8993_volatile(reg))
+ return wm8993_read_hw(codec, reg);
+ else
+ return reg_cache[reg];
+}
+
+static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u16 *reg_cache = codec->reg_cache;
+ u8 data[3];
+ int ret;
+
+ BUG_ON(reg > WM8993_MAX_REGISTER);
+
+ /* data is
+ * D15..D9 WM8993 register offset
+ * D8...D0 register data
+ */
+ data[0] = reg;
+ data[1] = value >> 8;
+ data[2] = value & 0x00ff;
+
+ if (!wm8993_volatile(reg))
+ reg_cache[reg] = value;
+
+ ret = codec->hw_write(codec->control_data, data, 3);
+
+ if (ret == 3)
+ return 0;
+ if (ret < 0)
+ return ret;
+ return -EIO;
+}
+
+struct _fll_div {
+ u16 fll_fratio;
+ u16 fll_outdiv;
+ u16 fll_clk_ref_div;
+ u16 n;
+ u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+ unsigned int min;
+ unsigned int max;
+ u16 fll_fratio;
+ int ratio;
+} fll_fratios[] = {
+ { 0, 64000, 4, 16 },
+ { 64000, 128000, 3, 8 },
+ { 128000, 256000, 2, 4 },
+ { 256000, 1000000, 1, 2 },
+ { 1000000, 13500000, 0, 1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+ unsigned int Fout)
+{
+ u64 Kpart;
+ unsigned int K, Ndiv, Nmod, target;
+ unsigned int div;
+ int i;
+
+ /* Fref must be <=13.5MHz */
+ div = 1;
+ fll_div->fll_clk_ref_div = 0;
+ while ((Fref / div) > 13500000) {
+ div *= 2;
+ fll_div->fll_clk_ref_div++;
+
+ if (div > 8) {
+ pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+ Fref);
+ return -EINVAL;
+ }
+ }
+
+ pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+ /* Apply the division for our remaining calculations */
+ Fref /= div;
+
+ /* Fvco should be 90-100MHz; don't check the upper bound */
+ div = 0;
+ target = Fout * 2;
+ while (target < 90000000) {
+ div++;
+ target *= 2;
+ if (div > 7) {
+ pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+ Fout);
+ return -EINVAL;
+ }
+ }
+ fll_div->fll_outdiv = div;
+
+ pr_debug("Fvco=%dHz\n", target);
+
+ /* Find an appropraite FLL_FRATIO and factor it out of the target */
+ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+ if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+ fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+ target /= fll_fratios[i].ratio;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fll_fratios)) {
+ pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+ return -EINVAL;
+ }
+
+ /* Now, calculate N.K */
+ Ndiv = target / Fref;
+
+ fll_div->n = Ndiv;
+ Nmod = target % Fref;
+ pr_debug("Nmod=%d\n", Nmod);
+
+ /* Calculate fractional part - scale up so we can round. */
+ Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+ do_div(Kpart, Fref);
+
+ K = Kpart & 0xFFFFFFFF;
+
+ if ((K % 10) >= 5)
+ K += 5;
+
+ /* Move down to proper range now rounding is done */
+ fll_div->k = K / 10;
+
+ pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+ fll_div->n, fll_div->k,
+ fll_div->fll_fratio, fll_div->fll_outdiv,
+ fll_div->fll_clk_ref_div);
+
+ return 0;
+}
+
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id,
+ unsigned int Fref, unsigned int Fout)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8993_priv *wm8993 = codec->private_data;
+ u16 reg1, reg4, reg5;
+ struct _fll_div fll_div;
+ int ret;
+
+ /* Any change? */
+ if (Fref == wm8993->fll_fref && Fout == wm8993->fll_fout)
+ return 0;
+
+ /* Disable the FLL */
+ if (Fout == 0) {
+ dev_dbg(codec->dev, "FLL disabled\n");
+ wm8993->fll_fref = 0;
+ wm8993->fll_fout = 0;
+
+ reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
+ reg1 &= ~WM8993_FLL_ENA;
+ wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+
+ return 0;
+ }
+
+ ret = fll_factors(&fll_div, Fref, Fout);
+ if (ret != 0)
+ return ret;
+
+ reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5);
+ reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
+
+ switch (fll_id) {
+ case WM8993_FLL_MCLK:
+ break;
+
+ case WM8993_FLL_LRCLK:
+ reg5 |= 1;
+ break;
+
+ case WM8993_FLL_BCLK:
+ reg5 |= 2;
+ break;
+
+ default:
+ dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+ return -EINVAL;
+ }
+
+ /* Any FLL configuration change requires that the FLL be
+ * disabled first. */
+ reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1);
+ reg1 &= ~WM8993_FLL_ENA;
+ wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+
+ /* Apply the configuration */
+ if (fll_div.k)
+ reg1 |= WM8993_FLL_FRAC_MASK;
+ else
+ reg1 &= ~WM8993_FLL_FRAC_MASK;
+ wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1);
+
+ wm8993_write(codec, WM8993_FLL_CONTROL_2,
+ (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
+ (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
+ wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k);
+
+ reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4);
+ reg4 &= ~WM8993_FLL_N_MASK;
+ reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
+ wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4);
+
+ reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
+ reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
+ wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5);
+
+ /* Enable the FLL */
+ wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
+
+ dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+
+ wm8993->fll_fref = Fref;
+ wm8993->fll_fout = Fout;
+
+ return 0;
+}
+
+static int configure_clock(struct snd_soc_codec *codec)
+{
+ struct wm8993_priv *wm8993 = codec->private_data;
+ unsigned int reg;
+
+ /* This should be done on init() for bypass paths */
+ switch (wm8993->sysclk_source) {
+ case WM8993_SYSCLK_MCLK:
+ dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
+
+ reg = wm8993_read(codec, WM8993_CLOCKING_2);
+ reg &= ~WM8993_SYSCLK_SRC;
+ if (wm8993->mclk_rate > 13500000) {
+ reg |= WM8993_MCLK_DIV;
+ wm8993->sysclk_rate = wm8993->mclk_rate / 2;
+ } else {
+ reg &= ~WM8993_MCLK_DIV;
+ wm8993->sysclk_rate = wm8993->mclk_rate;
+ }
+ reg &= ~WM8993_MCLK_DIV;
+ reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
+ wm8993_write(codec, WM8993_CLOCKING_2, reg);
+ break;
+
+ case WM8993_SYSCLK_FLL:
+ dev_dbg(codec->dev, "Using %dHz FLL clock\n",
+ wm8993->fll_fout);
+
+ reg = wm8993_read(codec, WM8993_CLOCKING_2);
+ reg |= WM8993_SYSCLK_SRC;
+ if (wm8993->fll_fout > 13500000) {
+ reg |= WM8993_MCLK_DIV;
+ wm8993->sysclk_rate = wm8993->fll_fout / 2;
+ } else {
+ reg &= ~WM8993_MCLK_DIV;
+ wm8993->sysclk_rate = wm8993->fll_fout;
+ }
+ wm8993_write(codec, WM8993_CLOCKING_2, reg);
+ break;
+
+ default:
+ dev_err(codec->dev, "System clock not configured\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
+
+ return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, int mask)
+{
+ unsigned int reg;
+ int count = 0;
+
+ dev_dbg(codec->dev, "Waiting for DC servo...\n");
+ do {
+ count++;
+ msleep(1);
+ reg = wm8993_read(codec, WM8993_DC_SERVO_READBACK_0);
+ dev_dbg(codec->dev, "DC servo status: %x\n", reg);
+ } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
+ != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000);
+
+ if ((reg & WM8993_DCS_CAL_COMPLETE_MASK)
+ != WM8993_DCS_CAL_COMPLETE_MASK)
+ dev_err(codec->dev, "Timed out waiting for DC Servo\n");
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
+static const unsigned int drc_max_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(spkmix_tlv, -300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
+static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
+static const unsigned int spkboost_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
+
+static const char *speaker_ref_text[] = {
+ "SPKVDD/2",
+ "VMID",
+};
+
+static const struct soc_enum speaker_ref =
+ SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text);
+
+static const char *speaker_mode_text[] = {
+ "Class D",
+ "Class AB",
+};
+
+static const struct soc_enum speaker_mode =
+ SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
+
+static const char *dac_deemph_text[] = {
+ "None",
+ "32kHz",
+ "44.1kHz",
+ "48kHz",
+};
+
+static const struct soc_enum dac_deemph =
+ SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text);
+
+static const char *adc_hpf_text[] = {
+ "Hi-Fi",
+ "Voice 1",
+ "Voice 2",
+ "Voice 3",
+};
+
+static const struct soc_enum adc_hpf =
+ SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text);
+
+static const char *drc_path_text[] = {
+ "ADC",
+ "DAC"
+};
+
+static const struct soc_enum drc_path =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text);
+
+static const char *drc_r0_text[] = {
+ "1",
+ "1/2",
+ "1/4",
+ "1/8",
+ "1/16",
+ "0",
+};
+
+static const struct soc_enum drc_r0 =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text);
+
+static const char *drc_r1_text[] = {
+ "1",
+ "1/2",
+ "1/4",
+ "1/8",
+ "0",
+};
+
+static const struct soc_enum drc_r1 =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text);
+
+static const char *drc_attack_text[] = {
+ "Reserved",
+ "181us",
+ "363us",
+ "726us",
+ "1.45ms",
+ "2.9ms",
+ "5.8ms",
+ "11.6ms",
+ "23.2ms",
+ "46.4ms",
+ "92.8ms",
+ "185.6ms",
+};
+
+static const struct soc_enum drc_attack =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text);
+
+static const char *drc_decay_text[] = {
+ "186ms",
+ "372ms",
+ "743ms",
+ "1.49s",
+ "2.97ms",
+ "5.94ms",
+ "11.89ms",
+ "23.78ms",
+ "47.56ms",
+};
+
+static const struct soc_enum drc_decay =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text);
+
+static const char *drc_ff_text[] = {
+ "5 samples",
+ "9 samples",
+};
+
+static const struct soc_enum drc_ff =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text);
+
+static const char *drc_qr_rate_text[] = {
+ "0.725ms",
+ "1.45ms",
+ "5.8ms",
+};
+
+static const struct soc_enum drc_qr_rate =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text);
+
+static const char *drc_smooth_text[] = {
+ "Low",
+ "Medium",
+ "High",
+};
+
+static const struct soc_enum drc_smooth =
+ SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text);
+
+
+/*
+ * Update the DC servo calibration on gain changes
+ */
+static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int ret;
+
+ ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+
+ /* Only need to do this if the outputs are active */
+ if (wm8993_read(codec, WM8993_POWER_MANAGEMENT_1)
+ & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
+ snd_soc_update_bits(codec,
+ WM8993_DC_SERVO_0,
+ WM8993_DCS_TRIG_SINGLE_0 |
+ WM8993_DCS_TRIG_SINGLE_1,
+ WM8993_DCS_TRIG_SINGLE_0 |
+ WM8993_DCS_TRIG_SINGLE_1);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new wm8993_snd_controls[] = {
+SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
+ inpga_tlv),
+SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
+ inpga_tlv),
+SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
+
+
+SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
+ inpga_tlv),
+SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
+ inpga_tlv),
+SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
+ inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
+ inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
+ inmix_tlv),
+SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
+SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
+ inmix_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
+ inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
+ inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
+ inmix_tlv),
+SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
+SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
+ inmix_tlv),
+
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
+ 5, 9, 12, 0, sidetone_tlv),
+
+SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0),
+SOC_ENUM("DRC Path", drc_path),
+SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2,
+ 2, 60, 1, drc_comp_threash),
+SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3,
+ 11, 30, 1, drc_comp_amp),
+SOC_ENUM("DRC R0", drc_r0),
+SOC_ENUM("DRC R1", drc_r1),
+SOC_SINGLE_TLV("DRC Minimum Volume", WM8993_DRC_CONTROL_1, 2, 3, 1,
+ drc_min_tlv),
+SOC_SINGLE_TLV("DRC Maximum Volume", WM8993_DRC_CONTROL_1, 0, 3, 0,
+ drc_max_tlv),
+SOC_ENUM("DRC Attack Rate", drc_attack),
+SOC_ENUM("DRC Decay Rate", drc_decay),
+SOC_ENUM("DRC FF Delay", drc_ff),
+SOC_SINGLE("DRC Anti-clip Switch", WM8993_DRC_CONTROL_1, 9, 1, 0),
+SOC_SINGLE("DRC Quick Release Switch", WM8993_DRC_CONTROL_1, 10, 1, 0),
+SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0,
+ drc_qr_tlv),
+SOC_ENUM("DRC Quick Release Rate", drc_qr_rate),
+SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0),
+SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0),
+SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth),
+SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0,
+ drc_startup_tlv),
+
+SOC_SINGLE("EQ Switch", WM8993_EQ1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8993_LEFT_ADC_DIGITAL_VOLUME,
+ WM8993_RIGHT_ADC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8993_ADC_CTRL, 8, 1, 0),
+SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
+
+SOC_DOUBLE_R_TLV("Playback Volume", WM8993_LEFT_DAC_DIGITAL_VOLUME,
+ WM8993_RIGHT_DAC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
+SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0,
+ dac_boost_tlv),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+
+SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
+ outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
+ outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
+ outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
+ outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
+ outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
+ WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
+ WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
+ outmix_tlv),
+
+SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
+ WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
+ WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
+ WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
+ WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
+ WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
+ WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
+ WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
+ WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
+
+SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
+ WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
+SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
+ WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
+SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
+ WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
+SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
+
+SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
+ 5, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
+ 4, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
+ 3, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION,
+ 2, 1, 1, spkmix_tlv),
+
+SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
+ 5, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
+ 4, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
+ 3, 1, 1, spkmix_tlv),
+SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION,
+ 2, 1, 1, spkmix_tlv),
+
+SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
+ WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
+ 0, 3, 1, spkmixout_tlv),
+SOC_DOUBLE_R_TLV("Speaker Volume",
+ WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+ 0, 63, 0, outpga_tlv),
+SOC_DOUBLE_R("Speaker Switch",
+ WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+ 6, 1, 0),
+SOC_DOUBLE_R("Speaker ZC Switch",
+ WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+ 7, 1, 0),
+SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0,
+ spkboost_tlv),
+SOC_ENUM("Speaker Reference", speaker_ref),
+SOC_ENUM("Speaker Mode", speaker_mode),
+
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .tlv.p = outpga_tlv,
+ .info = snd_soc_info_volsw_2r,
+ .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo,
+ .private_value = (unsigned long)&(struct soc_mixer_control) {
+ .reg = WM8993_LEFT_OUTPUT_VOLUME,
+ .rreg = WM8993_RIGHT_OUTPUT_VOLUME,
+ .shift = 0, .max = 63
+ },
+},
+SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
+ WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
+ WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
+SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
+SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
+ line_tlv),
+
+SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
+SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
+SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
+ line_tlv),
+};
+
+static const struct snd_kcontrol_new wm8993_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM8993_EQ2, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM8993_EQ3, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM8993_EQ4, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
+};
+
+static int wm8993_earpiece_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 reg = wm8993_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ reg |= WM8993_HPOUT2_IN_ENA;
+ wm8993_write(codec, WM8993_ANTIPOP1, reg);
+ udelay(50);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ wm8993_write(codec, WM8993_ANTIPOP1, reg);
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ return 0;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return configure_clock(codec);
+
+ case SND_SOC_DAPM_POST_PMD:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * When used with DAC outputs only the WM8993 charge pump supports
+ * operation in class W mode, providing very low power consumption
+ * when used with digital sources. Enable and disable this mode
+ * automatically depending on the mixer configuration.
+ *
+ * Currently the only supported paths are the direct DAC->headphone
+ * paths (which provide minimum power consumption anyway).
+ */
+static int wm8993_class_w_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = widget->codec;
+ struct wm8993_priv *wm8993 = codec->private_data;
+ int ret;
+
+ /* Turn it off if we're using the main output mixer */
+ if (ucontrol->value.integer.value[0] == 0) {
+ if (wm8993->class_w_users == 0) {
+ dev_dbg(codec->dev, "Disabling Class W\n");
+ snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+ WM8993_CP_DYN_FREQ |
+ WM8993_CP_DYN_V,
+ 0);
+ }
+ wm8993->class_w_users++;
+ }
+
+ /* Implement the change */
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ /* Enable it if we're using the direct DAC path */
+ if (ucontrol->value.integer.value[0] == 1) {
+ if (wm8993->class_w_users == 1) {
+ dev_dbg(codec->dev, "Enabling Class W\n");
+ snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+ WM8993_CP_DYN_FREQ |
+ WM8993_CP_DYN_V,
+ WM8993_CP_DYN_FREQ |
+ WM8993_CP_DYN_V);
+ }
+ wm8993->class_w_users--;
+ }
+
+ dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
+ wm8993->class_w_users);
+
+ return ret;
+}
+
+#define SOC_DAPM_ENUM_W(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = wm8993_class_w_put, \
+ .private_value = (unsigned long)&xenum }
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int reg = wm8993_read(codec, WM8993_ANALOGUE_HP_0);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
+ WM8993_CP_ENA, WM8993_CP_ENA);
+
+ msleep(5);
+
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
+ WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
+
+ reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
+ wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
+
+ /* Start the DC servo */
+ snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
+ WM8993_DCS_ENA_CHAN_0 |
+ WM8993_DCS_ENA_CHAN_1 |
+ WM8993_DCS_TRIG_STARTUP_1 |
+ WM8993_DCS_TRIG_STARTUP_0,
+ WM8993_DCS_ENA_CHAN_0 |
+ WM8993_DCS_ENA_CHAN_1 |
+ WM8993_DCS_TRIG_STARTUP_1 |
+ WM8993_DCS_TRIG_STARTUP_0);
+ wait_for_dc_servo(codec, WM8993_DCS_TRIG_STARTUP_0 |
+ WM8993_DCS_TRIG_STARTUP_1);
+ snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+ WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa);
+
+ reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
+ WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
+ wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ reg &= ~(WM8993_HPOUT1L_RMV_SHORT |
+ WM8993_HPOUT1L_DLY |
+ WM8993_HPOUT1L_OUTP |
+ WM8993_HPOUT1R_RMV_SHORT |
+ WM8993_HPOUT1R_DLY |
+ WM8993_HPOUT1R_OUTP);
+
+ snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+ WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
+ snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
+ WM8993_DCS_ENA_CHAN_0 |
+ WM8993_DCS_ENA_CHAN_1, 0);
+
+ wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg);
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
+ 0);
+
+ snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
+ WM8993_CP_ENA, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new in1l_pga[] = {
+SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new in1r_pga[] = {
+SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new in2l_pga[] = {
+SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
+SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new in2r_pga[] = {
+SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_output_mixer[] = {
+SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
+SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
+SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
+SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
+SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_mixer[] = {
+SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
+SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new earpiece_mixer[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
+SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_boost[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
+SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
+SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_boost[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
+SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
+SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
+};
+
+static const char *hp_mux_text[] = {
+ "Mixer",
+ "DAC",
+};
+
+static const struct soc_enum hpl_enum =
+ SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+ SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum);
+
+static const struct soc_enum hpr_enum =
+ SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+ SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum);
+
+static const struct snd_kcontrol_new line1_mix[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line1n_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new line1p_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2_mix[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2n_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2p_mix[] = {
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP/VXRN"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP/VXRP"),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
+SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
+
+SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
+ in1l_pga, ARRAY_SIZE(in1l_pga)),
+SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
+ in1r_pga, ARRAY_SIZE(in1r_pga)),
+
+SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
+ in2l_pga, ARRAY_SIZE(in2l_pga)),
+SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
+ in2r_pga, ARRAY_SIZE(in2r_pga)),
+
+/* Dummy widgets to represent differential paths */
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
+ mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
+ mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
+ left_output_mixer, ARRAY_SIZE(left_output_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
+ right_output_mixer, ARRAY_SIZE(right_output_mixer)),
+
+SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
+ earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
+SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
+ NULL, 0, wm8993_earpiece_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
+ left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0,
+ right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+
+SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
+ left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
+SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
+ right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
+
+SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0,
+ NULL, 0,
+ hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+ line1_mix, ARRAY_SIZE(line1_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+ line2_mix, ARRAY_SIZE(line2_mix)),
+
+SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
+ line1n_mix, ARRAY_SIZE(line1n_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
+ line1p_mix, ARRAY_SIZE(line1p_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
+ line2n_mix, ARRAY_SIZE(line2n_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
+ line2p_mix, ARRAY_SIZE(line2p_mix)),
+
+SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2P"),
+SND_SOC_DAPM_OUTPUT("HPOUT2N"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
+};
+
+static const struct snd_soc_dapm_route routes[] = {
+ { "IN1L PGA", "IN1LP Switch", "IN1LP" },
+ { "IN1L PGA", "IN1LN Switch", "IN1LN" },
+
+ { "IN1R PGA", "IN1RP Switch", "IN1RP" },
+ { "IN1R PGA", "IN1RN Switch", "IN1RN" },
+
+ { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" },
+ { "IN2L PGA", "IN2LN Switch", "IN2LN" },
+
+ { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" },
+ { "IN2R PGA", "IN2RN Switch", "IN2RN" },
+
+ { "Direct Voice", NULL, "IN2LP/VXRN" },
+ { "Direct Voice", NULL, "IN2RP/VXRP" },
+
+ { "MIXINL", "IN1L Switch", "IN1L PGA" },
+ { "MIXINL", "IN2L Switch", "IN2L PGA" },
+ { "MIXINL", NULL, "Direct Voice" },
+ { "MIXINL", NULL, "IN1LP" },
+ { "MIXINL", NULL, "Left Output Mixer" },
+
+ { "MIXINR", "IN1R Switch", "IN1R PGA" },
+ { "MIXINR", "IN2R Switch", "IN2R PGA" },
+ { "MIXINR", NULL, "Direct Voice" },
+ { "MIXINR", NULL, "IN1RP" },
+ { "MIXINR", NULL, "Right Output Mixer" },
+
+ { "ADCL", NULL, "MIXINL" },
+ { "ADCL", NULL, "CLK_SYS" },
+ { "ADCL", NULL, "CLK_DSP" },
+ { "ADCR", NULL, "MIXINR" },
+ { "ADCR", NULL, "CLK_SYS" },
+ { "ADCR", NULL, "CLK_DSP" },
+
+ { "DACL", NULL, "CLK_SYS" },
+ { "DACL", NULL, "CLK_DSP" },
+ { "DACR", NULL, "CLK_SYS" },
+ { "DACR", NULL, "CLK_DSP" },
+
+ { "Left Output Mixer", "Left Input Switch", "MIXINL" },
+ { "Left Output Mixer", "Right Input Switch", "MIXINR" },
+ { "Left Output Mixer", "IN2RN Switch", "IN2RN" },
+ { "Left Output Mixer", "IN2LN Switch", "IN2LN" },
+ { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" },
+ { "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
+ { "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
+ { "Left Output Mixer", "DAC Switch", "DACL" },
+
+ { "Right Output Mixer", "Left Input Switch", "MIXINL" },
+ { "Right Output Mixer", "Right Input Switch", "MIXINR" },
+ { "Right Output Mixer", "IN2LN Switch", "IN2LN" },
+ { "Right Output Mixer", "IN2RN Switch", "IN2RN" },
+ { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" },
+ { "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
+ { "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
+ { "Right Output Mixer", "DAC Switch", "DACR" },
+
+ { "Left Output PGA", NULL, "Left Output Mixer" },
+ { "Left Output PGA", NULL, "CLK_SYS" },
+ { "Left Output PGA", NULL, "TOCLK" },
+
+ { "Right Output PGA", NULL, "Right Output Mixer" },
+ { "Right Output PGA", NULL, "CLK_SYS" },
+ { "Right Output PGA", NULL, "TOCLK" },
+
+ { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
+ { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
+ { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
+
+ { "Earpiece Driver", NULL, "Earpiece Mixer" },
+ { "HPOUT2N", NULL, "Earpiece Driver" },
+ { "HPOUT2P", NULL, "Earpiece Driver" },
+
+ { "SPKL", "Input Switch", "MIXINL" },
+ { "SPKL", "IN1LP Switch", "IN1LP" },
+ { "SPKL", "Output Switch", "Left Output Mixer" },
+ { "SPKL", "DAC Switch", "DACL" },
+ { "SPKL", NULL, "CLK_SYS" },
+ { "SPKL", NULL, "TOCLK" },
+
+ { "SPKR", "Input Switch", "MIXINR" },
+ { "SPKR", "IN1RP Switch", "IN1RP" },
+ { "SPKR", "Output Switch", "Right Output Mixer" },
+ { "SPKR", "DAC Switch", "DACR" },
+ { "SPKR", NULL, "CLK_SYS" },
+ { "SPKR", NULL, "TOCLK" },
+
+ { "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
+ { "SPKL Boost", "SPKL Switch", "SPKL" },
+ { "SPKL Boost", "SPKR Switch", "SPKR" },
+
+ { "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
+ { "SPKR Boost", "SPKR Switch", "SPKR" },
+ { "SPKR Boost", "SPKL Switch", "SPKL" },
+
+ { "SPKL Driver", NULL, "SPKL Boost" },
+ { "SPKL Driver", NULL, "CLK_SYS" },
+
+ { "SPKR Driver", NULL, "SPKR Boost" },
+ { "SPKR Driver", NULL, "CLK_SYS" },
+
+ { "SPKOUTLP", NULL, "SPKL Driver" },
+ { "SPKOUTLN", NULL, "SPKL Driver" },
+ { "SPKOUTRP", NULL, "SPKR Driver" },
+ { "SPKOUTRN", NULL, "SPKR Driver" },
+
+ { "Left Headphone Mux", "DAC", "DACL" },
+ { "Left Headphone Mux", "Mixer", "Left Output Mixer" },
+ { "Right Headphone Mux", "DAC", "DACR" },
+ { "Right Headphone Mux", "Mixer", "Right Output Mixer" },
+
+ { "Headphone PGA", NULL, "Left Headphone Mux" },
+ { "Headphone PGA", NULL, "Right Headphone Mux" },
+ { "Headphone PGA", NULL, "CLK_SYS" },
+ { "Headphone PGA", NULL, "TOCLK" },
+
+ { "HPOUT1L", NULL, "Headphone PGA" },
+ { "HPOUT1R", NULL, "Headphone PGA" },
+
+ { "LINEOUT1N", NULL, "LINEOUT1N Driver" },
+ { "LINEOUT1P", NULL, "LINEOUT1P Driver" },
+ { "LINEOUT2N", NULL, "LINEOUT2N Driver" },
+ { "LINEOUT2P", NULL, "LINEOUT2P Driver" },
+};
+
+static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
+ { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
+ { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
+ { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
+
+ { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
+ { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout1_se_routes[] = {
+ { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
+ { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
+
+ { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
+
+ { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
+ { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
+ { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
+ { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
+ { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
+
+ { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
+ { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout2_se_routes[] = {
+ { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
+ { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
+
+ { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
+
+ { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
+ { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
+};
+
+static int wm8993_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8993_priv *wm8993 = codec->private_data;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID=2*40k */
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_VMID_SEL_MASK, 0x2);
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
+ WM8993_TSHUT_ENA, WM8993_TSHUT_ENA);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ /* Bring up VMID with fast soft start */
+ snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+ WM8993_STARTUP_BIAS_ENA |
+ WM8993_VMID_BUF_ENA |
+ WM8993_VMID_RAMP_MASK |
+ WM8993_BIAS_SRC,
+ WM8993_STARTUP_BIAS_ENA |
+ WM8993_VMID_BUF_ENA |
+ WM8993_VMID_RAMP_MASK |
+ WM8993_BIAS_SRC);
+
+ /* If either line output is single ended we
+ * need the VMID buffer */
+ if (!wm8993->pdata.lineout1_diff ||
+ !wm8993->pdata.lineout2_diff)
+ snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+ WM8993_LINEOUT_VMID_BUF_ENA,
+ WM8993_LINEOUT_VMID_BUF_ENA);
+
+ /* VMID=2*40k */
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_VMID_SEL_MASK |
+ WM8993_BIAS_ENA,
+ WM8993_BIAS_ENA | 0x2);
+ msleep(32);
+
+ /* Switch to normal bias */
+ snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+ WM8993_BIAS_SRC |
+ WM8993_STARTUP_BIAS_ENA, 0);
+ }
+
+ /* VMID=2*240k */
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_VMID_SEL_MASK, 0x4);
+
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
+ WM8993_TSHUT_ENA, 0);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+ WM8993_LINEOUT_VMID_BUF_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+ WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
+ 0);
+ break;
+ }
+
+ codec->bias_level = level;
+
+ return 0;
+}
+
+static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8993_priv *wm8993 = codec->private_data;
+
+ switch (clk_id) {
+ case WM8993_SYSCLK_MCLK:
+ wm8993->mclk_rate = freq;
+ case WM8993_SYSCLK_FLL:
+ wm8993->sysclk_source = clk_id;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8993_priv *wm8993 = codec->private_data;
+ unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
+ unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
+
+ aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
+ WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
+ aif4 &= ~WM8993_LRCLK_DIR;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ wm8993->master = 0;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ aif4 |= WM8993_LRCLK_DIR;
+ wm8993->master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ aif1 |= WM8993_BCLK_DIR;
+ wm8993->master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aif1 |= WM8993_BCLK_DIR;
+ aif4 |= WM8993_LRCLK_DIR;
+ wm8993->master = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_B:
+ aif1 |= WM8993_AIF_LRCLK_INV;
+ case SND_SOC_DAIFMT_DSP_A:
+ aif1 |= 0x18;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ aif1 |= 0x10;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aif1 |= 0x8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ /* frame inversion not valid for DSP modes */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif1 |= WM8993_AIF_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aif1 |= WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif1 |= WM8993_AIF_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aif1 |= WM8993_AIF_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
+ wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+
+ return 0;
+}
+
+static int wm8993_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 wm8993_priv *wm8993 = codec->private_data;
+ int ret, i, best, best_val, cur_val;
+ unsigned int clocking1, clocking3, aif1, aif4;
+
+ clocking1 = wm8993_read(codec, WM8993_CLOCKING_1);
+ clocking1 &= ~WM8993_BCLK_DIV_MASK;
+
+ clocking3 = wm8993_read(codec, WM8993_CLOCKING_3);
+ clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
+
+ aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1);
+ aif1 &= ~WM8993_AIF_WL_MASK;
+
+ aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4);
+ aif4 &= ~WM8993_LRCLK_RATE_MASK;
+
+ /* What BCLK do we need? */
+ wm8993->fs = params_rate(params);
+ wm8993->bclk = 2 * wm8993->fs;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ wm8993->bclk *= 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ wm8993->bclk *= 20;
+ aif1 |= 0x8;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ wm8993->bclk *= 24;
+ aif1 |= 0x10;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ wm8993->bclk *= 32;
+ aif1 |= 0x18;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
+
+ ret = configure_clock(codec);
+ if (ret != 0)
+ return ret;
+
+ /* Select nearest CLK_SYS_RATE */
+ best = 0;
+ best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio)
+ - wm8993->fs);
+ for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+ cur_val = abs((wm8993->sysclk_rate /
+ clk_sys_rates[i].ratio) - wm8993->fs);;
+ if (cur_val < best_val) {
+ best = i;
+ best_val = cur_val;
+ }
+ }
+ dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+ clk_sys_rates[best].ratio);
+ clocking3 |= (clk_sys_rates[best].clk_sys_rate
+ << WM8993_CLK_SYS_RATE_SHIFT);
+
+ /* SAMPLE_RATE */
+ best = 0;
+ best_val = abs(wm8993->fs - sample_rates[0].rate);
+ for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+ /* Closest match */
+ cur_val = abs(wm8993->fs - sample_rates[i].rate);
+ if (cur_val < best_val) {
+ best = i;
+ best_val = cur_val;
+ }
+ }
+ dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+ sample_rates[best].rate);
+ clocking3 |= (sample_rates[best].sample_rate
+ << WM8993_SAMPLE_RATE_SHIFT);
+
+ /* BCLK_DIV */
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ cur_val = ((wm8993->sysclk_rate * 10) / bclk_divs[i].div)
+ - wm8993->bclk;
+ if (cur_val < 0) /* Table is sorted */
+ break;
+ if (cur_val < best_val) {
+ best = i;
+ best_val = cur_val;
+ }
+ }
+ wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div;
+ dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+ bclk_divs[best].div, wm8993->bclk);
+ clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT;
+
+ /* LRCLK is a simple fraction of BCLK */
+ dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
+ aif4 |= wm8993->bclk / wm8993->fs;
+
+ wm8993_write(codec, WM8993_CLOCKING_1, clocking1);
+ wm8993_write(codec, WM8993_CLOCKING_3, clocking3);
+ wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
+ wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+
+ /* ReTune Mobile? */
+ if (wm8993->pdata.num_retune_configs) {
+ u16 eq1 = wm8993_read(codec, WM8993_EQ1);
+ struct wm8993_retune_mobile_setting *s;
+
+ best = 0;
+ best_val = abs(wm8993->pdata.retune_configs[0].rate
+ - wm8993->fs);
+ for (i = 0; i < wm8993->pdata.num_retune_configs; i++) {
+ cur_val = abs(wm8993->pdata.retune_configs[i].rate
+ - wm8993->fs);
+ if (cur_val < best_val) {
+ best_val = cur_val;
+ best = i;
+ }
+ }
+ s = &wm8993->pdata.retune_configs[best];
+
+ dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
+ s->name, s->rate);
+
+ /* Disable EQ while we reconfigure */
+ snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0);
+
+ for (i = 1; i < ARRAY_SIZE(s->config); i++)
+ wm8993_write(codec, WM8993_EQ1 + i, s->config[i]);
+
+ snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1);
+ }
+
+ return 0;
+}
+
+static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ unsigned int reg;
+
+ reg = wm8993_read(codec, WM8993_DAC_CTRL);
+
+ if (mute)
+ reg |= WM8993_DAC_MUTE;
+ else
+ reg &= ~WM8993_DAC_MUTE;
+
+ wm8993_write(codec, WM8993_DAC_CTRL, reg);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wm8993_ops = {
+ .set_sysclk = wm8993_set_sysclk,
+ .set_fmt = wm8993_set_dai_fmt,
+ .hw_params = wm8993_hw_params,
+ .digital_mute = wm8993_digital_mute,
+ .set_pll = wm8993_set_fll,
+};
+
+#define WM8993_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8993_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai wm8993_dai = {
+ .name = "WM8993",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8993_RATES,
+ .formats = WM8993_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8993_RATES,
+ .formats = WM8993_FORMATS,
+ },
+ .ops = &wm8993_ops,
+ .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8993_dai);
+
+static struct snd_soc_codec *wm8993_codec;
+
+static int wm8993_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct wm8993_priv *wm8993;
+ int ret = 0;
+
+ if (!wm8993_codec) {
+ dev_err(&pdev->dev, "I2C device not yet probed\n");
+ goto err;
+ }
+
+ socdev->card->codec = wm8993_codec;
+ codec = wm8993_codec;
+ wm8993 = codec->private_data;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms\n");
+ goto err;
+ }
+
+ snd_soc_add_controls(codec, wm8993_snd_controls,
+ ARRAY_SIZE(wm8993_snd_controls));
+ if (wm8993->pdata.num_retune_configs != 0) {
+ dev_dbg(codec->dev, "Using ReTune Mobile\n");
+ } else {
+ dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
+ snd_soc_add_controls(codec, wm8993_eq_controls,
+ ARRAY_SIZE(wm8993_eq_controls));
+ }
+
+ snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets,
+ ARRAY_SIZE(wm8993_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
+
+ if (wm8993->pdata.lineout1_diff)
+ snd_soc_dapm_add_routes(codec,
+ lineout1_diff_routes,
+ ARRAY_SIZE(lineout1_diff_routes));
+ else
+ snd_soc_dapm_add_routes(codec,
+ lineout1_se_routes,
+ ARRAY_SIZE(lineout1_se_routes));
+
+ if (wm8993->pdata.lineout2_diff)
+ snd_soc_dapm_add_routes(codec,
+ lineout2_diff_routes,
+ ARRAY_SIZE(lineout2_diff_routes));
+ else
+ snd_soc_dapm_add_routes(codec,
+ lineout2_se_routes,
+ ARRAY_SIZE(lineout2_se_routes));
+
+ snd_soc_dapm_new_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+err:
+ return ret;
+}
+
+static int wm8993_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_wm8993 = {
+ .probe = wm8993_probe,
+ .remove = wm8993_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
+
+static int wm8993_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8993_priv *wm8993;
+ struct snd_soc_codec *codec;
+ unsigned int val;
+ int ret;
+
+ if (wm8993_codec) {
+ dev_err(&i2c->dev, "A WM8993 is already registered\n");
+ return -EINVAL;
+ }
+
+ wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
+ if (wm8993 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8993->codec;
+ if (i2c->dev.platform_data)
+ memcpy(&wm8993->pdata, i2c->dev.platform_data,
+ sizeof(wm8993->pdata));
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "WM8993";
+ codec->read = wm8993_read;
+ codec->write = wm8993_write;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->reg_cache = wm8993->reg_cache;
+ codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8993_set_bias_level;
+ codec->dai = &wm8993_dai;
+ codec->num_dai = 1;
+ codec->private_data = wm8993;
+
+ memcpy(wm8993->reg_cache, wm8993_reg_defaults,
+ sizeof(wm8993->reg_cache));
+
+ i2c_set_clientdata(i2c, wm8993);
+ codec->control_data = i2c;
+ wm8993_codec = codec;
+
+ codec->dev = &i2c->dev;
+
+ val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET);
+ if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
+ dev_err(codec->dev, "Invalid ID register value %x\n", val);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
+ if (ret != 0)
+ goto err;
+
+ /* By default we're using the output mixers */
+ wm8993->class_w_users = 2;
+
+ /* Latch volume update bits and default ZC on */
+ snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8993_IN1_VU, WM8993_IN1_VU);
+ snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8993_IN1_VU, WM8993_IN1_VU);
+ snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8993_IN2_VU, WM8993_IN2_VU);
+ snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8993_IN2_VU, WM8993_IN2_VU);
+
+ snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
+ WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
+
+ snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
+ WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
+ snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
+ WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
+ WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
+
+ snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
+ WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
+ snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
+ WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
+ WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
+
+ snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+ WM8993_DAC_VU, WM8993_DAC_VU);
+ snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+ WM8993_ADC_VU, WM8993_ADC_VU);
+
+ /* Manualy manage the HPOUT sequencing for independent stereo
+ * control. */
+ snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+ WM8993_HPOUT1_AUTO_PU, 0);
+
+ /* Use automatic clock configuration */
+ snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+
+ 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);
+
+ ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (ret != 0)
+ goto err;
+
+ wm8993_dai.dev = codec->dev;
+
+ ret = snd_soc_register_dai(&wm8993_dai);
+ if (ret != 0)
+ goto err_bias;
+
+ ret = snd_soc_register_codec(codec);
+
+ return 0;
+
+err_bias:
+ wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+err:
+ wm8993_codec = NULL;
+ kfree(wm8993);
+ return ret;
+}
+
+static int wm8993_i2c_remove(struct i2c_client *client)
+{
+ struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&wm8993->codec);
+ snd_soc_unregister_dai(&wm8993_dai);
+
+ wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
+ kfree(wm8993);
+
+ return 0;
+}
+
+static const struct i2c_device_id wm8993_i2c_id[] = {
+ { "wm8993", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
+
+static struct i2c_driver wm8993_i2c_driver = {
+ .driver = {
+ .name = "WM8993",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8993_i2c_probe,
+ .remove = wm8993_i2c_remove,
+ .id_table = wm8993_i2c_id,
+};
+
+
+static int __init wm8993_modinit(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&wm8993_i2c_driver);
+ if (ret != 0)
+ pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
+
+ return ret;
+}
+module_init(wm8993_modinit);
+
+static void __exit wm8993_exit(void)
+{
+ i2c_del_driver(&wm8993_i2c_driver);
+}
+module_exit(wm8993_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8993 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
new file mode 100644
index 000000000000..30e71ca88dad
--- /dev/null
+++ b/sound/soc/codecs/wm8993.h
@@ -0,0 +1,2132 @@
+#ifndef WM8993_H
+#define WM8993_H
+
+extern struct snd_soc_dai wm8993_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8993;
+
+#define WM8993_SYSCLK_MCLK 1
+#define WM8993_SYSCLK_FLL 2
+
+#define WM8993_FLL_MCLK 1
+#define WM8993_FLL_BCLK 2
+#define WM8993_FLL_LRCLK 3
+
+/*
+ * Register values.
+ */
+#define WM8993_SOFTWARE_RESET 0x00
+#define WM8993_POWER_MANAGEMENT_1 0x01
+#define WM8993_POWER_MANAGEMENT_2 0x02
+#define WM8993_POWER_MANAGEMENT_3 0x03
+#define WM8993_AUDIO_INTERFACE_1 0x04
+#define WM8993_AUDIO_INTERFACE_2 0x05
+#define WM8993_CLOCKING_1 0x06
+#define WM8993_CLOCKING_2 0x07
+#define WM8993_AUDIO_INTERFACE_3 0x08
+#define WM8993_AUDIO_INTERFACE_4 0x09
+#define WM8993_DAC_CTRL 0x0A
+#define WM8993_LEFT_DAC_DIGITAL_VOLUME 0x0B
+#define WM8993_RIGHT_DAC_DIGITAL_VOLUME 0x0C
+#define WM8993_DIGITAL_SIDE_TONE 0x0D
+#define WM8993_ADC_CTRL 0x0E
+#define WM8993_LEFT_ADC_DIGITAL_VOLUME 0x0F
+#define WM8993_RIGHT_ADC_DIGITAL_VOLUME 0x10
+#define WM8993_GPIO_CTRL_1 0x12
+#define WM8993_GPIO1 0x13
+#define WM8993_IRQ_DEBOUNCE 0x14
+#define WM8993_GPIOCTRL_2 0x16
+#define WM8993_GPIO_POL 0x17
+#define WM8993_LEFT_LINE_INPUT_1_2_VOLUME 0x18
+#define WM8993_LEFT_LINE_INPUT_3_4_VOLUME 0x19
+#define WM8993_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
+#define WM8993_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
+#define WM8993_LEFT_OUTPUT_VOLUME 0x1C
+#define WM8993_RIGHT_OUTPUT_VOLUME 0x1D
+#define WM8993_LINE_OUTPUTS_VOLUME 0x1E
+#define WM8993_HPOUT2_VOLUME 0x1F
+#define WM8993_LEFT_OPGA_VOLUME 0x20
+#define WM8993_RIGHT_OPGA_VOLUME 0x21
+#define WM8993_SPKMIXL_ATTENUATION 0x22
+#define WM8993_SPKMIXR_ATTENUATION 0x23
+#define WM8993_SPKOUT_MIXERS 0x24
+#define WM8993_SPKOUT_BOOST 0x25
+#define WM8993_SPEAKER_VOLUME_LEFT 0x26
+#define WM8993_SPEAKER_VOLUME_RIGHT 0x27
+#define WM8993_INPUT_MIXER2 0x28
+#define WM8993_INPUT_MIXER3 0x29
+#define WM8993_INPUT_MIXER4 0x2A
+#define WM8993_INPUT_MIXER5 0x2B
+#define WM8993_INPUT_MIXER6 0x2C
+#define WM8993_OUTPUT_MIXER1 0x2D
+#define WM8993_OUTPUT_MIXER2 0x2E
+#define WM8993_OUTPUT_MIXER3 0x2F
+#define WM8993_OUTPUT_MIXER4 0x30
+#define WM8993_OUTPUT_MIXER5 0x31
+#define WM8993_OUTPUT_MIXER6 0x32
+#define WM8993_HPOUT2_MIXER 0x33
+#define WM8993_LINE_MIXER1 0x34
+#define WM8993_LINE_MIXER2 0x35
+#define WM8993_SPEAKER_MIXER 0x36
+#define WM8993_ADDITIONAL_CONTROL 0x37
+#define WM8993_ANTIPOP1 0x38
+#define WM8993_ANTIPOP2 0x39
+#define WM8993_MICBIAS 0x3A
+#define WM8993_FLL_CONTROL_1 0x3C
+#define WM8993_FLL_CONTROL_2 0x3D
+#define WM8993_FLL_CONTROL_3 0x3E
+#define WM8993_FLL_CONTROL_4 0x3F
+#define WM8993_FLL_CONTROL_5 0x40
+#define WM8993_CLOCKING_3 0x41
+#define WM8993_CLOCKING_4 0x42
+#define WM8993_MW_SLAVE_CONTROL 0x43
+#define WM8993_BUS_CONTROL_1 0x45
+#define WM8993_WRITE_SEQUENCER_0 0x46
+#define WM8993_WRITE_SEQUENCER_1 0x47
+#define WM8993_WRITE_SEQUENCER_2 0x48
+#define WM8993_WRITE_SEQUENCER_3 0x49
+#define WM8993_WRITE_SEQUENCER_4 0x4A
+#define WM8993_WRITE_SEQUENCER_5 0x4B
+#define WM8993_CHARGE_PUMP_1 0x4C
+#define WM8993_CLASS_W_0 0x51
+#define WM8993_DC_SERVO_0 0x54
+#define WM8993_DC_SERVO_1 0x55
+#define WM8993_DC_SERVO_3 0x57
+#define WM8993_DC_SERVO_READBACK_0 0x58
+#define WM8993_DC_SERVO_READBACK_1 0x59
+#define WM8993_DC_SERVO_READBACK_2 0x5A
+#define WM8993_ANALOGUE_HP_0 0x60
+#define WM8993_EQ1 0x62
+#define WM8993_EQ2 0x63
+#define WM8993_EQ3 0x64
+#define WM8993_EQ4 0x65
+#define WM8993_EQ5 0x66
+#define WM8993_EQ6 0x67
+#define WM8993_EQ7 0x68
+#define WM8993_EQ8 0x69
+#define WM8993_EQ9 0x6A
+#define WM8993_EQ10 0x6B
+#define WM8993_EQ11 0x6C
+#define WM8993_EQ12 0x6D
+#define WM8993_EQ13 0x6E
+#define WM8993_EQ14 0x6F
+#define WM8993_EQ15 0x70
+#define WM8993_EQ16 0x71
+#define WM8993_EQ17 0x72
+#define WM8993_EQ18 0x73
+#define WM8993_EQ19 0x74
+#define WM8993_EQ20 0x75
+#define WM8993_EQ21 0x76
+#define WM8993_EQ22 0x77
+#define WM8993_EQ23 0x78
+#define WM8993_EQ24 0x79
+#define WM8993_DIGITAL_PULLS 0x7A
+#define WM8993_DRC_CONTROL_1 0x7B
+#define WM8993_DRC_CONTROL_2 0x7C
+#define WM8993_DRC_CONTROL_3 0x7D
+#define WM8993_DRC_CONTROL_4 0x7E
+
+#define WM8993_REGISTER_COUNT 0x7F
+#define WM8993_MAX_REGISTER 0x7E
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8993_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */
+#define WM8993_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */
+#define WM8993_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8993_SPKOUTR_ENA 0x2000 /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_MASK 0x2000 /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_SHIFT 13 /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */
+#define WM8993_SPKOUTL_ENA 0x1000 /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_MASK 0x1000 /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_SHIFT 12 /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
+#define WM8993_HPOUT2_ENA 0x0800 /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_MASK 0x0800 /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_SHIFT 11 /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_WIDTH 1 /* HPOUT2_ENA */
+#define WM8993_HPOUT1L_ENA 0x0200 /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_MASK 0x0200 /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_SHIFT 9 /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */
+#define WM8993_HPOUT1R_ENA 0x0100 /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_MASK 0x0100 /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_SHIFT 8 /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */
+#define WM8993_MICB2_ENA 0x0020 /* MICB2_ENA */
+#define WM8993_MICB2_ENA_MASK 0x0020 /* MICB2_ENA */
+#define WM8993_MICB2_ENA_SHIFT 5 /* MICB2_ENA */
+#define WM8993_MICB2_ENA_WIDTH 1 /* MICB2_ENA */
+#define WM8993_MICB1_ENA 0x0010 /* MICB1_ENA */
+#define WM8993_MICB1_ENA_MASK 0x0010 /* MICB1_ENA */
+#define WM8993_MICB1_ENA_SHIFT 4 /* MICB1_ENA */
+#define WM8993_MICB1_ENA_WIDTH 1 /* MICB1_ENA */
+#define WM8993_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */
+#define WM8993_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */
+#define WM8993_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */
+#define WM8993_BIAS_ENA 0x0001 /* BIAS_ENA */
+#define WM8993_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */
+#define WM8993_BIAS_ENA_SHIFT 0 /* BIAS_ENA */
+#define WM8993_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8993_TSHUT_ENA 0x4000 /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */
+#define WM8993_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */
+#define WM8993_OPCLK_ENA 0x0800 /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
+#define WM8993_MIXINL_ENA 0x0200 /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_MASK 0x0200 /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_SHIFT 9 /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */
+#define WM8993_MIXINR_ENA 0x0100 /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_MASK 0x0100 /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_SHIFT 8 /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */
+#define WM8993_IN2L_ENA 0x0080 /* IN2L_ENA */
+#define WM8993_IN2L_ENA_MASK 0x0080 /* IN2L_ENA */
+#define WM8993_IN2L_ENA_SHIFT 7 /* IN2L_ENA */
+#define WM8993_IN2L_ENA_WIDTH 1 /* IN2L_ENA */
+#define WM8993_IN1L_ENA 0x0040 /* IN1L_ENA */
+#define WM8993_IN1L_ENA_MASK 0x0040 /* IN1L_ENA */
+#define WM8993_IN1L_ENA_SHIFT 6 /* IN1L_ENA */
+#define WM8993_IN1L_ENA_WIDTH 1 /* IN1L_ENA */
+#define WM8993_IN2R_ENA 0x0020 /* IN2R_ENA */
+#define WM8993_IN2R_ENA_MASK 0x0020 /* IN2R_ENA */
+#define WM8993_IN2R_ENA_SHIFT 5 /* IN2R_ENA */
+#define WM8993_IN2R_ENA_WIDTH 1 /* IN2R_ENA */
+#define WM8993_IN1R_ENA 0x0010 /* IN1R_ENA */
+#define WM8993_IN1R_ENA_MASK 0x0010 /* IN1R_ENA */
+#define WM8993_IN1R_ENA_SHIFT 4 /* IN1R_ENA */
+#define WM8993_IN1R_ENA_WIDTH 1 /* IN1R_ENA */
+#define WM8993_ADCL_ENA 0x0002 /* ADCL_ENA */
+#define WM8993_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */
+#define WM8993_ADCL_ENA_SHIFT 1 /* ADCL_ENA */
+#define WM8993_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
+#define WM8993_ADCR_ENA 0x0001 /* ADCR_ENA */
+#define WM8993_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */
+#define WM8993_ADCR_ENA_SHIFT 0 /* ADCR_ENA */
+#define WM8993_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8993_LINEOUT1N_ENA 0x2000 /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_MASK 0x2000 /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_SHIFT 13 /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_WIDTH 1 /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1P_ENA 0x1000 /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_MASK 0x1000 /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_SHIFT 12 /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_WIDTH 1 /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT2N_ENA 0x0800 /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_MASK 0x0800 /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_SHIFT 11 /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_WIDTH 1 /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2P_ENA 0x0400 /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_MASK 0x0400 /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_SHIFT 10 /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_WIDTH 1 /* LINEOUT2P_ENA */
+#define WM8993_SPKRVOL_ENA 0x0200 /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_MASK 0x0200 /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_SHIFT 9 /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_WIDTH 1 /* SPKRVOL_ENA */
+#define WM8993_SPKLVOL_ENA 0x0100 /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_MASK 0x0100 /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_SHIFT 8 /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_WIDTH 1 /* SPKLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA 0x0080 /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_MASK 0x0080 /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_SHIFT 7 /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_WIDTH 1 /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA 0x0040 /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_MASK 0x0040 /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_SHIFT 6 /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_WIDTH 1 /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTL_ENA 0x0020 /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_MASK 0x0020 /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_SHIFT 5 /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */
+#define WM8993_MIXOUTR_ENA 0x0010 /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_MASK 0x0010 /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_SHIFT 4 /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */
+#define WM8993_DACL_ENA 0x0002 /* DACL_ENA */
+#define WM8993_DACL_ENA_MASK 0x0002 /* DACL_ENA */
+#define WM8993_DACL_ENA_SHIFT 1 /* DACL_ENA */
+#define WM8993_DACL_ENA_WIDTH 1 /* DACL_ENA */
+#define WM8993_DACR_ENA 0x0001 /* DACR_ENA */
+#define WM8993_DACR_ENA_MASK 0x0001 /* DACR_ENA */
+#define WM8993_DACR_ENA_SHIFT 0 /* DACR_ENA */
+#define WM8993_DACR_ENA_WIDTH 1 /* DACR_ENA */
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8993_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_MASK 0x8000 /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_SHIFT 15 /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */
+#define WM8993_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_MASK 0x4000 /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_SHIFT 14 /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */
+#define WM8993_AIFADC_TDM 0x2000 /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_MASK 0x2000 /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_SHIFT 13 /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_MASK 0x1000 /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_SHIFT 12 /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */
+#define WM8993_BCLK_DIR 0x0200 /* BCLK_DIR */
+#define WM8993_BCLK_DIR_MASK 0x0200 /* BCLK_DIR */
+#define WM8993_BCLK_DIR_SHIFT 9 /* BCLK_DIR */
+#define WM8993_BCLK_DIR_WIDTH 1 /* BCLK_DIR */
+#define WM8993_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_MASK 0x0100 /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_SHIFT 8 /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */
+#define WM8993_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_MASK 0x0080 /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_SHIFT 7 /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */
+#define WM8993_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */
+#define WM8993_AIF_WL_SHIFT 5 /* AIF_WL - [6:5] */
+#define WM8993_AIF_WL_WIDTH 2 /* AIF_WL - [6:5] */
+#define WM8993_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */
+#define WM8993_AIF_FMT_SHIFT 3 /* AIF_FMT - [4:3] */
+#define WM8993_AIF_FMT_WIDTH 2 /* AIF_FMT - [4:3] */
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8993_AIFDACL_SRC 0x8000 /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_MASK 0x8000 /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_SHIFT 15 /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */
+#define WM8993_AIFDACR_SRC 0x4000 /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_MASK 0x4000 /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_SHIFT 14 /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */
+#define WM8993_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */
+#define WM8993_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_BOOST_SHIFT 10 /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_COMP 0x0010 /* DAC_COMP */
+#define WM8993_DAC_COMP_MASK 0x0010 /* DAC_COMP */
+#define WM8993_DAC_COMP_SHIFT 4 /* DAC_COMP */
+#define WM8993_DAC_COMP_WIDTH 1 /* DAC_COMP */
+#define WM8993_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
+#define WM8993_ADC_COMP 0x0004 /* ADC_COMP */
+#define WM8993_ADC_COMP_MASK 0x0004 /* ADC_COMP */
+#define WM8993_ADC_COMP_SHIFT 2 /* ADC_COMP */
+#define WM8993_ADC_COMP_WIDTH 1 /* ADC_COMP */
+#define WM8993_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
+#define WM8993_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8993_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8993_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8993_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking 1
+ */
+#define WM8993_TOCLK_RATE 0x8000 /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_MASK 0x8000 /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_SHIFT 15 /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */
+#define WM8993_TOCLK_ENA 0x4000 /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_MASK 0x4000 /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_SHIFT 14 /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
+#define WM8993_OPCLK_DIV_MASK 0x1E00 /* OPCLK_DIV - [12:9] */
+#define WM8993_OPCLK_DIV_SHIFT 9 /* OPCLK_DIV - [12:9] */
+#define WM8993_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [12:9] */
+#define WM8993_DCLK_DIV_MASK 0x01C0 /* DCLK_DIV - [8:6] */
+#define WM8993_DCLK_DIV_SHIFT 6 /* DCLK_DIV - [8:6] */
+#define WM8993_DCLK_DIV_WIDTH 3 /* DCLK_DIV - [8:6] */
+#define WM8993_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */
+#define WM8993_BCLK_DIV_SHIFT 1 /* BCLK_DIV - [4:1] */
+#define WM8993_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [4:1] */
+
+/*
+ * R7 (0x07) - Clocking 2
+ */
+#define WM8993_MCLK_SRC 0x8000 /* MCLK_SRC */
+#define WM8993_MCLK_SRC_MASK 0x8000 /* MCLK_SRC */
+#define WM8993_MCLK_SRC_SHIFT 15 /* MCLK_SRC */
+#define WM8993_MCLK_SRC_WIDTH 1 /* MCLK_SRC */
+#define WM8993_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */
+#define WM8993_MCLK_DIV 0x1000 /* MCLK_DIV */
+#define WM8993_MCLK_DIV_MASK 0x1000 /* MCLK_DIV */
+#define WM8993_MCLK_DIV_SHIFT 12 /* MCLK_DIV */
+#define WM8993_MCLK_DIV_WIDTH 1 /* MCLK_DIV */
+#define WM8993_MCLK_INV 0x0400 /* MCLK_INV */
+#define WM8993_MCLK_INV_MASK 0x0400 /* MCLK_INV */
+#define WM8993_MCLK_INV_SHIFT 10 /* MCLK_INV */
+#define WM8993_MCLK_INV_WIDTH 1 /* MCLK_INV */
+#define WM8993_ADC_DIV_MASK 0x00E0 /* ADC_DIV - [7:5] */
+#define WM8993_ADC_DIV_SHIFT 5 /* ADC_DIV - [7:5] */
+#define WM8993_ADC_DIV_WIDTH 3 /* ADC_DIV - [7:5] */
+#define WM8993_DAC_DIV_MASK 0x001C /* DAC_DIV - [4:2] */
+#define WM8993_DAC_DIV_SHIFT 2 /* DAC_DIV - [4:2] */
+#define WM8993_DAC_DIV_WIDTH 3 /* DAC_DIV - [4:2] */
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8993_AIF_MSTR1 0x8000 /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_MASK 0x8000 /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_SHIFT 15 /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_WIDTH 1 /* AIF_MSTR1 */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8993_AIF_TRIS 0x2000 /* AIF_TRIS */
+#define WM8993_AIF_TRIS_MASK 0x2000 /* AIF_TRIS */
+#define WM8993_AIF_TRIS_SHIFT 13 /* AIF_TRIS */
+#define WM8993_AIF_TRIS_WIDTH 1 /* AIF_TRIS */
+#define WM8993_LRCLK_DIR 0x0800 /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */
+#define WM8993_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */
+#define WM8993_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */
+#define WM8993_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8993_DAC_OSR128 0x2000 /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_MASK 0x2000 /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_SHIFT 13 /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */
+#define WM8993_DAC_MONO 0x0200 /* DAC_MONO */
+#define WM8993_DAC_MONO_MASK 0x0200 /* DAC_MONO */
+#define WM8993_DAC_MONO_SHIFT 9 /* DAC_MONO */
+#define WM8993_DAC_MONO_WIDTH 1 /* DAC_MONO */
+#define WM8993_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_MASK 0x0100 /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_SHIFT 8 /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */
+#define WM8993_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_MASK 0x0080 /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_SHIFT 7 /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
+#define WM8993_DAC_UNMUTE_RAMP 0x0040 /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_MASK 0x0040 /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_SHIFT 6 /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */
+#define WM8993_DEEMPH_MASK 0x0030 /* DEEMPH - [5:4] */
+#define WM8993_DEEMPH_SHIFT 4 /* DEEMPH - [5:4] */
+#define WM8993_DEEMPH_WIDTH 2 /* DEEMPH - [5:4] */
+#define WM8993_DAC_MUTE 0x0004 /* DAC_MUTE */
+#define WM8993_DAC_MUTE_MASK 0x0004 /* DAC_MUTE */
+#define WM8993_DAC_MUTE_SHIFT 2 /* DAC_MUTE */
+#define WM8993_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
+#define WM8993_DACL_DATINV 0x0002 /* DACL_DATINV */
+#define WM8993_DACL_DATINV_MASK 0x0002 /* DACL_DATINV */
+#define WM8993_DACL_DATINV_SHIFT 1 /* DACL_DATINV */
+#define WM8993_DACL_DATINV_WIDTH 1 /* DACL_DATINV */
+#define WM8993_DACR_DATINV 0x0001 /* DACR_DATINV */
+#define WM8993_DACR_DATINV_MASK 0x0001 /* DACR_DATINV */
+#define WM8993_DACR_DATINV_SHIFT 0 /* DACR_DATINV */
+#define WM8993_DACR_DATINV_WIDTH 1 /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8993_DAC_VU 0x0100 /* DAC_VU */
+#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8993_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
+#define WM8993_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
+#define WM8993_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8993_DAC_VU 0x0100 /* DAC_VU */
+#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8993_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
+#define WM8993_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
+#define WM8993_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8993_ADCL_DAC_SVOL_MASK 0x1E00 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCL_DAC_SVOL_SHIFT 9 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCR_DAC_SVOL_MASK 0x01E0 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADCR_DAC_SVOL_SHIFT 5 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */
+#define WM8993_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */
+#define WM8993_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8993_ADC_OSR128 0x0200 /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_MASK 0x0200 /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_SHIFT 9 /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */
+#define WM8993_ADC_HPF 0x0100 /* ADC_HPF */
+#define WM8993_ADC_HPF_MASK 0x0100 /* ADC_HPF */
+#define WM8993_ADC_HPF_SHIFT 8 /* ADC_HPF */
+#define WM8993_ADC_HPF_WIDTH 1 /* ADC_HPF */
+#define WM8993_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADCL_DATINV 0x0002 /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */
+#define WM8993_ADCR_DATINV 0x0001 /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8993_ADC_VU 0x0100 /* ADC_VU */
+#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8993_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
+#define WM8993_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
+#define WM8993_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8993_ADC_VU 0x0100 /* ADC_VU */
+#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8993_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
+#define WM8993_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
+#define WM8993_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8993_JD2_SC_EINT 0x8000 /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_MASK 0x8000 /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_SHIFT 15 /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_WIDTH 1 /* JD2_SC_EINT */
+#define WM8993_JD2_EINT 0x4000 /* JD2_EINT */
+#define WM8993_JD2_EINT_MASK 0x4000 /* JD2_EINT */
+#define WM8993_JD2_EINT_SHIFT 14 /* JD2_EINT */
+#define WM8993_JD2_EINT_WIDTH 1 /* JD2_EINT */
+#define WM8993_WSEQ_EINT 0x2000 /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_MASK 0x2000 /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_SHIFT 13 /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */
+#define WM8993_IRQ 0x1000 /* IRQ */
+#define WM8993_IRQ_MASK 0x1000 /* IRQ */
+#define WM8993_IRQ_SHIFT 12 /* IRQ */
+#define WM8993_IRQ_WIDTH 1 /* IRQ */
+#define WM8993_TEMPOK_EINT 0x0800 /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_MASK 0x0800 /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_SHIFT 11 /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_WIDTH 1 /* TEMPOK_EINT */
+#define WM8993_JD1_SC_EINT 0x0400 /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_MASK 0x0400 /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_SHIFT 10 /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_WIDTH 1 /* JD1_SC_EINT */
+#define WM8993_JD1_EINT 0x0200 /* JD1_EINT */
+#define WM8993_JD1_EINT_MASK 0x0200 /* JD1_EINT */
+#define WM8993_JD1_EINT_SHIFT 9 /* JD1_EINT */
+#define WM8993_JD1_EINT_WIDTH 1 /* JD1_EINT */
+#define WM8993_FLL_LOCK_EINT 0x0100 /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_MASK 0x0100 /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_SHIFT 8 /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */
+#define WM8993_GPI8_EINT 0x0080 /* GPI8_EINT */
+#define WM8993_GPI8_EINT_MASK 0x0080 /* GPI8_EINT */
+#define WM8993_GPI8_EINT_SHIFT 7 /* GPI8_EINT */
+#define WM8993_GPI8_EINT_WIDTH 1 /* GPI8_EINT */
+#define WM8993_GPI7_EINT 0x0040 /* GPI7_EINT */
+#define WM8993_GPI7_EINT_MASK 0x0040 /* GPI7_EINT */
+#define WM8993_GPI7_EINT_SHIFT 6 /* GPI7_EINT */
+#define WM8993_GPI7_EINT_WIDTH 1 /* GPI7_EINT */
+#define WM8993_GPIO1_EINT 0x0001 /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_MASK 0x0001 /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_SHIFT 0 /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */
+
+/*
+ * R19 (0x13) - GPIO1
+ */
+#define WM8993_GPIO1_PU 0x0020 /* GPIO1_PU */
+#define WM8993_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */
+#define WM8993_GPIO1_PU_SHIFT 5 /* GPIO1_PU */
+#define WM8993_GPIO1_PU_WIDTH 1 /* GPIO1_PU */
+#define WM8993_GPIO1_PD 0x0010 /* GPIO1_PD */
+#define WM8993_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */
+#define WM8993_GPIO1_PD_SHIFT 4 /* GPIO1_PD */
+#define WM8993_GPIO1_PD_WIDTH 1 /* GPIO1_PD */
+#define WM8993_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
+#define WM8993_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */
+#define WM8993_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - IRQ_DEBOUNCE
+ */
+#define WM8993_JD2_SC_DB 0x8000 /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_MASK 0x8000 /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_SHIFT 15 /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_WIDTH 1 /* JD2_SC_DB */
+#define WM8993_JD2_DB 0x4000 /* JD2_DB */
+#define WM8993_JD2_DB_MASK 0x4000 /* JD2_DB */
+#define WM8993_JD2_DB_SHIFT 14 /* JD2_DB */
+#define WM8993_JD2_DB_WIDTH 1 /* JD2_DB */
+#define WM8993_WSEQ_DB 0x2000 /* WSEQ_DB */
+#define WM8993_WSEQ_DB_MASK 0x2000 /* WSEQ_DB */
+#define WM8993_WSEQ_DB_SHIFT 13 /* WSEQ_DB */
+#define WM8993_WSEQ_DB_WIDTH 1 /* WSEQ_DB */
+#define WM8993_TEMPOK_DB 0x0800 /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_MASK 0x0800 /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_SHIFT 11 /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_WIDTH 1 /* TEMPOK_DB */
+#define WM8993_JD1_SC_DB 0x0400 /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_MASK 0x0400 /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_SHIFT 10 /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_WIDTH 1 /* JD1_SC_DB */
+#define WM8993_JD1_DB 0x0200 /* JD1_DB */
+#define WM8993_JD1_DB_MASK 0x0200 /* JD1_DB */
+#define WM8993_JD1_DB_SHIFT 9 /* JD1_DB */
+#define WM8993_JD1_DB_WIDTH 1 /* JD1_DB */
+#define WM8993_FLL_LOCK_DB 0x0100 /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_MASK 0x0100 /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_SHIFT 8 /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_WIDTH 1 /* FLL_LOCK_DB */
+#define WM8993_GPI8_DB 0x0080 /* GPI8_DB */
+#define WM8993_GPI8_DB_MASK 0x0080 /* GPI8_DB */
+#define WM8993_GPI8_DB_SHIFT 7 /* GPI8_DB */
+#define WM8993_GPI8_DB_WIDTH 1 /* GPI8_DB */
+#define WM8993_GPI7_DB 0x0008 /* GPI7_DB */
+#define WM8993_GPI7_DB_MASK 0x0008 /* GPI7_DB */
+#define WM8993_GPI7_DB_SHIFT 3 /* GPI7_DB */
+#define WM8993_GPI7_DB_WIDTH 1 /* GPI7_DB */
+#define WM8993_GPIO1_DB 0x0001 /* GPIO1_DB */
+#define WM8993_GPIO1_DB_MASK 0x0001 /* GPIO1_DB */
+#define WM8993_GPIO1_DB_SHIFT 0 /* GPIO1_DB */
+#define WM8993_GPIO1_DB_WIDTH 1 /* GPIO1_DB */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8993_IM_JD2_EINT 0x2000 /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_MASK 0x2000 /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_SHIFT 13 /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_WIDTH 1 /* IM_JD2_EINT */
+#define WM8993_IM_JD2_SC_EINT 0x1000 /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_MASK 0x1000 /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_SHIFT 12 /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_WIDTH 1 /* IM_JD2_SC_EINT */
+#define WM8993_IM_TEMPOK_EINT 0x0800 /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_MASK 0x0800 /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_SHIFT 11 /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_WIDTH 1 /* IM_TEMPOK_EINT */
+#define WM8993_IM_JD1_SC_EINT 0x0400 /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_MASK 0x0400 /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_SHIFT 10 /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_WIDTH 1 /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_EINT 0x0200 /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_MASK 0x0200 /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_SHIFT 9 /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_WIDTH 1 /* IM_JD1_EINT */
+#define WM8993_IM_FLL_LOCK_EINT 0x0100 /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_MASK 0x0100 /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_SHIFT 8 /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_GPI8_EINT 0x0040 /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_MASK 0x0040 /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_SHIFT 6 /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */
+#define WM8993_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */
+#define WM8993_GPI8_ENA 0x0010 /* GPI8_ENA */
+#define WM8993_GPI8_ENA_MASK 0x0010 /* GPI8_ENA */
+#define WM8993_GPI8_ENA_SHIFT 4 /* GPI8_ENA */
+#define WM8993_GPI8_ENA_WIDTH 1 /* GPI8_ENA */
+#define WM8993_IM_GPI7_EINT 0x0004 /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_MASK 0x0004 /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_SHIFT 2 /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */
+#define WM8993_IM_WSEQ_EINT 0x0002 /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_MASK 0x0002 /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_SHIFT 1 /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */
+#define WM8993_GPI7_ENA 0x0001 /* GPI7_ENA */
+#define WM8993_GPI7_ENA_MASK 0x0001 /* GPI7_ENA */
+#define WM8993_GPI7_ENA_SHIFT 0 /* GPI7_ENA */
+#define WM8993_GPI7_ENA_WIDTH 1 /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8993_JD2_SC_POL 0x8000 /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_MASK 0x8000 /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_SHIFT 15 /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_WIDTH 1 /* JD2_SC_POL */
+#define WM8993_JD2_POL 0x4000 /* JD2_POL */
+#define WM8993_JD2_POL_MASK 0x4000 /* JD2_POL */
+#define WM8993_JD2_POL_SHIFT 14 /* JD2_POL */
+#define WM8993_JD2_POL_WIDTH 1 /* JD2_POL */
+#define WM8993_WSEQ_POL 0x2000 /* WSEQ_POL */
+#define WM8993_WSEQ_POL_MASK 0x2000 /* WSEQ_POL */
+#define WM8993_WSEQ_POL_SHIFT 13 /* WSEQ_POL */
+#define WM8993_WSEQ_POL_WIDTH 1 /* WSEQ_POL */
+#define WM8993_IRQ_POL 0x1000 /* IRQ_POL */
+#define WM8993_IRQ_POL_MASK 0x1000 /* IRQ_POL */
+#define WM8993_IRQ_POL_SHIFT 12 /* IRQ_POL */
+#define WM8993_IRQ_POL_WIDTH 1 /* IRQ_POL */
+#define WM8993_TEMPOK_POL 0x0800 /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_MASK 0x0800 /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_SHIFT 11 /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_WIDTH 1 /* TEMPOK_POL */
+#define WM8993_JD1_SC_POL 0x0400 /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_MASK 0x0400 /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_SHIFT 10 /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_WIDTH 1 /* JD1_SC_POL */
+#define WM8993_JD1_POL 0x0200 /* JD1_POL */
+#define WM8993_JD1_POL_MASK 0x0200 /* JD1_POL */
+#define WM8993_JD1_POL_SHIFT 9 /* JD1_POL */
+#define WM8993_JD1_POL_WIDTH 1 /* JD1_POL */
+#define WM8993_FLL_LOCK_POL 0x0100 /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_MASK 0x0100 /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_SHIFT 8 /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_WIDTH 1 /* FLL_LOCK_POL */
+#define WM8993_GPI8_POL 0x0080 /* GPI8_POL */
+#define WM8993_GPI8_POL_MASK 0x0080 /* GPI8_POL */
+#define WM8993_GPI8_POL_SHIFT 7 /* GPI8_POL */
+#define WM8993_GPI8_POL_WIDTH 1 /* GPI8_POL */
+#define WM8993_GPI7_POL 0x0040 /* GPI7_POL */
+#define WM8993_GPI7_POL_MASK 0x0040 /* GPI7_POL */
+#define WM8993_GPI7_POL_SHIFT 6 /* GPI7_POL */
+#define WM8993_GPI7_POL_WIDTH 1 /* GPI7_POL */
+#define WM8993_GPIO1_POL 0x0001 /* GPIO1_POL */
+#define WM8993_GPIO1_POL_MASK 0x0001 /* GPIO1_POL */
+#define WM8993_GPIO1_POL_SHIFT 0 /* GPIO1_POL */
+#define WM8993_GPIO1_POL_WIDTH 1 /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8993_IN1_VU 0x0100 /* IN1_VU */
+#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */
+#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */
+#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */
+#define WM8993_IN1L_MUTE 0x0080 /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_MASK 0x0080 /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_SHIFT 7 /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */
+#define WM8993_IN1L_ZC 0x0040 /* IN1L_ZC */
+#define WM8993_IN1L_ZC_MASK 0x0040 /* IN1L_ZC */
+#define WM8993_IN1L_ZC_SHIFT 6 /* IN1L_ZC */
+#define WM8993_IN1L_ZC_WIDTH 1 /* IN1L_ZC */
+#define WM8993_IN1L_VOL_MASK 0x001F /* IN1L_VOL - [4:0] */
+#define WM8993_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [4:0] */
+#define WM8993_IN1L_VOL_WIDTH 5 /* IN1L_VOL - [4:0] */
+
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8993_IN2_VU 0x0100 /* IN2_VU */
+#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */
+#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */
+#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */
+#define WM8993_IN2L_MUTE 0x0080 /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_MASK 0x0080 /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_SHIFT 7 /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */
+#define WM8993_IN2L_ZC 0x0040 /* IN2L_ZC */
+#define WM8993_IN2L_ZC_MASK 0x0040 /* IN2L_ZC */
+#define WM8993_IN2L_ZC_SHIFT 6 /* IN2L_ZC */
+#define WM8993_IN2L_ZC_WIDTH 1 /* IN2L_ZC */
+#define WM8993_IN2L_VOL_MASK 0x001F /* IN2L_VOL - [4:0] */
+#define WM8993_IN2L_VOL_SHIFT 0 /* IN2L_VOL - [4:0] */
+#define WM8993_IN2L_VOL_WIDTH 5 /* IN2L_VOL - [4:0] */
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8993_IN1_VU 0x0100 /* IN1_VU */
+#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */
+#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */
+#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */
+#define WM8993_IN1R_MUTE 0x0080 /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_MASK 0x0080 /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_SHIFT 7 /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */
+#define WM8993_IN1R_ZC 0x0040 /* IN1R_ZC */
+#define WM8993_IN1R_ZC_MASK 0x0040 /* IN1R_ZC */
+#define WM8993_IN1R_ZC_SHIFT 6 /* IN1R_ZC */
+#define WM8993_IN1R_ZC_WIDTH 1 /* IN1R_ZC */
+#define WM8993_IN1R_VOL_MASK 0x001F /* IN1R_VOL - [4:0] */
+#define WM8993_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [4:0] */
+#define WM8993_IN1R_VOL_WIDTH 5 /* IN1R_VOL - [4:0] */
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8993_IN2_VU 0x0100 /* IN2_VU */
+#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */
+#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */
+#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */
+#define WM8993_IN2R_MUTE 0x0080 /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_MASK 0x0080 /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_SHIFT 7 /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */
+#define WM8993_IN2R_ZC 0x0040 /* IN2R_ZC */
+#define WM8993_IN2R_ZC_MASK 0x0040 /* IN2R_ZC */
+#define WM8993_IN2R_ZC_SHIFT 6 /* IN2R_ZC */
+#define WM8993_IN2R_ZC_WIDTH 1 /* IN2R_ZC */
+#define WM8993_IN2R_VOL_MASK 0x001F /* IN2R_VOL - [4:0] */
+#define WM8993_IN2R_VOL_SHIFT 0 /* IN2R_VOL - [4:0] */
+#define WM8993_IN2R_VOL_WIDTH 5 /* IN2R_VOL - [4:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
+#define WM8993_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_MUTE_N 0x0040 /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_MASK 0x0040 /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_SHIFT 6 /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_WIDTH 1 /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_VOL_MASK 0x003F /* HPOUT1L_VOL - [5:0] */
+#define WM8993_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [5:0] */
+#define WM8993_HPOUT1L_VOL_WIDTH 6 /* HPOUT1L_VOL - [5:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
+#define WM8993_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_MUTE_N 0x0040 /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_MASK 0x0040 /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_SHIFT 6 /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_WIDTH 1 /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_VOL_MASK 0x003F /* HPOUT1R_VOL - [5:0] */
+#define WM8993_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [5:0] */
+#define WM8993_HPOUT1R_VOL_WIDTH 6 /* HPOUT1R_VOL - [5:0] */
+
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8993_LINEOUT1N_MUTE 0x0040 /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_MASK 0x0040 /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_SHIFT 6 /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_WIDTH 1 /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1P_MUTE 0x0020 /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_MASK 0x0020 /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_SHIFT 5 /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_WIDTH 1 /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1_VOL 0x0010 /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_MASK 0x0010 /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_SHIFT 4 /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_WIDTH 1 /* LINEOUT1_VOL */
+#define WM8993_LINEOUT2N_MUTE 0x0004 /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_MASK 0x0004 /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_SHIFT 2 /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_WIDTH 1 /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2P_MUTE 0x0002 /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_MASK 0x0002 /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_SHIFT 1 /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_WIDTH 1 /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2_VOL 0x0001 /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_MASK 0x0001 /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_SHIFT 0 /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_WIDTH 1 /* LINEOUT2_VOL */
+
+/*
+ * R31 (0x1F) - HPOUT2 Volume
+ */
+#define WM8993_HPOUT2_MUTE 0x0020 /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_MASK 0x0020 /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_SHIFT 5 /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_WIDTH 1 /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_VOL 0x0010 /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_MASK 0x0010 /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_SHIFT 4 /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_WIDTH 1 /* HPOUT2_VOL */
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */
+#define WM8993_MIXOUTL_ZC 0x0080 /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_MASK 0x0080 /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_SHIFT 7 /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_WIDTH 1 /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_MUTE_N 0x0040 /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_MASK 0x0040 /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_SHIFT 6 /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_WIDTH 1 /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_VOL_MASK 0x003F /* MIXOUTL_VOL - [5:0] */
+#define WM8993_MIXOUTL_VOL_SHIFT 0 /* MIXOUTL_VOL - [5:0] */
+#define WM8993_MIXOUTL_VOL_WIDTH 6 /* MIXOUTL_VOL - [5:0] */
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */
+#define WM8993_MIXOUTR_ZC 0x0080 /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_MASK 0x0080 /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_SHIFT 7 /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_WIDTH 1 /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_MUTE_N 0x0040 /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_MASK 0x0040 /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_SHIFT 6 /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_WIDTH 1 /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_VOL_MASK 0x003F /* MIXOUTR_VOL - [5:0] */
+#define WM8993_MIXOUTR_VOL_SHIFT 0 /* MIXOUTR_VOL - [5:0] */
+#define WM8993_MIXOUTR_VOL_WIDTH 6 /* MIXOUTR_VOL - [5:0] */
+
+/*
+ * R34 (0x22) - SPKMIXL Attenuation
+ */
+#define WM8993_MIXINL_SPKMIXL_VOL 0x0020 /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_MASK 0x0020 /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_SHIFT 5 /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL 0x0010 /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_MASK 0x0010 /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_SHIFT 4 /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_WIDTH 1 /* IN1LP_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL 0x0008 /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_MASK 0x0008 /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_SHIFT 3 /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_WIDTH 1 /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL 0x0004 /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_MASK 0x0004 /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_SHIFT 2 /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_WIDTH 1 /* DACL_SPKMIXL_VOL */
+#define WM8993_SPKMIXL_VOL_MASK 0x0003 /* SPKMIXL_VOL - [1:0] */
+#define WM8993_SPKMIXL_VOL_SHIFT 0 /* SPKMIXL_VOL - [1:0] */
+#define WM8993_SPKMIXL_VOL_WIDTH 2 /* SPKMIXL_VOL - [1:0] */
+
+/*
+ * R35 (0x23) - SPKMIXR Attenuation
+ */
+#define WM8993_SPKOUT_CLASSAB_MODE 0x0100 /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_MASK 0x0100 /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_SHIFT 8 /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_WIDTH 1 /* SPKOUT_CLASSAB_MODE */
+#define WM8993_MIXINR_SPKMIXR_VOL 0x0020 /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_MASK 0x0020 /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_SHIFT 5 /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL 0x0010 /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_MASK 0x0010 /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_SHIFT 4 /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_WIDTH 1 /* IN1RP_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL 0x0008 /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_MASK 0x0008 /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_SHIFT 3 /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_WIDTH 1 /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL 0x0004 /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_MASK 0x0004 /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_SHIFT 2 /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_WIDTH 1 /* DACR_SPKMIXR_VOL */
+#define WM8993_SPKMIXR_VOL_MASK 0x0003 /* SPKMIXR_VOL - [1:0] */
+#define WM8993_SPKMIXR_VOL_SHIFT 0 /* SPKMIXR_VOL - [1:0] */
+#define WM8993_SPKMIXR_VOL_WIDTH 2 /* SPKMIXR_VOL - [1:0] */
+
+/*
+ * R36 (0x24) - SPKOUT Mixers
+ */
+#define WM8993_VRX_TO_SPKOUTL 0x0020 /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_MASK 0x0020 /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_SHIFT 5 /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_WIDTH 1 /* VRX_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL 0x0010 /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_MASK 0x0010 /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_SHIFT 4 /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_WIDTH 1 /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL 0x0008 /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_MASK 0x0008 /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_SHIFT 3 /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_WIDTH 1 /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTR 0x0004 /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_MASK 0x0004 /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_SHIFT 2 /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_WIDTH 1 /* VRX_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR 0x0002 /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_MASK 0x0002 /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_SHIFT 1 /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_WIDTH 1 /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR 0x0001 /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_MASK 0x0001 /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_SHIFT 0 /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_WIDTH 1 /* SPKMIXR_TO_SPKOUTR */
+
+/*
+ * R37 (0x25) - SPKOUT Boost
+ */
+#define WM8993_SPKOUTL_BOOST_MASK 0x0038 /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTL_BOOST_SHIFT 3 /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTL_BOOST_WIDTH 3 /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTR_BOOST_MASK 0x0007 /* SPKOUTR_BOOST - [2:0] */
+#define WM8993_SPKOUTR_BOOST_SHIFT 0 /* SPKOUTR_BOOST - [2:0] */
+#define WM8993_SPKOUTR_BOOST_WIDTH 3 /* SPKOUTR_BOOST - [2:0] */
+
+/*
+ * R38 (0x26) - Speaker Volume Left
+ */
+#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
+#define WM8993_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_MUTE_N 0x0040 /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_MASK 0x0040 /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_SHIFT 6 /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_WIDTH 1 /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */
+#define WM8993_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */
+#define WM8993_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */
+
+/*
+ * R39 (0x27) - Speaker Volume Right
+ */
+#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
+#define WM8993_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_MUTE_N 0x0040 /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_MASK 0x0040 /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_SHIFT 6 /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_WIDTH 1 /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_VOL_MASK 0x003F /* SPKOUTR_VOL - [5:0] */
+#define WM8993_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [5:0] */
+#define WM8993_SPKOUTR_VOL_WIDTH 6 /* SPKOUTR_VOL - [5:0] */
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8993_IN2LP_TO_IN2L 0x0080 /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_MASK 0x0080 /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_SHIFT 7 /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_WIDTH 1 /* IN2LP_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L 0x0040 /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_MASK 0x0040 /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_SHIFT 6 /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_WIDTH 1 /* IN2LN_TO_IN2L */
+#define WM8993_IN1LP_TO_IN1L 0x0020 /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_MASK 0x0020 /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_SHIFT 5 /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_WIDTH 1 /* IN1LP_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L 0x0010 /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_MASK 0x0010 /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_SHIFT 4 /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_WIDTH 1 /* IN1LN_TO_IN1L */
+#define WM8993_IN2RP_TO_IN2R 0x0008 /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_MASK 0x0008 /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_SHIFT 3 /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_WIDTH 1 /* IN2RP_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R 0x0004 /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_MASK 0x0004 /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_SHIFT 2 /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_WIDTH 1 /* IN2RN_TO_IN2R */
+#define WM8993_IN1RP_TO_IN1R 0x0002 /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_MASK 0x0002 /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_SHIFT 1 /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_WIDTH 1 /* IN1RP_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R 0x0001 /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_MASK 0x0001 /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_SHIFT 0 /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_WIDTH 1 /* IN1RN_TO_IN1R */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8993_IN2L_TO_MIXINL 0x0100 /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_MASK 0x0100 /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_SHIFT 8 /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_MIXINL_VOL 0x0080 /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_MASK 0x0080 /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_SHIFT 7 /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_WIDTH 1 /* IN2L_MIXINL_VOL */
+#define WM8993_IN1L_TO_MIXINL 0x0020 /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_MASK 0x0020 /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_SHIFT 5 /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_WIDTH 1 /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_MIXINL_VOL 0x0010 /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_MASK 0x0010 /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_SHIFT 4 /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_WIDTH 1 /* IN1L_MIXINL_VOL */
+#define WM8993_MIXOUTL_MIXINL_VOL_MASK 0x0007 /* MIXOUTL_MIXINL_VOL - [2:0] */
+#define WM8993_MIXOUTL_MIXINL_VOL_SHIFT 0 /* MIXOUTL_MIXINL_VOL - [2:0] */
+#define WM8993_MIXOUTL_MIXINL_VOL_WIDTH 3 /* MIXOUTL_MIXINL_VOL - [2:0] */
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8993_IN2R_TO_MIXINR 0x0100 /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_MASK 0x0100 /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_SHIFT 8 /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_MIXINR_VOL 0x0080 /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_MASK 0x0080 /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_SHIFT 7 /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_WIDTH 1 /* IN2R_MIXINR_VOL */
+#define WM8993_IN1R_TO_MIXINR 0x0020 /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_MASK 0x0020 /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_SHIFT 5 /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_WIDTH 1 /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_MIXINR_VOL 0x0010 /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_MASK 0x0010 /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_SHIFT 4 /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_WIDTH 1 /* IN1R_MIXINR_VOL */
+#define WM8993_MIXOUTR_MIXINR_VOL_MASK 0x0007 /* MIXOUTR_MIXINR_VOL - [2:0] */
+#define WM8993_MIXOUTR_MIXINR_VOL_SHIFT 0 /* MIXOUTR_MIXINR_VOL - [2:0] */
+#define WM8993_MIXOUTR_MIXINR_VOL_WIDTH 3 /* MIXOUTR_MIXINR_VOL - [2:0] */
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8993_IN1LP_MIXINL_VOL_MASK 0x01C0 /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_IN1LP_MIXINL_VOL_SHIFT 6 /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_IN1LP_MIXINL_VOL_WIDTH 3 /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_VRX_MIXINL_VOL_MASK 0x0007 /* VRX_MIXINL_VOL - [2:0] */
+#define WM8993_VRX_MIXINL_VOL_SHIFT 0 /* VRX_MIXINL_VOL - [2:0] */
+#define WM8993_VRX_MIXINL_VOL_WIDTH 3 /* VRX_MIXINL_VOL - [2:0] */
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8993_IN1RP_MIXINR_VOL_MASK 0x01C0 /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_IN1RP_MIXINR_VOL_SHIFT 6 /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_IN1RP_MIXINR_VOL_WIDTH 3 /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_VRX_MIXINR_VOL_MASK 0x0007 /* VRX_MIXINR_VOL - [2:0] */
+#define WM8993_VRX_MIXINR_VOL_SHIFT 0 /* VRX_MIXINR_VOL - [2:0] */
+#define WM8993_VRX_MIXINR_VOL_WIDTH 3 /* VRX_MIXINR_VOL - [2:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8993_DACL_TO_HPOUT1L 0x0100 /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_MASK 0x0100 /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_SHIFT 8 /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_WIDTH 1 /* DACL_TO_HPOUT1L */
+#define WM8993_MIXINR_TO_MIXOUTL 0x0080 /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_MASK 0x0080 /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_SHIFT 7 /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_WIDTH 1 /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL 0x0040 /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_MASK 0x0040 /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_SHIFT 6 /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_WIDTH 1 /* MIXINL_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL 0x0020 /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_MASK 0x0020 /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_SHIFT 5 /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_WIDTH 1 /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL 0x0010 /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_MASK 0x0010 /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_SHIFT 4 /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_WIDTH 1 /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL 0x0008 /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_MASK 0x0008 /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_SHIFT 3 /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_WIDTH 1 /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL 0x0004 /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_MASK 0x0004 /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_SHIFT 2 /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_WIDTH 1 /* IN1L_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL 0x0002 /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_MASK 0x0002 /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_SHIFT 1 /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_WIDTH 1 /* IN2LP_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL 0x0001 /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_MASK 0x0001 /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_SHIFT 0 /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_WIDTH 1 /* DACL_TO_MIXOUTL */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8993_DACR_TO_HPOUT1R 0x0100 /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_MASK 0x0100 /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_SHIFT 8 /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_WIDTH 1 /* DACR_TO_HPOUT1R */
+#define WM8993_MIXINL_TO_MIXOUTR 0x0080 /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_MASK 0x0080 /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_SHIFT 7 /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_WIDTH 1 /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR 0x0040 /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_MASK 0x0040 /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_SHIFT 6 /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_WIDTH 1 /* MIXINR_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR 0x0020 /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_MASK 0x0020 /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_SHIFT 5 /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_WIDTH 1 /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR 0x0010 /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_MASK 0x0010 /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_SHIFT 4 /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_WIDTH 1 /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR 0x0008 /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_MASK 0x0008 /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_SHIFT 3 /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_WIDTH 1 /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR 0x0004 /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_MASK 0x0004 /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_SHIFT 2 /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_WIDTH 1 /* IN1R_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR 0x0002 /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_MASK 0x0002 /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_SHIFT 1 /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_WIDTH 1 /* IN2RP_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR 0x0001 /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_MASK 0x0001 /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_SHIFT 0 /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_WIDTH 1 /* DACR_TO_MIXOUTR */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8993_IN2LP_MIXOUTL_VOL_MASK 0x0E00 /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LP_MIXOUTL_VOL_SHIFT 9 /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LP_MIXOUTL_VOL_WIDTH 3 /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LN_MIXOUTL_VOL_MASK 0x01C0 /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTL_VOL_SHIFT 6 /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTL_VOL_WIDTH 3 /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN1R_MIXOUTL_VOL_MASK 0x0038 /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTL_VOL_SHIFT 3 /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTL_VOL_WIDTH 3 /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTL_VOL_MASK 0x0007 /* IN1L_MIXOUTL_VOL - [2:0] */
+#define WM8993_IN1L_MIXOUTL_VOL_SHIFT 0 /* IN1L_MIXOUTL_VOL - [2:0] */
+#define WM8993_IN1L_MIXOUTL_VOL_WIDTH 3 /* IN1L_MIXOUTL_VOL - [2:0] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8993_IN2RP_MIXOUTR_VOL_MASK 0x0E00 /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RP_MIXOUTR_VOL_SHIFT 9 /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RP_MIXOUTR_VOL_WIDTH 3 /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RN_MIXOUTR_VOL_MASK 0x01C0 /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTR_VOL_SHIFT 6 /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTR_VOL_WIDTH 3 /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN1L_MIXOUTR_VOL_MASK 0x0038 /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTR_VOL_SHIFT 3 /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTR_VOL_WIDTH 3 /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTR_VOL_MASK 0x0007 /* IN1R_MIXOUTR_VOL - [2:0] */
+#define WM8993_IN1R_MIXOUTR_VOL_SHIFT 0 /* IN1R_MIXOUTR_VOL - [2:0] */
+#define WM8993_IN1R_MIXOUTR_VOL_WIDTH 3 /* IN1R_MIXOUTR_VOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8993_DACL_MIXOUTL_VOL_MASK 0x0E00 /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_DACL_MIXOUTL_VOL_SHIFT 9 /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_DACL_MIXOUTL_VOL_WIDTH 3 /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2RN_MIXOUTL_VOL_MASK 0x01C0 /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTL_VOL_SHIFT 6 /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTL_VOL_WIDTH 3 /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_MIXINR_MIXOUTL_VOL_MASK 0x0038 /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTL_VOL_SHIFT 3 /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTL_VOL_WIDTH 3 /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTL_VOL_MASK 0x0007 /* MIXINL_MIXOUTL_VOL - [2:0] */
+#define WM8993_MIXINL_MIXOUTL_VOL_SHIFT 0 /* MIXINL_MIXOUTL_VOL - [2:0] */
+#define WM8993_MIXINL_MIXOUTL_VOL_WIDTH 3 /* MIXINL_MIXOUTL_VOL - [2:0] */
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8993_DACR_MIXOUTR_VOL_MASK 0x0E00 /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_DACR_MIXOUTR_VOL_SHIFT 9 /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_DACR_MIXOUTR_VOL_WIDTH 3 /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2LN_MIXOUTR_VOL_MASK 0x01C0 /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTR_VOL_SHIFT 6 /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTR_VOL_WIDTH 3 /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_MIXINL_MIXOUTR_VOL_MASK 0x0038 /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTR_VOL_SHIFT 3 /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTR_VOL_WIDTH 3 /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTR_VOL_MASK 0x0007 /* MIXINR_MIXOUTR_VOL - [2:0] */
+#define WM8993_MIXINR_MIXOUTR_VOL_SHIFT 0 /* MIXINR_MIXOUTR_VOL - [2:0] */
+#define WM8993_MIXINR_MIXOUTR_VOL_WIDTH 3 /* MIXINR_MIXOUTR_VOL - [2:0] */
+
+/*
+ * R51 (0x33) - HPOUT2 Mixer
+ */
+#define WM8993_VRX_TO_HPOUT2 0x0020 /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_MASK 0x0020 /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_SHIFT 5 /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_WIDTH 1 /* VRX_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_MASK 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_SHIFT 4 /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_MASK 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_SHIFT 3 /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTRVOL_TO_HPOUT2 */
+
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8993_MIXOUTL_TO_LINEOUT1N 0x0040 /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_MASK 0x0040 /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_SHIFT 6 /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_WIDTH 1 /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N 0x0020 /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_MASK 0x0020 /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_SHIFT 5 /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_WIDTH 1 /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_LINEOUT1_MODE 0x0010 /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_MASK 0x0010 /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_SHIFT 4 /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_WIDTH 1 /* LINEOUT1_MODE */
+#define WM8993_IN1R_TO_LINEOUT1P 0x0004 /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_MASK 0x0004 /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_SHIFT 2 /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_WIDTH 1 /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P 0x0002 /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_MASK 0x0002 /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_SHIFT 1 /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_WIDTH 1 /* IN1L_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P 0x0001 /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_MASK 0x0001 /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_SHIFT 0 /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_WIDTH 1 /* MIXOUTL_TO_LINEOUT1P */
+
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8993_MIXOUTR_TO_LINEOUT2N 0x0040 /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_MASK 0x0040 /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_SHIFT 6 /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_WIDTH 1 /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N 0x0020 /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_MASK 0x0020 /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_SHIFT 5 /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_WIDTH 1 /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_LINEOUT2_MODE 0x0010 /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_MASK 0x0010 /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_SHIFT 4 /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_WIDTH 1 /* LINEOUT2_MODE */
+#define WM8993_IN1L_TO_LINEOUT2P 0x0004 /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_MASK 0x0004 /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_SHIFT 2 /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_WIDTH 1 /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P 0x0002 /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_MASK 0x0002 /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_SHIFT 1 /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_WIDTH 1 /* IN1R_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P 0x0001 /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_MASK 0x0001 /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_SHIFT 0 /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_WIDTH 1 /* MIXOUTR_TO_LINEOUT2P */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8993_SPKAB_REF_SEL 0x0100 /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_MASK 0x0100 /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_SHIFT 8 /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_WIDTH 1 /* SPKAB_REF_SEL */
+#define WM8993_MIXINL_TO_SPKMIXL 0x0080 /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_MASK 0x0080 /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_SHIFT 7 /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINR_TO_SPKMIXR 0x0040 /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_MASK 0x0040 /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_SHIFT 6 /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */
+#define WM8993_IN1LP_TO_SPKMIXL 0x0020 /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_MASK 0x0020 /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_SHIFT 5 /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_WIDTH 1 /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1RP_TO_SPKMIXR 0x0010 /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_MASK 0x0010 /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_SHIFT 4 /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_WIDTH 1 /* IN1RP_TO_SPKMIXR */
+#define WM8993_MIXOUTL_TO_SPKMIXL 0x0008 /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_MASK 0x0008 /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_SHIFT 3 /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_WIDTH 1 /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTR_TO_SPKMIXR 0x0004 /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_MASK 0x0004 /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_SHIFT 2 /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_WIDTH 1 /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_DACL_TO_SPKMIXL 0x0002 /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_MASK 0x0002 /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_SHIFT 1 /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_WIDTH 1 /* DACL_TO_SPKMIXL */
+#define WM8993_DACR_TO_SPKMIXR 0x0001 /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_MASK 0x0001 /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_SHIFT 0 /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_WIDTH 1 /* DACR_TO_SPKMIXR */
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8993_LINEOUT1_FB 0x0080 /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_MASK 0x0080 /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_SHIFT 7 /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_WIDTH 1 /* LINEOUT1_FB */
+#define WM8993_LINEOUT2_FB 0x0040 /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_MASK 0x0040 /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_SHIFT 6 /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_WIDTH 1 /* LINEOUT2_FB */
+#define WM8993_VROI 0x0001 /* VROI */
+#define WM8993_VROI_MASK 0x0001 /* VROI */
+#define WM8993_VROI_SHIFT 0 /* VROI */
+#define WM8993_VROI_WIDTH 1 /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8993_LINEOUT_VMID_BUF_ENA 0x0080 /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_MASK 0x0080 /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_SHIFT 7 /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_WIDTH 1 /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_HPOUT2_IN_ENA 0x0040 /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_MASK 0x0040 /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_SHIFT 6 /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_WIDTH 1 /* HPOUT2_IN_ENA */
+#define WM8993_LINEOUT1_DISCH 0x0020 /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_MASK 0x0020 /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_SHIFT 5 /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_WIDTH 1 /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT2_DISCH 0x0010 /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_MASK 0x0010 /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_SHIFT 4 /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_WIDTH 1 /* LINEOUT2_DISCH */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8993_VMID_RAMP_MASK 0x0060 /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_RAMP_SHIFT 5 /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_RAMP_WIDTH 2 /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
+#define WM8993_STARTUP_BIAS_ENA 0x0004 /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_MASK 0x0004 /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_SHIFT 2 /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */
+#define WM8993_BIAS_SRC 0x0002 /* BIAS_SRC */
+#define WM8993_BIAS_SRC_MASK 0x0002 /* BIAS_SRC */
+#define WM8993_BIAS_SRC_SHIFT 1 /* BIAS_SRC */
+#define WM8993_BIAS_SRC_WIDTH 1 /* BIAS_SRC */
+#define WM8993_VMID_DISCH 0x0001 /* VMID_DISCH */
+#define WM8993_VMID_DISCH_MASK 0x0001 /* VMID_DISCH */
+#define WM8993_VMID_DISCH_SHIFT 0 /* VMID_DISCH */
+#define WM8993_VMID_DISCH_WIDTH 1 /* VMID_DISCH */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8993_JD_SCTHR_MASK 0x00C0 /* JD_SCTHR - [7:6] */
+#define WM8993_JD_SCTHR_SHIFT 6 /* JD_SCTHR - [7:6] */
+#define WM8993_JD_SCTHR_WIDTH 2 /* JD_SCTHR - [7:6] */
+#define WM8993_JD_THR_MASK 0x0030 /* JD_THR - [5:4] */
+#define WM8993_JD_THR_SHIFT 4 /* JD_THR - [5:4] */
+#define WM8993_JD_THR_WIDTH 2 /* JD_THR - [5:4] */
+#define WM8993_JD_ENA 0x0004 /* JD_ENA */
+#define WM8993_JD_ENA_MASK 0x0004 /* JD_ENA */
+#define WM8993_JD_ENA_SHIFT 2 /* JD_ENA */
+#define WM8993_JD_ENA_WIDTH 1 /* JD_ENA */
+#define WM8993_MICB2_LVL 0x0002 /* MICB2_LVL */
+#define WM8993_MICB2_LVL_MASK 0x0002 /* MICB2_LVL */
+#define WM8993_MICB2_LVL_SHIFT 1 /* MICB2_LVL */
+#define WM8993_MICB2_LVL_WIDTH 1 /* MICB2_LVL */
+#define WM8993_MICB1_LVL 0x0001 /* MICB1_LVL */
+#define WM8993_MICB1_LVL_MASK 0x0001 /* MICB1_LVL */
+#define WM8993_MICB1_LVL_SHIFT 0 /* MICB1_LVL */
+#define WM8993_MICB1_LVL_WIDTH 1 /* MICB1_LVL */
+
+/*
+ * R60 (0x3C) - FLL Control 1
+ */
+#define WM8993_FLL_FRAC 0x0004 /* FLL_FRAC */
+#define WM8993_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */
+#define WM8993_FLL_FRAC_SHIFT 2 /* FLL_FRAC */
+#define WM8993_FLL_FRAC_WIDTH 1 /* FLL_FRAC */
+#define WM8993_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
+#define WM8993_FLL_ENA 0x0001 /* FLL_ENA */
+#define WM8993_FLL_ENA_MASK 0x0001 /* FLL_ENA */
+#define WM8993_FLL_ENA_SHIFT 0 /* FLL_ENA */
+#define WM8993_FLL_ENA_WIDTH 1 /* FLL_ENA */
+
+/*
+ * R61 (0x3D) - FLL Control 2
+ */
+#define WM8993_FLL_OUTDIV_MASK 0x0700 /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */
+#define WM8993_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */
+#define WM8993_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */
+
+/*
+ * R62 (0x3E) - FLL Control 3
+ */
+#define WM8993_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */
+#define WM8993_FLL_K_SHIFT 0 /* FLL_K - [15:0] */
+#define WM8993_FLL_K_WIDTH 16 /* FLL_K - [15:0] */
+
+/*
+ * R63 (0x3F) - FLL Control 4
+ */
+#define WM8993_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */
+#define WM8993_FLL_N_SHIFT 5 /* FLL_N - [14:5] */
+#define WM8993_FLL_N_WIDTH 10 /* FLL_N - [14:5] */
+#define WM8993_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */
+#define WM8993_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */
+#define WM8993_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */
+
+/*
+ * R64 (0x40) - FLL Control 5
+ */
+#define WM8993_FLL_FRC_NCO_VAL_MASK 0x1F80 /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO_VAL_SHIFT 7 /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO 0x0040 /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_MASK 0x0040 /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_SHIFT 6 /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */
+#define WM8993_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_SRC_MASK 0x0003 /* FLL_CLK_SRC - [1:0] */
+#define WM8993_FLL_CLK_SRC_SHIFT 0 /* FLL_CLK_SRC - [1:0] */
+#define WM8993_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [1:0] */
+
+/*
+ * R65 (0x41) - Clocking 3
+ */
+#define WM8993_CLK_DCS_DIV_MASK 0x3C00 /* CLK_DCS_DIV - [13:10] */
+#define WM8993_CLK_DCS_DIV_SHIFT 10 /* CLK_DCS_DIV - [13:10] */
+#define WM8993_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [13:10] */
+#define WM8993_SAMPLE_RATE_MASK 0x0380 /* SAMPLE_RATE - [9:7] */
+#define WM8993_SAMPLE_RATE_SHIFT 7 /* SAMPLE_RATE - [9:7] */
+#define WM8993_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [9:7] */
+#define WM8993_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_DSP_ENA 0x0001 /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_MASK 0x0001 /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_SHIFT 0 /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */
+
+/*
+ * R66 (0x42) - Clocking 4
+ */
+#define WM8993_DAC_DIV4 0x0200 /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_MASK 0x0200 /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_SHIFT 9 /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_WIDTH 1 /* DAC_DIV4 */
+#define WM8993_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */
+#define WM8993_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */
+#define WM8993_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */
+#define WM8993_SR_MODE 0x0001 /* SR_MODE */
+#define WM8993_SR_MODE_MASK 0x0001 /* SR_MODE */
+#define WM8993_SR_MODE_SHIFT 0 /* SR_MODE */
+#define WM8993_SR_MODE_WIDTH 1 /* SR_MODE */
+
+/*
+ * R67 (0x43) - MW Slave Control
+ */
+#define WM8993_MASK_WRITE_ENA 0x0001 /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_MASK 0x0001 /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_ENA */
+
+/*
+ * R69 (0x45) - Bus Control 1
+ */
+#define WM8993_CLK_SYS_ENA 0x0002 /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_MASK 0x0002 /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_SHIFT 1 /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */
+
+/*
+ * R70 (0x46) - Write Sequencer 0
+ */
+#define WM8993_WSEQ_ENA 0x0100 /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
+#define WM8993_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8993_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8993_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R71 (0x47) - Write Sequencer 1
+ */
+#define WM8993_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
+#define WM8993_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
+#define WM8993_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R72 (0x48) - Write Sequencer 2
+ */
+#define WM8993_WSEQ_EOS 0x4000 /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
+#define WM8993_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
+#define WM8993_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
+#define WM8993_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
+
+/*
+ * R73 (0x49) - Write Sequencer 3
+ */
+#define WM8993_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
+#define WM8993_WSEQ_START 0x0100 /* WSEQ_START */
+#define WM8993_WSEQ_START_MASK 0x0100 /* WSEQ_START */
+#define WM8993_WSEQ_START_SHIFT 8 /* WSEQ_START */
+#define WM8993_WSEQ_START_WIDTH 1 /* WSEQ_START */
+#define WM8993_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
+#define WM8993_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
+#define WM8993_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R74 (0x4A) - Write Sequencer 4
+ */
+#define WM8993_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
+
+/*
+ * R75 (0x4B) - Write Sequencer 5
+ */
+#define WM8993_WSEQ_CURRENT_INDEX_MASK 0x003F /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM8993_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM8993_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [5:0] */
+
+/*
+ * R76 (0x4C) - Charge Pump 1
+ */
+#define WM8993_CP_ENA 0x8000 /* CP_ENA */
+#define WM8993_CP_ENA_MASK 0x8000 /* CP_ENA */
+#define WM8993_CP_ENA_SHIFT 15 /* CP_ENA */
+#define WM8993_CP_ENA_WIDTH 1 /* CP_ENA */
+
+/*
+ * R81 (0x51) - Class W 0
+ */
+#define WM8993_CP_DYN_FREQ 0x0002 /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_MASK 0x0002 /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_SHIFT 1 /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_WIDTH 1 /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_V 0x0001 /* CP_DYN_V */
+#define WM8993_CP_DYN_V_MASK 0x0001 /* CP_DYN_V */
+#define WM8993_CP_DYN_V_SHIFT 0 /* CP_DYN_V */
+#define WM8993_CP_DYN_V_WIDTH 1 /* CP_DYN_V */
+
+/*
+ * R84 (0x54) - DC Servo 0
+ */
+#define WM8993_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_DAC_WR_1 0x0008 /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_MASK 0x0008 /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_SHIFT 3 /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_0 0x0004 /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_MASK 0x0004 /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_SHIFT 2 /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */
+
+/*
+ * R85 (0x55) - DC Servo 1
+ */
+#define WM8993_DCS_SERIES_NO_01_MASK 0x0FE0 /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_SERIES_NO_01_SHIFT 5 /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8993_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8993_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R87 (0x57) - DC Servo 3
+ */
+#define WM8993_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8993_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8993_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R88 (0x58) - DC Servo Readback 0
+ */
+#define WM8993_DCS_DATAPATH_BUSY 0x4000 /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_MASK 0x4000 /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_SHIFT 14 /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_WIDTH 1 /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_CHANNEL_MASK 0x3000 /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CHANNEL_SHIFT 12 /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CHANNEL_WIDTH 2 /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CAL_COMPLETE_MASK 0x0300 /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_CAL_COMPLETE_WIDTH 2 /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_DAC_WR_COMPLETE_MASK 0x0030 /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_DAC_WR_COMPLETE_WIDTH 2 /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_STARTUP_COMPLETE_MASK 0x0003 /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM8993_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM8993_DCS_STARTUP_COMPLETE_WIDTH 2 /* DCS_STARTUP_COMPLETE - [1:0] */
+
+/*
+ * R89 (0x59) - DC Servo Readback 1
+ */
+#define WM8993_DCS_INTEG_CHAN_1_MASK 0x00FF /* DCS_INTEG_CHAN_1 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_1_SHIFT 0 /* DCS_INTEG_CHAN_1 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_1_WIDTH 8 /* DCS_INTEG_CHAN_1 - [7:0] */
+
+/*
+ * R90 (0x5A) - DC Servo Readback 2
+ */
+#define WM8993_DCS_INTEG_CHAN_0_MASK 0x00FF /* DCS_INTEG_CHAN_0 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_0_SHIFT 0 /* DCS_INTEG_CHAN_0 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_0_WIDTH 8 /* DCS_INTEG_CHAN_0 - [7:0] */
+
+/*
+ * R96 (0x60) - Analogue HP 0
+ */
+#define WM8993_HPOUT1_AUTO_PU 0x0100 /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_MASK 0x0100 /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_SHIFT 8 /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_WIDTH 1 /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */
+#define WM8993_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */
+
+/*
+ * R98 (0x62) - EQ1
+ */
+#define WM8993_EQ_ENA 0x0001 /* EQ_ENA */
+#define WM8993_EQ_ENA_MASK 0x0001 /* EQ_ENA */
+#define WM8993_EQ_ENA_SHIFT 0 /* EQ_ENA */
+#define WM8993_EQ_ENA_WIDTH 1 /* EQ_ENA */
+
+/*
+ * R99 (0x63) - EQ2
+ */
+#define WM8993_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */
+#define WM8993_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */
+#define WM8993_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */
+
+/*
+ * R100 (0x64) - EQ3
+ */
+#define WM8993_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */
+#define WM8993_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */
+#define WM8993_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */
+
+/*
+ * R101 (0x65) - EQ4
+ */
+#define WM8993_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */
+#define WM8993_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */
+#define WM8993_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */
+
+/*
+ * R102 (0x66) - EQ5
+ */
+#define WM8993_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */
+#define WM8993_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */
+#define WM8993_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */
+
+/*
+ * R103 (0x67) - EQ6
+ */
+#define WM8993_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */
+#define WM8993_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */
+#define WM8993_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */
+
+/*
+ * R104 (0x68) - EQ7
+ */
+#define WM8993_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */
+#define WM8993_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */
+#define WM8993_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */
+
+/*
+ * R105 (0x69) - EQ8
+ */
+#define WM8993_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */
+#define WM8993_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */
+#define WM8993_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */
+
+/*
+ * R106 (0x6A) - EQ9
+ */
+#define WM8993_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */
+#define WM8993_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */
+#define WM8993_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */
+
+/*
+ * R107 (0x6B) - EQ10
+ */
+#define WM8993_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */
+#define WM8993_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */
+#define WM8993_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */
+
+/*
+ * R108 (0x6C) - EQ11
+ */
+#define WM8993_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */
+#define WM8993_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */
+#define WM8993_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */
+
+/*
+ * R109 (0x6D) - EQ12
+ */
+#define WM8993_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */
+#define WM8993_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */
+#define WM8993_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */
+
+/*
+ * R110 (0x6E) - EQ13
+ */
+#define WM8993_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */
+#define WM8993_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */
+#define WM8993_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */
+
+/*
+ * R111 (0x6F) - EQ14
+ */
+#define WM8993_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */
+#define WM8993_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */
+#define WM8993_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */
+
+/*
+ * R112 (0x70) - EQ15
+ */
+#define WM8993_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */
+#define WM8993_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */
+#define WM8993_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */
+
+/*
+ * R113 (0x71) - EQ16
+ */
+#define WM8993_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */
+#define WM8993_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */
+#define WM8993_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */
+
+/*
+ * R114 (0x72) - EQ17
+ */
+#define WM8993_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */
+#define WM8993_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */
+#define WM8993_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */
+
+/*
+ * R115 (0x73) - EQ18
+ */
+#define WM8993_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */
+#define WM8993_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */
+#define WM8993_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */
+
+/*
+ * R116 (0x74) - EQ19
+ */
+#define WM8993_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */
+#define WM8993_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */
+#define WM8993_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */
+
+/*
+ * R117 (0x75) - EQ20
+ */
+#define WM8993_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */
+#define WM8993_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */
+#define WM8993_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */
+
+/*
+ * R118 (0x76) - EQ21
+ */
+#define WM8993_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */
+#define WM8993_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */
+#define WM8993_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */
+
+/*
+ * R119 (0x77) - EQ22
+ */
+#define WM8993_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */
+#define WM8993_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */
+#define WM8993_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */
+
+/*
+ * R120 (0x78) - EQ23
+ */
+#define WM8993_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */
+#define WM8993_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */
+#define WM8993_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */
+
+/*
+ * R121 (0x79) - EQ24
+ */
+#define WM8993_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */
+#define WM8993_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */
+#define WM8993_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */
+
+/*
+ * R122 (0x7A) - Digital Pulls
+ */
+#define WM8993_MCLK_PU 0x0080 /* MCLK_PU */
+#define WM8993_MCLK_PU_MASK 0x0080 /* MCLK_PU */
+#define WM8993_MCLK_PU_SHIFT 7 /* MCLK_PU */
+#define WM8993_MCLK_PU_WIDTH 1 /* MCLK_PU */
+#define WM8993_MCLK_PD 0x0040 /* MCLK_PD */
+#define WM8993_MCLK_PD_MASK 0x0040 /* MCLK_PD */
+#define WM8993_MCLK_PD_SHIFT 6 /* MCLK_PD */
+#define WM8993_MCLK_PD_WIDTH 1 /* MCLK_PD */
+#define WM8993_DACDAT_PU 0x0020 /* DACDAT_PU */
+#define WM8993_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */
+#define WM8993_DACDAT_PU_SHIFT 5 /* DACDAT_PU */
+#define WM8993_DACDAT_PU_WIDTH 1 /* DACDAT_PU */
+#define WM8993_DACDAT_PD 0x0010 /* DACDAT_PD */
+#define WM8993_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */
+#define WM8993_DACDAT_PD_SHIFT 4 /* DACDAT_PD */
+#define WM8993_DACDAT_PD_WIDTH 1 /* DACDAT_PD */
+#define WM8993_LRCLK_PU 0x0008 /* LRCLK_PU */
+#define WM8993_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */
+#define WM8993_LRCLK_PU_SHIFT 3 /* LRCLK_PU */
+#define WM8993_LRCLK_PU_WIDTH 1 /* LRCLK_PU */
+#define WM8993_LRCLK_PD 0x0004 /* LRCLK_PD */
+#define WM8993_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */
+#define WM8993_LRCLK_PD_SHIFT 2 /* LRCLK_PD */
+#define WM8993_LRCLK_PD_WIDTH 1 /* LRCLK_PD */
+#define WM8993_BCLK_PU 0x0002 /* BCLK_PU */
+#define WM8993_BCLK_PU_MASK 0x0002 /* BCLK_PU */
+#define WM8993_BCLK_PU_SHIFT 1 /* BCLK_PU */
+#define WM8993_BCLK_PU_WIDTH 1 /* BCLK_PU */
+#define WM8993_BCLK_PD 0x0001 /* BCLK_PD */
+#define WM8993_BCLK_PD_MASK 0x0001 /* BCLK_PD */
+#define WM8993_BCLK_PD_SHIFT 0 /* BCLK_PD */
+#define WM8993_BCLK_PD_WIDTH 1 /* BCLK_PD */
+
+/*
+ * R123 (0x7B) - DRC Control 1
+ */
+#define WM8993_DRC_ENA 0x8000 /* DRC_ENA */
+#define WM8993_DRC_ENA_MASK 0x8000 /* DRC_ENA */
+#define WM8993_DRC_ENA_SHIFT 15 /* DRC_ENA */
+#define WM8993_DRC_ENA_WIDTH 1 /* DRC_ENA */
+#define WM8993_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */
+#define WM8993_DRC_SMOOTH_ENA 0x0800 /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_MASK 0x0800 /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_SHIFT 11 /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_WIDTH 1 /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_QR_ENA 0x0400 /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_MASK 0x0400 /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_SHIFT 10 /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_WIDTH 1 /* DRC_QR_ENA */
+#define WM8993_DRC_ANTICLIP_ENA 0x0200 /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_MASK 0x0200 /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_SHIFT 9 /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_WIDTH 1 /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_HYST_ENA 0x0100 /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_MASK 0x0100 /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_SHIFT 8 /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_WIDTH 1 /* DRC_HYST_ENA */
+#define WM8993_DRC_THRESH_HYST_MASK 0x0030 /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_THRESH_HYST_SHIFT 4 /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_THRESH_HYST_WIDTH 2 /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
+#define WM8993_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
+#define WM8993_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R124 (0x7C) - DRC Control 2
+ */
+#define WM8993_DRC_ATTACK_RATE_MASK 0xF000 /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_ATTACK_RATE_SHIFT 12 /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_ATTACK_RATE_WIDTH 4 /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_DECAY_RATE_MASK 0x0F00 /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_DECAY_RATE_SHIFT 8 /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_DECAY_RATE_WIDTH 4 /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_THRESH_COMP_MASK 0x00FC /* DRC_THRESH_COMP - [7:2] */
+#define WM8993_DRC_THRESH_COMP_SHIFT 2 /* DRC_THRESH_COMP - [7:2] */
+#define WM8993_DRC_THRESH_COMP_WIDTH 6 /* DRC_THRESH_COMP - [7:2] */
+
+/*
+ * R125 (0x7D) - DRC Control 3
+ */
+#define WM8993_DRC_AMP_COMP_MASK 0xF800 /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_AMP_COMP_SHIFT 11 /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_AMP_COMP_WIDTH 5 /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_R0_SLOPE_COMP_MASK 0x0700 /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_R0_SLOPE_COMP_SHIFT 8 /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_R0_SLOPE_COMP_WIDTH 3 /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_FF_DELAY 0x0080 /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_MASK 0x0080 /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_SHIFT 7 /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */
+#define WM8993_DRC_THRESH_QR_MASK 0x000C /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_THRESH_QR_SHIFT 2 /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_THRESH_QR_WIDTH 2 /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_RATE_QR_MASK 0x0003 /* DRC_RATE_QR - [1:0] */
+#define WM8993_DRC_RATE_QR_SHIFT 0 /* DRC_RATE_QR - [1:0] */
+#define WM8993_DRC_RATE_QR_WIDTH 2 /* DRC_RATE_QR - [1:0] */
+
+/*
+ * R126 (0x7E) - DRC Control 4
+ */
+#define WM8993_DRC_R1_SLOPE_COMP_MASK 0xE000 /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_R1_SLOPE_COMP_SHIFT 13 /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_R1_SLOPE_COMP_WIDTH 3 /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_STARTUP_GAIN_MASK 0x1F00 /* DRC_STARTUP_GAIN - [12:8] */
+#define WM8993_DRC_STARTUP_GAIN_SHIFT 8 /* DRC_STARTUP_GAIN - [12:8] */
+#define WM8993_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [12:8] */
+
+#endif
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 86fc57e25f97..156f2a4a5930 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -707,6 +707,10 @@ static int configure_clock(struct snd_soc_codec *codec)
target > 3000000)
break;
}
+
+ if (i == ARRAY_SIZE(clk_sys_rates))
+ return -EINVAL;
+
} else if (wm9081->fs) {
for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
new_sysclk = clk_sys_rates[i].ratio
@@ -714,6 +718,10 @@ static int configure_clock(struct snd_soc_codec *codec)
if (new_sysclk > 3000000)
break;
}
+
+ if (i == ARRAY_SIZE(clk_sys_rates))
+ return -EINVAL;
+
} else {
new_sysclk = 12288000;
}
@@ -1492,6 +1500,21 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&client->dev);
+}
+
+static int wm9081_i2c_resume(struct i2c_client *client)
+{
+ return snd_soc_resume_device(&client->dev);
+}
+#else
+#define wm9081_i2c_suspend NULL
+#define wm9081_i2c_resume NULL
+#endif
+
static const struct i2c_device_id wm9081_i2c_id[] = {
{ "wm9081", 0 },
{ }
@@ -1505,6 +1528,8 @@ static struct i2c_driver wm9081_i2c_driver = {
},
.probe = wm9081_i2c_probe,
.remove = __devexit_p(wm9081_i2c_remove),
+ .suspend = wm9081_i2c_suspend,
+ .resume = wm9081_i2c_resume,
.id_table = wm9081_i2c_id,
};
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 411a710be660..6802dd5e4731 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -9,6 +9,9 @@ config SND_DAVINCI_SOC
config SND_DAVINCI_SOC_I2S
tristate
+config SND_DAVINCI_SOC_MCASP
+ tristate
+
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM"
depends on SND_DAVINCI_SOC
@@ -19,6 +22,16 @@ config SND_DAVINCI_SOC_EVM
Say Y if you want to add support for SoC audio on TI
DaVinci DM6446 or DM355 EVM platforms.
+config SND_DM6467_SOC_EVM
+ tristate "SoC Audio support for DaVinci DM6467 EVM"
+ depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
+ select SND_DAVINCI_SOC_MCASP
+ select SND_SOC_TLV320AIC3X
+ select SND_SOC_SPDIF
+
+ help
+ Say Y if you want to add support for SoC audio on TI
+
config SND_DAVINCI_SOC_SFFSDR
tristate "SoC Audio support for SFFSDR"
depends on SND_DAVINCI_SOC && MACH_SFFSDR
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index ca8bae1fc3f6..67be54f3a3a5 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -1,13 +1,16 @@
# DAVINCI Platform Support
snd-soc-davinci-objs := davinci-pcm.o
snd-soc-davinci-i2s-objs := davinci-i2s.o
+snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
+obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
# DAVINCI Machine Support
snd-soc-evm-objs := davinci-evm.o
snd-soc-sffsdr-objs := davinci-sffsdr.o
obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 58fd1cbedd88..f3bb6f60f205 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -27,9 +27,10 @@
#include <mach/mux.h>
#include "../codecs/tlv320aic3x.h"
+#include "../codecs/spdif_transciever.h"
#include "davinci-pcm.h"
#include "davinci-i2s.h"
-
+#include "davinci-mcasp.h"
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -43,7 +44,7 @@ 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())
+ if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm())
sysclk = 27000000;
/* ASP0 in DM6446 EVM is clocked by U55, as configured by
@@ -144,6 +145,24 @@ static struct snd_soc_dai_link evm_dai = {
.ops = &evm_ops,
};
+static struct snd_soc_dai_link dm6467_evm_dai[] = {
+ {
+ .name = "TLV320AIC3X",
+ .stream_name = "AIC3X",
+ .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
+ .codec_dai = &aic3x_dai,
+ .init = evm_aic3x_init,
+ .ops = &evm_ops,
+ },
+ {
+ .name = "McASP",
+ .stream_name = "spdif",
+ .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
+ .codec_dai = &dit_stub_dai,
+ .ops = &evm_ops,
+ },
+};
+
/* davinci-evm audio machine driver */
static struct snd_soc_card snd_soc_card_evm = {
.name = "DaVinci EVM",
@@ -152,12 +171,26 @@ static struct snd_soc_card snd_soc_card_evm = {
.num_links = 1,
};
+/* davinci dm6467 evm audio machine driver */
+static struct snd_soc_card dm6467_snd_soc_card_evm = {
+ .name = "DaVinci DM6467 EVM",
+ .platform = &davinci_soc_platform,
+ .dai_link = dm6467_evm_dai,
+ .num_links = ARRAY_SIZE(dm6467_evm_dai),
+};
+
/* evm audio private data */
static struct aic3x_setup_data evm_aic3x_setup = {
.i2c_bus = 1,
.i2c_address = 0x1b,
};
+/* dm6467 evm audio private data */
+static struct aic3x_setup_data dm6467_evm_aic3x_setup = {
+ .i2c_bus = 1,
+ .i2c_address = 0x18,
+};
+
/* evm audio subsystem */
static struct snd_soc_device evm_snd_devdata = {
.card = &snd_soc_card_evm,
@@ -165,60 +198,30 @@ static struct snd_soc_device evm_snd_devdata = {
.codec_data = &evm_aic3x_setup,
};
-/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */
-static struct resource evm_snd_resources[] = {
- {
- .start = DAVINCI_ASP0_BASE,
- .end = DAVINCI_ASP0_BASE + SZ_8K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct evm_snd_platform_data evm_snd_data = {
- .tx_dma_ch = DAVINCI_DMA_ASP0_TX,
- .rx_dma_ch = DAVINCI_DMA_ASP0_RX,
-};
-
-/* DM335 EVM uses ASP1; line-out is a stereo mini-jack */
-static struct resource dm335evm_snd_resources[] = {
- {
- .start = DAVINCI_ASP1_BASE,
- .end = DAVINCI_ASP1_BASE + SZ_8K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct evm_snd_platform_data dm335evm_snd_data = {
- .tx_dma_ch = DAVINCI_DMA_ASP1_TX,
- .rx_dma_ch = DAVINCI_DMA_ASP1_RX,
+/* evm audio subsystem */
+static struct snd_soc_device dm6467_evm_snd_devdata = {
+ .card = &dm6467_snd_soc_card_evm,
+ .codec_dev = &soc_codec_dev_aic3x,
+ .codec_data = &dm6467_evm_aic3x_setup,
};
static struct platform_device *evm_snd_device;
static int __init evm_init(void)
{
- struct resource *resources;
- unsigned num_resources;
- struct evm_snd_platform_data *data;
+ struct snd_soc_device *evm_snd_dev_data;
int index;
int ret;
if (machine_is_davinci_evm()) {
- davinci_cfg_reg(DM644X_MCBSP);
-
- resources = evm_snd_resources;
- num_resources = ARRAY_SIZE(evm_snd_resources);
- data = &evm_snd_data;
+ evm_snd_dev_data = &evm_snd_devdata;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
- /* we don't use ASP1 IRQs, or we'd need to mux them ... */
- davinci_cfg_reg(DM355_EVT8_ASP1_TX);
- davinci_cfg_reg(DM355_EVT9_ASP1_RX);
-
- resources = dm335evm_snd_resources;
- num_resources = ARRAY_SIZE(dm335evm_snd_resources);
- data = &dm335evm_snd_data;
+ evm_snd_dev_data = &evm_snd_devdata;
index = 1;
+ } else if (machine_is_davinci_dm6467_evm()) {
+ evm_snd_dev_data = &dm6467_evm_snd_devdata;
+ index = 0;
} else
return -EINVAL;
@@ -226,17 +229,8 @@ static int __init evm_init(void)
if (!evm_snd_device)
return -ENOMEM;
- platform_set_drvdata(evm_snd_device, &evm_snd_devdata);
- evm_snd_devdata.dev = &evm_snd_device->dev;
- platform_device_add_data(evm_snd_device, data, sizeof(*data));
-
- ret = platform_device_add_resources(evm_snd_device, resources,
- num_resources);
- if (ret) {
- platform_device_put(evm_snd_device);
- return ret;
- }
-
+ platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
+ evm_snd_dev_data->dev = &evm_snd_device->dev;
ret = platform_device_add(evm_snd_device);
if (ret)
platform_device_put(evm_snd_device);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index b1ea52fc83c7..e5cd97b74c50 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -22,6 +22,8 @@
#include <sound/initval.h>
#include <sound/soc.h>
+#include <mach/asp.h>
+
#include "davinci-pcm.h"
@@ -63,6 +65,7 @@
#define DAVINCI_MCBSP_RCR_RWDLEN1(v) ((v) << 5)
#define DAVINCI_MCBSP_RCR_RFRLEN1(v) ((v) << 8)
#define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16)
+#define DAVINCI_MCBSP_RCR_RFIG (1 << 18)
#define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21)
#define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5)
@@ -85,14 +88,6 @@
#define DAVINCI_MCBSP_PCR_FSRM (1 << 10)
#define DAVINCI_MCBSP_PCR_FSXM (1 << 11)
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) { \
- val |= mask; \
- } else { \
- val &= ~mask; \
- } \
-} while (0)
-
enum {
DAVINCI_MCBSP_WORD_8 = 0,
DAVINCI_MCBSP_WORD_12,
@@ -112,6 +107,10 @@ static struct davinci_pcm_dma_params davinci_i2s_pcm_in = {
struct davinci_mcbsp_dev {
void __iomem *base;
+#define MOD_DSP_A 0
+#define MOD_DSP_B 1
+ int mode;
+ u32 pcr;
struct clk *clk;
struct davinci_pcm_dma_params *dma_params[2];
};
@@ -127,96 +126,100 @@ static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
return __raw_readl(dev->base + reg);
}
-static void davinci_mcbsp_start(struct snd_pcm_substream *substream)
+static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
+{
+ u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
+ /* The clock needs to toggle to complete reset.
+ * So, fake it by toggling the clk polarity.
+ */
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
+}
+
+static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
+ struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_platform *platform = socdev->card->platform;
- u32 w;
- int ret;
-
- /* Start the sample generator and enable transmitter/receiver */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ u32 spcr;
+ u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ if (spcr & mask) {
+ /* start off disabled */
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
+ spcr & ~mask);
+ toggle_clock(dev, playback);
+ }
+ if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM |
+ DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) {
+ /* Start the sample generator */
+ spcr |= DAVINCI_MCBSP_SPCR_GRST;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+ }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (playback) {
/* Stop the DMA to avoid data loss */
/* while the transmitter is out of reset to handle XSYNCERR */
if (platform->pcm_ops->trigger) {
- ret = platform->pcm_ops->trigger(substream,
+ int ret = platform->pcm_ops->trigger(substream,
SNDRV_PCM_TRIGGER_STOP);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA stop failed\n");
}
/* Enable the transmitter */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ spcr |= DAVINCI_MCBSP_SPCR_XRST;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
/* wait for any unexpected frame sync error to occur */
udelay(100);
/* Disable the transmitter to clear any outstanding XSYNCERR */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+ toggle_clock(dev, playback);
/* Restart the DMA */
if (platform->pcm_ops->trigger) {
- ret = platform->pcm_ops->trigger(substream,
+ int ret = platform->pcm_ops->trigger(substream,
SNDRV_PCM_TRIGGER_START);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA start failed\n");
}
- /* Enable the transmitter */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
-
- } else {
-
- /* Enable the reciever */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
}
+ /* Enable transmitter or receiver */
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ spcr |= mask;
- /* Start frame sync */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_FRST, 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) {
+ /* Start frame sync */
+ spcr |= DAVINCI_MCBSP_SPCR_FRST;
+ }
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
}
-static void davinci_mcbsp_stop(struct snd_pcm_substream *substream)
+static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
- u32 w;
+ u32 spcr;
/* Reset transmitter/receiver and sample rate/frame sync generators */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST |
- DAVINCI_MCBSP_SPCR_FRST, 0);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
- else
- MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 0);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
+ spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+ toggle_clock(dev, playback);
}
static int davinci_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
-
+ struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
cpu_dai->dma_data = dev->dma_params[substream->stream];
-
return 0;
}
@@ -228,12 +231,11 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
unsigned int pcr;
unsigned int srgr;
- unsigned int rcr;
- unsigned int xcr;
srgr = DAVINCI_MCBSP_SRGR_FSGM |
DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
+ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* cpu is master */
@@ -258,11 +260,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1);
- xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1);
+ /* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_B:
- break;
case SND_SOC_DAIFMT_I2S:
/* Davinci doesn't support TRUE I2S, but some codecs will have
* the left and right channels contiguous. This allows
@@ -282,8 +281,10 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
*/
fmt ^= SND_SOC_DAIFMT_NB_IF;
case SND_SOC_DAIFMT_DSP_A:
- rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
- xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+ dev->mode = MOD_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ dev->mode = MOD_DSP_B;
break;
default:
printk(KERN_ERR "%s:bad format\n", __func__);
@@ -343,9 +344,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+ dev->pcr = pcr;
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
return 0;
}
@@ -358,26 +358,36 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
struct snd_interval *i = NULL;
int mcbsp_word_length;
- u32 w;
+ unsigned int rcr, xcr, srgr;
+ u32 spcr;
/* general line settings */
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
} else {
- w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+ spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
}
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
- w = DAVINCI_MCBSP_SRGR_FSGM;
- MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1);
+ srgr = DAVINCI_MCBSP_SRGR_FSGM;
+ srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
- MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w);
+ srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+ rcr = DAVINCI_MCBSP_RCR_RFIG;
+ xcr = DAVINCI_MCBSP_XCR_XFIG;
+ if (dev->mode == MOD_DSP_B) {
+ rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
+ xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
+ } else {
+ rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
+ xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+ }
/* Determine xfer data type */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -397,18 +407,31 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
- DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w);
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1);
- } else {
- w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
- MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
- DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w);
+ rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
+ DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
+ xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
+ DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
+ else
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+ return 0;
+}
+
+static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ davinci_mcbsp_stop(dev, playback);
+ if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
+ /* codec is master */
+ davinci_mcbsp_start(dev, substream);
}
return 0;
}
@@ -416,35 +439,74 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
int ret = 0;
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
+ return 0; /* return if codec is master */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- davinci_mcbsp_start(substream);
+ davinci_mcbsp_start(dev, substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- davinci_mcbsp_stop(substream);
+ davinci_mcbsp_stop(dev, playback);
break;
default:
ret = -EINVAL;
}
-
return ret;
}
-static int davinci_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ davinci_mcbsp_stop(dev, playback);
+}
+
+#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
+
+static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+ .startup = davinci_i2s_startup,
+ .shutdown = davinci_i2s_shutdown,
+ .prepare = davinci_i2s_prepare,
+ .trigger = davinci_i2s_trigger,
+ .hw_params = davinci_i2s_hw_params,
+ .set_fmt = davinci_i2s_set_dai_fmt,
+
+};
+
+struct snd_soc_dai davinci_i2s_dai = {
+ .name = "davinci-i2s",
+ .id = 0,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &davinci_i2s_dai_ops,
+
+};
+EXPORT_SYMBOL_GPL(davinci_i2s_dai);
+
+static int davinci_i2s_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
+ struct snd_platform_data *pdata = pdev->dev.platform_data;
struct davinci_mcbsp_dev *dev;
- struct resource *mem, *ioarea;
- struct evm_snd_platform_data *pdata;
+ struct resource *mem, *ioarea, *res;
int ret;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -466,8 +528,6 @@ static int davinci_i2s_probe(struct platform_device *pdev,
goto err_release_region;
}
- cpu_dai->private_data = dev;
-
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = -ENODEV;
@@ -476,18 +536,37 @@ static int davinci_i2s_probe(struct platform_device *pdev,
clk_enable(dev->clk);
dev->base = (void __iomem *)IO_ADDRESS(mem->start);
- pdata = pdev->dev.platform_data;
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out;
- dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = pdata->tx_dma_ch;
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr =
(dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG);
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in;
- dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = pdata->rx_dma_ch;
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr =
(dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG);
+ /* first TX, then RX */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENXIO;
+ goto err_free_mem;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENXIO;
+ goto err_free_mem;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = res->start;
+
+ davinci_i2s_dai.private_data = dev;
+ ret = snd_soc_register_dai(&davinci_i2s_dai);
+ if (ret != 0)
+ goto err_free_mem;
+
return 0;
err_free_mem:
@@ -498,62 +577,40 @@ err_release_region:
return ret;
}
-static void davinci_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int davinci_i2s_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
struct resource *mem;
+ snd_soc_unregister_dai(&davinci_i2s_dai);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
-
kfree(dev);
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, (mem->end - mem->start) + 1);
-}
-
-#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
-static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
- .startup = davinci_i2s_startup,
- .trigger = davinci_i2s_trigger,
- .hw_params = davinci_i2s_hw_params,
- .set_fmt = davinci_i2s_set_dai_fmt,
-};
+ return 0;
+}
-struct snd_soc_dai davinci_i2s_dai = {
- .name = "davinci-i2s",
- .id = 0,
- .probe = davinci_i2s_probe,
- .remove = davinci_i2s_remove,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = DAVINCI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = DAVINCI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &davinci_i2s_dai_ops,
+static struct platform_driver davinci_mcbsp_driver = {
+ .probe = davinci_i2s_probe,
+ .remove = davinci_i2s_remove,
+ .driver = {
+ .name = "davinci-asp",
+ .owner = THIS_MODULE,
+ },
};
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
static int __init davinci_i2s_init(void)
{
- return snd_soc_register_dai(&davinci_i2s_dai);
+ return platform_driver_register(&davinci_mcbsp_driver);
}
module_init(davinci_i2s_init);
static void __exit davinci_i2s_exit(void)
{
- snd_soc_unregister_dai(&davinci_i2s_dai);
+ platform_driver_unregister(&davinci_mcbsp_driver);
}
module_exit(davinci_i2s_exit);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
new file mode 100644
index 000000000000..f0c034771062
--- /dev/null
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -0,0 +1,874 @@
+/*
+ * ALSA SoC McASP Audio Layer for TI DAVINCI processor
+ *
+ * Multi-channel Audio Serial Port Driver
+ *
+ * Author: Nirmal Pandey <n-pandey@ti.com>,
+ * Suresh Rajashekara <suresh.r@ti.com>
+ * Steve Chen <schen@.mvista.com>
+ *
+ * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright: (C) 2009 Texas Instruments, India
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "davinci-pcm.h"
+#include "davinci-mcasp.h"
+
+/*
+ * McASP register definitions
+ */
+#define DAVINCI_MCASP_PID_REG 0x00
+#define DAVINCI_MCASP_PWREMUMGT_REG 0x04
+
+#define DAVINCI_MCASP_PFUNC_REG 0x10
+#define DAVINCI_MCASP_PDIR_REG 0x14
+#define DAVINCI_MCASP_PDOUT_REG 0x18
+#define DAVINCI_MCASP_PDSET_REG 0x1c
+
+#define DAVINCI_MCASP_PDCLR_REG 0x20
+
+#define DAVINCI_MCASP_TLGC_REG 0x30
+#define DAVINCI_MCASP_TLMR_REG 0x34
+
+#define DAVINCI_MCASP_GBLCTL_REG 0x44
+#define DAVINCI_MCASP_AMUTE_REG 0x48
+#define DAVINCI_MCASP_LBCTL_REG 0x4c
+
+#define DAVINCI_MCASP_TXDITCTL_REG 0x50
+
+#define DAVINCI_MCASP_GBLCTLR_REG 0x60
+#define DAVINCI_MCASP_RXMASK_REG 0x64
+#define DAVINCI_MCASP_RXFMT_REG 0x68
+#define DAVINCI_MCASP_RXFMCTL_REG 0x6c
+
+#define DAVINCI_MCASP_ACLKRCTL_REG 0x70
+#define DAVINCI_MCASP_AHCLKRCTL_REG 0x74
+#define DAVINCI_MCASP_RXTDM_REG 0x78
+#define DAVINCI_MCASP_EVTCTLR_REG 0x7c
+
+#define DAVINCI_MCASP_RXSTAT_REG 0x80
+#define DAVINCI_MCASP_RXTDMSLOT_REG 0x84
+#define DAVINCI_MCASP_RXCLKCHK_REG 0x88
+#define DAVINCI_MCASP_REVTCTL_REG 0x8c
+
+#define DAVINCI_MCASP_GBLCTLX_REG 0xa0
+#define DAVINCI_MCASP_TXMASK_REG 0xa4
+#define DAVINCI_MCASP_TXFMT_REG 0xa8
+#define DAVINCI_MCASP_TXFMCTL_REG 0xac
+
+#define DAVINCI_MCASP_ACLKXCTL_REG 0xb0
+#define DAVINCI_MCASP_AHCLKXCTL_REG 0xb4
+#define DAVINCI_MCASP_TXTDM_REG 0xb8
+#define DAVINCI_MCASP_EVTCTLX_REG 0xbc
+
+#define DAVINCI_MCASP_TXSTAT_REG 0xc0
+#define DAVINCI_MCASP_TXTDMSLOT_REG 0xc4
+#define DAVINCI_MCASP_TXCLKCHK_REG 0xc8
+#define DAVINCI_MCASP_XEVTCTL_REG 0xcc
+
+/* Left(even TDM Slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRA_REG 0x100
+/* Right(odd TDM slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRB_REG 0x118
+/* Left(even TDM slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRA_REG 0x130
+/* Right(odd TDM Slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRB_REG 0x148
+
+/* Serializer n Control Register */
+#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
+#define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
+ (n << 2))
+
+/* Transmit Buffer for Serializer n */
+#define DAVINCI_MCASP_TXBUF_REG 0x200
+/* Receive Buffer for Serializer n */
+#define DAVINCI_MCASP_RXBUF_REG 0x280
+
+
+/*
+ * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
+ * Register Bits
+ */
+#define MCASP_FREE BIT(0)
+#define MCASP_SOFT BIT(1)
+
+/*
+ * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
+ */
+#define AXR(n) (1<<n)
+#define PFUNC_AMUTE BIT(25)
+#define ACLKX BIT(26)
+#define AHCLKX BIT(27)
+#define AFSX BIT(28)
+#define ACLKR BIT(29)
+#define AHCLKR BIT(30)
+#define AFSR BIT(31)
+
+/*
+ * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ */
+#define AXR(n) (1<<n)
+#define PDIR_AMUTE BIT(25)
+#define ACLKX BIT(26)
+#define AHCLKX BIT(27)
+#define AFSX BIT(28)
+#define ACLKR BIT(29)
+#define AHCLKR BIT(30)
+#define AFSR BIT(31)
+
+/*
+ * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
+ */
+#define DITEN BIT(0) /* Transmit DIT mode enable/disable */
+#define VA BIT(2)
+#define VB BIT(3)
+
+/*
+ * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
+ */
+#define TXROT(val) (val)
+#define TXSEL BIT(3)
+#define TXSSZ(val) (val<<4)
+#define TXPBIT(val) (val<<8)
+#define TXPAD(val) (val<<13)
+#define TXORD BIT(15)
+#define FSXDLY(val) (val<<16)
+
+/*
+ * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
+ */
+#define RXROT(val) (val)
+#define RXSEL BIT(3)
+#define RXSSZ(val) (val<<4)
+#define RXPBIT(val) (val<<8)
+#define RXPAD(val) (val<<13)
+#define RXORD BIT(15)
+#define FSRDLY(val) (val<<16)
+
+/*
+ * DAVINCI_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits
+ */
+#define FSXPOL BIT(0)
+#define AFSXE BIT(1)
+#define FSXDUR BIT(4)
+#define FSXMOD(val) (val<<7)
+
+/*
+ * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
+ */
+#define FSRPOL BIT(0)
+#define AFSRE BIT(1)
+#define FSRDUR BIT(4)
+#define FSRMOD(val) (val<<7)
+
+/*
+ * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
+ */
+#define ACLKXDIV(val) (val)
+#define ACLKXE BIT(5)
+#define TX_ASYNC BIT(6)
+#define ACLKXPOL BIT(7)
+
+/*
+ * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
+ */
+#define ACLKRDIV(val) (val)
+#define ACLKRE BIT(5)
+#define RX_ASYNC BIT(6)
+#define ACLKRPOL BIT(7)
+
+/*
+ * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
+ * Register Bits
+ */
+#define AHCLKXDIV(val) (val)
+#define AHCLKXPOL BIT(14)
+#define AHCLKXE BIT(15)
+
+/*
+ * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
+ * Register Bits
+ */
+#define AHCLKRDIV(val) (val)
+#define AHCLKRPOL BIT(14)
+#define AHCLKRE BIT(15)
+
+/*
+ * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits
+ */
+#define MODE(val) (val)
+#define DISMOD (val)(val<<2)
+#define TXSTATE BIT(4)
+#define RXSTATE BIT(5)
+
+/*
+ * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
+ */
+#define LBEN BIT(0)
+#define LBORD BIT(1)
+#define LBGENMODE(val) (val<<2)
+
+/*
+ * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
+ */
+#define TXTDMS(n) (1<<n)
+
+/*
+ * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
+ */
+#define RXTDMS(n) (1<<n)
+
+/*
+ * DAVINCI_MCASP_GBLCTL_REG - Global Control Register Bits
+ */
+#define RXCLKRST BIT(0) /* Receiver Clock Divider Reset */
+#define RXHCLKRST BIT(1) /* Receiver High Frequency Clock Divider */
+#define RXSERCLR BIT(2) /* Receiver Serializer Clear */
+#define RXSMRST BIT(3) /* Receiver State Machine Reset */
+#define RXFSRST BIT(4) /* Frame Sync Generator Reset */
+#define TXCLKRST BIT(8) /* Transmitter Clock Divider Reset */
+#define TXHCLKRST BIT(9) /* Transmitter High Frequency Clock Divider*/
+#define TXSERCLR BIT(10) /* Transmit Serializer Clear */
+#define TXSMRST BIT(11) /* Transmitter State Machine Reset */
+#define TXFSRST BIT(12) /* Frame Sync Generator Reset */
+
+/*
+ * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits
+ */
+#define MUTENA(val) (val)
+#define MUTEINPOL BIT(2)
+#define MUTEINENA BIT(3)
+#define MUTEIN BIT(4)
+#define MUTER BIT(5)
+#define MUTEX BIT(6)
+#define MUTEFSR BIT(7)
+#define MUTEFSX BIT(8)
+#define MUTEBADCLKR BIT(9)
+#define MUTEBADCLKX BIT(10)
+#define MUTERXDMAERR BIT(11)
+#define MUTETXDMAERR BIT(12)
+
+/*
+ * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
+ */
+#define RXDATADMADIS BIT(0)
+
+/*
+ * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
+ */
+#define TXDATADMADIS BIT(0)
+
+#define DAVINCI_MCASP_NUM_SERIALIZER 16
+
+static inline void mcasp_set_bits(void __iomem *reg, u32 val)
+{
+ __raw_writel(__raw_readl(reg) | val, reg);
+}
+
+static inline void mcasp_clr_bits(void __iomem *reg, u32 val)
+{
+ __raw_writel((__raw_readl(reg) & ~(val)), reg);
+}
+
+static inline void mcasp_mod_bits(void __iomem *reg, u32 val, u32 mask)
+{
+ __raw_writel((__raw_readl(reg) & ~mask) | val, reg);
+}
+
+static inline void mcasp_set_reg(void __iomem *reg, u32 val)
+{
+ __raw_writel(val, reg);
+}
+
+static inline u32 mcasp_get_reg(void __iomem *reg)
+{
+ return (unsigned int)__raw_readl(reg);
+}
+
+static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
+{
+ int i = 0;
+
+ mcasp_set_bits(regs, val);
+
+ /* programming GBLCTL needs to read back from GBLCTL and verfiy */
+ /* loop count is to avoid the lock-up */
+ for (i = 0; i < 1000; i++) {
+ if ((mcasp_get_reg(regs) & val) == val)
+ break;
+ }
+
+ if (i == 1000 && ((mcasp_get_reg(regs) & val) != val))
+ printk(KERN_ERR "GBLCTL write error\n");
+}
+
+static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_audio_dev *dev = cpu_dai->private_data;
+ cpu_dai->dma_data = dev->dma_params[substream->stream];
+ return 0;
+}
+
+static void mcasp_start_rx(struct davinci_audio_dev *dev)
+{
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+}
+
+static void mcasp_start_tx(struct davinci_audio_dev *dev)
+{
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+ mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+}
+
+static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
+{
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mcasp_start_tx(dev);
+ else
+ mcasp_start_rx(dev);
+}
+
+static void mcasp_stop_rx(struct davinci_audio_dev *dev)
+{
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+}
+
+static void mcasp_stop_tx(struct davinci_audio_dev *dev)
+{
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+}
+
+static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
+{
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mcasp_stop_tx(dev);
+ else
+ mcasp_stop_rx(dev);
+}
+
+static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct davinci_audio_dev *dev = cpu_dai->private_data;
+ void __iomem *base = dev->base;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* codec is clock and frame slave */
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+ mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+ mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+ mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26));
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* codec is clock and frame master */
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+ mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+ mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+ mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_NF:
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ break;
+
+ case SND_SOC_DAIFMT_IB_IF:
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ break;
+
+ case SND_SOC_DAIFMT_NB_NF:
+ mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+
+ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int davinci_config_channel_size(struct davinci_audio_dev *dev,
+ int channel_size)
+{
+ u32 fmt = 0;
+
+ switch (channel_size) {
+ case DAVINCI_AUDIO_WORD_8:
+ fmt = 0x03;
+ break;
+
+ case DAVINCI_AUDIO_WORD_12:
+ fmt = 0x05;
+ break;
+
+ case DAVINCI_AUDIO_WORD_16:
+ fmt = 0x07;
+ break;
+
+ case DAVINCI_AUDIO_WORD_20:
+ fmt = 0x09;
+ break;
+
+ case DAVINCI_AUDIO_WORD_24:
+ fmt = 0x0B;
+ break;
+
+ case DAVINCI_AUDIO_WORD_28:
+ fmt = 0x0D;
+ break;
+
+ case DAVINCI_AUDIO_WORD_32:
+ fmt = 0x0F;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+ RXSSZ(fmt), RXSSZ(0x0F));
+ mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+ TXSSZ(fmt), TXSSZ(0x0F));
+ return 0;
+}
+
+static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
+{
+ int i;
+
+ /* Default configuration */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
+
+ /* All PINS as McASP */
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG,
+ TXDATADMADIS);
+ } else {
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_REVTCTL_REG,
+ RXDATADMADIS);
+ }
+
+ for (i = 0; i < dev->num_serializer; i++) {
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
+ dev->serial_dir[i]);
+ if (dev->serial_dir[i] == TX_MODE)
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
+ AXR(i));
+ else if (dev->serial_dir[i] == RX_MODE)
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
+ AXR(i));
+ }
+}
+
+static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
+{
+ int i, active_slots;
+ u32 mask = 0;
+
+ active_slots = (dev->tdm_slots > 31) ? 32 : dev->tdm_slots;
+ for (i = 0; i < active_slots; i++)
+ mask |= (1 << i);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* bit stream is MSB first with no delay */
+ /* DSP_B mode */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG,
+ AHCLKXE);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask);
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD);
+
+ if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
+ mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(dev->tdm_slots), FSXMOD(0x1FF));
+ else
+ printk(KERN_ERR "playback tdm slot %d not supported\n",
+ dev->tdm_slots);
+
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ } else {
+ /* bit stream is MSB first with no delay */
+ /* DSP_B mode */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD);
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
+ AHCLKRE);
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask);
+
+ if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32))
+ mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG,
+ FSRMOD(dev->tdm_slots), FSRMOD(0x1FF));
+ else
+ printk(KERN_ERR "capture tdm slot %d not supported\n",
+ dev->tdm_slots);
+
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ }
+}
+
+/* S/PDIF */
+static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
+{
+ /* Set the PDIR for Serialiser as output */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
+
+ /* TXMASK for 24 bits */
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
+
+ /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
+ and LSB first */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+ TXROT(6) | TXSSZ(15));
+
+ /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
+ AFSXE | FSXMOD(0x180));
+
+ /* Set the TX tdm : for all the slots */
+ mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
+
+ /* Set the TX clock controls : div = 1 and internal */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
+ ACLKXE | TX_ASYNC);
+
+ mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+
+ /* Only 44100 and 48000 are valid, both have the same setting */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
+
+ /* Enable the DIT */
+ mcasp_set_bits(dev->base + DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+}
+
+static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_audio_dev *dev = cpu_dai->private_data;
+ struct davinci_pcm_dma_params *dma_params =
+ dev->dma_params[substream->stream];
+ int word_length;
+
+ davinci_hw_common_param(dev, substream->stream);
+
+ if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
+ davinci_hw_dit_param(dev);
+ else
+ davinci_hw_param(dev, substream->stream);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ dma_params->data_type = 1;
+ word_length = DAVINCI_AUDIO_WORD_8;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dma_params->data_type = 2;
+ word_length = DAVINCI_AUDIO_WORD_16;
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dma_params->data_type = 4;
+ word_length = DAVINCI_AUDIO_WORD_32;
+ break;
+
+ default:
+ printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
+ return -EINVAL;
+ }
+ davinci_config_channel_size(dev, word_length);
+
+ return 0;
+}
+
+static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ davinci_mcasp_start(dev, substream->stream);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ davinci_mcasp_stop(dev, substream->stream);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+ .startup = davinci_mcasp_startup,
+ .trigger = davinci_mcasp_trigger,
+ .hw_params = davinci_mcasp_hw_params,
+ .set_fmt = davinci_mcasp_set_dai_fmt,
+
+};
+
+struct snd_soc_dai davinci_mcasp_dai[] = {
+ {
+ .name = "davinci-i2s",
+ .id = 0,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_MCASP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_MCASP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &davinci_mcasp_dai_ops,
+
+ },
+ {
+ .name = "davinci-dit",
+ .id = 1,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 384,
+ .rates = DAVINCI_MCASP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &davinci_mcasp_dai_ops,
+ },
+
+};
+EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
+
+static int davinci_mcasp_probe(struct platform_device *pdev)
+{
+ struct davinci_pcm_dma_params *dma_data;
+ struct resource *mem, *ioarea, *res;
+ struct snd_platform_data *pdata;
+ struct davinci_audio_dev *dev;
+ int count = 0;
+ int ret = 0;
+
+ dev = kzalloc(sizeof(struct davinci_audio_dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dma_data = kzalloc(sizeof(struct davinci_pcm_dma_params) * 2,
+ GFP_KERNEL);
+ if (!dma_data) {
+ ret = -ENOMEM;
+ goto err_release_dev;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ ret = -ENODEV;
+ goto err_release_data;
+ }
+
+ ioarea = request_mem_region(mem->start,
+ (mem->end - mem->start) + 1, pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "Audio region already claimed\n");
+ ret = -EBUSY;
+ goto err_release_data;
+ }
+
+ pdata = pdev->dev.platform_data;
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ ret = -ENODEV;
+ goto err_release_region;
+ }
+
+ clk_enable(dev->clk);
+
+ dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+ dev->op_mode = pdata->op_mode;
+ dev->tdm_slots = pdata->tdm_slots;
+ dev->num_serializer = pdata->num_serializer;
+ dev->serial_dir = pdata->serial_dir;
+ dev->codec_fmt = pdata->codec_fmt;
+
+ dma_data[count].name = "I2S PCM Stereo out";
+ dma_data[count].eventq_no = pdata->eventq_no;
+ dma_data[count].dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
+ io_v2p(dev->base));
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &dma_data[count];
+
+ /* first TX, then RX */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ goto err_release_region;
+ }
+
+ dma_data[count].channel = res->start;
+ count++;
+ dma_data[count].name = "I2S PCM Stereo in";
+ dma_data[count].eventq_no = pdata->eventq_no;
+ dma_data[count].dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
+ io_v2p(dev->base));
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &dma_data[count];
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ goto err_release_region;
+ }
+
+ dma_data[count].channel = res->start;
+ davinci_mcasp_dai[pdev->id].private_data = dev;
+ davinci_mcasp_dai[pdev->id].dev = &pdev->dev;
+ ret = snd_soc_register_dai(&davinci_mcasp_dai[pdev->id]);
+
+ if (ret != 0)
+ goto err_release_region;
+ return 0;
+
+err_release_region:
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+err_release_data:
+ kfree(dma_data);
+err_release_dev:
+ kfree(dev);
+
+ return ret;
+}
+
+static int davinci_mcasp_remove(struct platform_device *pdev)
+{
+ struct davinci_pcm_dma_params *dma_data;
+ struct davinci_audio_dev *dev;
+ struct resource *mem;
+
+ snd_soc_unregister_dai(&davinci_mcasp_dai[pdev->id]);
+ dev = davinci_mcasp_dai[pdev->id].private_data;
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ dma_data = dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+ kfree(dma_data);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver davinci_mcasp_driver = {
+ .probe = davinci_mcasp_probe,
+ .remove = davinci_mcasp_remove,
+ .driver = {
+ .name = "davinci-mcasp",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init davinci_mcasp_init(void)
+{
+ return platform_driver_register(&davinci_mcasp_driver);
+}
+module_init(davinci_mcasp_init);
+
+static void __exit davinci_mcasp_exit(void)
+{
+ platform_driver_unregister(&davinci_mcasp_driver);
+}
+module_exit(davinci_mcasp_exit);
+
+MODULE_AUTHOR("Steve Chen");
+MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
new file mode 100644
index 000000000000..36b71047a06c
--- /dev/null
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -0,0 +1,55 @@
+/*
+ * ALSA SoC McASP Audio Layer for TI DAVINCI processor
+ *
+ * MCASP related definitions
+ *
+ * Author: Nirmal Pandey <n-pandey@ti.com>,
+ * Suresh Rajashekara <suresh.r@ti.com>
+ * Steve Chen <schen@.mvista.com>
+ *
+ * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright: (C) 2009 Texas Instruments, India
+ *
+ * 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 DAVINCI_MCASP_H
+#define DAVINCI_MCASP_H
+
+#include <linux/io.h>
+#include <mach/asp.h>
+#include "davinci-pcm.h"
+
+extern struct snd_soc_dai davinci_mcasp_dai[];
+
+#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000
+#define DAVINCI_MCASP_I2S_DAI 0
+#define DAVINCI_MCASP_DIT_DAI 1
+
+enum {
+ DAVINCI_AUDIO_WORD_8 = 0,
+ DAVINCI_AUDIO_WORD_12,
+ DAVINCI_AUDIO_WORD_16,
+ DAVINCI_AUDIO_WORD_20,
+ DAVINCI_AUDIO_WORD_24,
+ DAVINCI_AUDIO_WORD_32,
+ DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */
+};
+
+struct davinci_audio_dev {
+ void __iomem *base;
+ int sample_rate;
+ struct clk *clk;
+ struct davinci_pcm_dma_params *dma_params[2];
+ unsigned int codec_fmt;
+
+ /* McASP specific data */
+ int tdm_slots;
+ u8 op_mode;
+ u8 num_serializer;
+ u8 *serial_dir;
+};
+
+#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index a05996588489..fbda8ef521d7 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -143,7 +143,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
prtd->master_lch = ret;
/* Request parameter RAM reload slot */
- ret = edma_alloc_slot(EDMA_SLOT_ANY);
+ ret = edma_alloc_slot(EDMA_CTLR(prtd->master_lch), EDMA_SLOT_ANY);
if (ret < 0) {
edma_free_channel(prtd->master_lch);
return ret;
@@ -160,8 +160,8 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
edma_read_slot(prtd->slave_lch, &p_ram);
- p_ram.opt |= TCINTEN | EDMA_TCC(prtd->master_lch);
- p_ram.link_bcntrld = prtd->slave_lch << 5;
+ p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->master_lch));
+ p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->slave_lch) << 5;
edma_write_slot(prtd->slave_lch, &p_ram);
return 0;
@@ -206,6 +206,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
/* Copy self-linked parameter RAM entry into master channel */
edma_read_slot(prtd->slave_lch, &temp);
edma_write_slot(prtd->master_lch, &temp);
+ davinci_pcm_enqueue_dma(substream);
return 0;
}
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 62cb4eb07e34..eb4287faa3d5 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -12,17 +12,19 @@
#ifndef _DAVINCI_PCM_H
#define _DAVINCI_PCM_H
+#include <mach/edma.h>
+#include <mach/asp.h>
+
+
struct davinci_pcm_dma_params {
- char *name; /* stream identifier */
- int channel; /* sync dma channel ID */
- dma_addr_t dma_addr; /* device physical address for DMA */
- unsigned int data_type; /* xfer data type */
+ char *name; /* stream identifier */
+ int channel; /* sync dma channel ID */
+ dma_addr_t dma_addr; /* device physical address for DMA */
+ enum dma_event_q eventq_no; /* event queue number */
+ unsigned char data_type; /* xfer data type */
+ unsigned char convert_mono_stereo;
};
-struct evm_snd_platform_data {
- int tx_dma_ch;
- int rx_dma_ch;
-};
extern struct snd_soc_platform davinci_soc_platform;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 7eb549985d49..c4ae3e096bb9 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -112,7 +113,7 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
out_8(&regs->op1, MPC52xx_PSC_OP_RES);
udelay(10);
out_8(&regs->op0, MPC52xx_PSC_OP_RES);
- udelay(50);
+ msleep(1);
psc_ac97_warm_reset(ac97);
}
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index b771238662b6..a5a90e594535 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -72,4 +72,11 @@ config SND_OMAP_SOC_OMAP3_BEAGLE
help
Say Y if you want to add support for SoC audio on the Beagleboard.
+config SND_OMAP_SOC_ZOOM2
+ tristate "SoC Audio support for Zoom2"
+ depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y if you want to add support for Soc audio on Zoom2 board.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index a37f49862389..fefc48f02bd3 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -14,6 +14,7 @@ snd-soc-omap3evm-objs := omap3evm.o
snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o
+snd-soc-zoom2-objs := zoom2.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
+obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 84a1950880eb..c3c931d4537a 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -330,7 +330,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
}
-int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
int ret = 0;
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index b719e5db4f57..f7e5b7488c35 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -24,6 +24,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -39,6 +40,9 @@
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
+#define TWL4030_INTBR_PMBR1 0x0D
+#define EXTMUTE(value) (value << 2)
+
static struct snd_soc_card snd_soc_sdp3430;
static int sdp3430_hw_params(struct snd_pcm_substream *substream,
@@ -96,7 +100,7 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBS_CFM);
+ SND_SOC_DAIFMT_CBM_CFM);
if (ret) {
printk(KERN_ERR "can't set codec DAI configuration\n");
return ret;
@@ -280,6 +284,7 @@ static struct snd_soc_card snd_soc_sdp3430 = {
static struct twl4030_setup_data twl4030_setup = {
.ramp_delay_value = 3,
.sysclk = 26000,
+ .hs_extmute = 1,
};
/* Audio subsystem */
@@ -312,6 +317,10 @@ static int __init sdp3430_soc_init(void)
*(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
*(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+ /* Set TWL4030 GPIO6 as EXTMUTE signal */
+ twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, EXTMUTE(0x02),
+ TWL4030_MODULE_INTBR);
+
ret = platform_device_add(sdp3430_snd_device);
if (ret)
goto err1;
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
new file mode 100644
index 000000000000..f90b45f56220
--- /dev/null
+++ b/sound/soc/omap/zoom2.c
@@ -0,0 +1,314 @@
+/*
+ * zoom2.c -- SoC audio for Zoom2
+ *
+ * Author: Misael Lopez Cruz <x0052729@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
+#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
+
+static int zoom2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops zoom2_ops = {
+ .hw_params = zoom2_hw_params,
+};
+
+static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops zoom2_voice_ops = {
+ .hw_params = zoom2_hw_voice_params,
+};
+
+/* Zoom2 machine DAPM */
+static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Ext Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_LINE("Aux In", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* External Mics: MAINMIC, SUBMIC with bias*/
+ {"MAINMIC", NULL, "Mic Bias 1"},
+ {"SUBMIC", NULL, "Mic Bias 2"},
+ {"Mic Bias 1", NULL, "Ext Mic"},
+ {"Mic Bias 2", NULL, "Ext Mic"},
+
+ /* External Speakers: HFL, HFR */
+ {"Ext Spk", NULL, "HFL"},
+ {"Ext Spk", NULL, "HFR"},
+
+ /* Headset Stereophone: HSOL, HSOR */
+ {"Headset Stereophone", NULL, "HSOL"},
+ {"Headset Stereophone", NULL, "HSOR"},
+
+ /* Headset Mic: HSMIC with bias */
+ {"HSMIC", NULL, "Headset Mic Bias"},
+ {"Headset Mic Bias", NULL, "Headset Mic"},
+
+ /* Aux In: AUXL, AUXR */
+ {"Aux In", NULL, "AUXL"},
+ {"Aux In", NULL, "AUXR"},
+};
+
+static int zoom2_twl4030_init(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ /* Add Zoom2 specific widgets */
+ ret = snd_soc_dapm_new_controls(codec, zoom2_twl4030_dapm_widgets,
+ ARRAY_SIZE(zoom2_twl4030_dapm_widgets));
+ if (ret)
+ return ret;
+
+ /* Set up Zoom2 specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* Zoom2 connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Mic");
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ snd_soc_dapm_enable_pin(codec, "Headset Mic");
+ snd_soc_dapm_enable_pin(codec, "Headset Stereophone");
+ snd_soc_dapm_enable_pin(codec, "Aux In");
+
+ /* TWL4030 not connected pins */
+ snd_soc_dapm_nc_pin(codec, "CARKITMIC");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
+
+ snd_soc_dapm_nc_pin(codec, "OUTL");
+ snd_soc_dapm_nc_pin(codec, "OUTR");
+ snd_soc_dapm_nc_pin(codec, "EARPIECE");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVER");
+ snd_soc_dapm_nc_pin(codec, "CARKITL");
+ snd_soc_dapm_nc_pin(codec, "CARKITR");
+
+ ret = snd_soc_dapm_sync(codec);
+
+ return ret;
+}
+
+static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
+{
+ unsigned short reg;
+
+ /* Enable voice interface */
+ reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+ reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
+ codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+
+ return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link zoom2_dai[] = {
+ {
+ .name = "TWL4030 I2S",
+ .stream_name = "TWL4030 Audio",
+ .cpu_dai = &omap_mcbsp_dai[0],
+ .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .init = zoom2_twl4030_init,
+ .ops = &zoom2_ops,
+ },
+ {
+ .name = "TWL4030 PCM",
+ .stream_name = "TWL4030 Voice",
+ .cpu_dai = &omap_mcbsp_dai[1],
+ .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .init = zoom2_twl4030_voice_init,
+ .ops = &zoom2_voice_ops,
+ },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_zoom2 = {
+ .name = "Zoom2",
+ .platform = &omap_soc_platform,
+ .dai_link = zoom2_dai,
+ .num_links = ARRAY_SIZE(zoom2_dai),
+};
+
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+ gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
+
+/* twl4030 setup */
+static struct twl4030_setup_data twl4030_setup = {
+ .ramp_delay_value = 3, /* 161 ms */
+ .sysclk = 26000,
+ .hs_extmute = 1,
+ .set_hs_extmute = zoom2_set_hs_extmute,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device zoom2_snd_devdata = {
+ .card = &snd_soc_zoom2,
+ .codec_dev = &soc_codec_dev_twl4030,
+ .codec_data = &twl4030_setup,
+};
+
+static struct platform_device *zoom2_snd_device;
+
+static int __init zoom2_soc_init(void)
+{
+ int ret;
+
+ if (!machine_is_omap_zoom2()) {
+ pr_debug("Not Zoom2!\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "Zoom2 SoC init\n");
+
+ zoom2_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!zoom2_snd_device) {
+ printk(KERN_ERR "Platform device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
+ zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
+ *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+ *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+
+ ret = platform_device_add(zoom2_snd_device);
+ if (ret)
+ goto err1;
+
+ BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);
+ gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
+
+ BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
+ gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
+
+ return 0;
+
+err1:
+ printk(KERN_ERR "Unable to add platform device\n");
+ platform_device_put(zoom2_snd_device);
+
+ return ret;
+}
+module_init(zoom2_soc_init);
+
+static void __exit zoom2_soc_exit(void)
+{
+ gpio_free(ZOOM2_HEADSET_MUX_GPIO);
+ gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO);
+
+ platform_device_unregister(zoom2_snd_device);
+}
+module_exit(zoom2_soc_exit);
+
+MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC Zoom2");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 326955dea36c..8889cd371608 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -20,12 +20,14 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
#include <mach/magician.h>
#include <asm/mach-types.h>
@@ -447,34 +449,47 @@ static struct snd_soc_card snd_soc_card_magician = {
.platform = &pxa2xx_soc_platform,
};
-/* magician audio private data */
-static struct uda1380_setup_data magician_uda1380_setup = {
- .i2c_address = 0x18,
- .dac_clk = UDA1380_DAC_CLK_WSPLL,
-};
-
/* magician audio subsystem */
static struct snd_soc_device magician_snd_devdata = {
.card = &snd_soc_card_magician,
.codec_dev = &soc_codec_dev_uda1380,
- .codec_data = &magician_uda1380_setup,
};
static struct platform_device *magician_snd_device;
+/*
+ * FIXME: move into magician board file once merged into the pxa tree
+ */
+static struct uda1380_platform_data uda1380_info = {
+ .gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
+ .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
+ .dac_clk = UDA1380_DAC_CLK_WSPLL,
+};
+
+static struct i2c_board_info i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("uda1380", 0x18),
+ .platform_data = &uda1380_info,
+ },
+};
+
static int __init magician_init(void)
{
int ret;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
if (!machine_is_magician())
return -ENODEV;
- ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER");
- if (ret)
- goto err_request_power;
- ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET");
- if (ret)
- goto err_request_reset;
+ adapter = i2c_get_adapter(0);
+ if (!adapter)
+ return -ENODEV;
+ client = i2c_new_device(adapter, i2c_board_info);
+ i2c_put_adapter(adapter);
+ if (!client)
+ return -ENODEV;
+
ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
if (ret)
goto err_request_spk;
@@ -491,14 +506,8 @@ static int __init magician_init(void)
if (ret)
goto err_request_in_sel1;
- gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1);
gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
- /* we may need to have the clock running here - pH5 */
- gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1);
- udelay(5);
- gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0);
-
magician_snd_device = platform_device_alloc("soc-audio", -1);
if (!magician_snd_device) {
ret = -ENOMEM;
@@ -526,10 +535,6 @@ err_request_mic:
err_request_ep:
gpio_free(EGPIO_MAGICIAN_SPK_POWER);
err_request_spk:
- gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
-err_request_reset:
- gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
-err_request_power:
return ret;
}
@@ -540,15 +545,12 @@ static void __exit magician_exit(void)
gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
- gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0);
gpio_free(EGPIO_MAGICIAN_IN_SEL1);
gpio_free(EGPIO_MAGICIAN_IN_SEL0);
gpio_free(EGPIO_MAGICIAN_MIC_POWER);
gpio_free(EGPIO_MAGICIAN_EP_POWER);
gpio_free(EGPIO_MAGICIAN_SPK_POWER);
- gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
- gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
}
module_init(magician_init);
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index e6102fda0a7f..1f96e3227be5 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -17,13 +17,12 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/jack.h>
#include <asm/mach-types.h>
#include <mach/audio.h>
@@ -33,90 +32,31 @@
#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
-static int palm27x_jack_func = 1;
-static int palm27x_spk_func = 1;
-static int palm27x_ep_gpio = -1;
+static struct snd_soc_jack hs_jack;
-static void palm27x_ext_control(struct snd_soc_codec *codec)
-{
- if (!palm27x_spk_func)
- snd_soc_dapm_enable_pin(codec, "Speaker");
- else
- snd_soc_dapm_disable_pin(codec, "Speaker");
-
- if (!palm27x_jack_func)
- snd_soc_dapm_enable_pin(codec, "Headphone Jack");
- else
- snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-
- snd_soc_dapm_sync(codec);
-}
-
-static int palm27x_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
-
- /* check the jack status at stream startup */
- palm27x_ext_control(codec);
- return 0;
-}
-
-static struct snd_soc_ops palm27x_ops = {
- .startup = palm27x_startup,
+/* Headphones jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
};
-static irqreturn_t palm27x_interrupt(int irq, void *v)
-{
- palm27x_spk_func = gpio_get_value(palm27x_ep_gpio);
- palm27x_jack_func = !palm27x_spk_func;
- return IRQ_HANDLED;
-}
-
-static int palm27x_get_jack(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = palm27x_jack_func;
- return 0;
-}
-
-static int palm27x_set_jack(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- if (palm27x_jack_func == ucontrol->value.integer.value[0])
- return 0;
-
- palm27x_jack_func = ucontrol->value.integer.value[0];
- palm27x_ext_control(codec);
- return 1;
-}
-
-static int palm27x_get_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = palm27x_spk_func;
- return 0;
-}
-
-static int palm27x_set_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- if (palm27x_spk_func == ucontrol->value.integer.value[0])
- return 0;
-
- palm27x_spk_func = ucontrol->value.integer.value[0];
- palm27x_ext_control(codec);
- return 1;
-}
+/* Headphones jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ [0] = {
+ /* gpio is set on per-platform basis */
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 200,
+ },
+};
-/* PalmTX machine dapm widgets */
+/* Palm27x machine dapm widgets */
static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_SPK("Ext. Speaker", NULL),
+ SND_SOC_DAPM_MIC("Ext. Microphone", NULL),
};
/* PalmTX audio map */
@@ -126,46 +66,66 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Headphone Jack", NULL, "HPOUTR"},
/* ext speaker connected to ROUT2, LOUT2 */
- {"Speaker", NULL, "LOUT2"},
- {"Speaker", NULL, "ROUT2"},
-};
+ {"Ext. Speaker", NULL, "LOUT2"},
+ {"Ext. Speaker", NULL, "ROUT2"},
-static const char *jack_function[] = {"Headphone", "Off"};
-static const char *spk_function[] = {"On", "Off"};
-static const struct soc_enum palm27x_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, jack_function),
- SOC_ENUM_SINGLE_EXT(2, spk_function),
+ /* mic connected to MIC1 */
+ {"Ext. Microphone", NULL, "MIC1"},
};
-static const struct snd_kcontrol_new palm27x_controls[] = {
- SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack,
- palm27x_set_jack),
- SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk,
- palm27x_set_spk),
-};
+static struct snd_soc_card palm27x_asoc;
static int palm27x_ac97_init(struct snd_soc_codec *codec)
{
int err;
+ /* add palm27x specific widgets */
+ err = snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
+ ARRAY_SIZE(palm27x_dapm_widgets));
+ if (err)
+ return err;
+
+ /* set up palm27x specific audio path audio_map */
+ err = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ if (err)
+ return err;
+
+ /* connected pins */
+ if (machine_is_palmld())
+ snd_soc_dapm_enable_pin(codec, "MIC1");
+ snd_soc_dapm_enable_pin(codec, "HPOUTL");
+ snd_soc_dapm_enable_pin(codec, "HPOUTR");
+ snd_soc_dapm_enable_pin(codec, "LOUT2");
+ snd_soc_dapm_enable_pin(codec, "ROUT2");
+
+ /* not connected pins */
snd_soc_dapm_nc_pin(codec, "OUT3");
snd_soc_dapm_nc_pin(codec, "MONOOUT");
+ snd_soc_dapm_nc_pin(codec, "LINEINL");
+ snd_soc_dapm_nc_pin(codec, "LINEINR");
+ snd_soc_dapm_nc_pin(codec, "PCBEEP");
+ snd_soc_dapm_nc_pin(codec, "PHONE");
+ snd_soc_dapm_nc_pin(codec, "MIC2");
+
+ err = snd_soc_dapm_sync(codec);
+ if (err)
+ return err;
- /* add palm27x specific controls */
- err = snd_soc_add_controls(codec, palm27x_controls,
- ARRAY_SIZE(palm27x_controls));
- if (err < 0)
+ /* Jack detection API stuff */
+ err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+ SND_JACK_HEADPHONE, &hs_jack);
+ if (err)
return err;
- /* add palm27x specific widgets */
- snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
- ARRAY_SIZE(palm27x_dapm_widgets));
+ err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ if (err)
+ return err;
- /* set up palm27x specific audio path audio_map */
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
- snd_soc_dapm_sync(codec);
- return 0;
+ return err;
}
static struct snd_soc_dai_link palm27x_dai[] = {
@@ -175,14 +135,12 @@ static struct snd_soc_dai_link palm27x_dai[] = {
.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
.init = palm27x_ac97_init,
- .ops = &palm27x_ops,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
- .ops = &palm27x_ops,
},
};
@@ -208,27 +166,17 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
machine_is_palmld() || machine_is_palmte2()))
return -ENODEV;
- if (pdev->dev.platform_data)
- palm27x_ep_gpio = ((struct palm27x_asoc_info *)
- (pdev->dev.platform_data))->jack_gpio;
-
- ret = gpio_request(palm27x_ep_gpio, "Headphone Jack");
- if (ret)
- return ret;
- ret = gpio_direction_input(palm27x_ep_gpio);
- if (ret)
- goto err_alloc;
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "please supply platform_data\n");
+ return -ENODEV;
+ }
- if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Headphone jack", NULL))
- goto err_alloc;
+ hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
+ (pdev->dev.platform_data))->jack_gpio;
palm27x_snd_device = platform_device_alloc("soc-audio", -1);
- if (!palm27x_snd_device) {
- ret = -ENOMEM;
- goto err_dev;
- }
+ if (!palm27x_snd_device)
+ return -ENOMEM;
platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
@@ -241,18 +189,12 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
put_device:
platform_device_put(palm27x_snd_device);
-err_dev:
- free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
-err_alloc:
- gpio_free(palm27x_ep_gpio);
return ret;
}
static int __devexit palm27x_asoc_remove(struct platform_device *pdev)
{
- free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
- gpio_free(palm27x_ep_gpio);
platform_device_unregister(palm27x_snd_device);
return 0;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 19c45409d94c..e22c5cef8fec 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -457,31 +457,27 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- ssp_write_reg(ssp, SSCR0, sscr0);
- ssp_write_reg(ssp, SSCR1, sscr1);
- ssp_write_reg(ssp, SSPSP, sspsp);
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ sspsp |= SSPSP_SFRMP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ sspsp |= SSPSP_SCMODE(2);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
+ break;
+ default:
+ return -EINVAL;
+ }
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
-
/* See hw_params() */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- sspsp |= SSPSP_SFRMP;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- break;
- case SND_SOC_DAIFMT_IB_IF:
- sspsp |= SSPSP_SCMODE(2);
- break;
- case SND_SOC_DAIFMT_IB_NF:
- sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
- break;
- default:
- return -EINVAL;
- }
break;
case SND_SOC_DAIFMT_DSP_A:
@@ -489,22 +485,6 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_DSP_B:
sscr0 |= SSCR0_MOD | SSCR0_PSP;
sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
-
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- sspsp |= SSPSP_SFRMP;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- break;
- case SND_SOC_DAIFMT_IB_IF:
- sspsp |= SSPSP_SCMODE(2);
- break;
- case SND_SOC_DAIFMT_IB_NF:
- sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
- break;
- default:
- return -EINVAL;
- }
break;
default:
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1d70829464ef..5eabb7117608 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -28,6 +28,7 @@
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
+#include <sound/ac97_codec.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -619,8 +620,9 @@ static struct snd_pcm_ops soc_pcm_ops = {
#ifdef CONFIG_PM
/* powers down audio subsystem for suspend */
-static int soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int soc_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card;
struct snd_soc_platform *platform = card->platform;
@@ -656,7 +658,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
snd_pcm_suspend_all(card->dai_link[i].pcm);
if (card->suspend_pre)
- card->suspend_pre(pdev, state);
+ card->suspend_pre(pdev, PMSG_SUSPEND);
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
@@ -682,7 +684,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
}
if (codec_dev->suspend)
- codec_dev->suspend(pdev, state);
+ codec_dev->suspend(pdev, PMSG_SUSPEND);
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
@@ -691,7 +693,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
}
if (card->suspend_post)
- card->suspend_post(pdev, state);
+ card->suspend_post(pdev, PMSG_SUSPEND);
return 0;
}
@@ -765,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work)
}
/* powers up audio subsystem after a suspend */
-static int soc_resume(struct platform_device *pdev)
+static int soc_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card;
struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
@@ -788,6 +791,44 @@ static int soc_resume(struct platform_device *pdev)
return 0;
}
+/**
+ * snd_soc_suspend_device: Notify core of device suspend
+ *
+ * @dev: Device being suspended.
+ *
+ * In order to ensure that the entire audio subsystem is suspended in a
+ * coordinated fashion ASoC devices should suspend themselves when
+ * called by ASoC. When the standard kernel suspend process asks the
+ * device to suspend it should call this function to initiate a suspend
+ * of the entire ASoC card.
+ *
+ * \note Currently this function is stubbed out.
+ */
+int snd_soc_suspend_device(struct device *dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_suspend_device);
+
+/**
+ * snd_soc_resume_device: Notify core of device resume
+ *
+ * @dev: Device being resumed.
+ *
+ * In order to ensure that the entire audio subsystem is resumed in a
+ * coordinated fashion ASoC devices should resume themselves when called
+ * by ASoC. When the standard kernel resume process asks the device
+ * to resume it should call this function. Once all the components of
+ * the card have notified that they are ready to be resumed the card
+ * will be resumed.
+ *
+ * \note Currently this function is stubbed out.
+ */
+int snd_soc_resume_device(struct device *dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_resume_device);
#else
#define soc_suspend NULL
#define soc_resume NULL
@@ -981,16 +1022,39 @@ static int soc_remove(struct platform_device *pdev)
return 0;
}
+static int soc_poweroff(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = socdev->card;
+
+ if (!card->instantiated)
+ return 0;
+
+ /* Flush out pmdown_time work - we actually do want to run it
+ * now, we're shutting down so no imminent restart. */
+ run_delayed_work(&card->delayed_work);
+
+ snd_soc_dapm_shutdown(socdev);
+
+ return 0;
+}
+
+static struct dev_pm_ops soc_pm_ops = {
+ .suspend = soc_suspend,
+ .resume = soc_resume,
+ .poweroff = soc_poweroff,
+};
+
/* ASoC platform driver */
static struct platform_driver soc_driver = {
.driver = {
.name = "soc-audio",
.owner = THIS_MODULE,
+ .pm = &soc_pm_ops,
},
.probe = soc_probe,
.remove = soc_remove,
- .suspend = soc_suspend,
- .resume = soc_resume,
};
/* create a new pcm */
@@ -1062,6 +1126,23 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
return ret;
}
+/**
+ * snd_soc_codec_volatile_register: Report if a register is volatile.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indiciating if a CODEC register is volatile.
+ */
+int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
+{
+ if (codec->volatile_register)
+ return codec->volatile_register(reg);
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
+
/* codec register dump */
static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
{
@@ -1264,10 +1345,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
* Returns 1 for change else 0.
*/
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned short mask, unsigned short value)
+ unsigned int mask, unsigned int value)
{
int change;
- unsigned short old, new;
+ unsigned int old, new;
mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
@@ -1294,10 +1375,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
* Returns 1 for change else 0.
*/
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned short mask, unsigned short value)
+ unsigned int mask, unsigned int value)
{
int change;
- unsigned short old, new;
+ unsigned int old, new;
mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
@@ -1381,8 +1462,11 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
continue;
}
}
- if (card->dai_link[i].codec_dai->ac97_control)
+ if (card->dai_link[i].codec_dai->ac97_control) {
ac97 = 1;
+ snd_ac97_dev_add_pdata(codec->ac97,
+ card->dai_link[i].cpu_dai->ac97_pdata);
+ }
}
snprintf(codec->card->shortname, sizeof(codec->card->shortname),
"%s", card->name);
@@ -1586,7 +1670,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned short val, bitmask;
+ unsigned int val, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@@ -1615,8 +1699,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned short val;
- unsigned short mask, bitmask;
+ unsigned int val;
+ unsigned int mask, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@@ -1652,7 +1736,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned short reg_val, val, mux;
+ unsigned int reg_val, val, mux;
reg_val = snd_soc_read(codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
@@ -1691,8 +1775,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned short val;
- unsigned short mask;
+ unsigned int val;
+ unsigned int mask;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL;
@@ -1852,7 +1936,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- unsigned short val, val2, val_mask;
+ unsigned int val, val2, val_mask;
val = (ucontrol->value.integer.value[0] & mask);
if (invert)
@@ -1918,7 +2002,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
int max = mc->max;
- unsigned int mask = (1<<fls(max))-1;
+ unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
ucontrol->value.integer.value[0] =
@@ -1958,7 +2042,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
int err;
- unsigned short val, val2, val_mask;
+ unsigned int val, val2, val_mask;
val_mask = mask << shift;
val = (ucontrol->value.integer.value[0] & mask);
@@ -2050,7 +2134,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
int min = mc->min;
- unsigned short val;
+ unsigned int val;
val = (ucontrol->value.integer.value[0]+min) & 0xff;
val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 21c69074aa17..c68c204a48ad 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -52,19 +52,37 @@
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
- snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
- snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
- snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
- snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
- snd_soc_dapm_post
+ [snd_soc_dapm_pre] = 0,
+ [snd_soc_dapm_supply] = 1,
+ [snd_soc_dapm_micbias] = 2,
+ [snd_soc_dapm_mic] = 3,
+ [snd_soc_dapm_mux] = 4,
+ [snd_soc_dapm_value_mux] = 4,
+ [snd_soc_dapm_dac] = 5,
+ [snd_soc_dapm_mixer] = 6,
+ [snd_soc_dapm_mixer_named_ctl] = 6,
+ [snd_soc_dapm_pga] = 7,
+ [snd_soc_dapm_adc] = 8,
+ [snd_soc_dapm_hp] = 9,
+ [snd_soc_dapm_spk] = 10,
+ [snd_soc_dapm_post] = 11,
};
static int dapm_down_seq[] = {
- snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
- snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
- snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
- snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
- snd_soc_dapm_post
+ [snd_soc_dapm_pre] = 0,
+ [snd_soc_dapm_adc] = 1,
+ [snd_soc_dapm_hp] = 2,
+ [snd_soc_dapm_spk] = 3,
+ [snd_soc_dapm_pga] = 4,
+ [snd_soc_dapm_mixer_named_ctl] = 5,
+ [snd_soc_dapm_mixer] = 5,
+ [snd_soc_dapm_dac] = 6,
+ [snd_soc_dapm_mic] = 7,
+ [snd_soc_dapm_micbias] = 8,
+ [snd_soc_dapm_mux] = 9,
+ [snd_soc_dapm_value_mux] = 9,
+ [snd_soc_dapm_supply] = 10,
+ [snd_soc_dapm_post] = 11,
};
static void pop_wait(u32 pop_time)
@@ -268,7 +286,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec,
static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
{
int change, power;
- unsigned short old, new;
+ unsigned int old, new;
struct snd_soc_codec *codec = widget->codec;
/* check for valid widgets */
@@ -689,53 +707,211 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
return power;
}
-/*
- * Scan a single DAPM widget for a complete audio path and update the
- * power status appropriately.
- */
-static int dapm_power_widget(struct snd_soc_codec *codec, int event,
- struct snd_soc_dapm_widget *w)
+static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
+ struct snd_soc_dapm_widget *b,
+ int sort[])
{
- int ret;
+ if (sort[a->id] != sort[b->id])
+ return sort[a->id] - sort[b->id];
+ if (a->reg != b->reg)
+ return a->reg - b->reg;
- switch (w->id) {
- case snd_soc_dapm_pre:
- if (!w->event)
- return 0;
+ return 0;
+}
- if (event == SND_SOC_DAPM_STREAM_START) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_PRE_PMU);
+/* Insert a widget in order into a DAPM power sequence. */
+static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
+ struct list_head *list,
+ int sort[])
+{
+ struct snd_soc_dapm_widget *w;
+
+ list_for_each_entry(w, list, power_list)
+ if (dapm_seq_compare(new_widget, w, sort) < 0) {
+ list_add_tail(&new_widget->power_list, &w->power_list);
+ return;
+ }
+
+ list_add_tail(&new_widget->power_list, list);
+}
+
+/* Apply the coalesced changes from a DAPM sequence */
+static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
+ struct list_head *pending)
+{
+ struct snd_soc_dapm_widget *w;
+ int reg, power, ret;
+ unsigned int value = 0;
+ unsigned int mask = 0;
+ unsigned int cur_mask;
+
+ reg = list_first_entry(pending, struct snd_soc_dapm_widget,
+ power_list)->reg;
+
+ list_for_each_entry(w, pending, power_list) {
+ cur_mask = 1 << w->shift;
+ BUG_ON(reg != w->reg);
+
+ if (w->invert)
+ power = !w->power;
+ else
+ power = w->power;
+
+ mask |= cur_mask;
+ if (power)
+ value |= cur_mask;
+
+ pop_dbg(codec->pop_time,
+ "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
+ w->name, reg, value, mask);
+
+ /* power up pre event */
+ if (w->power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
+ pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n",
+ w->name);
+ ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
if (ret < 0)
- return ret;
- } else if (event == SND_SOC_DAPM_STREAM_STOP) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_PRE_PMD);
+ pr_err("%s: pre event failed: %d\n",
+ w->name, ret);
+ }
+
+ /* power down pre event */
+ if (!w->power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
+ pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n",
+ w->name);
+ ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
if (ret < 0)
- return ret;
+ pr_err("%s: pre event failed: %d\n",
+ w->name, ret);
}
- return 0;
- case snd_soc_dapm_post:
- if (!w->event)
- return 0;
+ /* Lower PGA volume to reduce pops */
+ if (w->id == snd_soc_dapm_pga && !w->power)
+ dapm_set_pga(w, w->power);
+ }
- if (event == SND_SOC_DAPM_STREAM_START) {
+ if (reg >= 0) {
+ pop_dbg(codec->pop_time,
+ "pop test : Applying 0x%x/0x%x to %x in %dms\n",
+ value, mask, reg, codec->pop_time);
+ pop_wait(codec->pop_time);
+ snd_soc_update_bits(codec, reg, mask, value);
+ }
+
+ list_for_each_entry(w, pending, power_list) {
+ /* Raise PGA volume to reduce pops */
+ if (w->id == snd_soc_dapm_pga && w->power)
+ dapm_set_pga(w, w->power);
+
+ /* power up post event */
+ if (w->power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
+ pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n",
+ w->name);
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMU);
if (ret < 0)
- return ret;
- } else if (event == SND_SOC_DAPM_STREAM_STOP) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_POST_PMD);
+ pr_err("%s: post event failed: %d\n",
+ w->name, ret);
+ }
+
+ /* power down post event */
+ if (!w->power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
+ pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n",
+ w->name);
+ ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
if (ret < 0)
- return ret;
+ pr_err("%s: post event failed: %d\n",
+ w->name, ret);
}
- return 0;
+ }
+}
- default:
- return dapm_generic_apply_power(w);
+/* Apply a DAPM power sequence.
+ *
+ * We walk over a pre-sorted list of widgets to apply power to. In
+ * order to minimise the number of writes to the device required
+ * multiple widgets will be updated in a single write where possible.
+ * Currently anything that requires more than a single write is not
+ * handled.
+ */
+static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
+ int event, int sort[])
+{
+ struct snd_soc_dapm_widget *w, *n;
+ LIST_HEAD(pending);
+ int cur_sort = -1;
+ int cur_reg = SND_SOC_NOPM;
+ int ret;
+
+ list_for_each_entry_safe(w, n, list, power_list) {
+ ret = 0;
+
+ /* Do we need to apply any queued changes? */
+ if (sort[w->id] != cur_sort || w->reg != cur_reg) {
+ if (!list_empty(&pending))
+ dapm_seq_run_coalesced(codec, &pending);
+
+ INIT_LIST_HEAD(&pending);
+ cur_sort = -1;
+ cur_reg = SND_SOC_NOPM;
+ }
+
+ switch (w->id) {
+ case snd_soc_dapm_pre:
+ if (!w->event)
+ list_for_each_entry_safe_continue(w, n, list,
+ power_list);
+
+ if (event == SND_SOC_DAPM_STREAM_START)
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_PRE_PMU);
+ else if (event == SND_SOC_DAPM_STREAM_STOP)
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_PRE_PMD);
+ break;
+
+ case snd_soc_dapm_post:
+ if (!w->event)
+ list_for_each_entry_safe_continue(w, n, list,
+ power_list);
+
+ if (event == SND_SOC_DAPM_STREAM_START)
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_POST_PMU);
+ else if (event == SND_SOC_DAPM_STREAM_STOP)
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_POST_PMD);
+ break;
+
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_spk:
+ /* No register support currently */
+ ret = dapm_generic_apply_power(w);
+ break;
+
+ default:
+ /* Queue it up for application */
+ cur_sort = sort[w->id];
+ cur_reg = w->reg;
+ list_move(&w->power_list, &pending);
+ break;
+ }
+
+ if (ret < 0)
+ pr_err("Failed to apply widget power: %d\n",
+ ret);
}
+
+ if (!list_empty(&pending))
+ dapm_seq_run_coalesced(codec, &pending);
}
/*
@@ -751,23 +927,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
struct snd_soc_device *socdev = codec->socdev;
struct snd_soc_dapm_widget *w;
+ LIST_HEAD(up_list);
+ LIST_HEAD(down_list);
int ret = 0;
- int i, power;
+ int power;
int sys_power = 0;
- INIT_LIST_HEAD(&codec->up_list);
- INIT_LIST_HEAD(&codec->down_list);
-
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
list_for_each_entry(w, &codec->dapm_widgets, list) {
switch (w->id) {
case snd_soc_dapm_pre:
- list_add_tail(&codec->down_list, &w->power_list);
+ dapm_seq_insert(w, &down_list, dapm_down_seq);
break;
case snd_soc_dapm_post:
- list_add_tail(&codec->up_list, &w->power_list);
+ dapm_seq_insert(w, &up_list, dapm_up_seq);
break;
default:
@@ -782,10 +957,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
continue;
if (power)
- list_add_tail(&w->power_list, &codec->up_list);
+ dapm_seq_insert(w, &up_list, dapm_up_seq);
else
- list_add_tail(&w->power_list,
- &codec->down_list);
+ dapm_seq_insert(w, &down_list, dapm_down_seq);
w->power = power;
break;
@@ -802,32 +976,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
}
/* Power down widgets first; try to avoid amplifying pops. */
- for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
- list_for_each_entry(w, &codec->down_list, power_list) {
- /* is widget in stream order */
- if (w->id != dapm_down_seq[i])
- continue;
-
- ret = dapm_power_widget(codec, event, w);
- if (ret != 0)
- pr_err("Failed to power down %s: %d\n",
- w->name, ret);
- }
- }
+ dapm_seq_run(codec, &down_list, event, dapm_down_seq);
/* Now power up. */
- for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) {
- list_for_each_entry(w, &codec->up_list, power_list) {
- /* is widget in stream order */
- if (w->id != dapm_up_seq[i])
- continue;
-
- ret = dapm_power_widget(codec, event, w);
- if (ret != 0)
- pr_err("Failed to power up %s: %d\n",
- w->name, ret);
- }
- }
+ dapm_seq_run(codec, &up_list, event, dapm_up_seq);
/* If we just powered the last thing off drop to standby bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
@@ -845,6 +997,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
pr_err("Failed to apply active bias: %d\n", ret);
}
+ pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n",
+ codec->pop_time);
+
return 0;
}
@@ -1138,8 +1293,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
if (wsink->id == snd_soc_dapm_input) {
if (wsource->id == snd_soc_dapm_micbias ||
wsource->id == snd_soc_dapm_mic ||
- wsink->id == snd_soc_dapm_line ||
- wsink->id == snd_soc_dapm_output)
+ wsource->id == snd_soc_dapm_line ||
+ wsource->id == snd_soc_dapm_output)
wsink->ext = 1;
}
if (wsource->id == snd_soc_dapm_output) {
@@ -1372,7 +1527,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- unsigned short val, val2, val_mask;
+ unsigned int val, val2, val_mask;
int ret;
val = (ucontrol->value.integer.value[0] & mask);
@@ -1436,7 +1591,7 @@ int snd_soc_dapm_get_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 short val, bitmask;
+ unsigned int val, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@@ -1464,8 +1619,8 @@ 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 short val, mux;
- unsigned short mask, bitmask;
+ unsigned int val, mux;
+ unsigned int mask, bitmask;
int ret = 0;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
@@ -1523,7 +1678,7 @@ int snd_soc_dapm_get_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 short reg_val, val, mux;
+ unsigned int reg_val, val, mux;
reg_val = snd_soc_read(widget->codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
@@ -1563,8 +1718,8 @@ 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 short val, mux;
- unsigned short mask;
+ unsigned int val, mux;
+ unsigned int mask;
int ret = 0;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
@@ -1880,6 +2035,36 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_dapm_widget *w;
+ LIST_HEAD(down_list);
+ int powerdown = 0;
+
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+ if (w->power) {
+ dapm_seq_insert(w, &down_list, dapm_down_seq);
+ w->power = 0;
+ powerdown = 1;
+ }
+ }
+
+ /* If there were no widgets to power down we're already in
+ * standby.
+ */
+ if (powerdown) {
+ snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+ dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
+ snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+ }
+
+ snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+}
+
/* Module information */
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 28346fb2e70c..4aa7d8f8ce77 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -73,14 +73,15 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
oldstatus = jack->status;
jack->status &= ~mask;
- jack->status |= status;
+ jack->status |= status & mask;
- /* The DAPM sync is expensive enough to be worth skipping */
- if (jack->status == oldstatus)
+ /* The DAPM sync is expensive enough to be worth skipping.
+ * However, empty mask means pin synchronization is desired. */
+ if (mask && (jack->status == oldstatus))
goto out;
list_for_each_entry(pin, &jack->pins, list) {
- enable = pin->mask & status;
+ enable = pin->mask & jack->status;
if (pin->invert)
enable = !enable;
@@ -228,8 +229,16 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
if (ret)
goto err;
+#ifdef CONFIG_GPIO_SYSFS
+ /* Expose GPIO value over sysfs for diagnostic purposes */
+ gpio_export(gpios[i].gpio, false);
+#endif
+
INIT_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack;
+
+ /* Update initial jack status */
+ snd_soc_jack_gpio_detect(&gpios[i]);
}
return 0;
@@ -258,6 +267,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
int i;
for (i = 0; i < count; i++) {
+#ifdef CONFIG_GPIO_SYSFS
+ gpio_unexport(gpios[i].gpio);
+#endif
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
gpio_free(gpios[i].gpio);
gpios[i].jack = NULL;
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 938a58a5a244..efed64b8b026 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -297,15 +297,17 @@ static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
static bool filter(struct dma_chan *chan, void *param)
{
struct txx9aclc_dmadata *dmadata = param;
- char devname[20 + 2]; /* FIXME: old BUS_ID_SIZE + 2 */
+ char *devname;
+ bool found = false;
- snprintf(devname, sizeof(devname), "%s.%d", dmadata->dma_res->name,
+ devname = kasprintf(GFP_KERNEL, "%s.%d", dmadata->dma_res->name,
(int)dmadata->dma_res->start);
if (strcmp(dev_name(chan->device->dev), devname) == 0) {
chan->private = &dmadata->dma_slave;
- return true;
+ found = true;
}
- return false;
+ kfree(devname);
+ return found;
}
static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 523aec188ccf..73525c048e7f 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -48,6 +48,7 @@ config SND_USB_CAIAQ
* Native Instruments Kore Controller
* Native Instruments Kore Controller 2
* Native Instruments Audio Kontrol 1
+ * Native Instruments Audio 2 DJ
* Native Instruments Audio 4 DJ
* Native Instruments Audio 8 DJ
* Native Instruments Guitar Rig Session I/O
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 8f9b60c5d74c..121af0644fd9 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -646,6 +646,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
dev->samplerates |= SNDRV_PCM_RATE_192000;
/* fall thru */
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
dev->samplerates |= SNDRV_PCM_RATE_88200;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index de38108f0b28..83e6c1312d47 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -35,13 +35,14 @@
#include "input.h"
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.18");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.19");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"
"{Native Instruments, Kore Controller},"
"{Native Instruments, Kore Controller 2},"
"{Native Instruments, Audio Kontrol 1},"
+ "{Native Instruments, Audio 2 DJ},"
"{Native Instruments, Audio 4 DJ},"
"{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O},"
@@ -121,6 +122,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_AUDIO4DJ
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = USB_VID_NATIVEINSTRUMENTS,
+ .idProduct = USB_PID_AUDIO2DJ
+ },
{ /* terminator */ }
};
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index ece73514854e..44e3edf88bef 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -10,6 +10,7 @@
#define USB_PID_KORECONTROLLER 0x4711
#define USB_PID_KORECONTROLLER2 0x4712
#define USB_PID_AK1 0x0815
+#define USB_PID_AUDIO2DJ 0x041c
#define USB_PID_AUDIO4DJ 0x0839
#define USB_PID_AUDIO8DJ 0x1978
#define USB_PID_SESSIONIO 0x1915
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 2fb35cc22a30..0eff19ceb7e1 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -45,6 +45,7 @@
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/usb.h>
+#include <linux/wait.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/asequencer.h>
@@ -62,6 +63,9 @@
*/
#define ERROR_DELAY_JIFFIES (HZ / 10)
+#define OUTPUT_URBS 7
+#define INPUT_URBS 7
+
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@@ -90,7 +94,7 @@ struct snd_usb_midi_endpoint;
struct usb_protocol_ops {
void (*input)(struct snd_usb_midi_in_endpoint*, uint8_t*, int);
- void (*output)(struct snd_usb_midi_out_endpoint*);
+ void (*output)(struct snd_usb_midi_out_endpoint *ep, struct urb *urb);
void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t);
void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint*);
void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint*);
@@ -116,11 +120,15 @@ struct snd_usb_midi {
struct snd_usb_midi_out_endpoint {
struct snd_usb_midi* umidi;
- struct urb* urb;
- int urb_active;
+ struct out_urb_context {
+ struct urb *urb;
+ struct snd_usb_midi_out_endpoint *ep;
+ } urbs[OUTPUT_URBS];
+ unsigned int active_urbs;
+ unsigned int drain_urbs;
int max_transfer; /* size of urb buffer */
struct tasklet_struct tasklet;
-
+ unsigned int next_urb;
spinlock_t buffer_lock;
struct usbmidi_out_port {
@@ -139,11 +147,13 @@ struct snd_usb_midi_out_endpoint {
uint8_t data[2];
} ports[0x10];
int current_port;
+
+ wait_queue_head_t drain_wait;
};
struct snd_usb_midi_in_endpoint {
struct snd_usb_midi* umidi;
- struct urb* urb;
+ struct urb* urbs[INPUT_URBS];
struct usbmidi_in_port {
struct snd_rawmidi_substream *substream;
u8 running_status_length;
@@ -251,10 +261,17 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
static void snd_usbmidi_out_urb_complete(struct urb* urb)
{
- struct snd_usb_midi_out_endpoint* ep = urb->context;
+ struct out_urb_context *context = urb->context;
+ struct snd_usb_midi_out_endpoint* ep = context->ep;
+ unsigned int urb_index;
spin_lock(&ep->buffer_lock);
- ep->urb_active = 0;
+ urb_index = context - ep->urbs;
+ ep->active_urbs &= ~(1 << urb_index);
+ if (unlikely(ep->drain_urbs)) {
+ ep->drain_urbs &= ~(1 << urb_index);
+ wake_up(&ep->drain_wait);
+ }
spin_unlock(&ep->buffer_lock);
if (urb->status < 0) {
int err = snd_usbmidi_urb_error(urb->status);
@@ -274,24 +291,38 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
*/
static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
{
- struct urb* urb = ep->urb;
+ unsigned int urb_index;
+ struct urb* urb;
unsigned long flags;
spin_lock_irqsave(&ep->buffer_lock, flags);
- if (ep->urb_active || ep->umidi->chip->shutdown) {
+ if (ep->umidi->chip->shutdown) {
spin_unlock_irqrestore(&ep->buffer_lock, flags);
return;
}
- urb->transfer_buffer_length = 0;
- ep->umidi->usb_protocol_ops->output(ep);
+ urb_index = ep->next_urb;
+ for (;;) {
+ if (!(ep->active_urbs & (1 << urb_index))) {
+ urb = ep->urbs[urb_index].urb;
+ urb->transfer_buffer_length = 0;
+ ep->umidi->usb_protocol_ops->output(ep, urb);
+ if (urb->transfer_buffer_length == 0)
+ break;
- if (urb->transfer_buffer_length > 0) {
- dump_urb("sending", urb->transfer_buffer,
- urb->transfer_buffer_length);
- urb->dev = ep->umidi->chip->dev;
- ep->urb_active = snd_usbmidi_submit_urb(urb, GFP_ATOMIC) >= 0;
+ dump_urb("sending", urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->dev = ep->umidi->chip->dev;
+ if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0)
+ break;
+ ep->active_urbs |= 1 << urb_index;
+ }
+ if (++urb_index >= OUTPUT_URBS)
+ urb_index = 0;
+ if (urb_index == ep->next_urb)
+ break;
}
+ ep->next_urb = urb_index;
spin_unlock_irqrestore(&ep->buffer_lock, flags);
}
@@ -306,7 +337,7 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
static void snd_usbmidi_error_timer(unsigned long data)
{
struct snd_usb_midi *umidi = (struct snd_usb_midi *)data;
- int i;
+ unsigned int i, j;
spin_lock(&umidi->disc_lock);
if (umidi->disconnected) {
@@ -317,8 +348,10 @@ static void snd_usbmidi_error_timer(unsigned long data)
struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in;
if (in && in->error_resubmit) {
in->error_resubmit = 0;
- in->urb->dev = umidi->chip->dev;
- snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
+ for (j = 0; j < INPUT_URBS; ++j) {
+ in->urbs[j]->dev = umidi->chip->dev;
+ snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
+ }
}
if (umidi->endpoints[i].out)
snd_usbmidi_do_output(umidi->endpoints[i].out);
@@ -330,13 +363,14 @@ static void snd_usbmidi_error_timer(unsigned long data)
static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep,
const void *data, int len)
{
- int err;
+ int err = 0;
void *buf = kmemdup(data, len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
dump_urb("sending", buf, len);
- err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len,
- NULL, 250);
+ if (ep->urbs[0].urb)
+ err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe,
+ buf, len, NULL, 250);
kfree(buf);
return err;
}
@@ -554,9 +588,9 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port,
}
}
-static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep,
+ struct urb *urb)
{
- struct urb* urb = ep->urb;
int p;
/* FIXME: lower-numbered ports can starve higher-numbered ports */
@@ -613,14 +647,15 @@ static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint* ep,
snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1);
}
-static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep,
+ struct urb *urb)
{
uint8_t* transfer_buffer;
int count;
if (!ep->ports[0].active)
return;
- transfer_buffer = ep->urb->transfer_buffer;
+ transfer_buffer = urb->transfer_buffer;
count = snd_rawmidi_transmit(ep->ports[0].substream,
&transfer_buffer[2],
ep->max_transfer - 2);
@@ -630,7 +665,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep)
}
transfer_buffer[0] = 0;
transfer_buffer[1] = count;
- ep->urb->transfer_buffer_length = 2 + count;
+ urb->transfer_buffer_length = 2 + count;
}
static struct usb_protocol_ops snd_usbmidi_novation_ops = {
@@ -648,20 +683,21 @@ static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,
snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
}
-static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep,
+ struct urb *urb)
{
int count;
if (!ep->ports[0].active)
return;
count = snd_rawmidi_transmit(ep->ports[0].substream,
- ep->urb->transfer_buffer,
+ urb->transfer_buffer,
ep->max_transfer);
if (count < 1) {
ep->ports[0].active = 0;
return;
}
- ep->urb->transfer_buffer_length = count;
+ urb->transfer_buffer_length = count;
}
static struct usb_protocol_ops snd_usbmidi_raw_ops = {
@@ -681,23 +717,25 @@ static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,
snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
}
-static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep)
+static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
+ struct urb *urb)
{
int count;
if (!ep->ports[0].active)
return;
- count = ep->urb->dev->speed == USB_SPEED_HIGH ? 1 : 2;
+ count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH
+ ? 1 : 2;
count = snd_rawmidi_transmit(ep->ports[0].substream,
- ep->urb->transfer_buffer,
+ urb->transfer_buffer,
count);
if (count < 1) {
ep->ports[0].active = 0;
return;
}
- memset(ep->urb->transfer_buffer + count, 0xFD, 9 - count);
- ep->urb->transfer_buffer_length = count;
+ memset(urb->transfer_buffer + count, 0xFD, 9 - count);
+ urb->transfer_buffer_length = count;
}
static struct usb_protocol_ops snd_usbmidi_122l_ops = {
@@ -786,10 +824,11 @@ static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep,
}
}
-static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep,
+ struct urb *urb)
{
int port0 = ep->current_port;
- uint8_t* buf = ep->urb->transfer_buffer;
+ uint8_t* buf = urb->transfer_buffer;
int buf_free = ep->max_transfer;
int length, i;
@@ -829,7 +868,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep)
*buf = 0xff;
--buf_free;
}
- ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
+ urb->transfer_buffer_length = ep->max_transfer - buf_free;
}
static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
@@ -884,6 +923,35 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
}
}
+static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
+{
+ struct usbmidi_out_port* port = substream->runtime->private_data;
+ struct snd_usb_midi_out_endpoint *ep = port->ep;
+ unsigned int drain_urbs;
+ DEFINE_WAIT(wait);
+ long timeout = msecs_to_jiffies(50);
+
+ /*
+ * The substream buffer is empty, but some data might still be in the
+ * currently active URBs, so we have to wait for those to complete.
+ */
+ spin_lock_irq(&ep->buffer_lock);
+ drain_urbs = ep->active_urbs;
+ if (drain_urbs) {
+ ep->drain_urbs |= drain_urbs;
+ do {
+ prepare_to_wait(&ep->drain_wait, &wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&ep->buffer_lock);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irq(&ep->buffer_lock);
+ drain_urbs &= ep->drain_urbs;
+ } while (drain_urbs && timeout);
+ finish_wait(&ep->drain_wait, &wait);
+ }
+ spin_unlock_irq(&ep->buffer_lock);
+}
+
static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
{
return 0;
@@ -908,6 +976,7 @@ static struct snd_rawmidi_ops snd_usbmidi_output_ops = {
.open = snd_usbmidi_output_open,
.close = snd_usbmidi_output_close,
.trigger = snd_usbmidi_output_trigger,
+ .drain = snd_usbmidi_output_drain,
};
static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
@@ -916,19 +985,26 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
.trigger = snd_usbmidi_input_trigger
};
+static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb,
+ unsigned int buffer_length)
+{
+ usb_buffer_free(umidi->chip->dev, buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+}
+
/*
* Frees an input endpoint.
* May be called when ep hasn't been initialized completely.
*/
static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep)
{
- if (ep->urb) {
- usb_buffer_free(ep->umidi->chip->dev,
- ep->urb->transfer_buffer_length,
- ep->urb->transfer_buffer,
- ep->urb->transfer_dma);
- usb_free_urb(ep->urb);
- }
+ unsigned int i;
+
+ for (i = 0; i < INPUT_URBS; ++i)
+ if (ep->urbs[i])
+ free_urb_and_buffer(ep->umidi, ep->urbs[i],
+ ep->urbs[i]->transfer_buffer_length);
kfree(ep);
}
@@ -943,6 +1019,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
void* buffer;
unsigned int pipe;
int length;
+ unsigned int i;
rep->in = NULL;
ep = kzalloc(sizeof(*ep), GFP_KERNEL);
@@ -950,30 +1027,36 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
return -ENOMEM;
ep->umidi = umidi;
- ep->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!ep->urb) {
- snd_usbmidi_in_endpoint_delete(ep);
- return -ENOMEM;
+ for (i = 0; i < INPUT_URBS; ++i) {
+ ep->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ep->urbs[i]) {
+ snd_usbmidi_in_endpoint_delete(ep);
+ return -ENOMEM;
+ }
}
if (ep_info->in_interval)
pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);
else
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
- buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
- &ep->urb->transfer_dma);
- if (!buffer) {
- snd_usbmidi_in_endpoint_delete(ep);
- return -ENOMEM;
+ for (i = 0; i < INPUT_URBS; ++i) {
+ buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
+ &ep->urbs[i]->transfer_dma);
+ if (!buffer) {
+ snd_usbmidi_in_endpoint_delete(ep);
+ return -ENOMEM;
+ }
+ if (ep_info->in_interval)
+ usb_fill_int_urb(ep->urbs[i], umidi->chip->dev,
+ pipe, buffer, length,
+ snd_usbmidi_in_urb_complete,
+ ep, ep_info->in_interval);
+ else
+ usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev,
+ pipe, buffer, length,
+ snd_usbmidi_in_urb_complete, ep);
+ ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
}
- if (ep_info->in_interval)
- usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer,
- length, snd_usbmidi_in_urb_complete, ep,
- ep_info->in_interval);
- else
- usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
- length, snd_usbmidi_in_urb_complete, ep);
- ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
rep->in = ep;
return 0;
@@ -994,12 +1077,12 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x)
*/
static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep)
{
- if (ep->urb) {
- usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
- ep->urb->transfer_buffer,
- ep->urb->transfer_dma);
- usb_free_urb(ep->urb);
- }
+ unsigned int i;
+
+ for (i = 0; i < OUTPUT_URBS; ++i)
+ if (ep->urbs[i].urb)
+ free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
+ ep->max_transfer);
kfree(ep);
}
@@ -1011,7 +1094,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
struct snd_usb_midi_endpoint* rep)
{
struct snd_usb_midi_out_endpoint* ep;
- int i;
+ unsigned int i;
unsigned int pipe;
void* buffer;
@@ -1021,38 +1104,46 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
return -ENOMEM;
ep->umidi = umidi;
- ep->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!ep->urb) {
- snd_usbmidi_out_endpoint_delete(ep);
- return -ENOMEM;
+ for (i = 0; i < OUTPUT_URBS; ++i) {
+ ep->urbs[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ep->urbs[i].urb) {
+ snd_usbmidi_out_endpoint_delete(ep);
+ return -ENOMEM;
+ }
+ ep->urbs[i].ep = ep;
}
if (ep_info->out_interval)
pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep);
else
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
- /* FIXME: we need more URBs to get reasonable bandwidth here: */
ep->max_transfer = 4;
else
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
- buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
- GFP_KERNEL, &ep->urb->transfer_dma);
- if (!buffer) {
- snd_usbmidi_out_endpoint_delete(ep);
- return -ENOMEM;
+ for (i = 0; i < OUTPUT_URBS; ++i) {
+ buffer = usb_buffer_alloc(umidi->chip->dev,
+ ep->max_transfer, GFP_KERNEL,
+ &ep->urbs[i].urb->transfer_dma);
+ if (!buffer) {
+ snd_usbmidi_out_endpoint_delete(ep);
+ return -ENOMEM;
+ }
+ if (ep_info->out_interval)
+ usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev,
+ pipe, buffer, ep->max_transfer,
+ snd_usbmidi_out_urb_complete,
+ &ep->urbs[i], ep_info->out_interval);
+ else
+ usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev,
+ pipe, buffer, ep->max_transfer,
+ snd_usbmidi_out_urb_complete,
+ &ep->urbs[i]);
+ ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
}
- if (ep_info->out_interval)
- usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer,
- ep->max_transfer, snd_usbmidi_out_urb_complete,
- ep, ep_info->out_interval);
- else
- usb_fill_bulk_urb(ep->urb, umidi->chip->dev,
- pipe, buffer, ep->max_transfer,
- snd_usbmidi_out_urb_complete, ep);
- ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
spin_lock_init(&ep->buffer_lock);
tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
+ init_waitqueue_head(&ep->drain_wait);
for (i = 0; i < 0x10; ++i)
if (ep_info->out_cables & (1 << i)) {
@@ -1090,7 +1181,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi)
void snd_usbmidi_disconnect(struct list_head* p)
{
struct snd_usb_midi* umidi;
- int i;
+ unsigned int i, j;
umidi = list_entry(p, struct snd_usb_midi, list);
/*
@@ -1105,13 +1196,15 @@ void snd_usbmidi_disconnect(struct list_head* p)
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
if (ep->out)
tasklet_kill(&ep->out->tasklet);
- if (ep->out && ep->out->urb) {
- usb_kill_urb(ep->out->urb);
+ if (ep->out) {
+ for (j = 0; j < OUTPUT_URBS; ++j)
+ usb_kill_urb(ep->out->urbs[j].urb);
if (umidi->usb_protocol_ops->finish_out_endpoint)
umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
}
if (ep->in)
- usb_kill_urb(ep->in->urb);
+ for (j = 0; j < INPUT_URBS; ++j)
+ usb_kill_urb(ep->in->urbs[j]);
/* free endpoints here; later call can result in Oops */
if (ep->out) {
snd_usbmidi_out_endpoint_delete(ep->out);
@@ -1692,20 +1785,25 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
void snd_usbmidi_input_stop(struct list_head* p)
{
struct snd_usb_midi* umidi;
- int i;
+ unsigned int i, j;
umidi = list_entry(p, struct snd_usb_midi, list);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
if (ep->in)
- usb_kill_urb(ep->in->urb);
+ for (j = 0; j < INPUT_URBS; ++j)
+ usb_kill_urb(ep->in->urbs[j]);
}
}
static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
{
- if (ep) {
- struct urb* urb = ep->urb;
+ unsigned int i;
+
+ if (!ep)
+ return;
+ for (i = 0; i < INPUT_URBS; ++i) {
+ struct urb* urb = ep->urbs[i];
urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(urb, GFP_KERNEL);
}
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 4bd3a7a0edc1..ab5a3ac2ac47 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -86,6 +86,7 @@ struct usb_mixer_interface {
u8 rc_buffer[6];
u8 audigy2nx_leds[3];
+ u8 xonar_u1_status;
};
@@ -461,7 +462,7 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv)
{
struct usb_mixer_elem_info *cval = kcontrol->private_data;
- DECLARE_TLV_DB_SCALE(scale, 0, 0, 0);
+ DECLARE_TLV_DB_MINMAX(scale, 0, 0);
if (size < sizeof(scale))
return -ENOMEM;
@@ -469,7 +470,16 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
* while ALSA TLV contains in 1/100 dB unit
*/
scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
- scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256;
+ scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
+ if (scale[3] <= scale[2]) {
+ /* something is wrong; assume it's either from/to 0dB */
+ if (scale[2] < 0)
+ scale[3] = 0;
+ else if (scale[2] > 0)
+ scale[2] = 0;
+ else /* totally crap, return an error */
+ return -EINVAL;
+ }
if (copy_to_user(_tlv, scale, sizeof(scale)))
return -EFAULT;
return 0;
@@ -990,20 +1000,35 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
break;
}
- /* quirk for UDA1321/N101 */
- /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
- /* is not very clear from datasheets */
- /* I hope that the min value is -15360 for newer firmware --jk */
+ /* volume control quirks */
switch (state->chip->usb_id) {
case USB_ID(0x0471, 0x0101):
case USB_ID(0x0471, 0x0104):
case USB_ID(0x0471, 0x0105):
case USB_ID(0x0672, 0x1041):
+ /* quirk for UDA1321/N101.
+ * note that detection between firmware 2.1.1.7 (N101)
+ * and later 2.1.1.21 is not very clear from datasheets.
+ * I hope that the min value is -15360 for newer firmware --jk
+ */
if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
cval->min == -15616) {
- snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n");
+ snd_printk(KERN_INFO
+ "set volume quirk for UDA1321/N101 chip\n");
cval->max = -256;
}
+ break;
+
+ case USB_ID(0x046d, 0x09a4):
+ if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+ snd_printk(KERN_INFO
+ "set volume quirk for QuickCam E3500\n");
+ cval->min = 6080;
+ cval->max = 8768;
+ cval->res = 192;
+ }
+ break;
+
}
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
@@ -2018,6 +2043,58 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
}
}
+static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
+ return 0;
+}
+
+static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ u8 old_status, new_status;
+ int err, changed;
+
+ old_status = mixer->xonar_u1_status;
+ if (ucontrol->value.integer.value[0])
+ new_status = old_status | 0x02;
+ else
+ new_status = old_status & ~0x02;
+ changed = new_status != old_status;
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ 50, 0, &new_status, 1, 100);
+ if (err < 0)
+ return err;
+ mixer->xonar_u1_status = new_status;
+ return changed;
+}
+
+static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_xonar_u1_switch_get,
+ .put = snd_xonar_u1_switch_put,
+};
+
+static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ err = snd_ctl_add(mixer->chip->card,
+ snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
+ if (err < 0)
+ return err;
+ mixer->xonar_u1_status = 0x05;
+ return 0;
+}
+
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
int ignore_error)
{
@@ -2060,6 +2137,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
snd_audigy2nx_proc_read);
}
+ if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) ||
+ mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) {
+ err = snd_xonar_u1_controls_create(mixer);
+ if (err < 0)
+ goto _error;
+ }
+
err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
if (err < 0)
goto _error;
diff --git a/usr/Makefile b/usr/Makefile
index 245145a99c10..1e6a9e4a72cc 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -6,7 +6,7 @@ klibcdirs:;
PHONY += klibcdirs
-# Gzip, but no bzip2
+# Gzip
suffix_$(CONFIG_INITRAMFS_COMPRESSION_GZIP) = .gz
# Bzip2
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
new file mode 100644
index 000000000000..daece36c0a57
--- /dev/null
+++ b/virt/kvm/Kconfig
@@ -0,0 +1,14 @@
+# KVM common configuration items and defaults
+
+config HAVE_KVM
+ bool
+
+config HAVE_KVM_IRQCHIP
+ bool
+
+config HAVE_KVM_EVENTFD
+ bool
+ select EVENTFD
+
+config KVM_APIC_ARCHITECTURE
+ bool
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 5ae620d32fac..04d69cd7049b 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -14,32 +14,28 @@
#include "coalesced_mmio.h"
-static int coalesced_mmio_in_range(struct kvm_io_device *this,
- gpa_t addr, int len, int is_write)
+static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)
+{
+ return container_of(dev, struct kvm_coalesced_mmio_dev, dev);
+}
+
+static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
+ gpa_t addr, int len)
{
- struct kvm_coalesced_mmio_dev *dev =
- (struct kvm_coalesced_mmio_dev*)this->private;
struct kvm_coalesced_mmio_zone *zone;
- int next;
+ struct kvm_coalesced_mmio_ring *ring;
+ unsigned avail;
int i;
- if (!is_write)
- return 0;
-
- /* kvm->lock is taken by the caller and must be not released before
- * dev.read/write
- */
-
/* Are we able to batch it ? */
/* last is the first free entry
* check if we don't meet the first used entry
* there is always one unused entry in the buffer
*/
-
- next = (dev->kvm->coalesced_mmio_ring->last + 1) %
- KVM_COALESCED_MMIO_MAX;
- if (next == dev->kvm->coalesced_mmio_ring->first) {
+ ring = dev->kvm->coalesced_mmio_ring;
+ avail = (ring->first - ring->last - 1) % KVM_COALESCED_MMIO_MAX;
+ if (avail < KVM_MAX_VCPUS) {
/* full */
return 0;
}
@@ -60,14 +56,15 @@ static int coalesced_mmio_in_range(struct kvm_io_device *this,
return 0;
}
-static void coalesced_mmio_write(struct kvm_io_device *this,
- gpa_t addr, int len, const void *val)
+static int coalesced_mmio_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *val)
{
- struct kvm_coalesced_mmio_dev *dev =
- (struct kvm_coalesced_mmio_dev*)this->private;
+ struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
+ if (!coalesced_mmio_in_range(dev, addr, len))
+ return -EOPNOTSUPP;
- /* kvm->lock must be taken by caller before call to in_range()*/
+ spin_lock(&dev->lock);
/* copy data in first free entry of the ring */
@@ -76,29 +73,40 @@ static void coalesced_mmio_write(struct kvm_io_device *this,
memcpy(ring->coalesced_mmio[ring->last].data, val, len);
smp_wmb();
ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX;
+ spin_unlock(&dev->lock);
+ return 0;
}
static void coalesced_mmio_destructor(struct kvm_io_device *this)
{
- kfree(this);
+ struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
+
+ kfree(dev);
}
+static const struct kvm_io_device_ops coalesced_mmio_ops = {
+ .write = coalesced_mmio_write,
+ .destructor = coalesced_mmio_destructor,
+};
+
int kvm_coalesced_mmio_init(struct kvm *kvm)
{
struct kvm_coalesced_mmio_dev *dev;
+ int ret;
dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- dev->dev.write = coalesced_mmio_write;
- dev->dev.in_range = coalesced_mmio_in_range;
- dev->dev.destructor = coalesced_mmio_destructor;
- dev->dev.private = dev;
+ spin_lock_init(&dev->lock);
+ kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
dev->kvm = kvm;
kvm->coalesced_mmio_dev = dev;
- kvm_io_bus_register_dev(&kvm->mmio_bus, &dev->dev);
- return 0;
+ ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
+ if (ret < 0)
+ kfree(dev);
+
+ return ret;
}
int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
@@ -109,16 +117,16 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
if (dev == NULL)
return -EINVAL;
- mutex_lock(&kvm->lock);
+ down_write(&kvm->slots_lock);
if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) {
- mutex_unlock(&kvm->lock);
+ up_write(&kvm->slots_lock);
return -ENOBUFS;
}
dev->zone[dev->nb_zones] = *zone;
dev->nb_zones++;
- mutex_unlock(&kvm->lock);
+ up_write(&kvm->slots_lock);
return 0;
}
@@ -132,7 +140,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
if (dev == NULL)
return -EINVAL;
- mutex_lock(&kvm->lock);
+ down_write(&kvm->slots_lock);
i = dev->nb_zones;
while(i) {
@@ -150,7 +158,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
i--;
}
- mutex_unlock(&kvm->lock);
+ up_write(&kvm->slots_lock);
return 0;
}
diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h
index 5ac0ec628461..4b49f27fa31e 100644
--- a/virt/kvm/coalesced_mmio.h
+++ b/virt/kvm/coalesced_mmio.h
@@ -12,6 +12,7 @@
struct kvm_coalesced_mmio_dev {
struct kvm_io_device dev;
struct kvm *kvm;
+ spinlock_t lock;
int nb_zones;
struct kvm_coalesced_mmio_zone zone[KVM_COALESCED_MMIO_ZONE_MAX];
};
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
new file mode 100644
index 000000000000..99017e8a92ac
--- /dev/null
+++ b/virt/kvm/eventfd.c
@@ -0,0 +1,578 @@
+/*
+ * kvm eventfd support - use eventfd objects to signal various KVM events
+ *
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/workqueue.h>
+#include <linux/syscalls.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/list.h>
+#include <linux/eventfd.h>
+#include <linux/kernel.h>
+
+#include "iodev.h"
+
+/*
+ * --------------------------------------------------------------------
+ * irqfd: Allows an fd to be used to inject an interrupt to the guest
+ *
+ * Credit goes to Avi Kivity for the original idea.
+ * --------------------------------------------------------------------
+ */
+
+struct _irqfd {
+ struct kvm *kvm;
+ struct eventfd_ctx *eventfd;
+ int gsi;
+ struct list_head list;
+ poll_table pt;
+ wait_queue_head_t *wqh;
+ wait_queue_t wait;
+ struct work_struct inject;
+ struct work_struct shutdown;
+};
+
+static struct workqueue_struct *irqfd_cleanup_wq;
+
+static void
+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);
+}
+
+/*
+ * Race-free decouple logic (ordering is critical)
+ */
+static void
+irqfd_shutdown(struct work_struct *work)
+{
+ struct _irqfd *irqfd = container_of(work, struct _irqfd, shutdown);
+
+ /*
+ * Synchronize with the wait-queue and unhook ourselves to prevent
+ * further events.
+ */
+ remove_wait_queue(irqfd->wqh, &irqfd->wait);
+
+ /*
+ * We know no new events will be scheduled at this point, so block
+ * until all previously outstanding events have completed
+ */
+ flush_work(&irqfd->inject);
+
+ /*
+ * It is now safe to release the object's resources
+ */
+ eventfd_ctx_put(irqfd->eventfd);
+ kfree(irqfd);
+}
+
+
+/* assumes kvm->irqfds.lock is held */
+static bool
+irqfd_is_active(struct _irqfd *irqfd)
+{
+ return list_empty(&irqfd->list) ? false : true;
+}
+
+/*
+ * Mark the irqfd as inactive and schedule it for removal
+ *
+ * assumes kvm->irqfds.lock is held
+ */
+static void
+irqfd_deactivate(struct _irqfd *irqfd)
+{
+ BUG_ON(!irqfd_is_active(irqfd));
+
+ list_del_init(&irqfd->list);
+
+ queue_work(irqfd_cleanup_wq, &irqfd->shutdown);
+}
+
+/*
+ * Called with wqh->lock held and interrupts disabled
+ */
+static int
+irqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct _irqfd *irqfd = container_of(wait, struct _irqfd, wait);
+ unsigned long flags = (unsigned long)key;
+
+ if (flags & POLLIN)
+ /* An event has been signaled, inject an interrupt */
+ schedule_work(&irqfd->inject);
+
+ if (flags & POLLHUP) {
+ /* The eventfd is closing, detach from KVM */
+ struct kvm *kvm = irqfd->kvm;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kvm->irqfds.lock, flags);
+
+ /*
+ * We must check if someone deactivated the irqfd before
+ * we could acquire the irqfds.lock since the item is
+ * deactivated from the KVM side before it is unhooked from
+ * the wait-queue. If it is already deactivated, we can
+ * simply return knowing the other side will cleanup for us.
+ * We cannot race against the irqfd going away since the
+ * other side is required to acquire wqh->lock, which we hold
+ */
+ if (irqfd_is_active(irqfd))
+ irqfd_deactivate(irqfd);
+
+ spin_unlock_irqrestore(&kvm->irqfds.lock, flags);
+ }
+
+ return 0;
+}
+
+static void
+irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh,
+ poll_table *pt)
+{
+ struct _irqfd *irqfd = container_of(pt, struct _irqfd, pt);
+
+ irqfd->wqh = wqh;
+ add_wait_queue(wqh, &irqfd->wait);
+}
+
+static int
+kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
+{
+ struct _irqfd *irqfd;
+ struct file *file = NULL;
+ struct eventfd_ctx *eventfd = NULL;
+ int ret;
+ unsigned int events;
+
+ irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
+ if (!irqfd)
+ return -ENOMEM;
+
+ irqfd->kvm = kvm;
+ irqfd->gsi = gsi;
+ INIT_LIST_HEAD(&irqfd->list);
+ INIT_WORK(&irqfd->inject, irqfd_inject);
+ INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
+
+ file = eventfd_fget(fd);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto fail;
+ }
+
+ eventfd = eventfd_ctx_fileget(file);
+ if (IS_ERR(eventfd)) {
+ ret = PTR_ERR(eventfd);
+ goto fail;
+ }
+
+ irqfd->eventfd = eventfd;
+
+ /*
+ * Install our own custom wake-up handling so we are notified via
+ * a callback whenever someone signals the underlying eventfd
+ */
+ init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
+ init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc);
+
+ events = file->f_op->poll(file, &irqfd->pt);
+
+ spin_lock_irq(&kvm->irqfds.lock);
+ list_add_tail(&irqfd->list, &kvm->irqfds.items);
+ spin_unlock_irq(&kvm->irqfds.lock);
+
+ /*
+ * Check if there was an event already pending on the eventfd
+ * before we registered, and trigger it as if we didn't miss it.
+ */
+ if (events & POLLIN)
+ schedule_work(&irqfd->inject);
+
+ /*
+ * do not drop the file until the irqfd is fully initialized, otherwise
+ * we might race against the POLLHUP
+ */
+ fput(file);
+
+ return 0;
+
+fail:
+ if (eventfd && !IS_ERR(eventfd))
+ eventfd_ctx_put(eventfd);
+
+ if (file && !IS_ERR(file))
+ fput(file);
+
+ kfree(irqfd);
+ return ret;
+}
+
+void
+kvm_eventfd_init(struct kvm *kvm)
+{
+ spin_lock_init(&kvm->irqfds.lock);
+ INIT_LIST_HEAD(&kvm->irqfds.items);
+ INIT_LIST_HEAD(&kvm->ioeventfds);
+}
+
+/*
+ * shutdown any irqfd's that match fd+gsi
+ */
+static int
+kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
+{
+ struct _irqfd *irqfd, *tmp;
+ struct eventfd_ctx *eventfd;
+
+ eventfd = eventfd_ctx_fdget(fd);
+ if (IS_ERR(eventfd))
+ return PTR_ERR(eventfd);
+
+ spin_lock_irq(&kvm->irqfds.lock);
+
+ list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) {
+ if (irqfd->eventfd == eventfd && irqfd->gsi == gsi)
+ irqfd_deactivate(irqfd);
+ }
+
+ spin_unlock_irq(&kvm->irqfds.lock);
+ eventfd_ctx_put(eventfd);
+
+ /*
+ * Block until we know all outstanding shutdown jobs have completed
+ * so that we guarantee there will not be any more interrupts on this
+ * gsi once this deassign function returns.
+ */
+ flush_workqueue(irqfd_cleanup_wq);
+
+ return 0;
+}
+
+int
+kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+{
+ if (flags & KVM_IRQFD_FLAG_DEASSIGN)
+ return kvm_irqfd_deassign(kvm, fd, gsi);
+
+ return kvm_irqfd_assign(kvm, fd, gsi);
+}
+
+/*
+ * This function is called as the kvm VM fd is being released. Shutdown all
+ * irqfds that still remain open
+ */
+void
+kvm_irqfd_release(struct kvm *kvm)
+{
+ struct _irqfd *irqfd, *tmp;
+
+ spin_lock_irq(&kvm->irqfds.lock);
+
+ list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list)
+ irqfd_deactivate(irqfd);
+
+ spin_unlock_irq(&kvm->irqfds.lock);
+
+ /*
+ * Block until we know all outstanding shutdown jobs have completed
+ * since we do not take a kvm* reference.
+ */
+ flush_workqueue(irqfd_cleanup_wq);
+
+}
+
+/*
+ * create a host-wide workqueue for issuing deferred shutdown requests
+ * aggregated from all vm* instances. We need our own isolated single-thread
+ * queue to prevent deadlock against flushing the normal work-queue.
+ */
+static int __init irqfd_module_init(void)
+{
+ irqfd_cleanup_wq = create_singlethread_workqueue("kvm-irqfd-cleanup");
+ if (!irqfd_cleanup_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit irqfd_module_exit(void)
+{
+ destroy_workqueue(irqfd_cleanup_wq);
+}
+
+module_init(irqfd_module_init);
+module_exit(irqfd_module_exit);
+
+/*
+ * --------------------------------------------------------------------
+ * ioeventfd: translate a PIO/MMIO memory write to an eventfd signal.
+ *
+ * userspace can register a PIO/MMIO address with an eventfd for receiving
+ * notification when the memory has been touched.
+ * --------------------------------------------------------------------
+ */
+
+struct _ioeventfd {
+ struct list_head list;
+ u64 addr;
+ int length;
+ struct eventfd_ctx *eventfd;
+ u64 datamatch;
+ struct kvm_io_device dev;
+ bool wildcard;
+};
+
+static inline struct _ioeventfd *
+to_ioeventfd(struct kvm_io_device *dev)
+{
+ return container_of(dev, struct _ioeventfd, dev);
+}
+
+static void
+ioeventfd_release(struct _ioeventfd *p)
+{
+ eventfd_ctx_put(p->eventfd);
+ list_del(&p->list);
+ kfree(p);
+}
+
+static bool
+ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val)
+{
+ u64 _val;
+
+ if (!(addr == p->addr && len == p->length))
+ /* address-range must be precise for a hit */
+ return false;
+
+ if (p->wildcard)
+ /* all else equal, wildcard is always a hit */
+ return true;
+
+ /* otherwise, we have to actually compare the data */
+
+ BUG_ON(!IS_ALIGNED((unsigned long)val, len));
+
+ switch (len) {
+ case 1:
+ _val = *(u8 *)val;
+ break;
+ case 2:
+ _val = *(u16 *)val;
+ break;
+ case 4:
+ _val = *(u32 *)val;
+ break;
+ case 8:
+ _val = *(u64 *)val;
+ break;
+ default:
+ return false;
+ }
+
+ return _val == p->datamatch ? true : false;
+}
+
+/* MMIO/PIO writes trigger an event if the addr/val match */
+static int
+ioeventfd_write(struct kvm_io_device *this, gpa_t addr, int len,
+ const void *val)
+{
+ struct _ioeventfd *p = to_ioeventfd(this);
+
+ if (!ioeventfd_in_range(p, addr, len, val))
+ return -EOPNOTSUPP;
+
+ eventfd_signal(p->eventfd, 1);
+ return 0;
+}
+
+/*
+ * This function is called as KVM is completely shutting down. We do not
+ * need to worry about locking just nuke anything we have as quickly as possible
+ */
+static void
+ioeventfd_destructor(struct kvm_io_device *this)
+{
+ struct _ioeventfd *p = to_ioeventfd(this);
+
+ ioeventfd_release(p);
+}
+
+static const struct kvm_io_device_ops ioeventfd_ops = {
+ .write = ioeventfd_write,
+ .destructor = ioeventfd_destructor,
+};
+
+/* assumes kvm->slots_lock held */
+static bool
+ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p)
+{
+ struct _ioeventfd *_p;
+
+ list_for_each_entry(_p, &kvm->ioeventfds, list)
+ if (_p->addr == p->addr && _p->length == p->length &&
+ (_p->wildcard || p->wildcard ||
+ _p->datamatch == p->datamatch))
+ return true;
+
+ return false;
+}
+
+static int
+kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
+{
+ int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO;
+ struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+ struct _ioeventfd *p;
+ struct eventfd_ctx *eventfd;
+ int ret;
+
+ /* must be natural-word sized */
+ switch (args->len) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* check for range overflow */
+ if (args->addr + args->len < args->addr)
+ return -EINVAL;
+
+ /* check for extra flags that we don't understand */
+ if (args->flags & ~KVM_IOEVENTFD_VALID_FLAG_MASK)
+ return -EINVAL;
+
+ eventfd = eventfd_ctx_fdget(args->fd);
+ if (IS_ERR(eventfd))
+ return PTR_ERR(eventfd);
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ INIT_LIST_HEAD(&p->list);
+ p->addr = args->addr;
+ p->length = args->len;
+ p->eventfd = eventfd;
+
+ /* The datamatch feature is optional, otherwise this is a wildcard */
+ if (args->flags & KVM_IOEVENTFD_FLAG_DATAMATCH)
+ p->datamatch = args->datamatch;
+ else
+ p->wildcard = true;
+
+ down_write(&kvm->slots_lock);
+
+ /* Verify that there isnt a match already */
+ if (ioeventfd_check_collision(kvm, p)) {
+ ret = -EEXIST;
+ goto unlock_fail;
+ }
+
+ kvm_iodevice_init(&p->dev, &ioeventfd_ops);
+
+ ret = __kvm_io_bus_register_dev(bus, &p->dev);
+ if (ret < 0)
+ goto unlock_fail;
+
+ list_add_tail(&p->list, &kvm->ioeventfds);
+
+ up_write(&kvm->slots_lock);
+
+ return 0;
+
+unlock_fail:
+ up_write(&kvm->slots_lock);
+
+fail:
+ kfree(p);
+ eventfd_ctx_put(eventfd);
+
+ return ret;
+}
+
+static int
+kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
+{
+ int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO;
+ struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+ struct _ioeventfd *p, *tmp;
+ struct eventfd_ctx *eventfd;
+ int ret = -ENOENT;
+
+ eventfd = eventfd_ctx_fdget(args->fd);
+ if (IS_ERR(eventfd))
+ return PTR_ERR(eventfd);
+
+ down_write(&kvm->slots_lock);
+
+ list_for_each_entry_safe(p, tmp, &kvm->ioeventfds, list) {
+ bool wildcard = !(args->flags & KVM_IOEVENTFD_FLAG_DATAMATCH);
+
+ if (p->eventfd != eventfd ||
+ p->addr != args->addr ||
+ p->length != args->len ||
+ p->wildcard != wildcard)
+ continue;
+
+ if (!p->wildcard && p->datamatch != args->datamatch)
+ continue;
+
+ __kvm_io_bus_unregister_dev(bus, &p->dev);
+ ioeventfd_release(p);
+ ret = 0;
+ break;
+ }
+
+ up_write(&kvm->slots_lock);
+
+ eventfd_ctx_put(eventfd);
+
+ return ret;
+}
+
+int
+kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
+{
+ if (args->flags & KVM_IOEVENTFD_FLAG_DEASSIGN)
+ return kvm_deassign_ioeventfd(kvm, args);
+
+ return kvm_assign_ioeventfd(kvm, args);
+}
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 1eddae94bab3..fa05f67423ab 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -36,6 +36,7 @@
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/current.h>
+#include <trace/events/kvm.h>
#include "ioapic.h"
#include "lapic.h"
@@ -95,8 +96,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
pent->fields.remote_irr = 1;
}
- if (!pent->fields.trig_mode)
- ioapic->irr &= ~(1 << idx);
return injected;
}
@@ -105,6 +104,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
{
unsigned index;
bool mask_before, mask_after;
+ union kvm_ioapic_redirect_entry *e;
switch (ioapic->ioregsel) {
case IOAPIC_REG_VERSION:
@@ -124,19 +124,21 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
ioapic_debug("change redir index %x val %x\n", index, val);
if (index >= IOAPIC_NUM_PINS)
return;
- mask_before = ioapic->redirtbl[index].fields.mask;
+ e = &ioapic->redirtbl[index];
+ mask_before = e->fields.mask;
if (ioapic->ioregsel & 1) {
- ioapic->redirtbl[index].bits &= 0xffffffff;
- ioapic->redirtbl[index].bits |= (u64) val << 32;
+ e->bits &= 0xffffffff;
+ e->bits |= (u64) val << 32;
} else {
- ioapic->redirtbl[index].bits &= ~0xffffffffULL;
- ioapic->redirtbl[index].bits |= (u32) val;
- ioapic->redirtbl[index].fields.remote_irr = 0;
+ e->bits &= ~0xffffffffULL;
+ e->bits |= (u32) val;
+ e->fields.remote_irr = 0;
}
- mask_after = ioapic->redirtbl[index].fields.mask;
+ mask_after = e->fields.mask;
if (mask_before != mask_after)
kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after);
- if (ioapic->irr & (1 << index))
+ if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
+ && ioapic->irr & (1 << index))
ioapic_service(ioapic, index);
break;
}
@@ -165,7 +167,9 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
/* Always delivery PIT interrupt to vcpu 0 */
if (irq == 0) {
irqe.dest_mode = 0; /* Physical mode. */
- irqe.dest_id = ioapic->kvm->vcpus[0]->vcpu_id;
+ /* need to read apic_id from apic regiest since
+ * it can be rewritten */
+ irqe.dest_id = ioapic->kvm->bsp_vcpu->vcpu_id;
}
#endif
return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
@@ -184,11 +188,13 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
if (!level)
ioapic->irr &= ~mask;
else {
+ int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
ioapic->irr |= mask;
- if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
- || !entry.fields.remote_irr)
+ if ((edge && old_irr != ioapic->irr) ||
+ (!edge && !entry.fields.remote_irr))
ret = ioapic_service(ioapic, irq);
}
+ trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
}
return ret;
}
@@ -220,24 +226,29 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
__kvm_ioapic_update_eoi(ioapic, i, trigger_mode);
}
-static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
- int len, int is_write)
+static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
{
- struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ return container_of(dev, struct kvm_ioapic, dev);
+}
+static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
+{
return ((addr >= ioapic->base_address &&
(addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
}
-static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
- void *val)
+static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
+ void *val)
{
- struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ struct kvm_ioapic *ioapic = to_ioapic(this);
u32 result;
+ if (!ioapic_in_range(ioapic, addr))
+ return -EOPNOTSUPP;
ioapic_debug("addr %lx\n", (unsigned long)addr);
ASSERT(!(addr & 0xf)); /* check alignment */
+ mutex_lock(&ioapic->kvm->irq_lock);
addr &= 0xff;
switch (addr) {
case IOAPIC_REG_SELECT:
@@ -264,22 +275,28 @@ static void 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;
}
-static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
- const void *val)
+static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
+ const void *val)
{
- struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ struct kvm_ioapic *ioapic = to_ioapic(this);
u32 data;
+ if (!ioapic_in_range(ioapic, addr))
+ return -EOPNOTSUPP;
ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n",
(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);
- return;
+ goto unlock;
}
addr &= 0xff;
@@ -300,6 +317,9 @@ static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
default:
break;
}
+unlock:
+ mutex_unlock(&ioapic->kvm->irq_lock);
+ return 0;
}
void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
@@ -314,21 +334,27 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
ioapic->id = 0;
}
+static const struct kvm_io_device_ops ioapic_mmio_ops = {
+ .read = ioapic_mmio_read,
+ .write = ioapic_mmio_write,
+};
+
int kvm_ioapic_init(struct kvm *kvm)
{
struct kvm_ioapic *ioapic;
+ int ret;
ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
if (!ioapic)
return -ENOMEM;
kvm->arch.vioapic = ioapic;
kvm_ioapic_reset(ioapic);
- ioapic->dev.read = ioapic_mmio_read;
- ioapic->dev.write = ioapic_mmio_write;
- ioapic->dev.in_range = ioapic_in_range;
- ioapic->dev.private = ioapic;
+ kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
ioapic->kvm = kvm;
- kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev);
- return 0;
+ ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
+ if (ret < 0)
+ kfree(ioapic);
+
+ return ret;
}
diff --git a/virt/kvm/iodev.h b/virt/kvm/iodev.h
index 55e8846ac3a6..12fd3caffd2b 100644
--- a/virt/kvm/iodev.h
+++ b/virt/kvm/iodev.h
@@ -17,49 +17,54 @@
#define __KVM_IODEV_H__
#include <linux/kvm_types.h>
+#include <asm/errno.h>
-struct kvm_io_device {
- void (*read)(struct kvm_io_device *this,
+struct kvm_io_device;
+
+/**
+ * kvm_io_device_ops are called under kvm slots_lock.
+ * read and write handlers return 0 if the transaction has been handled,
+ * or non-zero to have it passed to the next device.
+ **/
+struct kvm_io_device_ops {
+ int (*read)(struct kvm_io_device *this,
+ gpa_t addr,
+ int len,
+ void *val);
+ int (*write)(struct kvm_io_device *this,
gpa_t addr,
int len,
- void *val);
- void (*write)(struct kvm_io_device *this,
- gpa_t addr,
- int len,
- const void *val);
- int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len,
- int is_write);
+ const void *val);
void (*destructor)(struct kvm_io_device *this);
+};
- void *private;
+
+struct kvm_io_device {
+ const struct kvm_io_device_ops *ops;
};
-static inline void kvm_iodevice_read(struct kvm_io_device *dev,
- gpa_t addr,
- int len,
- void *val)
+static inline void kvm_iodevice_init(struct kvm_io_device *dev,
+ const struct kvm_io_device_ops *ops)
{
- dev->read(dev, addr, len, val);
+ dev->ops = ops;
}
-static inline void kvm_iodevice_write(struct kvm_io_device *dev,
- gpa_t addr,
- int len,
- const void *val)
+static inline int kvm_iodevice_read(struct kvm_io_device *dev,
+ gpa_t addr, int l, void *v)
{
- dev->write(dev, addr, len, val);
+ return dev->ops->read ? dev->ops->read(dev, addr, l, v) : -EOPNOTSUPP;
}
-static inline int kvm_iodevice_inrange(struct kvm_io_device *dev,
- gpa_t addr, int len, int is_write)
+static inline int kvm_iodevice_write(struct kvm_io_device *dev,
+ gpa_t addr, int l, const void *v)
{
- return dev->in_range(dev, addr, len, is_write);
+ return dev->ops->write ? dev->ops->write(dev, addr, l, v) : -EOPNOTSUPP;
}
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
{
- if (dev->destructor)
- dev->destructor(dev);
+ if (dev->ops->destructor)
+ dev->ops->destructor(dev);
}
#endif /* __KVM_IODEV_H__ */
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index a8bd466d00cc..100c267433b5 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -20,6 +20,7 @@
*/
#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
#include <asm/msidef.h>
#ifdef CONFIG_IA64
@@ -62,14 +63,14 @@ 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");
- for (i = 0; i < KVM_MAX_VCPUS; i++) {
- vcpu = kvm->vcpus[i];
-
- if (!vcpu || !kvm_apic_present(vcpu))
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ if (!kvm_apic_present(vcpu))
continue;
if (!kvm_apic_match_dest(vcpu, src, irq->shorthand,
@@ -99,6 +100,8 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
{
struct kvm_lapic_irq irq;
+ trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data);
+
irq.dest_id = (e->msi.address_lo &
MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
irq.vector = (e->msi.data &
@@ -113,7 +116,7 @@ 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->lock mutex held
+/* 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)
@@ -125,6 +128,10 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
unsigned long *irq_state, sig_level;
int ret = -1;
+ 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];
@@ -134,7 +141,9 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
else
clear_bit(irq_source_id, irq_state);
sig_level = !!(*irq_state);
- } else /* Deal with MSI/MSI-X */
+ } 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
@@ -159,6 +168,8 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
struct hlist_node *n;
unsigned gsi = pin;
+ trace_kvm_ack_irq(irqchip, pin);
+
list_for_each_entry(e, &kvm->irq_routing, link)
if (e->irqchip.irqchip == irqchip &&
e->irqchip.pin == pin) {
@@ -174,19 +185,26 @@ 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)
{
+ mutex_lock(&kvm->irq_lock);
hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list);
+ mutex_unlock(&kvm->irq_lock);
}
-void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian)
+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);
+ mutex_unlock(&kvm->irq_lock);
}
-/* The caller must hold kvm->lock mutex */
int kvm_request_irq_source_id(struct kvm *kvm)
{
unsigned long *bitmap = &kvm->arch.irq_sources_bitmap;
- int irq_source_id = find_first_zero_bit(bitmap,
+ int irq_source_id;
+
+ mutex_lock(&kvm->irq_lock);
+ irq_source_id = find_first_zero_bit(bitmap,
sizeof(kvm->arch.irq_sources_bitmap));
if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
@@ -196,6 +214,7 @@ int kvm_request_irq_source_id(struct kvm *kvm)
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
set_bit(irq_source_id, bitmap);
+ mutex_unlock(&kvm->irq_lock);
return irq_source_id;
}
@@ -206,6 +225,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
+ mutex_lock(&kvm->irq_lock);
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");
@@ -214,19 +234,24 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
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);
+ mutex_unlock(&kvm->irq_lock);
}
void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn)
{
+ mutex_lock(&kvm->irq_lock);
kimn->irq = irq;
hlist_add_head(&kimn->link, &kvm->mask_notifier_list);
+ mutex_unlock(&kvm->irq_lock);
}
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);
+ mutex_unlock(&kvm->irq_lock);
}
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
@@ -234,6 +259,8 @@ 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)
if (kimn->irq == irq)
kimn->func(kimn, mask);
@@ -249,7 +276,9 @@ static void __kvm_free_irq_routing(struct list_head *irq_routing)
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);
}
static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
@@ -323,13 +352,13 @@ int kvm_set_irq_routing(struct kvm *kvm,
e = NULL;
}
- mutex_lock(&kvm->lock);
+ 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);
- mutex_unlock(&kvm->lock);
+ mutex_unlock(&kvm->irq_lock);
r = 0;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2884baf1d5f9..f29fdcd589e6 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -59,9 +59,18 @@
#include "irq.h"
#endif
+#define CREATE_TRACE_POINTS
+#include <trace/events/kvm.h>
+
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
+/*
+ * Ordering of locks:
+ *
+ * kvm->slots_lock --> kvm->lock --> kvm->irq_lock
+ */
+
DEFINE_SPINLOCK(kvm_lock);
LIST_HEAD(vm_list);
@@ -79,6 +88,8 @@ static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
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)
@@ -120,17 +131,13 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
{
struct kvm_assigned_dev_kernel *assigned_dev;
struct kvm *kvm;
- int irq, i;
+ int i;
assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
interrupt_work);
kvm = assigned_dev->kvm;
- /* This is taken to safely inject irq inside the guest. When
- * the interrupt injection (or the ioapic code) uses a
- * finer-grained lock, update this
- */
- mutex_lock(&kvm->lock);
+ 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 =
@@ -143,23 +150,13 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
kvm_set_irq(assigned_dev->kvm,
assigned_dev->irq_source_id,
guest_entries[i].vector, 1);
- irq = assigned_dev->host_msix_entries[i].vector;
- if (irq != 0)
- enable_irq(irq);
- assigned_dev->host_irq_disabled = false;
}
- } else {
+ } else
kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
assigned_dev->guest_irq, 1);
- if (assigned_dev->irq_requested_type &
- KVM_DEV_IRQ_GUEST_MSI) {
- enable_irq(assigned_dev->host_irq);
- assigned_dev->host_irq_disabled = false;
- }
- }
spin_unlock_irq(&assigned_dev->assigned_dev_lock);
- mutex_unlock(&assigned_dev->kvm->lock);
+ mutex_unlock(&assigned_dev->kvm->irq_lock);
}
static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
@@ -179,8 +176,10 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
schedule_work(&assigned_dev->interrupt_work);
- disable_irq_nosync(irq);
- assigned_dev->host_irq_disabled = true;
+ 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);
@@ -215,7 +214,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
static void deassign_guest_irq(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev)
{
- kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier);
+ kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
assigned_dev->ack_notifier.gsi = -1;
if (assigned_dev->irq_source_id != -1)
@@ -417,6 +416,7 @@ static int assigned_device_enable_guest_msi(struct kvm *kvm,
{
dev->guest_irq = irq->guest_irq;
dev->ack_notifier.gsi = -1;
+ dev->host_irq_disabled = false;
return 0;
}
#endif
@@ -427,6 +427,7 @@ static int assigned_device_enable_guest_msix(struct kvm *kvm,
{
dev->guest_irq = irq->guest_irq;
dev->ack_notifier.gsi = -1;
+ dev->host_irq_disabled = false;
return 0;
}
#endif
@@ -693,11 +694,6 @@ out:
}
#endif
-static inline int valid_vcpu(int n)
-{
- return likely(n >= 0 && n < KVM_MAX_VCPUS);
-}
-
inline int kvm_is_mmio_pfn(pfn_t pfn)
{
if (pfn_valid(pfn)) {
@@ -742,15 +738,11 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
bool called = true;
struct kvm_vcpu *vcpu;
- if (alloc_cpumask_var(&cpus, GFP_ATOMIC))
- cpumask_clear(cpus);
+ zalloc_cpumask_var(&cpus, GFP_ATOMIC);
- me = get_cpu();
spin_lock(&kvm->requests_lock);
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
+ me = smp_processor_id();
+ kvm_for_each_vcpu(i, vcpu, kvm) {
if (test_and_set_bit(req, &vcpu->requests))
continue;
cpu = vcpu->cpu;
@@ -764,7 +756,6 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
else
called = false;
spin_unlock(&kvm->requests_lock);
- put_cpu();
free_cpumask_var(cpus);
return called;
}
@@ -986,7 +977,9 @@ static struct kvm *kvm_create_vm(void)
spin_lock_init(&kvm->mmu_lock);
spin_lock_init(&kvm->requests_lock);
kvm_io_bus_init(&kvm->pio_bus);
+ kvm_eventfd_init(kvm);
mutex_init(&kvm->lock);
+ mutex_init(&kvm->irq_lock);
kvm_io_bus_init(&kvm->mmio_bus);
init_rwsem(&kvm->slots_lock);
atomic_set(&kvm->users_count, 1);
@@ -1006,19 +999,25 @@ out:
static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
+ int i;
+
if (!dont || free->rmap != dont->rmap)
vfree(free->rmap);
if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
vfree(free->dirty_bitmap);
- if (!dont || free->lpage_info != dont->lpage_info)
- vfree(free->lpage_info);
+
+ for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+ if (!dont || free->lpage_info[i] != dont->lpage_info[i]) {
+ vfree(free->lpage_info[i]);
+ free->lpage_info[i] = NULL;
+ }
+ }
free->npages = 0;
free->dirty_bitmap = NULL;
free->rmap = NULL;
- free->lpage_info = NULL;
}
void kvm_free_physmem(struct kvm *kvm)
@@ -1071,6 +1070,8 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
{
struct kvm *kvm = filp->private_data;
+ kvm_irqfd_release(kvm);
+
kvm_put_kvm(kvm);
return 0;
}
@@ -1090,7 +1091,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
int r;
gfn_t base_gfn;
unsigned long npages, ugfn;
- unsigned long largepages, i;
+ int lpages;
+ unsigned long i, j;
struct kvm_memory_slot *memslot;
struct kvm_memory_slot old, new;
@@ -1164,31 +1166,48 @@ int __kvm_set_memory_region(struct kvm *kvm,
else
new.userspace_addr = 0;
}
- if (npages && !new.lpage_info) {
- largepages = 1 + (base_gfn + npages - 1) / KVM_PAGES_PER_HPAGE;
- largepages -= base_gfn / KVM_PAGES_PER_HPAGE;
+ if (!npages)
+ goto skip_lpage;
- new.lpage_info = vmalloc(largepages * sizeof(*new.lpage_info));
+ for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+ int level = i + 2;
- if (!new.lpage_info)
+ /* Avoid unused variable warning if no large pages */
+ (void)level;
+
+ if (new.lpage_info[i])
+ continue;
+
+ lpages = 1 + (base_gfn + npages - 1) /
+ KVM_PAGES_PER_HPAGE(level);
+ lpages -= base_gfn / KVM_PAGES_PER_HPAGE(level);
+
+ new.lpage_info[i] = vmalloc(lpages * sizeof(*new.lpage_info[i]));
+
+ if (!new.lpage_info[i])
goto out_free;
- memset(new.lpage_info, 0, largepages * sizeof(*new.lpage_info));
+ memset(new.lpage_info[i], 0,
+ lpages * sizeof(*new.lpage_info[i]));
- if (base_gfn % KVM_PAGES_PER_HPAGE)
- new.lpage_info[0].write_count = 1;
- if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE)
- new.lpage_info[largepages-1].write_count = 1;
+ if (base_gfn % KVM_PAGES_PER_HPAGE(level))
+ new.lpage_info[i][0].write_count = 1;
+ if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE(level))
+ new.lpage_info[i][lpages - 1].write_count = 1;
ugfn = new.userspace_addr >> PAGE_SHIFT;
/*
* If the gfn and userspace address are not aligned wrt each
- * other, disable large page support for this slot
+ * other, or if explicitly asked to, disable large page
+ * support for this slot
*/
- if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
- for (i = 0; i < largepages; ++i)
- new.lpage_info[i].write_count = 1;
+ if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
+ !largepages_enabled)
+ for (j = 0; j < lpages; ++j)
+ new.lpage_info[i][j].write_count = 1;
}
+skip_lpage:
+
/* Allocate page dirty bitmap if needed */
if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
@@ -1200,6 +1219,10 @@ int __kvm_set_memory_region(struct kvm *kvm,
if (old.npages)
kvm_arch_flush_shadow(kvm);
}
+#else /* not defined CONFIG_S390 */
+ new.user_alloc = user_alloc;
+ if (user_alloc)
+ new.userspace_addr = mem->userspace_addr;
#endif /* not defined CONFIG_S390 */
if (!npages)
@@ -1299,6 +1322,12 @@ out:
return r;
}
+void kvm_disable_largepages(void)
+{
+ largepages_enabled = false;
+}
+EXPORT_SYMBOL_GPL(kvm_disable_largepages);
+
int is_error_page(struct page *page)
{
return page == bad_page;
@@ -1635,9 +1664,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
for (;;) {
prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
- if ((kvm_arch_interrupt_allowed(vcpu) &&
- kvm_cpu_has_interrupt(vcpu)) ||
- kvm_arch_vcpu_runnable(vcpu)) {
+ if (kvm_arch_vcpu_runnable(vcpu)) {
set_bit(KVM_REQ_UNHALT, &vcpu->requests);
break;
}
@@ -1714,24 +1741,18 @@ static struct file_operations kvm_vcpu_fops = {
*/
static int create_vcpu_fd(struct kvm_vcpu *vcpu)
{
- int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
- if (fd < 0)
- kvm_put_kvm(vcpu->kvm);
- return fd;
+ return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
}
/*
* Creates some virtual cpus. Good luck creating more than one.
*/
-static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
+static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
{
int r;
- struct kvm_vcpu *vcpu;
+ struct kvm_vcpu *vcpu, *v;
- if (!valid_vcpu(n))
- return -EINVAL;
-
- vcpu = kvm_arch_vcpu_create(kvm, n);
+ vcpu = kvm_arch_vcpu_create(kvm, id);
if (IS_ERR(vcpu))
return PTR_ERR(vcpu);
@@ -1742,23 +1763,38 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
return r;
mutex_lock(&kvm->lock);
- if (kvm->vcpus[n]) {
- r = -EEXIST;
+ if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
+ r = -EINVAL;
goto vcpu_destroy;
}
- kvm->vcpus[n] = vcpu;
- mutex_unlock(&kvm->lock);
+
+ kvm_for_each_vcpu(r, v, kvm)
+ if (v->vcpu_id == id) {
+ r = -EEXIST;
+ goto vcpu_destroy;
+ }
+
+ BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]);
/* Now it's all set up, let userspace reach it */
kvm_get_kvm(kvm);
r = create_vcpu_fd(vcpu);
- if (r < 0)
- goto unlink;
+ if (r < 0) {
+ kvm_put_kvm(kvm);
+ goto vcpu_destroy;
+ }
+
+ kvm->vcpus[atomic_read(&kvm->online_vcpus)] = vcpu;
+ smp_wmb();
+ atomic_inc(&kvm->online_vcpus);
+
+#ifdef CONFIG_KVM_APIC_ARCHITECTURE
+ if (kvm->bsp_vcpu_id == id)
+ kvm->bsp_vcpu = vcpu;
+#endif
+ mutex_unlock(&kvm->lock);
return r;
-unlink:
- mutex_lock(&kvm->lock);
- kvm->vcpus[n] = NULL;
vcpu_destroy:
mutex_unlock(&kvm->lock);
kvm_arch_vcpu_destroy(vcpu);
@@ -2199,6 +2235,7 @@ static long kvm_vm_ioctl(struct file *filp,
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;
@@ -2221,7 +2258,35 @@ static long kvm_vm_ioctl(struct file *filp,
break;
}
#endif
-#endif /* KVM_CAP_IRQ_ROUTING */
+ case KVM_IRQFD: {
+ struct kvm_irqfd data;
+
+ r = -EFAULT;
+ if (copy_from_user(&data, argp, sizeof data))
+ goto out;
+ r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
+ break;
+ }
+ case KVM_IOEVENTFD: {
+ struct kvm_ioeventfd data;
+
+ r = -EFAULT;
+ if (copy_from_user(&data, argp, sizeof data))
+ goto out;
+ r = kvm_ioeventfd(kvm, &data);
+ break;
+ }
+#ifdef CONFIG_KVM_APIC_ARCHITECTURE
+ case KVM_SET_BOOT_CPU_ID:
+ r = 0;
+ mutex_lock(&kvm->lock);
+ if (atomic_read(&kvm->online_vcpus) != 0)
+ r = -EBUSY;
+ else
+ kvm->bsp_vcpu_id = arg;
+ mutex_unlock(&kvm->lock);
+ break;
+#endif
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
}
@@ -2288,6 +2353,9 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)
case KVM_CAP_USER_MEMORY:
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
case KVM_CAP_JOIN_MEMORY_REGIONS_WORKS:
+#ifdef CONFIG_KVM_APIC_ARCHITECTURE
+ case KVM_CAP_SET_BOOT_CPU_ID:
+#endif
return 1;
#ifdef CONFIG_HAVE_KVM_IRQCHIP
case KVM_CAP_IRQ_ROUTING:
@@ -2335,7 +2403,7 @@ static long kvm_dev_ioctl(struct file *filp,
case KVM_TRACE_ENABLE:
case KVM_TRACE_PAUSE:
case KVM_TRACE_DISABLE:
- r = kvm_trace_ioctl(ioctl, arg);
+ r = -EOPNOTSUPP;
break;
default:
return kvm_arch_dev_ioctl(filp, ioctl, arg);
@@ -2449,26 +2517,71 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)
}
}
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
- gpa_t addr, int len, int is_write)
+/* kvm_io_bus_write - called under kvm->slots_lock */
+int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,
+ int len, const void *val)
{
int i;
+ for (i = 0; i < bus->dev_count; i++)
+ if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
+ return 0;
+ return -EOPNOTSUPP;
+}
- for (i = 0; i < bus->dev_count; i++) {
- struct kvm_io_device *pos = bus->devs[i];
+/* kvm_io_bus_read - called under kvm->slots_lock */
+int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
+{
+ int i;
+ for (i = 0; i < bus->dev_count; i++)
+ if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
+ return 0;
+ return -EOPNOTSUPP;
+}
- if (pos->in_range(pos, addr, len, is_write))
- return pos;
- }
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+ struct kvm_io_device *dev)
+{
+ int ret;
- return NULL;
+ down_write(&kvm->slots_lock);
+ ret = __kvm_io_bus_register_dev(bus, dev);
+ up_write(&kvm->slots_lock);
+
+ return ret;
}
-void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev)
+/* An unlocked version. Caller must have write lock on slots_lock. */
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+ struct kvm_io_device *dev)
{
- BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+ if (bus->dev_count > NR_IOBUS_DEVS-1)
+ return -ENOSPC;
bus->devs[bus->dev_count++] = dev;
+
+ return 0;
+}
+
+void kvm_io_bus_unregister_dev(struct kvm *kvm,
+ struct kvm_io_bus *bus,
+ struct kvm_io_device *dev)
+{
+ down_write(&kvm->slots_lock);
+ __kvm_io_bus_unregister_dev(bus, dev);
+ up_write(&kvm->slots_lock);
+}
+
+/* An unlocked version. Caller must have write lock on slots_lock. */
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+ struct kvm_io_device *dev)
+{
+ int i;
+
+ for (i = 0; i < bus->dev_count; i++)
+ if (bus->devs[i] == dev) {
+ bus->devs[i] = bus->devs[--bus->dev_count];
+ break;
+ }
}
static struct notifier_block kvm_cpu_notifier = {
@@ -2501,11 +2614,9 @@ static int vcpu_stat_get(void *_offset, u64 *val)
*val = 0;
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list)
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (vcpu)
- *val += *(u32 *)((void *)vcpu + offset);
- }
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ *val += *(u32 *)((void *)vcpu + offset);
+
spin_unlock(&kvm_lock);
return 0;
}
@@ -2687,7 +2798,7 @@ EXPORT_SYMBOL_GPL(kvm_init);
void kvm_exit(void)
{
- kvm_trace_cleanup();
+ tracepoint_synchronize_unregister();
misc_deregister(&kvm_dev);
kmem_cache_destroy(kvm_vcpu_cache);
sysdev_unregister(&kvm_sysdev);
diff --git a/virt/kvm/kvm_trace.c b/virt/kvm/kvm_trace.c
deleted file mode 100644
index f59874446440..000000000000
--- a/virt/kvm/kvm_trace.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * kvm trace
- *
- * It is designed to allow debugging traces of kvm to be generated
- * on UP / SMP machines. Each trace entry can be timestamped so that
- * it's possible to reconstruct a chronological record of trace events.
- * The implementation refers to blktrace kernel support.
- *
- * Copyright (c) 2008 Intel Corporation
- * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
- *
- * Authors: Feng(Eric) Liu, eric.e.liu@intel.com
- *
- * Date: Feb 2008
- */
-
-#include <linux/module.h>
-#include <linux/relay.h>
-#include <linux/debugfs.h>
-#include <linux/ktime.h>
-
-#include <linux/kvm_host.h>
-
-#define KVM_TRACE_STATE_RUNNING (1 << 0)
-#define KVM_TRACE_STATE_PAUSE (1 << 1)
-#define KVM_TRACE_STATE_CLEARUP (1 << 2)
-
-struct kvm_trace {
- int trace_state;
- struct rchan *rchan;
- struct dentry *lost_file;
- atomic_t lost_records;
-};
-static struct kvm_trace *kvm_trace;
-
-struct kvm_trace_probe {
- const char *name;
- const char *format;
- u32 timestamp_in;
- marker_probe_func *probe_func;
-};
-
-static inline int calc_rec_size(int timestamp, int extra)
-{
- int rec_size = KVM_TRC_HEAD_SIZE;
-
- rec_size += extra;
- return timestamp ? rec_size += KVM_TRC_CYCLE_SIZE : rec_size;
-}
-
-static void kvm_add_trace(void *probe_private, void *call_data,
- const char *format, va_list *args)
-{
- struct kvm_trace_probe *p = probe_private;
- struct kvm_trace *kt = kvm_trace;
- struct kvm_trace_rec rec;
- struct kvm_vcpu *vcpu;
- int i, size;
- u32 extra;
-
- if (unlikely(kt->trace_state != KVM_TRACE_STATE_RUNNING))
- return;
-
- rec.rec_val = TRACE_REC_EVENT_ID(va_arg(*args, u32));
- vcpu = va_arg(*args, struct kvm_vcpu *);
- rec.pid = current->tgid;
- rec.vcpu_id = vcpu->vcpu_id;
-
- extra = va_arg(*args, u32);
- WARN_ON(!(extra <= KVM_TRC_EXTRA_MAX));
- extra = min_t(u32, extra, KVM_TRC_EXTRA_MAX);
-
- rec.rec_val |= TRACE_REC_TCS(p->timestamp_in)
- | TRACE_REC_NUM_DATA_ARGS(extra);
-
- if (p->timestamp_in) {
- rec.u.timestamp.timestamp = ktime_to_ns(ktime_get());
-
- for (i = 0; i < extra; i++)
- rec.u.timestamp.extra_u32[i] = va_arg(*args, u32);
- } else {
- for (i = 0; i < extra; i++)
- rec.u.notimestamp.extra_u32[i] = va_arg(*args, u32);
- }
-
- size = calc_rec_size(p->timestamp_in, extra * sizeof(u32));
- relay_write(kt->rchan, &rec, size);
-}
-
-static struct kvm_trace_probe kvm_trace_probes[] = {
- { "kvm_trace_entryexit", "%u %p %u %u %u %u %u %u", 1, kvm_add_trace },
- { "kvm_trace_handler", "%u %p %u %u %u %u %u %u", 0, kvm_add_trace },
-};
-
-static int lost_records_get(void *data, u64 *val)
-{
- struct kvm_trace *kt = data;
-
- *val = atomic_read(&kt->lost_records);
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(kvm_trace_lost_ops, lost_records_get, NULL, "%llu\n");
-
-/*
- * The relay channel is used in "no-overwrite" mode, it keeps trace of how
- * many times we encountered a full subbuffer, to tell user space app the
- * lost records there were.
- */
-static int kvm_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf, size_t prev_padding)
-{
- struct kvm_trace *kt;
-
- if (!relay_buf_full(buf)) {
- if (!prev_subbuf) {
- /*
- * executed only once when the channel is opened
- * save metadata as first record
- */
- subbuf_start_reserve(buf, sizeof(u32));
- *(u32 *)subbuf = 0x12345678;
- }
-
- return 1;
- }
-
- kt = buf->chan->private_data;
- atomic_inc(&kt->lost_records);
-
- return 0;
-}
-
-static struct dentry *kvm_create_buf_file_callack(const char *filename,
- struct dentry *parent,
- int mode,
- struct rchan_buf *buf,
- int *is_global)
-{
- return debugfs_create_file(filename, mode, parent, buf,
- &relay_file_operations);
-}
-
-static int kvm_remove_buf_file_callback(struct dentry *dentry)
-{
- debugfs_remove(dentry);
- return 0;
-}
-
-static struct rchan_callbacks kvm_relay_callbacks = {
- .subbuf_start = kvm_subbuf_start_callback,
- .create_buf_file = kvm_create_buf_file_callack,
- .remove_buf_file = kvm_remove_buf_file_callback,
-};
-
-static int do_kvm_trace_enable(struct kvm_user_trace_setup *kuts)
-{
- struct kvm_trace *kt;
- int i, r = -ENOMEM;
-
- if (!kuts->buf_size || !kuts->buf_nr)
- return -EINVAL;
-
- kt = kzalloc(sizeof(*kt), GFP_KERNEL);
- if (!kt)
- goto err;
-
- r = -EIO;
- atomic_set(&kt->lost_records, 0);
- kt->lost_file = debugfs_create_file("lost_records", 0444, kvm_debugfs_dir,
- kt, &kvm_trace_lost_ops);
- if (!kt->lost_file)
- goto err;
-
- kt->rchan = relay_open("trace", kvm_debugfs_dir, kuts->buf_size,
- kuts->buf_nr, &kvm_relay_callbacks, kt);
- if (!kt->rchan)
- goto err;
-
- kvm_trace = kt;
-
- for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) {
- struct kvm_trace_probe *p = &kvm_trace_probes[i];
-
- r = marker_probe_register(p->name, p->format, p->probe_func, p);
- if (r)
- printk(KERN_INFO "Unable to register probe %s\n",
- p->name);
- }
-
- kvm_trace->trace_state = KVM_TRACE_STATE_RUNNING;
-
- return 0;
-err:
- if (kt) {
- if (kt->lost_file)
- debugfs_remove(kt->lost_file);
- if (kt->rchan)
- relay_close(kt->rchan);
- kfree(kt);
- }
- return r;
-}
-
-static int kvm_trace_enable(char __user *arg)
-{
- struct kvm_user_trace_setup kuts;
- int ret;
-
- ret = copy_from_user(&kuts, arg, sizeof(kuts));
- if (ret)
- return -EFAULT;
-
- ret = do_kvm_trace_enable(&kuts);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int kvm_trace_pause(void)
-{
- struct kvm_trace *kt = kvm_trace;
- int r = -EINVAL;
-
- if (kt == NULL)
- return r;
-
- if (kt->trace_state == KVM_TRACE_STATE_RUNNING) {
- kt->trace_state = KVM_TRACE_STATE_PAUSE;
- relay_flush(kt->rchan);
- r = 0;
- }
-
- return r;
-}
-
-void kvm_trace_cleanup(void)
-{
- struct kvm_trace *kt = kvm_trace;
- int i;
-
- if (kt == NULL)
- return;
-
- if (kt->trace_state == KVM_TRACE_STATE_RUNNING ||
- kt->trace_state == KVM_TRACE_STATE_PAUSE) {
-
- kt->trace_state = KVM_TRACE_STATE_CLEARUP;
-
- for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) {
- struct kvm_trace_probe *p = &kvm_trace_probes[i];
- marker_probe_unregister(p->name, p->probe_func, p);
- }
- marker_synchronize_unregister();
-
- relay_close(kt->rchan);
- debugfs_remove(kt->lost_file);
- kfree(kt);
- }
-}
-
-int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
- long r = -EINVAL;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- switch (ioctl) {
- case KVM_TRACE_ENABLE:
- r = kvm_trace_enable(argp);
- break;
- case KVM_TRACE_PAUSE:
- r = kvm_trace_pause();
- break;
- case KVM_TRACE_DISABLE:
- r = 0;
- kvm_trace_cleanup();
- break;
- }
-
- return r;
-}